(define-key c-mode-map "\ea" 'c-beginning-of-statement)
(define-key c-mode-map "\ee" 'c-end-of-statement)
(define-key c-mode-map "\eq" 'c-fill-paragraph)
+ (define-key c-mode-map "\C-c\C-n" 'c-forward-conditional)
+ (define-key c-mode-map "\C-c\C-p" 'c-backward-conditional)
+ (define-key c-mode-map "\C-c\C-u" 'c-up-conditional)
(define-key c-mode-map "\177" 'backward-delete-char-untabify)
(define-key c-mode-map "\t" 'c-indent-command))
;; Make sure the "function decl" we found
;; is not inside a comment.
(progn
+ ;; Move back to the `(' starting arglist
+ (goto-char lim)
(beginning-of-line)
(while (and (not comment)
(search-forward "/*" lim t))
(beginning-of-defun)
(backward-paragraph))
\f
+;; Idea of ENDPOS is, indent each line, stopping when
+;; ENDPOS is encountered. But it's too much of a pain to make that work.
(defun indent-c-exp (&optional endpos)
- "Indent each line of the C grouping following point.
-If optional arg ENDPOS is given, indent each line, stopping when
-ENDPOS is encountered."
+ "Indent each line of the C grouping following point."
(interactive)
(let* ((indent-stack (list nil))
(opoint (point)) ;; May be altered below.
(save-excursion (forward-char 1)
(beginning-of-defun)
(setq funbeg (point)))
+ (setq opoint funbeg)
;; Try to find containing open,
;; but don't scan past that fcn-start.
(save-restriction
(narrow-to-region funbeg (point))
(condition-case nil
(save-excursion
- (backward-up-list 1) (point))
+ (backward-up-list 1)
+ (point))
;; We gave up: must be between fcns.
;; Set opoint to beg of prev fcn
;; since otherwise calculate-c-indent
restart outer-loop-done inner-loop-done state ostate
this-indent last-sexp
at-else at-brace at-while
- last-depth
+ last-depth this-point
(next-depth 0))
;; If the braces don't match, get an error right away.
(save-excursion
(and (re-search-forward
comment-start-skip
(save-excursion (end-of-line) (point)) t)
+ ;; Make sure this isn't a comment alone on a line
+ ;; (which should be indented like code instead).
+ (save-excursion
+ (goto-char (match-beginning 0))
+ (skip-chars-backward " \t")
+ (not (bolp)))
;; Make sure the comment starter we found
;; is not actually in a string or quoted.
(let ((new-state
(if (and (car (cdr (cdr state)))
(>= (car (cdr (cdr state))) 0))
(setq last-sexp (car (cdr (cdr state)))))
- (if (or (nth 4 ostate))
+ ;; If this line started within a comment, indent it as such.
+ (if (or (nth 4 ostate) (nth 7 ostate))
(c-indent-line))
- (if (or (nth 3 state))
+ ;; If it ends outside of comments or strings, exit the inner loop.
+ ;; Otherwise move on to next line.
+ (if (or (nth 3 state) (nth 4 state) (nth 7 state))
(forward-line 1)
(setq inner-loop-done t)))
(and endpos
(point)))))
(forward-line 1)
(skip-chars-forward " \t")
- (if (eolp)
+ ;; Don't really reindent if the line is just whitespace,
+ ;; or if it is past the endpos.
+ ;; (The exit test in the outer while
+ ;; does not exit until we have passed the first line
+ ;; past the region.)
+ (if (or (eolp) (and endpos (>= (point) endpos)))
nil
(if (and (car indent-stack)
(>= (car indent-stack) 0))
;; Is it a new statement? Is it an else?
;; Find last non-comment character before this line
(save-excursion
+ (setq this-point (point))
(setq at-else (looking-at "else\\W"))
(setq at-brace (= (following-char) ?{))
(setq at-while (looking-at "while\\b"))
(current-indentation))))
((and at-while (c-backward-to-start-of-do opoint))
(setq this-indent (current-indentation)))
+ ((eq (preceding-char) ?\,)
+ (goto-char this-point)
+ (setq this-indent (calculate-c-indent)))
(t (setq this-indent (car indent-stack)))))))
;; Just started a new nesting level.
;; Compute the standard indent for this level.
(if (car indent-stack)
(- (car indent-stack))
opoint))))
+ ;; t means we are in a block comment and should
+ ;; calculate accordingly.
+ (if (eq val t)
+ (setq val (calculate-c-indent-within-comment)))
(setcar indent-stack
(setq this-indent val))))
;; Adjust line indentation according to its contents
(if (= (following-char) ?})
(setq this-indent (- this-indent c-indent-level)))
(if (= (following-char) ?{)
- (setq this-indent (+ this-indent c-brace-offset)))
+ ;; Don't move an open-brace in column 0.
+ ;; This is good when constructs such as
+ ;; `extern "C" {' surround a function definition
+ ;; that should be indented as usual.
+ ;; It is also good for nested functions.
+ ;; It is bad when an open-brace is indented at column 0
+ ;; and you want to fix that, but we can't win 'em all.
+ (if (zerop (current-column))
+ (setq this-indent 0)
+ (setq this-indent (+ this-indent c-brace-offset))))
;; Don't leave indentation in empty lines.
(if (eolp) (setq this-indent 0))
;; Put chosen indentation into effect.
(defun c-indent-region (start end)
(save-excursion
(goto-char start)
- (let ((endmark (copy-marker end)))
- (and (bolp) (not (eolp))
- (c-indent-line))
- (indent-c-exp endmark)
+ ;; Advance to first nonblank line.
+ (skip-chars-forward " \t\n")
+ (beginning-of-line)
+ (let ((endmark (copy-marker end))
+ (c-tab-always-indent t))
+ (while (and (bolp) (not (eolp)))
+ ;; Indent one line as with TAB.
+ (let ((shift-amt (c-indent-line))
+ nextline sexpbeg sexpend)
+ (save-excursion
+ ;; Find beginning of following line.
+ (save-excursion
+ (forward-line 1) (setq nextline (point)))
+ ;; Find first beginning-of-sexp for sexp extending past this line.
+ (beginning-of-line)
+ (while (< (point) nextline)
+ (condition-case nil
+ (progn
+ (forward-sexp 1)
+ (setq sexpend (point-marker)))
+ (error (setq sexpend nil)
+ (goto-char nextline)))
+ (skip-chars-forward " \t\n"))
+ (if sexpend
+ (progn
+ ;; Make sure the sexp we found really starts on the
+ ;; current line and extends past it.
+ (goto-char sexpend)
+ (backward-sexp 1)
+ (setq sexpbeg (point)))))
+ ;; If that sexp ends within the region,
+ ;; indent it all at once, fast.
+ (if (and sexpend (> sexpend nextline) (<= sexpend endmark)
+ (< sexpbeg nextline))
+ (progn
+ (indent-c-exp)
+ (goto-char sexpend)))
+ ;; Move to following line and try again.
+ (and sexpend (set-marker sexpend nil))
+ (forward-line 1)))
(set-marker endmark nil))))
\f
(defun set-c-style (style &optional global)
When going backwards, `#elif' is treated like `#else' followed by `#if'.
When going forwards, `#elif' is ignored."
(interactive "p")
- (let* ((forward (< count 0))
+ (c-forward-conditional (- count) t))
+
+(defun c-backward-conditional (count &optional up-flag)
+ "Move back across a preprocessor conditional, leaving mark behind.
+A prefix argument acts as a repeat count. With a negative argument,
+move forward across a preprocessor conditional."
+ (interactive "p")
+ (c-forward-conditional (- count) up-flag))
+
+(defun c-forward-conditional (count &optional up-flag)
+ "Move forward across a preprocessor conditional, leaving mark behind.
+A prefix argument acts as a repeat count. With a negative argument,
+move backward across a preprocessor conditional."
+ (interactive "p")
+ (let* ((forward (> count 0))
(increment (if forward -1 1))
(search-function (if forward 're-search-forward 're-search-backward))
(opoint (point))
(new))
(save-excursion
(while (/= count 0)
- (if forward (end-of-line))
- (let ((depth 0) found)
+ (let ((depth (if up-flag 0 -1)) found)
(save-excursion
;; Find the "next" significant line in the proper direction.
(while (and (not found)
(beginning-of-line)
;; Now verify it is really a preproc line.
(if (looking-at "^[ \t]*#[ \t]*\\(if\\|elif\\|endif\\)")
- (progn
+ (let ((prev depth))
;; Update depth according to what we found.
(beginning-of-line)
(cond ((looking-at "[ \t]*#[ \t]*endif")
(if (and forward (= depth 0))
(setq found (point))))
(t (setq depth (- depth increment))))
+ ;; If we are trying to move across, and we find
+ ;; an end before we find a beginning, get an error.
+ (if (and (< prev 0) (< depth prev))
+ (error (if forward
+ "No following conditional at this level"
+ "No previous conditional at this level")))
+ ;; When searching forward, start from next line
+ ;; so that we don't find the same line again.
+ (if forward (forward-line 1))
;; If this line exits a level of conditional, exit inner loop.
(if (< depth 0)
- (setq found (point)))
- ;; When searching forward, start from end of line
- ;; so that we don't find the same line again.
- (if forward (end-of-line))))))
+ (setq found (point)))))))
(or found
(error "No containing preprocessor conditional"))
(goto-char (setq new found)))
- (setq count (- count increment))))
+ (setq count (+ count increment))))
(push-mark)
(goto-char new)))