1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-23 21:13:52 -08:00

Allow project-vc-ignores to be applied in more cases

Discussed in
https://lists.gnu.org/archive/html/emacs-devel/2025-12/msg00903.html.

* lisp/progmodes/project.el (project-files) <vc>: Look up the
value of 'project-vc-ignores' inside DIR rather than project root.
This allows this variable to be applied in external dirs as well.
(project-ignores) <vc>: Do likewise.
(project--value-in-dir): Ensure that DIR has a trailing slash.
The caller might pass the value without slash if produced
differently.

* test/lisp/progmodes/project-tests.el
(project-vc-ignores-in-external-directory): New test.
(project-vc-supports-files-in-subdirectory): Update the test,
considering the subtle change in behavior: the directory DIR
directly includes a .dir-locals.el which sets project-vc-ignores,
which wasn't previously applied because it wasn't set in the root.
This commit is contained in:
Dmitry Gutov 2026-01-01 04:12:49 +02:00
parent 20e1a57d44
commit 6c832af157
3 changed files with 37 additions and 10 deletions

View file

@ -2322,7 +2322,9 @@ Using this variable you can add more ignore patterns to the project, to
exclude more files from the project's file listing. The value is a list
of glob strings. They can match both regular files and directories. To
anchor an entry to the project root, start it with @code{./}. To match
directories only, end it with @code{/}.
directories only, end it with @code{/}. When this variable has
directory-local value, it will only be applied to the corresponding
directory subtree.
@end defopt
@defopt project-vc-name

View file

@ -466,7 +466,10 @@ the buffer's value of `default-directory'."
:group 'project)
(defcustom project-vc-ignores nil
"List of patterns to add to `project-ignores'."
"List of patterns to add to `project-ignores'.
Only global or directory-local values are supported. And directory-local
values will be applied to the corresponding directory subtrees."
:type '(repeat string))
;; Change to `list-of-strings-p' when support for Emacs 28 is dropped.
;;;###autoload(put 'project-vc-ignores 'safe-local-variable (lambda (val) (and (listp val) (not (memq nil (mapcar #'stringp val))))))
@ -688,12 +691,14 @@ See `project-vc-extra-root-markers' for the marker value format.")
(cl-defmethod project-files ((project (head vc)) &optional dirs)
(mapcan
(lambda (dir)
(let ((ignores (project--value-in-dir 'project-vc-ignores (nth 2 project)))
(let ((ignores (project--value-in-dir 'project-vc-ignores dir))
(backend (project-vc--backend project dir)))
(if backend
(vc-call-backend backend 'project-list-files dir ignores)
(project--files-in-directory
dir (append ignores (project-ignores nil nil))))))
dir (append ignores (append
(project-ignores nil nil)
ignores))))))
(or dirs
(list (project-root project)))))
@ -830,9 +835,9 @@ See `project-vc-extra-root-markers' for the marker value format.")
(file-missing nil)))
(cl-defmethod project-ignores ((project (head vc)) dir)
(let ((root (nth 2 project)))
(project--vc-ignores dir (project-vc--backend project dir)
(project--value-in-dir 'project-vc-ignores root))))
(project--vc-ignores dir
(project-vc--backend project dir)
(project--value-in-dir 'project-vc-ignores dir)))
(defun project--vc-ignores (dir backend extra-ignores)
(append
@ -890,7 +895,7 @@ DIRS must contain directory names."
(defun project--value-in-dir (var dir)
(with-temp-buffer
(setq default-directory dir)
(setq default-directory (file-name-as-directory dir))
(let ((enable-local-variables :all))
(hack-dir-local-variables))
;; Don't use `hack-local-variables-apply' to avoid setting modes.

View file

@ -162,7 +162,7 @@ When `project-ignores' includes a name matching project dir."
(mapcar #'file-name-nondirectory (project-files project))))))
(ert-deftest project-vc-supports-files-in-subdirectory ()
"Check that it lists only files from subdirectory."
"Check that it lists only files from a repo's subdirectory."
(skip-unless (eq (vc-responsible-backend default-directory) 'Git))
(let* ((dir (ert-resource-directory))
(_ (vc-file-clearprops dir))
@ -170,7 +170,27 @@ When `project-ignores' includes a name matching project dir."
(project (project-current nil dir)))
(should-not (null project))
(should (string-match-p "/test/lisp/progmodes/\\'" (project-root project)))
(should (equal '(".dir-locals.el" "etc" "foo")
(should (equal `(,@(when (version<= "2.13" (vc-git--program-version))
(list ".dir-locals.el"))
"foo")
(mapcar #'file-name-nondirectory
(project-files project
(list dir)))))))
(ert-deftest project-vc-ignores-in-external-directory ()
"Check that it applies project-vc-ignores when DIR is external to root."
(skip-unless (eq (vc-responsible-backend default-directory) 'Git))
(let* ((dir (ert-resource-directory))
(_ (vc-file-clearprops dir))
;; Do not detect VC backend.
(project-vc-backend-markers-alist nil)
(project-vc-extra-root-markers '("configure.ac"))
(project (project-current nil (expand-file-name "../autoconf-resources/" dir))))
(should-not (null project))
(should (string-match-p "/test/lisp/progmodes/autoconf-resources/\\'" (project-root project)))
(should (equal `(,@(when (version<= "2.13" (vc-git--program-version))
(list ".dir-locals.el"))
"foo")
(mapcar #'file-name-nondirectory
(project-files project
(list dir)))))))