From d27a3b60cea87cb3e7c230207832d04011b9871e Mon Sep 17 00:00:00 2001 From: Madeleine Sydney Date: Thu, 30 Jan 2025 03:26:07 -0700 Subject: [PATCH] fix: Enable syd-repl-mode /before/ displaying the buffer This ensures that display-buffer-alist predicates can test for repl buffers. --- .../programs/emacs/lib/syd-handle-repl.el | 89 +++++++++++-------- .../modules/doom-popup/doom-popup-config.el | 2 +- .../programs/emacs/modules/syd-keybinds.el | 30 +++++++ 3 files changed, 85 insertions(+), 36 deletions(-) diff --git a/users/crumb/programs/emacs/lib/syd-handle-repl.el b/users/crumb/programs/emacs/lib/syd-handle-repl.el index 270c247..3a6e8b6 100644 --- a/users/crumb/programs/emacs/lib/syd-handle-repl.el +++ b/users/crumb/programs/emacs/lib/syd-handle-repl.el @@ -12,9 +12,13 @@ buffers. Indeed, this implies a single REPL per language per project. Is this limitation worth overcoming? I'm not sure! I've yet to butt heads with it.") +(defvar-local syd-repl-plist nil) + +;;;###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.") +display of all repl buffers." + :after-hook (format "syd-repl-mode after %s" (current-buffer))) (defun syd--repl-from-major-mode () "TODO:" @@ -29,19 +33,36 @@ not-alive buffer." (remhash repl-key +syd-repl-buffers))) +syd-repl-buffers)) -(defun syd--call-repl-handler (repl-handler) +(defun syd--get-repl-key () + (cons major-mode (syd-project-root))) + +(defun syd--call-repl-handler (repl-handler &optional plist maybe-repl-buffer) "Call REPL-HANDLER, and error out if it does not return a buffer. REPL-HANDLER will be called interactively if supported." - (let ((repl-buffer (save-window-excursion - (if (commandp repl-handler) - (call-interactively repl-handler) - (funcall repl-handler))))) - (cond ((null repl-buffer) - (error "REPL handler %S couldn't open the REPL buffer" repl-handler)) - ((not (bufferp repl-buffer)) - (error "REPL handler %S failed to return a buffer" repl-handler)) - (t repl-buffer)))) + (let ((repl-buffer + (if (buffer-live-p maybe-repl-buffer) + maybe-repl-buffer + (let ((repl-buffer* + (save-window-excursion + (if (commandp repl-handler) + (call-interactively repl-handler) + (funcall repl-handler))))) + (cond ((null repl-buffer*) + (error "REPL handler %S couldn't open the REPL buffer" repl-handler)) + ((not (bufferp repl-buffer*)) + (error "REPL handler %S failed to return a buffer" repl-handler)) + (t repl-buffer*)))))) + ;; Repl buffers are to be saved in `+syd-repl-buffers'; we've just + ;; opened one, so do so. + (puthash (syd--get-repl-key) repl-buffer +syd-repl-buffers) + ;; If it isn't a buffer, we return nil. + (when (bufferp repl-buffer) + (with-current-buffer repl-buffer + (when plist + (setq syd-repl-plist plist)) + (syd-repl-mode 1)) + repl-buffer))) (defun syd--goto-end-of-repl () "Move point to the last comint prompt or the end of the buffer." @@ -62,25 +83,19 @@ by the given DISPLAY-FN. PLIST is a plist of repl-specific options." (syd--clean-repl-buffers) - (let* ((root (syd-project-root)) - (repl-key (cons major-mode root)) + (let* ((repl-key (syd--get-repl-key)) (maybe-repl-buffer (gethash repl-key +syd-repl-buffers))) (cl-check-type maybe-repl-buffer (or buffer null)) (unless (or (eq maybe-repl-buffer (current-buffer)) (null repl-handler)) - (let* ((repl-buffer (if (buffer-live-p maybe-repl-buffer) - maybe-repl-buffer - (syd--call-repl-handler repl-handler))) + (let* ((repl-buffer (syd--call-repl-handler repl-handler + plist + maybe-repl-buffer)) (displayed-repl-buffer (funcall display-fn repl-buffer))) - ;; Repl buffers are to be saved in `+syd-repl-buffers'; we've just - ;; opened one, so do so! - (puthash repl-key repl-buffer +syd-repl-buffers) - ;; If it isn't a buffer, we return nil. - (when (bufferp repl-buffer) - (with-current-buffer repl-buffer - (syd-repl-mode 1) + (when (bufferp displayed-repl-buffer) + (with-current-buffer displayed-repl-buffer (syd--goto-end-of-repl)) - repl-buffer))))) + displayed-repl-buffer))))) (defun syd--known-repls () "Return a list of all known mode-repl pairs, each as a two-element list. @@ -154,16 +169,20 @@ prefix argument is given, in which case the user will be prompted for a repl." (set-popup-rule! - (lambda (bufname _) - (when (boundp 'syd-repl-mode) - (buffer-local-value 'syd-repl-mode (get-buffer bufname)))) - :ttl (lambda (buf) - (unless (plist-get +eval-repl-plist :persist) - (when-let (process (get-buffer-process buf)) - (set-process-query-on-exit-flag process nil) - (kill-process process) - (kill-buffer buf)))) - :size 0.25 - :quit nil) + (lambda (bufname _) + (pp bufname) + (with-current-buffer bufname + (pp (boundp 'syd-repl-mode)) + (pp syd-repl-mode)) + (when (boundp 'syd-repl-mode) + (buffer-local-value 'syd-repl-mode (get-buffer bufname)))) + :ttl (lambda (buf) + (unless (plist-get syd-repl-plist :persist) + (when-let (process (get-buffer-process buf)) + (set-process-query-on-exit-flag process nil) + (kill-process process) + (kill-buffer buf)))) + :size 0.25 + :quit nil) (provide 'syd-handle-repl) diff --git a/users/crumb/programs/emacs/modules/doom-popup/doom-popup-config.el b/users/crumb/programs/emacs/modules/doom-popup/doom-popup-config.el index f343ee0..35c168e 100644 --- a/users/crumb/programs/emacs/modules/doom-popup/doom-popup-config.el +++ b/users/crumb/programs/emacs/modules/doom-popup/doom-popup-config.el @@ -67,7 +67,7 @@ adjustment.") (when (featurep 'evil) ;; For maximum escape coverage in emacs state buffers; this only works in ;; GUI Emacs, in tty Emacs use C-g instead - (define-key map [escape] #'doom/escape)) + (define-key map [escape] #'syd/escape)) map) "Active keymap in popup windows. See `doom-popup-buffer-mode'.") diff --git a/users/crumb/programs/emacs/modules/syd-keybinds.el b/users/crumb/programs/emacs/modules/syd-keybinds.el index f83c89e..f196f1e 100755 --- a/users/crumb/programs/emacs/modules/syd-keybinds.el +++ b/users/crumb/programs/emacs/modules/syd-keybinds.el @@ -53,9 +53,39 @@ are active.") (evil-define-key* syd-alt-leader-key-states map (kbd syd-alt-leader-key) 'syd/leader)) (general-override-mode 1)) +(defvar syd-escape-hook nil + "A hook run when C-g is pressed (or ESC in normal mode, for evil users). + +More specifically, when `syd/escape' is pressed. If any hook returns non-nil, +all hooks after it are ignored.") + +(defun syd/escape (&optional interactive) + "Run `syd-escape-hook'." + (interactive (list 'interactive)) + (let ((inhibit-quit t)) + (cond ((minibuffer-window-active-p (minibuffer-window)) + ;; quit the minibuffer if open. + (when interactive + (setq this-command 'abort-recursive-edit)) + (abort-recursive-edit)) + ;; Run all escape hooks. If any returns non-nil, then stop there. + ((run-hook-with-args-until-success 'syd-escape-hook)) + ;; don't abort macros + ((or defining-kbd-macro executing-kbd-macro) nil) + ;; Back to the default + ((unwind-protect (keyboard-quit) + (when interactive + (setq this-command 'keyboard-quit))))))) + + +(with-eval-after-load 'eldoc + (eldoc-add-command 'syd/escape)) + (defun syd-keybinds-initialise () (syd--initialise-leader) + (global-set-key [remap keyboard-quit] #'syd/escape) + ;; Buffer (require 'syd-buffers) (general-def