[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: c-mode pragma and preproc

From: Ergus
Subject: Re: c-mode pragma and preproc
Date: Mon, 20 Jan 2020 03:15:38 +0100

Hi Alan:

I just tried the patch and it seems to work as expected.

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

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. Why not just add an
extra syntactic symbol for pragmas? Isn't it more consistent that way?
Otherwise the user will get false information from C-c C-o and looses
somehow a bit of flexibility.
Maybe we just need a variable that when not specified indent pragmas as
macros else indent pragmas as it specifies...?

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++.

In any case the only real "issue" in my opinion is 1). But so far it
works pretty fine.

Very thanks,

On Sun, Jan 19, 2020 at 05:26:47PM +0000, Alan Mackenzie wrote:
Hello again, Ergus.

On Tue, Jan 14, 2020 at 15:01:10 +0100, Ergus wrote:
On Sat, Jan 11, 2020 at 11:44:02AM +0000, Alan Mackenzie wrote:
Hi Alan:
>On Thu, Dec 19, 2019 at 15:07:38 +0100, Ergus wrote:
>> Hi Alan:

>> Recently I have been noticing that many "modern" programming models
>> (Open-MP, OmpSs, OpenACC, programming for Intel Xeon Phi) use
>> extensively the #pragma sentence.

>> But in general, while the pre-processor sentences are usually in column
>> zero ([0]), the #pragma, on the other hand, are preferred to be aligned
>> with text (0). They are more readable that way.

OK, I have an experimental implementation of M-x
c-toggle-cpp-indent-to-body (see patch below).  This can be customised by
changing c-cpp-indent-to-body-directives, the list of directives which
should be indented as statements.  It's default value is ("pragma").
(Yes, I know you said that it would only be needed for "pragma", but it
seemed a bit restrictive so to restrict it.).

The indentation takes place either on typing <tab> (or any other action
which causes indentation) or on typing a space after "# pragma".

[ .... ]

For example the most general example so far is:

#pragma omp parallel shared(salaries1, salaries2)
     #pragma omp for reduction(+: salaries1)
     for (int employee = 0; employee < 25000; employee++)
         salaries1 += fetchTheSalary(employee, Co::Company1);

     #pragma omp single
         std::cout << "Salaries1: " << salaries1 << std::endl;

     #pragma omp for reduction(+: salaries1)
     for (int employee = 0; employee < 25000; employee++)
         salaries2 += fetchTheSalary(employee, Co::Company2);

     #pragma omp barrier

Thanks.  This example was helpful.

Just one thing - I haven't yet amended the CC Mode manual.

Would you please try the patch out, and let me know how well it satisfies
your needs.  The patch should apply cleanly to the master branch.


[ .... ]

diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el
index 1071191775..223266177a 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,78 @@ c-electric-continued-statement
        (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)
+    (save-excursion
+      (save-match-data
+       (back-to-indentation)
+       (when (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)


Alan Mackenzie (Nuremberg, Germany).

reply via email to

[Prev in Thread] Current Thread [Next in Thread]