-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgoogle-c-style.el
380 lines (354 loc) · 16.3 KB
/
google-c-style.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
;;; google-c-style.el --- Google's C/C++ style for c-mode
;; Keywords: c, tools
;; google-c-style.el is Copyright (C) 2008 Google Inc. All Rights Reserved.
;;
;; It is free software; you can redistribute it and/or modify it under the
;; terms of either:
;;
;; a) the GNU General Public License as published by the Free Software
;; Foundation; either version 1, or (at your option) any later version, or
;;
;; b) the "Artistic License".
;;; Commentary:
;; Provides the google C/C++ coding style. You may wish to add
;; `google-set-c-style' to your `c-mode-common-hook' after requiring this
;; file. For example:
;;
;; (add-hook 'c-mode-common-hook 'google-set-c-style)
;;
;; If you want the RETURN key to go to the next line and space over
;; to the right place, add this to your .emacs right after the load-file:
;;
;; (add-hook 'c-mode-common-hook 'google-make-newline-indent)
;; Original:
;; https://github.com/google/styleguide/blob/gh-pages/google-c-style.el
;; This is a modified copy found at:
;; https://github.com/mwolson/emacs-shared/blob/master/elisp/google-c-style.el
;;; Code:
;; For some reason 1) c-backward-syntactic-ws is a macro and 2) under Emacs 22
;; bytecode cannot call (unexpanded) macros at run time:
(eval-when-compile (require 'cc-defs))
;; Wrapper function needed for Emacs 21 and XEmacs (Emacs 22 offers the more
;; elegant solution of composing a list of lineup functions or quantities with
;; operators such as "add")
(defun google-c-lineup-expression-plus-4 (langelem)
"Indents to the beginning of the current C expression plus 4 spaces.
This implements title \"Function Declarations and Definitions\"
of the Google C++ Style Guide for the case where the previous
line ends with an open parenthese.
\"Current C expression\", as per the Google Style Guide and as
clarified by subsequent discussions, means the whole expression
regardless of the number of nested parentheses, but excluding
non-expression material such as \"if(\" and \"for(\" control
structures.
Suitable for inclusion in `c-offsets-alist'."
(save-excursion
(back-to-indentation)
;; Go to beginning of *previous* line:
(c-backward-syntactic-ws)
(back-to-indentation)
(cond
;; We are making a reasonable assumption that if there is a control
;; structure to indent past, it has to be at the beginning of the line.
((looking-at "\\(\\(if\\|for\\|while\\)\\s *(\\)")
(goto-char (match-end 1)))
;; For constructor initializer lists, the reference point for line-up is
;; the token after the initial colon.
((looking-at ":\\s *")
(goto-char (match-end 0))))
(vector (+ 4 (current-column)))))
(defun google-c-backwards-cascaded-call (stmt-start operator)
"Try to move backwards to the previous instance of `operator'.
Return non-nil if we are looking at one."
(and (zerop (c-backward-token-2 1 t stmt-start))
(eq (char-after) ?\()
(zerop (c-backward-token-2 2 t stmt-start))
(cond ((looking-at operator) t)
((eq (char-after) ?\>)
(forward-char)
(and (c-backward-<>-arglist nil stmt-start)
(eq (char-after) ?\<)
(c-backward-token-2 1 t stmt-start)
(looking-at operator))))))
(defun google-c-skip-comments ()
"If the point is at the beginning of a comment, skip past it.
Return non-nil if there was one, nil otherwise."
(when (and (looking-at c-current-comment-prefix)
(< 0 (- (match-end 0) (point))))
(c-forward-comments)))
(defun google-c-lineup-cascaded-calls (langelem)
"Line up \"cascaded calls\" under each other.
If the line begins with \"->\" or \".\" and the preceding line ends
with one or more function calls preceded by the same token, then the
arrow is lined up with the first of those tokens. E.g.:
result = proc->add(17)->add(18)
->add(19) + <- google-c-lineup-cascaded-calls
offset; <- google-c-lineup-cascaded-calls (inactive)
Further, if that rule doesn't apply, lines beginning with \"->\" or
\".\" will always be lined up according to c-basic-offset. E.g.:
result = proc
->add(17)
->add(18)
->add(19) <- google-c-lineup-cascaded-calls
In any other situation nil is returned to allow use in list
expressions.
Works with: topmost-intro-cont, statement-cont, arglist-cont,
arglist-cont-nonempty, func-decl-cont, comment-intro."
(if (and (eq (c-langelem-sym langelem) 'arglist-cont-nonempty)
(not (eq (c-langelem-2nd-pos c-syntactic-element)
(c-most-enclosing-brace (c-parse-state)))))
;; The innermost open paren is not ours, so don't do
;; anything. This can occur for arglist-cont-nonempty with
;; nested arglist starts on the same line.
nil
(save-excursion
(back-to-indentation)
(google-c-skip-comments)
(let ((operator (and (looking-at "->\\|\\.")
(regexp-quote (match-string 0))))
(stmt-start (c-langelem-pos langelem)) col)
(when (and operator
(looking-at operator))
(if (not (google-c-backwards-cascaded-call stmt-start operator))
(progn
(back-to-indentation)
(vector (+ 4 (current-column))))
(setq col (current-column))
(while (google-c-backwards-cascaded-call stmt-start operator)
(setq col (current-column)))
(vector col)))))))
(defun google-c-lineup-new-class-instance (langelem)
"If we are after a new class instance, use 2 spaces, otherwise fall through.
Suitable for arglist-cont-nonempty and inexpr-class."
(save-excursion
(if (eq (c-langelem-sym langelem) 'inexpr-class)
0
(goto-char (c-langelem-pos langelem))
(cond
((looking-at ".*?new[^\n(]+()\\s *{\\s *$")
(vector (current-column)))
(t nil)))))
(defvar google-c-lambda-op-regexp "->"
"Matches Java lambda operator, which is: ->")
(defun google-c-lineup-blocks (langelem)
"Treatment for blocks.
If we are on first line of block contents, use 2 additional spaces (total 4).
If we are on 2nd or more line of block contents, align to previous item.
If we are on the final ')}' part, then close the block.
If our innermost block-like thing is a paren continuation, indent exactly 4 spaces.
If we are on a return statement, align after 'return' and any whitespace.
Suitable for arglist-cont-nonempty, brace-list-intro, brace-list-close, statement-block-intro, statement-cont"
(save-excursion
(back-to-indentation)
(google-c-skip-comments)
(let* ((block-complete (looking-at "[)}]"))
(endpos (if (eq (c-langelem-sym langelem) 'arglist-cont-nonempty)
;; if it's an arglist-cont-nonempty then we bound the search to be outside of it
(c-langelem-2nd-pos c-syntactic-element)
(point)))
(before-lambda (save-excursion
(goto-char (c-langelem-pos langelem))
(and (c-syntactic-re-search-forward google-c-lambda-op-regexp endpos t nil nil)
(point))))
(before-equals (when (memq (c-langelem-sym langelem) '(brace-list-intro statement-cont))
(save-excursion
(goto-char (c-langelem-pos langelem))
(and (c-syntactic-re-search-forward c-assignment-op-regexp endpos t t t)
(or (not before-lambda)
(< before-lambda (point)))))))
(containing-brace (progn
(beginning-of-line)
(backward-up-list 1)
(point))))
(cond
(block-complete
(if (eq (c-langelem-sym langelem) 'brace-list-close)
(goto-char (c-langelem-pos langelem))
(goto-char containing-brace))
(back-to-indentation)
(vector (current-column)))
((eq (c-langelem-sym langelem) 'brace-list-intro)
(goto-char (c-langelem-pos langelem))
(back-to-indentation)
(if before-equals
(vector (+ 4 (current-column)))
(vector (+ 2 (current-column)))))
(before-equals nil)
(before-lambda
(goto-char (c-langelem-pos langelem))
(back-to-indentation)
(vector (+ 2 (current-column))))
((looking-at "{")
(cond ((eq (c-langelem-sym langelem) 'statement-cont)
;; Note: if we have a no-op line like "2\n+2" as first line of a function, the two lines are aligned
;; because we consider the enclosing function to open a block or array initializer. This is slightly
;; odd, but IntelliJ behaves the same way.
(goto-char (c-langelem-pos langelem))
(if (looking-at "return")
;; this a return statement, which we align differently
(progn
(goto-char (match-end 0))
(c-forward-syntactic-ws)
(vector (current-column)))
(let ((col (current-column)))
(c-backward-syntactic-ws)
(backward-char)
(if (looking-at "{")
;; if the line before our containing line ends with "{", then align to containing line
(vector col)
;; otherwise align to 2+ containing brace
(goto-char containing-brace)
(back-to-indentation)
(vector (+ 2 (current-column)))))))
((eq (c-langelem-sym langelem) 'arglist-cont-nonempty)
(back-to-indentation)
(vector (+ 2 (current-column))))))
((looking-at "(")
(when (eq (c-langelem-sym langelem) 'arglist-cont-nonempty)
(back-to-indentation)
(vector (+ 4 (current-column)))))))))
(defun google-c-lineup-parens (langelem)
"If we see an expression while surrounded by parens, line it up to 1+ paren level.
Suitable for `arglist-cont-nonempty'"
(save-excursion
(back-to-indentation)
(google-c-skip-comments)
(let ((saved-point (point))
(char-near-point (char-after))
(stmt-start (c-langelem-pos langelem)))
(backward-up-list 1)
(cond ((not (eq (char-after) ?\())
;; we are in a block or some other construct, don't modify it
nil)
((eq char-near-point ?\))
;; don't align closing parens
nil)
((and (c-backward-token-2 1 t stmt-start)
(looking-at "\\(\\(if\\|for\\|while\\)\\s *(\\)"))
;; we are at an if/for/while expression, so indent to 1+ paren
(goto-char saved-point)
(c-lineup-arglist-intro-after-paren langelem))
((looking-at "[[:alpha:]]")
;; we are at a function call, so indent to 1+ paren
(goto-char saved-point)
(c-lineup-arglist-intro-after-paren langelem))
(t
;; we are at an expression, so indent to 1+ paren
(goto-char saved-point)
(c-lineup-arglist-intro-after-paren langelem))))))
;;;###autoload
(defconst google-c-style
`((c-recognize-knr-p . nil)
(c-enable-xemacs-performance-kludge-p . t) ; speed up indentation in XEmacs
(c-recognize-<>-arglists . t)
(c-basic-offset . 2)
(indent-tabs-mode . nil)
(c-comment-only-line-offset . 0)
(c-hanging-braces-alist . ((defun-open after)
(defun-close before after)
(class-open after)
(class-close before after)
(inexpr-class-open after)
(inexpr-class-close before)
(namespace-open after)
(inline-open after)
(inline-close before after)
(block-open after)
(block-close . c-snug-do-while)
(extern-lang-open after)
(extern-lang-close after)
(statement-case-open after)
(substatement-open after)))
(c-hanging-colons-alist . ((case-label)
(label after)
(access-label after)
(member-init-intro before)
(inher-intro)))
(c-hanging-semi&comma-criteria
. (c-semi&comma-no-newlines-for-oneline-inliners
c-semi&comma-inside-parenlist
c-semi&comma-no-newlines-before-nonblanks))
(c-indent-comments-syntactically-p . t)
(comment-column . 40)
(c-indent-comment-alist . ((other . (space . 2))))
(c-cleanup-list . (brace-else-brace
brace-elseif-brace
brace-catch-brace
empty-defun-braces
defun-close-semi
list-close-comma
scope-operator))
(c-offsets-alist . ((arglist-intro google-c-lineup-expression-plus-4)
(arglist-cont-nonempty
. (google-c-lineup-new-class-instance
google-c-lineup-parens
google-c-lineup-blocks
++))
(arglist-cont
. (google-c-lineup-cascaded-calls
0))
(arglist-close
. (,(when (fboundp 'c-no-indent-after-java-annotations)
'c-no-indent-after-java-annotations)
google-c-lineup-parens
0))
(inexpr-class
. (google-c-lineup-new-class-instance
+))
(func-decl-cont
. (google-c-lineup-cascaded-calls
++))
(member-init-intro . ++)
(brace-list-intro
. (google-c-lineup-blocks
+))
(brace-list-close
. (google-c-lineup-blocks
0))
(inher-intro . ++)
(comment-intro
. (google-c-lineup-cascaded-calls
0))
(topmost-intro . 0)
(topmost-intro-cont . ++)
(block-open . 0)
(inline-open . 0)
(substatement-open . 0)
(annotation-var-cont . 0)
(statement-block-intro
. (google-c-lineup-blocks
+))
(statement-cont
. (,(when (fboundp 'c-no-indent-after-java-annotations)
'c-no-indent-after-java-annotations)
google-c-lineup-cascaded-calls
,(when (fboundp 'c-lineup-assignments)
'c-lineup-assignments)
google-c-lineup-blocks
++))
(label . /)
(case-label . 0)
(statement-case-open . +)
(statement-case-intro . +) ; case w/o {
(access-label . /)
(innamespace . 0))))
"Google C/C++ Programming Style.")
;;;###autoload
;(defun google-set-c-style ()
; "Set the current buffer's c-style to Google C/C++ Programming
; Style. Meant to be added to `c-mode-common-hook'."
; (interactive)
; (make-local-variable 'c-tab-always-indent)
; (setq c-tab-always-indent t)
; (c-add-style "google" google-c-style t))
;;;###autoload
;(defun google-make-newline-indent ()
; "Sets up preferred newline behavior. Not set by default. Meant
; to be added to `c-mode-common-hook'."
; (interactive)
; (define-key c-mode-base-map "\C-m" 'newline-and-indent)
; (define-key c-mode-base-map [ret] 'newline-and-indent))
; Add this to the list of c styles.
(c-add-style "google" google-c-style)
(provide 'google-c-style)
;;; google-c-style.el ends here