diff options
author | Alan Mackenzie <acm@muc.de> | 2011-10-28 14:34:39 +0000 |
---|---|---|
committer | Alan Mackenzie <acm@muc.de> | 2011-10-28 14:34:39 +0000 |
commit | 020716e178cdae443a3630c4307023cb3fc4c350 (patch) | |
tree | 47ed6164c0d4a262cce8d41cef7d88592fe69fa4 /lisp/progmodes | |
parent | 86c606818495d9411fd5d6b1477f9a097eb18020 (diff) | |
download | emacs-020716e178cdae443a3630c4307023cb3fc4c350.tar.gz |
DTRT for c-beginning/end-of-defun in nested declaration scopes.
Diffstat (limited to 'lisp/progmodes')
-rw-r--r-- | lisp/progmodes/cc-cmds.el | 284 | ||||
-rw-r--r-- | lisp/progmodes/cc-engine.el | 32 | ||||
-rw-r--r-- | lisp/progmodes/cc-vars.el | 14 |
3 files changed, 241 insertions, 89 deletions
diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el index 0f873e678c3..e59fdc16af7 100644 --- a/lisp/progmodes/cc-cmds.el +++ b/lisp/progmodes/cc-cmds.el @@ -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. diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index b2c548847c3..bc42e1032ab 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -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. diff --git a/lisp/progmodes/cc-vars.el b/lisp/progmodes/cc-vars.el index 58dc1737c5a..769bf63f63c 100644 --- a/lisp/progmodes/cc-vars.el +++ b/lisp/progmodes/cc-vars.el @@ -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: |