wip(emacs): Abstract strategy-running

- Show docs and goto def are confirmed working
This commit is contained in:
Madeleine Sydney
2025-02-15 16:26:19 -07:00
parent 753f0c2dd9
commit a0495c6df3
3 changed files with 115 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
;; syd-strategies-lookup.el -*- lexical-binding: t; -*-
(require 'syd-strategies)
(use-package better-jumper)
(require 'better-jumper)
(defun syd-strat--run-lookup-strategy (strategy identifier origin)
"Safely call a lookup STRATEGY. A lookup strategy, if it is not an
interactive command, will be called with the lone argument IDENTIFIER.
Interactive or not, the procedure is expected to return nil on failure. Returns
a marker if STRATEGY returns a buffer or marker, or nil on failure.
Modifications to the window configuration will be discarded if STRATEGY fails to
return a buffer or marker."
(condition-case-unless-debug e
(let ((wconf (current-window-configuration))
(result (condition-case-unless-debug e
(if (commandp strategy)
(call-interactively strategy)
(funcall strategy identifier))
(error
(message "Lookup strategy %S threw an error: %s" strategy e)
'fail))))
(cond ((eq result 'fail)
(set-window-configuration wconf)
nil)
((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 strategy %S: %s" strategy e)
nil)))
(cl-defun syd-strat--lookup-and-jump-to
(strategy-category identifier &key (display-fn #'switch-to-buffer))
(let* ((origin (point-marker))
(strategies (alist-get strategy-category syd-strat--strategies))
;; TODO: If called with a prefix argument, prompt the user to select a
;; strategy.
(result (syd-strat-try-functions-wrapped
#'syd-strat--run-lookup-strategy
strategies identifier origin)))
(unwind-protect
(when (cond ((null result)
(message "No lookup strategy could find %S" identifier)
nil)
((markerp result)
(funcall display-fn (marker-buffer result))
(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-strat-lookup-documentation (identifier)
(interactive (list (syd-thing-at-point-or-region)))
(syd-strat--lookup-and-jump-to :documentation identifier
:display-fn #'pop-to-buffer))
(defun syd-strat-lookup-definition (identifier)
(interactive (list (syd-thing-at-point-or-region)))
(syd-strat--lookup-and-jump-to :definition identifier))
(provide 'syd-strategies-lookup)

View File

@@ -0,0 +1,8 @@
;; syd-strategies-repl.el -*- lexical-binding: t; -*-
;;;###autoload
(define-minor-mode syd-repl-mode
"A minor mode for repl buffers. One use is to universally customise the
display of all repl buffers.")
(provide 'syd-strategies-repl)

View File

@@ -0,0 +1,37 @@
;; syd-strategies.el -*- lexical-binding: t; -*-
(require 'syd-text)
;; :documentation : Identifier -> Marker
(defvar-local syd-strat--strategies nil)
(defun syd-strat-try-functions-wrapped (wrapper fns &rest args)
"For each FN in FNS, call WRAPPER with the arguments FN followed by ARGS,
until a FN returns non-nil."
(cl-loop for fn in fns
with r = nil
do (setq r (apply wrapper fn args))
until r
finally return r))
(defun syd-strat--set-strategies (category strategies)
(cl-loop for ref in-ref syd-strat--strategies
until (eq category (car ref))
finally do (pp ref)))
(defun syd-set-strategies (modes &rest args)
(dolist (mode (ensure-list modes))
(let ((hook (intern (format "%s-hook" mode)))
(fn-name (intern (format "syd-strat--init-for-%s-h" mode))))
(unless (cl-evenp (length args))
(signal 'wrong-number-of-arguments args))
;; We use this `defalias' incantation instead of a raw `fset' because the
;; former will properly associate a source location to the definition.
(defalias fn-name
(function
(lambda ()
(cl-loop for (category strategies) on args by (lambda (x) (-drop 2 x))
do (syd-strat--set-strategies category strategies)))))
(add-hook hook fn-name))))
(provide 'syd-strategies)