From 37cb0e178cf136379c2bdb0e6c1c321ea149224a Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Tue, 8 Jan 2019 00:33:38 -0500 Subject: [PATCH] Make set-lookup-handlers! additive Consecutive calls to set-lookup-handlers! would redefine *all* lookup handlers, unsetting unspecified ones, so you were forced to redefine all handlers, even if you only wanted to change one. No more. Its side effects are now additive. Also adds :async handler support, however, due to their nature, they cannot fall back to other handlers (there's no reliable way to detect they worked or not). To get around this, write a blocking wrapper around the old async method and register it as a non-async handler. --- modules/feature/lookup/autoload/lookup.el | 104 ++++++++++++++-------- modules/lang/javascript/config.el | 2 +- 2 files changed, 66 insertions(+), 40 deletions(-) diff --git a/modules/feature/lookup/autoload/lookup.el b/modules/feature/lookup/autoload/lookup.el index 8f115a4a4..6ff84bd29 100644 --- a/modules/feature/lookup/autoload/lookup.el +++ b/modules/feature/lookup/autoload/lookup.el @@ -2,6 +2,8 @@ (defvar +lookup--last-provider nil) +(defvar +lookup--handler-alist nil) + ;;;###autodef (defun set-lookup-handlers! (modes &rest plist) "Define a jump target for major MODES. @@ -31,22 +33,42 @@ Otherwise, these properties are available to be set: :xref-backend FN Defines an xref backend for a major-mode. If you define :definition and :references along with :xref-backend, those will have higher precedence. +:async BOOL + Indicates that the supplied handlers *after* this property are asynchronous. + Note: async handlers do not fall back to the default handlers, due to their + nature. To get around this, you must write specialized wrappers to wait for + the async response and return 'fallback. -\(fn MODE-OR-MODES &key DEFINITION REFERENCES DOCUMENTATION FILE XREF-BACKEND)" +\(fn MODE-OR-MODES &key ASYNC DEFINITION REFERENCES DOCUMENTATION FILE XREF-BACKEND)" (declare (indent defun)) (dolist (mode (doom-enlist modes)) (let ((hook (intern (format "%s-hook" mode))) (fn (intern (format "+lookup|init-%s" mode)))) (cond ((null (car plist)) (remove-hook hook fn) + (setq +lookup--handler-alist + (delq (assq mode +lookup--handler-alist) + +lookup--handler-alist)) (unintern fn nil)) - ((fset fn + ((let ((old-plist (cdr (assq mode +lookup--handler-alist))) + async) + (while plist + (let ((prop (pop plist)) + (fns (pop plist))) + (if (eq prop :async) + (setq async t) + (dolist (fn (doom-enlist fns)) + (put fn '+lookup-async async)) + (setq old-plist (plist-put old-plist prop fns))))) + (setq plist old-plist) + (setf (alist-get mode +lookup--handler-alist) plist)) + (fset fn (lambda () (when (or (eq major-mode mode) (and (boundp mode) (symbol-value mode))) (cl-destructuring-bind - (&key definition references documentation file xref-backend) + (&key definition references documentation file xref-backend async) plist (when definition (add-hook '+lookup-definition-functions definition nil t)) @@ -86,29 +108,39 @@ Otherwise, these properties are available to be set: (xref-backend-identifier-at-point (xref-find-backend))))) (defun +lookup--jump-to (prop identifier &optional other-window) - (cl-loop with origin = (point-marker) - for fn - in (plist-get (list :definition +lookup-definition-functions - :references +lookup-references-functions - :documentation +lookup-documentation-functions - :file +lookup-file-functions) - prop) - for cmd = (or (command-remapping fn) fn) - if (condition-case e - (save-window-excursion - (when (or (if (commandp cmd) - (call-interactively cmd) - (funcall cmd identifier)) - (/= (point-marker) origin)) - (point-marker))) - (error (ignore (message "%s" e)))) - return - (progn - (funcall (if other-window - #'pop-to-buffer - #'pop-to-buffer-same-window) - (marker-buffer it)) - (goto-char it)))) + ;; TODO Refactor me + (let ((origin (point-marker))) + (cl-loop for fn + in (plist-get (list :definition +lookup-definition-functions + :references +lookup-references-functions + :documentation +lookup-documentation-functions + :file +lookup-file-functions) + prop) + for cmd = (or (command-remapping fn) fn) + if (get fn '+lookup-async) + return + (progn + (when other-window + ;; If async, we can't catch the window change or destination buffer + ;; reliably, so we set up the new window ahead of time. + (switch-to-buffer-other-window (current-buffer)) + (goto-char (marker-position origin))) + (call-interactively fn)) + if (condition-case e + (save-window-excursion + (when (or (if (commandp cmd) + (call-interactively cmd) + (funcall cmd identifier)) + (/= (point-marker) origin)) + (point-marker))) + (error (ignore (message "%s" e)))) + return + (progn + (funcall (if other-window + #'switch-to-buffer-other-window + #'switch-to-buffer) + (marker-buffer it)) + (goto-char it))))) (defun +lookup--file-search (identifier) (unless identifier @@ -214,8 +246,7 @@ evil-mode is active." current-prefix-arg)) (cond ((null identifier) (user-error "Nothing under point")) - ((and +lookup-definition-functions - (+lookup--jump-to :definition identifier other-window))) + ((+lookup--jump-to :definition identifier other-window)) ((error "Couldn't find the definition of '%s'" identifier)))) @@ -231,8 +262,7 @@ search otherwise." current-prefix-arg)) (cond ((null identifier) (user-error "Nothing under point")) - ((and +lookup-references-functions - (+lookup--jump-to :references identifier other-window))) + ((+lookup--jump-to :references identifier other-window)) ((error "Couldn't find references of '%s'" identifier)))) @@ -240,18 +270,15 @@ search otherwise." (defun +lookup/documentation (identifier &optional other-window) "Show documentation for IDENTIFIER (defaults to symbol at point or selection. -Goes down a list of possible backends: - -1. The :documentation spec defined with by `set-lookup-handlers!' -2. If the +docsets flag is active for :feature lookup, use `+lookup/in-docsets' -3. Fall back to an online search, with `+lookup/online'" +First attempts the :documentation handler specified with `set-lookup-handlers!' +for the current mode/buffer (if any), then falls back to the backends in +`+lookup-documentation-functions'." (interactive (list (+lookup--symbol-or-region) current-prefix-arg)) (cond ((null identifier) (user-error "Nothing under point")) - ((and +lookup-documentation-functions - (+lookup--jump-to :documentation identifier other-window))) + ((+lookup--jump-to :documentation identifier other-window)) ((user-error "Couldn't find documentation for '%s'" identifier)))) @@ -279,8 +306,7 @@ Otherwise, falls back on `find-file-at-point'." ((ffap-url-p path) (find-file-at-point path)) - ((not (and +lookup-file-functions - (+lookup--jump-to :file path))) + ((not (+lookup--jump-to :file path)) (let ((fullpath (expand-file-name path))) (when (and buffer-file-name (file-equal-p fullpath buffer-file-name)) (user-error "Already here")) diff --git a/modules/lang/javascript/config.el b/modules/lang/javascript/config.el index 92d6c33a3..e71b88505 100644 --- a/modules/lang/javascript/config.el +++ b/modules/lang/javascript/config.el @@ -148,7 +148,7 @@ (setq-default company-backends (delq 'company-tide (default-value 'company-backends)))) (set-company-backend! 'tide-mode 'company-tide) ;; navigation - (set-lookup-handlers! 'tide-mode + (set-lookup-handlers! 'tide-mode :async t :definition #'tide-jump-to-definition :references #'tide-references :documentation #'tide-documentation-at-point)