Subject: bug#17948: 24.3; cperl: Needs an equivalent to `c-file-style' [PATCH]

From: Harald Jörg <[email-masked]>
Date: Mon, 08 Jan 2024 08:23:35 +0000

So... I promised a bit too much.  It is not possible to override an
individual indentation setting (e.g. cperl-indent-level) when a
cperl-file-style is used.  File (and directory) variables are applied
after the body of cperl-mode, and the styles do their work only after
that in hack-local-variables-hook.  I did not know that.  So, styles
will always override the settings they provide.

But apart from that, the patch (attached) does what I would expect:  I
can set a default style in custom, individual styles from .dir-locals.el
or file local variables work without affecting other buffers.

I suggest this patch should go to the emacs-29 branch.

--
Cheers,
haj
>From 40407c365d8c092bbd94d3db20cc8e709498ca3f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Harald=20J=C3=B6rg?= <[email-masked]>
Date: Mon, 8 Jan 2024 09:01:02 +0100
Subject: [PATCH] cperl-mode.el: Make sure cperl-file-style is buffer-local
 when set

* lisp/progmodes/cperl-mode.el (cperl-file-style): Add description
what the options actually do.
(cperl-menu): Split the menu entry "Indent styles" into "Default
indent styles" and "Indent styles for current buffer"
(cperl--set-file-style): call `cperl-file-style' instead of
`cperl-set-style'.
(cperl-set-style): Explain when to use `cperl-file-style'.
Use `set-default-toplevel-value' instead of `set'.
(cperl-set-style-back): Use `set-default-toplevel-value' instead
of `set'.
(cperl-file-style): New command to set the file style for the
current buffer.

* etc/NEWS: Announce the new command cperl-file-style
---
 etc/NEWS                     |  5 +++
 lisp/progmodes/cperl-mode.el | 66 +++++++++++++++++++++++++++++++++---
 2 files changed, 66 insertions(+), 5 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 069661866ce..4b11c5208eb 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1638,6 +1638,11 @@ doc string.
 This option determines the indentation style to be used.  It can also
 be used as a file-local variable.
 
+*** New command 'cperl-file-style'.
+This command sets the indentation style for the current buffer.  To
+change the default style, either use the option with the same name or
+use the command cperl-set-style.
+
 ** Gud
 
 *** 'gud-go' is now bound to 'C-c C-v'.
diff --git a/lisp/progmodes/cperl-mode.el b/lisp/progmodes/cperl-mode.el
index b85db699e72..a75d257b101 100644
--- a/lisp/progmodes/cperl-mode.el
+++ b/lisp/progmodes/cperl-mode.el
@@ -101,7 +101,10 @@ cperl
   :version "20.3")
 
 (defgroup cperl-indentation-details nil
-  "Indentation."
+  "Indentation.
+The option `cperl-file-style' (which see) can be used to set
+several indentation options in one go, following popular
+indentation styles."
   :prefix "cperl-"
   :group 'cperl)
 
@@ -154,6 +157,29 @@ cperl-extra-newline-before-brace-multiline
   :type 'boolean
   :group 'cperl-autoinsert-details)
 
+(defcustom cperl-file-style nil
+  "Indentation style to use in cperl-mode.
+Setting this option will override options as given in
+`cperl-style-alist' for the keyword provided here.  If nil, then
+the individual options as customized are used.
+\"PBP\" is the style recommended in the Book \"Perl Best
+Practices\" by Damian Conway.  \"CPerl\" is the traditional style
+of cperl-mode, and \"PerlStyle\" follows the Perl documentation
+in perlstyle.  The other styles have been developed for other
+programming languages, mostly C."
+  :type '(choice (const "PBP")
+                 (const "CPerl")
+                 (const "PerlStyle")
+                 (const "GNU")
+                 (const "C++")
+                 (const "K&R")
+                 (const "BSD")
+                 (const "Whitesmith")
+                 (const :tag "Default" nil))
+  :group 'cperl-indentation-details
+  :version "29.1")
+;;;###autoload(put 'cperl-file-style 'safe-local-variable 'stringp)
+
 (defcustom cperl-indent-level 2
   "Indentation of CPerl statements with respect to containing block."
   :type 'integer
@@ -1147,7 +1173,7 @@ cperl-menu
      ["Fix whitespace on indent" cperl-toggle-construct-fix t]
      ["Auto-help on Perl constructs" cperl-toggle-autohelp t]
      ["Auto fill" auto-fill-mode t])
-    ("Indent styles..."
+    ("Default indent styles..."
      ["CPerl" (cperl-set-style "CPerl") t]
      ["PBP" (cperl-set-style  "PBP") t]
      ["PerlStyle" (cperl-set-style "PerlStyle") t]
@@ -1158,6 +1184,15 @@ cperl-menu
      ["Whitesmith" (cperl-set-style "Whitesmith") t]
      ["Memorize Current" (cperl-set-style "Current") t]
      ["Memorized" (cperl-set-style-back) cperl-old-style])
+    ("Indent styles for current buffer..."
+     ["CPerl" (cperl-set-style "CPerl") t]
+     ["PBP" (cperl-file-style  "PBP") t]
+     ["PerlStyle" (cperl-file-style "PerlStyle") t]
+     ["GNU" (cperl-file-style "GNU") t]
+     ["C++" (cperl-file-style "C++") t]
+     ["K&R" (cperl-file-style "K&R") t]
+     ["BSD" (cperl-file-style "BSD") t]
+     ["Whitesmith" (cperl-file-style "Whitesmith") t])
     ("Micro-docs"
      ["Tips" (describe-variable 'cperl-tips) t]
      ["Problems" (describe-variable 'cperl-problems) t]
@@ -1788,7 +1823,8 @@ cperl-mode
 
 (defun cperl--set-file-style ()
   (when cperl-file-style
-    (cperl-set-style cperl-file-style)))
+    (cperl-file-style cperl-file-style)))
+
 
 ;; Fix for perldb - make default reasonable
 (defun cperl-db ()
@@ -6259,6 +6295,10 @@ cperl-style-alist
 
 (defun cperl-set-style (style)
   "Set CPerl mode variables to use one of several different indentation styles.
+This command sets the default values for the variables.  It does
+not affect buffers visiting files where the style has been set as
+a file or directory variable.  To change the indentation style of
+a buffer, use the command `cperl-file-style' instead.
 The arguments are a string representing the desired style.
 The list of styles is in `cperl-style-alist', available styles
 are \"CPerl\", \"PBP\", \"PerlStyle\", \"GNU\", \"K&R\", \"BSD\", \"C++\"
@@ -6279,7 +6319,8 @@ cperl-set-style
   (let ((style (cdr (assoc style cperl-style-alist))) setting)
     (while style
       (setq setting (car style) style (cdr style))
-      (set (car setting) (cdr setting)))))
+      (set-default-toplevel-value (car setting) (cdr setting))))
+  (set-default-toplevel-value 'cperl-file-style style))
 
 (defun cperl-set-style-back ()
   "Restore a style memorized by `cperl-set-style'."
@@ -6289,7 +6330,22 @@ cperl-set-style-back
     (while cperl-old-style
       (setq setting (car cperl-old-style)
 	    cperl-old-style (cdr cperl-old-style))
-      (set (car setting) (cdr setting)))))
+      (set-default-toplevel-value (car setting) (cdr setting)))))
+
+(defun cperl-file-style (style)
+  "Set the indentation style for the current buffer to STYLE.
+The list of styles is in `cperl-style-alist', available styles
+are \"CPerl\", \"PBP\", \"PerlStyle\", \"GNU\", \"K&R\", \"BSD\", \"C++\"
+and \"Whitesmith\"."
+  (interactive
+   (list (completing-read "Enter style: " cperl-style-alist nil 'insist)))
+  (dolist (setting (cdr (assoc style cperl-style-alist)) style)
+    (let ((option (car setting))
+          (value (cdr setting)))
+      (make-variable-buffer-local option)
+      (set option value)))
+  (make-variable-buffer-local 'cperl-file-style)
+  (setq cperl-file-style style))
 
 (defvar perl-dbg-flags)
 (defun cperl-check-syntax ()
-- 
2.34.1