;;; -*-Scheme-*-
;;;
-;;; $Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/c-mode.scm,v 1.47 1991/08/06 15:39:50 arthur Exp $
+;;; $Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/c-mode.scm,v 1.48 1991/10/29 13:44:38 cph Exp $
;;;
;;; Copyright (c) 1986, 1989-91 Massachusetts Institute of Technology
;;;
Comments are delimited with /* ... */.
Paragraphs are separated by blank lines only.
Delete converts tabs to spaces as it moves back.
-The characters { } ; : correct indentation when typed.
Variables controlling indentation style:
+ c-tab-always-indent
+ True means TAB in C mode should always reindent the current line,
+ regardless of where in the line point is when the TAB command is used.
c-auto-newline
- Non-false means automatically newline before and after braces,
+ True means automatically newline before and after braces,
and after colons and semicolons, inserted in C code.
c-indent-level
Indentation of C statements within surrounding block.
c-continued-statement-offset
Extra indentation given to a substatement, such as the
then-clause of an if or body of a while.
+ c-continued-brace-offset
+ Extra indent for substatements that start with open-braces.
+ This is in addition to c-continued-statement-offset.
c-brace-offset
Extra indentation for line if it starts with an open brace.
c-brace-imaginary-offset
c-argdecl-indent
Indentation level of declarations of C function arguments.
c-label-offset
- Extra indentation for line that is a label, or case or default."
+ Extra indentation for line that is a label, or case or default.
+Settings for K&R and BSD indentation styles are
+ c-indent-level 5 8
+ c-continued-statement-offset 5 8
+ c-brace-offset -5 -8
+ c-argdecl-indent 0 8
+ c-label-offset -5 -8"
(local-set-variable! syntax-table c-mode:syntax-table)
(local-set-variable! syntax-ignore-comments-backwards true)
- (local-set-variable! paragraph-start "^$")
+ (local-set-variable! paragraph-start
+ (string-append "^$\\|" (ref-variable page-delimiter)))
(local-set-variable! paragraph-separate (ref-variable paragraph-start))
- (local-set-variable! indent-line-procedure (ref-command c-indent-line))
+ (local-set-variable! paragraph-ignore-fill-prefix true)
+ (local-set-variable! indent-line-procedure (ref-command c-indent-command))
(local-set-variable! require-final-newline true)
- (local-set-variable! comment-locator-hook c-mode:comment-locate)
- (local-set-variable! comment-indent-hook c-mode:comment-indent)
(local-set-variable! comment-start "/* ")
(local-set-variable! comment-end " */")
(local-set-variable! comment-column 32)
+ (local-set-variable! comment-locator-hook c-mode:comment-locate)
+ (local-set-variable! comment-indent-hook c-mode:comment-indent)
(event-distributor/invoke! (ref-variable c-mode-hook)))
-
+\f
(define-variable c-mode-hook
"An event distributor that is invoked when entering C mode."
(make-event-distributor))
-(define-key 'c #\linefeed 'reindent-then-newline-and-indent)
-(define-key 'c #\) 'lisp-insert-paren)
-(define-key 'c #\{ 'electric-c-brace)
-(define-key 'c #\} 'electric-c-brace)
-(define-key 'c #\; 'electric-c-semi)
-(define-key 'c #\: 'electric-c-terminator)
-(define-key 'c #\c-m-h 'mark-c-procedure)
-(define-key 'c #\c-m-q 'c-indent-expression)
-(define-key 'c #\rubout 'backward-delete-char-untabify)
-(define-key 'c #\tab 'c-indent-line)
-
(define c-mode:syntax-table (make-syntax-table))
(modify-syntax-entry! c-mode:syntax-table #\\ "\\")
(modify-syntax-entry! c-mode:syntax-table #\/ ". 14")
(modify-syntax-entry! c-mode:syntax-table #\% ".")
(modify-syntax-entry! c-mode:syntax-table #\< ".")
(modify-syntax-entry! c-mode:syntax-table #\> ".")
+(modify-syntax-entry! c-mode:syntax-table #\& ".")
+(modify-syntax-entry! c-mode:syntax-table #\| ".")
(modify-syntax-entry! c-mode:syntax-table #\' "\"")
-\f
+
(define (c-mode:comment-locate start)
- (and (re-search-forward "/\\*[ \t]*" start (line-end start 0))
+ (and (re-search-forward "/\\*+ *" start (line-end start 0))
(cons (re-match-start 0) (re-match-end 0))))
(define (c-mode:comment-indent start)
(if (re-match-forward "^/\\*" start (line-end start 0))
0
- (max (1+ (mark-column (horizontal-space-start start)))
- (ref-variable comment-column))))
+ (max (+ (mark-column (horizontal-space-start start)) 1)
+ (ref-variable comment-column start))))
(define-variable c-auto-newline
- "Non-false means automatically newline before and after braces,
+ "True means automatically newline before and after braces,
and after colons and semicolons, inserted in C code."
- false)
+ false
+ boolean?)
+(define-variable c-tab-always-indent
+ "True means TAB in C mode should always reindent the current line,
+regardless of where in the line point is when the TAB command is used."
+ true
+ boolean?)
+
+(define-key 'c #\linefeed 'reindent-then-newline-and-indent)
+(define-key 'c #\) 'lisp-insert-paren)
+(define-key 'c #\{ 'electric-c-brace)
+(define-key 'c #\} 'electric-c-brace)
+(define-key 'c #\; 'electric-c-semi)
+(define-key 'c #\: 'electric-c-terminator)
+(define-key 'c #\c-m-h 'mark-c-procedure)
+(define-key 'c #\c-m-q 'indent-c-exp)
+(define-key 'c #\rubout 'backward-delete-char-untabify)
+(define-key 'c #\tab 'c-indent-command)
+\f
(define-command electric-c-brace
"Insert character and correct line's indentation."
"P"
(lambda (argument)
- (let ((point (current-point)))
+ (let ((point (current-point))
+ (char (last-command-key)))
(if (and (not argument)
(line-end? point)
(or (line-blank? point)
(and (ref-variable c-auto-newline)
(begin
- ((ref-command c-indent-line) false)
+ ((ref-command c-indent-command) false)
(insert-newline)
true))))
(begin
- ((ref-command self-insert-command) false)
- ((ref-command c-indent-line) false)
+ (insert-char char)
+ ((ref-command c-indent-command) false)
(if (ref-variable c-auto-newline)
(begin
(insert-newline)
- ((ref-command c-indent-line) false))))
+ ((ref-command c-indent-command) false))))
((ref-command self-insert-command) false))
- (if (eqv? #\} (current-command-key))
+ (if (eqv? #\} char)
(mark-flash (backward-one-sexp (current-point)) 'RIGHT)))))
(define-command electric-c-semi
"Insert character and correct line's indentation."
"P"
(lambda (argument)
- (let ((point (current-point)))
+ (let ((point (current-point))
+ (char (last-command-key)))
(if (and (not argument)
(line-end? point)
(not (let ((mark (indentation-end point)))
(or (char-match-forward #\# mark)
- (let ((state (parse-partial-sexp mark point)))
+ ;; Colon is special only after a label, or
+ ;; case. So quickly rule out most other
+ ;; uses of colon and do no indentation for
+ ;; them.
+ (and (eqv? #\: char)
+ (not (re-match-forward "case\\b"
+ mark
+ (line-end mark 0)
+ false))
+ (mark< (skip-chars-forward
+ " \t"
+ (forward-word mark 1))
+ point))
+ (let ((state
+ (parse-partial-sexp
+ (backward-definition-start point 1 'LIMIT)
+ point)))
(or (parse-state-in-string? state)
(parse-state-in-comment? state)
(parse-state-quoted? state)))))))
(begin
- ((ref-command self-insert-command) false)
- ((ref-command c-indent-line) false)
+ (insert-char char)
+ ((ref-command c-indent-command) false)
(if (and (ref-variable c-auto-newline)
(not (c-inside-parens? point)))
(begin
(insert-newline)
- ((ref-command c-indent-line) false))))
+ ((ref-command c-indent-command) false))))
((ref-command self-insert-command) argument)))))
+
+(define (c-inside-parens? mark)
+ (let ((container (backward-up-list mark 1 false)))
+ (and container
+ (mark>= container (backward-definition-start mark 1 'LIMIT))
+ (char-match-forward #\( container))))
\f
(define-command mark-c-procedure
"Put mark at end of C procedure, point at beginning."
1
'LIMIT)))))
-(define-command c-indent-line
- "Indent current line as C code.
-Argument means shift any additional lines of grouping
-rigidly with this line."
+(define-command c-indent-command
+ "Indent current line as C code, or in some cases insert a tab character.
+If c-tab-always-indent is true (the default), always indent current line.
+Otherwise, indent the current line only if point is at the left margin
+or in the line's indentation; otherwise insert a tab.
+
+A numeric argument, regardless of its value,
+means indent rigidly all the lines of the expression starting after point
+so that this line becomes properly indented.
+The relative indentation among the lines of the expression are preserved."
"P"
(lambda (#!optional argument)
- (let ((argument (and (not (default-object? argument)) argument))
- (start (line-start (current-point) 0)))
- (let ((indentation (c-indent-line:indentation start)))
- (let ((shift-amount (- indentation (mark-indentation start))))
- (cond ((not (zero? shift-amount))
- (change-indentation indentation start)
- (if argument
- (indent-code-rigidly start
- (forward-sexp start 1 'ERROR)
- shift-amount
- "#")))
- ((within-indentation? (current-point))
- (set-current-point! (indentation-end (current-point))))))))))
-
-(define-command c-indent-expression
+ (let ((point (current-point)))
+ (cond ((and (not (default-object? argument)) argument)
+ (let ((shift-amount (c-indent-line point))
+ (start
+ (if (ref-variable c-tab-always-indent)
+ (line-start point 0)
+ point)))
+ (indent-code-rigidly start
+ (forward-sexp start 1 'ERROR)
+ shift-amount
+ "#")))
+ ((or (ref-variable c-tab-always-indent)
+ (within-indentation? point))
+ (c-indent-line point))
+ (else
+ ((ref-command insert-tab)))))))
+
+(define-command indent-c-exp
"Indent each line of the C grouping following point."
()
(lambda ()
;;; -*-Scheme-*-
;;;
-;;; $Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/cinden.scm,v 1.5 1991/04/21 00:49:09 cph Exp $
+;;; $Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/edwin/cinden.scm,v 1.6 1991/10/29 13:44:22 cph Exp $
;;;
;;; Copyright (c) 1986, 1989-91 Massachusetts Institute of Technology
;;;
\f
(define-variable c-indent-level
"Indentation of C statements with respect to containing block."
- 2)
-
-(define-variable c-brace-offset
- "Extra indentation for braces, compared with other text in same context."
- 0)
+ 2
+ exact-integer?)
(define-variable c-brace-imaginary-offset
"Imagined indentation of a C open brace that actually follows a statement."
- 0)
+ 0
+ exact-integer?)
+
+(define-variable c-brace-offset
+ "Extra indentation for braces, compared with other text in same context."
+ 0
+ exact-integer?)
(define-variable c-argdecl-indent
"Indentation level of declarations of C function arguments."
- 5)
+ 5
+ exact-integer?)
(define-variable c-label-offset
"Offset of C label lines and case statements relative to usual indentation."
- -2)
+ -2
+ exact-integer?)
(define-variable c-continued-statement-offset
"Extra indent for lines not starting new statements."
- 2)
+ 2
+ exact-integer?)
+(define-variable c-continued-brace-offset
+ "Extra indent for substatements that start with open-braces.
+This is in addition to c-continued-statement-offset."
+ 0
+ exact-integer?)
+\f
(define (c-indent-line start)
- (maybe-change-indentation (c-indent-line:indentation start) start))
-
-(define (c-indent-line:indentation start)
- (with-variable-value! (ref-variable-object case-fold-search) false
- (lambda ()
- (let ((indentation (calculate-indentation start false)))
- (cond ((not indentation) (mark-indentation start))
- ((eq? indentation true)
- ;; Inside a comment; indentation of line depends on
- ;; whether or not it starts with a *.
- (mark-column
- (let ((end (whitespace-start start (group-start start))))
- (let ((iend (indentation-end end)))
- (let ((comstart (re-search-forward "/\\*[ \t]*" iend end)))
- (cond ((not comstart) iend)
- ((re-match-forward "[ \t]*\\*" start)
+ (let* ((start (line-start start 0))
+ (old-indentation (mark-indentation start))
+ (new-indentation
+ (let ((indentation (calculate-indentation start false)))
+ (cond ((not indentation)
+ old-indentation)
+ ((eq? indentation true)
+ ;; Inside a comment.
+ (mark-column
+ (let* ((star?
+ (char-match-forward #\* (indentation-end start)))
+ (pend (whitespace-start start (group-start start)))
+ (pstart (indentation-end pend))
+ (comment-start
+ (and (mark< pstart pend)
+ (re-search-forward "/\\*[ \t]*" pstart pend
+ false))))
+ (cond ((not comment-start)
+ pstart)
+ (star?
(mark1+ (re-match-start 0)))
- (else comstart)))))))
- ((char-match-forward #\# start) 0)
- (else
- (indent-line:adjust-indentation (horizontal-space-end start)
- indentation)))))))
+ (else
+ comment-start)))))
+ ((char-match-forward #\# start)
+ 0)
+ (else
+ (indent-line:adjust-indentation (horizontal-space-end start)
+ indentation))))))
+ (if (not (= new-indentation old-indentation))
+ (change-indentation new-indentation start))
+ (- new-indentation old-indentation)))
(define (indent-line:adjust-indentation start indentation)
- (cond ((or (re-match-forward "case\\b" start)
+ (cond ((or (looking-at-keyword? "case" start)
(and (re-match-forward "[A-Za-z]" start)
- (char-match-forward #\: (forward-one-sexp start))))
- (max 1 (+ indentation (ref-variable c-label-offset))))
- ((re-match-forward "else\\b" start)
+ (char-match-forward #\: (forward-sexp start 1 'LIMIT))))
+ (max 1 (+ indentation (ref-variable c-label-offset start))))
+ ((looking-at-keyword? "else" start)
(mark-indentation
- (backward-to-start-of-if start
- (backward-one-definition-start start))))
+ (backward-to-start-of-if
+ start
+ (backward-definition-start start 1 'LIMIT))))
((char-match-forward #\} start)
- (- indentation (ref-variable c-indent-level)))
+ (- indentation (ref-variable c-indent-level start)))
((char-match-forward #\{ start)
- (+ indentation (ref-variable c-brace-offset)))
+ (+ indentation (ref-variable c-brace-offset start)))
(else indentation)))
\f
(define (calculate-indentation mark parse-start)
- (let ((gstart (group-start mark))
- (indent-point (line-start mark 0)))
- (define (find-outer-container start)
- (let ((state (parse-partial-sexp start indent-point 0)))
- (if (mark= (parse-state-location state) indent-point)
- state
- (find-outer-container (parse-state-location state)))))
+ (let ((indent-point (line-start mark 0)))
(let ((state
- (find-outer-container (or parse-start
- (backward-one-definition-start mark)
- gstart))))
- (if (or (parse-state-in-string? state)
- (parse-state-in-comment? state))
- ;; Return boolean if line should not be changed.
- (not (not (parse-state-in-comment? state)))
- (let ((container (parse-state-containing-sexp state)))
- (cond ((not container)
- ;; Line is at top level. Discriminate between
- ;; procedure definition and other cases.
- (if (re-match-forward "[ \t]*{" indent-point)
- 0
- ;; May be data definition, or may be function
- ;; argument declaration. Indent like the
- ;; previous top level line unless that ends
- ;; in a closeparen without semicolon, in
- ;; which case this line is the first argument
- ;; decl.
- (let ((mark
- (backward-to-noncomment indent-point
- (or parse-start
- gstart))))
- (if (char-match-backward #\) mark)
- (ref-variable c-argdecl-indent)
- (mark-indentation mark)))))
- ((char-match-forward #\{ container)
- (calculate-indentation:statement indent-point container))
- (else
- ;; Line is expression, not statement: indent to just
- ;; after the surrounding open.
- (mark-column (mark1+ container)))))))))
+ (let loop
+ ((start
+ (or parse-start (backward-definition-start mark 1 'LIMIT))))
+ (let ((state (parse-partial-sexp start indent-point 0)))
+ (if (mark= (parse-state-location state) indent-point)
+ state
+ (loop (parse-state-location state)))))))
+ (let ((container (parse-state-containing-sexp state)))
+ (cond ((parse-state-in-string? state)
+ false)
+ ((parse-state-in-comment? state)
+ true)
+ ((not container)
+ (calculate-indentation:top-level indent-point
+ (or parse-start
+ (group-start mark))))
+ ((char-match-forward #\{ container)
+ (calculate-indentation:statement indent-point container))
+ (else
+ ;; Line is expression, not statement: indent to just
+ ;; after the surrounding open.
+ (mark-column (mark1+ container))))))))
+(define (calculate-indentation:top-level indent-point parse-start)
+ (let ((gend (group-end indent-point)))
+ ;; Discriminate between procedure definition and other cases.
+ (if (re-match-forward "[ \t]*{" indent-point gend false)
+ 0
+ ;; May be data definition, or may be function argument
+ ;; declaration. Indent like the previous top level line
+ ;; unless that ends in a closeparen without semicolon, in
+ ;; which case this line is the first argument decl.
+ (let* ((mark (backward-to-noncomment indent-point parse-start))
+ ;; Look at previous line that's at column zero to
+ ;; determine whether we are in top-level decls or
+ ;; function's arg decls. Set basic-indent accordingly.
+ (basic-indent
+ (let ((m
+ (and mark
+ (re-search-backward "^[ \t\n\f#]"
+ mark
+ (group-start indent-point)
+ false))))
+ (if (and m
+ (re-match-forward "\\sw\\|\\s_" m gend false)
+ (re-match-forward ".*(" m gend false)
+ (let ((m
+ (forward-sexp (mark-1+ (re-match-end 0)) 1)))
+ (and m
+ (mark< m indent-point)
+ (not (re-match-forward "[ \t\n]*[,;]"
+ m gend false)))))
+ (ref-variable c-argdecl-indent indent-point)
+ 0))))
+ (if (or (not mark) (memv (extract-left-char mark) '(#F #\) #\; #\})))
+ basic-indent
+ (+ basic-indent
+ (ref-variable c-continued-statement-offset indent-point)))))))
+\f
(define (calculate-indentation:statement indent-point container)
- (let ((mark (backward-to-noncomment indent-point container)))
- (if (and mark
- (re-match-forward "[^,;:{}]" (mark-1+ mark)))
+ (let ((mark
+ (let loop ((start indent-point))
+ (let ((m (backward-to-noncomment start container)))
+ ;; Back up over label lines, since they don't affect
+ ;; whether our line is a continuation.
+ (case (and m (mark> m container) (extract-left-char m))
+ ((#\:)
+ (if (let ((m (backward-to-noncomment (mark-1+ m) container)))
+ (and m
+ (mark> m container)
+ (re-match-forward "'\\|\\sw\\|\\s_" (mark-1+ m))))
+ (loop (line-start m 0))
+ m))
+ ((#\,)
+ (loop
+ (line-start (backward-to-start-of-continued-exp m container)
+ 0)))
+ (else m))))))
+ (if (and mark (not (memv (extract-left-char mark) '(#F #\, #\; #\{ #\}))))
;; This line is continuation of preceding line's statement;
- ;; indent C Continued Statement Offset more than the previous
+ ;; indent c-continued-statement-offset more than the previous
;; line of the statement.
- (+ (ref-variable c-continued-statement-offset)
- (mark-column (backward-to-start-of-continued-exp mark container)))
- (let ((mark (skip-comments&labels (mark1+ container) indent-point)))
- (if (not mark)
- ;; If this is first statement after open brace, indent
- ;; it relative to line brace is on. For open brace in
- ;; column zero, don't let statement start there too. If
- ;; C Indent Level is zero, use C Brace Offset + C
- ;; Continued Statement Offset instead. For open-braces
- ;; not the first thing in a line, add in C Brace
- ;; Imaginary Offset.
- (+ (if (and (line-start? container)
- (zero? (ref-variable c-indent-level)))
- (+ (ref-variable c-brace-offset)
- (ref-variable c-continued-statement-offset))
- (ref-variable c-indent-level))
- (+ (if (within-indentation? container)
+ (+ (ref-variable c-continued-statement-offset indent-point)
+ (mark-column (backward-to-start-of-continued-exp mark container))
+ (if (re-match-forward "[ \t]*{" indent-point)
+ (ref-variable c-continued-brace-offset indent-point)
+ 0))
+ (or (skip-comments&labels (mark1+ container) indent-point)
+ ;; If no previous statement, indent it relative to line
+ ;; brace is on. For open brace in column zero, don't let
+ ;; statement start there too. If c-indent-level is zero,
+ ;; use c-brace-offset + c-continued-statement-offset
+ ;; instead. For open-braces not the first thing in a
+ ;; line, add in c-brace-imaginary-offset.
+ (+ (if (and (line-start? container)
+ (= 0 (ref-variable c-indent-level indent-point)))
+ (+ (ref-variable c-brace-offset indent-point)
+ (ref-variable c-continued-statement-offset indent-point))
+ (ref-variable c-indent-level indent-point))
+ (let ((container (skip-chars-backward " \t" container)))
+ ;; If open brace is not the first non-white thing on
+ ;; the line, add the c-brace-imaginary-offset.
+ (+ (if (line-start? container)
0
- (ref-variable c-brace-imaginary-offset))
- (mark-indentation container)))
- ;; Otherwise, indent under that first statement.
- (mark-column mark))))))
-\f
-(define (skip-comments&labels start end)
- (define (phi1 mark)
- (cond ((mark= mark end) false)
- ((char-match-forward #\# mark)
- (phi2 (line-start mark 1)))
- ((match-forward "/*" mark)
- (phi2 (search-forward "*/" mark end)))
- ((re-match-forward "case[ \t\n]\\|[a-zA-Z0-9_$]*:" mark)
- (phi2 (char-search-forward #\: mark end)))
- (else mark)))
+ (ref-variable c-brace-imaginary-offset indent-point))
+ (mark-indentation
+ ;; If the open brace is preceded by a
+ ;; parenthesized expression, move to the
+ ;; beginning of that; possibly a different line.
+ (if (eqv? #\) (extract-left-char container))
+ (backward-sexp container 1 'LIMIT)
+ container)))))))))
- (define (phi2 mark)
- (and mark
- (phi1 (whitespace-end mark end))))
-
- (phi1 (whitespace-end start end)))
+(define (skip-comments&labels start end)
+ (let ((gend (group-end start)))
+ (let loop ((mark start) (colon-line-end 0))
+ (let ((mark (whitespace-end mark gend)))
+ (cond ((mark>= mark end)
+ false)
+ ((char-match-forward #\# mark)
+ (loop (line-start mark 1 'LIMIT) colon-line-end))
+ ((match-forward "/*" mark)
+ (loop (or (search-forward "*/" mark gend) gend) colon-line-end))
+ ((re-match-forward "case[ \t\n].*:\\|[a-zA-Z0-9_$]*[ \t\n]*:"
+ mark gend false)
+ (loop (re-match-end 0) (line-end mark 0)))
+ ((mark> colon-line-end mark)
+ (- (mark-indentation mark)
+ (ref-variable c-label-offset mark)))
+ (else
+ (mark-column mark)))))))
+\f
+(define (c-indent-expression expression-start)
+ (let ((end
+ (mark-left-inserting-copy
+ (line-start (forward-sexp expression-start 1 'ERROR) 0))))
+ (let loop
+ ((start expression-start)
+ (state false)
+ (indent-stack (list false))
+ (contain-stack (list expression-start))
+ (last-depth 0))
+ (with-values (lambda () (c-indent-expression:parse-line start end state))
+ (lambda (start state)
+ (let* ((depth (parse-state-depth state))
+ (depth-delta (- depth last-depth))
+ (indent-stack (adjust-stack depth-delta indent-stack))
+ (contain-stack (adjust-stack depth-delta contain-stack))
+ (indent-line
+ (lambda ()
+ (if (not (line-blank? start))
+ (c-indent-expression:per-line
+ (skip-chars-forward " \t" start)
+ expression-start
+ indent-stack
+ contain-stack)))))
+ (if (not (car contain-stack))
+ (set-car! contain-stack
+ (or (parse-state-containing-sexp state)
+ (backward-sexp start 1 'LIMIT))))
+ (if (mark= start end)
+ (begin
+ (mark-temporary! end)
+ (indent-line))
+ (begin
+ (indent-line)
+ (loop start state indent-stack contain-stack depth)))))))))
+(define (c-indent-expression:parse-line start end state)
+ (let loop ((start start) (state state))
+ (let ((start* (line-start start 1)))
+ (let ((state*
+ (parse-partial-sexp start start* false false state)))
+ (if (and state (parse-state-in-comment? state))
+ (c-indent-line start))
+ (cond ((mark= start* end)
+ (values start* state*))
+ ((parse-state-in-comment? state*)
+ (if (not (and state (parse-state-in-comment? state)))
+ (if (re-search-forward "/\\*[ \t]*" start start* false)
+ (c-mode:comment-indent (re-match-start 0))
+ (error "Missing comment")))
+ (loop start* state*))
+ ((parse-state-in-string? state*)
+ (loop start* state*))
+ (else
+ (values start* state*)))))))
+\f
+(define (c-indent-expression:per-line start expression-start
+ indent-stack contain-stack)
+ (let ((indentation
+ (indent-line:adjust-indentation
+ start
+ (cond ((not (car indent-stack))
+ (let ((indentation (calculate-indentation start false)))
+ (set-car! indent-stack indentation)
+ indentation))
+ ((not (char-match-forward #\{ (car contain-stack)))
+ (car indent-stack))
+ (else
+ ;; Line is at statement level. Is it a new
+ ;; statement? Is it an else? Find last non-comment
+ ;; character before this line.
+ (let ((mark (backward-to-noncomment start expression-start)))
+ (cond ((not (memv (extract-left-char mark)
+ '(#F #\, #\; #\} #\: #\{)))
+ (+ (ref-variable c-continued-statement-offset mark)
+ (mark-column
+ (backward-to-start-of-continued-exp
+ mark
+ (car contain-stack)))
+ (if (char-match-forward #\{ start)
+ (ref-variable c-continued-brace-offset mark)
+ 0)))
+ ((looking-at-keyword? "else" start)
+ (mark-indentation
+ (backward-to-start-of-if mark expression-start)))
+ (else
+ (car indent-stack)))))))))
+ (if (not (char-match-forward #\# start))
+ (maybe-change-indentation indentation start))))
+\f
(define (whitespace-start start end)
(skip-chars-backward " \t\n" start end))
(define (whitespace-end start end)
(skip-chars-forward " \t\n" start end))
-(define (c-inside-parens? mark)
- (let ((container (backward-up-one-list mark)))
- (and container
- (mark>= container (backward-one-definition-start mark))
- (char-match-forward #\( container))))
+(define (looking-at-keyword? keyword start)
+ (let ((end (line-end start 0)))
+ (and (re-match-forward (string-append keyword "\\b") start end false)
+ (not (re-match-forward (string-append keyword "\\s_") start end
+ false)))))
(define (backward-to-noncomment start end)
(let loop ((start start))
(define (backward-to-start-of-continued-exp start end)
(let ((mark
(line-start (if (char-match-backward #\) start)
- (backward-one-sexp start)
+ (backward-sexp start 1 'LIMIT)
start)
0)))
(horizontal-space-end (if (mark<= mark end) (mark1+ end) mark))))
(define (backward-to-start-of-if start end)
- (define (phi2 mark if-level)
- (define (phi1 if-level)
- (if (zero? if-level)
- mark
- (phi2 (backward-sexp mark 1 'LIMIT) if-level)))
- (cond ((re-match-forward "else\\b" mark)
- (phi1 (1+ if-level)))
- ((re-match-forward "if\\b" mark)
- (phi1 (-1+ if-level)))
- ((mark>= mark end)
- (phi1 if-level))
- (else end)))
- (phi2 (backward-sexp start 1 'LIMIT) 1))
-\f
-(define (c-indent-expression expression-start)
- (with-variable-value! (ref-variable-object case-fold-search) false
- (lambda ()
- (let ((end
- (mark-left-inserting
- (line-start (forward-sexp expression-start 1 'ERROR) 0))))
- (define (loop start indent-stack contain-stack last-depth)
- (next-line-start start false
- (lambda (start state)
- (let ((depth-delta (- (parse-state-depth state) last-depth)))
- (let ((indent-stack (adjust-stack depth-delta indent-stack))
- (contain-stack (adjust-stack depth-delta contain-stack)))
- (if (not (car contain-stack))
- (set-car! contain-stack
- (or (parse-state-containing-sexp state)
- (backward-one-sexp start))))
- (if (not (line-blank? start))
- (indent-line start indent-stack contain-stack))
- (if (not (mark= start end))
- (loop start indent-stack contain-stack
- (parse-state-depth state))))))))
-
- (define (next-line-start start state receiver)
- (let loop ((start start) (state state))
- (let ((start* (line-start start 1)))
- (let ((state*
- (parse-partial-sexp start start* false false state)))
- (if (and state (parse-state-in-comment? state))
- (c-indent-line start))
- (cond ((mark= start* end)
- (receiver start* state*))
- ((parse-state-in-comment? state*)
- (if (not (and state (parse-state-in-comment? state)))
- (if (re-search-forward "/\\*[ \t]*" start start*)
- (c-mode:comment-indent (re-match-start 0))
- (error "C-Indent-Expression: Missing comment")))
- (loop start* state*))
- ((parse-state-in-string? state*)
- (loop start* state*))
- (else
- (receiver start* state*)))))))
-
- (define (indent-line start indent-stack contain-stack)
- (let ((indentation
- (indent-line:adjust-indentation
- start
- (if (car indent-stack)
- (if (char-match-forward #\{ (car contain-stack))
- ;; Line is at statement level. Is it a new
- ;; statement? Is it an else? Find last
- ;; non-comment character before this line.
- (let ((mark
- (backward-to-noncomment
- start expression-start)))
- (cond ((not (memv (extract-left-char mark)
- '(#F #\. #\; #\} #\:)))
- (+ (ref-variable
- c-continued-statement-offset)
- (mark-column
- (backward-to-start-of-continued-exp
- mark (car contain-stack)))))
- ((re-match-forward "else\\b" start)
- (mark-indentation
- (backward-to-start-of-if
- mark
- expression-start)))
- (else (car indent-stack))))
- (car indent-stack))
- (let ((indentation (calculate-indentation start false)))
- (set-car! indent-stack indentation)
- indentation)))))
- (if (not (or (= indentation (mark-indentation start))
- (re-match-forward "[ \t]*#" start)))
- (change-indentation indentation start))))
-
- (loop expression-start (list false) (list expression-start) 0)))))
-\f
-(define (adjust-stack depth-delta indent-stack)
- (cond ((zero? depth-delta) indent-stack)
- ((positive? depth-delta) (up-stack depth-delta indent-stack))
- (else (down-stack depth-delta indent-stack))))
-
-(define (down-stack n stack)
- (if (= -1 n)
- (cdr stack)
- (down-stack (1+ n) (cdr stack))))
+ (let loop ((mark start) (if-level 1))
+ (let ((mark (backward-sexp mark 1 'LIMIT)))
+ (let ((adjust-level
+ (lambda (if-level)
+ (if (= if-level 0)
+ mark
+ (loop mark if-level)))))
+ (cond ((looking-at-keyword? "else" mark)
+ (adjust-level (+ if-level 1)))
+ ((looking-at-keyword? "if" mark)
+ (adjust-level (- if-level 1)))
+ ((mark>= mark end)
+ (adjust-level if-level))
+ (else
+ end))))))
-(define (up-stack n stack)
- (if (= 1 n)
- (cons false stack)
- (up-stack (-1+ n) (cons false stack))))
\ No newline at end of file
+(define (adjust-stack depth-delta stack)
+ (cond ((= depth-delta 0)
+ stack)
+ ((> depth-delta 0)
+ (let loop ((depth-delta depth-delta) (stack stack))
+ (if (= 1 depth-delta)
+ (cons false stack)
+ (loop (- depth-delta 1) (cons false stack)))))
+ (else
+ (let loop ((depth-delta depth-delta) (stack stack))
+ (if (= -1 depth-delta)
+ (cdr stack)
+ (loop (+ depth-delta 1) (cdr stack)))))))
\ No newline at end of file