tools/eval: associate plist with repl handlers
Also consolidates all REPLs (opened through the :tools eval module) under one popup rule, which inhibits ESC from prematurely closing them (#1944), and cleans up after their buffers *only* if their handlers weren't specified to :persist, e.g. (set-repl-handler! 'some-mode #'some-repl-handler :persist t) Also standardized ESS's REPL commands.
This commit is contained in:
parent
e6094f262f
commit
0b67251159
9 changed files with 71 additions and 47 deletions
|
@ -17,8 +17,8 @@
|
||||||
:hook (clojure-mode-local-vars . cider-mode)
|
:hook (clojure-mode-local-vars . cider-mode)
|
||||||
:init
|
:init
|
||||||
(after! clojure-mode
|
(after! clojure-mode
|
||||||
(set-repl-handler! 'clojure-mode #'+clojure/open-repl)
|
(set-repl-handler! 'clojure-mode #'+clojure/open-repl :persist t)
|
||||||
(set-repl-handler! 'clojurescript-mode #'+clojure/open-cljs-repl)
|
(set-repl-handler! 'clojurescript-mode #'+clojure/open-cljs-repl :persist t)
|
||||||
(set-eval-handler! '(clojure-mode clojurescript-mode) #'cider-eval-region))
|
(set-eval-handler! '(clojure-mode clojurescript-mode) #'cider-eval-region))
|
||||||
:config
|
:config
|
||||||
(add-hook 'cider-mode-hook #'eldoc-mode)
|
(add-hook 'cider-mode-hook #'eldoc-mode)
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
;;; lang/ess/autoload.el -*- lexical-binding: t; -*-
|
;;; lang/ess/autoload.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +ess-repl-buffer (&optional start-args)
|
(defun +ess/open-julia-repl (&optional arg)
|
||||||
"Returns an R/Julia REPL buffer."
|
"Open an ESS Julia REPL"
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(pcase major-mode
|
(run-ess-julia arg)
|
||||||
('ess-r-mode (run-ess-r start-args))
|
(current-buffer))
|
||||||
('ess-julia-mode (run-ess-julia start-args))
|
|
||||||
(_ (inferior-ess nil nil t)))
|
;;;###autoload
|
||||||
|
(defun +ess/open-r-repl (&optional arg)
|
||||||
|
"Open an ESS R REPL"
|
||||||
|
(interactive "P")
|
||||||
|
(run-ess-r arg)
|
||||||
(current-buffer))
|
(current-buffer))
|
||||||
|
|
|
@ -21,7 +21,8 @@
|
||||||
ess-default-style 'DEFAULT
|
ess-default-style 'DEFAULT
|
||||||
ess-history-directory (expand-file-name "ess-history/" doom-cache-dir))
|
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)
|
(set-lookup-handlers! '(ess-r-mode ess-julia-mode)
|
||||||
:documentation #'ess-display-help-on-object)
|
:documentation #'ess-display-help-on-object)
|
||||||
|
|
||||||
|
|
|
@ -21,19 +21,9 @@
|
||||||
(set-file-template! 'haskell-mode
|
(set-file-template! 'haskell-mode
|
||||||
:trigger #'haskell-auto-insert-module-template
|
:trigger #'haskell-auto-insert-module-template
|
||||||
:project t)
|
:project t)
|
||||||
(set-repl-handler! '(haskell-mode
|
(set-repl-handler!
|
||||||
haskell-cabal-mode
|
'(haskell-mode haskell-cabal-mode literate-haskell-mode)
|
||||||
literate-haskell-mode)
|
#'+haskell/open-repl :persist t)
|
||||||
#'+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)
|
|
||||||
|
|
||||||
(add-hook! 'haskell-mode-hook
|
(add-hook! 'haskell-mode-hook
|
||||||
#'haskell-collapse-mode ; support folding haskell code blocks
|
#'haskell-collapse-mode ; support folding haskell code blocks
|
||||||
|
|
|
@ -21,7 +21,7 @@ called.")
|
||||||
(setq python-environment-directory doom-cache-dir
|
(setq python-environment-directory doom-cache-dir
|
||||||
python-indent-guess-indent-offset-verbose nil)
|
python-indent-guess-indent-offset-verbose nil)
|
||||||
:config
|
: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-docsets! 'python-mode "Python 3" "NumPy" "SciPy")
|
||||||
|
|
||||||
(set-pretty-symbols! 'python-mode
|
(set-pretty-symbols! 'python-mode
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
(use-package! racket-mode
|
(use-package! racket-mode
|
||||||
:hook (racket-repl-mode . racket-unicode-input-method-enable)
|
:hook (racket-repl-mode . racket-unicode-input-method-enable)
|
||||||
:config
|
:config
|
||||||
(set-popup-rule! "^\\*Racket REPL" :size 10 :select t)
|
|
||||||
(set-repl-handler! 'racket-mode #'+racket/open-repl)
|
(set-repl-handler! 'racket-mode #'+racket/open-repl)
|
||||||
(set-lookup-handlers! 'racket-mode
|
(set-lookup-handlers! 'racket-mode
|
||||||
:definition #'racket-visit-definition
|
:definition #'racket-visit-definition
|
||||||
|
|
|
@ -3,10 +3,12 @@
|
||||||
(defvar +eval-repl-buffers (make-hash-table :test 'equal)
|
(defvar +eval-repl-buffers (make-hash-table :test 'equal)
|
||||||
"The buffer of the last open repl.")
|
"The buffer of the last open repl.")
|
||||||
|
|
||||||
|
(defvar-local +eval-repl-plist nil)
|
||||||
|
|
||||||
(define-minor-mode +eval-repl-mode
|
(define-minor-mode +eval-repl-mode
|
||||||
"A minor mode for REPL buffers.")
|
"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)
|
(maphash (lambda (key buffer)
|
||||||
(unless (buffer-live-p buffer)
|
(unless (buffer-live-p buffer)
|
||||||
(remhash key +eval-repl-buffers)))
|
(remhash key +eval-repl-buffers)))
|
||||||
|
@ -21,14 +23,16 @@
|
||||||
buffer
|
buffer
|
||||||
(setq buffer
|
(setq buffer
|
||||||
(save-window-excursion
|
(save-window-excursion
|
||||||
(if (commandp command)
|
(if (commandp fn)
|
||||||
(call-interactively command)
|
(call-interactively fn)
|
||||||
(funcall command))))
|
(funcall fn))))
|
||||||
(cond ((null buffer)
|
(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))
|
((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
|
(with-current-buffer buffer
|
||||||
|
(when plist
|
||||||
|
(setq +eval-repl-plist plist))
|
||||||
(+eval-repl-mode +1))
|
(+eval-repl-mode +1))
|
||||||
(puthash key buffer +eval-repl-buffers)
|
(puthash key buffer +eval-repl-buffers)
|
||||||
buffer)))
|
buffer)))
|
||||||
|
@ -42,11 +46,10 @@
|
||||||
buffer)))
|
buffer)))
|
||||||
|
|
||||||
(defun +eval-open-repl (prompt-p &optional displayfn)
|
(defun +eval-open-repl (prompt-p &optional displayfn)
|
||||||
(let ((command (cdr (assq major-mode +eval-repls)))
|
(cl-destructuring-bind (mode fn . plist)
|
||||||
(region (if (use-region-p)
|
(or (assq major-mode +eval-repls)
|
||||||
(buffer-substring-no-properties (region-beginning)
|
(list))
|
||||||
(region-end)))))
|
(when (or (not fn) prompt-p)
|
||||||
(when (or (not command) prompt-p)
|
|
||||||
(let* ((choices (or (cl-loop for sym being the symbols
|
(let* ((choices (or (cl-loop for sym being the symbols
|
||||||
for sym-name = (symbol-name sym)
|
for sym-name = (symbol-name sym)
|
||||||
if (string-match "^\\(?:\\+\\)?\\([^/]+\\)/open-\\(?:\\(.+\\)-\\)?repl$" sym-name)
|
if (string-match "^\\(?:\\+\\)?\\([^/]+\\)/open-\\(?:\\(.+\\)-\\)?repl$" sym-name)
|
||||||
|
@ -60,20 +63,27 @@
|
||||||
(choice-split (split-string choice " " t))
|
(choice-split (split-string choice " " t))
|
||||||
(module (car choice-split))
|
(module (car choice-split))
|
||||||
(repl (substring (cadr choice-split) 1 -1)))
|
(repl (substring (cadr choice-split) 1 -1)))
|
||||||
(setq command
|
(setq fn
|
||||||
(intern-soft
|
(intern-soft
|
||||||
(format "+%s/open-%srepl" module
|
(format "+%s/open-%srepl" module
|
||||||
(if (string= repl "default")
|
(if (string= repl "default")
|
||||||
""
|
""
|
||||||
repl))))))
|
repl))))))
|
||||||
(unless (commandp command)
|
(let ((region (if (use-region-p)
|
||||||
(error "Couldn't find a valid REPL for %s" major-mode))
|
(buffer-substring-no-properties (region-beginning)
|
||||||
(with-current-buffer (+eval--ensure-in-repl-buffer command displayfn)
|
(region-end)))))
|
||||||
(when (bound-and-true-p evil-mode)
|
(unless (commandp fn)
|
||||||
(call-interactively #'evil-append-line))
|
(error "Couldn't find a valid REPL for %s" major-mode))
|
||||||
(when region
|
(with-current-buffer (+eval--ensure-in-repl-buffer fn plist displayfn)
|
||||||
(insert region))
|
(when (bound-and-true-p evil-mode)
|
||||||
t)))
|
(call-interactively #'evil-append-line))
|
||||||
|
(when region
|
||||||
|
(insert region))
|
||||||
|
t))))
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
|
;;; Commands
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +eval/open-repl-same-window (&optional arg)
|
(defun +eval/open-repl-same-window (&optional arg)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
`+eval/open-repl-other-window' and filled with the `:repl' setting.")
|
`+eval/open-repl-other-window' and filled with the `:repl' setting.")
|
||||||
|
|
||||||
;;;###autodef
|
;;;###autodef
|
||||||
(defun set-repl-handler! (modes command)
|
(defun set-repl-handler! (modes command &rest plist)
|
||||||
"Defines a REPL for MODES.
|
"Defines a REPL for MODES.
|
||||||
|
|
||||||
MODES is either a single major mode symbol or a list of them. COMMAND is a
|
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 can either be a function that takes no arguments, or an interactive
|
||||||
command that will be called interactively. COMMANDS must return either the repl
|
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))
|
(declare (indent defun))
|
||||||
(dolist (mode (doom-enlist modes))
|
(dolist (mode (doom-enlist modes))
|
||||||
(setf (alist-get mode +eval-repls) command)))
|
(setf (alist-get mode +eval-repls)
|
||||||
|
(cons command plist))))
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -8,6 +8,19 @@
|
||||||
;;
|
;;
|
||||||
;; Packages
|
;; 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
|
(after! quickrun
|
||||||
(setq quickrun-focus-p nil)
|
(setq quickrun-focus-p nil)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue