[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/go-mode 5b5ac61 364/495: cmd/guru: emacs: highlight all in
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/go-mode 5b5ac61 364/495: cmd/guru: emacs: highlight all instances of an identifier |
Date: |
Sat, 7 Aug 2021 09:05:49 -0400 (EDT) |
branch: elpa/go-mode
commit 5b5ac61f79186bcd0887be92f599531b0c94daff
Author: Dominik Honnef <dominik@honnef.co>
Commit: Dominik Honnef <dominik@honnef.co>
cmd/guru: emacs: highlight all instances of an identifier
Implement the "what" query and use it to get all uses of an
identifier (the "sameids" attribute). The user can either manually call
go-guru-hl-identifier, which will highlight all instances of the
identifier under point, or they can enable the
go-guru-hl-identifier-mode minor mode. The minor mode sets up an idle
timer, which will highlight the current identifier after a configurable
timeout. If the user modifies the buffer, or moves point off of an
identifier, we clear the highlight.
Change-Id: Iac870f3bcd17e0002eafcba0b73f07adaa03cd76
Reviewed-on: https://go-review.googlesource.com/20433
Reviewed-by: Alan Donovan <adonovan@google.com>
---
guru_import/cmd/guru/go-guru.el | 130 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 128 insertions(+), 2 deletions(-)
diff --git a/guru_import/cmd/guru/go-guru.el b/guru_import/cmd/guru/go-guru.el
index fd54927..a7f814b 100644
--- a/guru_import/cmd/guru/go-guru.el
+++ b/guru_import/cmd/guru/go-guru.el
@@ -50,11 +50,29 @@
:type 'string
:group 'go-guru)
+(defface go-guru-hl-identifier-face
+ '((t (:inherit highlight)))
+ "Face used for highlighting identifiers in `go-guru-hl-identifier'."
+ :group 'go-guru)
+
(defcustom go-guru-debug nil
"Print debug messages when running guru."
:type 'boolean
:group 'go-guru)
+(defcustom go-guru-hl-identifier-idle-time 0.5
+ "How long to wait after user input before highlighting the current
identifier."
+ :type 'float
+ :group 'go-guru)
+
+(defvar go-guru--current-hl-identifier-idle-time
+ 0
+ "The current delay for hl-identifier-mode.")
+
+(defvar go-guru--hl-identifier-timer
+ nil
+ "The global timer used for highlighting identifiers.")
+
;; Extend go-mode-map.
(let ((m (define-prefix-command 'go-guru-map)))
(define-key m "d" #'go-guru-describe)
@@ -219,14 +237,24 @@ If BUFFER, return the number of characters in that buffer
instead."
(string-bytes (buffer-substring (point-min)
(point-max)))))
-
+;; FIXME(dominikh): go-guru--goto-pos-no-file and go-guru--goto-pos
+;; assume that Guru is giving rune offsets in the columns field.
+;; However, it is giving us byte offsets, causing us to highlight
+;; wrong ranges as soon as there's any multi-byte runes in the line.
(defun go-guru--goto-pos (posn)
"Find the file containing the position POSN (of the form `file:line:col')
set the point to it, switching the current buffer."
(let ((file-line-pos (split-string posn ":")))
(find-file (car file-line-pos))
(goto-char (point-min))
- ;; NB: go/token's column offsets are byte- not rune-based.
+ (forward-line (1- (string-to-number (cadr file-line-pos))))
+ (forward-char (1- (string-to-number (caddr file-line-pos))))))
+
+(defun go-guru--goto-pos-no-file (posn)
+ "Given `file:line:col', go to the line and column. The file
+component will be ignored."
+ (let ((file-line-pos (split-string posn ":")))
+ (goto-char (point-min))
(forward-line (1- (string-to-number (cadr file-line-pos))))
(forward-char (1- (string-to-number (caddr file-line-pos))))))
@@ -310,6 +338,104 @@ expression (of type 'error') may refer."
(interactive)
(go-guru--run "whicherrs" t))
+(defun go-guru-what ()
+ "Run a 'what' query and return the parsed JSON response as an
+associative list."
+ (let ((res (with-current-buffer (go-guru--exec "what" nil '("-format=json")
t)
+ (goto-char (point-min))
+ (cdr (car (json-read))))))
+ res))
+
+(defun go-guru--hl-symbols (posn face id)
+ "Highlight the symbols at the positions POSN by creating
+overlays with face FACE. The attribute 'go-guru-overlay on the
+overlays will be set to ID."
+ (save-excursion
+ (mapc (lambda (pos)
+ (go-guru--goto-pos-no-file pos)
+ (let ((x (make-overlay (point) (+ (point) (length
(current-word))))))
+ (overlay-put x 'go-guru-overlay id)
+ (overlay-put x 'face face)))
+ posn)))
+
+;;;###autoload
+(defun go-guru-unhighlight-identifiers ()
+ "Remove highlights from previously highlighted identifier."
+ (remove-overlays nil nil 'go-guru-overlay 'sameid))
+
+;;;###autoload
+(defun go-guru-hl-identifier ()
+ "Highlight all instances of the identifier under point. Removes
+highlights from previously highlighted identifier."
+ (interactive)
+ (go-guru-unhighlight-identifiers)
+ (go-guru--hl-identifier))
+
+(defun go-guru--hl-identifier ()
+ "Highlight all instances of the identifier under point."
+ (let ((posn (cdr (assoc 'sameids (go-guru-what)))))
+ (go-guru--hl-symbols posn 'go-guru-hl-identifier-face 'sameid)))
+
+(defun go-guru--hl-identifiers-function ()
+ "Function run after an idle timeout, highlighting the
+identifier at point, if necessary."
+ (when go-guru-hl-identifier-mode
+ (unless (go-guru--on-overlay-p 'sameid)
+ ;; Ignore guru errors. Otherwise, we might end up with an error
+ ;; every time the timer runs, e.g. because of a malformed
+ ;; buffer.
+ (condition-case nil
+ (go-guru-hl-identifier)
+ (error nil)))
+ (unless (eq go-guru--current-hl-identifier-idle-time
go-guru-hl-identifier-idle-time)
+ (go-guru--hl-set-timer))))
+
+(defun go-guru--hl-set-timer ()
+ (if go-guru--hl-identifier-timer
+ (cancel-timer go-guru--hl-identifier-timer))
+ (setq go-guru--current-hl-identifier-idle-time
go-guru-hl-identifier-idle-time)
+ (setq go-guru--hl-identifier-timer (run-with-idle-timer
+ go-guru-hl-identifier-idle-time
+ t
+ #'go-guru--hl-identifiers-function)))
+
+;;;###autoload
+(define-minor-mode go-guru-hl-identifier-mode
+ "Highlight instances of the identifier at point after a short
+timeout."
+ :group 'go-guru
+ (if go-guru-hl-identifier-mode
+ (progn
+ (go-guru--hl-set-timer)
+ ;; Unhighlight if point moves off identifier
+ (add-hook 'post-command-hook
#'go-guru--hl-identifiers-post-command-hook nil t)
+ ;; Unhighlight any time the buffer changes
+ (add-hook 'before-change-functions
#'go-guru--hl-identifiers-before-change-function nil t))
+ (remove-hook 'post-command-hook
#'go-guru--hl-identifiers-post-command-hook t)
+ (remove-hook 'before-change-functions
#'go-guru--hl-identifiers-before-change-function t)
+ (go-guru-unhighlight-identifiers)))
+
+(defun go-guru--on-overlay-p (id)
+ "Return whether point is on a guru overlay of type ID."
+ (find-if (lambda (el) (eq (overlay-get el 'go-guru-overlay) id))
(overlays-at (point))))
+
+(defun go-guru--hl-identifiers-post-command-hook ()
+ (if (and go-guru-hl-identifier-mode
+ (not (go-guru--on-overlay-p 'sameid)))
+ (go-guru-unhighlight-identifiers)))
+
+(defun go-guru--hl-identifiers-before-change-function (_beg _end)
+ (go-guru-unhighlight-identifiers))
+
+;; FIXME(dominikh): currently we're using the same buffer for
+;; interactive and non-interactive output. E.g. if a user ran the
+;; referrers query, and then the hl-identifier timer ran a what query,
+;; the what query's json response would be visible and overwrite the
+;; referrers output
+
+;; TODO(dominikh): a future feature may be to cycle through all uses
+;; of an identifier.
+
(provide 'go-guru)
;;; go-guru.el ends here
- [nongnu] elpa/go-mode 8560557 354/495: cmd/guru: fix bug in mode map caused by bad merge, (continued)
- [nongnu] elpa/go-mode 8560557 354/495: cmd/guru: fix bug in mode map caused by bad merge, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode b36d2fd 352/495: cmd/guru: emacs: report an error when the guru command fails, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode d41ebaf 341/495: go.tools/oracle: improvements to command set and performance., ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 385153c 338/495: go.tools/oracle: new query 'referrers' returns all references to an identifier., ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode f18b4eb 369/495: cmd/guru: support streaming plain and -json output, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 9a5284b 362/495: cmd/guru: emacs: update scope documentation, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 4dfa1c4 350/495: cmd/guru: add support for loading modified files, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode fdb5dfa 335/495: go.tools/oracle: change notation for byte offsets to "-pos=file.go:#123-#456", ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 1dc6fb5 357/495: cmd/guru: fix mode map, again, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode fac4a24 336/495: go.tools/importer: negate "cgo" build tag to avoid native code in "net"., ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 5b5ac61 364/495: cmd/guru: emacs: highlight all instances of an identifier,
ELPA Syncer <=
- [nongnu] elpa/go-mode 4146860 373/495: cmd/guru: Emacs: run guru asynchronously using compilation-mode, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 7077c4f 375/495: cmd/guru: fix quoting bug in Emacs binding, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 142eae4 374/495: cmd/guru: add menu to Emacs, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode eb8cf16 386/495: refactor/rename: emacs: package.el compatibility changes, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode bfc4f9b 385/495: tools/refactor/rename: add provide to rename.el, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 0604054 388/495: cmd/gorename: emacs: do not auto shrink error window, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 1b85887 389/495: refactor/rename: require cl-lib, use cl- namespace, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 8144ae8 392/495: Merge commit '12ef34c', ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 269eb01 398/495: Remove support for Emacs 23, ELPA Syncer, 2021/08/07
- [nongnu] elpa/go-mode 5056b85 403/495: Use xref functions if available, ELPA Syncer, 2021/08/07