From a6e7145b40637c28a4020adedf4079ffcee2f6a9 Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Fri, 11 Apr 2025 21:36:14 +0200 Subject: [PATCH] Improve elisp 'xref-backend-references'. --- lisp/emacs-lisp/subr-x.el | 1 + lisp/progmodes/elisp-mode.el | 55 ++++++++++++++++++++++++++---------- lisp/progmodes/xref.el | 17 +++++++++++ 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el index 50b10a32400..2df580e4211 100644 --- a/lisp/emacs-lisp/subr-x.el +++ b/lisp/emacs-lisp/subr-x.el @@ -321,6 +321,7 @@ automatically killed, which means that in a such case buffer (generate-new-buffer " *work*" t)))) +;;;###autoload (defun work-buffer--release (buffer) "Release work BUFFER." (if (buffer-live-p buffer) diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index a9451fbda19..7cb079e75be 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el @@ -850,7 +850,9 @@ in `completion-at-point-functions' (which see)." ;;; Xref backend (declare-function xref-make "progmodes/xref" (summary location)) +(declare-function xref-make-match "progmodes/xref" (summary location length)) (declare-function xref-item-location "progmodes/xref" (this)) +(declare-function xref-make-file-pos-location "progmodes/xref" (file pos line)) (declare-function xref-make-buffer-location "progmodes/xref" (buffer position)) (defun elisp--xref-backend () 'elisp) @@ -1123,11 +1125,25 @@ confidence." (lambda (file) (string= (file-name-extension file) "el")) (project-files (project-current)))) "Scanning for references" - (with-current-buffer (find-file-noselect file) - (pcase-dolist (`(,type ,beg ,len . ,_) (elisp-symbols-index)) - (and (or (null types) (memq type types)) - (string= identifier (buffer-substring-no-properties beg (+ beg len))) - (push (elisp-make-xref beg len) res))))) + (pcase-dolist (`(,type ,beg ,len ,sym . ,_) (elisp-symbols-index file)) + (and (or (null types) (memq type types)) + (string= identifier sym) + (with-work-buffer + (insert-file-contents file) + (goto-char beg) + (push + (let* ((begg (pos-bol)) + (endd (pos-eol)) + (line (buffer-substring begg endd)) + (cur (- beg begg))) + (add-face-text-property + cur (+ len cur) 'xref-match t line) + (xref-make-match + line + (xref-make-file-pos-location + file beg (line-number-at-pos beg)) + len)) + res))))) (nreverse res)) ;; (cl-call-next-method backend identifier) ))) @@ -1141,7 +1157,7 @@ confidence." (line (buffer-substring begg end)) (cur (- beg begg))) (add-face-text-property cur (+ len cur) 'xref-match t line) - (xref-make line (xref-make-buffer-location (current-buffer) beg)))) + (xref-make-match line (xref-make-buffer-location (current-buffer) beg) len))) (defun elisp-make-xrefs (all) (let (res) @@ -2652,22 +2668,31 @@ of TARGET." (put 'read-symbol-shorthands 'safe-local-variable #'consp) -(defvar-local elisp-symbols-index-cache nil) +(defvar elisp-symbols-index-cache (make-hash-table :test #'equal)) -(defun elisp-symbols-index () - (cdr (if (<= (buffer-chars-modified-tick) - (or (car elisp-symbols-index-cache) 0)) - elisp-symbols-index-cache - (setq elisp-symbols-index-cache - (cons (buffer-chars-modified-tick) - (elisp-symbols-index-1)))))) +(defun elisp-symbols-index (file) + (let ((cached (gethash file elisp-symbols-index-cache)) + (modtime (file-attribute-modification-time (file-attributes file)))) + (cdr + (if (time-less-p (or (car cached) 0) modtime) + (puthash file (cons modtime + (with-work-buffer + (insert-file-contents file) + (elisp-symbols-index-1))) + elisp-symbols-index-cache) + cached)))) (defun elisp-symbols-index-1 () (let (all) (save-excursion (goto-char (point-min)) (condition-case e - (while t (scope (lambda (&rest args) (push args all)))) + (while t + (scope + (lambda (type beg len &rest _) + (push + (list type beg len (buffer-substring beg (+ beg len))) + all)))) (end-of-file (nreverse all)) (error (message "Encountered error while scanning %s: %S" buffer-file-name e) nil))))) diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index 5ce0e53654a..0ba209bc72d 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -165,6 +165,23 @@ Line numbers start from 1 and columns from 0." (forward-char column)) (point-marker)))))) +(cl-defstruct (xref-file-pos-location + (:constructor xref-make-file-pos-location (file pos line))) + "A specific position in a given file." + file pos line) + +(cl-defmethod xref-location-marker ((l xref-file-pos-location)) + (with-current-buffer + (let ((find-file-suppress-same-file-warnings t)) + (find-file-noselect (xref-file-pos-location-file l))) + (copy-marker (xref-file-pos-location-pos l)))) + +(cl-defmethod xref-location-group ((l xref-file-pos-location)) + (xref-file-pos-location-file l)) + +(cl-defmethod xref-location-line ((l xref-file-pos-location)) + (xref-file-pos-location-line l)) + (cl-defstruct (xref-buffer-location (:constructor xref-make-buffer-location (buffer position))) buffer position) -- 2.39.5