mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-17 11:20:39 -08:00
New variable 'project-files-relative-names'
* lisp/progmodes/project.el (project-files-relative-names): New variable (bug#69233). (project--files-in-directory): Honor it. (project--vc-list-files): Here too. (project-find-regexp): Use it to improve performance. (project-or-external-find-regexp): Add a TODO. (project-find-file): Use it here too. (project--read-file-cpd-relative, project--read-file-absolute): Try to handle file lists with absolute and relative files names. (project-find-file-in): Set default-directory, so relative names are interpreted correctly. * lisp/progmodes/xref.el (xref-matches-in-files): Consider that the first in FILES can be a relative file name. * test/lisp/progmodes/project-tests.el (project-find-regexp): New test. * etc/NEWS: Mention it.
This commit is contained in:
parent
e0993f5169
commit
370b216f08
4 changed files with 78 additions and 17 deletions
4
etc/NEWS
4
etc/NEWS
|
|
@ -696,6 +696,10 @@ you can add this to your init script:
|
||||||
|
|
||||||
(setopt project-switch-commands #'project-prefix-or-any-command)
|
(setopt project-switch-commands #'project-prefix-or-any-command)
|
||||||
|
|
||||||
|
*** New variable 'project-files-relative-names'.
|
||||||
|
Project backends can support it to improve the performance of their
|
||||||
|
'project-files' implementation when this variable is non-nil.
|
||||||
|
|
||||||
** VC
|
** VC
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -323,6 +323,12 @@ end it with `/'. DIR must be either `project-root' or one of
|
||||||
(cl-defmethod project-root ((project (head transient)))
|
(cl-defmethod project-root ((project (head transient)))
|
||||||
(cdr project))
|
(cdr project))
|
||||||
|
|
||||||
|
(defvar project-files-relative-names nil
|
||||||
|
"When non-nil, `project-files' is allowed to return relative names.
|
||||||
|
The names will be relative to the project root. And this can only
|
||||||
|
happen when all returned files are in the same directory. Meaning, the
|
||||||
|
DIRS argument has to be nil or have only one element.")
|
||||||
|
|
||||||
(cl-defgeneric project-files (project &optional dirs)
|
(cl-defgeneric project-files (project &optional dirs)
|
||||||
"Return a list of files in directories DIRS in PROJECT.
|
"Return a list of files in directories DIRS in PROJECT.
|
||||||
DIRS is a list of absolute directories; it should be some
|
DIRS is a list of absolute directories; it should be some
|
||||||
|
|
@ -345,7 +351,6 @@ to find the list of ignores for each directory."
|
||||||
;; expanded and not left for the shell command
|
;; expanded and not left for the shell command
|
||||||
;; to interpret.
|
;; to interpret.
|
||||||
(localdir (file-name-unquote (file-local-name (expand-file-name dir))))
|
(localdir (file-name-unquote (file-local-name (expand-file-name dir))))
|
||||||
(dfn (directory-file-name localdir))
|
|
||||||
(command (format "%s -H . %s -type f %s -print0"
|
(command (format "%s -H . %s -type f %s -print0"
|
||||||
find-program
|
find-program
|
||||||
(xref--find-ignores-arguments ignores "./")
|
(xref--find-ignores-arguments ignores "./")
|
||||||
|
|
@ -376,12 +381,14 @@ to find the list of ignores for each directory."
|
||||||
(error "File listing failed: %s" (buffer-string))))
|
(error "File listing failed: %s" (buffer-string))))
|
||||||
(goto-char pt)
|
(goto-char pt)
|
||||||
(while (search-forward "\0" nil t)
|
(while (search-forward "\0" nil t)
|
||||||
(push (buffer-substring-no-properties (1+ pt) (1- (point)))
|
(push (buffer-substring-no-properties (+ pt 2) (1- (point)))
|
||||||
res)
|
res)
|
||||||
(setq pt (point)))))
|
(setq pt (point)))))
|
||||||
|
(if project-files-relative-names
|
||||||
|
(sort res #'string<)
|
||||||
(project--remote-file-names
|
(project--remote-file-names
|
||||||
(mapcar (lambda (s) (concat dfn s))
|
(mapcar (lambda (s) (concat localdir s))
|
||||||
(sort res #'string<)))))
|
(sort res #'string<))))))
|
||||||
|
|
||||||
(defun project--remote-file-names (local-files)
|
(defun project--remote-file-names (local-files)
|
||||||
"Return LOCAL-FILES as if they were on the system of `default-directory'.
|
"Return LOCAL-FILES as if they were on the system of `default-directory'.
|
||||||
|
|
@ -689,7 +696,9 @@ See `project-vc-extra-root-markers' for the marker value format.")
|
||||||
(mapcar
|
(mapcar
|
||||||
(lambda (file)
|
(lambda (file)
|
||||||
(unless (member file submodules)
|
(unless (member file submodules)
|
||||||
(concat default-directory file)))
|
(if project-files-relative-names
|
||||||
|
file
|
||||||
|
(concat default-directory file))))
|
||||||
(split-string
|
(split-string
|
||||||
(apply #'vc-git--run-command-string nil "ls-files" args)
|
(apply #'vc-git--run-command-string nil "ls-files" args)
|
||||||
"\0" t))))
|
"\0" t))))
|
||||||
|
|
@ -716,7 +725,8 @@ See `project-vc-extra-root-markers' for the marker value format.")
|
||||||
dir))
|
dir))
|
||||||
(args (list (concat "-mcard" (and include-untracked "u"))
|
(args (list (concat "-mcard" (and include-untracked "u"))
|
||||||
"--no-status"
|
"--no-status"
|
||||||
"-0")))
|
"-0"))
|
||||||
|
files)
|
||||||
(when extra-ignores
|
(when extra-ignores
|
||||||
(setq args (nconc args
|
(setq args (nconc args
|
||||||
(mapcan
|
(mapcan
|
||||||
|
|
@ -725,9 +735,12 @@ See `project-vc-extra-root-markers' for the marker value format.")
|
||||||
extra-ignores))))
|
extra-ignores))))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(apply #'vc-hg-command t 0 "." "status" args)
|
(apply #'vc-hg-command t 0 "." "status" args)
|
||||||
(mapcar
|
(setq files (split-string (buffer-string) "\0" t))
|
||||||
|
(unless project-files-relative-names
|
||||||
|
(setq files (mapcar
|
||||||
(lambda (s) (concat default-directory s))
|
(lambda (s) (concat default-directory s))
|
||||||
(split-string (buffer-string) "\0" t)))))))
|
files)))
|
||||||
|
files)))))
|
||||||
|
|
||||||
(defun project--vc-merge-submodules-p (dir)
|
(defun project--vc-merge-submodules-p (dir)
|
||||||
(project--value-in-dir
|
(project--value-in-dir
|
||||||
|
|
@ -970,6 +983,7 @@ requires quoting, e.g. `\\[quoted-insert]<space>'."
|
||||||
(let* ((caller-dir default-directory)
|
(let* ((caller-dir default-directory)
|
||||||
(pr (project-current t))
|
(pr (project-current t))
|
||||||
(default-directory (project-root pr))
|
(default-directory (project-root pr))
|
||||||
|
(project-files-relative-names t)
|
||||||
(files
|
(files
|
||||||
(if (not current-prefix-arg)
|
(if (not current-prefix-arg)
|
||||||
(project-files pr)
|
(project-files pr)
|
||||||
|
|
@ -1000,6 +1014,8 @@ requires quoting, e.g. `\\[quoted-insert]<space>'."
|
||||||
(require 'xref)
|
(require 'xref)
|
||||||
(let* ((pr (project-current t))
|
(let* ((pr (project-current t))
|
||||||
(default-directory (project-root pr))
|
(default-directory (project-root pr))
|
||||||
|
;; TODO: Make use of `project-files-relative-names' by
|
||||||
|
;; searching each root separately (maybe in parallel, too).
|
||||||
(files
|
(files
|
||||||
(project-files pr (cons
|
(project-files pr (cons
|
||||||
(project-root pr)
|
(project-root pr)
|
||||||
|
|
@ -1054,7 +1070,8 @@ for VCS directories listed in `vc-directory-exclusion-list'."
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(let* ((pr (project-current t))
|
(let* ((pr (project-current t))
|
||||||
(root (project-root pr))
|
(root (project-root pr))
|
||||||
(dirs (list root)))
|
(dirs (list root))
|
||||||
|
(project-files-relative-names t))
|
||||||
(project-find-file-in
|
(project-find-file-in
|
||||||
(or (thing-at-point 'filename)
|
(or (thing-at-point 'filename)
|
||||||
(and buffer-file-name (project--find-default-from buffer-file-name pr)))
|
(and buffer-file-name (project--find-default-from buffer-file-name pr)))
|
||||||
|
|
@ -1130,7 +1147,12 @@ by the user at will."
|
||||||
(if (> (length common-prefix) 0)
|
(if (> (length common-prefix) 0)
|
||||||
(file-name-directory common-prefix))))
|
(file-name-directory common-prefix))))
|
||||||
(cpd-length (length common-parent-directory))
|
(cpd-length (length common-parent-directory))
|
||||||
(prompt (if (zerop cpd-length)
|
(common-parent-directory (if (file-name-absolute-p (car all-files))
|
||||||
|
common-parent-directory
|
||||||
|
(concat default-directory common-parent-directory)))
|
||||||
|
(prompt (if (and (zerop cpd-length)
|
||||||
|
all-files
|
||||||
|
(file-name-absolute-p (car all-files)))
|
||||||
prompt
|
prompt
|
||||||
(concat prompt (format " in %s" common-parent-directory))))
|
(concat prompt (format " in %s" common-parent-directory))))
|
||||||
(included-cpd (when (member common-parent-directory all-files)
|
(included-cpd (when (member common-parent-directory all-files)
|
||||||
|
|
@ -1167,10 +1189,19 @@ by the user at will."
|
||||||
(defun project--read-file-absolute (prompt
|
(defun project--read-file-absolute (prompt
|
||||||
all-files &optional predicate
|
all-files &optional predicate
|
||||||
hist mb-default)
|
hist mb-default)
|
||||||
(project--completing-read-strict prompt
|
(let* ((new-prompt (if (file-name-absolute-p (car all-files))
|
||||||
(project--file-completion-table all-files)
|
prompt
|
||||||
|
(concat prompt " in " default-directory)))
|
||||||
|
;; FIXME: Map relative names to absolute?
|
||||||
|
(ct (project--file-completion-table all-files))
|
||||||
|
(file
|
||||||
|
(project--completing-read-strict new-prompt
|
||||||
|
ct
|
||||||
predicate
|
predicate
|
||||||
hist mb-default))
|
hist mb-default)))
|
||||||
|
(unless (file-name-absolute-p file)
|
||||||
|
(setq file (expand-file-name file)))
|
||||||
|
file))
|
||||||
|
|
||||||
(defun project--read-file-name ( project prompt
|
(defun project--read-file-name ( project prompt
|
||||||
all-files &optional predicate
|
all-files &optional predicate
|
||||||
|
|
@ -1215,6 +1246,7 @@ directories listed in `vc-directory-exclusion-list'."
|
||||||
dirs)
|
dirs)
|
||||||
(project-files project dirs)))
|
(project-files project dirs)))
|
||||||
(completion-ignore-case read-file-name-completion-ignore-case)
|
(completion-ignore-case read-file-name-completion-ignore-case)
|
||||||
|
(default-directory (project-root project))
|
||||||
(file (project--read-file-name
|
(file (project--read-file-name
|
||||||
project "Find file"
|
project "Find file"
|
||||||
all-files nil 'file-name-history
|
all-files nil 'file-name-history
|
||||||
|
|
|
||||||
|
|
@ -1922,7 +1922,8 @@ to control which program to use when looking for matches."
|
||||||
(hits nil)
|
(hits nil)
|
||||||
;; Support for remote files. The assumption is that, if the
|
;; Support for remote files. The assumption is that, if the
|
||||||
;; first file is remote, they all are, and on the same host.
|
;; first file is remote, they all are, and on the same host.
|
||||||
(dir (file-name-directory (car files)))
|
(dir (or (file-name-directory (car files))
|
||||||
|
default-directory))
|
||||||
(remote-id (file-remote-p dir))
|
(remote-id (file-remote-p dir))
|
||||||
;; The 'auto' default would be fine too, but ripgrep can't handle
|
;; The 'auto' default would be fine too, but ripgrep can't handle
|
||||||
;; the options we pass in that case.
|
;; the options we pass in that case.
|
||||||
|
|
|
||||||
|
|
@ -163,4 +163,28 @@ When `project-ignores' includes a name matching project dir."
|
||||||
(should-not (null project))
|
(should-not (null project))
|
||||||
(should (string-match-p "/test/lisp/progmodes/project-resources/\\'" (project-root project)))))
|
(should (string-match-p "/test/lisp/progmodes/project-resources/\\'" (project-root project)))))
|
||||||
|
|
||||||
|
(ert-deftest project-find-regexp ()
|
||||||
|
"Check the happy path."
|
||||||
|
(skip-unless (executable-find find-program))
|
||||||
|
(skip-unless (executable-find "xargs"))
|
||||||
|
(skip-unless (executable-find "grep"))
|
||||||
|
(let* ((directory (ert-resource-directory))
|
||||||
|
(project-find-functions nil)
|
||||||
|
(project (cons 'transient directory)))
|
||||||
|
(add-hook 'project-find-functions (lambda (_dir) project))
|
||||||
|
(should (eq (project-current) project))
|
||||||
|
(let* ((matches nil)
|
||||||
|
(xref-search-program 'grep)
|
||||||
|
(xref-show-xrefs-function
|
||||||
|
(lambda (fetcher _display)
|
||||||
|
(setq matches (funcall fetcher)))))
|
||||||
|
(project-find-regexp "etc")
|
||||||
|
(should (equal (mapcar (lambda (item)
|
||||||
|
(file-name-base
|
||||||
|
(xref-location-group (xref-item-location item))))
|
||||||
|
matches)
|
||||||
|
'(".dir-locals" "etc")))
|
||||||
|
(should (equal (sort (mapcar #'xref-item-summary matches) #'string<)
|
||||||
|
'("((nil . ((project-vc-ignores . (\"etc\")))))" "etc"))))))
|
||||||
|
|
||||||
;;; project-tests.el ends here
|
;;; project-tests.el ends here
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue