From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Alan Mackenzie Newsgroups: gmane.emacs.bugs Subject: bug#36650: 27.0.50; CC Mode: Support C++ attributes Date: Sat, 20 Jul 2019 18:02:30 +0000 Message-ID: <20190720180230.GB27030@ACM> References: <20190715142718.71903.qmail@mail.muc.de> <87muhf9vjs.fsf@telefonica.net> Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="227859"; mail-complaints-to="usenet@blaine.gmane.org" User-Agent: Mutt/1.10.1 (2018-07-13) Cc: 36650@debbugs.gnu.org To: =?UTF-8?Q?=C3=93scar?= Fuentes Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Sat Jul 20 20:03:14 2019 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1hothR-000x7u-DL for geb-bug-gnu-emacs@m.gmane.org; Sat, 20 Jul 2019 20:03:13 +0200 Original-Received: from localhost ([::1]:52414 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hothP-0000Dy-Qx for geb-bug-gnu-emacs@m.gmane.org; Sat, 20 Jul 2019 14:03:11 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:47310) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hothL-0000Ci-ME for bug-gnu-emacs@gnu.org; Sat, 20 Jul 2019 14:03:09 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hothJ-0005YG-SB for bug-gnu-emacs@gnu.org; Sat, 20 Jul 2019 14:03:07 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:49072) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hothG-0005VZ-Ul; Sat, 20 Jul 2019 14:03:03 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1hothG-0000Mo-EV; Sat, 20 Jul 2019 14:03:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Alan Mackenzie Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org, bug-cc-mode@gnu.org Resent-Date: Sat, 20 Jul 2019 18:03:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 36650 X-GNU-PR-Package: emacs,cc-mode Original-Received: via spool by 36650-submit@debbugs.gnu.org id=B36650.15636457561379 (code B ref 36650); Sat, 20 Jul 2019 18:03:01 +0000 Original-Received: (at 36650) by debbugs.gnu.org; 20 Jul 2019 18:02:36 +0000 Original-Received: from localhost ([127.0.0.1]:57893 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hotgp-0000M9-Mk for submit@debbugs.gnu.org; Sat, 20 Jul 2019 14:02:36 -0400 Original-Received: from colin.muc.de ([193.149.48.1]:63633 helo=mail.muc.de) by debbugs.gnu.org with smtp (Exim 4.84_2) (envelope-from ) id 1hotgn-0000M0-0d for 36650@debbugs.gnu.org; Sat, 20 Jul 2019 14:02:34 -0400 Original-Received: (qmail 21688 invoked by uid 3782); 20 Jul 2019 17:10:07 -0000 Original-Received: from acm.muc.de (p2E5D5FE3.dip0.t-ipconnect.de [46.93.95.227]) by colin.muc.de (tmda-ofmipd) with ESMTP; Sat, 20 Jul 2019 19:10:05 +0200 Original-Received: (qmail 29830 invoked by uid 1000); 20 Jul 2019 18:02:30 -0000 Content-Disposition: inline In-Reply-To: <87muhf9vjs.fsf@telefonica.net> X-Delivery-Agent: TMDA/1.1.12 (Macallan) X-Primary-Address: acm@muc.de X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.51.188.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:163485 Archived-At: Hello, Óscar. On Mon, Jul 15, 2019 at 17:17:27 +0200, Óscar Fuentes wrote: > Alan Mackenzie writes: > > Yes. I'll have a look at this. > Thanks. > >> In general, considering them part of the following token for indentation > >> purposes and fontifying with some existing or new face should be enough. > > I will probably end up treating attributes as syntactic whitespace. > > They have no syntactic connection with the code they are embedded in, > > any more than macros do. The patch below (which should apply cleanly to the master branch) is a first attempt at handling C++ attributes. > I don't know how syntactic whitespace works on CC Mode, so just in case > I'll mention that this code > int foo([[maybe_unused]] int a, > int b); > should not be formatted as > int foo([[maybe_unused]] int a, > int b); Understood. Happily, the code appears to do the right thing anyway, without needing tedious fixing. :-) Could you please try out this patch, and let me know how well it works. Thanks! diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index cb88fc3e58..7963ab0d43 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -1827,45 +1827,122 @@ c-remove-is-and-in-sws (def-edebug-spec c-remove-is-and-in-sws t) ;; The type of literal position `end' is in a `before-change-functions' -;; function - one of `c', `c++', `pound', or nil (but NOT `string'). +;; function - one of `c', `c++', `pound', `attribute', or nil (but NOT +;; `string'). (defvar c-sws-lit-type nil) -;; A cons (START . STOP) of the bounds of the comment or CPP construct +;; A cons (START . STOP) of the bounds of the comment or CPP construct, etc., ;; enclosing END, if any, else nil. (defvar c-sws-lit-limits nil) +(defmacro c-looking-at-c++-attribute () + ;; If we're in C++ Mode, and point is at the [[ introducing an attribute, + ;; return the position of the end of the attribute, otherwise return nil. + ;; The match data are NOT preserved over this macro. + `(and + (c-major-mode-is 'c++-mode) + (looking-at "\\[\\[") + (save-excursion + (and + (c-go-list-forward) + (eq (char-before) ?\]) + (eq (char-before (1- (point))) ?\]) + (point))))) + +;; (defmacro c-enclosing-c++-attribute () +(defun c-enclosing-c++-attribute () + ;; If we're in C++ Mode, and point is within a correctly balanced [[ ... ]] + ;; attribute structure, return a cons of its starting and ending positions. + ;; Otherwise, return nil. We use the c-{in,is}-sws-face text properties for + ;; this determination, this macro being intended only for use in the *-sws-* + ;; functions and macros. The match data are NOT preserved over this macro. + (let (attr-end pos-is-sws) + (and + (c-major-mode-is 'c++-mode) + (> (point) (point-min)) + (setq pos-is-sws + (if (get-text-property (1- (point)) 'c-is-sws) + (1- (point)) + (1- (previous-single-property-change + (point) 'c-is-sws nil (point-min))))) + (save-excursion + (goto-char pos-is-sws) + (setq attr-end (c-looking-at-c++-attribute))) + (> attr-end (point)) + (cons pos-is-sws attr-end)))) + +(defun c-slow-enclosing-c++-attribute () + ;; Like `c-enclosing-c++-attribute', but does not depend on the c-i[ns]-sws + ;; properties being set. + (and + (c-major-mode-is 'c++-mode) + (save-excursion + (let ((paren-state (c-parse-state)) + cand) + (while + (progn + (setq cand + (catch 'found-cand + (while (cdr paren-state) + (when (and (numberp (car paren-state)) + (numberp (cadr paren-state)) + (eq (car paren-state) + (1+ (cadr paren-state))) + (eq (char-after (car paren-state)) ?\[) + (eq (char-after (cadr paren-state)) ?\[)) + (throw 'found-cand (cadr paren-state))) + (setq paren-state (cdr paren-state))))) + (and cand + (not + (and (c-go-list-forward cand) + (eq (char-before) ?\]) + (eq (char-before (1- (point))) ?\]))))) + (setq paren-state (cdr paren-state))) + (and cand (cons cand (point))))))) + (defun c-invalidate-sws-region-before (beg end) ;; Called from c-before-change. BEG and END are the bounds of the change ;; region, the standard parameters given to all before-change-functions. ;; - ;; Note whether END is inside a comment, CPP construct, or noise macro, and - ;; if so note its bounds in `c-sws-lit-limits' and type in `c-sws-lit-type'. + ;; Note whether END is inside a comment, CPP construct, C++ attribute, or + ;; noise macro, and if so note its bounds in `c-sws-lit-limits' and type in + ;; `c-sws-lit-type'. (setq c-sws-lit-type nil c-sws-lit-limits nil) - (save-excursion - (goto-char end) - (let* ((limits (c-literal-limits)) - (lit-type (c-literal-type limits))) - (cond - ((memq lit-type '(c c++)) - (setq c-sws-lit-type lit-type - c-sws-lit-limits limits)) - ((c-beginning-of-macro) - (setq c-sws-lit-type 'pound - c-sws-lit-limits (cons (point) - (progn (c-end-of-macro) (point))))) - ((progn (skip-syntax-backward "w_") - (looking-at c-noise-macro-name-re)) - (setq c-sws-lit-type 'noise - c-sws-lit-limits (cons (match-beginning 1) (match-end 1)))) - (t)))) - (save-excursion - (goto-char beg) - (skip-syntax-backward "w_") - (when (looking-at c-noise-macro-name-re) - (setq c-sws-lit-type 'noise) - (if (consp c-sws-lit-limits) - (setcar c-sws-lit-limits (match-beginning 1)) - (setq c-sws-lit-limits (cons (match-beginning 1) (match-end 1))))))) + (save-match-data + (save-excursion + (goto-char end) + (let* ((limits (c-literal-limits)) + (lit-type (c-literal-type limits))) + (cond + ((memq lit-type '(c c++)) + (setq c-sws-lit-type lit-type + c-sws-lit-limits limits)) + ((c-beginning-of-macro) + (setq c-sws-lit-type 'pound + c-sws-lit-limits (cons (point) + (progn (c-end-of-macro) (point))))) + ((eq lit-type 'string)) + ((setq c-sws-lit-limits (c-enclosing-c++-attribute)) + (setq c-sws-lit-type 'attribute)) + ((progn (skip-syntax-backward "w_") + (looking-at c-noise-macro-name-re)) + (setq c-sws-lit-type 'noise + c-sws-lit-limits (cons (match-beginning 1) (match-end 1)))) + (t)))) + (save-excursion + (goto-char beg) + (let ((attr-limits (c-enclosing-c++-attribute))) + (if attr-limits + (if (consp c-sws-lit-limits) + (setcar c-sws-lit-limits (car attr-limits)) + (setq c-sws-lit-limits attr-limits)) + (skip-syntax-backward "w_") + (when (looking-at c-noise-macro-name-re) + (setq c-sws-lit-type 'noise) + (if (consp c-sws-lit-limits) + (setcar c-sws-lit-limits (match-beginning 1)) + (setq c-sws-lit-limits (cons (match-beginning 1) + (match-end 1)))))))))) (defun c-invalidate-sws-region-after-del (beg end _old-len) ;; Text has been deleted, OLD-LEN characters of it starting from position @@ -1940,7 +2017,7 @@ c-invalidate-sws-region-after (when (and (eolp) (not (eobp))) (setq end (1+ (point))))) - (when (eq c-sws-lit-type 'noise) + (when (memq c-sws-lit-type '(noise attribute)) (setq beg (car c-sws-lit-limits) end (cdr c-sws-lit-limits))) ; This last setting may be redundant. @@ -1990,6 +2067,8 @@ c-forward-sws (when (or (looking-at c-syntactic-ws-start) (and c-opt-cpp-prefix (looking-at c-noise-macro-name-re)) + (and (c-major-mode-is 'c++-mode) + (looking-at "\\[\\[")) (looking-at c-doc-line-join-re)) (setq rung-end-pos (min (1+ (point)) (point-max))) @@ -2126,6 +2205,16 @@ c-forward-sws (goto-char (match-end 1)) (not (eobp))) + ((and (c-major-mode-is 'c++-mode) + (looking-at "\\[\\[") + (save-excursion + (and (c-go-list-forward) + (eq (char-before) ?\]) + (eq (char-before (1- (point))) ?\]) + (setq next-rung-pos (point)))) + (goto-char next-rung-pos)) + (not (eobp))) + ((looking-at c-doc-line-join-re) ;; Skip over a line join in (e.g.) Pike autodoc. (goto-char (match-end 0)) @@ -2240,6 +2329,13 @@ c-backward-sws (memq (char-before) c-doc-line-join-end-ch) ; For speed. (re-search-backward doc-line-join-here (c-point 'bopl) t)) + (and + (c-major-mode-is 'c++-mode) + (eq (char-before) ?\]) + (eq (char-before (1- (point))) ?\]) + (save-excursion + (and (c-go-list-backward) + (looking-at "\\(\\)\\[\\[")))) (progn (backward-char) (or (looking-at c-syntactic-ws-end) @@ -2250,7 +2346,7 @@ c-backward-sws ;; Try to find a rung position in the simple ws preceding point, so that ;; we can get a cache hit even if the last bit of the simple ws has ;; changed recently. - (setq simple-ws-beg (or (match-end 1) ; Noise macro + (setq simple-ws-beg (or (match-end 1) ; Noise macro, etc. (match-end 0))) ; c-syntactic-ws-end (skip-chars-backward " \t\n\r\f\v") (if (setq rung-is-marked (text-property-any @@ -2388,6 +2484,16 @@ c-backward-sws (goto-char next-rung-pos) t) + ((and (c-major-mode-is 'c++-mode) + (eq (char-before) ?\]) + (eq (char-before (1- (point))) ?\]) + (save-excursion + (and (c-go-list-backward) + (setq next-rung-pos (point)) + (looking-at "\\[\\[")))) + (goto-char next-rung-pos) + t) + ((and (memq (char-before) c-doc-line-join-end-ch) ; For speed. (re-search-backward doc-line-join-here (c-point 'bopl) t))))) diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 5ae7e0f09d..a5e158933b 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -2158,9 +2158,11 @@ c-fl-decl-end ;; count as being in a declarator (on pragmatic grounds). (goto-char pos) (let ((lit-start (c-literal-start)) - pos1) + enclosing-attribute pos1) (unless lit-start (c-backward-syntactic-ws) + (when (setq enclosing-attribute (c-slow-enclosing-c++-attribute)) + (goto-char (car enclosing-attribute))) ; Only happens in C++ Mode. (when (setq pos1 (c-on-identifier)) (goto-char pos1) (let ((lim (save-excursion -- Alan Mackenzie (Nuremberg, Germany).