fix: Enable syd-repl-mode /before/ displaying the buffer

This ensures that display-buffer-alist predicates can test for repl buffers.
This commit is contained in:
Madeleine Sydney
2025-01-30 03:26:07 -07:00
parent 4a3551ed12
commit d27a3b60ce
3 changed files with 85 additions and 36 deletions

View File

@@ -12,9 +12,13 @@
buffers. Indeed, this implies a single REPL per language per project. Is this 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.") 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 (define-minor-mode syd-repl-mode
"A minor mode for repl buffers. One use is to universally customise the "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 () (defun syd--repl-from-major-mode ()
"TODO:" "TODO:"
@@ -29,19 +33,36 @@ not-alive buffer."
(remhash repl-key +syd-repl-buffers))) (remhash repl-key +syd-repl-buffers)))
+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. "Call REPL-HANDLER, and error out if it does not return a buffer.
REPL-HANDLER will be called interactively if supported." REPL-HANDLER will be called interactively if supported."
(let ((repl-buffer (save-window-excursion (let ((repl-buffer
(if (buffer-live-p maybe-repl-buffer)
maybe-repl-buffer
(let ((repl-buffer*
(save-window-excursion
(if (commandp repl-handler) (if (commandp repl-handler)
(call-interactively repl-handler) (call-interactively repl-handler)
(funcall repl-handler))))) (funcall repl-handler)))))
(cond ((null repl-buffer) (cond ((null repl-buffer*)
(error "REPL handler %S couldn't open the REPL buffer" repl-handler)) (error "REPL handler %S couldn't open the REPL buffer" repl-handler))
((not (bufferp repl-buffer)) ((not (bufferp repl-buffer*))
(error "REPL handler %S failed to return a buffer" repl-handler)) (error "REPL handler %S failed to return a buffer" repl-handler))
(t repl-buffer)))) (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 () (defun syd--goto-end-of-repl ()
"Move point to the last comint prompt or the end of the buffer." "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." PLIST is a plist of repl-specific options."
(syd--clean-repl-buffers) (syd--clean-repl-buffers)
(let* ((root (syd-project-root)) (let* ((repl-key (syd--get-repl-key))
(repl-key (cons major-mode root))
(maybe-repl-buffer (gethash repl-key +syd-repl-buffers))) (maybe-repl-buffer (gethash repl-key +syd-repl-buffers)))
(cl-check-type maybe-repl-buffer (or buffer null)) (cl-check-type maybe-repl-buffer (or buffer null))
(unless (or (eq maybe-repl-buffer (current-buffer)) (unless (or (eq maybe-repl-buffer (current-buffer))
(null repl-handler)) (null repl-handler))
(let* ((repl-buffer (if (buffer-live-p maybe-repl-buffer) (let* ((repl-buffer (syd--call-repl-handler repl-handler
maybe-repl-buffer plist
(syd--call-repl-handler repl-handler))) maybe-repl-buffer))
(displayed-repl-buffer (funcall display-fn repl-buffer))) (displayed-repl-buffer (funcall display-fn repl-buffer)))
;; Repl buffers are to be saved in `+syd-repl-buffers'; we've just (when (bufferp displayed-repl-buffer)
;; opened one, so do so! (with-current-buffer displayed-repl-buffer
(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)
(syd--goto-end-of-repl)) (syd--goto-end-of-repl))
repl-buffer))))) displayed-repl-buffer)))))
(defun syd--known-repls () (defun syd--known-repls ()
"Return a list of all known mode-repl pairs, each as a two-element list. "Return a list of all known mode-repl pairs, each as a two-element list.
@@ -155,10 +170,14 @@ prefix argument is given, in which case the user will be prompted for a repl."
(set-popup-rule! (set-popup-rule!
(lambda (bufname _) (lambda (bufname _)
(pp bufname)
(with-current-buffer bufname
(pp (boundp 'syd-repl-mode))
(pp syd-repl-mode))
(when (boundp 'syd-repl-mode) (when (boundp 'syd-repl-mode)
(buffer-local-value 'syd-repl-mode (get-buffer bufname)))) (buffer-local-value 'syd-repl-mode (get-buffer bufname))))
:ttl (lambda (buf) :ttl (lambda (buf)
(unless (plist-get +eval-repl-plist :persist) (unless (plist-get syd-repl-plist :persist)
(when-let (process (get-buffer-process buf)) (when-let (process (get-buffer-process buf))
(set-process-query-on-exit-flag process nil) (set-process-query-on-exit-flag process nil)
(kill-process process) (kill-process process)

View File

@@ -67,7 +67,7 @@ adjustment.")
(when (featurep 'evil) (when (featurep 'evil)
;; For maximum escape coverage in emacs state buffers; this only works in ;; For maximum escape coverage in emacs state buffers; this only works in
;; GUI Emacs, in tty Emacs use C-g instead ;; GUI Emacs, in tty Emacs use C-g instead
(define-key map [escape] #'doom/escape)) (define-key map [escape] #'syd/escape))
map) map)
"Active keymap in popup windows. See `doom-popup-buffer-mode'.") "Active keymap in popup windows. See `doom-popup-buffer-mode'.")

View File

@@ -53,9 +53,39 @@ are active.")
(evil-define-key* syd-alt-leader-key-states map (kbd syd-alt-leader-key) 'syd/leader)) (evil-define-key* syd-alt-leader-key-states map (kbd syd-alt-leader-key) 'syd/leader))
(general-override-mode 1)) (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 () (defun syd-keybinds-initialise ()
(syd--initialise-leader) (syd--initialise-leader)
(global-set-key [remap keyboard-quit] #'syd/escape)
;; Buffer ;; Buffer
(require 'syd-buffers) (require 'syd-buffers)
(general-def (general-def