2
;; Copyright (c) 2002 by The XFree86 Project, Inc.
4
;; Permission is hereby granted, free of charge, to any person obtaining a
5
;; copy of this software and associated documentation files (the "Software"),
6
;; to deal in the Software without restriction, including without limitation
7
;; the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
;; and/or sell copies of the Software, and to permit persons to whom the
9
;; Software is furnished to do so, subject to the following conditions:
11
;; The above copyright notice and this permission notice shall be included in
12
;; all copies or substantial portions of the Software.
14
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
;; THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19
;; OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
;; Except as contained in this notice, the name of the XFree86 Project shall
23
;; not be used in advertising or otherwise to promote the sale, use or other
24
;; dealings in this Software without prior written authorization from the
27
;; Author: Paulo C�sar Pereira de Andrade
30
;; $XFree86: xc/programs/xedit/lisp/modules/progmodes/c.lsp,v 1.26 2003/01/29 03:05:54 paulo Exp $
37
(defsynprop *prop-format*
39
:font "*lucidatypewriter-medium-r*12*"
40
:foreground "RoyalBlue2"
44
(defsynoptions *c-DEFAULT-style*
45
;; Positive number. Basic indentation.
48
;; Boolean. Support for GNU style indentation.
51
;; Boolean. Add one indentation level to case and default?
54
;; Boolean. Remove one indentation level for labels?
57
;; Boolean. Add one indentation level to continuations?
60
;; Boolean. Move cursor to the indent column after pressing <Enter>?
63
;; Boolean. Set to T if tabs shouldn't be used to fill indentation.
66
;; Boolean. Force a newline before braces?
67
(:newline-before-brace . nil)
69
;; Boolean. Force a newline after braces?
70
(:newline-after-brace . nil)
72
;; Boolean. Force a newline after semicolons?
73
(:newline-after-semi . nil)
75
;; Boolean. Only calculate indentation after pressing <Enter>?
76
;; This may be useful if the parser does not always
77
;; do what the user expects...
78
(:only-newline-indent . nil)
80
;; Boolean. Remove extra spaces from previous line.
81
;; This should default to T when newline-indent is not NIL.
82
(:trim-blank-lines . t)
84
;; Boolean. If this hash-table entry is set, no indentation is done.
85
;; Useful to temporarily disable indentation.
86
(:disable-indent . nil)
90
(defsynoptions *c-BSD-style*
98
(:newline-before-brace . nil)
99
(:newline-after-brace . t)
100
(:newline-after-semi . t)
101
(:trim-blank-lines . t)
105
(defsynoptions *c-GNU-style*
111
(:newline-indent . nil)
112
(:emulate-tabs . nil)
113
(:newline-before-brace . t)
114
(:newline-after-brace . t)
115
(:newline-after-semi . t)
116
(:trim-blank-lines . nil)
120
(defsynoptions *c-K&R-style*
122
(:brace-indent . nil)
126
(:newline-indent . t)
128
(:newline-before-brace . t)
129
(:newline-after-brace . t)
130
(:newline-after-semi . t)
131
(:trim-blank-lines . t)
134
(defvar *c-styles* '(
135
("xedit" . *c-DEFAULT-style*)
136
("BSD" . *c-BSD-style*)
137
("GNU" . *c-GNU-style*)
138
("K&R" . *c-K&R-style*)
141
(defvar *c-mode-options* *c-DEFAULT-style*)
142
; (setq *c-mode-options* *c-gnu-style*)
144
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
145
;; This is a very lazy "pattern matcher" for the C language.
146
;; If the syntax in the code is not correct, it may get confused, and
147
;; because it is "lazy" some wrong constructs will be recognized as
148
;; correct when reducing patterns.
149
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
150
(defindent *c-mode-indent* :main
151
;; this must be the first token
152
(indtoken "^\\s*" :start-of-line)
153
(indtoken "\\<case\\>" :c-case)
154
(indtoken "\\<default\\>" :c-default)
155
(indtoken "\\<do\\>" :do)
156
(indtoken "\\<if\\>" :c-if)
157
(indtoken "\\<else\\>" :c-else)
158
(indtoken "\\<for\\>" :c-for)
159
(indtoken "\\<switch\\>" :c-switch)
160
(indtoken "\\<while\\>" :c-while)
161
;; Match identifiers and numbers as an expression
162
(indtoken "\\w+" :expression)
163
(indtoken ";" :semi :nospec t)
164
(indtoken "," :comma :nospec t)
165
(indtoken ":" :collon :nospec t)
166
;; Ignore spaces before collon, this avoids dedenting ternary
167
;; and bitfield definitions as the parser does not distinguish
168
;; labels from those, another option would be to use the pattern
169
;; "\\w+:", but this way should properly handle labels generated
170
;; by macros, example: `MACRO_LABEL(value):'
171
(indtoken "\\s+:" nil)
173
(indinit (c-braces 0))
177
:code (decf c-braces)
183
:code (incf c-braces)
190
:code (decf c-braces)
196
:code (incf c-braces)
201
(indtoken ")" :cparen :nospec t :code (incf c-bra))
202
(indtoken "(" :oparen :nospec t :code (decf c-bra))
203
(indtoken "]" :cbrack :nospec t :code (incf c-bra))
204
(indtoken "[" :obrack :nospec t :code (decf c-bra))
205
(indtoken "\\\\$" :continuation)
207
;; C++ style comment, disallow other tokens to match inside comment
208
(indtoken "//.*$" nil)
210
(indtoken "#" :hash :nospec t)
212
;; if in the same line, reduce now, this must be done because the
213
;; delimiters are identical
214
(indtoken "'([^\\']|\\\\.)*'" :expression)
215
(indtoken "\"([^\\\"]|\\\\.)*\"" :expression)
217
(indtoken "\"" :cstring :nospec t :begin :string)
219
(indtoken "'" :cconstant :nospec t :begin :constant)
221
(indtoken "*/" :ccomment :nospec t :begin :comment)
222
;; this must be the last token
223
(indtoken "$" :end-of-line)
226
;; Ignore escaped characters
228
;; Return to the toplevel when the start of the string is found
229
(indtoken "\"" :ostring :nospec t :switch -1)
232
;; Ignore escaped characters
234
;; Return to the toplevel when the start of the character is found
235
(indtoken "'" :oconstant :nospec t :switch -1)
238
(indtoken "/*" :ocomment :nospec t :switch -1)
241
;; "Complex" statements
242
(indinit (c-complex 0) (c-cases 0))
244
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
245
;; Order of reduce rules here is important, process comment,
246
;; continuations, preprocessor and set states when an eol is found.
247
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
249
(indinit (c-offset (point-max))
250
(c-prev-offset c-offset)
255
(and (= *ind-start* *ind-offset*)
257
*offset* (+ *ind-offset* *ind-length*)
261
c-prev-offset c-offset
262
c-offset *ind-offset*
269
((:ocomment nil :ccomment))
272
;; Join in a single token to simplify removal of possible multiline
273
;; preprocessor directives
274
(indinit c-continuation)
275
(indreduce :continuation
277
((:continuation :end-of-line))
278
(setq c-continuation t)
284
;; Anything after the eol offset is safe to parse now
285
(setq c-continuation nil)
288
;; Delete blank lines
294
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
296
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
298
(>= *ind-offset* *ind-start*)
301
(indent-macro-reject-left)
305
((:indent :hash nil :eol))
308
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
310
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
311
(indreduce :expression
313
;; Reduce to a single expression
314
((:expression :parens)
315
(:expression :bracks)
316
(:expression :expression)
317
;; These may be multiline
318
(:ostring (not :ostring) :cstring)
319
(:oconstant (not :oconstant) :cconstant)
323
(indreduce :expression
325
((:expression :eol :indent :expression)
326
(:expression :eol :expression)
330
(indreduce :exp-comma
332
((:expression :comma)
336
;; A semicollon, start a statement
342
;; Expression following (possibly empty) statement
345
(((or :expression :exp-comma) :stat))
348
;; Multiline statements
351
(((or :expression :exp-comma) :eol :indent :stat)
352
;; rule below may have removed the :indent
353
((or :expression :exp-comma) :eol :stat)
357
(indinit c-exp-indent)
358
;; XXX This rule avoids parsing large amounts of code
361
;; Eat eol if following expression
362
((:indent :stat :eol)
368
(/= (cdar c-exp-indent) (+ *ind-offset* *ind-length*))
370
;; A new statement, i.e. not just joining a multiline one
373
(offset-indentation *ind-offset* :resolve t)
374
(+ *ind-offset* *ind-length*)
378
;; Update start of statement
381
(offset-indentation *ind-offset* :resolve t)
384
(when (consp (cdr c-exp-indent))
389
(= (caar c-exp-indent) (caadr c-exp-indent))
391
;; Two statements with the same indentation
393
(setq *indent* (caar c-exp-indent))
394
(indent-macro-reject-left)
396
;; Different indentation or complex state
398
(rplacd c-exp-indent nil)
405
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
407
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
409
;; If block finishes before current line, group as a statement
410
(< (+ *ind-offset* *ind-length*) *ind-start*)
411
((:obrace (not :obrace) :cbrace))
414
;; If not in the first line
415
(< *ind-offset* *ind-start*)
416
;; If the opening { is the first non blank char in the line
418
(setq *indent* (offset-indentation (+ *ind-offset* *ind-length*)))
420
;; XXX This may be the starting brace of a switch
421
(setq c-case-flag nil)
422
(indent-macro-reject-left)
425
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
427
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
428
;; XXX this frequently doesn't do what is expected, should redefine
429
;; some rules, as it frequently will dedent while typing something
430
;; like test ? exp1 : exp2
431
;; ^ dedents here because it reduces everything
432
;; before ':' to a single :expression token.
435
((:indent :expression :collon :eol))
436
(when (and *label-dedent* (>= *ind-offset* *ind-start*))
439
(- (offset-indentation *ind-offset* :resolve t) *base-indent*)
441
(indent-macro-reject-left)
445
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
447
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
465
(:else :eol :indent :if)
470
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
472
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
473
;; Join with the parentheses
480
;; Before current line, simplify
482
(< (+ *ind-offset* *ind-length*) *ind-point*)
487
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
488
;; Handle while and do
489
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
493
;; Assume that it is yet being edited, or adjusting indentation
505
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
507
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
508
(indinit c-case-flag)
515
;; Transform in a statement
517
(< (+ *ind-offset* *ind-length*) *ind-start*)
519
;; Do it now or some rule may stop parsing, and calculate
520
;; a wrong indentation for nested switches
521
(:switch :eol :indent :stat)
528
(> *ind-start* *ind-offset*)
530
((:indent :switch :obrace)
533
*indent* (offset-indentation *ind-offset* :resolve t)
536
(indent-macro-reject-left)
541
(> *ind-start* *ind-offset*)
543
((:indent :switch :eol :indent :obrace)
546
*indent* (- (offset-indentation *ind-offset* :resolve t) *base-indent*)
549
(and *brace-indent* (incf *indent* *base-indent*))
550
(indent-macro-reject-left)
552
;; Before current line
557
(prog1 c-case-flag (setq c-case-flag t))
560
(< *ind-offset* *ind-start*)
565
*indent* (offset-indentation *ind-offset* :resolve t)
568
(indent-macro-reject-left)
572
((:c-case :expression :collon)
574
;; Assume that it is yet being edited, or adjusting indentation
578
(and (>= *ind-offset* *ind-start*)
583
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
584
;; Handle parentheses and brackets
585
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
589
((:oparen (not :oparen) :cparen))
592
(< *ind-offset* *ind-start*)
593
(> (+ *ind-offset* *ind-length*) *ind-start*)
595
(setq *indent* (1+ (offset-indentation *ind-offset* :align t)))
596
(indent-macro-reject-left)
601
((:obrack (not :obrack) :cbrack))
604
(< *ind-offset* *ind-start*)
605
(> (+ *ind-offset* *ind-length*) *ind-start*)
607
(setq *indent* (1+ (offset-indentation *ind-offset* :align t)))
608
(indent-macro-reject-left)
612
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
613
;; Assuming previous lines have correct indentation, this allows
614
;; resolving the indentation fastly
615
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
616
;; Line ended with an open brace
618
(< *ind-offset* *ind-start*)
619
((:indent (or :for :while :if :else-if :else :do) :obrace)
621
(setq *indent* (offset-indentation *ind-offset* :resolve t))
622
(indent-macro-reject-left)
624
;; Adjust indentation level if current line starts with an open brace
626
(< *ind-offset* *ind-start* (+ *ind-offset* *ind-length*))
627
;; Just set initial indentation
628
((:indent (or :for :while :if :else-if :else :do) :eol :indent :obrace)
632
(- (offset-indentation *ind-offset* :resolve t) *base-indent*)
634
(and *brace-indent* (incf *indent* *base-indent*))
635
(indent-macro-reject-left)
637
;; Previous rule failed, current line does not start with an open brace
639
;; first statement is in current line
642
(> (+ *ind-offset* *ind-length*) *ind-start* *ind-offset*)
644
((:indent (or :for :while :if :else-if :else :do) :eol :indent)
646
(setq *indent* (offset-indentation *ind-offset* :resolve t))
647
(indent-macro-reject-left)
650
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
651
;; Simplify, remove old (:eol :indent)
652
;; This must be the last rule, to avoid not matching the
653
;; rules for fast calculation of indentation above
654
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
656
(> *ind-offset* c-prev-offset)
663
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
665
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
668
(and (< *ind-offset* *ind-start*)
669
(push c-flow c-if-flow)
670
(incf *indent* *base-indent*)
674
(indresolve (:else-if :else)
676
(while (< c-flow (car c-if-flow))
677
(incf *indent* *base-indent*)
680
(or (eq *ind-token* :else-if) (pop c-if-flow))
682
(and (< *ind-offset* *ind-start*)
683
(incf *indent* *base-indent*)
689
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
691
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
693
(indresolve (:for :while :do)
694
(if (eq *ind-token* :do)
695
(and (< *ind-offset* *ind-start*) (push c-flow c-do-flow))
696
(when (and c-do-flow (eq *ind-token* :while))
697
(while (< c-flow (car c-do-flow))
698
(incf *indent* *base-indent*)
704
(and (< *ind-offset* *ind-start*)
705
(incf *indent* *base-indent*)
711
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
713
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
715
(setq c-case-flag nil)
717
(indresolve (:case :c-case)
718
(if (< *ind-offset* *ind-start*)
722
(+ (offset-indentation *ind-offset* :resolve t)
728
(and (= (decf c-cases) 0)
729
(decf *indent* *base-indent*)
732
(decf *indent* *base-indent*)
740
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
741
;; Braces/flow control
742
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
744
(incf *indent* *base-indent*)
747
(and (< *ind-offset* *ind-start*)
748
(incf *indent* *base-indent*)
752
(decf *indent* *base-indent*)
753
(and *case-indent* c-case-flag
754
(decf *indent* *base-indent*)
755
(setq c-case-flag nil)
757
(and (not *offset*) (>= *ind-offset* *ind-start*)
758
(setq *offset* *ind-offset*)
763
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
765
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
767
(when (< *ind-offset* *ind-start*)
770
*indent* (- *indent* *base-indent*)
777
(< *ind-offset* *ind-start*)
778
(> (+ *ind-offset* *ind-length*) *ind-start*)
779
(incf *indent* *base-indent*)
783
(indresolve :expression
788
(< *ind-offset* *ind-start*)
789
(> (+ *ind-offset* *ind-length*) *ind-start*)
790
(incf *indent* *base-indent*)
794
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
796
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
797
(indresolve (:oparen :obrack)
798
(and (< *ind-offset* *ind-start*)
799
(setq *indent* (1+ (offset-indentation *ind-offset* :align t)))
804
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
805
;; Find a "good" offset to start parsing backwards, so that it should
806
;; always generate the same results.
807
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
808
(defun c-offset-indent (&aux char (point (point)))
809
;; Skip spaces forward
810
(while (member (setq char (char-after point)) indent-spaces)
813
(or (characterp char) (return-from c-offset-indent point))
816
(when (alphanumericp char)
817
(while (and (setq char (char-after point)) (alphanumericp char))
820
(or (characterp char) (return-from c-offset-indent point))
822
;; Skip spaces forward
823
(while (member (setq char (char-after point)) indent-spaces)
826
(or (characterp char) (return-from c-offset-indent point))
829
;; don't include " or ' to avoid parsing strings "inverted"
830
(if (member char '(#\Newline #\" #\')) point (1+ point))
832
(compile 'c-offset-indent)
834
(defun c-should-indent (options)
835
(when (hash-table-p options)
836
;; check if previous line has extra spaces
837
(and (gethash :trim-blank-lines options)
838
(indent-clear-empty-line)
841
;; indentation disabled?
842
(and (gethash :disable-indent options)
843
(return-from c-should-indent)
849
(start (scan point :eol :left))
850
(char (char-before point))
856
;; at the start of an empty file
857
(or (characterp char)
858
(return-from c-should-indent)
861
;; if at bol and should indent only when starting a line
862
(and (gethash :only-newline-indent options)
863
(return-from c-should-indent (= point start))
868
(gethash :newline-after-semi options)
869
(return-from c-should-indent t)
872
;; if one of these was typed, must check indentation
873
(and (member char '(#\{ #\} #\: #\] #\) #\#))
874
(return-from c-should-indent t)
877
;; at the start of a line
879
(return-from c-should-indent (gethash :newline-indent options))
882
;; if first character
883
(and (= point (1+ start))
884
(return-from c-should-indent t)
887
;; check if is the first non-blank character in a new line
890
(gethash :cont-indent options)
891
(= point (scan point :eol :right))
894
(setq offset (1- point))
898
(member (char-before offset) indent-spaces)
902
;; line has only one character with possible spaces before it
903
(and (<= offset start)
904
(return-from c-should-indent t)
908
;; check for keywords that change indentation
909
(when (alphanumericp char)
910
(setq offset (1- point))
913
(alphanumericp (char-before offset))
919
text (read-text offset (- point offset))
920
match (re-exec #.(re-comp "(case|else|while)\\w?\\>")
925
(return-from c-should-indent (<= (- (caar match) offset) 2))
933
(compile 'c-should-indent)
936
(defun c-indent-check (syntax syntable options
937
&aux start point char left brace change)
940
char (char-before point)
942
brace (member char '(#\{ #\}))
946
(and brace (gethash :newline-before-brace options))
947
(setq start (scan point :eol :left))
950
(> (decf left) start)
951
(member (char-before left) indent-spaces)
956
(replace-text left left (string #\Newline))
957
(c-indent syntax syntable)
964
(and brace (not change) (gethash :newline-after-brace options))
965
(and (char= char #\;) (gethash :newline-after-semi options))
968
(replace-text left left (string #\Newline))
969
(goto-char (1+ left))
970
(c-indent syntax syntable)
974
(defun c-indent (syntax syntable)
977
(options (syntax-options syntax))
985
(or (c-should-indent options) (return-from c-indent))
988
*base-indent* (gethash :indentation options 4)
989
*brace-indent* (gethash :brace-indent options nil)
990
*case-indent* (gethash :case-indent options t)
991
*label-dedent* (gethash :label-dedent options t)
992
*cont-indent* (gethash :cont-indent options t)
998
(gethash :emulate-tabs options)
1001
(c-indent-check syntax syntable options)
1006
(defsyntax *c-mode* :main nil #'c-indent *c-mode-options*
1007
;; All recognized C keywords.
1011
"asm|auto|break|case|catch|char|class|const|continue|default|"
1012
"delete|do|double|else|enum|extern|float|for|friend|goto|if|"
1013
"inline|int|long|new|operator|private|protected|public|register|"
1014
"return|short|signed|sizeof|static|struct|switch|template|this|"
1015
"throw|try|typedef|union|unsigned|virtual|void|volatile|while"
1017
:property *prop-keyword*)
1019
;; Numbers, this is optional, comment this rule if xedit is
1020
;; too slow to load c files.
1025
"(\\d+|0x\\x+)(u|ul|ull|l|ll|lu|llu)?|"
1027
"\\d+\\.?\\d*(e[+-]?\\d+)?[lf]?"
1030
:property *prop-number*
1033
;; String start rule.
1034
(syntoken "\"" :nospec t :begin :string :contained t)
1036
;; Character start rule.
1037
(syntoken "'" :nospec t :begin :character :contained t)
1039
;; Preprocessor start rule.
1040
(syntoken "^\\s*#\\s*\\w+" :begin :preprocessor :contained t)
1042
;; Comment start rule.
1043
(syntoken "/*" :nospec t :begin :comment :contained t)
1045
;; C++ style comments.
1046
(syntoken "//.*" :property *prop-comment*)
1048
;; Punctuation, this is also optional, comment this rule if xedit is
1049
;; too slow to load c files.
1050
(syntoken "[][(){}/*+:;=<>,&.!%|^~?-][][(){}*+:;=<>,&.!%|^~?-]?"
1051
:property *prop-punctuation*)
1054
;; Rules for comments.
1055
(syntable :comment *prop-comment* #'default-indent
1056
;; Match nested comments as an error.
1057
(syntoken "/*" :nospec t :property *prop-error*)
1059
(syntoken "XXX|TODO|FIXME" :property *prop-annotation*)
1061
;; Rule to finish a comment.
1062
(syntoken "*/" :nospec t :switch -1)
1065
;; Rules for strings.
1066
(syntable :string *prop-string* #'default-indent
1067
;; Ignore escaped characters, this includes \".
1070
;; Match, most, printf arguments.
1071
(syntoken "%%|%([+-]?\\d+)?(l?[deEfgiouxX]|[cdeEfgiopsuxX])"
1072
:property *prop-format*)
1074
;; Ignore continuation in the next line.
1077
;; Rule to finish a string.
1078
(syntoken "\"" :nospec t :switch -1)
1080
;; Don't allow strings continuing in the next line.
1081
(syntoken ".?$" :begin :error)
1084
;; Rules for characters.
1085
(syntable :character *prop-constant* nil
1086
;; Ignore escaped characters, this includes \'.
1089
;; Ignore continuation in the next line.
1092
;; Rule to finish a character constant.
1093
(syntoken "'" :nospec t :switch -1)
1095
;; Don't allow constants continuing in the next line.
1096
(syntoken ".?$" :begin :error)
1099
;; Rules for preprocessor.
1100
(syntable :preprocessor *prop-preprocessor* #'default-indent
1101
;; Preprocessor includes comments.
1102
(syntoken "/*" :nospec t :begin :comment :contained t)
1104
;; Ignore lines finishing with a backslash.
1107
;; Return to previous state if end of line found.
1108
(syntoken ".?$" :switch -1)
1111
(syntable :error *prop-error* nil
1112
(syntoken "^.*$" :switch -2)
1115
;; You may also want to comment this rule if the parsing is
1117
(syntoken "\\c" :property *prop-control*)