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)