unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Alan Mackenzie <acm@muc.de>
To: Ergus <spacibba@aol.com>
Cc: emacs-devel@gnu.org
Subject: Re: c-mode pragma and preproc
Date: Tue, 11 Feb 2020 20:00:18 +0000	[thread overview]
Message-ID: <20200211200018.GA5902@ACM> (raw)
In-Reply-To: <20200120212702.GB4348@ACM>

Hello again, Ergus.

Just a quick ping!

I've now written the requisite documentation for the CC Mode manual.
Are you otherwise happy (or, at least, happy enough) with the state of
the code for me to commit it?

-- 
Alan Mackenzie (Nuremberg, Germany).


On Mon, Jan 20, 2020 at 21:27:02 +0000, Alan Mackenzie wrote:
> 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)
 \f
>  ;; 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)))
> +
 \f
 
>  (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).



  reply	other threads:[~2020-02-11 20:00 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20191219140738.q5zdmily5ubwnmg3.ref@Ergus>
2019-12-19 14:07 ` c-mode pragma and preproc Ergus
2020-01-11 11:44   ` Alan Mackenzie
2020-01-14 14:01     ` Ergus
2020-01-19 17:26       ` Alan Mackenzie
2020-01-20  2:15         ` Ergus via Emacs development discussions.
2020-01-20 21:27           ` Alan Mackenzie
2020-02-11 20:00             ` Alan Mackenzie [this message]
2020-02-12 10:19               ` Ergus via Emacs development discussions.

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200211200018.GA5902@ACM \
    --to=acm@muc.de \
    --cc=emacs-devel@gnu.org \
    --cc=spacibba@aol.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).