unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Mauro Aranda <maurooaranda@gmail.com>
To: Eli Zaretskii <eliz@gnu.org>
Cc: 66663@debbugs.gnu.org, juri@linkov.net
Subject: bug#66663: 30.0.50; Allow dir locals file selection in *-dir-local-variable functions
Date: Sat, 21 Oct 2023 11:06:28 -0300	[thread overview]
Message-ID: <a7797f9d-6d33-4fb1-bbf1-049676882f42@gmail.com> (raw)
In-Reply-To: <514ef416-843b-4b80-abcf-cb4621b4b58d@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1154 bytes --]

On 21/10/23 10:49, Mauro Aranda wrote:
 > On 21/10/23 09:45, Eli Zaretskii wrote:
 >  >> Cc: Juri Linkov <juri@linkov.net>
 >  >> Date: Sat, 21 Oct 2023 09:16:28 -0300
 >  >> From: Mauro Aranda <maurooaranda@gmail.com>
 >  >>
 >  >> +Since both @file{.dir-locals.el} and @file{.dir-locals-2.el} file
 >  >> +might exist in the same directory, there may be some clash about 
which
 >  >> +file you want to modify when executing the above three commands.  To
 >  >> +solve that, all three of them take a prefix argument, to indicate
 >  >> +which file you want to modify.  When both files exist, a prefix
 >  >> +argument means to prefer to modify @file{.dir-locals.el} instead of
 >  >> +@file{.dir-locals-2.el}.  When one of the files doesn't exist, and
 >  >> +you're adding a variable or copying the file-local variables, a 
prefix
 >  >> +argument means to modify (i.e., create) the file that doesn't yet
 >  >> +exist.
 >  >
 >  > I think a better UI is to ask the user when the command is invoked
 >  > with a prefix argument.
 >
 > Yes, that makes sense.  I'll try that approach.

I reworked the patch to implement that UI instead.  Patch attached.

[-- Attachment #2: 0001-Allow-specifying-the-dir-locals-file-to-edit-Bug-666.patch --]
[-- Type: text/x-patch, Size: 9732 bytes --]

From 077a6a8b83cd1fb6efa9f169831ad6adec52312a Mon Sep 17 00:00:00 2001
From: Mauro Aranda <maurooaranda@gmail.com>
Date: Sat, 21 Oct 2023 11:02:36 -0300
Subject: [PATCH] Allow specifying the dir locals file to edit (Bug#66663)

* lisp/files-x.el (modify-dir-local-variable): Take a 5th optional
argument, the filename of the dir locals file to modify.
(add-dir-local-variable, delete-dir-local-variable)
(copy-file-locals-to-dir-locals): Optionally read the filename to
modify, and pass it to modify-dir-local-variable.
* etc/NEWS: Announce the change.
* doc/emacs/custom.texi (Directory Variables): Document the new
functionality.
---
 doc/emacs/custom.texi |   8 ++-
 etc/NEWS              |  10 ++++
 lisp/files-x.el       | 110 ++++++++++++++++++++++++++++++------------
 3 files changed, 95 insertions(+), 33 deletions(-)

diff --git a/doc/emacs/custom.texi b/doc/emacs/custom.texi
index 8c30f26bbf7..adecc873163 100644
--- a/doc/emacs/custom.texi
+++ b/doc/emacs/custom.texi
@@ -1507,7 +1507,13 @@ Directory Variables
 entry defining the directory-local variable.  @kbd{M-x
 delete-dir-local-variable} deletes an entry.  @kbd{M-x
 copy-file-locals-to-dir-locals} copies the file-local variables in the
-current file into @file{.dir-locals.el}.
+current file into @file{.dir-locals.el}, or @file{.dir-locals-2.el} if
+that file is also present.
+
+With a prefix argument, all three commands prompt for the file you
+want to modify.  Although it doesn't have to exist, you must enter a
+valid filename, either @file{.dir-locals.el} or
+@file{.dir-locals-2.el}.
 
 @findex dir-locals-set-class-variables
 @findex dir-locals-set-directory-class
diff --git a/etc/NEWS b/etc/NEWS
index 3d4cdd876b3..d48466be305 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -187,6 +187,11 @@ right-aligned to is controlled by the new user option
 It can be used to add, remove and reorder functions that change
 the appearance of every tab on the tab bar.
 
++++
+** New optional argument for modifying directory local variables
+The commands 'add-dir-local-variable', 'delete-dir-local-variable' and
+'copy-file-locals-to-dir-locals' now take an optional prefix argument,
+to enter the file you want to modify.
 ** Miscellaneous
 
 ---
@@ -1337,6 +1342,11 @@ Since circular alias chains now cannot occur, 'function-alias-p',
 'indirect-function' and 'indirect-variable' will never signal an error.
 Their 'noerror' arguments have no effect and are therefore obsolete.
 
+---
+** New optional argument to 'modify-dir-local-variable'
+A 5th argument, optional, has been added to
+'modify-dir-local-variable'.  It can be used to specify which
+dir-locals file to modify.
 \f
 * Changes in Emacs 30.1 on Non-Free Operating Systems
 
diff --git a/lisp/files-x.el b/lisp/files-x.el
index 3ba7632d253..ef3adcb9cd3 100644
--- a/lisp/files-x.el
+++ b/lisp/files-x.el
@@ -31,6 +31,7 @@
 ;;; Code:
 
 (eval-when-compile (require 'subr-x)) ; for string-trim-right
+(declare-function dosified-file-name "dos-fns" (file-name))
 
 \f
 ;;; Commands to add/delete file-local/directory-local variables.
@@ -410,7 +411,7 @@ delete-file-local-variable-prop-line
 
 (defvar auto-insert) ; from autoinsert.el
 
-(defun modify-dir-local-variable (mode variable value op)
+(defun modify-dir-local-variable (mode variable value op &optional file)
   "Modify directory-local VARIABLE in .dir-locals.el depending on operation OP.
 
 If OP is `add-or-replace' then delete all existing settings of
@@ -422,28 +423,37 @@ modify-dir-local-variable
 this file in the current directory.
 
 If OP is `delete' then delete all existing settings of VARIABLE
-from the MODE alist ignoring the input argument VALUE."
+from the MODE alist ignoring the input argument VALUE.
+
+Optional argument FILE, when non-nil, specifies what file to modify.  It
+should be an expanded filename."
   (catch 'exit
     (unless enable-local-variables
       (throw 'exit (message "Directory-local variables are disabled")))
-    (let* ((dir-or-cache (and (buffer-file-name)
-                              (not (file-remote-p (buffer-file-name)))
-                              (dir-locals-find-file (buffer-file-name))))
-           (variables-file
-            ;; If there are several .dir-locals, the user probably
-            ;; wants to edit the last one (the highest priority).
-            (cond ((stringp dir-or-cache)
-                   (car (last (dir-locals--all-files dir-or-cache))))
-                  ((consp dir-or-cache)	; result from cache
-                   ;; If cache element has an mtime, assume it came
-                   ;; from a file.  Otherwise, assume it was set
-                   ;; directly.
-                   (if (nth 2 dir-or-cache)
-                       (car (last (dir-locals--all-files (car dir-or-cache))))
-                     (cadr dir-or-cache)))
-                  ;; Try to make a proper file-name.
-                  (t (expand-file-name dir-locals-file))))
-           variables)
+    (let ((variables-file
+           (if (stringp file)
+               file
+             (let ((dir-or-cache
+                    (and (buffer-file-name)
+                         (not (file-remote-p (buffer-file-name)))
+                         (dir-locals-find-file (buffer-file-name)))))
+               ;; If there are several .dir-locals, the user probably
+               ;; wants to edit the last one (the highest priority).
+               (cond
+                ((stringp dir-or-cache)
+                 (car (last (dir-locals--all-files dir-or-cache))))
+                ((consp dir-or-cache)	; result from cache
+                 ;; If cache element has an mtime, assume it came
+                 ;; from a file.  Otherwise, assume it was set
+                 ;; directly.
+                 (if (nth 2 dir-or-cache)
+                     (car (last (dir-locals--all-files (car dir-or-cache))))
+                   (cadr dir-or-cache)))
+                ;; Try to make a proper file-name.
+                (t (expand-file-name (if (eq system-type 'ms-dos)
+                                         (dosified-file-name dir-locals-file)
+                                       dir-locals-file)))))))
+          variables)
       ;; I can't be bothered to handle this case right now.
       ;; Dir locals were set directly from a class.  You need to
       ;; directly modify the class in dir-locals-class-alist.
@@ -527,33 +537,69 @@ dir-locals-to-string
                                      (cdr mode-variables) "\n"))))
            variables "\n")))
 
+(defun read-dir-locals-file ()
+  "Read a dir-locals filename using completion.
+Intended to be used in the `interactive' spec of `add-dir-local-variable',
+`delete-dir-local-variable' and `copy-file-locals-to-dir-locals'.
+
+Returns the filename, expanded."
+  (expand-file-name
+   (read-file-name "File" nil nil
+                   (lambda (fname)
+                     (member (file-name-nondirectory fname)
+                             (list dir-locals-file
+                                   (replace-regexp-in-string
+                                    ".el$" "-2.el" dir-locals-file))))
+                   dir-locals-file)))
+
 ;;;###autoload
-(defun add-dir-local-variable (mode variable value)
-  "Add directory-local VARIABLE with its VALUE and MODE to .dir-locals.el."
+(defun add-dir-local-variable (mode variable value &optional file)
+  "Add directory-local VARIABLE with its VALUE and MODE to .dir-locals.el.
+
+With a prefix argument, prompt for the file to modify.
+
+When called from Lisp, FILE may be the expanded name of the dir-locals file
+where to add VARIABLE."
   (interactive
    (let (variable)
      (list
       (read-file-local-variable-mode)
       (setq variable (read-file-local-variable "Add directory-local variable"))
-      (read-file-local-variable-value variable))))
-  (modify-dir-local-variable mode variable value 'add-or-replace))
+      (read-file-local-variable-value variable)
+      (when current-prefix-arg
+        (read-dir-locals-file)))))
+  (modify-dir-local-variable mode variable value 'add-or-replace file))
 
 ;;;###autoload
-(defun delete-dir-local-variable (mode variable)
-  "Delete all MODE settings of file-local VARIABLE from .dir-locals.el."
+(defun delete-dir-local-variable (mode variable &optional file)
+  "Delete all MODE settings of dir-local VARIABLE from .dir-locals.el.
+
+With a prefix argument, prompt for the file to modify.
+
+When called from Lisp, FILE may be the expanded name of the dir-locals file
+from where to delete VARIABLE."
   (interactive
    (list
     (read-file-local-variable-mode)
-    (read-file-local-variable "Delete directory-local variable")))
-  (modify-dir-local-variable mode variable nil 'delete))
+    (read-file-local-variable "Delete directory-local variable")
+    (when current-prefix-arg
+      (read-dir-locals-file))))
+  (modify-dir-local-variable mode variable nil 'delete file))
 
 ;;;###autoload
-(defun copy-file-locals-to-dir-locals ()
-  "Copy file-local variables to .dir-locals.el."
-  (interactive)
+(defun copy-file-locals-to-dir-locals (&optional file)
+  "Copy file-local variables to .dir-locals.el.
+
+With a prefix argument, prompt for the file to modify.
+
+When called from Lisp, FILE may be the expanded name of the dir-locals file
+where to copy the file-local variables."
+  (interactive
+   (list (when current-prefix-arg
+           (read-dir-locals-file))))
   (dolist (elt file-local-variables-alist)
     (unless (assq (car elt) dir-local-variables-alist)
-      (add-dir-local-variable major-mode (car elt) (cdr elt)))))
+      (add-dir-local-variable major-mode (car elt) (cdr elt) file))))
 
 ;;;###autoload
 (defun copy-dir-locals-to-file-locals ()
-- 
2.34.1


  reply	other threads:[~2023-10-21 14:06 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-21 12:08 bug#66663: 30.0.50; Allow dir locals file selection in *-dir-local-variable functions Mauro Aranda
2023-10-21 12:16 ` Mauro Aranda
2023-10-21 12:45   ` Eli Zaretskii
2023-10-21 13:49     ` Mauro Aranda
2023-10-21 14:06       ` Mauro Aranda [this message]
2023-10-21 18:21         ` Juri Linkov
2023-10-21 22:10           ` Mauro Aranda
2023-10-22 17:55             ` Juri Linkov

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=a7797f9d-6d33-4fb1-bbf1-049676882f42@gmail.com \
    --to=maurooaranda@gmail.com \
    --cc=66663@debbugs.gnu.org \
    --cc=eliz@gnu.org \
    --cc=juri@linkov.net \
    /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).