Add 'project-relative' as value for 'xref-file-name-display'

* lisp/progmodes/xref.el (xref-file-name-display): Document new value.
(xref-location-group ((l xref-file-location))): Handle the new value.
(xref--project-root): Extract from the default method of
'xref-backend-references' so it can be used in above's new code.
Also fix an old bug in the "backward compat" branch.

* lisp/progmodes/xref.el (xref--project-root-memo): New variable.

* test/lisp/progmodes/xref-tests.el: Add test cases for the three
possible settings of 'xref-file-name-display'.

Co-authored-by: Tobias Rittweiler <trittweiler@gmail.com>
This commit is contained in:
Dmitry Gutov 2020-12-30 13:48:45 +02:00
parent dd662fc972
commit 13b59c690a
3 changed files with 76 additions and 8 deletions

View file

@ -1302,6 +1302,11 @@ have been renamed to have "proper" public names and documented
('xref-show-definitions-buffer' and
'xref-show-definitions-buffer-at-bottom').
---
*** New value 'project-relative' for 'xref-file-name-display'
If chosen, file names in *xref* buffers will be displayed relative
to the 'project-root' of the current project, when available.
** json.el
---

View file

@ -109,12 +109,20 @@ This is typically the filename.")
(defcustom xref-file-name-display 'abs
"Style of file name display in *xref* buffers.
If the value is the symbol `abs', the default, show the file names
in their full absolute form.
If `nondirectory', show only the nondirectory (a.k.a. \"base name\")
part of the file name."
part of the file name.
If `project-relative', show only the file name relative to the
current project root. If there is no current project, or if the
file resides outside of its root, show that particular file name
in its full absolute form."
:type '(choice (const :tag "absolute file name" abs)
(const :tag "nondirectory file name" nondirectory))
(const :tag "nondirectory file name" nondirectory)
(const :tag "relative to project root" project-relative))
:version "27.1")
;; FIXME: might be useful to have an optional "hint" i.e. a string to
@ -149,10 +157,31 @@ Line numbers start from 1 and columns from 0.")
(forward-char column))
(point-marker))))))
(defvar xref--project-root-memo nil
"Cons mapping `default-directory' value to the search root.")
(cl-defmethod xref-location-group ((l xref-file-location))
(cl-ecase xref-file-name-display
(abs (oref l file))
(nondirectory (file-name-nondirectory (oref l file)))))
(abs
(oref l file))
(nondirectory
(file-name-nondirectory (oref l file)))
(project-relative
(unless (and xref--project-root-memo
(equal (car xref--project-root-memo)
default-directory))
(setq xref--project-root-memo
(cons default-directory
(let ((root
(let ((pr (project-current)))
(and pr (xref--project-root pr)))))
(and root (expand-file-name root))))))
(let ((file (oref l file))
(search-root (cdr xref--project-root-memo)))
(if (and search-root
(string-prefix-p search-root file))
(substring file (length search-root))
file)))))
(defclass xref-buffer-location (xref-location)
((buffer :type buffer :initarg :buffer)
@ -273,10 +302,7 @@ current project's main and external roots."
(xref-references-in-directory identifier dir))
(let ((pr (project-current t)))
(cons
(if (fboundp 'project-root)
(project-root pr)
(with-no-warnings
(project-roots pr)))
(xref--project-root pr)
(project-external-roots pr)))))
(cl-defgeneric xref-backend-apropos (backend pattern)
@ -913,6 +939,12 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)."
(pop-to-buffer (current-buffer))
(current-buffer))))
(defun xref--project-root (project)
(if (fboundp 'project-root)
(project-root project)
(with-no-warnings
(car (project-roots project)))))
(defun xref--show-common-initialize (xref-alist fetcher alist)
(setq buffer-undo-list nil)
(let ((inhibit-read-only t)

View file

@ -97,3 +97,34 @@
(should (null (marker-position (cdr (nth 0 (cdr cons1))))))
(should (null (marker-position (car (nth 0 (cdr cons2))))))
(should (null (marker-position (cdr (nth 0 (cdr cons2))))))))
(ert-deftest xref--xref-file-name-display-is-abs ()
(let ((xref-file-name-display 'abs))
(should (equal (delete-dups
(mapcar 'xref-location-group
(xref-tests--locations-in-data-dir "\\(bar\\|foo\\)")))
(list
(concat xref-tests--data-dir "file1.txt")
(concat xref-tests--data-dir "file2.txt"))))))
(ert-deftest xref--xref-file-name-display-is-nondirectory ()
(let ((xref-file-name-display 'nondirectory))
(should (equal (delete-dups
(mapcar 'xref-location-group
(xref-tests--locations-in-data-dir "\\(bar\\|foo\\)")))
(list
"file1.txt"
"file2.txt")))))
(ert-deftest xref--xref-file-name-display-is-relative-to-project-root ()
(let* ((data-parent-dir
(file-name-directory (directory-file-name xref-tests--data-dir)))
(project-find-functions
#'(lambda (_) (cons 'transient data-parent-dir)))
(xref-file-name-display 'project-relative))
(should (equal (delete-dups
(mapcar 'xref-location-group
(xref-tests--locations-in-data-dir "\\(bar\\|foo\\)")))
(list
"xref-resources/file1.txt"
"xref-resources/file2.txt")))))