From a24b3d7ec748ec89f665c7f5293e0705b2ce5525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Madeleine=20Sydney=20=C5=9Alaga?= Date: Mon, 22 Sep 2025 11:20:33 -0600 Subject: [PATCH] feat(emacs): handle --- .../users/msyds/emacs/lisp/syd/emacs-lisp.el | 7 +- .../home/users/msyds/emacs/lisp/syd/handle.el | 92 +++++++++++++++++-- 2 files changed, 88 insertions(+), 11 deletions(-) diff --git a/modules/home/users/msyds/emacs/lisp/syd/emacs-lisp.el b/modules/home/users/msyds/emacs/lisp/syd/emacs-lisp.el index 8dd7f21..df2e089 100644 --- a/modules/home/users/msyds/emacs/lisp/syd/emacs-lisp.el +++ b/modules/home/users/msyds/emacs/lisp/syd/emacs-lisp.el @@ -33,7 +33,7 @@ (bury-buffer b) b))))) -(defun syd-elisp-lookup-documentation (identifier) +(defun syd-elisp-handle-docs (identifier) "Lookup IDENTIFIER with `describe-symbol'" ;; HACK: Much to my frustration, `describe-symbol' has no defined return ;; value. To test if the call was successful or not, we check if any window @@ -45,9 +45,8 @@ (and (get-buffer-window-list buffer) buffer))) -;; (handle '(emacs-lisp-mode lisp-interaction-mode -;; inferior-emacs-lisp-mode) -;; :repl #'syd-elisp-open-repl) +(syd-handle '(emacs-lisp-mode lisp-interaction-mode) + :docs #'syd-elisp-handle-docs) diff --git a/modules/home/users/msyds/emacs/lisp/syd/handle.el b/modules/home/users/msyds/emacs/lisp/syd/handle.el index b34d138..71bd1c1 100644 --- a/modules/home/users/msyds/emacs/lisp/syd/handle.el +++ b/modules/home/users/msyds/emacs/lisp/syd/handle.el @@ -3,14 +3,92 @@ (require 'cl-lib) (require 'syd/straight) (require 'syd/use-package) +(require 'syd/dash) (eval-when-compile (require 'cl-lib)) -(use-package handle - :preface - (require 'cl-lib) - :init - (setq handle-keywords - '(:repl - :docs))) + +;;; Core machinery + +(defun syd-parent-mode-list (mode) + "Return a list of MODE, then MODE's parent, then MODE's grandparent..." + (cl-loop for m = mode then (get m 'derived-mode-parent) + while m + collect m)) + +(defun syd-handler-alist-name (type) + (intern (concat "syd-handle-" + (symbol-name type) + "-alist"))) + +(defun syd-handler-function-name (type) + (intern (concat "syd-handle-" (symbol-name type)))) + +(defmacro syd-define-handler-type + (handler-type arglist &optional docstring) + (declare (indent defun)) + (let ((hook-name (syd-handler-alist-name handler-type)) + (fn-name (syd-handler-function-name handler-type))) + `(progn + (defvar ,hook-name nil) + (defun ,fn-name (&rest args) + ,@(ensure-list docstring) + (let (r) + (cl-loop + for (mode . handle) in ,hook-name + ;; Test mode's variable to determine if it's active. Some modes + ;; lack an associated variable, which is very annoying! The + ;; `major-mode' and sledgehammer `minor-mode-list' tests should + ;; catch these guys. + ;; + ;; TODO: Use `syd-parent-mode-list' to support hierarchies of modes. + when (or (eq mode major-mode) + (and (boundp mode) + (symbol-value mode)) + (memq mode minor-mode-list)) + do (setq r (apply handle args)) + when r return r)))))) + +(defun syd-handle (modes &rest args) + (declare (indent defun)) + (cl-loop + for m in (ensure-list modes) + do (cl-loop for (type handler) on args by (lambda (xs) + (cdr (cdr xs))) + do (let ((s (->> (symbol-name type) + (string-remove-prefix ":") + intern + syd-handler-alist-name))) + (set s (cons (cons m handler) + (symbol-value s))))))) + + +;;; Docs handler + +(syd-define-handler-type docs (identifier) + "Return a buffer visiting documentation for IDENTIFIER.") + +(defun syd-handle-docs* (identifier) + (interactive (list (symbol-at-point))) + (if-let* ((b (save-excursion + (save-window-excursion + (syd-handle-docs identifier))))) + (display-buffer b) + (message "Couldn't find documentation on %S" + (substring-no-properties identifier)))) + + +;;; REPL handler + +(syd-define-handler-type repl () + "Return a buffer.") + +(defun syd-handle-repl* () + (if-let* ((b (save-window-excursion + (syd-handle-repl)))) + (display-buffer b) + (message "Couldn't open a REPL for %S" + (substring-no-properties identifier)))) + + (provide 'syd/handle)