-;;; cc-cmds.el --- user level commands for CC Mode
+;;; cc-cmds.el --- user level commands for CC Mode
-;; Copyright (C) 1985,87,92,93,94,95,96,97 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+;; Free Software Foundation, Inc.
-;; Authors: 1992-1997 Barry A. Warsaw
+;; Authors: 2003- Alan Mackenzie
+;; 1998- Martin Stjernholm
+;; 1992-1999 Barry A. Warsaw
;; 1987 Dave Detlefs and Stewart Clamen
;; 1985 Richard M. Stallman
-;; Maintainer: cc-mode-help@python.org
+;; Maintainer: bug-cc-mode@gnu.org
;; Created: 22-Apr-1997 (split from cc-mode.el)
-;; Version: 5.15
+;; Version: See cc-mode.el
;; Keywords: c languages oop
;; This file is part of GNU Emacs.
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; along with this program; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;; Commentary:
+
+;;; Code:
(eval-when-compile
- (require 'cc-defs))
+ (let ((load-path
+ (if (and (boundp 'byte-compile-dest-file)
+ (stringp byte-compile-dest-file))
+ (cons (file-name-directory byte-compile-dest-file) load-path)
+ load-path)))
+ (load "cc-bytecomp" nil t)))
+
+(cc-require 'cc-defs)
+(cc-require 'cc-vars)
+(cc-require 'cc-engine)
+;; Silence the compiler.
+(cc-bytecomp-defun delete-forward-p) ; XEmacs
+(cc-bytecomp-defvar filladapt-mode) ; c-fill-paragraph contains a kludge
+ ; which looks at this.
+(cc-bytecomp-defun c-forward-subword)
+(cc-bytecomp-defun c-backward-subword)
\f
-(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
- ;; the state off, and if arg is positive, turn the state on
- (if (or (not arg)
- (zerop (setq arg (prefix-numeric-value arg))))
- (not prevstate)
- (> arg 0)))
-
-;; Auto-newline and hungry-delete
-(defun c-toggle-auto-state (arg)
+;; Indentation / Display syntax functions
+(defvar c-fix-backslashes t)
+
+(defun c-indent-line (&optional syntax quiet ignore-point-pos)
+ "Indent the current line according to the syntactic context,
+if `c-syntactic-indentation' is non-nil. Optional SYNTAX is the
+syntactic information for the current line. Be silent about syntactic
+errors if the optional argument QUIET is non-nil, even if
+`c-report-syntactic-errors' is non-nil. Normally the position of
+point is used to decide where the old indentation is on a lines that
+is otherwise empty \(ignoring any line continuation backslash), but
+that's not done if IGNORE-POINT-POS is non-nil. Returns the amount of
+indentation change \(in columns)."
+
+ (let ((line-cont-backslash (save-excursion
+ (end-of-line)
+ (eq (char-before) ?\\)))
+ (c-fix-backslashes c-fix-backslashes)
+ bs-col
+ shift-amt)
+ (when (and (not ignore-point-pos)
+ (save-excursion
+ (beginning-of-line)
+ (looking-at (if line-cont-backslash
+ ;; Don't use "\\s " - ^L doesn't count as WS
+ ;; here
+ "\\([ \t]*\\)\\\\$"
+ "\\([ \t]*\\)$")))
+ (<= (point) (match-end 1)))
+ ;; Delete all whitespace after point if there's only whitespace
+ ;; on the line, so that any code that does back-to-indentation
+ ;; or similar gets the current column in this case. If this
+ ;; removes a line continuation backslash it'll be restored
+ ;; at the end.
+ (unless c-auto-align-backslashes
+ ;; Should try to keep the backslash alignment
+ ;; in this case.
+ (save-excursion
+ (goto-char (match-end 0))
+ (setq bs-col (1- (current-column)))))
+ (delete-region (point) (match-end 0))
+ (setq c-fix-backslashes t))
+ (if c-syntactic-indentation
+ (setq c-parsing-error
+ (or (let ((c-parsing-error nil)
+ (c-syntactic-context
+ (or syntax
+ (and (boundp 'c-syntactic-context)
+ c-syntactic-context))))
+ (c-save-buffer-state (indent)
+ (unless c-syntactic-context
+ (setq c-syntactic-context (c-guess-basic-syntax)))
+ (setq indent (c-get-syntactic-indentation
+ c-syntactic-context))
+ (and (not (c-echo-parsing-error quiet))
+ c-echo-syntactic-information-p
+ (message "syntax: %s, indent: %d"
+ c-syntactic-context indent))
+ (setq shift-amt (- indent (current-indentation))))
+ (c-shift-line-indentation shift-amt)
+ (run-hooks 'c-special-indent-hook)
+ c-parsing-error)
+ c-parsing-error))
+ (let ((indent 0))
+ (save-excursion
+ (while (and (= (forward-line -1) 0)
+ (if (looking-at "\\s *\\\\?$")
+ t
+ (setq indent (current-indentation))
+ nil))))
+ (setq shift-amt (- indent (current-indentation)))
+ (c-shift-line-indentation shift-amt)))
+ (when (and c-fix-backslashes line-cont-backslash)
+ (if bs-col
+ (save-excursion
+ (indent-to bs-col)
+ (insert ?\\))
+ (when c-auto-align-backslashes
+ ;; Realign the line continuation backslash.
+ (c-backslash-region (point) (point) nil t))))
+ shift-amt))
+
+(defun c-newline-and-indent (&optional newline-arg)
+ "Insert a newline and indent the new line.
+This function fixes line continuation backslashes if inside a macro,
+and takes care to set the indentation before calling
+`indent-according-to-mode', so that lineup functions like
+`c-lineup-dont-change' works better."
+
+ ;; TODO: Backslashes before eol in comments and literals aren't
+ ;; kept intact.
+ (let ((c-macro-start (c-query-macro-start))
+ ;; Avoid calling c-backslash-region from c-indent-line if it's
+ ;; called during the newline call, which can happen due to
+ ;; c-electric-continued-statement, for example. We also don't
+ ;; want any backslash alignment from indent-according-to-mode.
+ (c-fix-backslashes nil)
+ has-backslash insert-backslash
+ start col)
+ (save-excursion
+ (beginning-of-line)
+ (setq start (point))
+ (while (and (looking-at "[ \t]*\\\\?$")
+ (= (forward-line -1) 0)))
+ (setq col (current-indentation)))
+ (when c-macro-start
+ (if (and (eolp) (eq (char-before) ?\\))
+ (setq insert-backslash t
+ has-backslash t)
+ (setq has-backslash (eq (char-before (c-point 'eol)) ?\\))))
+ (newline newline-arg)
+ (indent-to col)
+ (when c-macro-start
+ (if insert-backslash
+ (progn
+ ;; The backslash stayed on the previous line. Insert one
+ ;; before calling c-backslash-region, so that
+ ;; bs-col-after-end in it works better. Fixup the
+ ;; backslashes on the newly inserted line.
+ (insert ?\\)
+ (backward-char)
+ (c-backslash-region (point) (point) nil t))
+ ;; The backslash moved to the new line, if there was any. Let
+ ;; c-backslash-region fix a backslash on the previous line,
+ ;; and the one that might be on the new line.
+ ;; c-auto-align-backslashes is intentionally ignored here;
+ ;; maybe the moved backslash should be left alone if it's set,
+ ;; but we fix both lines on the grounds that the old backslash
+ ;; has been moved anyway and is now in a different context.
+ (c-backslash-region start (if has-backslash (point) start) nil t)))
+ (when c-syntactic-indentation
+ ;; Reindent syntactically. The indentation done above is not
+ ;; wasted, since c-indent-line might look at the current
+ ;; indentation.
+ (let ((c-syntactic-context (c-save-buffer-state nil
+ (c-guess-basic-syntax))))
+ ;; We temporarily insert another line break, so that the
+ ;; lineup functions will see the line as empty. That makes
+ ;; e.g. c-lineup-cpp-define more intuitive since it then
+ ;; proceeds to the preceding line in this case.
+ (insert ?\n)
+ (delete-horizontal-space)
+ (setq start (- (point-max) (point)))
+ (unwind-protect
+ (progn
+ (backward-char)
+ (indent-according-to-mode))
+ (goto-char (- (point-max) start))
+ (delete-char -1)))
+ (when has-backslash
+ ;; Must align the backslash again after reindentation. The
+ ;; c-backslash-region call above can't be optimized to ignore
+ ;; this line, since it then won't align correctly with the
+ ;; lines below if the first line in the macro is broken.
+ (c-backslash-region (point) (point) nil t)))))
+
+(defun c-show-syntactic-information (arg)
+ "Show syntactic information for current line.
+With universal argument, inserts the analysis as a comment on that line."
+ (interactive "P")
+ (let* ((c-parsing-error nil)
+ (syntax (if (boundp 'c-syntactic-context)
+ ;; Use `c-syntactic-context' in the same way as
+ ;; `c-indent-line', to be consistent.
+ c-syntactic-context
+ (c-save-buffer-state nil
+ (c-guess-basic-syntax)))))
+ (if (not (consp arg))
+ (let (elem pos ols)
+ (message "Syntactic analysis: %s" syntax)
+ (unwind-protect
+ (progn
+ (while syntax
+ (setq elem (pop syntax))
+ (when (setq pos (c-langelem-pos elem))
+ (push (c-put-overlay pos (1+ pos)
+ 'face 'highlight)
+ ols))
+ (when (setq pos (c-langelem-2nd-pos elem))
+ (push (c-put-overlay pos (1+ pos)
+ 'face 'secondary-selection)
+ ols)))
+ (sit-for 10))
+ (while ols
+ (c-delete-overlay (pop ols)))))
+ (indent-for-comment)
+ (insert-and-inherit (format "%s" syntax))
+ ))
+ (c-keep-region-active))
+
+(defun c-syntactic-information-on-region (from to)
+ "Insert a comment with the syntactic analysis on every line in the region."
+ (interactive "*r")
+ (save-excursion
+ (save-restriction
+ (narrow-to-region from to)
+ (goto-char (point-min))
+ (while (not (eobp))
+ (c-show-syntactic-information '(0))
+ (forward-line)))))
+
+\f
+;; Minor mode functions.
+(defun c-update-modeline ()
+ (let ((fmt (format "/%s%s%s%s"
+ (if c-electric-flag "l" "")
+ (if (and c-electric-flag c-auto-newline)
+ "a" "")
+ (if c-hungry-delete-key "h" "")
+ (if (and
+ ;; cc-subword might not be loaded.
+ (boundp 'c-subword-mode)
+ (symbol-value 'c-subword-mode))
+ "w"
+ "")))
+ (bare-mode-name (if (string-match "\\(^[^/]*\\)/" mode-name)
+ (substring mode-name (match-beginning 1) (match-end 1))
+ mode-name)))
+;; (setq c-submode-indicators
+;; (if (> (length fmt) 1)
+;; fmt))
+ (setq mode-name
+ (if (> (length fmt) 1)
+ (concat bare-mode-name fmt)
+ bare-mode-name))
+ (force-mode-line-update)))
+
+(defun c-toggle-syntactic-indentation (&optional arg)
+ "Toggle syntactic indentation.
+Optional numeric ARG, if supplied, turns on syntactic indentation when
+positive, turns it off when negative, and just toggles it when zero or
+left out.
+
+When syntactic indentation is turned on (the default), the indentation
+functions and the electric keys indent according to the syntactic
+context keys, when applicable.
+
+When it's turned off, the electric keys don't reindent, the indentation
+functions indents every new line to the same level as the previous
+nonempty line, and \\[c-indent-command] adjusts the indentation in steps
+specified by `c-basic-offset'. The indentation style has no effect in
+this mode, nor any of the indentation associated variables,
+e.g. `c-special-indent-hook'.
+
+This command sets the variable `c-syntactic-indentation'."
+ (interactive "P")
+ (setq c-syntactic-indentation
+ (c-calculate-state arg c-syntactic-indentation))
+ (c-keep-region-active))
+
+(defun c-toggle-auto-newline (&optional arg)
"Toggle auto-newline feature.
-Optional numeric ARG, if supplied turns on auto-newline when positive,
-turns it off when negative, and just toggles it when zero.
+Optional numeric ARG, if supplied, turns on auto-newline when
+positive, turns it off when negative, and just toggles it when zero or
+left out.
-When the auto-newline feature is enabled (as evidenced by the `/a' or
-`/ah' on the modeline after the mode name) newlines are automatically
-inserted after special characters such as brace, comma, semi-colon,
-and colon."
+Turning on auto-newline automatically enables electric indentation.
+
+When the auto-newline feature is enabled (indicated by \"/la\" on the
+modeline after the mode name) newlines are automatically inserted
+after special characters such as brace, comma, semi-colon, and colon."
(interactive "P")
- (setq c-auto-newline (c-calculate-state arg c-auto-newline))
+ (setq c-auto-newline
+ (c-calculate-state arg (and c-auto-newline c-electric-flag)))
+ (if c-auto-newline (setq c-electric-flag t))
(c-update-modeline)
(c-keep-region-active))
-(defun c-toggle-hungry-state (arg)
+(defalias 'c-toggle-auto-state 'c-toggle-auto-newline)
+(make-obsolete 'c-toggle-auto-state 'c-toggle-auto-newline)
+
+(defun c-toggle-hungry-state (&optional arg)
"Toggle hungry-delete-key feature.
-Optional numeric ARG, if supplied turns on hungry-delete when positive,
-turns it off when negative, and just toggles it when zero.
+Optional numeric ARG, if supplied, turns on hungry-delete when
+positive, turns it off when negative, and just toggles it when zero or
+left out.
-When the hungry-delete-key feature is enabled (as evidenced by the
-`/h' or `/ah' on the modeline after the mode name) the delete key
-gobbles all preceding whitespace in one fell swoop."
+When the hungry-delete-key feature is enabled (indicated by \"/h\" on
+the modeline after the mode name) the delete key gobbles all preceding
+whitespace in one fell swoop."
(interactive "P")
(setq c-hungry-delete-key (c-calculate-state arg c-hungry-delete-key))
(c-update-modeline)
(c-keep-region-active))
-(defun c-toggle-auto-hungry-state (arg)
+(defun c-toggle-auto-hungry-state (&optional arg)
"Toggle auto-newline and hungry-delete-key features.
-Optional numeric ARG, if supplied turns on auto-newline and
+Optional numeric ARG, if supplied, turns on auto-newline and
hungry-delete when positive, turns them off when negative, and just
-toggles them when zero.
+toggles them when zero or left out.
-See `c-toggle-auto-state' and `c-toggle-hungry-state' for details."
+See `c-toggle-auto-newline' and `c-toggle-hungry-state' for details."
(interactive "P")
(setq c-auto-newline (c-calculate-state arg c-auto-newline))
(setq c-hungry-delete-key (c-calculate-state arg c-hungry-delete-key))
(c-update-modeline)
(c-keep-region-active))
+(defun c-toggle-electric-state (&optional arg)
+ "Toggle the electric indentation feature.
+Optional numeric ARG, if supplied, turns on electric indentation when
+positive, turns it off when negative, and just toggles it when zero or
+left out."
+ (interactive "P")
+ (setq c-electric-flag (c-calculate-state arg c-electric-flag))
+ (c-update-modeline)
+ (c-keep-region-active))
+
\f
;; Electric keys
-;; Note: In XEmacs 20.3 the Delete and BackSpace keysyms have been
-;; separated and "\177" is no longer an alias for both keys. Also,
-;; the variable delete-key-deletes-forward controls in which direction
-;; the Delete keysym deletes characters. The functions
-;; c-electric-delete and c-electric-backspace attempt to deal with
-;; this new functionality. For Emacs 19 and XEmacs 19 backwards
-;; compatibility, the old behavior has moved to c-electric-backspace
-;; and c-backspace-function.
-
(defun c-electric-backspace (arg)
- "Deletes preceding character or whitespace.
-If `c-hungry-delete-key' is non-nil, as evidenced by the \"/h\" or
-\"/ah\" string on the mode line, then all preceding whitespace is
-consumed. If however an ARG is supplied, or `c-hungry-delete-key' is
-nil, or point is inside a literal then the function in the variable
-`c-backspace-function' is called.
-
-See also \\[c-electric-delete]."
- (interactive "P")
- (if (or (not c-hungry-delete-key)
- arg
- (c-in-literal))
+ "Delete the preceding character or whitespace.
+If `c-hungry-delete-key' is non-nil (indicated by \"/h\" on the mode
+line) then all preceding whitespace is consumed. If however a prefix
+argument is supplied, or `c-hungry-delete-key' is nil, or point is
+inside a literal then the function in the variable
+`c-backspace-function' is called."
+ (interactive "*P")
+ (if (c-save-buffer-state ()
+ (or (not c-hungry-delete-key)
+ arg
+ (c-in-literal)))
(funcall c-backspace-function (prefix-numeric-value arg))
- (let ((here (point)))
- (skip-chars-backward " \t\n")
- (if (/= (point) here)
- (delete-region (point) here)
- (funcall c-backspace-function 1)
- ))))
+ (c-hungry-delete-backwards)))
+
+(defun c-hungry-delete-backwards ()
+ "Delete the preceding character or all preceding whitespace
+back to the previous non-whitespace character.
+See also \\[c-hungry-delete-forward]."
+ (interactive)
+ (let ((here (point)))
+ (c-skip-ws-backward)
+ (if (/= (point) here)
+ (delete-region (point) here)
+ (funcall c-backspace-function 1))))
+
+(defalias 'c-hungry-backspace 'c-hungry-delete-backwards)
+(defun c-electric-delete-forward (arg)
+ "Delete the following character or whitespace.
+If `c-hungry-delete-key' is non-nil (indicated by \"/h\" on the mode
+line) then all following whitespace is consumed. If however a prefix
+argument is supplied, or `c-hungry-delete-key' is nil, or point is
+inside a literal then the function in the variable `c-delete-function'
+is called."
+ (interactive "*P")
+ (if (c-save-buffer-state ()
+ (or (not c-hungry-delete-key)
+ arg
+ (c-in-literal)))
+ (funcall c-delete-function (prefix-numeric-value arg))
+ (c-hungry-delete-forward)))
+
+(defun c-hungry-delete-forward ()
+ "Delete the following character or all following whitespace
+up to the next non-whitespace character.
+See also \\[c-hungry-delete-backwards]."
+ (interactive)
+ (let ((here (point)))
+ (c-skip-ws-forward)
+ (if (/= (point) here)
+ (delete-region (point) here)
+ (funcall c-delete-function 1))))
+
+;; This function is only used in XEmacs.
(defun c-electric-delete (arg)
"Deletes preceding or following character or whitespace.
+This function either deletes forward as `c-electric-delete-forward' or
+backward as `c-electric-backspace', depending on the configuration: If
+the function `delete-forward-p' is defined and returns non-nil, it
+deletes forward. Otherwise it deletes backward.
-The behavior of this function depends on the variable
-`delete-key-deletes-forward'. If this variable is nil (or does not
-exist, as in older Emacsen), then this function behaves identical to
-\\[c-electric-backspace].
-
-If `delete-key-deletes-forward' is non-nil, then deletion occurs in
-the forward direction. So if `c-hungry-delete-key' is non-nil, as
-evidenced by the \"/h\" or \"/ah\" string on the mode line, then all
-following whitespace is consumed. If however an ARG is supplied, or
-`c-hungry-delete-key' is nil, or point is inside a literal then the
-function in the variable `c-delete-function' is called."
- (interactive "P")
- (if (and (boundp 'delete-key-deletes-forward)
- delete-key-deletes-forward)
- (if (or (not c-hungry-delete-key)
- arg
- (c-in-literal))
- (funcall c-delete-function (prefix-numeric-value arg))
- (let ((here (point)))
- (skip-chars-forward " \t\n")
- (if (/= (point) here)
- (delete-region (point) here)
- (funcall c-delete-function 1))))
- ;; act just like c-electric-backspace
+Note: This is the way in XEmacs to choose the correct action for the
+\[delete] key, whichever key that means. Other flavors don't use this
+function to control that."
+ (interactive "*P")
+ (if (and (fboundp 'delete-forward-p)
+ (delete-forward-p))
+ (c-electric-delete-forward arg)
(c-electric-backspace arg)))
+;; This function is only used in XEmacs.
+(defun c-hungry-delete ()
+ "Delete a non-whitespace char, or all whitespace up to the next non-whitespace char.
+The direction of deletion depends on the configuration: If the
+function `delete-forward-p' is defined and returns non-nil, it deletes
+forward using `c-hungry-delete-forward'. Otherwise it deletes
+backward using `c-hungry-backspace'.
+
+Note: This is the way in XEmacs to choose the correct action for the
+\[delete] key, whichever key that means. Other flavors don't use this
+function to control that."
+ (interactive)
+ (if (and (fboundp 'delete-forward-p)
+ (delete-forward-p))
+ (c-hungry-delete-forward)
+ (c-hungry-delete-backwards)))
+
(defun c-electric-pound (arg)
- "Electric pound (`#') insertion.
-Inserts a `#' character specially depending on the variable
-`c-electric-pound-behavior'. If a numeric ARG is supplied, or if
-point is inside a literal, nothing special happens."
- (interactive "P")
- (if (or (c-in-literal)
- arg
- (not (memq 'alignleft c-electric-pound-behavior)))
+ "Insert a \"#\".
+If `c-electric-flag' is set, handle it specially according to the variable
+`c-electric-pound-behavior'. If a numeric ARG is supplied, or if point is
+inside a literal or a macro, nothing special happens."
+ (interactive "*P")
+ (if (c-save-buffer-state ()
+ (or arg
+ (not c-electric-flag)
+ (not (memq 'alignleft c-electric-pound-behavior))
+ (save-excursion
+ (skip-chars-backward " \t")
+ (not (bolp)))
+ (save-excursion
+ (and (= (forward-line -1) 0)
+ (progn (end-of-line)
+ (eq (char-before) ?\\))))
+ (c-in-literal)))
;; do nothing special
(self-insert-command (prefix-numeric-value arg))
;; place the pound character at the left edge
(bolp (bolp)))
(beginning-of-line)
(delete-horizontal-space)
- (insert-char last-command-char 1)
+ (insert last-command-char)
(and (not bolp)
(goto-char (- (point-max) pos)))
)))
+(defun c-point-syntax ()
+ ;; Return the syntactic context of the construct at point. (This is NOT
+ ;; nec. the same as the s.c. of the line point is on). N.B. This won't work
+ ;; between the `#' of a cpp thing and what follows (see c-opt-cpp-prefix).
+ (c-save-buffer-state (;; shut this up too
+ (c-echo-syntactic-information-p nil)
+ syntax)
+ (c-tentative-buffer-changes
+ ;; insert a newline to isolate the construct at point for syntactic
+ ;; analysis.
+ (insert-char ?\n 1)
+ ;; In AWK (etc.) or in a macro, make sure this CR hasn't changed
+ ;; the syntax. (There might already be an escaped NL there.)
+ (when (or (c-at-vsemi-p (1- (point)))
+ (let ((pt (point)))
+ (save-excursion
+ (backward-char)
+ (and (c-beginning-of-macro)
+ (progn (c-end-of-macro)
+ (< (point) pt))))))
+ (backward-char)
+ (insert-char ?\\ 1)
+ (forward-char))
+ (let ((c-syntactic-indentation-in-macros t)
+ (c-auto-newline-analysis t))
+ ;; Turn on syntactic macro analysis to help with auto
+ ;; newlines only.
+ (setq syntax (c-guess-basic-syntax))
+ nil))
+ syntax))
+
+(defun c-brace-newlines (syntax)
+ ;; A brace stands at point. SYNTAX is the syntactic context of this brace
+ ;; (not necessarily the same as the S.C. of the line it is on). Return
+ ;; NEWLINES, the list containing some combination of the symbols `before'
+ ;; and `after' saying where newlines should be inserted.
+ (c-save-buffer-state
+ ((syms
+ ;; This is the list of brace syntactic symbols that can hang.
+ ;; If any new ones are added to c-offsets-alist, they should be
+ ;; added here as well.
+ '(class-open class-close defun-open defun-close
+ inline-open inline-close
+ brace-list-open brace-list-close
+ brace-list-intro brace-entry-open
+ block-open block-close
+ substatement-open statement-case-open
+ extern-lang-open extern-lang-close
+ namespace-open namespace-close
+ module-open module-close
+ composition-open composition-close
+ inexpr-class-open inexpr-class-close
+ ;; `statement-cont' is here for the case with a brace
+ ;; list opener inside a statement. C.f. CASE B.2 in
+ ;; `c-guess-continued-construct'.
+ statement-cont))
+ ;; shut this up too
+ (c-echo-syntactic-information-p nil)
+ symb-newlines) ; e.g. (substatement-open . (after))
+
+ (setq symb-newlines
+ ;; Do not try to insert newlines around a special
+ ;; (Pike-style) brace list.
+ (if (and c-special-brace-lists
+ (save-excursion
+ (c-safe (if (= (char-before) ?{)
+ (forward-char -1)
+ (c-forward-sexp -1))
+ (c-looking-at-special-brace-list))))
+ nil
+ ;; Seek the matching entry in c-hanging-braces-alist.
+ (or (c-lookup-lists
+ syms
+ ;; Substitute inexpr-class and class-open or
+ ;; class-close with inexpr-class-open or
+ ;; inexpr-class-close.
+ (if (assq 'inexpr-class syntax)
+ (cond ((assq 'class-open syntax)
+ '((inexpr-class-open)))
+ ((assq 'class-close syntax)
+ '((inexpr-class-close)))
+ (t syntax))
+ syntax)
+ c-hanging-braces-alist)
+ '(ignore before after)))) ; Default, when not in c-h-b-l.
+
+ ;; If syntax is a function symbol, then call it using the
+ ;; defined semantics.
+ (if (and (not (consp (cdr symb-newlines)))
+ (functionp (cdr symb-newlines)))
+ (let ((c-syntactic-context syntax))
+ (funcall (cdr symb-newlines)
+ (car symb-newlines)
+ (point)))
+ (cdr symb-newlines))))
+
+(defun c-try-one-liner ()
+ ;; Point is just after a newly inserted }. If the non-whitespace
+ ;; content of the braces is a single line of code, compact the whole
+ ;; construct to a single line, if this line isn't too long. The Right
+ ;; Thing is done with comments.
+ ;;
+ ;; Point will be left after the }, regardless of whether the clean-up is
+ ;; done. Return NON-NIL if the clean-up happened, NIL if it didn't.
+
+ (let ((here (point))
+ (pos (- (point-max) (point)))
+ mbeg1 mend1 mbeg4 mend4
+ eol-col cmnt-pos cmnt-col cmnt-gap)
+
+ (when
+ (save-excursion
+ (save-restriction
+ ;; Avoid backtracking over a very large block. The one we
+ ;; deal with here can never be more than three lines.
+ (narrow-to-region (save-excursion
+ (forward-line -2)
+ (point))
+ (point))
+ (and (c-safe (c-backward-sexp))
+ (progn
+ (forward-char)
+ (narrow-to-region (point) (1- here)) ; innards of {.}
+ (looking-at
+ (cc-eval-when-compile
+ (concat
+ "\\(" ; (match-beginning 1)
+ "[ \t]*\\([\r\n][ \t]*\\)?" ; WS with opt. NL
+ "\\)" ; (match-end 1)
+ "[^ \t\r\n]+\\([ \t]+[^ \t\r\n]+\\)*" ; non-WS
+ "\\(" ; (match-beginning 4)
+ "[ \t]*\\([\r\n][ \t]*\\)?" ; WS with opt. NL
+ "\\)\\'"))))))) ; (match-end 4) at EOB.
+
+ (if (c-tentative-buffer-changes
+ (setq mbeg1 (match-beginning 1) mend1 (match-end 1)
+ mbeg4 (match-beginning 4) mend4 (match-end 4))
+ (backward-char) ; back over the `}'
+ (save-excursion
+ (setq cmnt-pos (and (c-backward-single-comment)
+ (- (point) (- mend1 mbeg1)))))
+ (delete-region mbeg4 mend4)
+ (delete-region mbeg1 mend1)
+ (setq eol-col (save-excursion (end-of-line) (current-column)))
+
+ ;; Necessary to put the closing brace before any line
+ ;; oriented comment to keep it syntactically significant.
+ ;; This isn't necessary for block comments, but the result
+ ;; looks nicer anyway.
+ (when cmnt-pos
+ (delete-char 1) ; the `}' has blundered into a comment
+ (goto-char cmnt-pos)
+ (setq cmnt-col (1+ (current-column)))
+ (setq cmnt-pos (1+ cmnt-pos)) ; we're inserting a `}'
+ (c-skip-ws-backward)
+ (insert-char ?\} 1) ; reinsert the `}' before the comment.
+ (setq cmnt-gap (- cmnt-col (current-column)))
+ (when (zerop cmnt-gap)
+ (insert-char ?\ 1) ; Put a space before a bare comment.
+ (setq cmnt-gap 1)))
+
+ (or (null c-max-one-liner-length)
+ (zerop c-max-one-liner-length)
+ (<= eol-col c-max-one-liner-length)
+ ;; Can we trim space before comment to make the line fit?
+ (and cmnt-gap
+ (< (- eol-col cmnt-gap) c-max-one-liner-length)
+ (progn (goto-char cmnt-pos)
+ (backward-delete-char-untabify
+ (- eol-col c-max-one-liner-length))
+ t))))
+ (goto-char (- (point-max) pos))))))
+
(defun c-electric-brace (arg)
"Insert a brace.
-If the auto-newline feature is turned on, as evidenced by the \"/a\"
-or \"/ah\" string on the mode line, newlines are inserted before and
-after braces based on the value of `c-hanging-braces-alist'.
+If `c-electric-flag' is non-nil, the brace is not inside a literal and a
+numeric ARG hasn't been supplied, the command performs several electric
+actions:
+
+\(a) If the auto-newline feature is turned on (indicated by \"/la\" on
+the mode line) newlines are inserted before and after the brace as
+directed by the settings in `c-hanging-braces-alist'.
+
+\(b) Any auto-newlines are indented. The original line is also
+reindented unless `c-syntactic-indentation' is nil.
+
+\(c) If auto-newline is turned on, various newline cleanups based on the
+settings of `c-cleanup-list' are done."
+
+ (interactive "*P")
+ (let (safepos literal
+ ;; We want to inhibit blinking the paren since this would be
+ ;; most disruptive. We'll blink it ourselves later on.
+ (old-blink-paren blink-paren-function)
+ blink-paren-function)
+
+ (c-save-buffer-state ()
+ (setq safepos (c-safe-position (point) (c-parse-state))
+ literal (c-in-literal safepos)))
+
+ ;; Insert the brace. Note that expand-abbrev might reindent
+ ;; the line here if there's a preceding "else" or something.
+ (self-insert-command (prefix-numeric-value arg))
+
+ (when (and c-electric-flag (not literal) (not arg))
+ (if (not (looking-at "[ \t]*\\\\?$"))
+ (if c-syntactic-indentation
+ (indent-according-to-mode))
+
+ (let ( ;; shut this up too
+ (c-echo-syntactic-information-p nil)
+ newlines
+ ln-syntax br-syntax syntax) ; Syntactic context of the original line,
+ ; of the brace itself, of the line the brace ends up on.
+ (c-save-buffer-state ((c-syntactic-indentation-in-macros t)
+ (c-auto-newline-analysis t))
+ (setq ln-syntax (c-guess-basic-syntax)))
+ (if c-syntactic-indentation
+ (c-indent-line ln-syntax))
+
+ (when c-auto-newline
+ (backward-char)
+ (setq br-syntax (c-point-syntax)
+ newlines (c-brace-newlines br-syntax))
+
+ ;; Insert the BEFORE newline, if wanted, and reindent the newline.
+ (if (and (memq 'before newlines)
+ (> (current-column) (current-indentation)))
+ (if c-syntactic-indentation
+ ;; Only a plain newline for now - it's indented
+ ;; after the cleanups when the line has its final
+ ;; appearance.
+ (newline)
+ (c-newline-and-indent)))
+ (forward-char)
+
+ ;; `syntax' is the syntactic context of the line which ends up
+ ;; with the brace on it.
+ (setq syntax (if (memq 'before newlines) br-syntax ln-syntax))
+
+ ;; Do all appropriate clean ups
+ (let ((here (point))
+ (pos (- (point-max) (point)))
+ mbeg mend
+ )
+
+ ;; `}': clean up empty defun braces
+ (when (c-save-buffer-state ()
+ (and (memq 'empty-defun-braces c-cleanup-list)
+ (eq last-command-char ?\})
+ (c-intersect-lists '(defun-close class-close inline-close)
+ syntax)
+ (progn
+ (forward-char -1)
+ (c-skip-ws-backward)
+ (eq (char-before) ?\{))
+ ;; make sure matching open brace isn't in a comment
+ (not (c-in-literal))))
+ (delete-region (point) (1- here))
+ (setq here (- (point-max) pos)))
+ (goto-char here)
+
+ ;; `}': compact to a one-liner defun?
+ (save-match-data
+ (when
+ (and (eq last-command-char ?\})
+ (memq 'one-liner-defun c-cleanup-list)
+ (c-intersect-lists '(defun-close) syntax)
+ (c-try-one-liner))
+ (setq here (- (point-max) pos))))
+
+ ;; `{': clean up brace-else-brace and brace-elseif-brace
+ (when (eq last-command-char ?\{)
+ (cond
+ ((and (memq 'brace-else-brace c-cleanup-list)
+ (re-search-backward
+ (concat "}"
+ "\\([ \t\n]\\|\\\\\n\\)*"
+ "else"
+ "\\([ \t\n]\\|\\\\\n\\)*"
+ "{"
+ "\\=")
+ nil t))
+ (delete-region (match-beginning 0) (match-end 0))
+ (insert-and-inherit "} else {"))
+ ((and (memq 'brace-elseif-brace c-cleanup-list)
+ (progn
+ (goto-char (1- here))
+ (setq mend (point))
+ (c-skip-ws-backward)
+ (setq mbeg (point))
+ (eq (char-before) ?\)))
+ (zerop (c-save-buffer-state nil (c-backward-token-2 1 t)))
+ (eq (char-after) ?\()
+ ; (progn
+ ; (setq tmp (point))
+ (re-search-backward
+ (concat "}"
+ "\\([ \t\n]\\|\\\\\n\\)*"
+ "else"
+ "\\([ \t\n]\\|\\\\\n\\)+"
+ "if"
+ "\\([ \t\n]\\|\\\\\n\\)*"
+ "\\=")
+ nil t);)
+ ;(eq (match-end 0) tmp);
+ )
+ (delete-region mbeg mend)
+ (goto-char mbeg)
+ (insert ?\ ))))
-Also, the line is re-indented unless a numeric ARG is supplied, there
-are non-whitespace characters present on the line after the brace, or
-the brace is inserted inside a literal."
- (interactive "P")
- (let* ((c-state-cache (c-parse-state))
- (safepos (c-safe-position (point) c-state-cache))
- (literal (c-in-literal safepos)))
- ;; if we're in a literal, or we're not at the end of the line, or
- ;; a numeric arg is provided, or auto-newlining is turned off,
- ;; then just insert the character.
- (if (or literal arg
-; (not c-auto-newline)
- (not (looking-at "[ \t]*$")))
- (self-insert-command (prefix-numeric-value arg))
- (let* ((syms '(class-open class-close defun-open defun-close
- inline-open inline-close brace-list-open brace-list-close
- brace-list-intro brace-list-entry block-open block-close
- substatement-open statement-case-open
- extern-lang-open extern-lang-close))
- ;; we want to inhibit blinking the paren since this will
- ;; be most disruptive. we'll blink it ourselves later on
- (old-blink-paren blink-paren-function)
- blink-paren-function
- (insertion-point (point))
- delete-temp-newline
- (preserve-p (and (not (bobp))
- (eq ?\ (char-syntax (char-before)))))
- ;; shut this up too
- (c-echo-syntactic-information-p nil)
- (syntax (progn
- ;; only insert a newline if there is
- ;; non-whitespace behind us
- (if (save-excursion
- (skip-chars-backward " \t")
- (not (bolp)))
- (progn (newline)
- (setq delete-temp-newline t)))
- (self-insert-command (prefix-numeric-value arg))
- ;; state cache doesn't change
- (c-guess-basic-syntax)))
- (newlines (and
- c-auto-newline
- (or (c-lookup-lists syms syntax c-hanging-braces-alist)
- '(ignore before after)))))
- ;; If syntax is a function symbol, then call it using the
- ;; defined semantics.
- (if (and (not (consp (cdr newlines)))
- (functionp (cdr newlines)))
- (let ((c-syntactic-context syntax))
- (setq newlines
- (funcall (cdr newlines) (car newlines) insertion-point))))
- ;; does a newline go before the open brace?
- (if (memq 'before newlines)
- ;; we leave the newline we've put in there before,
- ;; but we need to re-indent the line above
- (let ((pos (- (point-max) (point)))
- (here (point))
- (c-state-cache c-state-cache))
- (forward-line -1)
- ;; we may need to update the cache. this should still be
- ;; faster than recalculating the state in many cases
- (save-excursion
- (save-restriction
- (narrow-to-region here (point))
- (if (and (c-safe (progn (backward-up-list -1) t))
- (memq (char-before) '(?\) ?}))
- (progn (widen)
- (c-safe (progn (forward-sexp -1) t))))
- (setq c-state-cache
- (c-hack-state (point) 'open c-state-cache))
- (if (and (car c-state-cache)
- (not (consp (car c-state-cache)))
- (<= (point) (car c-state-cache)))
- (setq c-state-cache (cdr c-state-cache))
- ))))
- (let ((here (point))
- (shift (c-indent-line)))
- (setq c-state-cache (c-adjust-state (c-point 'bol) here
- (- shift) c-state-cache)))
(goto-char (- (point-max) pos))
- ;; if the buffer has changed due to the indentation, we
- ;; need to recalculate syntax for the current line, but
- ;; we won't need to update the state cache.
- (if (/= (point) here)
- (setq syntax (c-guess-basic-syntax))))
- ;; must remove the newline we just stuck in (if we really did it)
- (and delete-temp-newline
- (save-excursion
- ;; if there is whitespace before point, then preserve
- ;; at least one space.
- (delete-indentation)
- (just-one-space)
- (if (not preserve-p)
- (delete-char -1))))
- ;; since we're hanging the brace, we need to recalculate
- ;; syntax. Update the state to accurately reflect the
- ;; beginning of the line. We punt if we cross any open or
- ;; closed parens because its just too hard to modify the
- ;; known state. This limitation will be fixed in v5.
- (save-excursion
- (let ((bol (c-point 'bol)))
- (if (zerop (car (parse-partial-sexp bol (1- (point)))))
- (setq c-state-cache (c-whack-state bol c-state-cache)
- syntax (c-guess-basic-syntax))
- ;; gotta punt. this requires some horrible kludgery
- (beginning-of-line)
- (makunbound 'c-state-cache)
- (setq c-state-cache (c-parse-state)
- syntax nil))))
- )
- ;; now adjust the line's indentation. don't update the state
- ;; cache since c-guess-basic-syntax isn't called when the
- ;; syntax is passed to c-indent-line
- (let ((here (point))
- (shift (c-indent-line syntax)))
- (setq c-state-cache (c-adjust-state (c-point 'bol) here
- (- shift) c-state-cache)))
- ;; Do all appropriate clean ups
- (let ((here (point))
- (pos (- (point-max) (point)))
- mbeg mend)
- ;; clean up empty defun braces
- (if (and c-auto-newline
- (memq 'empty-defun-braces c-cleanup-list)
- (eq last-command-char ?\})
- (c-intersect-lists '(defun-close class-close inline-close)
- syntax)
- (progn
- (forward-char -1)
- (skip-chars-backward " \t\n")
- (eq (char-before) ?\{))
- ;; 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 ?\{)
- (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 {")))
- ;; clean up brace-elseif-brace
- (if (and c-auto-newline
- (memq 'brace-elseif-brace c-cleanup-list)
- (eq last-command-char ?\{)
- (re-search-backward "}[ \t\n]*else[ \t\n]+if[ \t\n]*" nil t)
- (save-excursion
- (goto-char (match-end 0))
- (c-safe (forward-sexp 1))
- (skip-chars-forward " \t\n")
- (setq mbeg (match-beginning 0)
- mend (match-end 0))
- (= here (1+ (point))))
- (not (c-in-literal)))
- (progn
- (delete-region mbeg mend)
- (insert "} else if ")))
- (goto-char (- (point-max) pos))
- )
- ;; does a newline go after the brace?
- (if (memq 'after newlines)
- (progn
- (newline)
- ;; update on c-state-cache
- (let* ((bufpos (- (point) 2))
- (which (if (eq (char-after bufpos) ?{) 'open 'close))
- (c-state-cache (c-hack-state bufpos which c-state-cache)))
- (c-indent-line))))
- ;; blink the paren
- (and (eq last-command-char ?\})
- old-blink-paren
- (save-excursion
- (c-backward-syntactic-ws safepos)
- (funcall old-blink-paren)))
- ))))
-
+
+ ;; Indent the line after the cleanups since it might
+ ;; very well indent differently due to them, e.g. if
+ ;; c-indent-one-line-block is used together with the
+ ;; one-liner-defun cleanup.
+ (when c-syntactic-indentation
+ (c-indent-line)))
+
+ ;; does a newline go after the brace?
+ (if (memq 'after newlines)
+ (c-newline-and-indent))
+ ))))
+
+ ;; blink the paren
+ (and (eq last-command-char ?\})
+ (not executing-kbd-macro)
+ old-blink-paren
+ (save-excursion
+ (c-save-buffer-state nil
+ (c-backward-syntactic-ws safepos))
+ (funcall old-blink-paren)))))
+
(defun c-electric-slash (arg)
"Insert a slash character.
+If the slash is inserted immediately after the comment prefix in a c-style
+comment, the comment might get closed by removing whitespace and possibly
+inserting a \"*\". See the variable `c-cleanup-list'.
+
Indent the line as a comment, if:
- 1. The slash is second of a `//' line oriented comment introducing
+ 1. The slash is second of a \"//\" line oriented comment introducing
token and we are on a comment-only-line, or
- 2. The slash is part of a `*/' token that closes a block oriented
+ 2. The slash is part of a \"*/\" token that closes a block oriented
comment.
-If numeric ARG is supplied or point is inside a literal, indentation
+If a numeric ARG is supplied, point is inside a literal, or
+`c-syntactic-indentation' is nil or `c-electric-flag' is nil, indentation
is inhibited."
- (interactive "P")
- (let* ((ch (char-before))
- (indentp (and (not arg)
+ (interactive "*P")
+ (let ((literal (c-save-buffer-state () (c-in-literal)))
+ indentp
+ ;; shut this up
+ (c-echo-syntactic-information-p nil))
+
+ ;; comment-close-slash cleanup? This DOESN'T need `c-electric-flag' or
+ ;; `c-syntactic-indentation' set.
+ (when (and (not arg)
+ (eq literal 'c)
+ (memq 'comment-close-slash c-cleanup-list)
+ (eq last-command-char ?/)
+ (looking-at (concat "[ \t]*\\("
+ (regexp-quote comment-end) "\\)?$"))
+ ; (eq c-block-comment-ender "*/") ; C-style comments ALWAYS end in */
+ (save-excursion
+ (save-restriction
+ (narrow-to-region (point-min) (point))
+ (back-to-indentation)
+ (looking-at (concat c-current-comment-prefix "[ \t]*$")))))
+ (delete-region (progn (forward-line 0) (point))
+ (progn (end-of-line) (point)))
+ (insert-char ?* 1)) ; the / comes later. ; Do I need a t (retain sticky properties) here?
+
+ (setq indentp (and (not arg)
+ c-syntactic-indentation
+ c-electric-flag
(eq last-command-char ?/)
- (or (and (eq ch ?/)
- (not (c-in-literal)))
- (and (eq ch ?*)
- (c-in-literal)))
- ))
- ;; shut this up
- (c-echo-syntactic-information-p nil))
+ (eq (char-before) (if literal ?* ?/))))
(self-insert-command (prefix-numeric-value arg))
(if indentp
- (c-indent-line))))
+ (indent-according-to-mode))))
(defun c-electric-star (arg)
"Insert a star character.
-If the star is the second character of a C style comment introducing
-construct, and we are on a comment-only-line, indent line as comment.
-If numeric ARG is supplied or point is inside a literal, indentation
-is inhibited."
- (interactive "P")
+If `c-electric-flag' and `c-syntactic-indentation' are both non-nil, and
+the star is the second character of a C style comment starter on a
+comment-only-line, indent the line as a comment. If a numeric ARG is
+supplied, point is inside a literal, or `c-syntactic-indentation' is nil,
+this indentation is inhibited."
+
+ (interactive "*P")
(self-insert-command (prefix-numeric-value arg))
- ;; if we are in a literal, or if arg is given do not re-indent the
+ ;; if we are in a literal, or if arg is given do not reindent the
;; current line, unless this star introduces a comment-only line.
- (if (and (not arg)
- (memq (c-in-literal) '(c))
- (eq (char-before) ?*)
- (save-excursion
- (forward-char -1)
- (skip-chars-backward "*")
- (if (eq (char-before) ?/)
- (forward-char -1))
- (skip-chars-backward " \t")
- (bolp)))
- ;; shut this up
- (let (c-echo-syntactic-information-p)
- (c-indent-line))
+ (if (c-save-buffer-state ()
+ (and c-syntactic-indentation
+ c-electric-flag
+ (not arg)
+ (eq (c-in-literal) 'c)
+ (eq (char-before) ?*)
+ (save-excursion
+ (forward-char -1)
+ (skip-chars-backward "*")
+ (if (eq (char-before) ?/)
+ (forward-char -1))
+ (skip-chars-backward " \t")
+ (bolp))))
+ (let (c-echo-syntactic-information-p) ; shut this up
+ (indent-according-to-mode))
))
(defun c-electric-semi&comma (arg)
"Insert a comma or semicolon.
-When the auto-newline feature is turned on, as evidenced by the \"/a\"
-or \"/ah\" string on the mode line, a newline might be inserted. See
-the variable `c-hanging-semi&comma-criteria' for how newline insertion
-is determined.
-
-When semicolon is inserted, the line is re-indented unless a numeric
-arg is supplied, point is inside a literal, or there are
-non-whitespace characters on the line following the semicolon."
- (interactive "P")
- (let* ((lim (c-most-enclosing-brace (c-parse-state)))
- (literal (c-in-literal lim))
+
+If `c-electric-flag' is non-nil, point isn't inside a literal and a
+numeric ARG hasn't been supplied, the command performs several electric
+actions:
+
+\(a) When the auto-newline feature is turned on (indicated by \"/la\" on
+the mode line) a newline might be inserted. See the variable
+`c-hanging-semi&comma-criteria' for how newline insertion is determined.
+
+\(b) Any auto-newlines are indented. The original line is also
+reindented unless `c-syntactic-indentation' is nil.
+
+\(c) If auto-newline is turned on, a comma following a brace list or a
+semicolon following a defun might be cleaned up, depending on the
+settings of `c-cleanup-list'."
+ (interactive "*P")
+ (let* (lim literal c-syntactic-context
(here (point))
;; shut this up
(c-echo-syntactic-information-p nil))
- (if (or literal
- arg
- (not (looking-at "[ \t]*$")))
- (self-insert-command (prefix-numeric-value arg))
- ;; do some special stuff with the character
- (self-insert-command (prefix-numeric-value arg))
- ;; do all cleanups, reindentations, and newline insertions, but
- ;; only if c-auto-newline is turned on
- (if (not c-auto-newline) nil
- ;; clean ups
- (let ((pos (- (point-max) (point))))
- (if (and (or (and
- (eq last-command-char ?,)
- (memq 'list-close-comma c-cleanup-list))
- (and
- (eq last-command-char ?\;)
- (memq 'defun-close-semi c-cleanup-list)))
- (progn
- (forward-char -1)
- (skip-chars-backward " \t\n")
- (eq (char-before) ?}))
- ;; make sure matching open brace isn't in a comment
- (not (c-in-literal lim)))
- (delete-region (point) here))
- (goto-char (- (point-max) pos)))
- ;; re-indent line
- (c-indent-line)
- ;; check to see if a newline should be added
- (let ((criteria c-hanging-semi&comma-criteria)
- answer add-newline-p)
- (while criteria
- (setq answer (funcall (car criteria)))
- ;; only nil value means continue checking
- (if (not answer)
- (setq criteria (cdr criteria))
- (setq criteria nil)
- ;; only 'stop specifically says do not add a newline
- (setq add-newline-p (not (eq answer 'stop)))
- ))
- (if add-newline-p
- (progn (newline)
- (c-indent-line)))
- )))))
+
+ (c-save-buffer-state ()
+ (setq lim (c-most-enclosing-brace (c-parse-state))
+ literal (c-in-literal lim)))
+
+ (self-insert-command (prefix-numeric-value arg))
+
+ (if (and c-electric-flag (not literal) (not arg))
+ ;; do all cleanups and newline insertions if c-auto-newline is on.
+ (if (or (not c-auto-newline)
+ (not (looking-at "[ \t]*\\\\?$")))
+ (if c-syntactic-indentation
+ (c-indent-line))
+ ;; clean ups: list-close-comma or defun-close-semi
+ (let ((pos (- (point-max) (point))))
+ (if (c-save-buffer-state ()
+ (and (or (and
+ (eq last-command-char ?,)
+ (memq 'list-close-comma c-cleanup-list))
+ (and
+ (eq last-command-char ?\;)
+ (memq 'defun-close-semi c-cleanup-list)))
+ (progn
+ (forward-char -1)
+ (c-skip-ws-backward)
+ (eq (char-before) ?}))
+ ;; make sure matching open brace isn't in a comment
+ (not (c-in-literal lim))))
+ (delete-region (point) here))
+ (goto-char (- (point-max) pos)))
+ ;; reindent line
+ (when c-syntactic-indentation
+ (setq c-syntactic-context (c-guess-basic-syntax))
+ (c-indent-line c-syntactic-context))
+ ;; check to see if a newline should be added
+ (let ((criteria c-hanging-semi&comma-criteria)
+ answer add-newline-p)
+ (while criteria
+ (setq answer (funcall (car criteria)))
+ ;; only nil value means continue checking
+ (if (not answer)
+ (setq criteria (cdr criteria))
+ (setq criteria nil)
+ ;; only 'stop specifically says do not add a newline
+ (setq add-newline-p (not (eq answer 'stop)))
+ ))
+ (if add-newline-p
+ (c-newline-and-indent))
+ )))))
(defun c-electric-colon (arg)
"Insert a colon.
-If the auto-newline feature is turned on, as evidenced by the \"/a\"
-or \"/ah\" string on the mode line, newlines are inserted before and
-after colons based on the value of `c-hanging-colons-alist'.
+If `c-electric-flag' is non-nil, the colon is not inside a literal and a
+numeric ARG hasn't been supplied, the command performs several electric
+actions:
-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.
+\(a) If the auto-newline feature is turned on (indicated by \"/la\" on
+the mode line) newlines are inserted before and after the colon based on
+the settings in `c-hanging-colons-alist'.
-This function cleans up double colon scope operators based on the
-value of `c-cleanup-list'."
- (interactive "P")
+\(b) Any auto-newlines are indented. The original line is also
+reindented unless `c-syntactic-indentation' is nil.
+
+\(c) If auto-newline is turned on, whitespace between two colons will be
+\"cleaned up\" leaving a scope operator, if this action is set in
+`c-cleanup-list'."
+
+ (interactive "*P")
(let* ((bod (c-point 'bod))
- (literal (c-in-literal bod))
- syntax newlines
+ (literal (c-save-buffer-state () (c-in-literal bod)))
+ newlines is-scope-op
;; shut this up
(c-echo-syntactic-information-p nil))
- (if (or literal
- arg
- (not (looking-at "[ \t]*$")))
- (self-insert-command (prefix-numeric-value arg))
- ;; insert the colon, then do any specified cleanups
- (self-insert-command (prefix-numeric-value arg))
- (let ((pos (- (point-max) (point)))
- (here (point)))
- (if (and c-auto-newline
- (memq 'scope-operator c-cleanup-list)
- (eq (char-before) ?:)
- (progn
- (forward-char -1)
- (skip-chars-backward " \t\n")
- (eq (char-before) ?:))
- (not (c-in-literal))
- (not (eq (char-after (- (point) 2)) ?:)))
- (delete-region (point) (1- here)))
- (goto-char (- (point-max) pos)))
- ;; lets do some special stuff with the colon character
- (setq syntax (c-guess-basic-syntax)
- ;; some language elements can only be determined by
- ;; checking the following line. Lets first look for ones
- ;; that can be found when looking on the line with the
- ;; colon
- newlines
- (and c-auto-newline
- (or (c-lookup-lists '(case-label label access-label)
- syntax c-hanging-colons-alist)
- (c-lookup-lists '(member-init-intro inher-intro)
- (prog2
- (insert "\n")
- (c-guess-basic-syntax)
- (delete-char -1))
- c-hanging-colons-alist))))
- ;; indent the current line
- (c-indent-line syntax)
- ;; does a newline go before the colon? Watch out for already
- ;; non-hung colons. However, we don't unhang them because that
- ;; would be a cleanup (and anti-social).
- (if (and (memq 'before newlines)
- (save-excursion
- (skip-chars-backward ": \t")
- (not (bolp))))
- (let ((pos (- (point-max) (point))))
- (forward-char -1)
- (newline)
- (c-indent-line)
- (goto-char (- (point-max) pos))))
- ;; does a newline go after the colon?
- (if (memq 'after (cdr-safe newlines))
- (progn
- (newline)
- (c-indent-line)))
- )))
+ (self-insert-command (prefix-numeric-value arg))
+ ;; Any electric action?
+ (if (and c-electric-flag (not literal) (not arg))
+ ;; Unless we're at EOL, only re-indentation happens.
+ (if (not (looking-at "[ \t]*\\\\?$"))
+ (if c-syntactic-indentation
+ (indent-according-to-mode))
+
+ ;; scope-operator clean-up?
+ (let ((pos (- (point-max) (point)))
+ (here (point)))
+ (if (c-save-buffer-state () ; Why do we need this? [ACM, 2003-03-12]
+ (and c-auto-newline
+ (memq 'scope-operator c-cleanup-list)
+ (eq (char-before) ?:)
+ (progn
+ (forward-char -1)
+ (c-skip-ws-backward)
+ (eq (char-before) ?:))
+ (not (c-in-literal))
+ (not (eq (char-after (- (point) 2)) ?:))))
+ (progn
+ (delete-region (point) (1- here))
+ (setq is-scope-op t)))
+ (goto-char (- (point-max) pos)))
+
+ ;; indent the current line if it's done syntactically.
+ (if c-syntactic-indentation
+ ;; Cannot use the same syntax analysis as we find below,
+ ;; since that's made with c-syntactic-indentation-in-macros
+ ;; always set to t.
+ (indent-according-to-mode))
+
+ ;; Calculate where, if anywhere, we want newlines.
+ (c-save-buffer-state
+ ((c-syntactic-indentation-in-macros t)
+ (c-auto-newline-analysis t)
+ ;; Turn on syntactic macro analysis to help with auto newlines
+ ;; only.
+ (syntax (c-guess-basic-syntax))
+ (elem syntax))
+ ;; Translate substatement-label to label for this operation.
+ (while elem
+ (if (eq (car (car elem)) 'substatement-label)
+ (setcar (car elem) 'label))
+ (setq elem (cdr elem)))
+ ;; some language elements can only be determined by checking
+ ;; the following line. Lets first look for ones that can be
+ ;; found when looking on the line with the colon
+ (setq newlines
+ (and c-auto-newline
+ (or (c-lookup-lists '(case-label label access-label)
+ syntax c-hanging-colons-alist)
+ (c-lookup-lists '(member-init-intro inher-intro)
+ (progn
+ (insert ?\n)
+ (unwind-protect
+ (c-guess-basic-syntax)
+ (delete-char -1)))
+ c-hanging-colons-alist)))))
+ ;; does a newline go before the colon? Watch out for already
+ ;; non-hung colons. However, we don't unhang them because that
+ ;; would be a cleanup (and anti-social).
+ (if (and (memq 'before newlines)
+ (not is-scope-op)
+ (save-excursion
+ (skip-chars-backward ": \t")
+ (not (bolp))))
+ (let ((pos (- (point-max) (point))))
+ (forward-char -1)
+ (c-newline-and-indent)
+ (goto-char (- (point-max) pos))))
+ ;; does a newline go after the colon?
+ (if (and (memq 'after (cdr-safe newlines))
+ (not is-scope-op))
+ (c-newline-and-indent))
+ ))))
(defun c-electric-lt-gt (arg)
- "Insert a less-than, or greater-than character.
-When the auto-newline feature is turned on, as evidenced by the \"/a\"
-or \"/ah\" string on the mode line, the line will be re-indented if
-the character inserted is the second of a C++ style stream operator
-and the buffer is in C++ mode.
-
-The line will also not be re-indented if a numeric argument is
-supplied, or point is inside a literal."
- (interactive "P")
- (let ((indentp (and (not arg)
- (eq (char-before) last-command-char)
- (not (c-in-literal))))
+ "Insert a \"<\" or \">\" character.
+If the current language uses angle bracket parens (e.g. template
+arguments in C++), try to find out if the inserted character is a
+paren and give it paren syntax if appropriate.
+
+If `c-electric-flag' and `c-syntactic-indentation' are both non-nil, the
+line will be reindented if the inserted character is a paren or if it
+finishes a C++ style stream operator in C++ mode. Exceptions are when a
+numeric argument is supplied, or the point is inside a literal."
+
+ (interactive "*P")
+ (let ((c-echo-syntactic-information-p nil)
+ final-pos close-paren-inserted)
+
+ (self-insert-command (prefix-numeric-value arg))
+ (setq final-pos (point))
+
+ (c-save-buffer-state (c-parse-and-markup-<>-arglists
+ c-restricted-<>-arglists
+ <-pos)
+
+ (when c-recognize-<>-arglists
+ (if (eq last-command-char ?<)
+ (when (and (progn
+ (backward-char)
+ (= (point)
+ (progn
+ (c-beginning-of-current-token)
+ (point))))
+ (progn
+ (c-backward-token-2)
+ (looking-at c-opt-<>-sexp-key)))
+ (c-mark-<-as-paren (1- final-pos)))
+
+ ;; It's a ">". Check if there's an earlier "<" which either has
+ ;; open paren syntax already or that can be recognized as an arglist
+ ;; together with this ">". Note that this won't work in cases like
+ ;; "template <x, a < b, y>" but they ought to be rare.
+
+ (save-restriction
+ ;; Narrow to avoid that `c-forward-<>-arglist' below searches past
+ ;; our position.
+ (narrow-to-region (point-min) final-pos)
+
+ (while (and
+ (progn
+ (goto-char final-pos)
+ (c-syntactic-skip-backward "^<;}" nil t)
+ (eq (char-before) ?<))
+ (progn
+ (backward-char)
+ ;; If the "<" already got open paren syntax we know we
+ ;; have the matching closer. Handle it and exit the
+ ;; loop.
+ (if (looking-at "\\s\(")
+ (progn
+ (c-mark->-as-paren (1- final-pos))
+ (setq close-paren-inserted t)
+ nil)
+ t))
+
+ (progn
+ (setq <-pos (point))
+ (c-backward-syntactic-ws)
+ (c-simple-skip-symbol-backward))
+ (or (looking-at c-opt-<>-sexp-key)
+ (not (looking-at c-keywords-regexp)))
+
+ (let ((c-parse-and-markup-<>-arglists t)
+ c-restricted-<>-arglists
+ (containing-sexp
+ (c-most-enclosing-brace (c-parse-state))))
+ (when (and containing-sexp
+ (progn (goto-char containing-sexp)
+ (eq (char-after) ?\())
+ (not (eq (get-text-property (point) 'c-type)
+ 'c-decl-arg-start)))
+ (setq c-restricted-<>-arglists t))
+ (goto-char <-pos)
+ (c-forward-<>-arglist nil))
+
+ ;; Loop here if the "<" we found above belongs to a nested
+ ;; angle bracket sexp. When we start over we'll find the
+ ;; previous or surrounding sexp.
+ (if (< (point) final-pos)
+ t
+ (setq close-paren-inserted t)
+ nil)))))))
+ (goto-char final-pos)
+
+ ;; Indent the line if appropriate.
+ (when (and c-electric-flag c-syntactic-indentation)
+ (backward-char)
+ (when (prog1 (or (looking-at "\\s\(\\|\\s\)")
+ (and (c-major-mode-is 'c++-mode)
+ (progn
+ (c-beginning-of-current-token)
+ (looking-at "<<\\|>>"))
+ (= (match-end 0) final-pos)))
+ (goto-char final-pos))
+ (indent-according-to-mode)))
+
+ (when (and close-paren-inserted
+ (not executing-kbd-macro)
+ blink-paren-function)
+ ;; Note: Most paren blink functions, such as the standard
+ ;; `blink-matching-open', currently doesn't handle paren chars
+ ;; marked with text properties very well. Maybe we should avoid
+ ;; this call for the time being?
+ (funcall blink-paren-function))))
+
+(defun c-electric-paren (arg)
+ "Insert a parenthesis.
+
+If `c-syntactic-indentation' and `c-electric-flag' are both non-nil, the
+line is reindented unless a numeric ARG is supplied, or the parenthesis
+is inserted inside a literal.
+
+Whitespace between a function name and the parenthesis may get added or
+removed; see the variable `c-cleanup-list'.
+
+Also, if `c-electric-flag' and `c-auto-newline' are both non-nil, some
+newline cleanups are done if appropriate; see the variable `c-cleanup-list'."
+ (interactive "*P")
+ (let ((literal (c-save-buffer-state () (c-in-literal)))
;; shut this up
(c-echo-syntactic-information-p nil))
(self-insert-command (prefix-numeric-value arg))
- (if indentp
- (c-indent-line))))
+ (if (and (not arg) (not literal))
+ (let* ( ;; We want to inhibit blinking the paren since this will
+ ;; be most disruptive. We'll blink it ourselves
+ ;; afterwards.
+ (old-blink-paren blink-paren-function)
+ blink-paren-function)
+ (if (and c-syntactic-indentation c-electric-flag)
+ (indent-according-to-mode))
+
+ ;; If we're at EOL, check for new-line clean-ups.
+ (when (and c-electric-flag c-auto-newline
+ (looking-at "[ \t]*\\\\?$"))
+
+ ;; clean up brace-elseif-brace
+ (when
+ (and (memq 'brace-elseif-brace c-cleanup-list)
+ (eq last-command-char ?\()
+ (re-search-backward
+ (concat "}"
+ "\\([ \t\n]\\|\\\\\n\\)*"
+ "else"
+ "\\([ \t\n]\\|\\\\\n\\)+"
+ "if"
+ "\\([ \t\n]\\|\\\\\n\\)*"
+ "("
+ "\\=")
+ nil t)
+ (not (c-save-buffer-state () (c-in-literal))))
+ (delete-region (match-beginning 0) (match-end 0))
+ (insert-and-inherit "} else if ("))
+
+ ;; clean up brace-catch-brace
+ (when
+ (and (memq 'brace-catch-brace c-cleanup-list)
+ (eq last-command-char ?\()
+ (re-search-backward
+ (concat "}"
+ "\\([ \t\n]\\|\\\\\n\\)*"
+ "catch"
+ "\\([ \t\n]\\|\\\\\n\\)*"
+ "("
+ "\\=")
+ nil t)
+ (not (c-save-buffer-state () (c-in-literal))))
+ (delete-region (match-beginning 0) (match-end 0))
+ (insert-and-inherit "} catch (")))
+
+ ;; Check for clean-ups at function calls. These two DON'T need
+ ;; `c-electric-flag' or `c-syntactic-indentation' set.
+ ;; Point is currently just after the inserted paren.
+ (let (beg (end (1- (point))))
+ (cond
+
+ ;; space-before-funcall clean-up?
+ ((and (memq 'space-before-funcall c-cleanup-list)
+ (eq last-command-char ?\()
+ (save-excursion
+ (backward-char)
+ (skip-chars-backward " \t")
+ (setq beg (point))
+ (and (c-save-buffer-state () (c-on-identifier))
+ ;; Don't add a space into #define FOO()....
+ (not (and (c-beginning-of-macro)
+ (c-forward-over-cpp-define-id)
+ (eq (point) beg))))))
+ (save-excursion
+ (delete-region beg end)
+ (goto-char beg)
+ (insert ?\ )))
+
+ ;; compact-empty-funcall clean-up?
+ ((c-save-buffer-state ()
+ (and (memq 'compact-empty-funcall c-cleanup-list)
+ (eq last-command-char ?\))
+ (save-excursion
+ (c-safe (backward-char 2))
+ (when (looking-at "()")
+ (setq end (point))
+ (skip-chars-backward " \t")
+ (setq beg (point))
+ (c-on-identifier)))))
+ (delete-region beg end))))
+ (and (eq last-input-event ?\))
+ (not executing-kbd-macro)
+ old-blink-paren
+ (funcall old-blink-paren))))))
+
+(defun c-electric-continued-statement ()
+ "Reindent the current line if appropriate.
+
+This function is used to reindent the line after a keyword which
+continues an earlier statement is typed, e.g. an \"else\" or the
+\"while\" in a do-while block.
+
+The line is reindented if there is nothing but whitespace before the
+keyword on the line, the keyword is not inserted inside a literal, and
+`c-electric-flag' and `c-syntactic-indentation' are both non-nil."
+ (let (;; shut this up
+ (c-echo-syntactic-information-p nil))
+ (when (c-save-buffer-state ()
+ (and c-electric-flag
+ c-syntactic-indentation
+ (not (eq last-command-char ?_))
+ (= (save-excursion
+ (skip-syntax-backward "w")
+ (point))
+ (c-point 'boi))
+ (not (c-in-literal (c-point 'bod)))))
+ ;; Have to temporarily insert a space so that
+ ;; c-guess-basic-syntax recognizes the keyword. Follow the
+ ;; space with a nonspace to avoid messing up any whitespace
+ ;; sensitive meddling that might be done, e.g. by
+ ;; `c-backslash-region'.
+ (insert-and-inherit " x")
+ (unwind-protect
+ (indent-according-to-mode)
+ (delete-char -2)))))
+
+\f
+;; "nomenclature" functions + c-scope-operator.
+(defun c-forward-into-nomenclature (&optional arg)
+ "Compatibility alias for `c-forward-subword'."
+ (interactive "p")
+ (require 'cc-subword)
+ (c-forward-subword arg))
+(make-obsolete 'c-forward-into-nomenclature 'c-forward-subword)
+
+(defun c-backward-into-nomenclature (&optional arg)
+ "Compatibility alias for `c-backward-subword'."
+ (interactive "p")
+ (require 'cc-subword)
+ (c-backward-subword arg))
+(make-obsolete 'c-backward-into-nomenclature 'c-backward-subword)
+
+(defun c-scope-operator ()
+ "Insert a double colon scope operator at point.
+No indentation or other \"electric\" behavior is performed."
+ (interactive "*")
+ (insert-and-inherit "::"))
+
+\f
+;; Movement (etc.) by defuns.
+(defun c-in-function-trailer-p (&optional lim)
+ ;; Return non-nil if point is between the closing brace and the semicolon of
+ ;; a brace construct which needs a semicolon, e.g. within the "variables"
+ ;; portion of a declaration like "struct foo {...} bar ;".
+ ;;
+ ;; Return the position of the main declaration. Otherwise, return nil.
+ ;; Point is assumed to be at the top level and outside of any macro or
+ ;; literal.
+ ;;
+ ;; If LIM is non-nil, it is the bound on a the backward search for the
+ ;; beginning of the declaration.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (and c-opt-block-decls-with-vars-key
+ (save-excursion
+ (c-syntactic-skip-backward "^;}" lim)
+ (let ((eo-block (point))
+ bod)
+ (and (eq (char-before) ?\})
+ (eq (car (c-beginning-of-decl-1 lim)) 'previous)
+ (setq bod (point))
+ ;; Look for struct or union or ... If we find one, it might
+ ;; be the return type of a function, or the like. Exclude
+ ;; this case.
+ (c-syntactic-re-search-forward
+ (concat "[;=\(\[{]\\|\\("
+ c-opt-block-decls-with-vars-key
+ "\\)")
+ eo-block t t t)
+ (match-beginning 1) ; Is there a "struct" etc., somewhere?
+ (not (eq (char-before) ?_))
+ (c-syntactic-re-search-forward "[;=\(\[{]" eo-block t t t)
+ (eq (char-before) ?\{)
+ bod)))))
+
+(defun c-where-wrt-brace-construct ()
+ ;; Determine where we are with respect to functions (or other brace
+ ;; constructs, included in the term "function" in the rest of this comment).
+ ;; Point is assumed to be outside any macro or literal.
+ ;; This is used by c-\(begining\|end\)-of-defun.
+ ;;
+ ;; Return one of these symbols:
+ ;; at-header : we're at the start of a function's header.
+ ;; in-header : we're inside a function's header, this extending right
+ ;; up to the brace. This bit includes any k&r declarations.
+ ;; in-block : we're inside a function's brace block.
+ ;; in-trailer : we're in the area between the "}" and ";" of something
+ ;; like "struct foo {...} bar, baz;".
+ ;; at-function-end : we're just after the closing brace (or semicolon) that
+ ;; terminates the function.
+ ;; outwith-function: we're not at or in any function. Being inside a
+ ;; non-brace construct also counts as 'outwith-function'.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-excursion
+ (let* (kluge-start
+ decl-result brace-decl-p
+ (start (point))
+ (paren-state (c-parse-state))
+ (least-enclosing (c-least-enclosing-brace paren-state)))
+
+ (cond
+ ((and least-enclosing
+ (eq (char-after least-enclosing) ?\{))
+ 'in-block)
+ ((c-in-function-trailer-p)
+ 'in-trailer)
+ ((and (not least-enclosing)
+ (consp paren-state)
+ (consp (car paren-state))
+ (eq start (cdar paren-state)))
+ 'at-function-end)
+ (t
+ ;; Find the start of the current declaration. NOTE: If we're in the
+ ;; variables after a "struct/eval" type block, we don't get to the
+ ;; real declaration here - we detect and correct for this later.
+
+ ;;If we're in the parameters' parens, move back out of them.
+ (if least-enclosing (goto-char least-enclosing))
+ ;; Kluge so that c-beginning-of-decl-1 won't go back if we're already
+ ;; at a declaration.
+ (if (or (and (eolp) (not (eobp))) ; EOL is matched by "\\s>"
+ (not (looking-at
+"\\([;#]\\|\\'\\|\\s(\\|\\s)\\|\\s\"\\|\\s\\\\|\\s$\\|\\s<\\|\\s>\\|\\s!\\)")))
+ (forward-char))
+ (setq kluge-start (point))
+ (setq decl-result
+ (car (c-beginning-of-decl-1
+ ;; NOTE: If we're in a K&R region, this might be the start
+ ;; of a parameter declaration, not the actual function.
+ (and least-enclosing ; LIMIT for c-b-of-decl-1
+ (c-safe-position least-enclosing paren-state)))))
+
+ ;; Has the declaration we've gone back to got braces?
+ (setq brace-decl-p
+ (save-excursion
+ (and (c-syntactic-re-search-forward "[;{]" nil t t)
+ (or (eq (char-before) ?\{)
+ (and c-recognize-knr-p
+ ;; Might have stopped on the
+ ;; ';' in a K&R argdecl. In
+ ;; that case the declaration
+ ;; should contain a block.
+ (c-in-knr-argdecl))))))
+
+ (cond
+ ((= (point) kluge-start) ; might be BOB or unbalanced parens.
+ 'outwith-function)
+ ((eq decl-result 'same)
+ (if brace-decl-p
+ (if (eq (point) start)
+ 'at-header
+ 'in-header)
+ 'outwith-function))
+ ((eq decl-result 'previous)
+ (if (and (not brace-decl-p)
+ (c-in-function-trailer-p))
+ 'at-function-end
+ 'outwith-function))
+ (t (error
+ "c-where-wrt-brace-construct: c-beginning-of-decl-1 returned %s"
+ decl-result))))))))
+
+(defun c-backward-to-nth-BOF-{ (n where)
+ ;; Skip to the opening brace of the Nth function before point. If
+ ;; point is inside a function, this counts as the first. Point must be
+ ;; outside any comment/string or macro.
+ ;;
+ ;; N must be strictly positive.
+ ;; WHERE describes the position of point, one of the symbols `at-header',
+ ;; `in-header', `in-block', `in-trailer', `at-function-end',
+ ;; `outwith-function' as returned by c-where-wrt-brace-construct.
+ ;;
+ ;; If we run out of functions, leave point at BOB. Return zero on success,
+ ;; otherwise the number of {s still to go.
+ ;;
+ ;; This function may do hidden buffer changes
+ (cond
+ ;; What we do to go back the first defun depends on where we start.
+ ((bobp))
+ ((eq where 'in-block)
+ (goto-char (c-least-enclosing-brace (c-parse-state)))
+ (setq n (1- n)))
+ ((eq where 'in-header)
+ (c-syntactic-re-search-forward "{")
+ (backward-char)
+ (setq n (1- n)))
+ ((memq where '(at-header outwith-function at-function-end in-trailer))
+ (c-syntactic-skip-backward "^}")
+ (when (eq (char-before) ?\})
+ (backward-sexp)
+ (setq n (1- n))))
+ (t (error "Unknown `where' %s in c-backward-to-nth-EOF-{" where)))
+
+ ;; Each time round the loop, go back to a "{" at the outermost level.
+ (while (and (> n 0) (not (bobp)))
+ (c-parse-state) ; This call speeds up the following one
+ ; by a factor of ~6. Hmmm. 2006/4/5.
+ (c-syntactic-skip-backward "^}")
+ (when (eq (char-before) ?\})
+ (backward-sexp)
+ (setq n (1- n))))
+ n)
+
+(defun c-beginning-of-defun (&optional arg)
+ "Move backward to the beginning of a defun.
+Every top level declaration that contains a brace paren block is
+considered to be a defun.
+
+With a positive argument, move backward that many defuns. A negative
+argument -N means move forward to the Nth following beginning. Return
+t unless search stops due to beginning or end of buffer.
+
+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")
+ (or arg (setq arg 1))
+
+ (c-save-buffer-state
+ (beginning-of-defun-function end-of-defun-function
+ (start (point))
+ where paren-state pos)
+
+ ;; Move back out of any macro/comment/string we happen to be in.
+ (c-beginning-of-macro)
+ (setq pos (c-literal-limits))
+ (if pos (goto-char (car pos)))
+
+ (setq where (c-where-wrt-brace-construct))
+
+ (if (< arg 0)
+ ;; Move forward to the closing brace of a function.
+ (progn
+ (if (memq where '(at-function-end outwith-function))
+ (setq arg (1+ arg)))
+ (if (< arg 0)
+ (setq arg (c-forward-to-nth-EOF-} (- arg) where)))
+ ;; Move forward to the next opening brace....
+ (when (and (= arg 0)
+ (c-syntactic-re-search-forward "{" nil 'eob))
+ (backward-char)
+ ;; ... and backward to the function header.
+ (c-beginning-of-decl-1)
+ t))
+
+ ;; Move backward to the opening brace of a function.
+ (when (and (> arg 0)
+ (eq (setq arg (c-backward-to-nth-BOF-{ arg where)) 0))
+
+ ;; Go backward to this function's header.
+ (c-beginning-of-decl-1)
+
+ (setq pos (point))
+ ;; We're now there, modulo comments and whitespace.
+ ;; Try to be line oriented; position point at the closest
+ ;; preceding boi that isn't inside a comment, but if we hit
+ ;; the previous declaration then we use the current point
+ ;; instead.
+ (while (and (/= (point) (c-point 'boi))
+ (c-backward-single-comment)))
+ (if (/= (point) (c-point 'boi))
+ (goto-char pos)))
+
+ (c-keep-region-active)
+ (= arg 0))))
+
+(defun c-forward-to-nth-EOF-} (n where)
+ ;; Skip to the closing brace of the Nth function after point. If
+ ;; point is inside a function, this counts as the first. Point must be
+ ;; outside any comment/string or macro.
+ ;;
+ ;; N must be strictly positive.
+ ;; WHERE describes the position of point, one of the symbols `at-header',
+ ;; `in-header', `in-block', `in-trailer', `at-function-end',
+ ;; `outwith-function' as returned by c-where-wrt-brace-construct.
+ ;;
+ ;; If we run out of functions, leave point at EOB. Return zero on success,
+ ;; otherwise the number of }s still to go.
+ ;;
+ ;; This function may do hidden buffer changes.
+
+ (cond
+ ;; What we do to go forward over the first defun depends on where we
+ ;; start. We go to the closing brace of that defun, even when we go
+ ;; backwards to it (in a "struct foo {...} bar ;").
+ ((eobp))
+ ((eq where 'in-block)
+ (goto-char (c-least-enclosing-brace (c-parse-state)))
+ (forward-sexp)
+ (setq n (1- n)))
+ ((eq where 'in-trailer)
+ (c-syntactic-skip-backward "^}")
+ (setq n (1- n)))
+ ((memq where '(at-function-end outwith-function at-header in-header))
+ (when (c-syntactic-re-search-forward "{" nil 'eob)
+ (backward-char)
+ (forward-sexp)
+ (setq n (1- n))))
+ (t (error "c-forward-to-nth-EOF-}: `where' is %s" where)))
+
+ ;; Each time round the loop, go forward to a "}" at the outermost level.
+ (while (and (> n 0) (not (eobp)))
+ ;(c-parse-state) ; This call speeds up the following one by a factor
+ ; of ~6. Hmmm. 2006/4/5.
+ (when (c-syntactic-re-search-forward "{" nil 'eob)
+ (backward-char)
+ (forward-sexp))
+ (setq n (1- n)))
+ n)
+
+(defun c-end-of-defun (&optional arg)
+ "Move forward to the end of a top level declaration.
+With argument, do it that many times. Negative argument -N means move
+back to Nth preceding end. 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'."
+ (interactive "p")
+ (or arg (setq arg 1))
+
+ (c-save-buffer-state
+ (beginning-of-defun-function end-of-defun-function
+ (start (point))
+ where paren-state pos)
+
+ ;; Move back out of any macro/comment/string we happen to be in.
+ (c-beginning-of-macro)
+ (setq pos (c-literal-limits))
+ (if pos (goto-char (car pos)))
+
+ (setq where (c-where-wrt-brace-construct))
+
+ (if (< arg 0)
+ ;; Move backwards to the } of a function
+ (progn
+ (if (memq where '(at-header outwith-function))
+ (setq arg (1+ arg)))
+ (if (< arg 0)
+ (setq arg (c-backward-to-nth-BOF-{ (- arg) where)))
+ (if (= arg 0)
+ (c-syntactic-skip-backward "^}")))
+
+ ;; Move forward to the } of a function
+ (if (> arg 0)
+ (setq arg (c-forward-to-nth-EOF-} arg where))))
+
+ ;; Do we need to move forward from the brace to the semicolon?
+ (when (eq arg 0)
+ (if (c-in-function-trailer-p) ; after "}" of struct/enum, etc.
+ (c-syntactic-re-search-forward ";"))
+
+ (setq pos (point))
+ ;; We're there now, modulo comments and whitespace.
+ ;; Try to be line oriented; position point after the next
+ ;; newline that isn't inside a comment, but if we hit the
+ ;; next declaration then we use the current point instead.
+ (while (and (not (bolp))
+ (not (looking-at "\\s *$"))
+ (c-forward-single-comment)))
+ (cond ((bolp))
+ ((looking-at "\\s *$")
+ (forward-line 1))
+ (t
+ (goto-char pos))))
+
+ (c-keep-region-active)
+ (= arg 0)))
+
+(defun c-declaration-limits (near)
+ ;; Return a cons of the beginning and end positions of the current
+ ;; top level declaration or macro. If point is not inside any then
+ ;; nil is returned, unless NEAR is non-nil in which case the closest
+ ;; following one is chosen instead (if there is any). The end
+ ;; position is at the next line, providing there is one before the
+ ;; declaration.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-excursion
+
+ ;; Note: Some code duplication in `c-beginning-of-defun' and
+ ;; `c-end-of-defun'.
+ (catch 'exit
+ (let ((start (point))
+ (paren-state (c-parse-state))
+ lim pos end-pos)
+ (unless (c-safe
+ (goto-char (c-least-enclosing-brace paren-state))
+ ;; If we moved to the outermost enclosing paren then we
+ ;; can use c-safe-position to set the limit. Can't do
+ ;; that otherwise since the earlier paren pair on
+ ;; paren-state might very well be part of the
+ ;; declaration we should go to.
+ (setq lim (c-safe-position (point) paren-state))
+ t)
+ ;; At top level. Make sure we aren't inside a literal.
+ (setq pos (c-literal-limits
+ (c-safe-position (point) paren-state)))
+ (if pos (goto-char (car pos))))
+
+ (when (c-beginning-of-macro)
+ (throw 'exit
+ (cons (point)
+ (save-excursion
+ (c-end-of-macro)
+ (forward-line 1)
+ (point)))))
+
+ (setq pos (point))
+ (when (or (eq (car (c-beginning-of-decl-1 lim)) 'previous)
+ (= pos (point)))
+ ;; We moved back over the previous defun. Skip to the next
+ ;; one. Not using c-forward-syntactic-ws here since we
+ ;; should not skip a macro. We can also be directly after
+ ;; the block in a `c-opt-block-decls-with-vars-key'
+ ;; declaration, but then we won't move significantly far
+ ;; here.
+ (goto-char pos)
+ (c-forward-comments)
+
+ (when (and near (c-beginning-of-macro))
+ (throw 'exit
+ (cons (point)
+ (save-excursion
+ (c-end-of-macro)
+ (forward-line 1)
+ (point))))))
+
+ (if (eobp) (throw 'exit nil))
+
+ ;; Check if `c-beginning-of-decl-1' put us after the block in a
+ ;; declaration that doesn't end there. We're searching back and
+ ;; forth over the block here, which can be expensive.
+ (setq pos (point))
+ (if (and c-opt-block-decls-with-vars-key
+ (progn
+ (c-backward-syntactic-ws)
+ (eq (char-before) ?}))
+ (eq (car (c-beginning-of-decl-1))
+ 'previous)
+ (save-excursion
+ (c-end-of-decl-1)
+ (and (> (point) pos)
+ (setq end-pos (point)))))
+ nil
+ (goto-char pos))
+
+ (if (and (not near) (> (point) start))
+ nil
+
+ ;; Try to be line oriented; position the limits at the
+ ;; closest preceding boi, and after the next newline, that
+ ;; isn't inside a comment, but if we hit a neighboring
+ ;; declaration then we instead use the exact declaration
+ ;; limit in that direction.
+ (cons (progn
+ (setq pos (point))
+ (while (and (/= (point) (c-point 'boi))
+ (c-backward-single-comment)))
+ (if (/= (point) (c-point 'boi))
+ pos
+ (point)))
+ (progn
+ (if end-pos
+ (goto-char end-pos)
+ (c-end-of-decl-1))
+ (setq pos (point))
+ (while (and (not (bolp))
+ (not (looking-at "\\s *$"))
+ (c-forward-single-comment)))
+ (cond ((bolp)
+ (point))
+ ((looking-at "\\s *$")
+ (forward-line 1)
+ (point))
+ (t
+ pos)))))
+ ))))
+
+(defun c-mark-function ()
+ "Put mark at end of the current top-level declaration or macro, point at beginning.
+If point is not inside any then the closest following one is chosen.
+
+As opposed to \\[c-beginning-of-defun] and \\[c-end-of-defun], this
+function does not require the declaration to contain a brace block."
+ (interactive)
+
+ (let (decl-limits)
+ (c-save-buffer-state nil
+ ;; We try to be line oriented, unless there are several
+ ;; declarations on the same line.
+ (if (looking-at c-syntactic-eol)
+ (c-backward-token-2 1 nil (c-point 'bol)))
+ (setq decl-limits (c-declaration-limits t)))
+
+ (if (not decl-limits)
+ (error "Cannot find any declaration")
+ (goto-char (car decl-limits))
+ (push-mark (cdr decl-limits) nil t))))
+
+\f
+;; Movement by statements.
+(defun c-in-comment-line-prefix-p ()
+ ;; Point is within a comment. Is it also within a comment-prefix?
+ ;; Space at BOL which precedes a comment-prefix counts as part of it.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (let ((here (point)))
+ (save-excursion
+ (beginning-of-line)
+ (skip-chars-forward " \t")
+ (and (looking-at c-current-comment-prefix)
+ (/= (match-beginning 0) (match-end 0))
+ (< here (match-end 0))))))
+
+(defun c-narrow-to-comment-innards (range)
+ ;; Narrow to the "inside" of the comment (block) defined by range, as
+ ;; follows:
+ ;;
+ ;; A c-style block comment has its opening "/*" and its closing "*/" (if
+ ;; present) removed. A c++-style line comment retains its opening "//" but
+ ;; has any final NL removed. If POINT is currently outwith these innards,
+ ;; move it to the appropriate boundary.
+ ;;
+ ;; This narrowing simplifies the sentence movement functions, since it
+ ;; eliminates awkward things at the boundaries of the comment (block).
+ ;;
+ ;; This function might do hidden buffer changes.
+ (let* ((lit-type (c-literal-type range))
+ (beg (if (eq lit-type 'c) (+ (car range) 2) (car range)))
+ (end (if (eq lit-type 'c)
+ (if (and (eq (char-before (cdr range)) ?/)
+ (eq (char-before (1- (cdr range))) ?*))
+ (- (cdr range) 2)
+ (point-max))
+ (if (eq (cdr range) (point-max))
+ (point-max)
+ (- (cdr range) 1)))))
+ (if (> (point) end)
+ (goto-char end)) ; This would be done automatically by ...
+ (if (< (point) beg)
+ (goto-char beg)) ; ... narrow-to-region but is not documented.
+ (narrow-to-region beg end)))
+
+(defun c-beginning-of-sentence-in-comment (range)
+ ;; Move backwards to the "beginning of a sentence" within the comment
+ ;; defined by RANGE, a cons of its starting and ending positions. If we
+ ;; find a BOS, return NIL. Otherwise, move point to just before the start
+ ;; of the comment and return T.
+ ;;
+ ;; The BOS is either text which follows a regexp match of sentence-end,
+ ;; or text which is a beginning of "paragraph".
+ ;; Comment-prefixes are treated like WS when calculating BOSes or BOPs.
+ ;;
+ ;; This code was adapted from GNU Emacs's forward-sentence in paragraphs.el.
+ ;; It is not a general function, but is intended only for calling from
+ ;; c-move-over-sentence. Not all preconditions have been explicitly stated.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-match-data
+ (let ((start-point (point)))
+ (save-restriction
+ (c-narrow-to-comment-innards range) ; This may move point back.
+ (let* ((here (point))
+ last
+ (here-filler ; matches WS and comment-prefices at point.
+ (concat "\\=\\(^[ \t]*\\(" c-current-comment-prefix "\\)"
+ "\\|[ \t\n\r\f]\\)*"))
+ (prefix-at-bol-here ; matches WS and prefix at BOL, just before point
+ (concat "^[ \t]*\\(" c-current-comment-prefix "\\)[ \t\n\r\f]*\\="))
+ ;; First, find the previous paragraph start, if any.
+ (par-beg ; point where non-WS/non-prefix text of paragraph starts.
+ (save-excursion
+ (forward-paragraph -1) ; uses cc-mode values of
+ ; paragraph-\(start\|separate\)
+ (if (> (re-search-forward here-filler nil t) here)
+ (goto-char here))
+ (when (>= (point) here)
+ (forward-paragraph -2)
+ (if (> (re-search-forward here-filler nil t) here)
+ (goto-char here)))
+ (point))))
+
+ ;; Now seek successively earlier sentence ends between PAR-BEG and
+ ;; HERE, until the "start of sentence" following it is earlier than
+ ;; HERE, or we hit PAR-BEG. Beware of comment prefices!
+ (while (and (re-search-backward (c-sentence-end) par-beg 'limit)
+ (setq last (point))
+ (goto-char (match-end 0)) ; tentative beginning of sentence
+ (or (>= (point) here)
+ (and (not (bolp)) ; Found a non-blank comment-prefix?
+ (save-excursion
+ (if (re-search-backward prefix-at-bol-here nil t)
+ (/= (match-beginning 1) (match-end 1)))))
+ (progn ; Skip the crud to find a real b-o-s.
+ (if (c-in-comment-line-prefix-p)
+ (beginning-of-line))
+ (re-search-forward here-filler) ; always succeeds.
+ (>= (point) here))))
+ (goto-char last))
+ (re-search-forward here-filler)))
+
+ (if (< (point) start-point)
+ nil
+ (goto-char (car range))
+ t))))
+
+(defun c-end-of-sentence-in-comment (range)
+ ;; Move forward to the "end of a sentence" within the comment defined by
+ ;; RANGE, a cons of its starting and ending positions (enclosing the opening
+ ;; comment delimiter and the terminating */ or newline). If we find an EOS,
+ ;; return NIL. Otherwise, move point to just after the end of the comment
+ ;; and return T.
+ ;;
+ ;; The EOS is just after the non-WS part of the next match of the regexp
+ ;; sentence-end. Typically, this is just after one of [.!?]. If there is
+ ;; no sentence-end match following point, any WS before the end of the
+ ;; comment will count as EOS, providing we're not already in it.
+ ;;
+ ;; This code was adapted from GNU Emacs's forward-sentence in paragraphs.el.
+ ;; It is not a general function, but is intended only for calling from
+ ;; c-move-over-sentence.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-match-data
+ (let ((start-point (point))
+ ;; (lit-type (c-literal-type range)) ; Commented out, 2005/11/23, ACM
+ )
+ (save-restriction
+ (c-narrow-to-comment-innards range) ; This might move point forwards.
+ (let* ((here (point))
+ (par-end ; EOL position of last text in current/next paragraph.
+ (save-excursion
+ ;; The cc-mode values of paragraph-\(start\|separate\), set
+ ;; in c-setup-paragraph-variables, are used in the
+ ;; following.
+ (forward-paragraph 1)
+ (if (eq (preceding-char) ?\n) (forward-char -1))
+ (when (<= (point) here) ; can happen, e.g., when HERE is at EOL.
+ (goto-char here)
+ (forward-paragraph 2)
+ (if (eq (preceding-char) ?\n) (forward-char -1)))
+ (point)))
+
+ last
+ (prefix-at-bol-here
+ (concat "^[ \t]*\\(" c-current-comment-prefix "\\)\\=")))
+ ;; Go forward one "comment-prefix which looks like sentence-end"
+ ;; each time round the following:
+ (while (and (re-search-forward (c-sentence-end) par-end 'limit)
+ (progn
+ (setq last (point))
+ (skip-chars-backward " \t\n")
+ (or (and (not (bolp))
+ (re-search-backward prefix-at-bol-here nil t)
+ (/= (match-beginning 1) (match-end 1)))
+ (<= (point) here))))
+ (goto-char last))
+
+ ;; Take special action if we're up against the end of a comment (of
+ ;; either sort): Leave point just after the last non-ws text.
+ (if (eq (point) (point-max))
+ (while (or (/= (skip-chars-backward " \t\n") 0)
+ (and (re-search-backward prefix-at-bol-here nil t)
+ (/= (match-beginning 1) (match-end 1))))))))
+
+ (if (> (point) start-point)
+ nil
+ (goto-char (cdr range))
+ t))))
+
+(defun c-beginning-of-sentence-in-string (range)
+ ;; Move backwards to the "beginning of a sentence" within the string defined
+ ;; by RANGE, a cons of its starting and ending positions (enclosing the
+ ;; string quotes). If we find a BOS, return NIL. Otherwise, move point to
+ ;; just before the start of the string and return T.
+ ;;
+ ;; The BOS is either the text which follows a regexp match of sentence-end
+ ;; or text which is a beginning of "paragraph". For the purposes of
+ ;; determining paragraph boundaries, escaped newlines are treated as
+ ;; ordinary newlines.
+ ;;
+ ;; This code was adapted from GNU Emacs's forward-sentence in paragraphs.el.
+ ;; It is not a general function, but is intended only for calling from
+ ;; c-move-over-sentence.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-match-data
+ (let* ((here (point)) last
+ (end (1- (cdr range)))
+ (here-filler ; matches WS and escaped newlines at point.
+ "\\=\\([ \t\n\r\f]\\|\\\\[\n\r]\\)*")
+ ;; Enhance paragraph-start and paragraph-separate also to recognise
+ ;; blank lines terminated by escaped EOLs. IT MAY WELL BE that
+ ;; these values should be customizable user options, or something.
+ (paragraph-start c-string-par-start)
+ (paragraph-separate c-string-par-separate)
+
+ (par-beg ; beginning of current (or previous) paragraph.
+ (save-excursion
+ (save-restriction
+ (narrow-to-region (1+ (car range)) end)
+ (forward-paragraph -1) ; uses above values of
+ ; paragraph-\(start\|separate\)
+ (if (> (re-search-forward here-filler nil t) here)
+ (goto-char here))
+ (when (>= (point) here)
+ (forward-paragraph -2)
+ (if (> (re-search-forward here-filler nil t) here)
+ (goto-char here)))
+ (point)))))
+ ;; Now see if we can find a sentence end after PAR-BEG.
+ (while (and (re-search-backward c-sentence-end-with-esc-eol par-beg 'limit)
+ (setq last (point))
+ (goto-char (match-end 0))
+ (or (> (point) end)
+ (progn
+ (re-search-forward
+ here-filler end t) ; always succeeds. Use end rather
+ ; than here, in case point starts
+ ; beyond the closing quote.
+ (>= (point) here))))
+ (goto-char last))
+ (re-search-forward here-filler here t)
+ (if (< (point) here)
+ nil
+ (goto-char (car range))
+ t))))
+
+(defun c-end-of-sentence-in-string (range)
+ ;; Move forward to the "end of a sentence" within the string defined by
+ ;; RANGE, a cons of its starting and ending positions. If we find an EOS,
+ ;; return NIL. Otherwise, move point to just after the end of the string
+ ;; and return T.
+ ;;
+ ;; The EOS is just after the non-WS part of the next match of the regexp
+ ;; sentence-end. Typically, this is just after one of [.!?]. If there is
+ ;; no sentence-end match following point, any WS before the end of the
+ ;; string will count as EOS, providing we're not already in it.
+ ;;
+ ;; This code was adapted from GNU Emacs's forward-sentence in paragraphs.el.
+ ;; It is not a general function, but is intended only for calling from
+ ;; c-move-over-sentence.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-match-data
+ (let* ((here (point))
+ last
+ ;; Enhance paragraph-start and paragraph-separate to recognise
+ ;; blank lines terminated by escaped EOLs.
+ (paragraph-start c-string-par-start)
+ (paragraph-separate c-string-par-separate)
+
+ (par-end ; EOL position of last text in current/next paragraph.
+ (save-excursion
+ (save-restriction
+ (narrow-to-region (car range) (1- (cdr range)))
+ ;; The above values of paragraph-\(start\|separate\) are used
+ ;; in the following.
+ (forward-paragraph 1)
+ (setq last (point))
+ ;; (re-search-backward filler-here nil t) would find an empty
+ ;; string. Therefore we simulate it by the following:
+ (while (or (/= (skip-chars-backward " \t\n\r\f") 0)
+ (re-search-backward "\\\\\\($\\)\\=" nil t)))
+ (unless (> (point) here)
+ (goto-char last)
+ (forward-paragraph 1)
+ (while (or (/= (skip-chars-backward " \t\n\r\f") 0)
+ (re-search-backward "\\\\\\($\\)\\=" nil t))))
+ (point)))))
+ ;; Try to go forward a sentence.
+ (when (re-search-forward c-sentence-end-with-esc-eol par-end 'limit)
+ (setq last (point))
+ (while (or (/= (skip-chars-backward " \t\n") 0)
+ (re-search-backward "\\\\\\($\\)\\=" nil t))))
+ ;; Did we move a sentence, or did we hit the end of the string?
+ (if (> (point) here)
+ nil
+ (goto-char (cdr range))
+ t))))
+
+(defun c-ascertain-preceding-literal ()
+ ;; Point is not in a literal (i.e. comment or string (include AWK regexp)).
+ ;; If a literal is the next thing (aside from whitespace) to be found before
+ ;; point, return a cons of its start.end positions (enclosing the
+ ;; delimiters). Otherwise return NIL.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-excursion
+ (c-collect-line-comments
+ (let ((here (point))
+ pos)
+ (if (c-backward-single-comment)
+ (cons (point) (progn (c-forward-single-comment) (point)))
+ (save-restriction
+ ;; to prevent `looking-at' seeing a " at point.
+ (narrow-to-region (point-min) here)
+ (when
+ (or
+ ;; An EOL can act as an "open string" terminator in AWK.
+ (looking-at c-ws*-string-limit-regexp)
+ (and (not (bobp))
+ (progn (backward-char)
+ (looking-at c-string-limit-regexp))))
+ (goto-char (match-end 0)) ; just after the string terminator.
+ (setq pos (point))
+ (c-safe (c-backward-sexp 1) ; move back over the string.
+ (cons (point) pos)))))))))
+
+(defun c-ascertain-following-literal ()
+ ;; Point is not in a literal (i.e. comment or string (include AWK regexp)).
+ ;; If a literal is the next thing (aside from whitespace) following point,
+ ;; return a cons of its start.end positions (enclosing the delimiters).
+ ;; Otherwise return NIL.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-excursion
+ (c-collect-line-comments
+ (let (pos)
+ (c-skip-ws-forward)
+ (if (looking-at c-string-limit-regexp) ; string-delimiter.
+ (cons (point) (or (c-safe (progn (c-forward-sexp 1) (point)))
+ (point-max)))
+ (setq pos (point))
+ (if (c-forward-single-comment)
+ (cons pos (point))))))))
+
+(defun c-after-statement-terminator-p () ; Should we pass in LIM here?
+ ;; Does point immediately follow a statement "terminator"? A virtual
+ ;; semicolon is regarded here as such. So is a an opening brace ;-)
+ ;;
+ ;; This function might do hidden buffer changes.
+ (or (save-excursion
+ (backward-char)
+ (and (looking-at "[;{}]")
+ (not (and c-special-brace-lists ; Pike special brace lists.
+ (eq (char-after) ?{)
+ (c-looking-at-special-brace-list)))))
+ (c-at-vsemi-p)
+ ;; The following (for macros) is not strict about exactly where we are
+ ;; wrt white space at the end of the macro. Doesn't seem to matter too
+ ;; much. ACM 2004/3/29.
+ (let (eom)
+ (save-excursion
+ (if (c-beginning-of-macro)
+ (setq eom (progn (c-end-of-macro)
+ (point)))))
+ (when eom
+ (save-excursion
+ (c-forward-comments)
+ (>= (point) eom))))))
+
+(defun c-back-over-illiterals (macro-start)
+ ;; Move backwards over code which isn't a literal (i.e. comment or string),
+ ;; stopping before reaching BOB or a literal or the boundary of a
+ ;; preprocessor statement or the "beginning of a statement". MACRO-START is
+ ;; the position of the '#' beginning the current preprocessor directive, or
+ ;; NIL if we're not in such.
+ ;;
+ ;; Return a cons (A.B), where
+ ;; A is NIL if we moved back to a BOS (and know it), T otherwise (we
+ ;; didn't move, or we hit a literal, or we're not sure about BOS).
+ ;; B is MACRO-BOUNDARY if we are about to cross the boundary out of or
+ ;; into a macro, otherwise LITERAL if we've hit a literal, otherwise NIL
+ ;;
+ ;; The total collection of returned values is as follows:
+ ;; (nil . nil): Found a BOS whilst remaining inside the illiterals.
+ ;; (t . literal): No BOS found: only a comment/string. We _might_ be at
+ ;; a BOS - the caller must check this.
+ ;; (nil . macro-boundary): only happens with non-nil macro-start. We've
+ ;; moved and reached the opening # of the macro.
+ ;; (t . macro-boundary): Every other circumstance in which we're at a
+ ;; macro-boundary. We might be at a BOS.
+ ;;
+ ;; Point is left either at the beginning-of-statement, or at the last non-ws
+ ;; code before encountering the literal/BOB or macro-boundary.
+ ;;
+ ;; Note that this function moves within either preprocessor commands
+ ;; (macros) or normal code, but will not cross a boundary between the two,
+ ;; or between two distinct preprocessor commands.
+ ;;
+ ;; 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 at boi on a line.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-match-data
+ (let ((here (point))
+ last) ; marks the position of non-ws code, what'll be BOS if, say, a
+ ; semicolon precedes it.
+ (catch 'done
+ (while t ;; We go back one "token" each iteration of the loop.
+ (setq last (point))
+ (cond
+ ;; Stop at the token after a comment.
+ ((c-backward-single-comment) ; Also functions as backwards-ws.
+ (goto-char last)
+ (throw 'done '(t . literal)))
+
+ ;; If we've gone back over a LF, we might have moved into or out of
+ ;; a preprocessor line.
+ ((and (save-excursion
+ (beginning-of-line)
+ (re-search-forward "\\(^\\|[^\\]\\)[\n\r]" last t))
+ (if macro-start
+ (< (point) macro-start)
+ (c-beginning-of-macro)))
+ (goto-char last)
+ ;; Return a car of NIL ONLY if we've hit the opening # of a macro.
+ (throw 'done (cons (or (eq (point) here)
+ (not macro-start))
+ 'macro-boundary)))
+
+ ;; Have we found a virtual semicolon? If so, stop, unless the next
+ ;; statement is where we started from.
+ ((and (c-at-vsemi-p)
+ (< last here)
+ (not (memq (char-after last) '(?\) ?})))) ; we've moved back from ) or }
+ (goto-char last)
+ (throw 'done '(nil . nil)))
+
+ ;; Hit the beginning of the buffer/region?
+ ((bobp)
+ (if (/= here last)
+ (goto-char last))
+ (throw 'done '(nil . nil)))
+
+ ;; Move back a character.
+ ((progn (backward-char) nil))
+
+ ;; Stop at "{" (unless it's a PIKE special brace list.)
+ ((eq (char-after) ?\{)
+ (if (and c-special-brace-lists
+ (c-looking-at-special-brace-list))
+ (skip-syntax-backward "w_") ; Speedup only.
+ (if (/= here last)
+ (goto-char last))
+ (throw 'done '(nil . nil))))
+
+ ;; Have we reached the start of a macro? This always counts as
+ ;; BOS. (N.B. I don't think (eq (point) here) can ever be true
+ ;; here. FIXME!!! ACM 2004/3/29)
+ ((and macro-start (eq (point) macro-start))
+ (throw 'done (cons (eq (point) here) 'macro-boundary)))
+
+ ;; Stop at token just after "}" or ";".
+ ((looking-at "[;}]")
+ ;; If we've gone back over ;, {, or }, we're done.
+ (if (or (= here last)
+ (memq (char-after last) '(?\) ?}))) ; we've moved back from ) or }
+ (if (and (eq (char-before) ?}) ; If };, treat them as a unit.
+ (eq (char-after) ?\;))
+ (backward-char))
+ (goto-char last) ; To the statement starting after the ; or }.
+ (throw 'done '(nil . nil))))
+
+ ;; Stop at the token after a string.
+ ((looking-at c-string-limit-regexp) ; Just gone back over a string terminator?
+ (goto-char last)
+ (throw 'done '(t . literal)))
+
+ ;; Nothing special: go back word characters.
+ (t (skip-syntax-backward "w_")) ; Speedup only.
+ ))))))
+
+(defun c-forward-over-illiterals (macro-end allow-early-stop)
+ ;; Move forwards over code, stopping before reaching EOB or a literal
+ ;; (i.e. a comment/string) or the boundary of a preprocessor statement or
+ ;; the "end of a statement". MACRO-END is the position of the EOL/EOB which
+ ;; terminates the current preprocessor directive, or NIL if we're not in
+ ;; such.
+ ;;
+ ;; ALLOW-EARLY-STOP is non-nil if it is permissible to return without moving
+ ;; forward at all, should we encounter a `{'. This is an ugly kludge, but
+ ;; seems unavoidable. Depending on the context this function is called
+ ;; from, we _sometimes_ need to stop there. Currently (2004/4/3),
+ ;; ALLOW-EARLY-STOP is applied only to open braces, not to virtual
+ ;; semicolons, or anything else.
+ ;;
+ ;; Return a cons (A.B), where
+ ;; A is NIL if we moved forward to an EOS, or stay at one (when
+ ;; ALLOW-EARLY-STOP is set), T otherwise (we hit a literal).
+ ;; B is 'MACRO-BOUNDARY if we are about to cross the boundary out of or
+ ;; into a macro, otherwise 'LITERAL if we've hit a literal, otherwise NIL
+ ;;
+ ;; Point is left either after the end-of-statement, or at the last non-ws
+ ;; code before encountering the literal, or the # of the preprocessor
+ ;; statement, or at EOB [or just after last non-WS stuff??].
+ ;;
+ ;; As a clarification of "after the end-of-statement", if a comment or
+ ;; whitespace follows a completed AWK statement, that statement is treated
+ ;; as ending just after the last non-ws character before the comment.
+ ;;
+ ;; Note that this function moves within either preprocessor commands
+ ;; (macros) or normal code, but not both within the same invocation.
+ ;;
+ ;; Stop before `{', `}', and `#' when it's at boi 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 with `#' at
+ ;; the boi.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (let ((here (point))
+ last)
+ (catch 'done
+ (while t ;; We go one "token" forward each time round this loop.
+ (setq last (point))
+
+ ;; If we've moved forward to a virtual semicolon, we're done.
+ (if (and (> last here) ; Should we check ALLOW-EARLY-STOP, here? 2004/4/3
+ (c-at-vsemi-p))
+ (throw 'done '(nil . nil)))
+
+ (c-skip-ws-forward)
+ (cond
+ ;; Gone past the end of a macro?
+ ((and macro-end (> (point) macro-end))
+ (goto-char last)
+ (throw 'done (cons (eq (point) here) 'macro-boundary)))
+
+ ;; About to hit a comment?
+ ((save-excursion (c-forward-single-comment))
+ (goto-char last)
+ (throw 'done '(t . literal)))
+
+ ;; End of buffer?
+ ((eobp)
+ (if (/= here last)
+ (goto-char last))
+ (throw 'done '(nil . nil)))
+
+ ;; If we encounter a '{', stop just after the previous token.
+ ((and (eq (char-after) ?{)
+ (not (and c-special-brace-lists
+ (c-looking-at-special-brace-list)))
+ (or allow-early-stop (/= here last))
+ (save-excursion ; Is this a check that we're NOT at top level?
+;;;; NO! This seems to check that (i) EITHER we're at the top level; OR (ii) The next enclosing
+;;;; level of bracketing is a '{'. HMM. Doesn't seem to make sense.
+;;;; 2003/8/8 This might have something to do with the GCC extension "Statement Expressions", e.g.
+;;;; while ({stmt1 ; stmt2 ; exp ;}). This form excludes such Statement Expressions.
+ (or (not (c-safe (up-list -1) t))
+ (= (char-after) ?{))))
+ (goto-char last)
+ (throw 'done '(nil . nil)))
-\f
-;; better movement routines for ThisStyleOfVariablesCommonInCPlusPlus
-;; originally contributed by Terry_Glanfield.Southern@rxuk.xerox.com
-(defun c-forward-into-nomenclature (&optional arg)
- "Move forward to end of a nomenclature section or word.
-With arg, to it arg times."
- (interactive "p")
- (let ((case-fold-search nil))
- (if (> arg 0)
- (re-search-forward "\\W*\\([A-Z]*[a-z0-9]*\\)" (point-max) t arg)
- (while (and (< arg 0)
- (re-search-backward
- "\\(\\(\\W\\|[a-z0-9]\\)[A-Z]+\\|\\W\\w+\\)"
- (point-min) 0))
- (forward-char 1)
- (setq arg (1+ arg)))))
- (c-keep-region-active))
+ ;; End of a PIKE special brace list? If so, step over it and continue.
+ ((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)
+ (skip-syntax-forward "w_")) ; Speedup only.
-(defun c-backward-into-nomenclature (&optional arg)
- "Move backward to beginning of a nomenclature section or word.
-With optional ARG, move that many times. If ARG is negative, move
-forward."
- (interactive "p")
- (c-forward-into-nomenclature (- arg))
- (c-keep-region-active))
+ ;; Have we got a '}' after having moved? If so, stop after the
+ ;; previous token.
+ ((and (eq (char-after) ?})
+ (/= here last))
+ (goto-char last)
+ (throw 'done '(nil . nil)))
-(defun c-scope-operator ()
- "Insert a double colon scope operator at point.
-No indentation or other \"electric\" behavior is performed."
- (interactive)
- (insert "::"))
+ ;; Stop if we encounter a preprocessor line.
+ ((and (not macro-end)
+ (eq (char-after) ?#)
+ (= (point) (c-point 'boi)))
+ (goto-char last)
+ ;(throw 'done (cons (eq (point) here) 'macro-boundary))) ; Changed 2003/3/26
+ (throw 'done '(t . macro-boundary)))
+
+ ;; Stop after a ';', '}', or "};"
+ ((looking-at ";\\|};?")
+ (goto-char (match-end 0))
+ (throw 'done '(nil . nil)))
+
+ ;; Found a string (this subsumes AWK regexps)?
+ ((looking-at c-string-limit-regexp)
+ (goto-char last)
+ (throw 'done '(t . literal)))
+
+ (t
+ (forward-char) ; Can't fail - we checked (eobp) earlier on.
+ (skip-syntax-forward "w_") ; Speedup only.
+ (when (and macro-end (> (point) macro-end))
+ (goto-char last)
+ (throw 'done (cons (eq (point) here) 'macro-boundary))))
+ )))))
+
+(defun c-one-line-string-p (range)
+ ;; Is the literal defined by RANGE a string contained in a single line?
+ ;;
+ ;; This function might do hidden buffer changes.
+ (save-excursion
+ (goto-char (car range))
+ (and (looking-at c-string-limit-regexp)
+ (progn (skip-chars-forward "^\n" (cdr range))
+ (eq (point) (cdr range))))))
-\f
(defun c-beginning-of-statement (&optional count lim sentence-flag)
"Go to the beginning of the innermost C statement.
With prefix arg, go back N - 1 statements. If already at the
-beginning of a statement then go to the beginning of the preceding
-one. If within a string or comment, or next to a comment (only
-whitespace between), move by sentences instead of statements.
+beginning of a statement then go to the beginning of the closest
+preceding one, moving into nested blocks if necessary (use
+\\[backward-sexp] to skip over a block). If within or next to a
+comment or multiline string, move by sentences instead of statements.
When called from a program, this function takes 3 optional args: the
repetition count, a buffer position limit which is the farthest back
-to search, and a flag saying whether to do sentence motion when in a
-comment."
+to search for the syntactic context, and a flag saying whether to do
+sentence motion in or near comments and multiline strings.
+
+Note that for use in programs, `c-beginning-of-statement-1' is
+usually better. It has much better defined semantics than this one,
+which is intended for interactive use, and might therefore change to
+be more \"DWIM:ey\"."
(interactive (list (prefix-numeric-value current-prefix-arg)
nil t))
- (let ((here (point))
- (count (or count 1))
- (lim (or lim (c-point 'bod)))
- state)
- (save-excursion
- (goto-char lim)
- (setq state (parse-partial-sexp (point) here nil nil)))
- (if (and sentence-flag
- (or (nth 3 state)
- (nth 4 state)
-; (looking-at (concat "[ \t]*" comment-start-skip))
- (save-excursion
- (skip-chars-backward " \t")
- (goto-char (- (point) 2))
- (looking-at "\\*/"))))
- (forward-sentence (- count))
- (while (> count 0)
- (c-beginning-of-statement-1 lim)
- (setq count (1- count)))
- (while (< count 0)
- (c-end-of-statement-1)
- (setq count (1+ count))))
- ;; its possible we've been left up-buf of lim
- (goto-char (max (point) lim))
- )
- (c-keep-region-active))
+ (if (< count 0)
+ (c-end-of-statement (- count) lim sentence-flag)
+ (c-save-buffer-state
+ ((count (or count 1))
+ last ; start point for going back ONE chunk. Updated each chunk movement.
+ (macro-fence
+ (save-excursion (and (not (bobp)) (c-beginning-of-macro) (point))))
+ res ; result from sub-function call
+ not-bos ; "not beginning-of-statement"
+ (range (c-collect-line-comments (c-literal-limits lim)))) ; (start.end) of current literal or NIL
+
+ ;; Go back one statement at each iteration of the following loop.
+ (while (and (/= count 0)
+ (or (not lim) (> (point) lim)))
+ ;; Go back one "chunk" each time round the following loop, stopping
+ ;; when we reach a statement boundary, etc.
+ (setq last (point))
+ (while
+ (cond ; Each arm of this cond returns NIL on reaching a desired
+ ; statement boundary, non-NIL otherwise.
+ ((bobp)
+ (setq count 0)
+ nil)
+
+ (range ; point is within or approaching a literal.
+ (cond
+ ;; Single line string or sentence-flag is null => skip the
+ ;; entire literal.
+ ((or (null sentence-flag)
+ (c-one-line-string-p range))
+ (goto-char (car range))
+ (setq range (c-ascertain-preceding-literal))
+ ;; N.B. The following is essentially testing for an AWK regexp
+ ;; at BOS:
+ ;; Was the previous non-ws thing an end of statement?
+ (save-excursion
+ (if macro-fence
+ (c-backward-comments)
+ (c-backward-syntactic-ws))
+ (not (or (bobp) (c-after-statement-terminator-p)))))
+
+ ;; Comment inside a statement or a multi-line string.
+ (t (when (setq res ; returns non-nil when we go out of the literal
+ (if (eq (c-literal-type range) 'string)
+ (c-beginning-of-sentence-in-string range)
+ (c-beginning-of-sentence-in-comment range)))
+ (setq range (c-ascertain-preceding-literal)))
+ res)))
+
+ ;; Non-literal code.
+ (t (setq res (c-back-over-illiterals macro-fence))
+ (setq not-bos ; "not reached beginning-of-statement".
+ (or (= (point) last)
+ (memq (char-after) '(?\) ?\}))
+ (and
+ (car res)
+ ;; We're at a tentative BOS. The next form goes
+ ;; back over WS looking for an end of previous
+ ;; statement.
+ (not (save-excursion
+ (if macro-fence
+ (c-backward-comments)
+ (c-backward-syntactic-ws))
+ (or (bobp) (c-after-statement-terminator-p)))))))
+ ;; Are we about to move backwards into or out of a
+ ;; preprocessor command? If so, locate it's beginning.
+ (when (eq (cdr res) 'macro-boundary)
+ (save-excursion
+ (beginning-of-line)
+ (setq macro-fence
+ (and (not (bobp))
+ (progn (c-skip-ws-backward) (c-beginning-of-macro))
+ (point)))))
+ ;; Are we about to move backwards into a literal?
+ (when (memq (cdr res) '(macro-boundary literal))
+ (setq range (c-ascertain-preceding-literal)))
+ not-bos))
+ (setq last (point)))
+
+ (if (/= count 0) (setq count (1- count))))
+ (c-keep-region-active))))
(defun c-end-of-statement (&optional count lim sentence-flag)
"Go to the end of the innermost C statement.
-
-With prefix arg, go forward N - 1 statements. Move forward to end of
-the next statement if already at end. If within a string or comment,
-move by sentences instead of statements.
+With prefix arg, go forward N - 1 statements. Move forward to the end
+of the next statement if already at end, and move into nested blocks
+\(use \\[forward-sexp] to skip over a block). If within or next to a
+comment or multiline string, move by sentences instead of statements.
When called from a program, this function takes 3 optional args: the
repetition count, a buffer position limit which is the farthest back
-to search, and a flag saying whether to do sentence motion when in a
-comment."
+to search for the syntactic context, and a flag saying whether to do
+sentence motion in or near comments and multiline strings."
(interactive (list (prefix-numeric-value current-prefix-arg)
nil t))
- (c-beginning-of-statement (- (or count 1)) lim sentence-flag)
- (c-keep-region-active))
+ (setq count (or count 1))
+ (if (< count 0) (c-beginning-of-statement (- count) lim sentence-flag)
+
+ (c-save-buffer-state
+ (here ; start point for going forward ONE statement. Updated each statement.
+ (macro-fence
+ (save-excursion
+ (and (not (eobp)) (c-beginning-of-macro)
+ (progn (c-end-of-macro) (point)))))
+ res
+ (range (c-collect-line-comments (c-literal-limits lim)))) ; (start.end) of current literal or NIL
+
+ ;; Go back/forward one statement at each iteration of the following loop.
+ (while (and (/= count 0)
+ (or (not lim) (< (point) lim)))
+ (setq here (point)) ; ONLY HERE is HERE updated
+
+ ;; Go forward one "chunk" each time round the following loop, stopping
+ ;; when we reach a statement boundary, etc.
+ (while
+ (cond ; Each arm of this cond returns NIL on reaching a desired
+ ; statement boundary, non-NIL otherwise.
+ ((eobp)
+ (setq count 0)
+ nil)
+
+ (range ; point is within a literal.
+ (cond
+ ;; sentence-flag is null => skip the entire literal.
+ ;; or a Single line string.
+ ((or (null sentence-flag)
+ (c-one-line-string-p range))
+ (goto-char (cdr range))
+ (setq range (c-ascertain-following-literal))
+ ;; Is there a virtual semicolon here (e.g. for AWK)?
+ (not (c-at-vsemi-p)))
+
+ ;; Comment or multi-line string.
+ (t (when (setq res ; gets non-nil when we go out of the literal
+ (if (eq (c-literal-type range) 'string)
+ (c-end-of-sentence-in-string range)
+ (c-end-of-sentence-in-comment range)))
+ (setq range (c-ascertain-following-literal)))
+ ;; If we've just come forward out of a literal, check for
+ ;; vsemi. (N.B. AWK can't have a vsemi after a comment, but
+ ;; some other language may do in the future)
+ (and res
+ (not (c-at-vsemi-p))))))
+
+ ;; Non-literal code.
+ (t (setq res (c-forward-over-illiterals macro-fence
+ (> (point) here)))
+ ;; Are we about to move forward into or out of a
+ ;; preprocessor command?
+ (when (eq (cdr res) 'macro-boundary)
+ (save-excursion
+ (end-of-line)
+ (setq macro-fence
+ (and (not (eobp))
+ (progn (c-skip-ws-forward)
+ (c-beginning-of-macro))
+ (progn (c-end-of-macro)
+ (point))))))
+ ;; Are we about to move forward into a literal?
+ (when (memq (cdr res) '(macro-boundary literal))
+ (setq range (c-ascertain-following-literal)))
+ (car res))))
+
+ (if (/= count 0) (setq count (1- count))))
+ (c-keep-region-active))))
\f
;; set up electric character functions to work with pending-del,
c-electric-star
c-electric-semi&comma
c-electric-lt-gt
- c-electric-colon))
+ c-electric-colon
+ c-electric-paren))
(put 'c-electric-delete 'delete-selection 'supersede) ; delsel
(put 'c-electric-delete 'pending-delete 'supersede) ; pending-del
(put 'c-electric-backspace 'delete-selection 'supersede) ; delsel
(put 'c-electric-backspace 'pending-delete 'supersede) ; pending-del
+(put 'c-electric-delete-forward 'delete-selection 'supersede) ; delsel
+(put 'c-electric-delete-forward 'pending-delete 'supersede) ; pending-del
\f
-;; This is used by indent-for-comment to decide how much to indent a
-;; comment in C code based on its context.
+;; Inserting/indenting comments
+(defun c-calc-comment-indent (entry)
+ ;; This function might do hidden buffer changes.
+ (if (symbolp entry)
+ (setq entry (or (assq entry c-indent-comment-alist)
+ (assq 'other c-indent-comment-alist)
+ '(default . (column . nil)))))
+ (let ((action (car (cdr entry)))
+ (value (cdr (cdr entry)))
+ (col (current-column)))
+ (cond ((eq action 'space)
+ (+ col value))
+ ((eq action 'column)
+ (unless value (setq value comment-column))
+ (if (bolp)
+ ;; Do not pad with one space if we're at bol.
+ value
+ (max (1+ col) value)))
+ ((eq action 'align)
+ (or (save-excursion
+ (beginning-of-line)
+ (unless (bobp)
+ (backward-char)
+ (let ((lim (c-literal-limits (c-point 'bol) t)))
+ (when (consp lim)
+ (goto-char (car lim))
+ (when (looking-at "/[/*]") ; FIXME!!! Adapt for AWK! (ACM, 2005/11/18)
+ ;; Found comment to align with.
+ (if (bolp)
+ ;; Do not pad with one space if we're at bol.
+ 0
+ (max (1+ col) (current-column))))))))
+ ;; Recurse to handle value as a new spec.
+ (c-calc-comment-indent (cdr entry)))))))
+
(defun c-comment-indent ()
- (if (looking-at (concat "^\\(" c-comment-start-regexp "\\)"))
- 0 ;Existing comment at bol stays there.
- (let ((opoint (point))
- placeholder)
- (save-excursion
- (beginning-of-line)
- (cond
- ;; CASE 1: A comment following a solitary close-brace should
- ;; have only one space.
- ((looking-at (concat "[ \t]*}[ \t]*\\($\\|"
- c-comment-start-regexp
- "\\)"))
- (search-forward "}")
- (1+ (current-column)))
- ;; CASE 2: 2 spaces after #endif
- ((or (looking-at "^#[ \t]*endif[ \t]*")
- (looking-at "^#[ \t]*else[ \t]*"))
- 7)
- ;; CASE 3: when comment-column is nil, calculate the offset
- ;; according to c-offsets-alist. E.g. identical to hitting
- ;; TAB.
- ((and c-indent-comments-syntactically-p
- (save-excursion
- (skip-chars-forward " \t")
- (or (looking-at comment-start)
- (eolp))))
- (let ((syntax (c-guess-basic-syntax)))
+ "Used by `indent-for-comment' to create and indent comments.
+See `c-indent-comment-alist' for a description."
+ (save-excursion
+ (end-of-line)
+ (c-save-buffer-state
+ ((eot (let ((lim (c-literal-limits (c-point 'bol) t)))
+ (or (when (consp lim)
+ (goto-char (car lim))
+ (when (looking-at "/[/*]")
+ (skip-chars-backward " \t")
+ (point)))
+ (progn
+ (skip-chars-backward " \t")
+ (point)))))
+ (line-type
+ (cond ((looking-at "^/[/*]")
+ 'anchored-comment)
+ ((progn (beginning-of-line)
+ (eq (point) eot))
+ 'empty-line)
+ ((progn (back-to-indentation)
+ (and (eq (char-after) ?})
+ (eq (point) (1- eot))))
+ 'end-block)
+ ((and (looking-at "#[ \t]*\\(endif\\|else\\)")
+ (eq (match-end 0) eot))
+ 'cpp-end-block)
+ (t
+ 'other))))
+ (if (and (memq line-type '(anchored-comment empty-line))
+ c-indent-comments-syntactically-p)
+ (let ((c-syntactic-context (c-guess-basic-syntax)))
;; BOGOSITY ALERT: if we're looking at the eol, its
;; because indent-for-comment hasn't put the comment-start
;; in the buffer yet. this will screw up the syntactic
;; kludge is that if we're at the bol, then we really want
;; to ignore any anchoring as specified by
;; c-comment-only-line-offset since it doesn't apply here.
- (if (save-excursion
- (beginning-of-line)
- (skip-chars-forward " \t")
- (eolp))
+ (if (eolp)
(c-add-syntax 'comment-intro))
(let ((c-comment-only-line-offset
(if (consp c-comment-only-line-offset)
c-comment-only-line-offset
(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
- ((save-excursion
- (beginning-of-line)
- (and (not (bobp))
- (forward-line -1))
- (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)))
- ;; CASE 5: If comment-column is 0, and nothing but space
- ;; before the comment, align it at 0 rather than 1.
- ((progn
- (goto-char opoint)
- (skip-chars-backward " \t")
- (and (= comment-column 0) (bolp)))
- 0)
- ;; CASE 6: indent at comment column except leave at least one
- ;; space.
- (t (max (1+ (current-column))
- comment-column))
- )))))
-
-;; 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
- (if (not c-comment-continuation-stars)
- (indent-new-comment-line soft)
- (let ((here (point))
- (leader c-comment-continuation-stars))
- (back-to-indentation)
- ;; 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 "// "))
- (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)
- (c-indent-line))))
-
-;; advice for indent-new-comment-line for older Emacsen
-(if (boundp 'comment-line-break-function)
- nil
- (require 'advice)
- (defadvice indent-new-comment-line (around c-line-break-advice activate)
- (if (or (not c-buffer-is-cc-mode)
- (not c-comment-continuation-stars))
- ad-do-it
- (c-comment-line-break-function (ad-get-arg 0)))))
+ (c-get-syntactic-indentation c-syntactic-context)))
+ (goto-char eot)
+ (c-calc-comment-indent line-type)))))
+\f
;; used by outline-minor-mode
(defun c-outline-level ()
- (save-excursion
- (skip-chars-forward "\t ")
- (current-column)))
+ (let (buffer-invisibility-spec);; This so that `current-column' DTRT
+ ;; in otherwise-hidden text.
+ (save-excursion
+ (skip-chars-forward "\t ")
+ (current-column))))
\f
+;; Movement by CPP conditionals.
(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) t)
+ (c-forward-conditional (- count) -1)
(c-keep-region-active))
-(defun c-backward-conditional (count &optional up-flag)
+(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 1)
+ (c-keep-region-active))
+
+(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)
;; 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)))
\f
;; commands to indent lines, regions, defuns, and expressions
-(defun c-indent-command (&optional whole-exp)
+(defun c-indent-command (&optional arg)
"Indent current line as C code, and/or insert some whitespace.
If `c-tab-always-indent' is t, always just indent the current line.
If nil, indent the current line only if point is at the left margin or
in the line's indentation; otherwise insert some whitespace[*]. If
other than nil or t, then some whitespace[*] is inserted only within
-literals (comments and strings) and inside preprocessor directives,
-but the line is always reindented.
+literals (comments and strings), but the line is always reindented.
+
+If `c-syntactic-indentation' is t, indentation is done according to
+the syntactic context. 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 is preserved.
-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.
+If `c-syntactic-indentation' is nil, the line is just indented one
+step according to `c-basic-offset'. In this mode, a numeric argument
+indents a number of such steps, positive or negative, and an empty
+prefix argument is equivalent to -1.
[*] The amount and kind of whitespace inserted is controlled by the
variable `c-insert-tab-function', which is called to do the actual
depending on the variable `indent-tabs-mode'."
(interactive "P")
- (let ((bod (c-point 'bod)))
- (if whole-exp
- ;; If arg, always indent this line as C
- ;; and shift remaining lines of expression the same amount.
- (let ((shift-amt (c-indent-line))
+ (let ((indent-function
+ (if c-syntactic-indentation
+ (symbol-function 'indent-according-to-mode)
+ (lambda ()
+ (let ((c-macro-start c-macro-start)
+ (steps (if (equal arg '(4))
+ -1
+ (prefix-numeric-value arg))))
+ (c-shift-line-indentation (* steps c-basic-offset))
+ (when (and c-auto-align-backslashes
+ (save-excursion
+ (end-of-line)
+ (eq (char-before) ?\\))
+ (c-query-and-set-macro-start))
+ ;; Realign the line continuation backslash if inside a macro.
+ (c-backslash-region (point) (point) nil t)))
+ ))))
+ (if (and c-syntactic-indentation arg)
+ ;; If c-syntactic-indentation and got arg, always indent this
+ ;; line as C and shift remaining lines of expression the same
+ ;; amount.
+ (let ((shift-amt (save-excursion
+ (back-to-indentation)
+ (current-column)))
beg end)
+ (c-indent-line)
+ (setq shift-amt (- (save-excursion
+ (back-to-indentation)
+ (current-column))
+ shift-amt))
(save-excursion
(if (eq c-tab-always-indent t)
- (beginning-of-line))
+ (beginning-of-line)) ; FIXME!!! What is this here for? ACM 2005/10/31
(setq beg (point))
- (forward-sexp 1)
+ (c-forward-sexp 1)
(setq end (point))
(goto-char beg)
(forward-line 1)
(setq beg (point)))
(if (> end beg)
- (indent-code-rigidly beg end (- shift-amt) "#")))
- ;; No arg supplied, use c-tab-always-indent to determine
- ;; behavior
+ (indent-code-rigidly beg end shift-amt "#")))
+ ;; Else use c-tab-always-indent to determine behavior.
(cond
- ;; CASE 1: indent when at column zero or in lines indentation,
+ ;; CASE 1: indent when at column zero or in line's indentation,
;; otherwise insert a tab
((not c-tab-always-indent)
(if (save-excursion
(skip-chars-backward " \t")
(not (bolp)))
(funcall c-insert-tab-function)
- (c-indent-line)))
+ (funcall indent-function)))
;; CASE 2: just indent the line
((eq c-tab-always-indent t)
- (c-indent-line))
+ (funcall indent-function))
;; CASE 3: if in a literal, insert a tab, but always indent the
;; line
(t
- (if (c-in-literal bod)
+ (if (c-save-buffer-state () (c-in-literal))
(funcall c-insert-tab-function))
- (c-indent-line)
+ (funcall indent-function)
)))))
(defun c-indent-exp (&optional shutup-p)
- "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))
- end progress-p)
+ "Indent each line in the balanced expression following point syntactically.
+If optional SHUTUP-P is non-nil, no errors are signaled if no
+balanced expression is found."
+ (interactive "*P")
+ (let ((here (point-marker))
+ end)
+ (set-marker-insertion-type here t)
(unwind-protect
- (let ((c-echo-syntactic-information-p nil) ;keep quiet for speed
- (start (progn
- ;; try to be smarter about finding the range of
- ;; lines to indent. skip all following
- ;; whitespace. failing that, try to find any
- ;; opening brace on the current line
- (skip-chars-forward " \t\n")
- (if (memq (char-after) '(?\( ?\[ ?\{))
- (point)
- (let ((state (parse-partial-sexp (point)
- (c-point 'eol))))
- (and (nth 1 state)
- (goto-char (nth 1 state))
- (memq (char-after) '(?\( ?\[ ?\{))
- (point)))))))
- ;; find balanced expression end
- (setq end (and (c-safe (progn (forward-sexp 1) t))
- (point-marker)))
+ (let ((start (save-restriction
+ ;; Find the closest following open paren that
+ ;; ends on another line.
+ (narrow-to-region (point-min) (c-point 'eol))
+ (let (beg (end (point)))
+ (while (and (setq beg (c-down-list-forward end))
+ (setq end (c-up-list-forward beg))))
+ (and beg
+ (eq (char-syntax (char-before beg)) ?\()
+ (1- beg))))))
;; sanity check
- (and (not start)
- (not shutup-p)
- (error "Cannot find start of balanced expression to indent."))
- (and (not end)
- (not shutup-p)
- (error "Cannot find end of balanced expression to indent."))
- (c-progress-init start end 'c-indent-exp)
- (setq progress-p t)
- (goto-char start)
- (beginning-of-line)
- (while (< (point) end)
- (if (not (looking-at "[ \t]*$"))
- (c-indent-line))
- (c-progress-update)
- (forward-line 1)))
- ;; make sure marker is deleted
- (and end
- (set-marker end nil))
- (and progress-p
- (c-progress-fini 'c-indent-exp))
- (goto-char here))))
+ (if (not start)
+ (unless shutup-p
+ (error "Cannot find start of balanced expression to indent"))
+ (goto-char start)
+ (setq end (c-safe (scan-sexps (point) 1)))
+ (if (not end)
+ (unless shutup-p
+ (error "Cannot find end of balanced expression to indent"))
+ (forward-line)
+ (if (< (point) end)
+ (c-indent-region (point) end)))))
+ (goto-char here)
+ (set-marker here nil))))
(defun c-indent-defun ()
- "Re-indents the current top-level function def, struct or class declaration."
- (interactive)
- (let ((here (point-marker))
- (c-echo-syntactic-information-p nil)
- (brace (c-least-enclosing-brace (c-parse-state))))
- (if brace
- (goto-char brace)
- (beginning-of-defun))
- ;; if we're sitting at b-o-b, it might be because there was no
- ;; least enclosing brace and we were sitting on the defun's open
- ;; brace.
- (if (and (bobp) (not (eq (char-after) ?\{)))
- (goto-char here))
- ;; if defun-prompt-regexp is non-nil, b-o-d might not leave us at
- ;; the open brace. I consider this an Emacs bug.
- (and (boundp 'defun-prompt-regexp)
- defun-prompt-regexp
- (looking-at defun-prompt-regexp)
- (goto-char (match-end 0)))
- ;; catch all errors in c-indent-exp so we can 1. give more
- ;; meaningful error message, and 2. restore point
+ "Indent the current top-level declaration or macro syntactically.
+In the macro case this also has the effect of realigning any line
+continuation backslashes, unless `c-auto-align-backslashes' is nil."
+ (interactive "*")
+ (let ((here (point-marker)) decl-limits)
(unwind-protect
- (c-indent-exp)
+ (progn
+ (c-save-buffer-state nil
+ ;; We try to be line oriented, unless there are several
+ ;; declarations on the same line.
+ (if (looking-at c-syntactic-eol)
+ (c-backward-token-2 1 nil (c-point 'bol))
+ (c-forward-token-2 0 nil (c-point 'eol)))
+ (setq decl-limits (c-declaration-limits nil)))
+ (if decl-limits
+ (c-indent-region (car decl-limits)
+ (cdr decl-limits))))
(goto-char here)
(set-marker here nil))))
-(defun c-indent-region (start end)
- ;; Indent every line whose first char is between START and END inclusive.
+(defun c-indent-region (start end &optional quiet)
+ "Indent syntactically every line whose first char is between START
+and END inclusive. If the optional argument QUIET is non-nil then no
+syntactic errors are reported, even if `c-report-syntactic-errors' is
+non-nil."
(save-excursion
+ (goto-char end)
+ (skip-chars-backward " \t\n\r\f\v")
+ (setq end (point))
(goto-char start)
;; Advance to first nonblank line.
- (skip-chars-forward " \t\n")
(beginning-of-line)
- (let (endmark)
- (unwind-protect
- (let ((c-tab-always-indent t)
- ;; shut up any echo msgs on indiv lines
- (c-echo-syntactic-information-p nil)
- fence)
- (c-progress-init start end 'c-indent-region)
- (setq endmark (copy-marker end))
- (while (and (bolp)
- (not (eobp))
- (< (point) endmark))
- ;; update progress
- (c-progress-update)
- ;; Indent one line as with TAB.
- (let (nextline sexpend sexpbeg)
- ;; skip blank lines
- (skip-chars-forward " \t\n")
- (beginning-of-line)
- ;; indent the current line
- (c-indent-line)
- (setq fence (point))
- (if (save-excursion
- (beginning-of-line)
- (looking-at "[ \t]*#"))
- (forward-line 1)
- (save-excursion
- ;; Find beginning of following line.
- (setq nextline (c-point 'bonl))
- ;; 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)))
- (error (setq sexpend nil)
- (goto-char nextline)))
- (c-forward-syntactic-ws))
- (if sexpend
- (progn
- ;; make sure the sexp we found really starts on the
- ;; current line and extends past it
- (goto-char sexpend)
- (setq sexpend (point-marker))
- (c-safe (backward-sexp 1))
- (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))))
- ;; If that sexp ends within the region, indent it all at
- ;; once, fast.
- (condition-case nil
- (if (and sexpend
- (> sexpend nextline)
- (<= sexpend endmark))
- (progn
- (goto-char sexpbeg)
- (c-indent-exp 'shutup)
- (c-progress-update)
- (goto-char sexpend)))
- (error
- (goto-char sexpbeg)
- (c-indent-line)))
- ;; Move to following line and try again.
- (and sexpend
- (markerp sexpend)
- (set-marker sexpend nil))
- (forward-line 1)
- (setq fence (point))))))
- (set-marker endmark nil)
- (c-progress-fini 'c-indent-region)
- (c-echo-parsing-error)
- ))))
+ (skip-chars-forward " \t\n\r\f\v")
+ (setq start (point))
+ (beginning-of-line)
+ (setq c-parsing-error
+ (or (let ((endmark (copy-marker end))
+ (c-parsing-error nil)
+ ;; shut up any echo msgs on indiv lines
+ (c-echo-syntactic-information-p nil)
+ (in-macro (and c-auto-align-backslashes
+ (c-save-buffer-state ()
+ (save-excursion (c-beginning-of-macro)))
+ start))
+ (c-fix-backslashes nil)
+ syntax)
+ (unwind-protect
+ (progn
+ (c-progress-init start end 'c-indent-region)
+ (while (and (bolp)
+ (not (eobp))
+ (< (point) endmark))
+ ;; update progress
+ (c-progress-update)
+ ;; skip empty lines
+ (skip-chars-forward " \t\n")
+ (beginning-of-line)
+ ;; Get syntax and indent.
+ (c-save-buffer-state nil
+ (setq syntax (c-guess-basic-syntax)))
+ (if (and c-auto-align-backslashes
+ (assq 'cpp-macro syntax))
+ ;; Record macro start.
+ (setq in-macro (point)))
+ (if in-macro
+ (if (looking-at "\\s *\\\\$")
+ (forward-line)
+ (c-indent-line syntax t t)
+ (if (progn (end-of-line)
+ (not (eq (char-before) ?\\)))
+ (progn
+ ;; Fixup macro backslashes.
+ (forward-line)
+ (c-backslash-region in-macro (point) nil)
+ (setq in-macro nil))
+ (forward-line)))
+ (c-indent-line syntax t t)
+ (forward-line)))
+ (if in-macro
+ (c-backslash-region in-macro (c-point 'bopl) nil t)))
+ (set-marker endmark nil)
+ (c-progress-fini 'c-indent-region))
+ (c-echo-parsing-error quiet))
+ c-parsing-error))))
-(defun c-mark-function ()
- "Put mark at end of a C, C++, or Objective-C defun, point at beginning."
+(defun c-fn-region-is-active-p ()
+ ;; Function version of the macro for use in places that aren't
+ ;; compiled, e.g. in the menus.
+ (c-region-is-active-p))
+
+(defun c-indent-line-or-region ()
+ "When the region is active, indent it syntactically. Otherwise
+indent the current line syntactically."
+ ;; Emacs has a variable called mark-active, XEmacs uses region-active-p
(interactive)
- (let ((here (point))
- ;; there should be a c-point position for 'eod
- (eod (save-excursion (end-of-defun) (point)))
- (state (c-parse-state))
- brace)
- (while state
- (setq brace (car state))
- (if (consp brace)
- (goto-char (cdr brace))
- (goto-char brace))
- (setq state (cdr state)))
- (if (eq (char-after) ?{)
- (progn
- (forward-line -1)
- (while (not (or (bobp)
- (looking-at "[ \t]*$")))
- (forward-line -1)))
- (forward-line 1)
- (skip-chars-forward " \t\n"))
- (push-mark here)
- (push-mark eod nil t)))
+ (if (c-region-is-active-p)
+ (c-indent-region (region-beginning) (region-end))
+ (c-indent-line)))
\f
;; for progress reporting
(defvar c-progress-info nil)
(defun c-progress-init (start end context)
- ;; start the progress update messages. if this emacs doesn't have a
- ;; built-in timer, just be dumb about it
- (if (not (fboundp 'current-time))
- (message "indenting region... (this may take a while)")
- ;; if progress has already been initialized, do nothing. otherwise
- ;; initialize the counter with a vector of:
- ;; [start end lastsec context]
- (if c-progress-info
- ()
- (setq c-progress-info (vector start
+ (cond
+ ;; Be silent
+ ((not c-progress-interval))
+ ;; Start the progress update messages. If this Emacs doesn't have
+ ;; a built-in timer, just be dumb about it.
+ ((not (fboundp 'current-time))
+ (message "Indenting region... (this may take a while)"))
+ ;; If progress has already been initialized, do nothing. otherwise
+ ;; initialize the counter with a vector of:
+ ;; [start end lastsec context]
+ (c-progress-info)
+ (t (setq c-progress-info (vector start
(save-excursion
(goto-char end)
(point-marker))
(nth 1 (current-time))
context))
- (message "indenting region..."))))
+ (message "Indenting region..."))
+ ))
(defun c-progress-update ()
- ;; update progress
(if (not (and c-progress-info c-progress-interval))
nil
(let ((now (nth 1 (current-time)))
;; what's the right value?
(if (< c-progress-interval (- now lastsecs))
(progn
- (message "indenting region... (%d%% complete)"
+ (message "Indenting region... (%d%% complete)"
(/ (* 100 (- (point) start)) (- end start)))
(aset c-progress-info 2 now)))
)))
(defun c-progress-fini (context)
- ;; finished
- (if (or (eq context (aref c-progress-info 3))
- (eq context t))
- (progn
- (set-marker (aref c-progress-info 1) nil)
- (setq c-progress-info nil)
- (message "indenting region...done"))))
+ (if (not c-progress-interval)
+ nil
+ (if (or (eq context (aref c-progress-info 3))
+ (eq context t))
+ (progn
+ (set-marker (aref c-progress-info 1) nil)
+ (setq c-progress-info nil)
+ (message "Indenting region... done")))))
\f
;;; This page handles insertion and removal of backslashes for C macros.
-(defun c-backslash-region (from to delete-flag)
+(defun c-backslash-region (from to delete-flag &optional line-mode)
"Insert, align, or delete end-of-line backslashes on the lines in the region.
With no argument, inserts backslashes and aligns existing backslashes.
-With an argument, deletes the backslashes.
+With an argument, deletes the backslashes. The backslash alignment is
+done according to the settings in `c-backslash-column',
+`c-backslash-max-column' and `c-auto-align-backslashes'.
This function does not modify blank lines at the start of the region.
-If the region ends at the start of a line, it always deletes the
-backslash (if any) at the end of the previous line.
-
+If the region ends at the start of a line and the macro doesn't
+continue below it, the backslash (if any) at the end of the previous
+line is deleted.
+
You can put the region around an entire macro definition and use this
command to conveniently insert and align the necessary backslashes."
- (interactive "r\nP")
- (save-excursion
- (goto-char from)
- (let ((column c-backslash-column)
- (endmark (make-marker)))
- (move-marker endmark to)
- ;; Compute the smallest column number past the ends of all the lines.
- (if (not delete-flag)
- (while (< (point) to)
- (end-of-line)
- (if (eq (char-before) ?\\)
- (progn (forward-char -1)
- (skip-chars-backward " \t")))
- (setq column (max column (1+ (current-column))))
- (forward-line 1)))
- ;; Adjust upward to a tab column, if that doesn't push past the margin.
- (if (> (% column tab-width) 0)
- (let ((adjusted (* (/ (+ column tab-width -1) tab-width) tab-width)))
- (if (< adjusted (window-width))
- (setq column adjusted))))
- ;; Don't modify blank lines at start of region.
- (goto-char from)
- (while (and (< (point) endmark) (eolp))
- (forward-line 1))
- ;; Add or remove backslashes on all the lines.
- (while (< (point) endmark)
- (if (and (not delete-flag)
- ;; Un-backslashify the last line
- ;; if the region ends right at the start of the next line.
- (save-excursion
- (forward-line 1)
- (< (point) endmark)))
- (c-append-backslash column)
- (c-delete-backslash))
- (forward-line 1))
- (move-marker endmark nil)))
- (c-keep-region-active))
+ (interactive "*r\nP")
+ (let ((endmark (make-marker))
+ ;; Keep the backslash trimming functions from changing the
+ ;; whitespace around point, since in this case it's only the
+ ;; position of point that tells the indentation of the line.
+ (point-pos (if (save-excursion
+ (skip-chars-backward " \t")
+ (and (bolp) (looking-at "[ \t]*\\\\?$")))
+ (point-marker)
+ (point-min)))
+ column longest-line-col bs-col-after-end)
+ (save-excursion
+ (goto-char to)
+ (if (and (not line-mode) (bobp))
+ ;; Nothing to do if to is at bob, since we should back up
+ ;; and there's no line to back up to.
+ nil
+ (when (and (not line-mode) (bolp))
+ ;; Do not back up the to line if line-mode is set, to make
+ ;; e.g. c-newline-and-indent consistent regardless whether
+ ;; the (newline) call leaves point at bol or not.
+ (backward-char)
+ (setq to (point)))
+ (if delete-flag
+ (progn
+ (set-marker endmark (point))
+ (goto-char from)
+ (c-delete-backslashes-forward endmark point-pos))
+ ;; Set bs-col-after-end to the column of any backslash
+ ;; following the region, or nil if there is none.
+ (setq bs-col-after-end
+ (and (progn (end-of-line)
+ (eq (char-before) ?\\))
+ (= (forward-line 1) 0)
+ (progn (end-of-line)
+ (eq (char-before) ?\\))
+ (1- (current-column))))
+ (when line-mode
+ ;; Back up the to line if line-mode is set, since the line
+ ;; after the newly inserted line break should not be
+ ;; touched in c-newline-and-indent.
+ (setq to (max from (or (c-safe (c-point 'eopl)) from)))
+ (unless bs-col-after-end
+ ;; Set bs-col-after-end to non-nil in any case, since we
+ ;; do not want to delete the backslash at the last line.
+ (setq bs-col-after-end t)))
+ (if (and line-mode
+ (not c-auto-align-backslashes))
+ (goto-char from)
+ ;; Compute the smallest column number past the ends of all
+ ;; the lines.
+ (setq longest-line-col 0)
+ (goto-char to)
+ (if bs-col-after-end
+ ;; Include one more line in the max column
+ ;; calculation, since the to line will be backslashed
+ ;; too.
+ (forward-line 1))
+ (end-of-line)
+ (while (and (>= (point) from)
+ (progn
+ (if (eq (char-before) ?\\)
+ (forward-char -1))
+ (skip-chars-backward " \t")
+ (setq longest-line-col (max longest-line-col
+ (1+ (current-column))))
+ (beginning-of-line)
+ (not (bobp))))
+ (backward-char))
+ ;; Try to align with surrounding backslashes.
+ (goto-char from)
+ (beginning-of-line)
+ (if (and (not (bobp))
+ (progn (backward-char)
+ (eq (char-before) ?\\)))
+ (progn
+ (setq column (1- (current-column)))
+ (if (numberp bs-col-after-end)
+ ;; Both a preceding and a following backslash.
+ ;; Choose the greatest of them.
+ (setq column (max column bs-col-after-end)))
+ (goto-char from))
+ ;; No preceding backslash. Try to align with one
+ ;; following the region. Disregard the backslash at the
+ ;; to line since it's likely to be bogus (e.g. when
+ ;; called from c-newline-and-indent).
+ (if (numberp bs-col-after-end)
+ (setq column bs-col-after-end))
+ ;; Don't modify blank lines at start of region.
+ (goto-char from)
+ (while (and (< (point) to) (bolp) (eolp))
+ (forward-line 1)))
+ (if (and column (< column longest-line-col))
+ ;; Don't try to align with surrounding backslashes if
+ ;; any line is too long.
+ (setq column nil))
+ (unless column
+ ;; Impose minimum limit and tab width alignment only if
+ ;; we can't align with surrounding backslashes.
+ (if (> (% longest-line-col tab-width) 0)
+ (setq longest-line-col
+ (* (/ (+ longest-line-col tab-width -1)
+ tab-width)
+ tab-width)))
+ (setq column (max c-backslash-column
+ longest-line-col)))
+ ;; Always impose maximum limit.
+ (setq column (min column c-backslash-max-column)))
+ (if bs-col-after-end
+ ;; Add backslashes on all lines if the macro continues
+ ;; after the to line.
+ (progn
+ (set-marker endmark to)
+ (c-append-backslashes-forward endmark column point-pos))
+ ;; Add backslashes on all lines except the last, and
+ ;; remove any on the last line.
+ (if (save-excursion
+ (goto-char to)
+ (beginning-of-line)
+ (if (not (bobp))
+ (set-marker endmark (1- (point)))))
+ (progn
+ (c-append-backslashes-forward endmark column point-pos)
+ ;; The function above leaves point on the line
+ ;; following endmark.
+ (set-marker endmark (point)))
+ (set-marker endmark to))
+ (c-delete-backslashes-forward endmark point-pos)))))
+ (set-marker endmark nil)
+ (if (markerp point-pos)
+ (set-marker point-pos nil))))
+
+(defun c-append-backslashes-forward (to-mark column point-pos)
+ (let ((state (parse-partial-sexp (c-point 'bol) (point))))
+ (if column
+ (while
+ (and
+ (<= (point) to-mark)
+
+ (let ((start (point)) (inserted nil) end col)
+ (end-of-line)
+ (unless (eq (char-before) ?\\)
+ (insert ?\\)
+ (setq inserted t))
+ (setq state (parse-partial-sexp
+ start (point) nil nil state))
+ (backward-char)
+ (setq col (current-column))
+
+ ;; Avoid unnecessary changes of the buffer.
+ (cond ((and (not inserted) (nth 3 state))
+ ;; Don't realign backslashes in string literals
+ ;; since that would change them.
+ )
+
+ ((< col column)
+ (delete-region
+ (point)
+ (progn
+ (skip-chars-backward
+ " \t" (if (>= (point) point-pos) point-pos))
+ (point)))
+ (indent-to column))
+
+ ((and (= col column)
+ (memq (char-before) '(?\ ?\t))))
+
+ ((progn
+ (setq end (point))
+ (or (/= (skip-chars-backward
+ " \t" (if (>= (point) point-pos) point-pos))
+ -1)
+ (/= (char-after) ?\ )))
+ (delete-region (point) end)
+ (indent-to column 1)))
+
+ (zerop (forward-line 1)))
+ (bolp))) ; forward-line has funny behavior at eob.
+
+ ;; Make sure there are backslashes with at least one space in
+ ;; front of them.
+ (while
+ (and
+ (<= (point) to-mark)
+
+ (let ((start (point)))
+ (end-of-line)
+ (setq state (parse-partial-sexp
+ start (point) nil nil state))
+
+ (if (eq (char-before) ?\\)
+ (unless (nth 3 state)
+ (backward-char)
+ (unless (and (memq (char-before) '(?\ ?\t))
+ (/= (point) point-pos))
+ (insert ?\ )))
+
+ (if (and (memq (char-before) '(?\ ?\t))
+ (/= (point) point-pos))
+ (insert ?\\)
+ (insert ?\ ?\\)))
+
+ (zerop (forward-line 1)))
+ (bolp)))))) ; forward-line has funny behavior at eob.
+
+(defun c-delete-backslashes-forward (to-mark point-pos)
+ (while
+ (and (<= (point) to-mark)
+ (progn
+ (end-of-line)
+ (if (eq (char-before) ?\\)
+ (delete-region
+ (point)
+ (progn (backward-char)
+ (skip-chars-backward " \t" (if (>= (point) point-pos)
+ point-pos))
+ (point))))
+ (zerop (forward-line 1)))
+ (bolp)))) ; forward-line has funny behavior at eob.
-(defun c-append-backslash (column)
- (end-of-line)
- (if (eq (char-before) ?\\)
- (progn (forward-char -1)
- (delete-horizontal-space)
- (indent-to column))
- (indent-to column)
- (insert "\\")))
-
-(defun c-delete-backslash ()
- (end-of-line)
- (or (bolp)
- (progn
- (forward-char -1)
- (if (looking-at "\\\\")
- (delete-region (1+ (point))
- (progn (skip-chars-backward " \t") (point)))))))
\f
+;;; Line breaking and paragraph filling.
+
+(defvar c-auto-fill-prefix t)
+(defvar c-lit-limits nil)
+(defvar c-lit-type nil)
+
+;; 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.
+ ;;
+ ;; This function might do hidden buffer changes.
+
+ (let* ((here (point))
+ (prefix-regexp (concat "[ \t]*\\("
+ c-current-comment-prefix
+ "\\)[ \t]*"))
+ (comment-start-regexp (if (eq lit-type 'c++)
+ prefix-regexp
+ comment-start-skip))
+ prefix-line comment-prefix res comment-text-end)
+
+ (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 ((start (point)))
+ (unwind-protect
+ (progn
+ (insert-and-inherit "\n" fill-prefix)
+ (current-column))
+ (delete-region start (point)))))))
+
+ ((eq lit-type 'c++)
+ (save-excursion
+ ;; Set fallback for comment-prefix if none is found.
+ (setq comment-prefix "// "
+ comment-text-end (cdr lit-limits))
+
+ (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"))
+
+ (let (str col)
+ (if (eq (c-point 'boi) (car lit-limits))
+ ;; There is only whitespace before the comment
+ ;; starter; take the prefix straight from this line.
+ (setq str (buffer-substring-no-properties
+ (c-point 'bol) (point))
+ col (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 ((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)
+ (setq str (buffer-substring-no-properties
+ (c-point 'bol) (point))
+ col (current-column)))
+ (delete-region (car lit-limits) tmp))))
+
+ (setq res
+ (if (or (string-match "\\s \\'" str) (not (eolp)))
+ (cons str col)
+ ;; The prefix ends the line with no whitespace
+ ;; after it. Default to a single space.
+ (cons (concat str " ") (1+ col))))
+ )))))
+
+ (t
+ (setq comment-text-end
+ (save-excursion
+ (goto-char (- (cdr lit-limits) 2))
+ (if (looking-at "\\*/") (point) (cdr lit-limits))))
+
+ (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))
+
+ (cond ((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))))
+ ;; The comment is either one line or the next line contains
+ ;; just the comment ender. In this case 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 "")))
+
+ ((< here (point))
+ ;; The point was on the comment opener line, so we might want
+ ;; to treat this as a not yet closed comment.
+
+ (if (and (match-beginning 1)
+ (/= (match-beginning 1) (match-end 1)))
+ ;; Above `prefix-regexp' matched a nonempty prefix on the
+ ;; second line, so let's use it. Normally it should do
+ ;; to set `prefix-line' and let the code below pick up
+ ;; the whole prefix, but if there's no text after the
+ ;; match then it will probably fall back to no prefix at
+ ;; all if the comment isn't closed yet, so in that case
+ ;; it's better to force use of the prefix matched now.
+ (if (= (match-end 0) (c-point 'eol))
+ (setq comment-prefix (match-string 1))
+ (setq prefix-line (point)))
+
+ ;; There's no nonempty prefix on the line after the
+ ;; comment opener. If the line is empty, or if the
+ ;; text on it has less or equal indentation than the
+ ;; comment starter we assume it's an unclosed
+ ;; comment starter, i.e. that
+ ;; `c-block-comment-prefix' should be used.
+ ;; Otherwise we assume it's a closed comment where
+ ;; the prefix really is the empty string.
+ ;; E.g. this is an unclosed comment:
+ ;;
+ ;; /*
+ ;; foo
+ ;;
+ ;; But this is not:
+ ;;
+ ;; /*
+ ;; foo
+ ;; */
+ ;;
+ ;; (Looking for the presence of the comment closer
+ ;; rarely works since it's probably the closer of
+ ;; some comment further down when the comment
+ ;; really is unclosed.)
+ (if (<= (save-excursion (back-to-indentation)
+ (current-column))
+ (save-excursion (goto-char (car lit-limits))
+ (current-column)))
+ (setq comment-prefix (or c-block-comment-prefix ""))
+ (setq prefix-line (point)))))
+
+ (t
+ ;; Otherwise the line after the comment starter is good
+ ;; enough to find the prefix in.
+ (setq prefix-line (point))))
+
+ (when comment-prefix
+ ;; Haven't got the comment prefix on any real line that we
+ ;; can take it from, so we have to temporarily insert
+ ;; `comment-prefix' on a line and indent it to find the
+ ;; correct column and the correct mix of tabs and spaces.
+ (setq res
+ (let (tmp-pre tmp-post)
+ (unwind-protect
+ (progn
+
+ (goto-char (car lit-limits))
+ (if (looking-at comment-start-regexp)
+ (goto-char (min (match-end 0)
+ comment-text-end))
+ (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-and-inherit "x\n" comment-prefix "x")
+ (setq tmp-post (point-marker))
+
+ (indent-according-to-mode)
+
+ (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))))))))))
+
+ (or res ; Found a good prefix above.
+
+ (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) comment-text-end))
+ (unless (eq (match-end 0) (c-point 'eol))
+ ;; The match is fine if there's text after it.
+ (throw 'found (cons (buffer-substring-no-properties
+ (match-beginning 0) (match-end 0))
+ (progn (goto-char (match-end 0))
+ (current-column)))))
+ (unless fb-string
+ ;; This match is better than nothing, so let's
+ ;; remember it in case nothing better is found
+ ;; on another line.
+ (setq fb-string (buffer-substring-no-properties
+ (match-beginning 0) (match-end 0))
+ fb-endpos (match-end 0)))
+ t))))
+
+ (or (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)
+ (or (/= (match-end 1) (match-end 0))
+ ;; The whitespace is sucked up by the
+ ;; first [ \t]* glob if the prefix is empty.
+ (and (= (match-beginning 1) (match-end 1))
+ (/= (match-beginning 0) (match-end 0)))))
+ ;; If the current line doesn't have text but do
+ ;; have whitespace after the prefix, we'll use it.
+ (throw 'found (cons fb-string
+ (progn (goto-char fb-endpos)
+ (current-column)))))
+
+ (if (eq lit-type 'c++)
+ ;; For line comments we can search up to and
+ ;; including the first line.
+ (while (and (zerop (forward-line -1))
+ (>= (point) (car lit-limits)))
+ (funcall test-line))
+ ;; For block comments we must stop before the
+ ;; block starter.
+ (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))
+
+ (goto-char prefix-line)
+ nil)
+
+ (when fb-string
+ ;; A good line wasn't found, but at least we have a
+ ;; fallback that matches the comment prefix regexp.
+ (cond ((or (string-match "\\s \\'" fb-string)
+ (progn
+ (goto-char fb-endpos)
+ (not (eolp))))
+ ;; There are ws or text after the prefix, so
+ ;; let's use it.
+ (cons fb-string (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"))
+ (or (not (eolp))
+ (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 ((tmp (point)))
+ ;; Got to mess in the buffer once again to
+ ;; ensure the column gets correct. :P
+ (unwind-protect
+ (progn
+ (insert-and-inherit 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-mask-paragraph (fill-paragraph apply-outside-literal fun &rest args)
+ ;; Calls FUN with ARGS ar arguments while the current paragraph is
+ ;; masked to allow adaptive filling to work correctly. That
+ ;; includes narrowing the buffer and, if point is inside a comment,
+ ;; masking the comment starter and ender appropriately.
+ ;;
+ ;; FILL-PARAGRAPH is non-nil if called for whole paragraph filling.
+ ;; The position of point is then less significant when doing masking
+ ;; and narrowing.
+ ;;
+ ;; If APPLY-OUTSIDE-LITERAL is nil then the function will be called
+ ;; only if the point turns out to be inside a comment or a string.
+ ;;
+ ;; Note that this function does not do any hidden buffer changes.
+
+ (let (fill
+ ;; beg and end limit the region to narrow. end is a marker.
+ beg end
+ ;; tmp-pre and tmp-post mark 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
+ ;; If hang-ender-stuck isn't nil, the comment ender is
+ ;; hanging. In that case it's set to the number of spaces
+ ;; that should be between the text and the ender.
+ hang-ender-stuck
+ ;; auto-fill-spaces is the exact sequence of whitespace between a
+ ;; comment's last word and the comment ender, temporarily replaced
+ ;; with 'x's before calling FUN when FILL-PARAGRAPH is nil.
+ auto-fill-spaces
+ (here (point))
+ (c-lit-limits c-lit-limits)
+ (c-lit-type c-lit-type))
+
+ ;; 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)))
+
+ ;; Determine the limits and type of the containing literal (if any):
+ ;; C-LIT-LIMITS, C-LIT-TYPE; and the limits of the current paragraph:
+ ;; BEG and END.
+ (c-save-buffer-state ()
+ (save-restriction
+ ;; Widen to catch comment limits correctly.
+ (widen)
+ (unless c-lit-limits
+ (setq c-lit-limits (c-literal-limits nil fill-paragraph)))
+ (setq c-lit-limits (c-collect-line-comments c-lit-limits))
+ (unless c-lit-type
+ (setq c-lit-type (c-literal-type c-lit-limits))))
+
+ (save-excursion
+ (unless (c-safe (backward-char)
+ (forward-paragraph)
+ (>= (point) here))
+ (goto-char here)
+ (forward-paragraph))
+ (setq end (point-marker)))
+ (save-excursion
+ (unless (c-safe (forward-char)
+ (backward-paragraph)
+ (<= (point) here))
+ (goto-char here)
+ (backward-paragraph))
+ (setq beg (point))))
+
+ (unwind-protect
+ (progn
+ ;; For each of the possible types of text (string, C comment ...)
+ ;; determine BEG and END, the region we will narrow to. If we're in
+ ;; a literal, constrain BEG and END to the limits of this literal.
+ ;;
+ ;; For some of these text types, particularly a block comment, we
+ ;; may need to massage whitespace near literal delimiters, so that
+ ;; these don't get filled inappropriately.
+ (cond
+
+ ((eq c-lit-type 'c++) ; Line comment.
+ (save-excursion
+ ;; Limit to the comment or paragraph end, whichever
+ ;; comes first.
+ (set-marker end (min end (cdr c-lit-limits)))
+
+ (when (<= beg (car c-lit-limits))
+ ;; The region includes the comment starter, so we must
+ ;; check it.
+ (goto-char (car c-lit-limits))
+ (back-to-indentation)
+ (if (eq (point) (car c-lit-limits))
+ ;; Include the first line in the region.
+ (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))))
+
+ (setq apply-outside-literal t))
+
+ ((eq c-lit-type 'c) ; Block comment.
+ (when
+ (or (> end (cdr c-lit-limits))
+ (and (= end (cdr c-lit-limits))
+ (eq (char-before end) ?/)
+ (eq (char-before (1- end)) ?*)
+ ;; disallow "/*/"
+ (> (- (cdr c-lit-limits) (car c-lit-limits)) 3)))
+ ;; There is a comment ender, and the region includes it. If
+ ;; it's on its own line, it stays on its own line. If it's got
+ ;; company on the line, it keeps (at least one word of) it.
+ ;; "=====*/" counts as a comment ender here, but "===== */"
+ ;; doesn't and "foo*/" doesn't.
+ (unless
+ (save-excursion
+ (goto-char (cdr c-lit-limits))
+ (beginning-of-line)
+ (and (search-forward-regexp
+ (concat "\\=[ \t]*\\(" c-current-comment-prefix "\\)")
+ (- (cdr c-lit-limits) 2) t)
+ (not (search-forward-regexp
+ "\\(\\s \\|\\sw\\)"
+ (- (cdr c-lit-limits) 2) 'limit))
+ ;; The comment ender IS on its own line. Exclude
+ ;; this line from the filling.
+ (set-marker end (c-point 'bol))))
+
+ ;; The comment ender is hanging. Replace all space between it
+ ;; and the last word either by one or two 'x's (when
+ ;; FILL-PARAGRAPH is non-nil), or a row of x's the same width
+ ;; as the whitespace (when auto filling), and include it in
+ ;; the region. We'll change them back to whitespace
+ ;; afterwards. The effect of this is to glue the comment
+ ;; ender to the last word in the comment during filling.
+ (let* ((ender-start (save-excursion
+ (goto-char (cdr c-lit-limits))
+ (skip-syntax-backward "^w ")
+ (point)))
+ (ender-column (save-excursion
+ (goto-char ender-start)
+ (current-column)))
+ (point-rel (- ender-start here))
+ spaces)
+
+ (save-excursion
+ ;; Insert a CR after the "*/", adjust END
+ (goto-char (cdr c-lit-limits))
+ (setq tmp-post (point-marker))
+ (insert ?\n)
+ (set-marker end (point))
+
+ (forward-line -1) ; last line of the comment
+ (if (and (looking-at (concat "[ \t]*\\(\\("
+ c-current-comment-prefix
+ "\\)[ \t]*\\)"))
+ (eq ender-start (match-end 0)))
+ ;; The comment ender is prefixed by nothing but a
+ ;; comment line prefix. IS THIS POSSIBLE? (ACM,
+ ;; 2006/4/28). Remove it along with surrounding ws.
+ (setq spaces (- (match-end 1) (match-end 2)))
+ (goto-char ender-start))
+ (skip-chars-backward " \t\r\n") ; Surely this can be
+ ; " \t"? "*/" is NOT alone on the line (ACM, 2005/8/18)
+
+ ;; What's being tested here? 2006/4/20. FIXME!!!
+ (if (/= (point) ender-start)
+ (progn
+ (if (<= here (point))
+ ;; Don't adjust point below if it's
+ ;; before the string we replace.
+ (setq point-rel -1))
+ ;; Keep one or two spaces between the
+ ;; text and the ender, depending on how
+ ;; many there are now.
+ (unless spaces
+ (setq spaces (- ender-column (current-column))))
+ (setq auto-fill-spaces (c-delete-and-extract-region
+ (point) ender-start))
+ ;; paragraph filling condenses multiple spaces to
+ ;; single or double spaces. auto-fill doesn't.
+ (if fill-paragraph
+ (setq spaces
+ (max
+ (min spaces
+ (if sentence-end-double-space 2 1))
+ 1)))
+ ;; Insert the filler first to keep marks right.
+ (insert-char ?x spaces t)
+ (setq hang-ender-stuck spaces)
+ (setq point-rel
+ (and (>= point-rel 0)
+ (- (point) (min point-rel spaces)))))
+ (setq point-rel nil)))
+
+ (if point-rel
+ ;; Point was in the middle of the string we
+ ;; replaced above, so put it back in the same
+ ;; relative position, counting from the end.
+ (goto-char point-rel)))
+ ))
+
+ (when (<= beg (car c-lit-limits))
+ ;; The region includes the comment starter.
+ (save-excursion
+ (goto-char (car c-lit-limits))
+ (if (looking-at (concat "\\(" comment-start-skip "\\)$"))
+ ;; Begin with the next line.
+ (setq beg (c-point 'bonl))
+ ;; Fake the fill prefix in the first line.
+ (setq tmp-pre t))))
+
+ (setq apply-outside-literal t))
+
+ ((eq c-lit-type 'string) ; String.
+ (save-excursion
+ (when (>= end (cdr c-lit-limits))
+ (goto-char (1- (cdr c-lit-limits)))
+ (setq tmp-post (point-marker))
+ (insert ?\n)
+ (set-marker end (point)))
+ (when (<= beg (car c-lit-limits))
+ (goto-char (1+ (car c-lit-limits)))
+ (setq beg (if (looking-at "\\\\$")
+ ;; Leave the start line if it's
+ ;; nothing but an escaped newline.
+ (1+ (match-end 0))
+ (point)))))
+ (setq apply-outside-literal t))
+
+ ((eq c-lit-type 'pound) ; Macro
+ ;; Narrow to the macro limits if they are nearer than the
+ ;; paragraph limits. Don't know if this is necessary but
+ ;; do it for completeness sake (doing auto filling at all
+ ;; inside macros is bogus to begin with since the line
+ ;; continuation backslashes aren't handled).
+ (save-excursion
+ (c-save-buffer-state ()
+ (c-beginning-of-macro)
+ (beginning-of-line)
+ (if (> (point) beg)
+ (setq beg (point)))
+ (c-end-of-macro)
+ (forward-line)
+ (if (< (point) end)
+ (set-marker end (point))))))
+
+ (t ; Other code.
+ ;; Try to avoid comments and macros in the paragraph to
+ ;; avoid that the adaptive fill mode gets the prefix from
+ ;; them.
+ (c-save-buffer-state nil
+ (save-excursion
+ (goto-char beg)
+ (c-forward-syntactic-ws end)
+ (beginning-of-line)
+ (setq beg (point))
+ (goto-char end)
+ (c-backward-syntactic-ws beg)
+ (forward-line)
+ (set-marker end (point))))))
+
+ (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-save-buffer-state nil
+ (c-guess-fill-prefix c-lit-limits c-lit-type)))
+ (unless (string-match (concat "\\`[ \t]*\\("
+ c-current-comment-prefix
+ "\\)[ \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: Regexp from `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 c-lit-limits))
+ (if (looking-at (if (eq c-lit-type 'c++)
+ c-current-comment-prefix
+ comment-start-skip))
+ (goto-char (match-end 0))
+ (forward-char 2)
+ (skip-chars-forward " \t"))
+ (while (and (< (current-column) (cdr fill))
+ (not (eolp)))
+ (forward-char 1))
+ (let ((col (current-column)))
+ (setq beg (1+ (point))
+ tmp-pre (list (point)))
+ (unwind-protect
+ (progn
+ (insert-and-inherit "\n" (car fill))
+ (insert-char ?x (- col (current-column)) t))
+ (setcdr tmp-pre (point))))))
+
+ (when apply-outside-literal
+ ;; `apply-outside-literal' is always set to t here if
+ ;; we're inside a literal.
+
+ (let ((fill-prefix
+ (or fill-prefix
+ ;; 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.
+ (when (and (eq c-lit-type 'c++)
+ ;; Kludge the kludge: filladapt-mode doesn't
+ ;; have this problem, but it currently
+ ;; doesn't override fill-context-prefix
+ ;; (version 2.12).
+ (not (and (boundp 'filladapt-mode)
+ filladapt-mode))
+ (not (string-match
+ "\\`[ \t]*//"
+ (or (fill-context-prefix beg end)
+ ""))))
+ (c-save-buffer-state nil
+ (car (or fill (c-guess-fill-prefix
+ c-lit-limits c-lit-type)))))))
+
+ ;; Save the relative position of point if it's outside the
+ ;; region we're going to narrow. Want to restore it in that
+ ;; case, but otherwise it should be moved according to the
+ ;; called function.
+ (point-rel (cond ((< (point) beg) (- (point) beg))
+ ((> (point) end) (- (point) end)))))
+
+ ;; Preparations finally done! Now we can call the
+ ;; actual function.
+ (prog1
+ (save-restriction
+ (narrow-to-region beg end)
+ (apply fun args))
+ (if point-rel
+ ;; Restore point if it was outside the region.
+ (if (< point-rel 0)
+ (goto-char (+ beg point-rel))
+ (goto-char (+ end point-rel))))))))
+
+ (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
+ ;; Preserve point even if it's in the middle of the string
+ ;; we replace; save-excursion doesn't work in that case.
+ (setq here (point))
+ (goto-char tmp-post)
+ (skip-syntax-backward "^w ")
+ (forward-char (- hang-ender-stuck))
+ (if (or fill-paragraph (not auto-fill-spaces))
+ (insert-char ?\ hang-ender-stuck t)
+ (insert auto-fill-spaces)
+ (setq here (- here (- hang-ender-stuck (length auto-fill-spaces)))))
+ (delete-char hang-ender-stuck)
+ (goto-char here))
+ (set-marker tmp-post nil))
+
+ (set-marker end nil))))
+
(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
+is the very first thing in the string. The intended use for this rule
+is in situations like the following:
+
+char description[] = \"\\
+A very long description of something that you want to fill to make
+nicely formatted output.\"\;
+
+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* (comment-start-place
- (first-line
- ;; Check for obvious entry to comment.
- (save-excursion
- (beginning-of-line)
- (skip-chars-forward " \t\n")
- (and (looking-at comment-start-skip)
- (setq comment-start-place (point)))))
- (re1 "\\|[ \t]*/\\*[ \t]*$\\|[ \t]*\\*/[ \t]*$\\|[ \t/*]*$"))
- (if (and c-double-slash-is-comments-p
- (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 fill-prefix)
- (forward-line 1))
- (point)))
- (fill-paragraph arg)
- t)))
- ;; else C style comments
- (if (or first-line
- ;; t if we enter a comment between start of function and
- ;; this line.
- (eq (c-in-literal) 'c)
- ;; 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))))))
- ;; Inside a comment: fill one comment paragraph.
- (let ((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 "[ \t]*/\\*.*\\*/")
- (progn (re-search-forward comment-start-skip)
- (make-string (current-column) ?\ ))
- (if first-line (forward-line 1))
+ (interactive "*P")
+ (let ((fill-paragraph-function
+ ;; Avoid infinite recursion.
+ (if (not (eq fill-paragraph-function 'c-fill-paragraph))
+ fill-paragraph-function)))
+ (c-mask-paragraph t nil 'fill-paragraph arg))
+ ;; 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))
+ (c-mask-paragraph nil t 'do-auto-fill)))
+
+(defun c-indent-new-comment-line (&optional soft allow-auto-fill)
+ "Break line at point and indent, continuing comment or macro 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 single line 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 inside a macro, a line
+continuation backslash is inserted and aligned as appropriate, and the
+new line is indented according to `c-syntactic-indentation'.
+
+If a fill prefix is specified, it overrides all the above."
+ ;; allow-auto-fill is used from c-context-line-break to allow auto
+ ;; filling to break the line more than once. Since this function is
+ ;; used from auto-fill itself, that's normally disabled to avoid
+ ;; unnecessary recursion.
+ (interactive)
+ (let ((fill-prefix fill-prefix)
+ (do-line-break
+ (lambda ()
+ (delete-horizontal-space)
+ (if soft
+ (insert-and-inherit ?\n)
+ (newline (if allow-auto-fill nil 1)))))
+ ;; Already know the literal type and limits when called from
+ ;; c-context-line-break.
+ (c-lit-limits c-lit-limits)
+ (c-lit-type c-lit-type)
+ (c-macro-start c-macro-start))
- (let ((line-width (progn (end-of-line) (current-column))))
+ (c-save-buffer-state ()
+ (when (not (eq c-auto-fill-prefix t))
+ ;; 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 ((c-query-and-set-macro-start) '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 (and (null c-auto-fill-prefix)
+ (eq c-lit-type 'c)
+ (<= (c-point 'bol) (car c-lit-limits)))
+ ;; The adaptive fill function has generated a prefix, but
+ ;; we're on the first line in a block comment so it'll be
+ ;; wrong. Ignore it to guess a better one below.
+ (setq fill-prefix nil)
+ (when (and (eq c-lit-type 'c++)
+ (not (string-match (concat "\\`[ \t]*"
+ c-line-comment-starter)
+ (or fill-prefix ""))))
+ ;; Kludge: If the function that adapted the fill prefix
+ ;; doesn't produce the required comment starter for line
+ ;; comments, then we ignore it.
+ (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))
+ ((c-save-buffer-state ()
+ (unless c-lit-limits
+ (setq c-lit-limits (c-literal-limits)))
+ (unless c-lit-type
+ (setq c-lit-type (c-literal-type c-lit-limits)))
+ (memq c-lit-type '(c c++)))
+ ;; Some sort of comment.
+ (if (or comment-multi-line
+ (save-excursion
+ (goto-char (car c-lit-limits))
+ (end-of-line)
+ (< (point) (cdr c-lit-limits))))
+ ;; Inside a comment that should be continued.
+ (let ((fill (c-save-buffer-state nil
+ (c-guess-fill-prefix
+ (setq c-lit-limits
+ (c-collect-line-comments c-lit-limits))
+ c-lit-type)))
+ (pos (point))
+ (start-col (current-column))
+ (comment-text-end
+ (or (and (eq c-lit-type 'c)
+ (save-excursion
+ (goto-char (- (cdr c-lit-limits) 2))
+ (if (looking-at "\\*/") (point))))
+ (cdr c-lit-limits))))
+ ;; Skip forward past the fill prefix in case
+ ;; we're standing in it.
+ ;;
+ ;; FIXME: This doesn't work well in cases like
+ ;;
+ ;; /* Bla bla bla bla bla
+ ;; bla bla
+ ;;
+ ;; If point is on the 'B' then the line will be
+ ;; broken after "Bla b".
+ ;;
+ ;; If we have an empty comment, /* */, the next
+ ;; lot of code pushes point to the */. We fix
+ ;; this by never allowing point to end up to the
+ ;; right of where it started.
+ (while (and (< (current-column) (cdr fill))
+ (not (eolp)))
+ (forward-char 1))
+ (if (and (> (point) comment-text-end)
+ (> (c-point 'bol) (car c-lit-limits)))
+ (progn
+ ;; The skip takes us out of the (block)
+ ;; comment; insert the fill prefix at bol
+ ;; instead and keep the position.
+ (setq pos (copy-marker pos t))
(beginning-of-line)
- (prog1
- (buffer-substring
- (point)
+ (insert-and-inherit (car fill))
+ (if soft (insert-and-inherit ?\n) (newline 1))
+ (goto-char pos)
+ (set-marker pos nil))
+ ;; Don't break in the middle of a comment starter
+ ;; or ender.
+ (cond ((> (point) comment-text-end)
+ (goto-char comment-text-end))
+ ((< (point) (+ (car c-lit-limits) 2))
+ (goto-char (+ (car c-lit-limits) 2))))
+ (funcall do-line-break)
+ (insert-and-inherit (car fill))
+ (if (> (current-column) start-col)
+ (move-to-column start-col)))) ; can this hit the
+ ; middle of a TAB?
+ ;; 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))))
+ ((c-query-and-set-macro-start)
+ ;; In a macro.
+ (unless (looking-at "[ \t]*\\\\$")
+ ;; Do not clobber the alignment of the line continuation
+ ;; slash; c-backslash-region might look at it.
+ (delete-horizontal-space))
+ ;; Got an asymmetry here: In normal code this command
+ ;; doesn't indent the next line syntactically, and otoh a
+ ;; normal syntactically indenting newline doesn't continue
+ ;; the macro.
+ (c-newline-and-indent (if allow-auto-fill nil 1)))
+ (t
+ ;; Somewhere else in the code.
+ (let ((col (save-excursion
+ (beginning-of-line)
+ (while (and (looking-at "[ \t]*\\\\?$")
+ (= (forward-line -1) 0)))
+ (current-indentation))))
+ (funcall do-line-break)
+ (indent-to col))))))
- ;; How shall we decide where the end of the
- ;; fill-prefix is?
- (progn
- (beginning-of-line)
- (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 (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)
- (forward-line 1)
- (point)))
- (fill-paragraph arg)
- (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)))
- (forward-line -1)
- (fill-region-as-paragraph (point) (point-max))))))
- t)))))
+(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)
+ (defvar c-inside-line-break-advice nil)
+ (defadvice indent-new-comment-line (around c-line-break-advice
+ activate preactivate)
+ "Call `c-indent-new-comment-line' if in CC Mode."
+ (if (or c-inside-line-break-advice
+ (not c-buffer-is-cc-mode))
+ ad-do-it
+ (let ((c-inside-line-break-advice t))
+ (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 or macro, insert a newline and indent
+according to the syntactic context, unless `c-syntactic-indentation'
+is nil, in which case the new line is indented as the previous
+non-empty line instead.
+
+When point is inside the content of a preprocessor directive, a line
+continuation backslash is inserted before the line break and aligned
+appropriately. The end of the cpp directive doesn't count as inside
+it.
+
+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 it.
+
+When point is inside a string, only insert a backslash when it is also
+inside a preprocessor directive."
+
+ (interactive "*")
+ (let* (c-lit-limits c-lit-type
+ (c-macro-start c-macro-start))
+
+ (c-save-buffer-state ()
+ (setq c-lit-limits (c-literal-limits nil nil t)
+ c-lit-type (c-literal-type c-lit-limits))
+ (when (eq c-lit-type 'c++)
+ (setq c-lit-limits (c-collect-line-comments c-lit-limits)))
+ (c-query-and-set-macro-start))
+
+ (cond
+ ((or (eq c-lit-type 'c)
+ (and (eq c-lit-type 'c++) ; C++ comment, but not at the very end of it.
+ (< (save-excursion
+ (skip-chars-forward " \t")
+ (point))
+ (1- (cdr c-lit-limits))))
+ (and (numberp c-macro-start) ; Macro, but not at the very end of
+ ; it, not in a string, and not in the
+ ; cpp keyword.
+ (not (eq c-lit-type 'string))
+ (or (not (looking-at "\\s *$"))
+ (eq (char-before) ?\\))
+ (<= (save-excursion
+ (goto-char c-macro-start)
+ (if (looking-at c-opt-cpp-start)
+ (goto-char (match-end 0)))
+ (point))
+ (point))))
+ (let ((comment-multi-line t)
+ (fill-prefix nil))
+ (c-indent-new-comment-line nil t)))
+
+ ((eq c-lit-type 'string)
+ (if (and (numberp c-macro-start)
+ (not (eq (char-before) ?\\)))
+ (insert ?\\))
+ (newline))
+
+ (t (delete-horizontal-space)
+ (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
+ (backward-char)
+ (forward-line 0)
+ (while (and (looking-at "[ \t]*\\\\?$")
+ (= (forward-line -1) 0)))
+ (current-indentation))))
+ (indent-to col))
+ (indent-according-to-mode)))))
+
+(defun c-context-open-line ()
+ "Insert a line break suitable to the context and leave point before it.
+This is the `c-context-line-break' equivalent to `open-line', which is
+normally bound to C-o. See `c-context-line-break' for the details."
+ (interactive "*")
+ (let ((here (point)))
+ (unwind-protect
+ (progn
+ ;; Temporarily insert a non-whitespace char to keep any
+ ;; preceding whitespace intact.
+ (insert ?x)
+ (c-context-line-break))
+ (goto-char here)
+ (delete-char 1))))
\f
-(provide 'cc-cmds)
+(cc-provide 'cc-cmds)
+
+;;; arch-tag: bf0611dc-d1f4-449e-9e45-4ec7c6936677
;;; cc-cmds.el ends here