aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes
diff options
context:
space:
mode:
authorDmitry Gutov2015-11-14 13:02:35 +0200
committerDmitry Gutov2015-11-14 13:02:35 +0200
commitf234fc2cb319de1e5e2eca1a84450ec220ce7955 (patch)
tree37134b43d4270bf955757a7c7f571756b493c7a8 /lisp/progmodes
parent4d71d2471aaf341791fd728287bf8db62aebb3ba (diff)
parent138ad3d93b7abe08ac399f582aa6c8aac869e17e (diff)
downloademacs-f234fc2cb319de1e5e2eca1a84450ec220ce7955.tar.gz
emacs-f234fc2cb319de1e5e2eca1a84450ec220ce7955.zip
Merge branch 'master' into emacs-25
Diffstat (limited to 'lisp/progmodes')
-rw-r--r--lisp/progmodes/elisp-mode.el41
-rw-r--r--lisp/progmodes/etags.el21
-rw-r--r--lisp/progmodes/xref.el249
3 files changed, 159 insertions, 152 deletions
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index af2ea56dcee..2c22483e86f 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -228,8 +228,7 @@ Blank lines separate paragraphs. Semicolons start comments.
228 228
229\\{emacs-lisp-mode-map}" 229\\{emacs-lisp-mode-map}"
230 :group 'lisp 230 :group 'lisp
231 (defvar xref-find-function) 231 (defvar xref-backend-functions)
232 (defvar xref-identifier-completion-table-function)
233 (defvar project-library-roots-function) 232 (defvar project-library-roots-function)
234 (lisp-mode-variables nil nil 'elisp) 233 (lisp-mode-variables nil nil 'elisp)
235 (add-hook 'after-load-functions #'elisp--font-lock-flush-elisp-buffers) 234 (add-hook 'after-load-functions #'elisp--font-lock-flush-elisp-buffers)
@@ -239,9 +238,7 @@ Blank lines separate paragraphs. Semicolons start comments.
239 (setq imenu-case-fold-search nil) 238 (setq imenu-case-fold-search nil)
240 (add-function :before-until (local 'eldoc-documentation-function) 239 (add-function :before-until (local 'eldoc-documentation-function)
241 #'elisp-eldoc-documentation-function) 240 #'elisp-eldoc-documentation-function)
242 (setq-local xref-find-function #'elisp-xref-find) 241 (add-hook 'xref-backend-functions #'elisp--xref-backend nil t)
243 (setq-local xref-identifier-completion-table-function
244 #'elisp--xref-identifier-completion-table)
245 (setq-local project-library-roots-function #'elisp-library-roots) 242 (setq-local project-library-roots-function #'elisp-library-roots)
246 (add-hook 'completion-at-point-functions 243 (add-hook 'completion-at-point-functions
247 #'elisp-completion-at-point nil 'local)) 244 #'elisp-completion-at-point nil 'local))
@@ -588,21 +585,7 @@ It can be quoted, or be inside a quoted form."
588(declare-function xref-make "xref" (summary location)) 585(declare-function xref-make "xref" (summary location))
589(declare-function xref-collect-references "xref" (symbol dir)) 586(declare-function xref-collect-references "xref" (symbol dir))
590 587
591(defun elisp-xref-find (action id) 588(defun elisp--xref-backend () 'elisp)
592 (require 'find-func)
593 ;; FIXME: use information in source near point to filter results:
594 ;; (dvc-log-edit ...) - exclude 'feature
595 ;; (require 'dvc-log-edit) - only 'feature
596 ;; Semantic may provide additional information
597 (pcase action
598 (`definitions
599 (let ((sym (intern-soft id)))
600 (when sym
601 (elisp--xref-find-definitions sym))))
602 (`references
603 (elisp--xref-find-references id))
604 (`apropos
605 (elisp--xref-find-apropos id))))
606 589
607;; WORKAROUND: This is nominally a constant, but the text properties 590;; WORKAROUND: This is nominally a constant, but the text properties
608;; are not preserved thru dump if use defconst. See bug#21237. 591;; are not preserved thru dump if use defconst. See bug#21237.
@@ -638,7 +621,17 @@ Each function should return a list of xrefs, or nil; the first
638non-nil result supercedes the xrefs produced by 621non-nil result supercedes the xrefs produced by
639`elisp--xref-find-definitions'.") 622`elisp--xref-find-definitions'.")
640 623
641;; FIXME: name should be singular; match xref-find-definition 624(cl-defmethod xref-backend-definitions ((_backend (eql elisp)) identifier)
625 (require 'find-func)
626 ;; FIXME: use information in source near point to filter results:
627 ;; (dvc-log-edit ...) - exclude 'feature
628 ;; (require 'dvc-log-edit) - only 'feature
629 ;; Semantic may provide additional information
630 ;;
631 (let ((sym (intern-soft identifier)))
632 (when sym
633 (elisp--xref-find-definitions sym))))
634
642(defun elisp--xref-find-definitions (symbol) 635(defun elisp--xref-find-definitions (symbol)
643 ;; The file name is not known when `symbol' is defined via interactive eval. 636 ;; The file name is not known when `symbol' is defined via interactive eval.
644 (let (xrefs) 637 (let (xrefs)
@@ -805,7 +798,7 @@ non-nil result supercedes the xrefs produced by
805(declare-function project-roots "project") 798(declare-function project-roots "project")
806(declare-function project-current "project") 799(declare-function project-current "project")
807 800
808(defun elisp--xref-find-references (symbol) 801(cl-defmethod xref-backend-references ((_backend (eql elisp)) symbol)
809 "Find all references to SYMBOL (a string) in the current project." 802 "Find all references to SYMBOL (a string) in the current project."
810 (cl-mapcan 803 (cl-mapcan
811 (lambda (dir) 804 (lambda (dir)
@@ -815,7 +808,7 @@ non-nil result supercedes the xrefs produced by
815 (project-roots pr) 808 (project-roots pr)
816 (project-library-roots pr))))) 809 (project-library-roots pr)))))
817 810
818(defun elisp--xref-find-apropos (regexp) 811(cl-defmethod xref-backend-apropos ((_backend (eql elisp)) regexp)
819 (apply #'nconc 812 (apply #'nconc
820 (let (lst) 813 (let (lst)
821 (dolist (sym (apropos-internal regexp)) 814 (dolist (sym (apropos-internal regexp))
@@ -832,7 +825,7 @@ non-nil result supercedes the xrefs produced by
832 (facep sym))) 825 (facep sym)))
833 'strict)) 826 'strict))
834 827
835(defun elisp--xref-identifier-completion-table () 828(cl-defmethod xref-backend-identifier-completion-table ((_backend (eql elisp)))
836 elisp--xref-identifier-completion-table) 829 elisp--xref-identifier-completion-table)
837 830
838(cl-defstruct (xref-elisp-location 831(cl-defstruct (xref-elisp-location
diff --git a/lisp/progmodes/etags.el b/lisp/progmodes/etags.el
index 38c5cc2bdb6..ae1aa11fbc2 100644
--- a/lisp/progmodes/etags.el
+++ b/lisp/progmodes/etags.el
@@ -2084,17 +2084,12 @@ for \\[find-tag] (which see)."
2084 2084
2085(defvar etags-xref-find-definitions-tag-order '(tag-exact-match-p 2085(defvar etags-xref-find-definitions-tag-order '(tag-exact-match-p
2086 tag-implicit-name-match-p) 2086 tag-implicit-name-match-p)
2087 "Tag order used in `etags-xref-find' to look for definitions.") 2087 "Tag order used in `xref-backend-definitions' to look for definitions.")
2088 2088
2089;;;###autoload 2089(cl-defmethod xref-backend-identifier-completion-table ((_backend (eql etags)))
2090(defun etags-xref-find (action id) 2090 (tags-lazy-completion-table))
2091 (pcase action 2091
2092 (`definitions (etags--xref-find-definitions id)) 2092(cl-defmethod xref-backend-references ((_backend (eql etags)) symbol)
2093 (`references (etags--xref-find-references id))
2094 (`apropos (etags--xref-find-definitions id t))))
2095
2096(defun etags--xref-find-references (symbol)
2097 ;; TODO: Merge together with the Elisp impl.
2098 (cl-mapcan 2093 (cl-mapcan
2099 (lambda (dir) 2094 (lambda (dir)
2100 (xref-collect-references symbol dir)) 2095 (xref-collect-references symbol dir))
@@ -2103,6 +2098,12 @@ for \\[find-tag] (which see)."
2103 (project-roots pr) 2098 (project-roots pr)
2104 (project-library-roots pr))))) 2099 (project-library-roots pr)))))
2105 2100
2101(cl-defmethod xref-backend-definitions ((_backend (eql etags)) symbol)
2102 (etags--xref-find-definitions symbol))
2103
2104(cl-defmethod xref-backend-apropos ((_backend (eql etags)) symbol)
2105 (etags--xref-find-definitions symbol t))
2106
2106(defun etags--xref-find-definitions (pattern &optional regexp?) 2107(defun etags--xref-find-definitions (pattern &optional regexp?)
2107 ;; This emulates the behaviour of `find-tag-in-order' but instead of 2108 ;; This emulates the behaviour of `find-tag-in-order' but instead of
2108 ;; returning one match at a time all matches are returned as list. 2109 ;; returning one match at a time all matches are returned as list.
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 89a06046ca2..6a3b42ff646 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -23,14 +23,21 @@
23;; referencing commands, in particular "find-definition". 23;; referencing commands, in particular "find-definition".
24;; 24;;
25;; Some part of the functionality must be implemented in a language 25;; Some part of the functionality must be implemented in a language
26;; dependent way and that's done by defining `xref-find-function', 26;; dependent way and that's done by defining an xref backend.
27;; `xref-identifier-at-point-function' and
28;; `xref-identifier-completion-table-function', which see.
29;; 27;;
30;; A major mode should make these variables buffer-local first. 28;; That consists of a constructor function, which should return a
29;; backend value, and a set of implementations for the generic
30;; functions:
31;; 31;;
32;; `xref-find-function' can be called in several ways, see its 32;; `xref-backend-identifier-at-point',
33;; description. It has to operate with "xref" and "location" values. 33;; `xref-backend-identifier-completion-table',
34;; `xref-backend-definitions', `xref-backend-references',
35;; `xref-backend-apropos', which see.
36;;
37;; A major mode would normally use `add-hook' to add the backend
38;; constructor to `xref-backend-functions'.
39;;
40;; The last three methods operate with "xref" and "location" values.
34;; 41;;
35;; One would usually call `make-xref' and `xref-make-file-location', 42;; One would usually call `make-xref' and `xref-make-file-location',
36;; `xref-make-buffer-location' or `xref-make-bogus-location' to create 43;; `xref-make-buffer-location' or `xref-make-bogus-location' to create
@@ -38,15 +45,19 @@
38;; class inheriting from `xref-location' and implementing 45;; class inheriting from `xref-location' and implementing
39;; `xref-location-group' and `xref-location-marker'. 46;; `xref-location-group' and `xref-location-marker'.
40;; 47;;
48;; There's a special kind of xrefs we call "match xrefs", which
49;; correspond to search results. For these values,
50;; `xref-match-length' must be defined, and `xref-location-marker'
51;; must return the beginning of the match.
52;;
41;; Each identifier must be represented as a string. Implementers can 53;; Each identifier must be represented as a string. Implementers can
42;; use string properties to store additional information about the 54;; use string properties to store additional information about the
43;; identifier, but they should keep in mind that values returned from 55;; identifier, but they should keep in mind that values returned from
44;; `xref-identifier-completion-table-function' should still be 56;; `xref-backend-identifier-completion-table' should still be
45;; distinct, because the user can't see the properties when making the 57;; distinct, because the user can't see the properties when making the
46;; choice. 58;; choice.
47;; 59;;
48;; See the functions `etags-xref-find' and `elisp-xref-find' for full 60;; See the etags and elisp-mode implementations for full examples.
49;; examples.
50 61
51;;; Code: 62;;; Code:
52 63
@@ -79,8 +90,8 @@ This is typically the filename.")
79 "Return the line number corresponding to the location." 90 "Return the line number corresponding to the location."
80 nil) 91 nil)
81 92
82(cl-defgeneric xref-match-bounds (_item) 93(cl-defgeneric xref-match-length (_item)
83 "Return a cons with columns of the beginning and end of the match." 94 "Return the length of the match."
84 nil) 95 nil)
85 96
86;;;; Commonly needed location classes are defined here: 97;;;; Commonly needed location classes are defined here:
@@ -109,7 +120,7 @@ Line numbers start from 1 and columns from 0.")
109 (save-excursion 120 (save-excursion
110 (goto-char (point-min)) 121 (goto-char (point-min))
111 (beginning-of-line line) 122 (beginning-of-line line)
112 (move-to-column column) 123 (forward-char column)
113 (point-marker)))))) 124 (point-marker))))))
114 125
115(cl-defmethod xref-location-group ((l xref-file-location)) 126(cl-defmethod xref-location-group ((l xref-file-location))
@@ -176,55 +187,60 @@ LOCATION is an `xref-location'."
176 (location :initarg :location 187 (location :initarg :location
177 :type xref-file-location 188 :type xref-file-location
178 :reader xref-item-location) 189 :reader xref-item-location)
179 (end-column :initarg :end-column)) 190 (length :initarg :length :reader xref-match-length))
180 :comment "An xref item describes a reference to a location 191 :comment "A match xref item describes a search result.")
181somewhere.")
182
183(cl-defmethod xref-match-bounds ((i xref-match-item))
184 (with-slots (end-column location) i
185 (cons (xref-file-location-column location)
186 end-column)))
187 192
188(defun xref-make-match (summary end-column location) 193(defun xref-make-match (summary location length)
189 "Create and return a new `xref-match-item'. 194 "Create and return a new `xref-match-item'.
190SUMMARY is a short string to describe the xref. 195SUMMARY is a short string to describe the xref.
191END-COLUMN is the match end column number inside SUMMARY. 196LOCATION is an `xref-location'.
192LOCATION is an `xref-location'." 197LENGTH is the match length, in characters."
193 (make-instance 'xref-match-item :summary summary :location location 198 (make-instance 'xref-match-item :summary summary
194 :end-column end-column)) 199 :location location :length length))
195 200
196 201
197;;; API 202;;; API
198 203
199(declare-function etags-xref-find "etags" (action id)) 204;; We make the etags backend the default for now, until something
200(declare-function tags-lazy-completion-table "etags" ()) 205;; better comes along.
206(defvar xref-backend-functions (list #'xref--etags-backend)
207 "Special hook to find the xref backend for the current context.
208Each functions on this hook is called in turn with no arguments
209and should return either nil to mean that it is not applicable,
210or an xref backend, which is a value to be used to dispatch the
211generic functions.")
201 212
202;; For now, make the etags backend the default. 213(defun xref-find-backend ()
203(defvar xref-find-function #'etags-xref-find 214 (run-hook-with-args-until-success 'xref-backend-functions))
204 "Function to look for cross-references.
205It can be called in several ways:
206 215
207 (definitions IDENTIFIER): Find definitions of IDENTIFIER. The 216(defun xref--etags-backend () 'etags)
208result must be a list of xref objects. If IDENTIFIER contains
209sufficient information to determine a unique definition, returns
210only that definition. If there are multiple possible definitions,
211return all of them. If no definitions can be found, return nil.
212 217
213 (references IDENTIFIER): Find references of IDENTIFIER. The 218(cl-defgeneric xref-backend-definitions (backend identifier)
214result must be a list of xref objects. If no references can be 219 "Find definitions of IDENTIFIER.
215found, return nil.
216 220
217 (apropos PATTERN): Find all symbols that match PATTERN. PATTERN 221The result must be a list of xref objects. If IDENTIFIER
218is a regexp. 222contains sufficient information to determine a unique definition,
223return only that definition. If there are multiple possible
224definitions, return all of them. If no definitions can be found,
225return nil.
219 226
220IDENTIFIER can be any string returned by 227IDENTIFIER can be any string returned by
221`xref-identifier-at-point-function', or from the table returned 228`xref-backend-identifier-at-point', or from the table returned by
222by `xref-identifier-completion-table-function'. 229`xref-backend-identifier-completion-table'.
223 230
224To create an xref object, call `xref-make'.") 231To create an xref object, call `xref-make'.")
225 232
226(defvar xref-identifier-at-point-function #'xref-default-identifier-at-point 233(cl-defgeneric xref-backend-references (backend identifier)
227 "Function to get the relevant identifier at point. 234 "Find references of IDENTIFIER.
235The result must be a list of xref objects. If no references can
236be found, return nil.")
237
238(cl-defgeneric xref-backend-apropos (backend pattern)
239 "Find all symbols that match PATTERN.
240PATTERN is a regexp")
241
242(cl-defgeneric xref-backend-identifier-at-point (_backend)
243 "Return the relevant identifier at point.
228 244
229The return value must be a string or nil. nil means no 245The return value must be a string or nil. nil means no
230identifier at point found. 246identifier at point found.
@@ -232,16 +248,14 @@ identifier at point found.
232If it's hard to determine the identifier precisely (e.g., because 248If it's hard to determine the identifier precisely (e.g., because
233it's a method call on unknown type), the implementation can 249it's a method call on unknown type), the implementation can
234return a simple string (such as symbol at point) marked with a 250return a simple string (such as symbol at point) marked with a
235special text property which `xref-find-function' would recognize 251special text property which e.g. `xref-backend-definitions' would
236and then delegate the work to an external process.") 252recognize and then delegate the work to an external process."
237
238(defvar xref-identifier-completion-table-function #'tags-lazy-completion-table
239 "Function that returns the completion table for identifiers.")
240
241(defun xref-default-identifier-at-point ()
242 (let ((thing (thing-at-point 'symbol))) 253 (let ((thing (thing-at-point 'symbol)))
243 (and thing (substring-no-properties thing)))) 254 (and thing (substring-no-properties thing))))
244 255
256(cl-defgeneric xref-backend-identifier-completion-table (backend)
257 "Returns the completion table for identifiers.")
258
245 259
246;;; misc utilities 260;;; misc utilities
247(defun xref--alistify (list key test) 261(defun xref--alistify (list key test)
@@ -345,22 +359,14 @@ elements is negated."
345 (pcase-let ((`(,beg . ,end) 359 (pcase-let ((`(,beg . ,end)
346 (save-excursion 360 (save-excursion
347 (or 361 (or
348 (xref--match-buffer-bounds xref--current-item) 362 (let ((length (xref-match-length xref--current-item)))
363 (and length (cons (point) (+ (point) length))))
349 (back-to-indentation) 364 (back-to-indentation)
350 (if (eolp) 365 (if (eolp)
351 (cons (line-beginning-position) (1+ (point))) 366 (cons (line-beginning-position) (1+ (point)))
352 (cons (point) (line-end-position))))))) 367 (cons (point) (line-end-position)))))))
353 (pulse-momentary-highlight-region beg end 'next-error))) 368 (pulse-momentary-highlight-region beg end 'next-error)))
354 369
355(defun xref--match-buffer-bounds (item)
356 (save-excursion
357 (let ((bounds (xref-match-bounds item)))
358 (when bounds
359 (cons (progn (move-to-column (car bounds))
360 (point))
361 (progn (move-to-column (cdr bounds))
362 (point)))))))
363
364;; etags.el needs this 370;; etags.el needs this
365(defun xref-clear-marker-stack () 371(defun xref-clear-marker-stack ()
366 "Discard all markers from the marker stack." 372 "Discard all markers from the marker stack."
@@ -487,50 +493,54 @@ WINDOW controls how the buffer is displayed:
487 (progn 493 (progn
488 (save-excursion 494 (save-excursion
489 (goto-char (point-min)) 495 (goto-char (point-min))
490 ;; TODO: Check that none of the matches are out of date;
491 ;; offer to re-scan otherwise. Note that saving the last
492 ;; modification tick won't work, as long as not all of the
493 ;; buffers are kept open.
494 (while (setq item (xref--search-property 'xref-item)) 496 (while (setq item (xref--search-property 'xref-item))
495 (when (xref-match-bounds item) 497 (when (xref-match-length item)
496 (save-excursion 498 (save-excursion
497 ;; FIXME: Get rid of xref--goto-location, by making 499 (let* ((loc (xref-item-location item))
498 ;; xref-match-bounds return markers already. 500 (beg (xref-location-marker loc))
499 (xref--goto-location (xref-item-location item)) 501 (len (xref-match-length item)))
500 (let ((bounds (xref--match-buffer-bounds item)) 502 ;; Perform sanity check first.
501 (beg (make-marker)) 503 (xref--goto-location loc)
502 (end (make-marker))) 504 ;; FIXME: The check should probably be a generic
503 (move-marker beg (car bounds)) 505 ;; function, instead of the assumption that all
504 (move-marker end (cdr bounds)) 506 ;; matches contain the full line as summary.
505 (push (cons beg end) pairs))))) 507 ;; TODO: Offer to re-scan otherwise.
508 (unless (equal (buffer-substring-no-properties
509 (line-beginning-position)
510 (line-end-position))
511 (xref-item-summary item))
512 (user-error "Search results out of date"))
513 (push (cons beg len) pairs)))))
506 (setq pairs (nreverse pairs))) 514 (setq pairs (nreverse pairs)))
507 (unless pairs (user-error "No suitable matches here")) 515 (unless pairs (user-error "No suitable matches here"))
508 (xref--query-replace-1 from to pairs)) 516 (xref--query-replace-1 from to pairs))
509 (dolist (pair pairs) 517 (dolist (pair pairs)
510 (move-marker (car pair) nil) 518 (move-marker (car pair) nil)))))
511 (move-marker (cdr pair) nil)))))
512 519
520;; FIXME: Write a nicer UI.
513(defun xref--query-replace-1 (from to pairs) 521(defun xref--query-replace-1 (from to pairs)
514 (let* ((query-replace-lazy-highlight nil) 522 (let* ((query-replace-lazy-highlight nil)
515 current-pair current-buf 523 current-beg current-len current-buf
516 ;; Counteract the "do the next match now" hack in 524 ;; Counteract the "do the next match now" hack in
517 ;; `perform-replace'. And still, it'll report that those 525 ;; `perform-replace'. And still, it'll report that those
518 ;; matches were "filtered out" at the end. 526 ;; matches were "filtered out" at the end.
519 (isearch-filter-predicate 527 (isearch-filter-predicate
520 (lambda (beg end) 528 (lambda (beg end)
521 (and current-pair 529 (and current-beg
522 (eq (current-buffer) current-buf) 530 (eq (current-buffer) current-buf)
523 (>= beg (car current-pair)) 531 (>= beg current-beg)
524 (<= end (cdr current-pair))))) 532 (<= end (+ current-beg current-len)))))
525 (replace-re-search-function 533 (replace-re-search-function
526 (lambda (from &optional _bound noerror) 534 (lambda (from &optional _bound noerror)
527 (let (found) 535 (let (found pair)
528 (while (and (not found) pairs) 536 (while (and (not found) pairs)
529 (setq current-pair (pop pairs) 537 (setq pair (pop pairs)
530 current-buf (marker-buffer (car current-pair))) 538 current-beg (car pair)
539 current-len (cdr pair)
540 current-buf (marker-buffer current-beg))
531 (pop-to-buffer current-buf) 541 (pop-to-buffer current-buf)
532 (goto-char (car current-pair)) 542 (goto-char current-beg)
533 (when (re-search-forward from (cdr current-pair) noerror) 543 (when (re-search-forward from (+ current-beg current-len) noerror)
534 (setq found t))) 544 (setq found t)))
535 found)))) 545 found))))
536 ;; FIXME: Despite this being a multi-buffer replacement, `N' 546 ;; FIXME: Despite this being a multi-buffer replacement, `N'
@@ -695,7 +705,8 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)."
695 705
696(defun xref--read-identifier (prompt) 706(defun xref--read-identifier (prompt)
697 "Return the identifier at point or read it from the minibuffer." 707 "Return the identifier at point or read it from the minibuffer."
698 (let ((id (funcall xref-identifier-at-point-function))) 708 (let* ((backend (xref-find-backend))
709 (id (xref-backend-identifier-at-point backend)))
699 (cond ((or current-prefix-arg 710 (cond ((or current-prefix-arg
700 (not id) 711 (not id)
701 (xref--prompt-p this-command)) 712 (xref--prompt-p this-command))
@@ -705,7 +716,7 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)."
705 "[ :]+\\'" prompt)) 716 "[ :]+\\'" prompt))
706 id) 717 id)
707 prompt) 718 prompt)
708 (funcall xref-identifier-completion-table-function) 719 (xref-backend-identifier-completion-table backend)
709 nil nil nil 720 nil nil nil
710 'xref--read-identifier-history id)) 721 'xref--read-identifier-history id))
711 (t id)))) 722 (t id))))
@@ -714,7 +725,9 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)."
714;;; Commands 725;;; Commands
715 726
716(defun xref--find-xrefs (input kind arg window) 727(defun xref--find-xrefs (input kind arg window)
717 (let ((xrefs (funcall xref-find-function kind arg))) 728 (let ((xrefs (funcall (intern (format "xref-backend-%s" kind))
729 (xref-find-backend)
730 arg)))
718 (unless xrefs 731 (unless xrefs
719 (user-error "No %s found for: %s" (symbol-name kind) input)) 732 (user-error "No %s found for: %s" (symbol-name kind) input))
720 (xref--show-xrefs xrefs window))) 733 (xref--show-xrefs xrefs window)))
@@ -799,14 +812,9 @@ and just use etags."
799 :lighter "" 812 :lighter ""
800 (if xref-etags-mode 813 (if xref-etags-mode
801 (progn 814 (progn
802 (setq xref-etags-mode--saved 815 (setq xref-etags-mode--saved xref-backend-functions)
803 (cons xref-find-function 816 (kill-local-variable 'xref-backend-functions))
804 xref-identifier-completion-table-function)) 817 (setq-local xref-backend-functions xref-etags-mode--saved)))
805 (kill-local-variable 'xref-find-function)
806 (kill-local-variable 'xref-identifier-completion-table-function))
807 (setq-local xref-find-function (car xref-etags-mode--saved))
808 (setq-local xref-identifier-completion-table-function
809 (cdr xref-etags-mode--saved))))
810 818
811(declare-function semantic-symref-find-references-by-name "semantic/symref") 819(declare-function semantic-symref-find-references-by-name "semantic/symref")
812(declare-function semantic-find-file-noselect "semantic/fw") 820(declare-function semantic-find-file-noselect "semantic/fw")
@@ -826,10 +834,11 @@ tools are used, and when."
826 (hits (and res (oref res hit-lines))) 834 (hits (and res (oref res hit-lines)))
827 (orig-buffers (buffer-list))) 835 (orig-buffers (buffer-list)))
828 (unwind-protect 836 (unwind-protect
829 (delq nil 837 (cl-mapcan (lambda (hit) (xref--collect-matches
830 (mapcar (lambda (hit) (xref--collect-match 838 hit (format "\\_<%s\\_>" (regexp-quote symbol))))
831 hit (format "\\_<%s\\_>" (regexp-quote symbol)))) 839 hits)
832 hits)) 840 ;; TODO: Implement "lightweight" buffer visiting, so that we
841 ;; don't have to kill them.
833 (mapc #'kill-buffer 842 (mapc #'kill-buffer
834 (cl-set-difference (buffer-list) orig-buffers))))) 843 (cl-set-difference (buffer-list) orig-buffers)))))
835 844
@@ -860,9 +869,9 @@ IGNORES is a list of glob patterns."
860 (match-string 1)) 869 (match-string 1))
861 hits))) 870 hits)))
862 (unwind-protect 871 (unwind-protect
863 (delq nil 872 (cl-mapcan (lambda (hit) (xref--collect-matches hit regexp))
864 (mapcar (lambda (hit) (xref--collect-match hit regexp)) 873 (nreverse hits))
865 (nreverse hits))) 874 ;; TODO: Same as above.
866 (mapc #'kill-buffer 875 (mapc #'kill-buffer
867 (cl-set-difference (buffer-list) orig-buffers))))) 876 (cl-set-difference (buffer-list) orig-buffers)))))
868 877
@@ -918,7 +927,7 @@ IGNORES is a list of glob patterns."
918 (match-string 1 str))))) 927 (match-string 1 str)))))
919 str t t)) 928 str t t))
920 929
921(defun xref--collect-match (hit regexp) 930(defun xref--collect-matches (hit regexp)
922 (pcase-let* ((`(,line . ,file) hit) 931 (pcase-let* ((`(,line . ,file) hit)
923 (buf (or (find-buffer-visiting file) 932 (buf (or (find-buffer-visiting file)
924 (semantic-find-file-noselect file)))) 933 (semantic-find-file-noselect file))))
@@ -926,18 +935,22 @@ IGNORES is a list of glob patterns."
926 (save-excursion 935 (save-excursion
927 (goto-char (point-min)) 936 (goto-char (point-min))
928 (forward-line (1- line)) 937 (forward-line (1- line))
929 (syntax-propertize (line-end-position)) 938 (let ((line-end (line-end-position))
930 ;; TODO: Handle multiple matches per line. 939 (line-beg (line-beginning-position))
931 (when (re-search-forward regexp (line-end-position) t) 940 matches)
932 (goto-char (match-beginning 0)) 941 (syntax-propertize line-end)
933 (let ((loc (xref-make-file-location file line 942 ;; FIXME: This results in several lines with the same
934 (current-column)))) 943 ;; summary. Solve with composite pattern?
935 (goto-char (match-end 0)) 944 (while (re-search-forward regexp line-end t)
936 (xref-make-match (buffer-substring 945 (let* ((beg-column (- (match-beginning 0) line-beg))
937 (line-beginning-position) 946 (end-column (- (match-end 0) line-beg))
938 (line-end-position)) 947 (loc (xref-make-file-location file line beg-column))
939 (current-column) 948 (summary (buffer-substring line-beg line-end)))
940 loc))))))) 949 (add-face-text-property beg-column end-column 'highlight
950 t summary)
951 (push (xref-make-match summary loc (- end-column beg-column))
952 matches)))
953 (nreverse matches))))))
941 954
942(provide 'xref) 955(provide 'xref)
943 956