diff --git a/modules/lang/clojure/config.el b/modules/lang/clojure/config.el index 3da3d0ab6..39bff666f 100644 --- a/modules/lang/clojure/config.el +++ b/modules/lang/clojure/config.el @@ -17,8 +17,8 @@ :hook (clojure-mode-local-vars . cider-mode) :init (after! clojure-mode - (set-repl-handler! 'clojure-mode #'+clojure/open-repl) - (set-repl-handler! 'clojurescript-mode #'+clojure/open-cljs-repl) + (set-repl-handler! 'clojure-mode #'+clojure/open-repl :persist t) + (set-repl-handler! 'clojurescript-mode #'+clojure/open-cljs-repl :persist t) (set-eval-handler! '(clojure-mode clojurescript-mode) #'cider-eval-region)) :config (add-hook 'cider-mode-hook #'eldoc-mode) diff --git a/modules/lang/ess/autoload.el b/modules/lang/ess/autoload.el index 134e6f55c..5e7455899 100644 --- a/modules/lang/ess/autoload.el +++ b/modules/lang/ess/autoload.el @@ -1,11 +1,15 @@ ;;; lang/ess/autoload.el -*- lexical-binding: t; -*- ;;;###autoload -(defun +ess-repl-buffer (&optional start-args) - "Returns an R/Julia REPL buffer." +(defun +ess/open-julia-repl (&optional arg) + "Open an ESS Julia REPL" (interactive "P") - (pcase major-mode - ('ess-r-mode (run-ess-r start-args)) - ('ess-julia-mode (run-ess-julia start-args)) - (_ (inferior-ess nil nil t))) + (run-ess-julia arg) + (current-buffer)) + +;;;###autoload +(defun +ess/open-r-repl (&optional arg) + "Open an ESS R REPL" + (interactive "P") + (run-ess-r arg) (current-buffer)) diff --git a/modules/lang/ess/config.el b/modules/lang/ess/config.el index 8bdccc198..6a9326adc 100644 --- a/modules/lang/ess/config.el +++ b/modules/lang/ess/config.el @@ -21,7 +21,8 @@ ess-default-style 'DEFAULT ess-history-directory (expand-file-name "ess-history/" doom-cache-dir)) - (set-repl-handler! '(ess-r-mode ess-julia-mode) #'+ess-repl-buffer) + (set-repl-handler! 'ess-r-mode #'+ess/open-r-repl) + (set-repl-handler! 'ess-julia-mode #'+ess/open-julia-repl) (set-lookup-handlers! '(ess-r-mode ess-julia-mode) :documentation #'ess-display-help-on-object) diff --git a/modules/lang/haskell/config.el b/modules/lang/haskell/config.el index 63c26248a..07898eaf1 100644 --- a/modules/lang/haskell/config.el +++ b/modules/lang/haskell/config.el @@ -21,19 +21,9 @@ (set-file-template! 'haskell-mode :trigger #'haskell-auto-insert-module-template :project t) - (set-repl-handler! '(haskell-mode - haskell-cabal-mode - literate-haskell-mode) - #'+haskell/open-repl) - - ;; Prevent the 'Kill the whole session (y or n)?' prompt caused by the popup - ;; manager auto-killing haskell-interactive-mode's popup buffer (and process) - ;; by settings :ttl to nil. - (set-popup-rule! - (lambda (bname _action) - (eq (buffer-local-value 'major-mode (get-buffer bname)) - 'haskell-interactive-mode)) - :select t :ttl nil :quit nil) + (set-repl-handler! + '(haskell-mode haskell-cabal-mode literate-haskell-mode) + #'+haskell/open-repl :persist t) (add-hook! 'haskell-mode-hook #'haskell-collapse-mode ; support folding haskell code blocks diff --git a/modules/lang/python/config.el b/modules/lang/python/config.el index 1b4d03338..3bfd7c9ea 100644 --- a/modules/lang/python/config.el +++ b/modules/lang/python/config.el @@ -21,7 +21,7 @@ called.") (setq python-environment-directory doom-cache-dir python-indent-guess-indent-offset-verbose nil) :config - (set-repl-handler! 'python-mode #'+python/open-repl) + (set-repl-handler! 'python-mode #'+python/open-repl :persist t) (set-docsets! 'python-mode "Python 3" "NumPy" "SciPy") (set-pretty-symbols! 'python-mode diff --git a/modules/lang/racket/config.el b/modules/lang/racket/config.el index 86b18e2aa..40b2048df 100644 --- a/modules/lang/racket/config.el +++ b/modules/lang/racket/config.el @@ -10,7 +10,6 @@ (use-package! racket-mode :hook (racket-repl-mode . racket-unicode-input-method-enable) :config - (set-popup-rule! "^\\*Racket REPL" :size 10 :select t) (set-repl-handler! 'racket-mode #'+racket/open-repl) (set-lookup-handlers! 'racket-mode :definition #'racket-visit-definition diff --git a/modules/tools/eval/autoload/repl.el b/modules/tools/eval/autoload/repl.el index e5ce18550..a63e40be3 100644 --- a/modules/tools/eval/autoload/repl.el +++ b/modules/tools/eval/autoload/repl.el @@ -3,10 +3,12 @@ (defvar +eval-repl-buffers (make-hash-table :test 'equal) "The buffer of the last open repl.") +(defvar-local +eval-repl-plist nil) + (define-minor-mode +eval-repl-mode "A minor mode for REPL buffers.") -(defun +eval--ensure-in-repl-buffer (&optional command displayfn) +(defun +eval--ensure-in-repl-buffer (&optional fn plist displayfn) (maphash (lambda (key buffer) (unless (buffer-live-p buffer) (remhash key +eval-repl-buffers))) @@ -21,14 +23,16 @@ buffer (setq buffer (save-window-excursion - (if (commandp command) - (call-interactively command) - (funcall command)))) + (if (commandp fn) + (call-interactively fn) + (funcall fn)))) (cond ((null buffer) - (error "REPL handler %S couldn't open the REPL buffer" command)) + (error "REPL handler %S couldn't open the REPL buffer" fn)) ((not (bufferp buffer)) - (error "REPL handler %S failed to return a buffer" command))) + (error "REPL handler %S failed to return a buffer" fn))) (with-current-buffer buffer + (when plist + (setq +eval-repl-plist plist)) (+eval-repl-mode +1)) (puthash key buffer +eval-repl-buffers) buffer))) @@ -42,11 +46,10 @@ buffer))) (defun +eval-open-repl (prompt-p &optional displayfn) - (let ((command (cdr (assq major-mode +eval-repls))) - (region (if (use-region-p) - (buffer-substring-no-properties (region-beginning) - (region-end))))) - (when (or (not command) prompt-p) + (cl-destructuring-bind (mode fn . plist) + (or (assq major-mode +eval-repls) + (list)) + (when (or (not fn) prompt-p) (let* ((choices (or (cl-loop for sym being the symbols for sym-name = (symbol-name sym) if (string-match "^\\(?:\\+\\)?\\([^/]+\\)/open-\\(?:\\(.+\\)-\\)?repl$" sym-name) @@ -60,20 +63,27 @@ (choice-split (split-string choice " " t)) (module (car choice-split)) (repl (substring (cadr choice-split) 1 -1))) - (setq command + (setq fn (intern-soft (format "+%s/open-%srepl" module (if (string= repl "default") "" repl)))))) - (unless (commandp command) - (error "Couldn't find a valid REPL for %s" major-mode)) - (with-current-buffer (+eval--ensure-in-repl-buffer command displayfn) - (when (bound-and-true-p evil-mode) - (call-interactively #'evil-append-line)) - (when region - (insert region)) - t))) + (let ((region (if (use-region-p) + (buffer-substring-no-properties (region-beginning) + (region-end))))) + (unless (commandp fn) + (error "Couldn't find a valid REPL for %s" major-mode)) + (with-current-buffer (+eval--ensure-in-repl-buffer fn plist displayfn) + (when (bound-and-true-p evil-mode) + (call-interactively #'evil-append-line)) + (when region + (insert region)) + t)))) + + +;; +;;; Commands ;;;###autoload (defun +eval/open-repl-same-window (&optional arg) diff --git a/modules/tools/eval/autoload/settings.el b/modules/tools/eval/autoload/settings.el index 3ad1aa7d7..e6cbf0814 100644 --- a/modules/tools/eval/autoload/settings.el +++ b/modules/tools/eval/autoload/settings.el @@ -8,7 +8,7 @@ `+eval/open-repl-other-window' and filled with the `:repl' setting.") ;;;###autodef -(defun set-repl-handler! (modes command) +(defun set-repl-handler! (modes command &rest plist) "Defines a REPL for MODES. MODES is either a single major mode symbol or a list of them. COMMAND is a @@ -16,10 +16,17 @@ function that creates and returns the REPL buffer. COMMAND can either be a function that takes no arguments, or an interactive command that will be called interactively. COMMANDS must return either the repl -buffer or a function that takes no arguments and returns the repl buffer." +buffer or a function that takes no arguments and returns the repl buffer. + +PLIST is a property list that map special attributes to this repl. These are +recognized: + + :persist BOOL + If non-nil, this REPL won't be killed when its window is closed." (declare (indent defun)) (dolist (mode (doom-enlist modes)) - (setf (alist-get mode +eval-repls) command))) + (setf (alist-get mode +eval-repls) + (cons command plist)))) ;; diff --git a/modules/tools/eval/config.el b/modules/tools/eval/config.el index 23b28e80d..0b9abf085 100644 --- a/modules/tools/eval/config.el +++ b/modules/tools/eval/config.el @@ -8,6 +8,19 @@ ;; ;; Packages +(set-popup-rule! + (lambda (bufname _) + (when (boundp '+eval-repl-mode) + (buffer-local-value '+eval-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) + + (after! quickrun (setq quickrun-focus-p nil)