diff options
| author | Dmitry Gutov | 2015-11-14 13:02:35 +0200 |
|---|---|---|
| committer | Dmitry Gutov | 2015-11-14 13:02:35 +0200 |
| commit | f234fc2cb319de1e5e2eca1a84450ec220ce7955 (patch) | |
| tree | 37134b43d4270bf955757a7c7f571756b493c7a8 /lisp/progmodes | |
| parent | 4d71d2471aaf341791fd728287bf8db62aebb3ba (diff) | |
| parent | 138ad3d93b7abe08ac399f582aa6c8aac869e17e (diff) | |
| download | emacs-f234fc2cb319de1e5e2eca1a84450ec220ce7955.tar.gz emacs-f234fc2cb319de1e5e2eca1a84450ec220ce7955.zip | |
Merge branch 'master' into emacs-25
Diffstat (limited to 'lisp/progmodes')
| -rw-r--r-- | lisp/progmodes/elisp-mode.el | 41 | ||||
| -rw-r--r-- | lisp/progmodes/etags.el | 21 | ||||
| -rw-r--r-- | lisp/progmodes/xref.el | 249 |
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 | |||
| 638 | non-nil result supercedes the xrefs produced by | 621 | non-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.") |
| 181 | somewhere.") | ||
| 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'. |
| 190 | SUMMARY is a short string to describe the xref. | 195 | SUMMARY is a short string to describe the xref. |
| 191 | END-COLUMN is the match end column number inside SUMMARY. | 196 | LOCATION is an `xref-location'. |
| 192 | LOCATION is an `xref-location'." | 197 | LENGTH 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. | ||
| 208 | Each functions on this hook is called in turn with no arguments | ||
| 209 | and should return either nil to mean that it is not applicable, | ||
| 210 | or an xref backend, which is a value to be used to dispatch the | ||
| 211 | generic 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. | ||
| 205 | It can be called in several ways: | ||
| 206 | 215 | ||
| 207 | (definitions IDENTIFIER): Find definitions of IDENTIFIER. The | 216 | (defun xref--etags-backend () 'etags) |
| 208 | result must be a list of xref objects. If IDENTIFIER contains | ||
| 209 | sufficient information to determine a unique definition, returns | ||
| 210 | only that definition. If there are multiple possible definitions, | ||
| 211 | return 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) |
| 214 | result must be a list of xref objects. If no references can be | 219 | "Find definitions of IDENTIFIER. |
| 215 | found, return nil. | ||
| 216 | 220 | ||
| 217 | (apropos PATTERN): Find all symbols that match PATTERN. PATTERN | 221 | The result must be a list of xref objects. If IDENTIFIER |
| 218 | is a regexp. | 222 | contains sufficient information to determine a unique definition, |
| 223 | return only that definition. If there are multiple possible | ||
| 224 | definitions, return all of them. If no definitions can be found, | ||
| 225 | return nil. | ||
| 219 | 226 | ||
| 220 | IDENTIFIER can be any string returned by | 227 | IDENTIFIER 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 |
| 222 | by `xref-identifier-completion-table-function'. | 229 | `xref-backend-identifier-completion-table'. |
| 223 | 230 | ||
| 224 | To create an xref object, call `xref-make'.") | 231 | To 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. |
| 235 | The result must be a list of xref objects. If no references can | ||
| 236 | be found, return nil.") | ||
| 237 | |||
| 238 | (cl-defgeneric xref-backend-apropos (backend pattern) | ||
| 239 | "Find all symbols that match PATTERN. | ||
| 240 | PATTERN is a regexp") | ||
| 241 | |||
| 242 | (cl-defgeneric xref-backend-identifier-at-point (_backend) | ||
| 243 | "Return the relevant identifier at point. | ||
| 228 | 244 | ||
| 229 | The return value must be a string or nil. nil means no | 245 | The return value must be a string or nil. nil means no |
| 230 | identifier at point found. | 246 | identifier at point found. |
| @@ -232,16 +248,14 @@ identifier at point found. | |||
| 232 | If it's hard to determine the identifier precisely (e.g., because | 248 | If it's hard to determine the identifier precisely (e.g., because |
| 233 | it's a method call on unknown type), the implementation can | 249 | it's a method call on unknown type), the implementation can |
| 234 | return a simple string (such as symbol at point) marked with a | 250 | return a simple string (such as symbol at point) marked with a |
| 235 | special text property which `xref-find-function' would recognize | 251 | special text property which e.g. `xref-backend-definitions' would |
| 236 | and then delegate the work to an external process.") | 252 | recognize 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 | ||