emacs-devel
[Top][All Lists]
Advanced

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

Re: c-mode pragma and preproc


From: Alan Mackenzie
Subject: Re: c-mode pragma and preproc
Date: Sun, 19 Jan 2020 17:26:47 +0000
User-agent: Mutt/1.10.1 (2018-07-13)

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.

Thanks!

[ .... ]




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
          (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)
+    (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)


> Best,
> Ergus

-- 
Alan Mackenzie (Nuremberg, Germany).



reply via email to

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