1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-15 10:30:25 -08:00

Fix c-declaration-limits to return correct limits in all cases.

This function is the guts of c-indent-defun and c-mark-function.

In particular, when c-defun-tactic is nil, return a correct value rather than
always nil, and when it's 'go-outward, go through an intricate algorithm to
determine the requisite narrowing before the "top-level" defuns go to work.

* lisp/progmodes/cc-cmds.el (c-narrow-to-most-enclosing-decl-block): Enhance
to take additional optional parameter LEVEL, saying how many enclosing levels
of decl-block to narrow to.
(c-declaration-limits): Introduce algorithm to determine narrowing.  Use
c-where-wrt-to-brace-block to determine whether to go back to BOD to determine
lower bound.
This commit is contained in:
Alan Mackenzie 2016-09-01 18:06:22 +00:00
parent 0c94b84708
commit dda2d6a311

View file

@ -1501,15 +1501,24 @@ No indentation or other \"electric\" behavior is performed."
(setq n (1- n))))
n)
(defun c-narrow-to-most-enclosing-decl-block (&optional inclusive)
(defun c-narrow-to-most-enclosing-decl-block (&optional inclusive level)
;; 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.
;; otherwise include the braces and the declaration which introduces them.
;; If the closing brace is missing, (point-max) is used instead. LEVEL, if
;; non-nil, says narrow to the LEVELth decl-block outward, default value
;; being 1.
(let ((paren-state (c-parse-state))
encl-decl)
(setq encl-decl (and paren-state (c-most-enclosing-decl-block paren-state)))
(setq level (or level 1))
(while (> level 0)
(setq encl-decl (c-most-enclosing-decl-block paren-state))
(if encl-decl
(progn
(while (> (c-pull-open-brace paren-state) encl-decl))
(setq level (1- level)))
(setq level 0)))
(if encl-decl
(save-excursion
(narrow-to-region
@ -1875,114 +1884,133 @@ 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)
(let ((start (point))
(paren-state (c-parse-state))
lim pos end-pos encl-decl-block where)
;; Narrow enclosing brace blocks out, as required by the values of
;; `c-defun-tactic', `near', and the position of point.
(when (eq c-defun-tactic 'go-outward)
(let ((bounds
(save-restriction
(if (and (not (save-excursion (c-beginning-of-macro)))
(save-restriction
(c-narrow-to-most-enclosing-decl-block)
(memq (c-where-wrt-brace-construct)
'(at-function-end outwith-function)))
(not near))
(c-narrow-to-most-enclosing-decl-block nil 2)
(c-narrow-to-most-enclosing-decl-block))
(cons (point-min) (point-max)))))
(narrow-to-region (car bounds) (cdr bounds))))
(setq paren-state (c-parse-state))
;; 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-start
(c-safe-position (point) paren-state)))
(if pos (goto-char pos)))
(or
;; Note: Some code duplication in `c-beginning-of-defun' and
;; `c-end-of-defun'.
(catch 'exit
(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-start
(c-safe-position (point) paren-state)))
(if pos (goto-char pos)))
(when (c-beginning-of-macro)
(throw 'exit
(cons (point)
(save-excursion
(c-end-of-macro)
(forward-line 1)
(point)))))
(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)
(setq pos (point))
(setq where (and (not (save-excursion (c-beginning-of-macro)))
(c-where-wrt-brace-construct)))
(when (and (not (eq where 'at-header))
(or (and near
(memq where
'(at-function-end outwith-function)))
(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))))))
(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))
(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))
;; 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
(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))))))))
(and (not near)
(goto-char (point-min))
(c-forward-decl-or-cast-1 -1 nil nil)
(eq (char-after) ?\{)
(cons (point-min) (point-max))))))))
;; 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))))))
(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.