From 5330a45ebff0214cc5c5d123e7cc68f00f68ff39 Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Mon, 20 Jul 2015 04:32:58 +0300 Subject: [PATCH] Add xref-match-item, and use it * lisp/progmodes/xref.el (xref-match-bounds): New generic function. (xref-file-location): Add reader for the column slot. (xref-match-item): New class. (xref-match-bounds): A method implementation for it. (xref-make-match): New constructor function. (xref--current-item): New private variable. (xref-pulse-momentarily): Use it. (xref--pop-to-location): Change the first argument to an xref item, instead of location, bind xref--current-item. Update all callers. (xref-next-line, xref-prev-line, xref--next-error-function) (xref--mouse-2): Look for the property `xref-item', instead of `xref-location'. (xref--item-at-point): Likewise. This function replaces `xref-location-at-point'. Update all callers. (xref--insert-xrefs): Add the `xref-item' text property, instead of `xref-location'. (xref--collect-match): Use xref-make-match. --- lisp/progmodes/xref.el | 107 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 73 insertions(+), 34 deletions(-) diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index a17550f445f..0847fdaf1b9 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -78,6 +78,10 @@ This is typically the filename.") "Return the line number corresponding to the location." nil) +(cl-defgeneric xref-match-bounds (_item) + "Return a cons with columns of the beginning and end of the match." + nil) + ;;;; Commonly needed location classes are defined here: ;; FIXME: might be useful to have an optional "hint" i.e. a string to @@ -85,7 +89,7 @@ This is typically the filename.") (defclass xref-file-location (xref-location) ((file :type string :initarg :file) (line :type fixnum :initarg :line :reader xref-location-line) - (column :type fixnum :initarg :column)) + (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.") @@ -165,6 +169,29 @@ 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-file-location + :reader xref-item-location) + (end-column :initarg :end-column)) + :comment "An xref item describes a reference to a location +somewhere.") + +(cl-defmethod xref-match-bounds ((i xref-match-item)) + (with-slots (end-column location) i + (cons (xref-file-location-column location) + end-column))) + +(defun xref-make-match (summary end-column location) + "Create and return a new xref match item. +SUMMARY is a short string to describe the xref. +END-COLUMN is the match end column number inside SUMMARY. +LOCATION is an `xref-location'." + (make-instance 'xref-match-item :summary summary :location location + :end-column end-column)) + ;;; API @@ -309,15 +336,22 @@ elements is negated." (set-marker marker nil nil) (run-hooks 'xref-after-return-hook)))) +(defvar xref--current-item nil) + (defun xref-pulse-momentarily () - (let (beg end) - (save-excursion - (back-to-indentation) - (if (eolp) - (setq beg (line-beginning-position) - end (1+ (point))) - (setq beg (point) - end (line-end-position)))) + (pcase-let ((`(,beg . ,end) + (save-excursion + (or + (let ((bounds (xref-match-bounds xref--current-item))) + (when bounds + (cons (progn (move-to-column (car bounds)) + (point)) + (progn (move-to-column (cdr bounds)) + (point))))) + (back-to-indentation) + (if (eolp) + (cons (line-beginning-position) (1+ (point))) + (cons (point) (line-end-position))))))) (pulse-momentary-highlight-region beg end 'next-error))) ;; etags.el needs this @@ -343,18 +377,19 @@ elements is negated." (t (error "Location is outside accessible part of buffer"))) (goto-char marker))) -(defun xref--pop-to-location (location &optional window) - "Goto xref-location LOCATION and display the buffer. +(defun xref--pop-to-location (item &optional window) + "Go to the location of ITEM and display the buffer. WINDOW controls how the buffer is displayed: nil -- switch-to-buffer 'window -- pop-to-buffer (other window) 'frame -- pop-to-buffer (other frame)" - (xref--goto-location location) + (xref--goto-location (xref-item-location item)) (cl-ecase window ((nil) (switch-to-buffer (current-buffer))) (window (pop-to-buffer (current-buffer) t)) (frame (let ((pop-up-frames t)) (pop-to-buffer (current-buffer) t)))) - (run-hooks 'xref-after-jump-hook)) + (let ((xref--current-item item)) + (run-hooks 'xref-after-jump-hook))) ;;; XREF buffer (part of the UI) @@ -414,26 +449,27 @@ Used for temporary buffers.") (defun xref-show-location-at-point () "Display the source of xref at point in the other window, if any." (interactive) - (let ((loc (xref--location-at-point))) - (when loc - (xref--show-location loc)))) + (let* ((xref (xref--item-at-point)) + (xref--current-item xref)) + (when xref + (xref--show-location (xref-item-location xref))))) (defun xref-next-line () "Move to the next xref and display its source in the other window." (interactive) - (xref--search-property 'xref-location) + (xref--search-property 'xref-item) (xref-show-location-at-point)) (defun xref-prev-line () "Move to the previous xref and display its source in the other window." (interactive) - (xref--search-property 'xref-location t) + (xref--search-property 'xref-item t) (xref-show-location-at-point)) -(defun xref--location-at-point () +(defun xref--item-at-point () (save-excursion (back-to-indentation) - (get-text-property (point) 'xref-location))) + (get-text-property (point) 'xref-item))) (defvar-local xref--window nil "ACTION argument to call `display-buffer' with.") @@ -441,11 +477,11 @@ Used for temporary buffers.") (defun xref-goto-xref () "Jump to the xref on the current line and bury the xref buffer." (interactive) - (let ((loc (or (xref--location-at-point) + (let ((xref (or (xref--item-at-point) (user-error "No reference at point"))) (window xref--window)) (xref-quit) - (xref--pop-to-location loc window))) + (xref--pop-to-location xref window))) (defvar xref--xref-buffer-mode-map (let ((map (make-sparse-keymap))) @@ -470,11 +506,11 @@ Used for temporary buffers.") (goto-char (point-min))) (let ((backward (< n 0)) (n (abs n)) - (loc nil)) + (xref nil)) (dotimes (_ n) - (setq loc (xref--search-property 'xref-location backward))) - (cond (loc - (xref--pop-to-location loc)) + (setq (xref--search-property 'xref-item backward))) + (cond (xref + (xref--pop-to-location xref)) (t (error "No %s xref" (if backward "previous" "next")))))) @@ -518,7 +554,7 @@ meantime are preserved." (interactive "e") (mouse-set-point event) (forward-line 0) - (xref--search-property 'xref-location) + (xref--search-property 'xref-item) (xref-show-location-at-point)) (defun xref--insert-xrefs (xref-alist) @@ -546,7 +582,7 @@ GROUP is a string for decoration purposes and XREF is an 'face 'compilation-line-number) " "))) (xref--insert-propertized - (list 'xref-location location + (list 'xref-item xref ;; 'face 'font-lock-keyword-face 'mouse-face 'highlight 'keymap xref--button-map @@ -603,7 +639,7 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)." (user-error "No %s found for: %s" (symbol-name kind) input)) ((not (cdr xrefs)) (xref-push-marker-stack) - (xref--pop-to-location (xref-item-location (car xrefs)) window)) + (xref--pop-to-location (car xrefs) window)) (t (xref-push-marker-stack) (funcall xref-show-xrefs-function xrefs @@ -866,11 +902,14 @@ IGNORES is a list of glob patterns." (syntax-propertize (line-end-position)) (when (re-search-forward regexp (line-end-position) t) (goto-char (match-beginning 0)) - (xref-make (buffer-substring - (line-beginning-position) - (line-end-position)) - (xref-make-file-location file line - (current-column)))))))) + (let ((loc (xref-make-file-location file line + (current-column)))) + (goto-char (match-end 0)) + (xref-make-match (buffer-substring + (line-beginning-position) + (line-end-position)) + (current-column) + loc))))))) (provide 'xref) -- 2.11.4.GIT