If I have a list of file locations in elisp, how would I create an xref window, showing these locations?
3 Answers
You will need to convert that list to "xref item" values.
See xref--collect-matches-1
for how this is done. Since your locations are not "xref matches", though, you will call xref-make
instead of xref-make-match
, and won't need the length
argument.
Note that you will also need the string contents on that line (it will be shown in the xref buffer as "summary").
To show the list, you call xref--show-xrefs
. The first argument, fetcher
, must be a function that returns that list we computed above. Depending on how you retrieve that list, the fetcher could call the retrieval logic as well and then create the xref items from the result. Then xref-revert-buffer
will work as expected in such buffers.
Alternatively, if the list is static, fetcher can just process that list (by either looking up a lexical var up the scope, or some global var defined in the package). Also, for now, fetcher
can be a simple list (of xref items). But that's an obsolete convention.
Note that xref--show-xrefs
is ostensibly a "private" function. But it should be stable enough in the near future.

- 3,508
- 15
- 20
This function creates an xref
buffer from a list of references (thanks to @Dmitry's answer).
(defun my-xref-from-file-references (file-references)
"Create an xref buffer from FILE-REFERENCES ((file line column display-text) ...)."
;; Needed for xref API.
(require 'xref)
(let ((xrefs (list)))
(dolist (item file-references)
(pcase-let ((`(,file ,line ,col ,display-text) item))
(push (xref-make display-text (xref-make-file-location file line col)) xrefs))
(xref--show-xrefs (lambda () xrefs) nil))))
Note that (filepath line column)
isn't quite enough information for xref
, so a display-text
has been included which would typically be the line of text - but can be anything.

- 8,375
- 1
- 28
- 105
Not an answer, but too much code for a comment.
May be you can reuse and adapt this code:
(save-excursion
(and ;;; try finding file from make buffer javac error
(re-search-forward "(\\(\\([A-Za-z]:\\)?\\.?\\.?/?[a-zA-Z0-9._/+-]+\\.[a-zA-Z0-9_/,+-]+\\):\\([0-9]+\\))" nil t)
(or
(and
(file-readable-p (match-string 1))
(let ((file (match-string 1)) (line (string-to-int (match-string 3))))
(find-file file) (goto-line line) (recenter) t
))
(and
(get-buffer (file-name-nondirectory (match-string 1)))
(let ((file (get-buffer (file-name-nondirectory (match-string 1)))) (line (string-to-int (match-string 3))))
(switch-to-buffer file) (goto-line line) (recenter) t
))
)))

- 101
- 3
-
This seems more like a way to step over lines of text (as xref does), not xref. If this is all thats needed compilation-mode can already do this. The reason I ask about xref is it gives some extra functionality for stepping over references, which are nice to have. I rather not have to re-implement xref. – ideasman42 Oct 23 '20 at 01:07
-
@ideasman42 Yes, definitely not xref, and as I said, not an answer but too much text for a comment. This snippet jumps from an error line of javac to the corresponding source line in a (possibly new) buffer. Please copy the code, if it is any help to you and leave me a comment so that I can delete this. – Gyro Gearloose Oct 24 '20 at 12:28
-
I have a function where many such snippets are encased by (or ...) so that the function opens a buffer to the first match. I use this quite a lot and would be lost without it. – Gyro Gearloose Oct 24 '20 at 12:32