1

If I have a list of file locations in elisp, how would I create an xref window, showing these locations?

ideasman42
  • 8,375
  • 1
  • 28
  • 105

3 Answers3

1

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.

Dmitry
  • 3,508
  • 15
  • 20
1

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.

ideasman42
  • 8,375
  • 1
  • 28
  • 105
0

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
          ))
       )))
  • 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