Commit 020716e1 authored by Alan Mackenzie's avatar Alan Mackenzie

DTRT for c-beginning/end-of-defun in nested declaration scopes.

parent 86c60681
......@@ -882,6 +882,8 @@ lines.
@itemx @kbd{C-M-e} (@code{c-end-of-defun})
@findex c-beginning-of-defun
@findex c-end-of-defun
@vindex c-defun-tactic
@vindex defun-tactic (c-)
Move to the beginning or end of the current or next function. Other
constructs (such as a structs or classes) which have a brace block
......@@ -895,6 +897,15 @@ commands try to leave point at the beginning of a line near the actual
start or end of the function. This occasionally causes point not to
move at all.
By default, these commands will recognize functions contained within a
@dfn{declaration scope} such as a C++ @code{class} or @code{namespace}
construct, should the point start inside it. If @ccmode fails to find
function beginnings or ends inside the current declaration scope, it
will search the enclosing scopes. If you want @ccmode to recognize
functions only at the top level@footnote{this was @ccmode{}'s
behaviour prior to version 5.32.}, set @code{c-defun-tatic} to
@code{t}.
These functions are analogous to the Emacs built-in commands
@code{beginning-of-defun} and @code{end-of-defun}, except they
eliminate the constraint that the top-level opening brace of the defun
......
......@@ -1485,6 +1485,78 @@ No indentation or other \"electric\" behavior is performed."
(setq n (1- n))))
n)
(defun c-narrow-to-most-enclosing-decl-block (&optional inclusive)
;; If we are inside a decl-block (in the sense of c-looking-at-decl-block),
;; i.e. something like namespace{} or extern{}, narrow to the insides of
;; that block (NOT including the enclosing braces) if INCLUSIVE is nil,
;; otherwise include the braces. If the closing brace is missing,
;; (point-max) is used instead.
(let ((paren-state (c-parse-state))
encl-decl)
(setq encl-decl (and paren-state (c-most-enclosing-decl-block paren-state)))
(if encl-decl
(save-excursion
(narrow-to-region
(if inclusive
(progn (goto-char encl-decl)
(c-beginning-of-decl-1)
(point))
(1+ encl-decl))
(progn
(goto-char encl-decl)
(or (c-safe (forward-list)
(if inclusive
(point)
(1- (point))))
(point-max))))))))
(defun c-widen-to-enclosing-decl-scope (paren-state orig-point-min orig-point-max)
;; Narrow the buffer to the innermost declaration scope (e.g. a class, a
;; namespace or the "whole buffer") recorded in PAREN-STATE, the bounding
;; braces NOT being included in the resulting region. On no account may the
;; final region exceed that bounded by ORIG-POINT-MIN, ORIG-POINT-MAX.
;; PAREN-STATE is a list of buffer positions in the style of
;; (c-parse-state), one of which will be that of the desired opening brace,
;; if there is one.
;;
;; Return the position of the enclosing opening brace, or nil
(let (encl-decl) ; putative position of decl-scope's opening brace.
(save-restriction
(narrow-to-region orig-point-min orig-point-max)
(setq encl-decl (and paren-state
(c-most-enclosing-decl-block paren-state))))
(if encl-decl
(progn
(widen)
(narrow-to-region (1+ encl-decl)
(save-excursion
(goto-char encl-decl)
(or (c-safe (forward-list)
(1- (point)))
orig-point-max)))
encl-decl)
(narrow-to-region orig-point-min orig-point-max)
nil)))
(eval-and-compile
(defmacro c-while-widening-to-decl-block (condition)
;; Repeatedly evaluate CONDITION until it returns nil. After each
;; evaluation, if `c-defun-tactic' is set appropriately, widen to innards
;; of the next enclosing declaration block (e.g. namespace, class), or the
;; buffer's original restriction.
;;
;; This is a very special purpose macro, which assumes the existence of
;; several variables. It is for use only in c-beginning-of-defun and
;; c-end-of-defun.
`(while
(and ,condition
(eq c-defun-tactic 'go-outward)
lim)
(setq paren-state (c-whack-state-after lim paren-state))
(setq lim (c-widen-to-enclosing-decl-scope
paren-state orig-point-min orig-point-max))
(setq where 'in-block))))
(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
......@@ -1509,50 +1581,66 @@ defun."
(c-save-buffer-state
(beginning-of-defun-function end-of-defun-function
(start (point))
where paren-state pos)
(paren-state (copy-tree (c-parse-state))) ; This must not share list
; structure with other users of c-state-cache.
(orig-point-min (point-min)) (orig-point-max (point-max))
lim ; Position of { which has been widened to.
where 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))
(save-restriction
(if (eq c-defun-tactic 'go-outward)
(setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace.
paren-state orig-point-min orig-point-max)))
;; Go backward to this function's header.
(c-beginning-of-decl-1)
;; 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 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)))
(setq where (c-where-wrt-brace-construct))
(c-keep-region-active)
(= arg 0))))
(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)
(c-while-widening-to-decl-block
(< (setq arg (- (c-forward-to-nth-EOF-} (- arg) where))) 0)))
;; Move forward to the next opening brace....
(when (and (= arg 0)
(progn
(c-while-widening-to-decl-block
(not (c-syntactic-re-search-forward "{" nil 'eob)))
(eq (char-before) ?{)))
(backward-char)
;; ... and backward to the function header.
(c-beginning-of-decl-1)
t))
;; Move backward to the opening brace of a function, making successively
;; larger portions of the buffer visible as necessary.
(when (> arg 0)
(c-while-widening-to-decl-block
(> (setq arg (c-backward-to-nth-BOF-{ arg where)) 0)))
(when (eq arg 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
......@@ -1617,50 +1705,62 @@ the open-parenthesis that starts a defun; see `beginning-of-defun'."
(c-save-buffer-state
(beginning-of-defun-function end-of-defun-function
(start (point))
where paren-state pos)
(paren-state (copy-tree (c-parse-state))) ; This must not share list
; structure with other users of c-state-cache.
(orig-point-min (point-min)) (orig-point-max (point-max))
lim
where pos)
(save-restriction
(if (eq c-defun-tactic 'go-outward)
(setq lim (c-widen-to-enclosing-decl-scope ; e.g. class, namespace
paren-state orig-point-min orig-point-max)))
;; 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)))
;; 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))
(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))))
(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)
(c-while-widening-to-decl-block
(< (setq arg (- (c-backward-to-nth-BOF-{ (- arg) where))) 0)))
(if (= arg 0)
(c-while-widening-to-decl-block
(progn (c-syntactic-skip-backward "^}")
(not (eq (char-before) ?}))))))
;; Move forward to the } of a function
(if (> arg 0)
(c-while-widening-to-decl-block
(> (setq arg (c-forward-to-nth-EOF-} arg where)) 0))))
;; 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 ";"))
(c-keep-region-active)
(= arg 0)))
(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-defun-name ()
"Return the name of the current defun, or NIL if there isn't one.
......@@ -1746,6 +1846,11 @@ with a brace block."
;;
;; This function might do hidden buffer changes.
(save-excursion
(save-restriction
(when (eq c-defun-tactic 'go-outward)
(c-narrow-to-most-enclosing-decl-block t) ; e.g. class, namespace
(or (save-restriction
(c-narrow-to-most-enclosing-decl-block nil)
;; Note: Some code duplication in `c-beginning-of-defun' and
;; `c-end-of-defun'.
......@@ -1755,11 +1860,12 @@ with a brace block."
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.
;; 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.
......@@ -1843,8 +1949,12 @@ with a brace block."
(forward-line 1)
(point))
(t
pos)))))
))))
pos))))))))
(and (not near)
(goto-char (point-min))
(c-forward-decl-or-cast-1 -1 nil nil)
(eq (char-after) ?\{)
(cons (point-min) (point-max))))))))
(defun c-mark-function ()
"Put mark at end of the current top-level declaration or macro, point at beginning.
......
......@@ -705,7 +705,7 @@ comment at the start of cc-engine.el for more info."
;; The last position where a label is possible provided the
;; statement started there. It's nil as long as no invalid
;; label content has been found (according to
;; `c-nonlabel-token-key'. It's `start' if no valid label
;; `c-nonlabel-token-key'). It's `start' if no valid label
;; content was found in the label. Note that we might still
;; regard it a label if it starts with `c-label-kwds'.
label-good-pos
......@@ -1035,7 +1035,12 @@ comment at the start of cc-engine.el for more info."
;; (including a case label) or something like C++'s "public:"?
;; A case label might use an expression rather than a token.
(setq after-case:-pos (or tok start))
(if (looking-at c-nonlabel-token-key) ; e.g. "while" or "'a'"
(if (or (looking-at c-nonlabel-token-key) ; e.g. "while" or "'a'"
;; Catch C++'s inheritance construct "class foo : bar".
(save-excursion
(and
(c-safe (c-backward-sexp) t)
(looking-at c-nonlabel-token-2-key))))
(setq c-maybe-labelp nil)
(if after-labels-pos ; Have we already encountered a label?
(if (not last-label-pos)
......@@ -8037,6 +8042,29 @@ comment at the start of cc-engine.el for more info."
(back-to-indentation)
(vector (point) open-paren-pos))))))
(defmacro c-pull-open-brace (ps)
;; Pull the next open brace from PS (which has the form of paren-state),
;; skipping over any brace pairs. Returns NIL when PS is exhausted.
`(progn
(while (consp (car ,ps))
(setq ,ps (cdr ,ps)))
(prog1 (car ,ps)
(setq ,ps (cdr ,ps)))))
(defun c-most-enclosing-decl-block (paren-state)
;; Return the buffer position of the most enclosing decl-block brace (in the
;; sense of c-looking-at-decl-block) in the PAREN-STATE structure, or nil if
;; none was found.
(let* ((open-brace (c-pull-open-brace paren-state))
(next-open-brace (c-pull-open-brace paren-state)))
(while (and open-brace
(save-excursion
(goto-char open-brace)
(not (c-looking-at-decl-block next-open-brace nil))))
(setq open-brace next-open-brace
next-open-brace (c-pull-open-brace paren-state)))
open-brace))
(defun c-inside-bracelist-p (containing-sexp paren-state)
;; return the buffer position of the beginning of the brace list
;; statement if we're inside a brace list, otherwise return nil.
......
......@@ -340,6 +340,20 @@ better with the \"do { ... } while \(0)\" trick)."
:group 'c)
(put 'c-syntactic-indentation-in-macros 'safe-local-variable 'booleanp)
(defcustom c-defun-tactic 'go-outward
"*Whether functions are recognized inside, e.g., a class.
This is used by `c-beginning-of-defun' and like functions.
Its value is one of:
t -- Functions are recognized only at the top level.
go-outward -- Nested functions are also recognized. Should a function
command hit the beginning/end of a nested scope, it will
carry on at the less nested level."
:type '(radio
(const :tag "Functions are at the top-level" t)
(const :tag "Functions are also recognized inside declaration scopes" go-outward))
:group 'c)
(defcustom-c-stylevar c-comment-only-line-offset 0
"*Extra offset for line which contains only the start of a comment.
Can contain an integer or a cons cell of the form:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment