From 33219d385bbb271e2812fef615c81df1983e61d9 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Mon, 4 Jan 2016 22:29:33 +0000 Subject: [PATCH] Apply text properties for <, > in new after-change function (C++ Java Modes). These are category/syntax-table properties to give < and > paren syntax. Also apply certain `c-type' text properties to the insides of <..> constructs to ensure that identifiers contained by them get fontified. This patch fixes bug #681. * lisp/progmodes/cc-cmds.el (c-electric-lt-gt): Reformulate due to new after-change action. * lisp/progmodes/cc-engine.el (c-before-change-check-<>-operators): Expand change region to include s which might not be already marked as parens, rather than just when paren text properties are removed. (c-restore-<>-properties): New after-change function, which applies text properties marking < and > with paren syntax. * lisp/progmodes/cc-fonts.el (c-font-lock-declarations): Ensure `c-type' properties are applied to the interiors of <...> constructs, to ensure fontification of identifiers there. * lisp/progmodes/cc-langs.el (c-before-font-lock-functions): Add c-restore-<>-properties to this list for C++ and Java. * lisp/progmodes/cc-mode.el (c-common-init): When invoking c-before-font-lock-functions, exclude c-restore-<>-properties from the functions invoked. (c-before-change): Initialize c-new-BEG/END here (rather than c-after-change) to allow modification by before-change functions. (c-after-change): Amend c-new-END here, rather than initializing it and c-new-BEG. --- lisp/progmodes/cc-cmds.el | 38 ++++-------------- lisp/progmodes/cc-engine.el | 78 ++++++++++++++++++++++++------------- lisp/progmodes/cc-fonts.el | 25 ++++++++++++ lisp/progmodes/cc-langs.el | 9 ++++- lisp/progmodes/cc-mode.el | 17 +++++--- 5 files changed, 103 insertions(+), 64 deletions(-) diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el index a46f0488e76..6761de11700 100644 --- a/lisp/progmodes/cc-cmds.el +++ b/lisp/progmodes/cc-cmds.el @@ -1121,35 +1121,15 @@ numeric argument is supplied, or the point is inside a literal." (looking-at "<<")) (>= (match-end 0) final-pos))) - ;; It's a >. Either a C++ >> operator. ...... - (or (and (c-major-mode-is 'c++-mode) + ;; It's a >. Either a template/generic terminator ... + (or (c-get-char-property (1- final-pos) 'syntax-table) + ;; or a C++ >> operator. + (and (c-major-mode-is 'c++-mode) (progn (goto-char (1- final-pos)) (c-beginning-of-current-token) (looking-at ">>")) - (>= (match-end 0) final-pos)) - ;; ...., or search back for a < which isn't already marked as an - ;; opening template delimiter. - (save-restriction - (widen) - ;; Narrow to avoid `c-forward-<>-arglist' below searching past - ;; our position. - (narrow-to-region (point-min) final-pos) - (goto-char final-pos) - (while - (and - (progn - (c-syntactic-skip-backward "^<;}" nil t) - (eq (char-before) ?<)) - (progn - (backward-char) - (looking-at "\\s(")))) - (and (eq (char-after) ?<) - (not (looking-at "\\s(")) - (progn (c-backward-syntactic-ws) - (c-simple-skip-symbol-backward)) - (or (looking-at c-opt-<>-sexp-key) - (not (looking-at c-keywords-regexp))))))))) + (>= (match-end 0) final-pos)))))) (goto-char final-pos) (when found-delim @@ -1157,11 +1137,9 @@ numeric argument is supplied, or the point is inside a literal." (when (and (eq (char-before) ?>) (not executing-kbd-macro) blink-paren-function) - ;; Currently (2014-10-19), the syntax-table text properties on < and > - ;; are only applied in code called during Emacs redisplay. We thus - ;; explicitly cause a redisplay so that these properties have been - ;; applied when `blink-paren-function' gets called. - (sit-for 0) + ;; From now (2016-01-01), the syntax-table text properties on < and > + ;; are applied in an after-change function, not during redisplay. Hence + ;; we no longer need to call (sit-for 0) for blink paren to work. (funcall blink-paren-function))))) (defun c-electric-paren (arg) diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index 617c94aae08..2a35a647ff8 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -5577,8 +5577,9 @@ comment at the start of cc-engine.el for more info." (defun c-before-change-check-<>-operators (beg end) ;; Unmark certain pairs of "< .... >" which are currently marked as - ;; template/generic delimiters. (This marking is via syntax-table - ;; text properties). + ;; template/generic delimiters. (This marking is via syntax-table text + ;; properties), and expand the (c-new-BEG c-new-END) region to include all + ;; unmarked < and > operators within the certain bounds (see below). ;; ;; These pairs are those which are in the current "statement" (i.e., ;; the region between the {, }, or ; before BEG and the one after @@ -5597,38 +5598,40 @@ comment at the start of cc-engine.el for more info." (save-excursion (let ((beg-lit-limits (progn (goto-char beg) (c-literal-limits))) (end-lit-limits (progn (goto-char end) (c-literal-limits))) - new-beg new-end need-new-beg need-new-end) - ;; Locate the barrier before the changed region + new-beg new-end beg-limit end-limit) + ;; Locate the earliest < after the barrier before the changed region, + ;; which isn't already marked as a paren. (goto-char (if beg-lit-limits (car beg-lit-limits) beg)) - (c-syntactic-skip-backward "^;{}" (c-determine-limit 512)) - (setq new-beg (point)) + (setq beg-limit (c-determine-limit 512)) ;; Remove the syntax-table/category properties from each pertinent <...> - ;; pair. Firsly, the ones with the < before beg and > after beg. - (while - (c-search-forward-char-property 'syntax-table c-<-as-paren-syntax beg) - (if (c-clear-<-pair-props-if-match-after beg (1- (point))) - (setq need-new-beg t))) + ;; pair. Firstly, the ones with the < before beg and > after beg.... + (while (progn (c-syntactic-skip-backward "^;{}<" beg-limit) + (eq (char-before) ?<)) + (c-backward-token-2) + (when (eq (char-after) ?<) + (c-clear-<-pair-props-if-match-after beg))) + (c-forward-syntactic-ws) + (setq new-beg (point)) - ;; Locate the barrier after END. + ;; ...Then the ones with < before end and > after end. (goto-char (if end-lit-limits (cdr end-lit-limits) end)) - (c-syntactic-re-search-forward "[;{}]" (c-determine-+ve-limit 512) 'end) + (setq end-limit (c-determine-+ve-limit 512)) + (while (and (c-syntactic-re-search-forward "[;{}>]" end-limit 'end) + (eq (char-before) ?>)) + (c-end-of-current-token) + (when (eq (char-before) ?>) + (c-clear->-pair-props-if-match-before end (1- (point))))) + (c-backward-syntactic-ws) (setq new-end (point)) - ;; Remove syntax-table properties from the remaining pertinent <...> - ;; pairs, those with a > after end and < before end. - (while (c-search-backward-char-property 'syntax-table c->-as-paren-syntax end) - (if (c-clear->-pair-props-if-match-before end) - (setq need-new-end t))) - ;; Extend the fontification region, if needed. - (when need-new-beg - (goto-char new-beg) - (c-forward-syntactic-ws) - (and (< (point) c-new-BEG) (setq c-new-BEG (point)))) - - (when need-new-end - (and (> new-end c-new-END) (setq c-new-END new-end)))))) + (and new-beg + (< new-beg c-new-BEG) + (setq c-new-BEG new-beg)) + (and new-end + (> new-end c-new-END) + (setq c-new-END new-end))))) (defun c-after-change-check-<>-operators (beg end) ;; This is called from `after-change-functions' when @@ -5668,7 +5671,28 @@ comment at the start of cc-engine.el for more info." (c-clear-<>-pair-props) (forward-char))))))) - +(defun c-restore-<>-properties (_beg _end _old-len) + ;; This function is called as an after-change function. It restores the + ;; category/syntax-table properties on template/generic <..> pairs between + ;; c-new-BEG and c-new-END. It may do hidden buffer changes. + (c-save-buffer-state ((c-parse-and-markup-<>-arglists t) + c-restricted-<>-arglists lit-limits) + (goto-char c-new-BEG) + (if (setq lit-limits (c-literal-limits)) + (goto-char (cdr lit-limits))) + (while (and (< (point) c-new-END) + (c-syntactic-re-search-forward "<" c-new-END 'bound)) + (backward-char) + (save-excursion + (c-backward-token-2) + (setq c-restricted-<>-arglists + (and (not (looking-at c-opt-<>-sexp-key)) + (progn (c-backward-syntactic-ws) ; to < or , + (and (memq (char-before) '(?< ?,)) + (not (eq (c-get-char-property (point) 'c-type) + 'c-decl-arg-start))))))) + (or (c-forward-<>-arglist nil) + (forward-char))))) ;; Handling of small scale constructs like types and names. diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el index c2b2d72649f..f74e5cbf678 100644 --- a/lisp/progmodes/cc-fonts.el +++ b/lisp/progmodes/cc-fonts.el @@ -1205,6 +1205,9 @@ casts and declarations are fontified. Used on level 2 and higher." ;; Same as `max-type-decl-*', but used when we're before ;; `token-pos'. (max-type-decl-end-before-token 0) + ;; End of <..> construct which has had c-<>-arg-sep c-type + ;; properties set within it. + (max-<>-end 0) ;; Set according to the context to direct the heuristics for ;; recognizing C++ templates. c-restricted-<>-arglists @@ -1347,6 +1350,28 @@ casts and declarations are fontified. Used on level 2 and higher." (setq decl-or-cast (c-forward-decl-or-cast-1 match-pos context last-cast-end)) + ;; Ensure that c-<>-arg-sep c-type properties are in place on the + ;; commas separating the arguments inside template/generic <..>s. + (when (and (eq (char-before match-pos) ?<) + (> match-pos max-<>-end)) + (save-excursion + (goto-char match-pos) + (c-backward-token-2) + (if (and + (eq (char-after) ?<) + (let ((c-restricted-<>-arglists + (save-excursion + (c-backward-token-2) + (and + (not (looking-at c-opt-<>-sexp-key)) + (progn (c-backward-syntactic-ws) + (memq (char-before) '(?\( ?,))) + (not (eq (c-get-char-property (1- (point)) + 'c-type) + 'c-decl-arg-start)))))) + (c-forward-<>-arglist nil))) + (setq max-<>-end (point))))) + (cond ((eq decl-or-cast 'cast) ;; Save the position after the previous cast so we can feed diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 8ae75277925..d7972b4ef83 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -499,8 +499,13 @@ parameters \(point-min) and \(point-max).") ;; For documentation see the following c-lang-defvar of the same name. ;; The value here may be a list of functions or a single function. t 'c-change-expand-fl-region - (c c++ objc) '(c-neutralize-syntax-in-and-mark-CPP - c-change-expand-fl-region) + (c objc) '(c-neutralize-syntax-in-and-mark-CPP + c-change-expand-fl-region) + c++ '(c-neutralize-syntax-in-and-mark-CPP + c-restore-<>-properties + c-change-expand-fl-region) + java '(c-restore-<>-properties + c-change-expand-fl-region) awk 'c-awk-extend-and-syntax-tablify-region) (c-lang-defvar c-before-font-lock-functions (let ((fs (c-lang-const c-before-font-lock-functions))) diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 7f71700c650..e5be0b53b12 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -631,8 +631,11 @@ that requires a literal mode spec at compile time." (font-lock-mode 1))) ;; Buffer local variables defining the region to be fontified by a font lock -;; after-change function. They are set in c-after-change to -;; after-change-functions' BEG and END, and may be modified by functions in +;; after-change function. They are initialized in c-before-change to +;; before-change-functions' BEG and END. `c-new-END' is amended in +;; c-after-change with after-change-functions' BEG, END, and OLD-LEN. These +;; variables may be modified by any before/after-change function, in +;; particular by functions in `c-get-state-before-change-functions' and ;; `c-before-font-lock-functions'. (defvar c-new-BEG 0) (make-variable-buffer-local 'c-new-BEG) @@ -671,8 +674,9 @@ compatible with old code; callers should always specify it." (funcall fn (point-min) (point-max))) c-get-state-before-change-functions) (mapc (lambda (fn) - (funcall fn (point-min) (point-max) - (- (point-max) (point-min)))) + (if (not (eq fn 'c-restore-<>-properties)) + (funcall fn (point-min) (point-max) + (- (point-max) (point-min))))) c-before-font-lock-functions)))) (set (make-local-variable 'outline-regexp) "[^#\n\^M]") @@ -1032,6 +1036,8 @@ Note that the style variables are always made local to the buffer." c-just-done-before-change) ; guard against a spurious second ; invocation of before-change-functions. (setq c-just-done-before-change t) + ;; (c-new-BEG c-new-END) will be the region to fontify. + (setq c-new-BEG beg c-new-END end) (setq c-maybe-stale-found-type nil) (save-restriction (save-match-data @@ -1126,7 +1132,8 @@ Note that the style variables are always made local to the buffer." ;; (c-new-BEG c-new-END) will be the region to fontify. It may become ;; larger than (beg end). - (setq c-new-BEG beg c-new-END end) + ;; (setq c-new-BEG beg c-new-END end) + (setq c-new-END (- (+ c-new-END (- end beg)) old-len)) (unless (c-called-from-text-property-change-p) (setq c-just-done-before-change nil) -- 2.39.2