From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.ciao.gmane.io!not-for-mail From: Alan Mackenzie Newsgroups: gmane.emacs.devel Subject: Re: c-mode pragma and preproc Date: Mon, 20 Jan 2020 21:27:02 +0000 Message-ID: <20200120212702.GB4348@ACM> References: <20191219140738.q5zdmily5ubwnmg3.ref@Ergus> <20191219140738.q5zdmily5ubwnmg3@Ergus> <20200111114402.GA6005@ACM> <20200114140110.hrfqmrfkffwsknse@Ergus> <20200119172647.GB9172@ACM> <20200120021538.wxtxv3vbsorksqdg@Ergus> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: ciao.gmane.io; posting-host="ciao.gmane.io:159.69.161.202"; logging-data="128031"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Mutt/1.10.1 (2018-07-13) Cc: emacs-devel@gnu.org To: Ergus Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Mon Jan 20 22:27:41 2020 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1iteaC-000XFN-Ru for ged-emacs-devel@m.gmane-mx.org; Mon, 20 Jan 2020 22:27:40 +0100 Original-Received: from localhost ([::1]:44308 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iteaB-0007Fb-U6 for ged-emacs-devel@m.gmane-mx.org; Mon, 20 Jan 2020 16:27:39 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:47820) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iteZj-0006p3-0B for emacs-devel@gnu.org; Mon, 20 Jan 2020 16:27:12 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iteZh-0008RS-CZ for emacs-devel@gnu.org; Mon, 20 Jan 2020 16:27:10 -0500 Original-Received: from colin.muc.de ([193.149.48.1]:43474 helo=mail.muc.de) by eggs.gnu.org with smtp (Exim 4.71) (envelope-from ) id 1iteZf-0008QM-Ii for emacs-devel@gnu.org; Mon, 20 Jan 2020 16:27:09 -0500 Original-Received: (qmail 49569 invoked by uid 3782); 20 Jan 2020 21:27:05 -0000 Original-Received: from acm.muc.de (p4FE15C36.dip0.t-ipconnect.de [79.225.92.54]) by colin.muc.de (tmda-ofmipd) with ESMTP; Mon, 20 Jan 2020 22:27:02 +0100 Original-Received: (qmail 4750 invoked by uid 1000); 20 Jan 2020 21:27:02 -0000 Content-Disposition: inline In-Reply-To: <20200120021538.wxtxv3vbsorksqdg@Ergus> X-Delivery-Agent: TMDA/1.1.12 (Macallan) X-Primary-Address: acm@muc.de X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 193.149.48.1 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:244442 Archived-At: On Mon, Jan 20, 2020 at 03:15:38 +0100, Ergus via Emacs development discussions. wrote: > Hi Alan: > I just tried the patch and it seems to work as expected. Thanks! > I just have 3 observations/suggestions/questions: > 1) When I stay in column 0 like > |#pragma bla bla > and I press tab (to indent the line's) I get: > | #pragma bla bla > instead of: > |#pragma bla bla > as it happens with other lines (where | is the cursor position). Is this > intended? Whoops! That sort of thing is why I normally ask bug reporters to check the patch before I commit it. It's difficult to see when one is fixing a bug, but stands out like a sore thumb to somebody trying it out. What happened was I called c-indent-line from inside a save-excursion. c-indent-line placed point correctly, but emerging from the save-excursion put it back to column 0. To fix this, either substitute this new version of c-align-cpp-indent-to-body for the old one, or reapply the patch below from scratch (whichever you prefer): (defun c-align-cpp-indent-to-body () "Align a \"#pragma\" line under the previous line. This function is intented for use as a member of `c-special-indent-hook'." (when (assq 'cpp-macro c-syntactic-context) (when (save-excursion (save-match-data (back-to-indentation) (looking-at "#[ \t]*pragma\\([^[:alnum:]_$]\\|$\\)"))) (c-indent-line (delete '(cpp-macro) c-syntactic-context))))) . > 2) This new implementation breaks the "normal" way to configure the > indentation in c-mode because C-c C-o still returns cpp-macro (as > expected) while the indentation is not behaving as specified for > cpp-macros. So it seems to be confusing for the user and somehow a bit > inconsistent with the rest of cc-mode indentation. It does a bit, yes. This is an inevitable downside of using c-special-indent-hook which counterbalances to some extent the ability to add lightweight, yet effective, solutions to otherwise awkward indentation problems. The other standard c-special-indent-hook function is c-gnu-impose-minimum, which in gnu style ensures that source code within functions has a minimum indentation. That also suffers from the inability to use C-c C-o with it. > Why not just add an extra syntactic symbol for pragmas? Isn't it more > consistent that way? There's no "just" about a new syntactic symbol. It would be more work to back it, more likely to interact with other features, and more likely to increase the complexity of CC Mode more than needed. Consider that, in reality, #pragma _is_ a cpp-macro, not something new. > Otherwise the user will get false information from C-c C-o and looses > somehow a bit of flexibility. This is true. > Maybe we just need a variable that when not specified indent pragmas as > macros else indent pragmas as it specifies...? Are you thinking of c-cpp-indent-to-body-flag? ;-) > 3) Why the new function is called c-toggle-cpp-indent*? pragmas are part > of C too. Actually in HPC we usually use more C (and Fortran) than C++. cpp for "C PreProcessor". :-) I don't think there are any instances of cpp meaning C++ in CC Mode, but I agree it's an unfortunate collision of abbreviations. :-( I still haven't amended the CC Mode manual, but I will. > In any case the only real "issue" in my opinion is 1). But so far it > works pretty fine. OK, here's the replacement patch: diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el index 1071191775..56e3421ba2 100644 --- a/lisp/progmodes/cc-cmds.el +++ b/lisp/progmodes/cc-cmds.el @@ -48,6 +48,7 @@ (cc-bytecomp-defvar filladapt-mode) ; c-fill-paragraph contains a kludge ; which looks at this. (cc-bytecomp-defun electric-pair-post-self-insert-function) +(cc-bytecomp-defvar c-indent-to-body-directives) ;; Indentation / Display syntax functions (defvar c-fix-backslashes t) @@ -1441,6 +1442,79 @@ c-electric-continued-statement (indent-according-to-mode) (delete-char -2))))) +(defun c-align-cpp-indent-to-body () + "Align a \"#pragma\" line under the previous line. +This function is intented for use as a member of `c-special-indent-hook'." + (when (assq 'cpp-macro c-syntactic-context) + (when + (save-excursion + (save-match-data + (back-to-indentation) + (looking-at "#[ \t]*pragma\\([^[:alnum:]_$]\\|$\\)"))) + (c-indent-line (delete '(cpp-macro) c-syntactic-context))))) + +(defvar c-cpp-indent-to-body-flag nil) +;; Non-nil when CPP directives such as "#pragma" should be indented to under +;; the preceding statement. +(make-variable-buffer-local 'c-cpp-indent-to-body-flag) + +(defun c-electric-pragma () + "Reindent the current line if appropriate. + +This function is used to reindent a preprocessor line when the +symbol for the directive, typically \"pragma\", triggers this +function as a hook function of an abbreviation. + +The \"#\" of the preprocessor construct is aligned under the +first anchor point of the line's syntactic context. + +The line is reindented if the construct is not in a string or +comment, there is exactly one \"#\" contained in optional +whitespace before it on the current line, and `c-electric-flag' +and `c-syntactic-indentation' are both non-nil." + (save-excursion + (save-match-data + (when + (and + c-cpp-indent-to-body-flag + c-electric-flag + c-syntactic-indentation + last-abbrev-location + c-opt-cpp-symbol ; "#" or nil. + (progn (back-to-indentation) + (looking-at (concat c-opt-cpp-symbol "[ \t]*"))) + (>= (match-end 0) last-abbrev-location) + (not (c-literal-limits))) + (c-indent-line (delete '(cpp-macro) (c-guess-basic-syntax))))))) + +(defun c-add-indent-to-body-to-abbrev-table (d) + ;; Create an abbreviation table entry for the directive D, and add it to the + ;; current abbreviation table. Existing abbreviation (e.g. for "else") do + ;; not get overwritten. + (when (and c-buffer-is-cc-mode + local-abbrev-table + (not (abbrev-symbol d local-abbrev-table))) + (define-abbrev local-abbrev-table d d 'c-electric-pragma))) + +(defun c-toggle-cpp-indent-to-body (&optional arg) + "Toggle the cpp indent-to-body feature. +When enabled, when CPP directives which are words in +`c-indent-to-body-directives', the are indented such that the +initial \"#\" appears below the previous statement. + +Optional numeric ARG, if supplied, turns on the feature when positive, +turns it off when negative, and just toggles it when zero or +left out." + (interactive "P") + (setq c-cpp-indent-to-body-flag + (c-calculate-state arg c-cpp-indent-to-body-flag)) + (if c-cpp-indent-to-body-flag + (progn + (mapc 'c-add-indent-to-body-to-abbrev-table + c-cpp-indent-to-body-directives) + (add-hook 'c-special-indent-hook 'c-align-cpp-indent-to-body nil t)) + (remove-hook 'c-special-indent-hook 'c-align-cpp-indent-to-body t))) + (declare-function subword-forward "subword" (&optional arg)) diff --git a/lisp/progmodes/cc-vars.el b/lisp/progmodes/cc-vars.el index 861872486c..0391cdccfd 100644 --- a/lisp/progmodes/cc-vars.el +++ b/lisp/progmodes/cc-vars.el @@ -1649,6 +1649,15 @@ c-asymmetry-fontification-flag :type 'boolean :group 'c) +(defcustom c-cpp-indent-to-body-directives '("pragma") + "Preprocessor directives which will be indented as statements. + +A list of Preprocessor directives which when reindented, or newly +typed in, will cause the \"#\" introducing the directive to be +indented as a statement." + :type '(repeat string) + :group 'c) + ;; Initialize the next two to a regexp which never matches. (defvar c-noise-macro-with-parens-name-re regexp-unmatchable) (make-variable-buffer-local 'c-noise-macro-with-parens-name-re) > Very thanks, > Ergus. -- Alan Mackenzie (Nuremberg, Germany).