From: Mauro Aranda <maurooaranda@gmail.com>
To: Juri Linkov <juri@linkov.net>
Cc: Eli Zaretskii <eliz@gnu.org>, 66663@debbugs.gnu.org
Subject: bug#66663: 30.0.50; Allow dir locals file selection in *-dir-local-variable functions
Date: Sat, 21 Oct 2023 19:10:10 -0300 [thread overview]
Message-ID: <8b4f9985-6bde-40e8-bd89-e74084e823a5@gmail.com> (raw)
In-Reply-To: <86zg0bu99e.fsf@mail.linkov.net>
[-- Attachment #1: Type: text/plain, Size: 1306 bytes --]
On 21/10/23 15:21, Juri Linkov wrote:
>> +(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
>
> The prompt needs a colon.
Fixed.
>> + (lambda (fname)
>> + (member (file-name-nondirectory fname)
>> + (list dir-locals-file
>> + (replace-regexp-in-string
>> + ".el$" "-2.el" dir-locals-file))))
>> + dir-locals-file)))
>
> This needs to be run in the project's root directory
> where the dir-locals file is saved. Probably it's not easy
> to find the root without using project.el. But when one of the
> files already exists (either .dir-locals.el or .dir-locals-2.el),
> then better to use the directory of the existing file by default.
In this new patch, I went for using it if already available and we
couldn't find an existing file by other means.
[-- Attachment #2: 0001-Allow-specifying-the-dir-locals-file-to-edit-Bug-666.patch --]
[-- Type: text/x-patch, Size: 9967 bytes --]
From 8a084557ca4647e82effc7007974ac1b1c66a27a 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.
(read-dir-locals-file): New function.
(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 | 117 ++++++++++++++++++++++++++++++------------
3 files changed, 102 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 5d42d88fb60..a3639620ebb 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
---
@@ -1358,6 +1363,11 @@ Their 'noerror' arguments have no effect and are therefore obsolete.
When supplied with ':default-language LANGUAGE', rules after it will
default to use 'LANGUAGE'.
+---
+** 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..f6fbd44ce21 100644
--- a/lisp/files-x.el
+++ b/lisp/files-x.el
@@ -31,6 +31,8 @@
;;; Code:
(eval-when-compile (require 'subr-x)) ; for string-trim-right
+(declare-function dosified-file-name "dos-fns" (file-name))
+(declare-function project-root "project" (project))
\f
;;; Commands to add/delete file-local/directory-local variables.
@@ -410,7 +412,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 +424,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 +538,75 @@ 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."
+ (let* ((pri dir-locals-file)
+ (sec (replace-regexp-in-string ".el$" "-2.el" dir-locals-file))
+ (dir (or (locate-dominating-file default-directory pri)
+ (locate-dominating-file default-directory sec))))
+ (expand-file-name
+ (read-file-name
+ "File: "
+ (cond (dir)
+ ((when-let ((proj (and (featurep 'project) (project-current))))
+ (project-root proj))))
+ nil
+ (lambda (fname)
+ (member (file-name-nondirectory fname) (list pri sec)))
+ 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
next prev parent reply other threads:[~2023-10-21 22:10 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
2023-10-21 18:21 ` Juri Linkov
2023-10-21 22:10 ` Mauro Aranda [this message]
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=8b4f9985-6bde-40e8-bd89-e74084e823a5@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).