diff --git a/modules/config/default/+bindings.el b/modules/config/default/+bindings.el index b7251d7af..b88300234 100644 --- a/modules/config/default/+bindings.el +++ b/modules/config/default/+bindings.el @@ -324,6 +324,7 @@ :m "gT" #'+workspace/switch-left :m "gd" #'+lookup/definition :m "gD" #'+lookup/references + :n "gf" #'+lookup/file :n "gp" #'+evil/reselect-paste :v "gp" #'+evil/paste-preserve-register :n "gr" #'+eval:region diff --git a/modules/feature/lookup/autoload/lookup.el b/modules/feature/lookup/autoload/lookup.el index 9aace7db3..b248c18d3 100644 --- a/modules/feature/lookup/autoload/lookup.el +++ b/modules/feature/lookup/autoload/lookup.el @@ -28,7 +28,8 @@ (cl-loop with origin = (point-marker) for fn in (plist-get (list :definition +lookup-definition-functions :references +lookup-references-functions - :documentation +lookup-documentation-functions) + :documentation +lookup-documentation-functions + :file +lookup-file-functions) prop) for fn = (or (command-remapping fn) fn) if (condition-case e @@ -159,6 +160,51 @@ Goes down a list of possible backends: identifier (+lookup--online-provider (not current-prefix-arg)))))) +;;;###autoload +(defun +lookup/file (path) + "Figure out PATH from whatever is at point and open it. + +Each function in `+lookup-file-functions' is tried until one changes the point +or the current buffer. + +Otherwise, falls back on `find-file-at-point'." + (interactive + (progn + (require 'ffap) + (list + (or (ffap-guesser) + (ffap-read-file-or-url + (if ffap-url-regexp "Find file or URL: " "Find file: ") + (+lookup--symbol-or-region)))))) + (require 'ffap) + (cond ((not path) + (call-interactively #'find-file-at-point)) + + ((ffap-url-p path) + (find-file-at-point path)) + + ((not (and +lookup-file-functions + (+lookup--jump-to :file path))) + (let ((fullpath (expand-file-name path))) + (when (file-equal-p fullpath buffer-file-name) + (user-error "Already here")) + (let* ((insert-default-directory t) + (project-root (doom-project-root 'nocache)) + (ffap-file-finder + (cond ((not (file-directory-p fullpath)) + #'find-file) + ((file-in-directory-p fullpath project-root) + (lambda (dir) + (let ((default-directory dir)) + (without-project-cache! + (let ((file (projectile-completing-read "Find file: " + (projectile-current-project-files) + :initial-input path))) + (find-file (expand-file-name file (projectile-project-root))) + (run-hooks 'projectile-find-file-hook)))))) + (#'doom-project-browse)))) + (find-file-at-point path)))))) + ;; ;; Source-specific commands @@ -229,4 +275,5 @@ for the provider." (after! evil (evil-set-command-property '+lookup/definition :jump t) (evil-set-command-property '+lookup/references :jump t) - (evil-set-command-property '+lookup/documentation :jump t)) + (evil-set-command-property '+lookup/documentation :jump t) + (evil-set-command-property '+lookup/file :jump t)) diff --git a/modules/feature/lookup/config.el b/modules/feature/lookup/config.el index 37f4df9f3..8b5b1d611 100644 --- a/modules/feature/lookup/config.el +++ b/modules/feature/lookup/config.el @@ -36,17 +36,38 @@ produces an url. Used by `+lookup/online'.") (defvar +lookup-definition-functions '(+lookup-xref-definitions) "Functions for `+lookup/definition' to try, before resorting to `dumb-jump'. Stops at the first function to return non-nil or change the current -window/point.") +window/point. + +If the argument is interactive (satisfies `commandp'), it is called with +`call-interactively' (with no arguments). Otherwise, it is called with one +argument: the identifier at point.") (defvar +lookup-references-functions '(+lookup-xref-references) "Functions for `+lookup/references' to try, before resorting to `dumb-jump'. Stops at the first function to return non-nil or change the current -window/point.") +window/point. + +If the argument is interactive (satisfies `commandp'), it is called with +`call-interactively' (with no arguments). Otherwise, it is called with one +argument: the identifier at point.") (defvar +lookup-documentation-functions () "Functions for `+lookup/documentation' to try, before resorting to `dumb-jump'. Stops at the first function to return non-nil or change the current -window/point.") +window/point. + +If the argument is interactive (satisfies `commandp'), it is called with +`call-interactively' (with no arguments). Otherwise, it is called with one +argument: the identifier at point.") + +(defvar +lookup-file-functions () + "Function for `+lookup/file' to try, before restoring to `find-file-at-point'. +Stops at the first function to return non-nil or change the current +window/point. + +If the argument is interactive (satisfies `commandp'), it is called with +`call-interactively' (with no arguments). Otherwise, it is called with one +argument: the identifier at point.") (def-setting! :lookup (modes &rest plist) "Defines a jump target for major MODES. PLIST accepts the following @@ -61,6 +82,9 @@ properties: :documentation FN Run when looking up documentation for a symbol. Used by `+lookup/documentation'. + :file FN + Run when looking up the file for a symbol/string. Typically a file path. + Used by `+lookup/file'. :xref-backend FN Defines an xref backend for a major-mode. With this, :definition and :references are unnecessary. @@ -77,10 +101,12 @@ ones." (let ((xref ,(plist-get plist :xref-backend)) (def ,(plist-get plist :definition)) (ref ,(plist-get plist :references)) + (fil ,(plist-get plist :file)) (doc ,(plist-get plist :documentation))) (if xref (add-hook 'xref-backend-functions xref nil t)) (if def (add-hook '+lookup-definition-functions def nil t)) (if ref (add-hook '+lookup-references-functions ref nil t)) + (if fil (add-hook '+lookup-file-functions fil nil t)) (if doc (add-hook '+lookup-documentation-functions doc nil t))))) collect `(add-hook! ,mode #',def-name))))