From 94b16cba6c56c89e541cf7e4b51cf7cc8a40fbe7 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Mon, 18 Feb 2019 01:56:38 -0500 Subject: [PATCH] Standardize REPL commands & improve SPC o r - SPC o r now prompts for a REPL to open when none was found for the current buffer. - REPL handlers must now follow the naming convention "*/open*-repl". e.g. +python/open-ipython-repl, +emacs-lisp/open-repl, etc. - +eval/open-repl has been split in two: - +eval/open-repl-other-window - +eval/open-repl-same-window --- modules/config/default/+evil-bindings.el | 13 +++--- modules/feature/eval/README.org | 12 +++--- modules/feature/eval/autoload/evil.el | 2 +- modules/feature/eval/autoload/repl.el | 52 ++++++++++++++++++----- modules/feature/eval/autoload/settings.el | 2 +- modules/lang/emacs-lisp/autoload.el | 2 +- modules/lang/emacs-lisp/config.el | 2 +- modules/lang/haskell/autoload.el | 14 +++--- modules/lang/haskell/config.el | 2 +- modules/lang/javascript/README.org | 2 +- modules/lang/javascript/autoload.el | 2 +- modules/lang/javascript/config.el | 2 +- modules/lang/lua/autoload.el | 2 +- modules/lang/lua/config.el | 2 +- modules/lang/python/autoload/python.el | 6 +-- modules/lang/python/config.el | 2 +- modules/lang/sh/README.org | 12 +++--- modules/lang/sh/autoload.el | 2 +- modules/lang/sh/config.el | 2 +- 19 files changed, 83 insertions(+), 52 deletions(-) diff --git a/modules/config/default/+evil-bindings.el b/modules/config/default/+evil-bindings.el index 76ab8c82b..5fcc83fe9 100644 --- a/modules/config/default/+evil-bindings.el +++ b/modules/config/default/+evil-bindings.el @@ -590,7 +590,7 @@ :desc "Jump to definition" "d" #'+lookup/definition :desc "Evaluate buffer/region" "e" #'+eval/buffer-or-region :desc "Format buffer/region" "f" #'+format/region-or-buffer - :desc "Open REPL" "r" #'+eval/open-repl + :desc "Open REPL" "r" #'+eval/open-repl-other-window :desc "Delete trailing whitespace" "w" #'delete-trailing-whitespace :desc "List errors" "x" #'flycheck-list-errors) @@ -700,11 +700,12 @@ :desc "Org capture" "x" #'org-capture) (:prefix ("o" . "open") - :desc "Org agenda" "a" #'org-agenda - :desc "Default browser" "b" #'browse-url-of-file - :desc "Debugger" "d" #'+debug/open - :desc "REPL" "r" #'+eval/open-repl - :desc "Dired" "-" #'dired-jump + :desc "Org agenda" "a" #'org-agenda + :desc "Default browser" "b" #'browse-url-of-file + :desc "Debugger" "d" #'+debug/open + :desc "REPL" "r" #'+eval/open-repl-other-window + :desc "REPL (same window)" "R" #'+eval/open-repl-same-window + :desc "Dired" "-" #'dired-jump (:when (featurep! :ui neotree) :desc "Project sidebar" "p" #'+neotree/open :desc "Find file in project sidebar" "P" #'+neotree/find-this-file) diff --git a/modules/feature/eval/README.org b/modules/feature/eval/README.org index cfdad3535..f52e6c1a3 100644 --- a/modules/feature/eval/README.org +++ b/modules/feature/eval/README.org @@ -52,7 +52,8 @@ Invoked via: + =SPC o r= or ~:repl~ will open a REPL in a popup window. =C-u SPC o r= or ~:repl!~ will open a REPL in the current window. If a REPL is already open and a selection is active, it will be sent to the REPL. -+ ~M-x +eval/open-repl~ ++ ~M-x +eval/open-repl-other-window~ ++ ~M-x +eval/open-repl-same-window~ + ~M-x +eval/send-region-to-repl~ while a selection (and REPL) is active * Configuration @@ -60,8 +61,9 @@ Invoked via: REPLs are defined for most languages Doom supports. Check that language module's README.org to see if it does (and if it requires additional setup). -To use them, you may use ~M-x +eval/open-repl~, ~:repl~ (for evil users) or the -default binding: =SPC o r=. These will open a REPL in a popup window. +To use them, you may use ~M-x +eval/open-repl-other-window~, ~M-x ++eval/open-repl-same-window~, ~:repl~ (for evil users) or the default binding: +=SPC o r=. These will open a REPL in a popup window. #+begin_quote You can simply call that mode's REPL command manually. e.g. ~M-x ielm~, but @@ -75,12 +77,12 @@ FUNCTION should return a repl buffer. Any window changes in this function are ignored, then the REPL is opened in a popup window. #+BEGIN_SRC emacs-lisp -(defun +lua/repl () +(defun +lua/open-repl () (interactive) (lua-start-process "lua" "lua") (pop-to-buffer lua-process-buffer)) -(set-repl-handler! 'lua-mode #'+lua/repl) +(set-repl-handler! 'lua-mode #'+lua/open-repl) #+END_SRC ** Change how code is evaluated in a major mode diff --git a/modules/feature/eval/autoload/evil.el b/modules/feature/eval/autoload/evil.el index aa76f73f1..279b41e32 100644 --- a/modules/feature/eval/autoload/evil.el +++ b/modules/feature/eval/autoload/evil.el @@ -19,5 +19,5 @@ :move-point nil (interactive "") (if (evil-normal-state-p) - (+eval/open-repl bang) + (+eval/open-repl-other-window bang) (+eval/send-region-to-repl beg end bang))) diff --git a/modules/feature/eval/autoload/repl.el b/modules/feature/eval/autoload/repl.el index 3bb2335d2..3bc558b8a 100644 --- a/modules/feature/eval/autoload/repl.el +++ b/modules/feature/eval/autoload/repl.el @@ -6,7 +6,7 @@ (define-minor-mode +eval-repl-mode "A minor mode for REPL buffers.") -(defun +eval--ensure-in-repl-buffer (&optional command same-window-p) +(defun +eval--ensure-in-repl-buffer (&optional command other-window-p) (maphash (lambda (key buffer) (unless (buffer-live-p buffer) (remhash key +eval-repl-buffers))) @@ -16,7 +16,7 @@ (buffer (gethash key +eval-repl-buffers))) (cl-check-type buffer (or buffer null)) (unless (eq buffer (current-buffer)) - (funcall (if same-window-p #'switch-to-buffer #'pop-to-buffer) + (funcall (if other-window-p #'pop-to-buffer #'switch-to-buffer) (if (buffer-live-p buffer) buffer (setq buffer @@ -36,19 +36,51 @@ (point-max))) buffer))) +(defun +eval-open-repl (prompt-p other-window-p) + (let ((command (cdr (assq major-mode +eval-repls)))) + (when (or (not command) 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) + collect + (format "%s (%s)" + (match-string-no-properties 1 sym-name) + (or (match-string-no-properties 2 sym-name) "default"))) + (user-error "There are no known available REPLs"))) + (choice (or (completing-read "Open a REPL for: " choices) + (user-error "Aborting"))) + (choice-split (split-string choice " " t)) + (module (car choice-split)) + (repl (substring (cadr choice-split) 1 -1))) + (setq command + (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)) + (when (+eval--ensure-in-repl-buffer command other-window-p) + (when (bound-and-true-p evil-mode) + (call-interactively #'evil-append-line)) + t))) + ;;;###autoload -(defun +eval/open-repl (&optional same-window-p) +(defun +eval/open-repl-same-window (&optional arg) "Opens (or reopens) the REPL associated with the current major-mode and place the cursor at the prompt. -If SAME-WINDOW-P is non-nil, open REPL in current window." +If ARG (universal argument), prompt for a specific REPL to open." (interactive "P") - (if-let* ((command (cdr (assq major-mode +eval-repls)))) - (when (+eval--ensure-in-repl-buffer command same-window-p) - (when (bound-and-true-p evil-mode) - (call-interactively #'evil-append-line)) - t) - (user-error "No REPL is defined for %s" major-mode))) + (+eval-open-repl arg)) + +;;;###autoload +(defun +eval/open-repl-other-window (&optional arg) + "Does `+eval/open-repl', but in a popup window. + +If ARG (universal argument), prompt for a specific REPL to open." + (interactive "P") + (+eval-open-repl arg t)) ;;;###autoload (defun +eval/send-region-to-repl (beg end &optional auto-execute-p) diff --git a/modules/feature/eval/autoload/settings.el b/modules/feature/eval/autoload/settings.el index d6fb3249f..0cf618514 100644 --- a/modules/feature/eval/autoload/settings.el +++ b/modules/feature/eval/autoload/settings.el @@ -6,7 +6,7 @@ ;;;###autoload (defvar +eval-repls nil "An alist mapping major modes to plists that describe REPLs. Used by -`+eval/open-repl' and filled with the `:repl' setting.") +`+eval/open-repl-other-window' and filled with the `:repl' setting.") ;;;###autodef (defun set-repl-handler! (modes command) diff --git a/modules/lang/emacs-lisp/autoload.el b/modules/lang/emacs-lisp/autoload.el index 482ace7c7..0a21cc4cf 100644 --- a/modules/lang/emacs-lisp/autoload.el +++ b/modules/lang/emacs-lisp/autoload.el @@ -79,7 +79,7 @@ library/userland functions" ;; Commands ;;;###autoload -(defun +emacs-lisp/repl () +(defun +emacs-lisp/open-repl () "Open the Emacs Lisp REPL (`ielm')." (interactive) (pop-to-buffer diff --git a/modules/lang/emacs-lisp/config.el b/modules/lang/emacs-lisp/config.el index 3539f6279..856a9cb61 100644 --- a/modules/lang/emacs-lisp/config.el +++ b/modules/lang/emacs-lisp/config.el @@ -14,7 +14,7 @@ (add-to-list 'auto-mode-alist '("\\.Cask\\'" . emacs-lisp-mode)) (after! elisp-mode - (set-repl-handler! 'emacs-lisp-mode #'+emacs-lisp/repl) + (set-repl-handler! 'emacs-lisp-mode #'+emacs-lisp/open-repl) (set-eval-handler! 'emacs-lisp-mode #'+emacs-lisp-eval) (set-lookup-handlers! 'emacs-lisp-mode :definition #'elisp-def diff --git a/modules/lang/haskell/autoload.el b/modules/lang/haskell/autoload.el index d3c5edb17..d3c36a20b 100644 --- a/modules/lang/haskell/autoload.el +++ b/modules/lang/haskell/autoload.el @@ -1,14 +1,10 @@ ;;; lang/haskell/autoload.el -*- lexical-binding: t; -*- ;;;###autoload -(defun +haskell-repl-buffer (&optional arg) - "Returns the appropriate Haskell REPL buffer." - (if (featurep! +intero) - (intero-repl-buffer arg) - (haskell-session-interactive-buffer (haskell-session)))) - -;;;###autoload -(defun +haskell/repl (&optional arg) +(defun +haskell/open-repl (&optional arg) "Opens a Haskell REPL." (interactive "P") - (display-buffer (+haskell-repl-buffer arg))) + (display-buffer + (if (featurep! +intero) + (intero-repl-buffer arg) + (haskell-session-interactive-buffer (haskell-session))))) diff --git a/modules/lang/haskell/config.el b/modules/lang/haskell/config.el index 28daa4e64..836475a33 100644 --- a/modules/lang/haskell/config.el +++ b/modules/lang/haskell/config.el @@ -16,7 +16,7 @@ interactive-haskell-mode)) (set-lookup-handlers! 'haskell-mode :definition #'haskell-mode-jump-to-def-or-tag) (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-repl-buffer) + (set-repl-handler! '(haskell-mode haskell-cabal-mode literate-haskell-mode) #'+haskell/open-repl) (add-to-list 'completion-ignored-extensions ".hi") diff --git a/modules/lang/javascript/README.org b/modules/lang/javascript/README.org index e184bbb0e..2bb3f4b6c 100644 --- a/modules/lang/javascript/README.org +++ b/modules/lang/javascript/README.org @@ -34,5 +34,5 @@ sudo pacman --needed --noconfirm -S nodejs npm ** Commands | command | key / ex command | description | |----------------------------------+------------------+------------------------------------------------------------| -| ~+javascript/repl~ | =:repl= | Open the NodeJS REPL (or send the current selection to it) | +| ~+javascript/open-repl~ | =:repl= | Open the NodeJS REPL (or send the current selection to it) | | ~+javascript/skewer-this-buffer~ | =SPC m S= | Attaches a browser to the current buffer | diff --git a/modules/lang/javascript/autoload.el b/modules/lang/javascript/autoload.el index 260767c10..330aef52a 100644 --- a/modules/lang/javascript/autoload.el +++ b/modules/lang/javascript/autoload.el @@ -36,7 +36,7 @@ ignore the cache." ;; Commands ;;;###autoload -(defun +javascript/repl () +(defun +javascript/open-repl () "Open a Javascript REPL. Meaning either `skewer-repl', if any of the skewer-*-mode's are enabled, or `nodejs-repl' otherwise." (interactive) diff --git a/modules/lang/javascript/config.el b/modules/lang/javascript/config.el index d93d1bd7f..d125e96e3 100644 --- a/modules/lang/javascript/config.el +++ b/modules/lang/javascript/config.el @@ -52,7 +52,7 @@ mode-name "JS2") (set-electric! 'js2-mode :chars '(?\} ?\) ?. ?:)) - (set-repl-handler! 'js2-mode #'+javascript/repl) + (set-repl-handler! 'js2-mode #'+javascript/open-repl) (map! :map js2-mode-map :localleader diff --git a/modules/lang/lua/autoload.el b/modules/lang/lua/autoload.el index d244c2000..0100d1808 100644 --- a/modules/lang/lua/autoload.el +++ b/modules/lang/lua/autoload.el @@ -1,7 +1,7 @@ ;;; lang/lua/autoload.el -*- lexical-binding: t; -*- ;;;###autoload -(defun +lua/repl () +(defun +lua/open-repl () "Open Lua REPL." (interactive) (lua-start-process "lua" "lua") diff --git a/modules/lang/lua/config.el b/modules/lang/lua/config.el index e1c536878..ea6882fa1 100644 --- a/modules/lang/lua/config.el +++ b/modules/lang/lua/config.el @@ -15,7 +15,7 @@ :config (set-lookup-handlers! 'lua-mode :documentation 'lua-search-documentation) (set-electric! 'lua-mode :words '("else" "end")) - (set-repl-handler! 'lua-mode #'+lua/repl) + (set-repl-handler! 'lua-mode #'+lua/open-repl) (set-company-backend! 'lua-mode '(company-lua company-yasnippet))) diff --git a/modules/lang/python/autoload/python.el b/modules/lang/python/autoload/python.el index 796223ccd..af9d19724 100644 --- a/modules/lang/python/autoload/python.el +++ b/modules/lang/python/autoload/python.el @@ -4,7 +4,7 @@ "TODO") ;;;###autoload -(defun +python/repl () +(defun +python/open-repl () "Open the Python REPL." (interactive) (unless python-shell-interpreter @@ -28,7 +28,7 @@ (interactive) (let ((python-shell-interpreter "ipython") (python-shell-interpreter-args +python-jupyter-repl-args)) - (+python/repl))) + (+python/open-repl))) ;;;###autoload (defun +python/open-jupyter-repl () @@ -37,7 +37,7 @@ (add-to-list 'python-shell-completion-native-disabled-interpreters "jupyter") (let ((python-shell-interpreter "jupyter") (python-shell-interpreter-args (format "console %s" +python-jupyter-repl-args))) - (+python/repl))) + (+python/open-repl))) (defun +python--extract-version (prefix str) (when str diff --git a/modules/lang/python/config.el b/modules/lang/python/config.el index 681486b91..30bac7222 100644 --- a/modules/lang/python/config.el +++ b/modules/lang/python/config.el @@ -26,7 +26,7 @@ called.") :config (set-env! "PYTHONPATH" "PYENV_ROOT" "ANACONDA_HOME") (set-electric! 'python-mode :chars '(?:)) - (set-repl-handler! 'python-mode #'+python/repl) + (set-repl-handler! 'python-mode #'+python/open-repl) (set-pretty-symbols! 'python-mode ;; Functional diff --git a/modules/lang/sh/README.org b/modules/lang/sh/README.org index 8ee01d3d9..5bfd3c502 100644 --- a/modules/lang/sh/README.org +++ b/modules/lang/sh/README.org @@ -8,15 +8,15 @@ This module adds support for shell scripting languages. + REPL support * Table of Contents :TOC: -- [[#install][Install]] -- [[#appendix][Appendix]] - - [[#commands][Commands]] +- [[Install][Install]] +- [[Appendix][Appendix]] + - [[Commands][Commands]] * Install This module has no dependencies. * Appendix ** Commands -| command | key / ex command | description | -|------------+------------------+-------------------------------------------------------| -| ~+sh/repl~ | =:repl= | Open a terminal (or send the current selection to it) | +| command | key / ex command | description | +|-----------------+------------------+-------------------------------------------------------| +| ~+sh/open-repl~ | =:repl= | Open a terminal (or send the current selection to it) | diff --git a/modules/lang/sh/autoload.el b/modules/lang/sh/autoload.el index ad78ecc4b..886cfcad1 100644 --- a/modules/lang/sh/autoload.el +++ b/modules/lang/sh/autoload.el @@ -27,7 +27,7 @@ (defvar sh-shell-file) ;;;###autoload -(defun +sh/repl () +(defun +sh/open-repl () "Open a shell REPL." (let* ((dest-sh (symbol-name sh-shell)) (sh-shell-file dest-sh)) diff --git a/modules/lang/sh/config.el b/modules/lang/sh/config.el index f6ae743b7..d71f81662 100644 --- a/modules/lang/sh/config.el +++ b/modules/lang/sh/config.el @@ -15,7 +15,7 @@ :mode ("/bspwmrc\\'" . sh-mode) :config (set-electric! 'sh-mode :words '("else" "elif" "fi" "done" "then" "do" "esac" ";;")) - (set-repl-handler! 'sh-mode #'+sh/repl) + (set-repl-handler! 'sh-mode #'+sh/open-repl) (setq sh-indent-after-continuation 'always)