Subject: CC Mode: Add new cleanup space-before-keyword-exp

From: Jason Thatcher <[email-masked]>
Date: Mon, 20 Feb 2023 22:02:45 +1000

Hi,

This patch adds a `space-before-keyword-exp` cleanup to CC Mode that 
inserts a space between a keyword and its subsequent opening 
parenthesis. For example, typing `if(` will clean up to `if (`. Clean up 
occurs when the opening parenthesis is typed, as per `space-before-funcall`.

I would appreciate any feedback. This is my first attempt to contribute; 
I'm not sure if this requires a copyright assignment.

Thanks,
Jason

From 56c167e3873499d2abc66584d0c83593cb134e19 Mon Sep 17 00:00:00 2001
From: Jason Thatcher <[email-masked]>
Date: Mon, 20 Feb 2023 18:24:55 +1000
Subject: [PATCH] CC Mode: Add new cleanup space-before-keyword-exp

* doc/misc/cc-mode.texi (Clean-ups): Document.
* etc/NEWS: Add new entries.
* lisp/progmodes/cc-cmds.el (c-electric-paren): Implement.
* lisp/progmodes/cc-engine.el (c-on-keyword): Add dependent function.
* lisp/progmodes/cc-vars.el (c-cleanup-list): Document.
---
 doc/misc/cc-mode.texi       |  7 +++++++
 etc/NEWS                    | 14 ++++++++++++++
 lisp/progmodes/cc-cmds.el   | 13 +++++++++++++
 lisp/progmodes/cc-engine.el | 10 ++++++++++
 lisp/progmodes/cc-vars.el   |  6 ++++++
 5 files changed, 50 insertions(+)

diff --git a/doc/misc/cc-mode.texi b/doc/misc/cc-mode.texi
index 3a808619868..e73096ff4b5 100644
--- a/doc/misc/cc-mode.texi
+++ b/doc/misc/cc-mode.texi
@@ -3919,6 +3919,13 @@ Clean-ups
 Mode, since such a space is syntactically invalid for user defined
 functions.
 
+@item space-before-keyword-exp
+Insert a space between a keyword and the opening parenthesis of a
+subsequent expression.  This produces keyword expressions in the style
+mandated by the GNU coding standards, e.g., @samp{if@w{ }(...)@w{ }@{}
+and @samp{sizeof@w{ }(long)}.  Clean up occurs when the opening
+parenthesis is typed.
+
 @item compact-empty-funcall
 Clean up any space between the function name and the opening parenthesis
 of a function call that has no arguments.  This is typically used
diff --git a/etc/NEWS b/etc/NEWS
index bcce416ebc1..337448bed7f 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -192,6 +192,20 @@ This command adds a docstring comment to the current defun.  If a
 comment already exists, point is only moved to the comment.  It is
 bound to 'C-c C-d' in 'go-ts-mode'.
 
+** CC Mode
+
++++
+*** New cleanup space-before-keyword-exp.
+A new cleanup has been added to c-cleanup-list:
+
+space-before-keyword-exp causes a space to be inserted before the
+opening parenthesis of a keyword expression, which gives the style
+"if (...)".
+
+---
+*** New function 'c-on-keyword'.
+It's the keyword equivalent of 'c-on-identifier'.
+
 
 * New Modes and Packages in Emacs 30.1
 
diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el
index 4c2340bfc2c..1091a39555e 100644
--- a/lisp/progmodes/cc-cmds.el
+++ b/lisp/progmodes/cc-cmds.el
@@ -1400,6 +1400,19 @@ c-electric-paren
 		 (goto-char beg)
 		 (insert ?\ )))
 
+	      ;; space-before-keyword-exp clean-up?
+	      ((and (memq 'space-before-keyword-exp c-cleanup-list)
+		    (eq (c-last-command-char) ?\()
+		    (save-excursion
+		      (backward-char)
+		      (skip-chars-backward " \t")
+		      (setq beg (point))
+		      (c-on-keyword)))
+	       (save-excursion
+		 (delete-region beg end)
+		 (goto-char beg)
+		 (insert ?\ )))
+
 	      ;; compact-empty-funcall clean-up?
 	      ((c-save-buffer-state ()
 		 (and (memq 'compact-empty-funcall c-cleanup-list)
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 037a53421a8..3adb2e187f4 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -4857,6 +4857,16 @@ c-on-identifier
 
      )))
 
+(defun c-on-keyword ()
+  "Return non-nil if the point is on or directly after a keyword.
+If a keyword is detected, the returned value is its starting position.
+
+This function does not do any hidden buffer changes."
+
+  (save-excursion
+    (skip-syntax-backward "w_")
+    (looking-at c-keywords-regexp)))
+
 (defsubst c-simple-skip-symbol-backward ()
   ;; If the point is at the end of a symbol then skip backward to the
   ;; beginning of it.  Don't move otherwise.  Return non-nil if point
diff --git a/lisp/progmodes/cc-vars.el b/lisp/progmodes/cc-vars.el
index 60ed3521b8a..1dc6fd1655d 100644
--- a/lisp/progmodes/cc-vars.el
+++ b/lisp/progmodes/cc-vars.el
@@ -710,6 +710,10 @@ c-cleanup-list
  space-before-funcall -- Insert exactly one space before the opening
                         parenthesis of a function call.  Clean up
                         occurs when the opening parenthesis is typed.
+ space-before-keyword-exp -- Insert exactly one space before the
+                        opening parenthesis of a keyword expression,
+                        which gives the style \"if (...)\".  Clean up
+                        occurs when the opening parenthesis is typed.
  compact-empty-funcall -- Clean up any space before the function call
                         opening parenthesis if and only if the
                         argument list is empty.  This is typically
@@ -740,6 +744,8 @@ c-cleanup-list
 		 scope-operator)
 	  (const :tag "Put a space before funcall parens, e.g. \"foo (bar)\" (space-before-funcall)"
 		 space-before-funcall)
+	  (const :tag "Put a space before keyword parens, e.g. \"if (foo)\" (space-before-keyword-exp)"
+		 space-before-keyword-exp)
 	  (const :tag "Remove space before empty funcalls, e.g. \"foo()\" (compact-empty-funcall)"
 		 compact-empty-funcall)
 	  (const :tag "Make / on a bare line of a C-style comment close it (comment-close-slash)"
-- 
2.39.2