diff options
author | Dmitry Gutov <dgutov@yandex.ru> | 2021-10-01 00:02:21 +0300 |
---|---|---|
committer | Dmitry Gutov <dgutov@yandex.ru> | 2021-10-01 00:02:21 +0300 |
commit | 86da812afb2572c7fead2bb07570b976bffd7c55 (patch) | |
tree | 86af033eb09c8d524d8378f710c55734ee561625 /lisp/progmodes/xref.el | |
parent | 5c73dfcbcb12d107dfdad335328b7c258bdd64c8 (diff) | |
download | emacs-86da812afb2572c7fead2bb07570b976bffd7c55.tar.gz emacs-86da812afb2572c7fead2bb07570b976bffd7c55.tar.bz2 emacs-86da812afb2572c7fead2bb07570b976bffd7c55.zip |
Migrate Xref off EIEIO
To improve performance and flexibility (bug#50777).
* lisp/progmodes/xref.el (xref-location): Remove.
(xref-file-location): Change to cl-struct.
(xref-buffer-location, xref-bogus-location): Ditto.
(xref-item, xref-match-item): Same.
And update all method definitions accordingly.
(xref--insert-xrefs): Don't use 'oref', use 'xref-item-location'.
(xref--insert-xrefs, xref-show-definitions-completing-read):
Insetad of 'with-slots', use 'xref-item-summary' and
'xref-item-location'.
* lisp/progmodes/etags.el (xref-etags-location):
Change from EIEIO class into a cl-struct.
(xref-etags-apropos-location): Ditto.
Update all method definitions.
* test/lisp/progmodes/elisp-mode-tests.el (xref-elisp-test-run):
Avoid using 'oref'.
Diffstat (limited to 'lisp/progmodes/xref.el')
-rw-r--r-- | lisp/progmodes/xref.el | 154 |
1 files changed, 65 insertions, 89 deletions
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index 8906f6326a7..f151a980bbc 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -46,9 +46,9 @@ ;; ;; One would usually call `make-xref' and `xref-make-file-location', ;; `xref-make-buffer-location' or `xref-make-bogus-location' to create -;; them. More generally, a location must be an instance of an EIEIO -;; class inheriting from `xref-location' and implementing -;; `xref-location-group' and `xref-location-marker'. +;; them. More generally, a location must be an instance of a type for +;; which methods `xref-location-group' and `xref-location-marker' are +;; implemented. ;; ;; There's a special kind of xrefs we call "match xrefs", which ;; correspond to search results. For these values, @@ -62,12 +62,15 @@ ;; distinct, because the user can't see the properties when making the ;; choice. ;; +;; Older versions of Xref used EIEIO for implementation of the +;; built-in types, and included a class called `xref-location' which +;; was supposed to be inherited from. Neither is true anymore. +;; ;; See the etags and elisp-mode implementations for full examples. ;;; Code: (require 'cl-lib) -(require 'eieio) (require 'ring) (require 'project) @@ -78,9 +81,6 @@ ;;; Locations -(defclass xref-location () () - :documentation "A location represents a position in a file or buffer.") - (cl-defgeneric xref-location-marker (location) "Return the marker for LOCATION.") @@ -121,19 +121,20 @@ in its full absolute form." ;; FIXME: might be useful to have an optional "hint" i.e. a string to ;; search for in case the line number is slightly out of date. -(defclass xref-file-location (xref-location) - ((file :type string :initarg :file :reader xref-location-group) - (line :type fixnum :initarg :line :reader xref-location-line) - (column :type fixnum :initarg :column :reader xref-file-location-column)) - :documentation "A file location is a file/line/column triple. -Line numbers start from 1 and columns from 0.") +(cl-defstruct (xref-file-location + (:constructor xref-make-file-location (file line column))) + "A file location is a file/line/column triple. +Line numbers start from 1 and columns from 0." + file line column) -(defun xref-make-file-location (file line column) - "Create and return a new `xref-file-location'." - (make-instance 'xref-file-location :file file :line line :column column)) +(cl-defmethod xref-location-group ((l xref-file-location)) + (xref-file-location-file l)) + +(cl-defmethod xref-location-line ((l xref-file-location)) + (xref-file-location-line l)) (cl-defmethod xref-location-marker ((l xref-file-location)) - (with-slots (file line column) l + (pcase-let (((cl-struct xref-file-location file line column) l)) (with-current-buffer (or (get-file-buffer file) (let ((find-file-suppress-same-file-warnings t)) @@ -151,77 +152,51 @@ Line numbers start from 1 and columns from 0.") (forward-char column)) (point-marker)))))) -(defclass xref-buffer-location (xref-location) - ((buffer :type buffer :initarg :buffer) - (position :type fixnum :initarg :position))) - -(defun xref-make-buffer-location (buffer position) - "Create and return a new `xref-buffer-location'." - (make-instance 'xref-buffer-location :buffer buffer :position position)) +(cl-defstruct (xref-buffer-location + (:constructor xref-make-buffer-location (buffer position))) + buffer position) (cl-defmethod xref-location-marker ((l xref-buffer-location)) - (with-slots (buffer position) l + (pcase-let (((cl-struct xref-buffer-location buffer position) l)) (let ((m (make-marker))) (move-marker m position buffer)))) (cl-defmethod xref-location-group ((l xref-buffer-location)) - (with-slots (buffer) l + (pcase-let (((cl-struct xref-buffer-location buffer) l)) (or (buffer-file-name buffer) (format "(buffer %s)" (buffer-name buffer))))) -(defclass xref-bogus-location (xref-location) - ((message :type string :initarg :message - :reader xref-bogus-location-message)) - :documentation "Bogus locations are sometimes useful to -indicate errors, e.g. when we know that a function exists but the -actual location is not known.") - -(defun xref-make-bogus-location (message) - "Create and return a new `xref-bogus-location'." - (make-instance 'xref-bogus-location :message message)) +(cl-defstruct (xref-bogus-location + (:constructor xref-make-bogus-location (message))) + "Bogus locations are sometimes useful to indicate errors, +e.g. when we know that a function exists but the actual location +is not known." + message) (cl-defmethod xref-location-marker ((l xref-bogus-location)) - (user-error "%s" (oref l message))) + (user-error "%s" (xref-bogus-location-message l))) (cl-defmethod xref-location-group ((_ xref-bogus-location)) "(No location)") ;;; Cross-reference -(defclass xref-item () - ((summary :type string :initarg :summary - :reader xref-item-summary - :documentation "One line which will be displayed for -this item in the output buffer.") - (location :initarg :location - :reader xref-item-location - :documentation "An object describing how to navigate -to the reference's target.")) - :comment "An xref item describes a reference to a location -somewhere.") - -(defun xref-make (summary location) - "Create and return a new `xref-item'. -SUMMARY is a short string to describe the xref. -LOCATION is an `xref-location'." - (make-instance 'xref-item :summary summary :location location)) - -(defclass xref-match-item () - ((summary :type string :initarg :summary - :reader xref-item-summary) - (location :initarg :location - :type xref-location - :reader xref-item-location) - (length :initarg :length :reader xref-match-length)) - :comment "A match xref item describes a search result.") - -(defun xref-make-match (summary location length) - "Create and return a new `xref-match-item'. -SUMMARY is a short string to describe the xref. -LOCATION is an `xref-location'. -LENGTH is the match length, in characters." - (make-instance 'xref-match-item :summary summary - :location location :length length)) +(cl-defstruct (xref-item + (:constructor xref-make (summary location)) + (:noinline t)) + "An xref item describes a reference to a location somewhere." + summary location) + +(cl-defstruct (xref-match-item + (:include xref-item) + (:constructor xref-make-match (summary location length)) + (:noinline t)) + "A match xref item describes a search result." + length) + +(cl-defgeneric xref-match-length ((item xref-match-item)) + "Return the length of the match." + (xref-match-item-length item)) ;;; API @@ -970,7 +945,7 @@ GROUP is a string for decoration purposes and XREF is an for max-line-width = (cl-loop for xref in xrefs maximize (let ((line (xref-location-line - (oref xref location)))) + (xref-item-location xref)))) (and line (1+ (floor (log line 10)))))) for line-format = (and max-line-width (format "%%%dd: " max-line-width)) @@ -985,7 +960,7 @@ GROUP is a string for decoration purposes and XREF is an (xref--insert-propertized '(face xref-file-header xref-group t) group "\n") (cl-loop for xref in xrefs do - (with-slots (summary location) xref + (pcase-let (((cl-struct xref-item summary location) xref)) (let* ((line (xref-location-line location)) (prefix (cond @@ -1206,22 +1181,23 @@ between them by typing in the minibuffer with completion." (cl-loop for ((group . xrefs) . more1) on xref-alist do (cl-loop for (xref . more2) on xrefs do - (with-slots (summary location) xref - (let* ((line (xref-location-line location)) - (line-fmt - (if line - (format #("%d:" 0 2 (face xref-line-number)) - line) - "")) - (group-prefix - (substring group group-prefix-length)) - (group-fmt - (propertize group-prefix - 'face 'xref-file-header - 'xref--group group-prefix)) - (candidate - (format "%s:%s%s" group-fmt line-fmt summary))) - (push (cons candidate xref) xref-alist-with-line-info))))) + (let* ((summary (xref-item-summary xref)) + (location (xref-item-location xref)) + (line (xref-location-line location)) + (line-fmt + (if line + (format #("%d:" 0 2 (face xref-line-number)) + line) + "")) + (group-prefix + (substring group group-prefix-length)) + (group-fmt + (propertize group-prefix + 'face 'xref-file-header + 'xref--group group-prefix)) + (candidate + (format "%s:%s%s" group-fmt line-fmt summary))) + (push (cons candidate xref) xref-alist-with-line-info)))) (setq xref (if (not (cdr xrefs)) (car xrefs) |