133 lines
5.3 KiB
EmacsLisp
133 lines
5.3 KiB
EmacsLisp
;;; syd-handle-lookup.el -*- lexical-binding: t; -*-
|
|
|
|
(require 'syd-text)
|
|
|
|
(use-package better-jumper)
|
|
|
|
(require 'better-jumper)
|
|
|
|
(defvar syd-lookup-online-documentation-backends
|
|
`(("Kagi" . "https://kagi.com/search?q=%s")
|
|
("DuckDuckGo" . "https://duckduckgo.com/?q=%s")
|
|
("Nixpkgs" . "https://search.nixos.org/packages?query=%s")
|
|
("Hackage" . "https://hackage.haskell.org/packages/search?terms=%s")
|
|
("The Free Dictionary" . "https://www.thefreedictionary.com/%s")
|
|
("The Free Thesaurus" . "https://www.freethesaurus.com/%s"))
|
|
"A list of pairs (NAME . BACKEND) describing the various backends
|
|
`syd-lookup-online-documentation' may delegate to.
|
|
|
|
NAME is a string used when speaking to the user about BACKEND.
|
|
|
|
If BACKEND is an interactive command, it will be called interactively.
|
|
|
|
If BACKEND is a procedure, it will be called with the search string as the lone
|
|
argument.
|
|
|
|
If BACKEND is a string, the user's browser will be opened to the URL returned by
|
|
(format BACKEND QUERY), where QUERY is the appropriately-encoded search
|
|
string.")
|
|
|
|
(defvar syd-lookup-documentation-handlers '(syd-lookup-online-documentation)
|
|
"A list of lookup handlers used to find documentation. A lookup handler
|
|
receives an identifier, and is expected to return nil on failure, and non-nil on
|
|
success. When a handler returns a marker, the marker will be jumped to.")
|
|
|
|
(defun syd-lookup--prompt-for-online-backend ()
|
|
(assoc-string
|
|
(completing-read "Search with: "
|
|
(mapcar #'car syd-lookup-online-documentation-backends)
|
|
nil
|
|
t)
|
|
syd-lookup-online-documentation-backends))
|
|
|
|
(cl-defun syd-lookup--call-online-backend (backend &key query-string)
|
|
(pcase-let ((`(,name . ,backend-fn) backend))
|
|
(cond ((functionp backend-fn) (if (commandp backend-fn)
|
|
(call-interactively backend-fn)
|
|
(funcall backend-fn query-string)))
|
|
((stringp backend-fn)
|
|
(browse-url (format backend-fn
|
|
(url-encode-url
|
|
(read-string (format "Search %s for: "
|
|
name)
|
|
query-string)))))
|
|
(t (signal 'wrong-type-argument `("backend" ,backend-fn))))))
|
|
|
|
;;;###autoload
|
|
(cl-defun syd-lookup-online-documentation (backend &key query-string)
|
|
(interactive (list (syd-lookup--prompt-for-online-backend)
|
|
:query-string (when (use-region-p)
|
|
(syd-thing-at-point-or-region))))
|
|
(syd-lookup--call-online-backend backend
|
|
:query-string query-string))
|
|
|
|
;;;###autoload
|
|
(defun syd-lookup-documentation (identifier)
|
|
"Try to find documentation on IDENTIFIER, and "
|
|
(interactive (list (syd-thing-at-point-or-region)))
|
|
(or (syd-lookup--jump-to 'documentation identifier
|
|
:display-fn #'display-buffer)
|
|
(user-error "Couldn't find documentation on %S"
|
|
(substring-no-properties identifier))))
|
|
|
|
(defvar syd-lookup--handlers-by-category
|
|
'((documentation . syd-lookup-documentation-handlers)))
|
|
|
|
(cl-defun syd-lookup--jump-to
|
|
(category identifier &key (display-fn #'switch-to-buffer))
|
|
(let* ((handlers (alist-get category syd-lookup--handlers-by-category))
|
|
(origin (point-marker))
|
|
;; TODO: If called with a prefix argument, prompt the user to select a
|
|
;; handler.
|
|
(result (run-hook-wrapped handlers #'syd-lookup--run-handler
|
|
identifier origin)))
|
|
(unwind-protect
|
|
(when (cond ((null result)
|
|
(message "No lookup handler could find %S" identifier)
|
|
nil)
|
|
((markerp result)
|
|
(let ((b (marker-buffer result)))
|
|
(funcall display-fn b)
|
|
(when (eq (current-buffer) b)
|
|
(goto-char result)))
|
|
result)
|
|
(result))
|
|
(with-current-buffer (marker-buffer origin)
|
|
(better-jumper-set-jump (marker-position origin)))
|
|
result))
|
|
(set-marker origin nil)))
|
|
|
|
(defun syd-lookup--run-handler (handler identifier origin)
|
|
(condition-case-unless-debug e
|
|
(let ((wconf (current-window-configuration))
|
|
(result (condition-case-unless-debug e
|
|
(if (commandp handler)
|
|
(call-interactively handler)
|
|
(funcall handler identifier))
|
|
(error
|
|
(message "Lookup handler %S threw an error: %s" handler e)
|
|
'fail))))
|
|
(cond ((eq result 'fail)
|
|
(set-window-configuration wconf)
|
|
nil)
|
|
((or (get handler 'syd-lookup-async)
|
|
(eq result 'deferred)))
|
|
((bufferp result)
|
|
(with-current-buffer result
|
|
(point-marker)))
|
|
((or result
|
|
(null origin)
|
|
(/= (point-marker) origin))
|
|
(prog1 (point-marker)
|
|
(set-window-configuration wconf)))))
|
|
((error user-error)
|
|
(message "Lookup handler %S: %s" handler e)
|
|
nil)))
|
|
|
|
(general-def
|
|
:states 'normal
|
|
"K" #'syd-lookup-documentation)
|
|
|
|
(provide 'syd-handle-lookup)
|
|
;;; syd-handle-lookup.el ends here
|