aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/cc-cmds.el
diff options
context:
space:
mode:
authorGerd Moellmann <[email protected]>1999-12-12 18:24:19 +0000
committerGerd Moellmann <[email protected]>1999-12-12 18:24:19 +0000
commit51f606dea8d768c59b6f78ba278c04978d712fd1 (patch)
tree6149934ab99d60f0d9fb8c15c3a236884125bc1a /lisp/progmodes/cc-cmds.el
parent3fc558970037e71143dcf92b8f5b2876a1386d57 (diff)
Installed version 5.26
Diffstat (limited to 'lisp/progmodes/cc-cmds.el')
-rw-r--r--lisp/progmodes/cc-cmds.el1526
1 files changed, 1028 insertions, 498 deletions
diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el
index 9877832804..05d2599d95 100644
--- a/lisp/progmodes/cc-cmds.el
+++ b/lisp/progmodes/cc-cmds.el
@@ -1,8 +1,8 @@
;;; cc-cmds.el --- user level commands for CC Mode
-;; Copyright (C) 1985,87,92,93,94,95,96,97,98 Free Softare Foundation, Inc.
+;; Copyright (C) 1985,1987,1992-1999 Free Software Foundation, Inc.
-;; Authors: 1998 Barry A. Warsaw and Martin Stjernholm
+;; Authors: 1998-1999 Barry A. Warsaw and Martin Stjernholm
;; 1992-1997 Barry A. Warsaw
;; 1987 Dave Detlefs and Stewart Clamen
;; 1985 Richard M. Stallman
@@ -28,11 +28,17 @@
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
-
-
(eval-when-compile
- (require 'cc-defs))
+ (let ((load-path
+ (if (and (boundp 'byte-compile-current-file)
+ (stringp byte-compile-current-file))
+ (cons (file-name-directory byte-compile-current-file)
+ load-path)
+ load-path)))
+ (load "cc-defs" nil t)))
+(require 'cc-engine)
+
(defun c-calculate-state (arg prevstate)
;; Calculate the new state of PREVSTATE, t or nil, based on arg. If
;; arg is nil or zero, toggle the state. If arg is negative, turn
@@ -331,7 +337,7 @@ This function does various newline cleanups based on the value of
;; Do all appropriate clean ups
(let ((here (point))
(pos (- (point-max) (point)))
- mbeg mend)
+ mbeg mend tmp)
;; clean up empty defun braces
(if (and c-auto-newline
(memq 'empty-defun-braces c-cleanup-list)
@@ -345,19 +351,36 @@ This function does various newline cleanups based on the value of
;; make sure matching open brace isn't in a comment
(not (c-in-literal)))
(delete-region (point) (1- here)))
- ;; clean up brace-else-brace
- (if (and c-auto-newline
- (memq 'brace-else-brace c-cleanup-list)
- (eq last-command-char ?\{)
+ ;; clean up brace-else-brace and brace-elseif-brace
+ (when (and c-auto-newline
+ (eq last-command-char ?\{)
+ (not (c-in-literal)))
+ (cond
+ ((and (memq 'brace-else-brace c-cleanup-list)
(re-search-backward "}[ \t\n]*else[ \t\n]*{" nil t)
(progn
(setq mbeg (match-beginning 0)
mend (match-end 0))
- (= mend here))
- (not (c-in-literal)))
- (progn
- (delete-region mbeg mend)
- (insert "} else {")))
+ (eq (match-end 0) here)))
+ (delete-region mbeg mend)
+ (insert "} else {"))
+ ((and (memq 'brace-elseif-brace c-cleanup-list)
+ (progn
+ (goto-char (1- here))
+ (setq mend (point))
+ (skip-chars-backward " \t\n")
+ (setq mbeg (point))
+ (eq (char-before) ?\)))
+ (= (c-backward-token-1 1 t) 0)
+ (eq (char-after) ?\()
+ (progn
+ (setq tmp (point))
+ (re-search-backward "}[ \t\n]*else[ \t\n]+if[ \t\n]*"
+ nil t))
+ (eq (match-end 0) tmp))
+ (delete-region mbeg mend)
+ (goto-char mbeg)
+ (insert " "))))
(goto-char (- (point-max) pos))
)
;; does a newline go after the brace?
@@ -598,8 +621,8 @@ or \"/ah\" string on the mode line, some newline cleanups are done if
appropriate; see the variable `c-cleanup-list'.
Also, the line is re-indented unless a numeric ARG is supplied, there
-are non-whitespace characters present on the line after the colon, or
-the colon is inserted inside a literal."
+are non-whitespace characters present on the line after the
+parenthesis, or the parenthesis is inserted inside a literal."
(interactive "*P")
(let (;; shut this up
(c-echo-syntactic-information-p nil))
@@ -647,7 +670,8 @@ the colon is inserted inside a literal."
(insert "} catch (")))
(goto-char (- (point-max) pos))
))
- (funcall old-blink-paren)))))
+ (if old-blink-paren
+ (funcall old-blink-paren))))))
@@ -692,6 +716,7 @@ Unlike the built-in `beginning-of-defun' this tries to be smarter
about finding the char with open-parenthesis syntax that starts the
defun."
(interactive "p")
+ (unless arg (setq arg 1))
(if (< arg 0)
(c-end-of-defun (- arg))
(while (> arg 0)
@@ -706,13 +731,16 @@ defun."
(cond
(bod (goto-char bod))
(prevbod (goto-char prevbod))
- (t (goto-char (c-point 'bod)))))
- (setq arg (1- arg))))
- (c-keep-region-active))
+ (t (goto-char (point-min))
+ (setq arg 0)))
+ (setq arg (1- arg))))
+ (c-keep-region-active)
+ (= arg 0)))
(defun c-end-of-defun (&optional arg)
"Move forward to next end of defun. With argument, do it that many times.
Negative argument -N means move back to Nth preceding end of defun.
+Returns t unless search stops due to beginning or end of buffer.
An end of a defun occurs right after the close-parenthesis that matches
the open-parenthesis that starts a defun; see `beginning-of-defun'."
@@ -722,16 +750,25 @@ the open-parenthesis that starts a defun; see `beginning-of-defun'."
(if (< arg 0)
(c-beginning-of-defun (- arg))
(while (> arg 0)
- ;; skip down into the next defun-block
- (while (and (c-safe (down-list 1) t)
- (not (eq (char-before) ?{)))
- (forward-char -1)
- (c-forward-sexp))
- (c-beginning-of-defun 1)
- (c-forward-sexp 1)
- (setq arg (1- arg)))
- (forward-line 1))
- (c-keep-region-active))
+ (let ((pos (point))
+ eol)
+ (while (and (c-safe (down-list 1) t)
+ (not (eq (char-before) ?{)))
+ ;; skip down into the next defun-block
+ (forward-char -1)
+ (c-forward-sexp))
+ (c-beginning-of-defun 1)
+ (setq eol (c-point 'eol))
+ (c-forward-sexp)
+ (if (< eol (point))
+ ;; Don't move to next line for one line defuns.
+ (forward-line 1))
+ (when (<= (point) pos)
+ (goto-char (point-max))
+ (setq arg 0))
+ (setq arg (1- arg))))
+ (c-keep-region-active)
+ (= arg 0)))
(defun c-beginning-of-statement (&optional count lim sentence-flag)
@@ -759,18 +796,12 @@ comment."
(save-excursion
;; Find the comment next to point if we're not in one.
(if (> count 0)
- ;; Finding a comment backwards is a bit cumbersome
- ;; because `forward-comment' regards every newline as
- ;; a comment when searching backwards (Emacs 19.34).
- (while (and (progn (skip-chars-backward " \t")
- (setq range (point))
- (setq range (if (forward-comment -1)
- (cons (point) range)
- nil)))
- (= (char-after) ?\n)))
+ (setq range (if (c-forward-comment -1)
+ (cons (point)
+ (progn (c-forward-comment 1) (point)))))
(skip-chars-forward " \t\n")
(setq range (point))
- (setq range (if (forward-comment 1)
+ (setq range (if (c-forward-comment 1)
(cons range (point))
nil)))
(setq range (c-collect-line-comments range))))
@@ -780,23 +811,72 @@ comment."
(if range
(if (and sentence-flag
(/= (char-syntax (char-after (car range))) ?\"))
- (progn
+ (let* ((lit-type (c-literal-type range))
+ (beg (save-excursion
+ (goto-char (car range))
+ (looking-at (if (eq lit-type 'c)
+ comment-start-skip
+ (concat "\\("
+ c-comment-prefix-regexp
+ "\\)[ \t]*")))
+ (goto-char (match-end 0))
+ (point)))
+ (end (save-excursion
+ (goto-char (- (cdr range)
+ (if (eq lit-type 'c) 2 1)))
+ (point))))
;; move by sentence, but not past the limit of the literal
(save-restriction
- (narrow-to-region (save-excursion
- (goto-char (car range))
- (looking-at comment-start-skip)
- (goto-char (match-end 0))
- (point))
- (save-excursion
- (goto-char (cdr range))
- (if (save-excursion
- (goto-char (car range))
- (looking-at "/\\*"))
- (backward-char 2))
- (skip-chars-backward " \t\n")
- (point)))
- (c-safe (forward-sentence (if (> count 0) -1 1))))
+ (narrow-to-region beg end)
+ (c-safe (forward-sentence (if (< count 0) 1 -1)))
+ (if (and (memq lit-type '(c c++))
+ ;; Check if we stopped due to a comment
+ ;; prefix and not a sentence end.
+ (/= (point) beg)
+ (save-excursion
+ (beginning-of-line)
+ (looking-at (concat "[ \t]*\\("
+ c-comment-prefix-regexp
+ "\\)[ \t]*")))
+ (>= (point) (match-beginning 0))
+ (/= (match-beginning 1) (match-end 1))
+ (or (< (point) (match-end 0))
+ (and
+ (= (point) (match-end 0))
+ ;; The comment prefix may contain
+ ;; characters that is regarded as end
+ ;; of sentence.
+ (or (eolp)
+ (and
+ (save-excursion
+ (forward-paragraph -1)
+ (< (point) (match-beginning 0)))
+ (save-excursion
+ (beginning-of-line)
+ (or (not (re-search-backward
+ sentence-end
+ (c-point 'bopl)
+ t))
+ (< (match-end 0)
+ (c-point 'eol)))))))))
+ (setq count (+ count (if (< count 0) -1 1)))
+ (if (< count 0)
+ (progn
+ ;; In block comments, if there's only
+ ;; horizontal ws between the text and the
+ ;; comment ender, stop before it. Stop after
+ ;; the ender if there's either nothing or
+ ;; newlines between.
+ (when (and (eq lit-type 'c) (eq (point) end))
+ (widen)
+ (skip-chars-backward " \t")
+ (when (or (eq (point) end) (bolp))
+ (goto-char (cdr range)))))
+ (when (and (eq (point) beg) (looking-at "[ \t]*$"))
+ ;; Stop before instead of after the comment
+ ;; starter if nothing follows it.
+ (widen)
+ (goto-char (car range))))))
;; See if we should escape the literal.
(if (> count 0)
(if (< (point) here)
@@ -810,89 +890,143 @@ comment."
(goto-char (if (> count 0) (car range) (cdr range)))
(setq range nil))
;; Below we do approximately the same as
- ;; c-beginning-of-statement-1 and c-end-of-statement-1 and
+ ;; c-beginning-of-statement-1 and c-end-of-statement-1, and
;; perhaps they should be changed, but that'd likely break a
;; lot in cc-engine.
(goto-char here)
(if (> count 0)
- (if (condition-case nil
- ;; Stop before `{' and after `;', `{', `}' and
- ;; `};' when not followed by `}' or `)', but on
- ;; the other side of the syntactic ws. Also stop
- ;; before `}', but only to catch comments. Move
- ;; by sexps and move into parens.
- (catch 'done
- (let (last)
- (while t
- (setq last (point))
- (if (and (looking-at "[{}]")
- (/= here last))
- (throw 'done (= (char-after) ?{)))
- (c-backward-syntactic-ws)
- (cond ((bobp) ; Must handle bob specially.
- (if (= here last)
- (if (= last (point-min))
- (throw 'done t)
- (goto-char last)
- (throw 'done nil))
- (goto-char last)
- (throw 'done t)))
- ((progn (backward-char)
- (looking-at "[;{}]"))
- (if (or (= here last)
- (memq (char-after last) '(?\) ?})))
- (if (and (= (char-before) ?})
- (= (char-after) ?\;))
- (backward-char))
- (goto-char last)
- (throw 'done t)))
- ((= (char-syntax (char-after)) ?\")
- (forward-char)
- (c-backward-sexp))
- ))))
- (error
- (goto-char (point-min))
- t))
- (setq count (1- count)))
- (if (condition-case nil
- ;; Stop before `{' and `}', but on the other side of
- ;; the syntactic ws, and after `;', `}' and `};'.
- ;; Only stop before `{' if at top level or inside
- ;; braces, though. Also stop after `{', but only to
- ;; catch comments. Move by sexps and move into
- ;; parens.
+ (condition-case nil
+ ;; Stop before `{' and after `;', `{', `}' and `};'
+ ;; when not followed by `}' or `)', but on the other
+ ;; side of the syntactic ws. Move by sexps and move
+ ;; into parens. Also stop before `#' when it's first
+ ;; on a line.
+ (let ((comment-pos (not sentence-flag))
+ (large-enough (- (point-max)))
+ last last-below-line)
(catch 'done
- (let (last)
- (while t
- (setq last (point))
- (c-forward-syntactic-ws)
- (cond ((= (char-after) ?{)
+ (while t
+ (setq last (point))
+ (when (and (looking-at "{\\|^#") (/= here last))
+ (unless (and c-special-brace-lists
+ (eq (char-after) ?{)
+ (c-looking-at-special-brace-list))
+ (if (and (eq (char-after) ?#)
+ (numberp last-below-line)
+ (not (eq last-below-line here)))
+ (goto-char last-below-line))
+ (throw 'done t)))
+ (if comment-pos
+ (c-forward-comment large-enough)
+ (when (c-forward-comment -1)
+ ;; Record position of first comment.
+ (save-excursion
+ (c-forward-comment 1)
+ (setq comment-pos (point)))
+ (c-forward-comment large-enough)))
+ (unless last-below-line
+ (if (save-excursion
+ (re-search-forward "\\(^\\|[^\\]\\)$" last t))
+ (setq last-below-line last)))
+ (cond ((bobp) ; Must handle bob specially.
+ (if (= here last)
+ (throw 'done t)
+ (goto-char last)
+ (throw 'done t)))
+ ((progn (backward-char)
+ (looking-at "[;{}]"))
+ (if (and c-special-brace-lists
+ (eq (char-after) ?{)
+ (c-looking-at-special-brace-list))
+ (skip-syntax-backward "w_") ; Speedup only.
(if (or (= here last)
- (save-excursion
- (and (c-safe (progn (up-list -1) t))
- (/= (char-after) ?{))))
- (progn (forward-char)
- (throw 'done nil))
+ (memq (char-after last) '(?\) ?})))
+ (if (and (eq (char-before) ?})
+ (eq (char-after) ?\;))
+ (backward-char))
(goto-char last)
- (throw 'done t)))
- ((and (= (char-after) ?})
- (/= here last))
- (goto-char last)
- (throw 'done t))
- ((looking-at ";\\|};?")
- (goto-char (match-end 0))
- (throw 'done t))
- ((= (char-syntax (char-after)) ?\")
- (c-forward-sexp))
- (t
- (forward-char))
- ))))
- (error
- (goto-char (point-max))
- t))
- (setq count (1+ count)))))
+ (throw 'done t))))
+ ((= (char-syntax (char-after)) ?\")
+ (forward-char)
+ (c-backward-sexp))
+ (t (skip-syntax-backward "w_")) ; Speedup only.
+ )))
+ (if (and (numberp comment-pos)
+ (< (point) comment-pos))
+ ;; We jumped over a comment that should be investigated.
+ (goto-char comment-pos)
+ (setq count (1- count))))
+ (error
+ (goto-char (point-min))
+ (setq count 0)))
+ (condition-case nil
+ ;; Stop before `{', `}', and `#' when it's first on a
+ ;; line, but on the other side of the syntactic ws, and
+ ;; after `;', `}' and `};'. Only stop before `{' if at
+ ;; top level or inside braces, though. Move by sexps
+ ;; and move into parens. Also stop at eol of lines
+ ;; starting with `#'.
+ (let ((comment-pos (not sentence-flag))
+ (large-enough (point-max))
+ last)
+ (catch 'done
+ (while t
+ (setq last (point))
+ (if comment-pos
+ (c-forward-comment large-enough)
+ (if (progn
+ (skip-chars-forward " \t\n\r\f")
+ ;; Record position of first comment.
+ (setq comment-pos (point))
+ (c-forward-comment 1))
+ (c-forward-comment large-enough)
+ (setq comment-pos nil)))
+ (cond ((and (eq (char-after) ?{)
+ (not (and c-special-brace-lists
+ (c-looking-at-special-brace-list)))
+ (/= here last)
+ (save-excursion
+ (or (not (c-safe (up-list -1) t))
+ (= (char-after) ?{))))
+ (goto-char last)
+ (throw 'done t))
+ ((and c-special-brace-lists
+ (eq (char-after) ?})
+ (save-excursion
+ (and (c-safe (up-list -1) t)
+ (c-looking-at-special-brace-list))))
+ (forward-char 1)
+ (skip-syntax-forward "w_")) ; Speedup only.
+ ((and (eq (char-after) ?})
+ (/= here last))
+ (goto-char last)
+ (throw 'done t))
+ ((looking-at "^#")
+ (if (= here last)
+ (or (re-search-forward "\\(^\\|[^\\]\\)$" nil t)
+ (goto-char (point-max)))
+ (goto-char last))
+ (throw 'done t))
+ ((looking-at ";\\|};?")
+ (goto-char (match-end 0))
+ (throw 'done t))
+ ((= (char-syntax (char-after)) ?\")
+ (c-forward-sexp))
+ (t
+ (forward-char 1)
+ (skip-syntax-forward "w_")) ; Speedup only.
+ )))
+ (if (and (numberp comment-pos)
+ (> (point) comment-pos))
+ ;; We jumped over a comment that should be investigated.
+ (goto-char comment-pos)
+ (setq count (1+ count))))
+ (error
+ (goto-char (point-max))
+ (setq count 0)))
+ ))
;; If we haven't moved we're near a buffer limit.
- (when (= (point) here)
+ (when (and (not (zerop count)) (= (point) here))
(goto-char (if (> count 0) (point-min) (point-max)))
(setq count 0)))
;; its possible we've been left up-buf of lim
@@ -987,8 +1121,10 @@ comment."
(cons c-comment-only-line-offset
c-comment-only-line-offset))))
(apply '+ (mapcar 'c-get-offset syntax)))))
- ;; CASE 4: use comment-column if previous line is a
- ;; comment-only line indented to the left of comment-column
+ ;; CASE 4: If previous line is a comment-only line, use its
+ ;; indentation if it's greater than comment-column. Leave at
+ ;; least one space between the comment and the last nonblank
+ ;; character in any case.
((save-excursion
(beginning-of-line)
(and (not (bobp))
@@ -996,11 +1132,12 @@ comment."
(skip-chars-forward " \t")
(prog1
(looking-at c-comment-start-regexp)
- (setq placeholder (point))))
- (goto-char placeholder)
- (if (< (current-column) comment-column)
- comment-column
- (current-column)))
+ (setq placeholder (current-column))))
+ (goto-char opoint)
+ (skip-chars-backward " \t")
+ (max (if (bolp) 0 (1+ (current-column)))
+ placeholder
+ comment-column))
;; CASE 5: If comment-column is 0, and nothing but space
;; before the comment, align it at 0 rather than 1.
((progn
@@ -1015,93 +1152,89 @@ comment."
)))))
-;; for proposed new variable comment-line-break-function
-(defun c-comment-line-break-function (&optional soft)
- ;; we currently don't do anything with soft line breaks
- (let ((literal (c-in-literal))
- at-comment-col)
- (cond
- ((eq literal 'string)
- (insert ?\n))
- ((or (not c-comment-continuation-stars)
- (not literal))
- (indent-new-comment-line soft))
- (t (let ((here (point))
- (leader c-comment-continuation-stars))
- (back-to-indentation)
- ;; comment could be hanging
- (if (not (c-in-literal))
- (progn
- (forward-line 1)
- (forward-comment -1)
- (setq at-comment-col (= (current-column) comment-column))))
- ;; are we looking at a block or lines style comment?
- (if (and (looking-at (concat "\\(" c-comment-start-regexp
- "\\)[ \t]+"))
- (string-equal (match-string 1) "//"))
- ;; line style
- (setq leader (match-string 0)))
- (goto-char here)
- (delete-region (progn (skip-chars-backward " \t") (point))
- (progn (skip-chars-forward " \t") (point)))
- (newline)
- ;; to avoid having an anchored comment that c-indent-line will
- ;; trip up on
- (insert " " leader)
- (if at-comment-col
- (indent-for-comment))
- (c-indent-line))))))
-
-;; advice for indent-new-comment-line for older Emacsen
-(or (boundp 'comment-line-break-function)
- (defadvice indent-new-comment-line (around c-line-break-advice
- activate preactivate)
- "Calls c-comment-line-break-function if in a comment in CC Mode."
- (if (or (not c-buffer-is-cc-mode)
- (not (c-in-literal))
- (not c-comment-continuation-stars))
- ad-do-it
- (c-comment-line-break-function (ad-get-arg 0)))))
-
;; used by outline-minor-mode
(defun c-outline-level ()
- ;; This so that `current-column' DTRT in otherwise-hidden text.
- (let (buffer-invisibility-spec)
- (save-excursion
- (skip-chars-forward "\t ")
- (current-column))))
+ (save-excursion
+ (skip-chars-forward "\t ")
+ (current-column)))
(defun c-up-conditional (count)
"Move back to the containing preprocessor conditional, leaving mark behind.
A prefix argument acts as a repeat count. With a negative argument,
move forward to the end of the containing preprocessor conditional.
-When going backwards, `#elif' is treated like `#else' followed by
-`#if'. When going forwards, `#elif' is ignored."
+
+`#elif' is treated like `#else' followed by `#if', so the function
+stops at them when going backward, but not when going forward."
+ (interactive "p")
+ (c-forward-conditional (- count) -1)
+ (c-keep-region-active))
+
+(defun c-up-conditional-with-else (count)
+ "Move back to the containing preprocessor conditional, including `#else'.
+Just like `c-up-conditional', except it also stops at `#else'
+directives."
+ (interactive "p")
+ (c-forward-conditional (- count) -1 t)
+ (c-keep-region-active))
+
+(defun c-down-conditional (count)
+ "Move forward into the next preprocessor conditional, leaving mark behind.
+A prefix argument acts as a repeat count. With a negative argument,
+move backward into the previous preprocessor conditional.
+
+`#elif' is treated like `#else' followed by `#if', so the function
+stops at them when going forward, but not when going backward."
(interactive "p")
- (c-forward-conditional (- count) t)
+ (c-forward-conditional count 1)
(c-keep-region-active))
-(defun c-backward-conditional (count &optional up-flag)
+(defun c-down-conditional-with-else (count)
+ "Move forward into the next preprocessor conditional, including `#else'.
+Just like `c-down-conditional', except it also stops at `#else'
+directives."
+ (interactive "p")
+ (c-forward-conditional count 1 t)
+ (c-keep-region-active))
+
+(defun c-backward-conditional (count &optional target-depth with-else)
"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)
+ (c-forward-conditional (- count) target-depth with-else)
(c-keep-region-active))
-(defun c-forward-conditional (count &optional up-flag)
+(defun c-forward-conditional (count &optional target-depth with-else)
"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."
+move backward across a preprocessor conditional.
+
+`#elif' is treated like `#else' followed by `#if', except that the
+nesting level isn't changed when tracking subconditionals.
+
+The optional argument TARGET-DEPTH specifies the wanted nesting depth
+after each scan. I.e. if TARGET-DEPTH is -1, the function will move
+out of the enclosing conditional. A non-integer non-nil TARGET-DEPTH
+counts as -1.
+
+If the optional argument WITH-ELSE is non-nil, `#else' directives are
+treated as conditional clause limits. Normally they are ignored."
(interactive "p")
(let* ((forward (> count 0))
(increment (if forward -1 1))
(search-function (if forward 're-search-forward 're-search-backward))
(new))
+ (unless (integerp target-depth)
+ (setq target-depth (if target-depth -1 0)))
(save-excursion
(while (/= count 0)
- (let ((depth (if up-flag 0 -1)) found)
+ (let ((depth 0)
+ ;; subdepth is the depth in "uninteresting" subtrees,
+ ;; i.e. those that takes us farther from the target
+ ;; depth instead of closer.
+ (subdepth 0)
+ found)
(save-excursion
;; Find the "next" significant line in the proper direction.
(while (and (not found)
@@ -1112,36 +1245,50 @@ move backward across a preprocessor conditional."
;; precedes it. This is faster on account of
;; the fastmap feature of the regexp matcher.
(funcall search-function
- "#[ \t]*\\(if\\|elif\\|endif\\)"
+ "#[ \t]*\\(if\\|elif\\|endif\\|else\\)"
nil t))
(beginning-of-line)
;; Now verify it is really a preproc line.
- (if (looking-at "^[ \t]*#[ \t]*\\(if\\|elif\\|endif\\)")
- (let ((prev depth))
- ;; Update depth according to what we found.
- (beginning-of-line)
- (cond ((looking-at "[ \t]*#[ \t]*endif")
- (setq depth (+ depth increment)))
- ((looking-at "[ \t]*#[ \t]*elif")
- (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")))
+ (if (looking-at "^[ \t]*#[ \t]*\\(if\\|elif\\|endif\\|else\\)")
+ (let (dchange (directive (match-string 1)))
+ (cond ((string= directive "if")
+ (setq dchange (- increment)))
+ ((string= directive "endif")
+ (setq dchange increment))
+ ((= subdepth 0)
+ ;; When we're not in an "uninteresting"
+ ;; subtree, we might want to act on "elif"
+ ;; and "else" too.
+ (if (cond (with-else
+ ;; Always move toward the target depth.
+ (setq dchange
+ (if (> target-depth 0) 1 -1)))
+ ((string= directive "elif")
+ (setq dchange (- increment))))
+ ;; Ignore the change if it'd take us
+ ;; into an "uninteresting" subtree.
+ (if (eq (> dchange 0) (<= target-depth 0))
+ (setq dchange nil)))))
+ (when dchange
+ (when (or (/= subdepth 0)
+ (eq (> dchange 0) (<= target-depth 0)))
+ (setq subdepth (+ subdepth dchange)))
+ (setq depth (+ depth dchange))
+ ;; If we are trying to move across, and we find an
+ ;; end before we find a beginning, get an error.
+ (if (and (< depth target-depth) (< dchange 0))
+ (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)
+ ;; We found something if we've arrived at the
+ ;; target depth.
+ (if (and dchange (= depth target-depth))
(setq found (point))))
;; else
- (if forward (forward-line 1))
- )))
+ (if forward (forward-line 1)))))
(or found
(error "No containing preprocessor conditional"))
(goto-char (setq new found)))
@@ -1217,8 +1364,9 @@ of the expression is preserved.
"Indent each line in balanced expression following point.
Optional SHUTUP-P if non-nil, inhibits message printing and error checking."
(interactive "*P")
- (let ((here (point))
+ (let ((here (point-marker))
end progress-p)
+ (set-marker-insertion-type here t)
(unwind-protect
(let ((c-echo-syntactic-information-p nil) ;keep quiet for speed
(start (progn
@@ -1259,7 +1407,8 @@ Optional SHUTUP-P if non-nil, inhibits message printing and error checking."
(set-marker end nil))
(and progress-p
(c-progress-fini 'c-indent-exp))
- (goto-char here))))
+ (goto-char here)
+ (set-marker here nil))))
(defun c-indent-defun ()
"Re-indents the current top-level function def, struct or class declaration."
@@ -1342,13 +1491,16 @@ Optional SHUTUP-P if non-nil, inhibits message printing and error checking."
(setq sexpbeg (point))))
(if (and sexpbeg (< sexpbeg fence))
(setq sexpbeg fence)))
- ;; check to see if the next line starts a
- ;; comment-only line
- (save-excursion
- (forward-line 1)
- (skip-chars-forward " \t")
- (if (looking-at c-comment-start-regexp)
- (setq sexpbeg (c-point 'bol))))
+ ;; Since we move by sexps we might have missed
+ ;; comment-only lines.
+ (if sexpbeg
+ (save-excursion
+ (while (progn
+ (forward-line 1)
+ (skip-chars-forward " \t")
+ (< (point) sexpbeg))
+ (if (looking-at c-comment-start-regexp)
+ (setq sexpbeg (c-point 'bol))))))
;; If that sexp ends within the region, indent it all at
;; once, fast.
(condition-case nil
@@ -1560,12 +1712,288 @@ command to conveniently insert and align the necessary backslashes."
(delete-region (1+ (point))
(progn (skip-chars-backward " \t") (point)))))))
+
+;;; Line breaking and paragraph filling.
+
+;; The filling code is based on a simple theory; leave the intricacies
+;; of the text handling to the currently active mode for that
+;; (e.g. adaptive-fill-mode or filladapt-mode) and do as little as
+;; possible to make them work correctly wrt the comment and string
+;; separators, one-line paragraphs etc. Unfortunately, when it comes
+;; to it, there's quite a lot of special cases to handle which makes
+;; the code anything but simple. The intention is that it will work
+;; with any well-written text filling package that preserves a fill
+;; prefix.
+;;
+;; We temporarily mask comment starters and enders as necessary for
+;; the filling code to do its job on a seemingly normal text block.
+;; We do _not_ mask the fill prefix, so it's up to the filling code to
+;; preserve it correctly (especially important when filling C++ style
+;; line comments). By default, we set up and use adaptive-fill-mode,
+;; which is standard in all supported Emacs flavors.
+
+(defun c-guess-fill-prefix (lit-limits lit-type)
+ ;; Determine the appropriate comment fill prefix for a block or line
+ ;; comment. Return a cons of the prefix string and the column where
+ ;; it ends. If fill-prefix is set, it'll override. Note that this
+ ;; function also uses the value of point in some heuristics.
+ (let* ((here (point))
+ (prefix-regexp (concat "[ \t]*\\("
+ c-comment-prefix-regexp
+ "\\)[ \t]*"))
+ (comment-start-regexp (if (eq lit-type 'c++)
+ prefix-regexp
+ comment-start-skip))
+ prefix-line comment-prefix res)
+ (cond
+ (fill-prefix
+ (setq res (cons fill-prefix
+ ;; Ugly way of getting the column after the fill
+ ;; prefix; it'd be nice with a current-column
+ ;; that works on strings..
+ (let ((buffer-modified (buffer-modified-p))
+ (buffer-undo-list t)
+ (start (point)))
+ (unwind-protect
+ (progn
+ (insert ?\n fill-prefix)
+ (current-column))
+ (delete-region start (point))
+ (set-buffer-modified-p buffer-modified))))))
+ ((eq lit-type 'c++)
+ (save-excursion
+ ;; Set fallback for comment-prefix if none is found.
+ (setq comment-prefix "// ")
+ (beginning-of-line)
+ (if (> (point) (car lit-limits))
+ ;; The current line is not the comment starter, so the
+ ;; comment has more than one line, and it can therefore be
+ ;; used to find the comment fill prefix.
+ (setq prefix-line (point))
+ (goto-char (car lit-limits))
+ (if (and (= (forward-line 1) 0)
+ (< (point) (cdr lit-limits)))
+ ;; The line after the comment starter is inside the
+ ;; comment, so we can use it.
+ (setq prefix-line (point))
+ ;; The comment is only one line. Take the comment prefix
+ ;; from it and keep the indentation.
+ (goto-char (car lit-limits))
+ (if (looking-at prefix-regexp)
+ (goto-char (match-end 0))
+ (forward-char 2)
+ (skip-chars-forward " \t"))
+ (setq res
+ (if (eq (c-point 'boi) (car lit-limits))
+ ;; There is only whitespace before the comment
+ ;; starter; take the prefix straight from this
+ ;; line.
+ (cons (buffer-substring-no-properties
+ (c-point 'bol) (point))
+ (current-column))
+ ;; There is code before the comment starter, so we
+ ;; have to temporarily insert and indent a new
+ ;; line to get the right space/tab mix in the
+ ;; indentation.
+ (let ((buffer-modified (buffer-modified-p))
+ (buffer-undo-list t)
+ (prefix-len (- (point) (car lit-limits)))
+ tmp)
+ (unwind-protect
+ (progn
+ (goto-char (car lit-limits))
+ (indent-to (prog1 (current-column)
+ (insert ?\n)))
+ (setq tmp (point))
+ (forward-char prefix-len)
+ (cons (buffer-substring-no-properties
+ (c-point 'bol) (point))
+ (current-column)))
+ (delete-region (car lit-limits) tmp)
+ (set-buffer-modified-p buffer-modified))))
+ )))))
+ (t
+ (save-excursion
+ (beginning-of-line)
+ (if (and (> (point) (car lit-limits))
+ (not (and (looking-at "[ \t]*\\*/")
+ (eq (cdr lit-limits) (match-end 0)))))
+ ;; The current line is not the comment starter and
+ ;; contains more than just the ender, so it's good enough
+ ;; to be used for the comment fill prefix.
+ (setq prefix-line (point))
+ (goto-char (car lit-limits))
+ (if (or (/= (forward-line 1) 0)
+ (>= (point) (cdr lit-limits))
+ (and (looking-at "[ \t]*\\*/")
+ (eq (cdr lit-limits) (match-end 0)))
+ (and (looking-at prefix-regexp)
+ (<= (1- (cdr lit-limits)) (match-end 0)))
+ (and (< here (point))
+ (or (not (match-beginning 0))
+ (looking-at "[ \t]*$"))))
+ ;; The comment is either one line or the next line
+ ;; contains just the comment ender. Also, if point is
+ ;; on the comment opener line and the following line is
+ ;; empty or doesn't match c-comment-prefix-regexp we
+ ;; assume that this is in fact a not yet closed one line
+ ;; comment, so we shouldn't look for the comment prefix
+ ;; on the next line. In these cases we have no
+ ;; information about a suitable comment prefix, so we
+ ;; resort to c-block-comment-prefix.
+ (setq comment-prefix (or c-block-comment-prefix "")
+ res (let ((buffer-modified (buffer-modified-p))
+ (buffer-undo-list t)
+ tmp-pre tmp-post)
+ ;; The comment doesn't give any information
+ ;; about the indentation column. We'll have to
+ ;; temporarily insert a new comment line and
+ ;; indent it to find the correct column.
+ (unwind-protect
+ (progn
+ (goto-char (car lit-limits))
+ (if (looking-at comment-start-regexp)
+ (goto-char (match-end 0))
+ (forward-char 2)
+ (skip-chars-forward " \t"))
+ (when (eq (char-syntax (char-before)) ?\ )
+ ;; If there's ws on the current
+ ;; line, we'll use it instead of
+ ;; what's ending comment-prefix.
+ (setq comment-prefix
+ (concat (substring comment-prefix
+ 0 (string-match
+ "\\s *\\'"
+ comment-prefix))
+ (buffer-substring-no-properties
+ (save-excursion
+ (skip-chars-backward " \t")
+ (point))
+ (point)))))
+ (setq tmp-pre (point-marker))
+ ;; We insert an extra non-whitespace
+ ;; character before the line break and
+ ;; after comment-prefix in case it's
+ ;; "" or ends with whitespace.
+ (insert "x\n" comment-prefix ?x)
+ (setq tmp-post (point-marker))
+ (c-indent-line)
+ (goto-char (1- tmp-post))
+ (cons (buffer-substring-no-properties
+ (c-point 'bol) (point))
+ (current-column)))
+ (when tmp-post
+ (delete-region tmp-pre tmp-post)
+ (set-marker tmp-pre nil)
+ (set-marker tmp-post nil))
+ (set-buffer-modified-p buffer-modified))))
+ ;; Otherwise the line after the comment starter is good
+ ;; enough to find the prefix in.
+ (setq prefix-line (point)))))))
+ (or res
+ (save-excursion
+ ;; prefix-line is the bol of a line on which we should try
+ ;; to find the prefix.
+ (let* (fb-string fb-endpos ; Contains any fallback prefix found.
+ (test-line
+ (lambda ()
+ (when (and (looking-at prefix-regexp)
+ (< (match-end 0) (1- (cdr lit-limits))))
+ (unless fb-string
+ (setq fb-string (buffer-substring-no-properties
+ (match-beginning 0) (match-end 0))
+ fb-endpos (match-end 0)))
+ (unless (eq (match-end 0) (c-point 'eol))
+ (throw 'found t))
+ t))))
+ (if (catch 'found
+ ;; Search for a line which has text after the prefix
+ ;; so that we get the proper amount of whitespace
+ ;; after it. We start with the current line, then
+ ;; search backwards, then forwards.
+ (goto-char prefix-line)
+ (when (and (funcall test-line)
+ (/= (match-end 1) (match-end 0)))
+ ;; If the current line doesn't have text but do
+ ;; have whitespace after the prefix, we'll use it.
+ (throw 'found t))
+ (while (and (zerop (forward-line -1))
+ (> (point) (car lit-limits)))
+ (funcall test-line))
+ (goto-char prefix-line)
+ (while (and (zerop (forward-line 1))
+ (< (point) (cdr lit-limits)))
+ (funcall test-line))
+ nil)
+ ;; A good line with text after the prefix was found.
+ (cons (buffer-substring-no-properties (point) (match-end 0))
+ (progn (goto-char (match-end 0)) (current-column)))
+ (if fb-string
+ ;; A good line wasn't found, but at least we have a
+ ;; fallback that matches the comment prefix regexp.
+ (cond ((string-match "\\s \\'" fb-string)
+ ;; There are ws after the prefix, so let's use it.
+ (cons fb-string
+ (progn (goto-char fb-endpos) (current-column))))
+ ((progn
+ ;; Check if there's any whitespace padding
+ ;; on the comment start line that we can
+ ;; use after the prefix.
+ (goto-char (car lit-limits))
+ (if (looking-at comment-start-regexp)
+ (goto-char (match-end 0))
+ (forward-char 2)
+ (skip-chars-forward " \t"))
+ (eq (char-syntax (char-before)) ?\ ))
+ (setq fb-string (buffer-substring-no-properties
+ (save-excursion
+ (skip-chars-backward " \t")
+ (point))
+ (point)))
+ (goto-char fb-endpos)
+ (skip-chars-backward " \t")
+ (let ((buffer-modified (buffer-modified-p))
+ (buffer-undo-list t)
+ (tmp (point)))
+ ;; Got to mess in the buffer once again to
+ ;; ensure the column gets correct. :P
+ (unwind-protect
+ (progn
+ (insert fb-string)
+ (cons (buffer-substring-no-properties
+ (c-point 'bol)
+ (point))
+ (current-column)))
+ (delete-region tmp (point)))))
+ (t
+ ;; Last resort: Just add a single space after
+ ;; the prefix.
+ (cons (concat fb-string " ")
+ (progn (goto-char fb-endpos)
+ (1+ (current-column))))))
+ ;; The line doesn't match the comment prefix regexp.
+ (if comment-prefix
+ ;; We have a fallback for line comments that we must use.
+ (cons (concat (buffer-substring-no-properties
+ prefix-line (c-point 'boi))
+ comment-prefix)
+ (progn (back-to-indentation)
+ (+ (current-column) (length comment-prefix))))
+ ;; Assume we are dealing with a "free text" block
+ ;; comment where the lines doesn't have any comment
+ ;; prefix at all and we should just fill it as
+ ;; normal text.
+ '("" . 0)))))))
+ ))
+
(defun c-fill-paragraph (&optional arg)
"Like \\[fill-paragraph] but handles C and C++ style comments.
-If any of the current line is a comment or within a comment,
-fill the comment or the paragraph of it that point is in,
-preserving the comment indentation or line-starting decorations.
+If any of the current line is a comment or within a comment, fill the
+comment or the paragraph of it that point is in, preserving the
+comment indentation or line-starting decorations (see the
+`c-comment-prefix-regexp' and `c-block-comment-prefix' variables for
+details).
If point is inside multiline string literal, fill it. This currently
does not respect escaped newlines, except for the special case when it
@@ -1580,274 +2008,376 @@ If point is in any other situation, i.e. in normal code, do nothing.
Optional prefix ARG means justify paragraph as well."
(interactive "*P")
- (let* ((point-save (point-marker))
- limits
- comment-start-place
- (first-line
- ;; Check for obvious entry to comment.
- (save-excursion
- (beginning-of-line)
- (skip-chars-forward " \t")
- (and (looking-at comment-start-skip)
- (setq comment-start-place (point)))))
- (re1 "\\|\\([ \t]*/\\*[ \t]*\\|[ \t]*\\*/[ \t]*\\|[ \t/*]*\\)"))
- (if (save-excursion
- (beginning-of-line)
- (looking-at ".*//"))
- (let ((fill-prefix fill-prefix)
- ;; Lines containing just a comment start or just an end
- ;; should not be filled into paragraphs they are next
- ;; to.
- (paragraph-start (concat paragraph-start re1 "$"))
- (paragraph-separate (concat paragraph-separate re1 "$")))
- (save-excursion
- (beginning-of-line)
- ;; Move up to first line of this comment.
- (while (and (not (bobp))
- (looking-at "[ \t]*//[ \t]*[^ \t\n]"))
- (forward-line -1))
- (if (not (looking-at ".*//[ \t]*[^ \t\n]"))
- (forward-line 1))
- ;; Find the comment start in this line.
- (re-search-forward "[ \t]*//[ \t]*")
- ;; Set the fill-prefix to be what all lines except the first
- ;; should start with. But do not alter a user set fill-prefix.
- (if (null fill-prefix)
- (setq fill-prefix (buffer-substring (match-beginning 0)
- (match-end 0))))
- (save-restriction
- ;; Narrow down to just the lines of this comment.
- (narrow-to-region (c-point 'bol)
- (save-excursion
- (forward-line 1)
- (while
- (looking-at (regexp-quote fill-prefix))
- (forward-line 1))
- (point)))
- (or (c-safe
- ;; fill-paragraph sometimes fails to detect when we
- ;; are between paragraphs.
- (beginning-of-line)
- (search-forward fill-prefix (c-point 'eol))
- (looking-at paragraph-separate))
- ;; Avoids recursion
- (let (fill-paragraph-function)
- (fill-paragraph arg))))))
- ;; else C style comments
- (if (or first-line
- ;; t if we enter a comment between start of function and
- ;; this line.
+ (let (lit-limits lit-type fill
+ ;; beg and end limits the region to be filled. end is a marker.
+ beg end
+ ;; tmp-pre and tmp-post marks strings that are temporarily
+ ;; inserted at the start and end of the region. tmp-pre is a
+ ;; cons of the positions of the prepended string. tmp-post is
+ ;; a marker pointing to the single character of the appended
+ ;; string.
+ tmp-pre tmp-post
+ hang-ender-stuck)
+ ;; Restore point on undo. It's necessary since we do a lot of
+ ;; hidden inserts and deletes below that should be as transparent
+ ;; as possible.
+ (if (and buffer-undo-list (not (eq buffer-undo-list t)))
+ (setq buffer-undo-list (cons (point) buffer-undo-list)))
+ (save-excursion
+ (save-restriction
+ ;; Widen to catch comment limits correctly.
+ (widen)
+ (setq lit-limits (c-collect-line-comments (c-literal-limits nil t))
+ lit-type (c-literal-type lit-limits)))
+ (forward-paragraph)
+ (setq end (point-marker))
+ (backward-paragraph)
+ (setq beg (point)))
+ (when (and (>= (point) beg) (<= (point) end))
+ (unwind-protect
+ (progn
+ (cond
+ ((eq lit-type 'c++) ; Line comment.
(save-excursion
- (setq limits (c-literal-limits))
- (and (consp limits)
- (save-excursion
- (goto-char (car limits))
- (looking-at c-comment-start-regexp))))
- ;; t if this line contains a comment starter.
- (setq first-line
- (save-excursion
- (beginning-of-line)
- (prog1
- (re-search-forward comment-start-skip
- (save-excursion (end-of-line)
- (point))
- t)
- (setq comment-start-place (point)))))
- ;; t if we're in the whitespace after a comment ender
- ;; which ends its line.
- (and (not limits)
- (when (and (looking-at "[ \t]*$")
- (save-excursion
- (beginning-of-line)
- (looking-at ".*\\*/[ \t]*$")))
- (save-excursion
- (forward-comment -1)
- (setq comment-start-place (point)))
- t)))
- ;; Inside a comment: fill one comment paragraph.
- (let ((fill-prefix
- (or
- ;; Keep user set fill prefix if any.
- fill-prefix
- ;; The prefix for each line of this paragraph
- ;; is the appropriate part of the start of this line,
- ;; up to the column at which text should be indented.
- (save-excursion
- (beginning-of-line)
- (if (looking-at ".*/\\*.*\\*/")
- (progn (re-search-forward comment-start-skip)
- (make-string (current-column) ?\ ))
- (if first-line
- (forward-line 1)
- (if (and (looking-at "[ \t]*\\*/")
- (not (save-excursion
- (forward-line -1)
- (looking-at ".*/\\*"))))
- (forward-line -1)))
-
- (let ((line-width (progn (end-of-line)
- (current-column))))
- (beginning-of-line)
- (prog1
- (buffer-substring
- (point)
-
- ;; How shall we decide where the end of the
- ;; fill-prefix is?
- (progn
- (skip-chars-forward " \t*" (c-point 'eol))
- ;; kludge alert, watch out for */, in
- ;; which case fill-prefix should *not*
- ;; be "*"!
- (if (and (eq (char-after) ?/)
- (eq (char-before) ?*))
- (forward-char -1))
- (point)))
-
- ;; If the comment is only one line followed
- ;; by a blank line, calling move-to-column
- ;; above may have added some spaces and tabs
- ;; to the end of the line; the fill-paragraph
- ;; function will then delete it and the
- ;; newline following it, so we'll lose a
- ;; blank line when we shouldn't. So delete
- ;; anything move-to-column added to the end
- ;; of the line. We record the line width
- ;; instead of the position of the old line
- ;; end because move-to-column might break a
- ;; tab into spaces, and the new characters
- ;; introduced there shouldn't be deleted.
-
- ;; If you can see a better way to do this,
- ;; please make the change. This seems very
- ;; messy to me.
- (delete-region (progn (move-to-column line-width)
- (point))
- (progn (end-of-line) (point)))))))))
-
- ;; Lines containing just a comment start or just an end
- ;; should not be filled into paragraphs they are next
- ;; to.
- (paragraph-start (if (c-major-mode-is 'java-mode)
- (concat paragraph-start
- re1 "\\("
- c-Java-javadoc-paragraph-start
- "\\|$\\)")
- (concat paragraph-start re1 "$")))
- (paragraph-separate (concat paragraph-separate re1 "$"))
- (chars-to-delete 0)
- )
- (save-restriction
- ;; Don't fill the comment together with the code
- ;; following it. So temporarily exclude everything
- ;; before the comment start, and everything after the
- ;; line where the comment ends. If comment-start-place
- ;; is non-nil, the comment starter is there. Otherwise,
- ;; point is inside the comment.
- (narrow-to-region (save-excursion
- (if comment-start-place
- (goto-char comment-start-place)
- (search-backward "/*"))
- (if (and (not c-hanging-comment-starter-p)
- (looking-at
- (concat c-comment-start-regexp
- "[ \t]*$")))
- (forward-line 1))
- ;; Protect text before the comment
- ;; start by excluding it. Add
- ;; spaces to bring back proper
- ;; indentation of that point.
- (let ((column (current-column)))
- (prog1 (point)
- (setq chars-to-delete column)
- (insert-char ?\ column))))
- (save-excursion
- (if comment-start-place
- (goto-char (+ comment-start-place 2)))
- (search-forward "*/" nil 'move)
- (if (and (not c-hanging-comment-ender-p)
- (save-excursion
- (beginning-of-line)
- (looking-at "[ \t]*\\*/")))
- (beginning-of-line)
- (forward-line 1))
- (point)))
- (or (c-safe
- ;; fill-paragraph sometimes fails to detect when we
- ;; are between paragraphs.
- (beginning-of-line)
- (search-forward fill-prefix (c-point 'eol))
- (looking-at paragraph-separate))
- ;; Avoids recursion
- (let (fill-paragraph-function)
- (fill-paragraph arg)))
+ ;; Fill to the comment or paragraph end, whichever
+ ;; comes first.
+ (set-marker end (min end (cdr lit-limits)))
+ (when (<= beg (car lit-limits))
+ ;; The region to be filled includes the comment
+ ;; starter, so we must check it.
+ (goto-char (car lit-limits))
+ (back-to-indentation)
+ (if (eq (point) (car lit-limits))
+ ;; Include the first line in the fill.
+ (setq beg (c-point 'bol))
+ ;; The first line contains code before the
+ ;; comment. We must fake a line that doesn't.
+ (setq tmp-pre t)))
+ ))
+ ((eq lit-type 'c) ; Block comment.
(save-excursion
- ;; Delete the chars we inserted to avoid clobbering
- ;; the stuff before the comment start.
- (goto-char (point-min))
- (if (> chars-to-delete 0)
- (delete-region (point) (+ (point) chars-to-delete)))
- ;; Find the comment ender (should be on last line of
- ;; buffer, given the narrowing) and don't leave it on
- ;; its own line, unless that's the style that's desired.
- (goto-char (point-max))
- (forward-line -1)
- (search-forward "*/" nil 'move)
- (beginning-of-line)
- (if (and c-hanging-comment-ender-p
- (looking-at "[ \t]*\\*/"))
- ;(delete-indentation)))))
- (let ((fill-column (+ fill-column 9999)))
+ (when (>= end (cdr lit-limits))
+ ;; The region to be filled includes the comment ender.
+ (goto-char (cdr lit-limits))
+ (beginning-of-line)
+ (if (and (looking-at (concat "[ \t]*\\("
+ c-comment-prefix-regexp
+ "\\)\\*/"))
+ (eq (cdr lit-limits) (match-end 0)))
+ ;; Leave the comment ender on its own line.
+ (set-marker end (point))
+ ;; The comment ender should hang. Replace all
+ ;; cruft between it and the last word with a 'x'
+ ;; and include it in the fill. We'll change it
+ ;; back to a space afterwards.
+ (let ((ender-start (progn
+ (goto-char (cdr lit-limits))
+ (skip-syntax-backward "^w ")
+ (point))))
+ (goto-char (cdr lit-limits))
+ (setq tmp-post (point-marker))
+ (insert ?\n)
+ (set-marker end (point))
(forward-line -1)
- (fill-region-as-paragraph (point) (point-max))
- ;; If fill-prefix ended with a `*', it may be
- ;; taken away from the comment ender. We got to
- ;; check this and put it back if that is the
- ;; case.
- (goto-char (- (point-max) 2))
- (if (not (= (char-before) ?*))
- (insert ?*))
- )))))
- ;; Else maybe a string. Fill it if it's a multiline string.
- ;; FIXME: This currently doesn't handle escaped newlines.
- ;; Doing that correctly is a bit tricky.
- (if (and limits
- (eq (char-syntax (char-after (car limits))) ?\")
- (save-excursion
- (goto-char (car limits))
- (end-of-line)
- (< (point) (cdr limits))))
- (let (fill-paragraph-function)
- (save-restriction
- (narrow-to-region (save-excursion
- (goto-char (1+ (car limits)))
- (if (looking-at "\\\\$")
- ;; Some DWIM: Leave the start
- ;; line if it's nothing but an
- ;; escaped newline.
- (1+ (match-end 0))
- (point)))
- (save-excursion
- (goto-char (1- (cdr limits)))
- ;; Inserting a newline and
- ;; removing it again after
- ;; fill-paragraph makes it more
- ;; predictable.
- (insert ?\n)
- (point)))
- ;; Do not compensate for the narrowed column. This
- ;; way the literal will always be filled at the same
- ;; column internally.
- (fill-paragraph arg)
- (goto-char (1- (point-max)))
- (delete-char 1)))
- )))
- (goto-char (marker-position point-save))
- (set-marker point-save nil)
- ;; Always return t. This has the effect that if filling isn't
- ;; done above, it isn't done at all, and it's therefore
- ;; effectively disabled in normal code.
- t))
+ (if (and (looking-at (concat "[ \t]*\\("
+ c-comment-prefix-regexp
+ "\\)[ \t]*"))
+ (eq ender-start (match-end 0)))
+ ;; The comment ender is prefixed by nothing
+ ;; but a comment line prefix. Remove it
+ ;; along with surrounding ws.
+ nil
+ (goto-char ender-start))
+ (skip-chars-backward " \t\r\n")
+ (when (/= (point) ender-start)
+ (insert ?x) ; Insert first to keep marks right.
+ (delete-region (point) (1+ ender-start))
+ (setq hang-ender-stuck t)))))
+ (when (<= beg (car lit-limits))
+ ;; The region to be filled includes the comment starter.
+ (goto-char (car lit-limits))
+ (if (looking-at (concat "\\(" comment-start-skip "\\)$"))
+ ;; Begin filling with the next line.
+ (setq beg (c-point 'bonl))
+ ;; Fake the fill prefix in the first line.
+ (setq tmp-pre t)))
+ ))
+ ((eq lit-type 'string) ; String.
+ (save-excursion
+ (when (>= end (cdr lit-limits))
+ (goto-char (1- (cdr lit-limits)))
+ (setq tmp-post (point-marker))
+ (insert ?\n)
+ (set-marker end (point)))
+ (when (<= beg (car lit-limits))
+ (goto-char (1+ (car lit-limits)))
+ (setq beg (if (looking-at "\\\\$")
+ ;; Leave the start line if it's
+ ;; nothing but an escaped newline.
+ (1+ (match-end 0))
+ (point))))))
+ (t (setq beg nil)))
+ (when tmp-pre
+ ;; Temporarily insert the fill prefix after the comment
+ ;; starter so that the first line looks like any other
+ ;; comment line in the narrowed region.
+ (setq fill (c-guess-fill-prefix lit-limits lit-type))
+ (unless (string-match (concat "\\`[ \t]*\\("
+ c-comment-prefix-regexp
+ "\\)[ \t]*\\'")
+ (car fill))
+ ;; Oops, the prefix doesn't match the comment prefix
+ ;; regexp. This could produce very confusing
+ ;; results with adaptive fill packages together with
+ ;; the insert prefix magic below, since the prefix
+ ;; often doesn't appear at all. So let's warn about
+ ;; it.
+ (message "\
+Warning: `c-comment-prefix-regexp' doesn't match the comment prefix %S"
+ (car fill)))
+ ;; Find the right spot on the line, break it, insert
+ ;; the fill prefix and make sure we're back in the
+ ;; same column by temporarily prefixing the first word
+ ;; with a number of 'x'.
+ (save-excursion
+ (goto-char (car lit-limits))
+ (if (looking-at (if (eq lit-type 'c++)
+ c-comment-prefix-regexp
+ comment-start-skip))
+ (goto-char (match-end 0))
+ (forward-char 2)
+ (skip-chars-forward " \t"))
+ (while (< (current-column) (cdr fill)) (forward-char 1))
+ (let ((col (current-column)))
+ (setq beg (1+ (point))
+ tmp-pre (list (point)))
+ (unwind-protect
+ (progn
+ (insert ?\n (car fill))
+ (insert (make-string (- col (current-column)) ?x)))
+ (setcdr tmp-pre (point))))))
+ (when beg
+ (let ((fill-paragraph-function
+ ;; Avoid infinite recursion.
+ (if (not (eq fill-paragraph-function 'c-fill-paragraph))
+ fill-paragraph-function))
+ (fill-prefix
+ (or fill-prefix
+ (when (and (eq lit-type 'c++)
+ (not (string-match
+ "\\`[ \t]*//"
+ (or (fill-context-prefix beg end)
+ ""))))
+ ;; Kludge: If the function that adapts the
+ ;; fill prefix doesn't produce the required
+ ;; comment starter for line comments, then
+ ;; force it by setting fill-prefix.
+ (car (or fill (c-guess-fill-prefix
+ lit-limits lit-type)))))))
+ ;; Preparations finally done! Now we can call the
+ ;; real fill function.
+ (save-restriction
+ (narrow-to-region beg end)
+ (fill-paragraph arg)))))
+ (when (consp tmp-pre)
+ (delete-region (car tmp-pre) (cdr tmp-pre)))
+ (when tmp-post
+ (save-excursion
+ (goto-char tmp-post)
+ (delete-char 1)
+ (when hang-ender-stuck
+ (skip-syntax-backward "^w ")
+ (forward-char -1)
+ (insert ?\ )
+ (delete-char 1))
+ (set-marker tmp-post nil)))))
+ (set-marker end nil))
+ ;; Always return t. This has the effect that if filling isn't done
+ ;; above, it isn't done at all, and it's therefore effectively
+ ;; disabled in normal code.
+ t)
+
+(defun c-do-auto-fill ()
+ ;; Do automatic filling if not inside a context where it should be
+ ;; ignored.
+ (let ((c-auto-fill-prefix
+ ;; The decision whether the line should be broken is actually
+ ;; done in c-indent-new-comment-line, which do-auto-fill
+ ;; calls to break lines. We just set this special variable
+ ;; so that we'll know when we're called from there. It's
+ ;; also used to detect whether fill-prefix is user set or
+ ;; generated automatically by do-auto-fill.
+ fill-prefix))
+ (do-auto-fill)))
+
+(defun c-indent-new-comment-line (&optional soft)
+ "Break line at point and indent, continuing comment if within one.
+If inside a comment and `comment-multi-line' is non-nil, the
+indentation and line prefix are preserved (see the
+`c-comment-prefix-regexp' and `c-block-comment-prefix' variables for
+details). If inside a comment and `comment-multi-line' is nil, a new
+comment of the same type is started on the next line and indented as
+appropriate for comments.
+
+If a fill prefix is specified, it overrides all the above."
+ (interactive)
+ (let ((fill-prefix fill-prefix)
+ (do-line-break
+ (lambda ()
+ (delete-region (progn (skip-chars-backward " \t") (point))
+ (progn (skip-chars-forward " \t") (point)))
+ (if soft (insert-and-inherit ?\n) (newline 1))))
+ ;; Already know the literal type and limits when called from
+ ;; c-context-line-break.
+ (c-lit-limits (if (boundp 'c-lit-limits) c-lit-limits))
+ (c-lit-type (if (boundp 'c-lit-type) c-lit-type)))
+ (when (boundp 'c-auto-fill-prefix)
+ ;; Called from do-auto-fill.
+ (unless c-lit-limits
+ (setq c-lit-limits (c-literal-limits nil nil t)))
+ (unless c-lit-type
+ (setq c-lit-type (c-literal-type c-lit-limits)))
+ (if (memq (cond ((eq c-lit-type 'pound)
+ ;; Come to think about it, "pound" is a bit
+ ;; of a misnomer, so call it "cpp" instead
+ ;; in user interaction.
+ 'cpp)
+ ((null c-lit-type) 'code)
+ (t c-lit-type))
+ c-ignore-auto-fill)
+ (setq fill-prefix t) ; Used as flag in the cond.
+ (if (null c-auto-fill-prefix)
+ (setq fill-prefix nil))))
+ (cond ((eq fill-prefix t)
+ ;; A call from do-auto-fill which should be ignored.
+ )
+ (fill-prefix
+ ;; A fill-prefix overrides anything.
+ (funcall do-line-break)
+ (insert-and-inherit fill-prefix))
+ ((progn
+ (unless c-lit-limits
+ (setq c-lit-limits (c-literal-limits nil nil t)))
+ (unless c-lit-type
+ (setq c-lit-type (c-literal-type c-lit-limits)))
+ (memq c-lit-type '(c c++)))
+ (if comment-multi-line
+ ;; Inside a comment that should be continued.
+ (let ((fill (c-guess-fill-prefix
+ (setq c-lit-limits
+ (c-collect-line-comments c-lit-limits))
+ c-lit-type))
+ (pos (point)))
+ (if (save-excursion
+ (back-to-indentation)
+ (> (point) (car c-lit-limits))
+ (looking-at c-comment-prefix-regexp))
+ (progn
+ ;; Skip forward past the fill prefix in case
+ ;; we're standing in it.
+ (while (and (< (current-column) (cdr fill))
+ (not (eolp)))
+ (forward-char 1))
+ (if (> (point) (if (and (eq c-lit-type 'c)
+ (save-excursion
+ (forward-char -2)
+ (looking-at "\\*/")))
+ (- (cdr c-lit-limits) 2)
+ (cdr c-lit-limits)))
+ (progn
+ ;; The skip takes us out of the comment;
+ ;; insert the fill prefix at bol instead
+ ;; and keep the position.
+ (setq pos (copy-marker pos t))
+ (beginning-of-line)
+ (insert-and-inherit (car fill))
+ (if soft (insert-and-inherit ?\n) (newline 1))
+ (goto-char pos)
+ (set-marker pos nil))
+ (funcall do-line-break)
+ (insert-and-inherit (car fill))))
+ (funcall do-line-break)
+ (insert-and-inherit (car fill))))
+ ;; Inside a comment that should be broken.
+ (let ((comment-start comment-start)
+ (comment-end comment-end)
+ col)
+ (if (eq c-lit-type 'c)
+ (unless (string-match "[ \t]*/\\*" comment-start)
+ (setq comment-start "/* " comment-end " */"))
+ (unless (string-match "[ \t]*//" comment-start)
+ (setq comment-start "// " comment-end "")))
+ (setq col (save-excursion
+ (back-to-indentation)
+ (current-column)))
+ (funcall do-line-break)
+ (when (and comment-end (not (equal comment-end "")))
+ (forward-char -1)
+ (insert-and-inherit comment-end)
+ (forward-char 1))
+ ;; c-comment-indent may look at the current
+ ;; indentation, so let's start out with the same
+ ;; indentation as the previous one.
+ (indent-to col)
+ (insert-and-inherit comment-start)
+ (indent-for-comment))))
+ (t
+ ;; Somewhere else in the code.
+ (let ((col (save-excursion
+ (while (progn (back-to-indentation)
+ (and (looking-at "^\\s *$")
+ (= (forward-line -1) 0))))
+ (current-column))))
+ (funcall do-line-break)
+ (indent-to col))))))
+
+(defalias 'c-comment-line-break-function 'c-indent-new-comment-line)
+(make-obsolete 'c-comment-line-break-function 'c-indent-new-comment-line)
+
+;; advice for indent-new-comment-line for older Emacsen
+(unless (boundp 'comment-line-break-function)
+ (defadvice indent-new-comment-line (around c-line-break-advice
+ activate preactivate)
+ "Call `c-indent-new-comment-line' if in CC Mode."
+ (if (or (boundp 'c-inside-line-break-advice)
+ (not c-buffer-is-cc-mode))
+ ad-do-it
+ (let (c-inside-line-break-advice)
+ (c-indent-new-comment-line (ad-get-arg 0))))))
+
+(defun c-context-line-break ()
+ "Do a line break suitable to the context.
+
+When point is outside a comment, insert a newline and indent according
+to the syntactic context.
+
+When point is inside a comment, continue it with the appropriate
+comment prefix (see the `c-comment-prefix-regexp' and
+`c-block-comment-prefix' variables for details). The end of a
+C++-style line comment doesn't count as inside the comment, though."
+ (interactive "*")
+ (let* ((c-lit-limits (c-literal-limits nil nil t))
+ (c-lit-type (c-literal-type c-lit-limits)))
+ (if (or (eq c-lit-type 'c)
+ (and (eq c-lit-type 'c++)
+ (< (point)
+ (1- (cdr (setq c-lit-limits
+ (c-collect-line-comments c-lit-limits)))))))
+ (let ((comment-multi-line t)
+ (fill-prefix nil))
+ (c-indent-new-comment-line))
+ (delete-region (point) (progn (skip-chars-backward " \t") (point)))
+ (newline)
+ ;; c-indent-line may look at the current indentation, so let's
+ ;; start out with the same indentation as the previous line.
+ (let ((col (save-excursion
+ (forward-line -1)
+ (while (progn (back-to-indentation)
+ (and (looking-at "^\\s *$")
+ (= (forward-line -1) 0))))
+ (current-column))))
+ (indent-to col))
+ (c-indent-line))))
(provide 'cc-cmds)