From 84a063ca783bb1820fb323f56ea04cf9e8178c10 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Sat, 26 Oct 2019 01:37:36 -0400 Subject: [PATCH] tools/eval: add +overlay feature Now, inline evaluation will display results in an overlay next to the cursor, rather than in the minibuffer (unless it gets too big, in which case it'll use a popup buffer). --- init.example.el | 2 +- modules/README.org | 2 +- modules/lang/emacs-lisp/autoload.el | 30 +++++++++------- modules/tools/eval/README.org | 8 +++-- modules/tools/eval/autoload/eval.el | 46 +++++++++++++++++++++++++ modules/tools/eval/config.el | 53 +++++++++++++++++++++-------- modules/tools/eval/packages.el | 3 +- 7 files changed, 111 insertions(+), 33 deletions(-) diff --git a/init.example.el b/init.example.el index 5ce4ab515..623cfc1f1 100644 --- a/init.example.el +++ b/init.example.el @@ -76,7 +76,7 @@ ;;docker ;;editorconfig ; let someone else argue about tabs vs spaces ;;ein ; tame Jupyter notebooks with emacs - eval ; run code, run (also, repls) + (eval +overlay) ; run code, run (also, repls) flycheck ; tasing you for every semicolon you forget ;;flyspell ; tasing you for misspelling mispelling ;;gist ; interacting with github gists diff --git a/modules/README.org b/modules/README.org index 5292a0f34..492301a40 100644 --- a/modules/README.org +++ b/modules/README.org @@ -84,7 +84,7 @@ Small modules that give Emacs access to external tools & services. + [[file:tools/direnv/README.org][direnv]]: + [[file:tools/editorconfig/README.org][editorconfig]]: + [[file:tools/ein/README.org][ein]]: -+ [[file:tools/eval/README.org][eval]]: REPL & code evaluation support for a variety of languages ++ [[file:tools/eval/README.org][eval]] =+overlay=: REPL & code evaluation support for a variety of languages + flycheck: Live error/warning highlights + flyspell: Spell checking + gist: diff --git a/modules/lang/emacs-lisp/autoload.el b/modules/lang/emacs-lisp/autoload.el index 6a3089c65..88b67df53 100644 --- a/modules/lang/emacs-lisp/autoload.el +++ b/modules/lang/emacs-lisp/autoload.el @@ -7,19 +7,23 @@ (defun +emacs-lisp-eval (beg end) "Evaluate a region and print it to the echo area (if one line long), otherwise to a pop up buffer." - (require 'pp) - (let ((debug-on-error t) - (buffer-file-name (buffer-file-name (buffer-base-buffer))) - (doom--current-module (ignore-errors (doom-module-from-path buffer-file-name))) - (temp-buffer-show-hook - (cons (if (fboundp '+word-wrap-mode) - '+word-wrap-mode - 'visual-line-mode) - temp-buffer-show-hook))) - (pp-eval-expression - (read (buffer-substring-no-properties beg end))) - (when-let (win (get-buffer-window "*Pp Eval Output*")) - (fit-window-to-buffer win)))) + (+eval-display-results + (let* ((buffer-file-name (buffer-file-name (buffer-base-buffer)))) + (string-trim-right + (condition-case-unless-debug e + (let ((result + (let ((debug-on-error t)) + (eval (read (buffer-substring-no-properties beg end)) + `((buffer-file-name . ,buffer-file-name) + (doom--current-module + . ,(ignore-errors + (doom-module-from-path buffer-file-name)))))))) + (if (stringp result) + result + (require 'pp) + (pp-to-string result))) + (error (error-message-string e))))) + (current-buffer))) (defvar +emacs-lisp--face nil) ;;;###autoload diff --git a/modules/tools/eval/README.org b/modules/tools/eval/README.org index 86ad84209..af2842ea3 100644 --- a/modules/tools/eval/README.org +++ b/modules/tools/eval/README.org @@ -18,11 +18,13 @@ - [[Troubleshooting][Troubleshooting]] * Description -This modules adds inline code evaluation support to Emacs, and supplies a -universal interface for opening and interacting with REPLs. +This modules adds inline code evaluation support to Emacs and a universal +interface for opening and interacting with REPLs. ** Module Flags -This module has no flags. ++ =+overlay= Enables the use of overlays (near the cursor) to display the result + of inline code evaluation (rather than the minibuffer). That is, unless the + results are too big, in which case it will still fall back to popup buffers. ** Plugins + [[https://github.com/syohex/emacs-quickrun][quickrun]] diff --git a/modules/tools/eval/autoload/eval.el b/modules/tools/eval/autoload/eval.el index 6a129a2be..e14353861 100644 --- a/modules/tools/eval/autoload/eval.el +++ b/modules/tools/eval/autoload/eval.el @@ -1,5 +1,51 @@ ;;; tools/eval/autoload/eval.el -*- lexical-binding: t; -*- +;;;###autoload +(defun +eval-display-results-in-popup (output &optional source-buffer) + "Display OUTPUT in a popup buffer." + (let ((output-buffer (get-buffer-create "*doom eval*")) + (origin (selected-window))) + (with-current-buffer output-buffer + (setq-local scroll-margin 0) + (erase-buffer) + (insert output) + (goto-char (point-min)) + (if (fboundp '+word-wrap-mode) + (+word-wrap-mode +1) + (visual-line-mode +1))) + (when-let (win (display-buffer output-buffer)) + (fit-window-to-buffer win)) + (select-window origin) + output-buffer)) + +;;;###autoload +(defun +eval-display-results-in-overlay (output &optional source-buffer) + "Display OUTPUT in a floating overlay next to the cursor." + (let ((this-command #'+eval/buffer-or-region) + eros-overlays-use-font-lock) + (with-current-buffer (or source-buffer (current-buffer)) + (eros--make-result-overlay output + :where (line-end-position) + :duration eros-eval-result-duration)))) + +;;;###autoload +(defun +eval-display-results (output &optional source-buffer) + "Display OUTPUT in an overlay or a popup buffer." + (funcall (if (and (or current-prefix-arg + (with-temp-buffer + (insert output) + (>= (count-lines (point-min) (point-max)) + +eval-overlay-max-lines))) + (require 'eros nil t)) + #'+eval-display-results-in-popup + #'+eval-display-results-in-overlay) + output source-buffer) + output) + + +;; +;;; Commands + ;;;###autoload (defun +eval/buffer () "Evaluate the whole buffer." diff --git a/modules/tools/eval/config.el b/modules/tools/eval/config.el index 0b9abf085..480f2c476 100644 --- a/modules/tools/eval/config.el +++ b/modules/tools/eval/config.el @@ -1,12 +1,16 @@ ;;; tools/eval/config.el -*- lexical-binding: t; -*- +(defvar +eval-overlay-max-lines 4 + "The output height threshold (inclusive) before output is displayed in a popup +buffer rather than an overlay on the line at point.") + ;; remove ellipsis when printing sexps in message buffer (setq eval-expression-print-length nil eval-expression-print-level nil) ;; -;; Packages +;;; Packages (set-popup-rule! (lambda (bufname _) @@ -26,15 +30,6 @@ (set-popup-rule! "^\\*quickrun" :size 0.3 :ttl 0) - (defadvice! +eval--quickrun-auto-close-a (&rest _) - "Allows us to silently re-run quickrun from within the quickrun buffer." - :before '(quickrun quickrun-region) - (when-let (win (get-buffer-window quickrun--buffer-name)) - (let ((inhibit-message t)) - (quickrun--kill-running-process) - (message "")) - (delete-window win))) - (defadvice! +eval--quickrun-fix-evil-visual-region-a () "Make `quickrun-replace-region' recognize evil visual selections." :override #'quickrun--outputter-replace-region @@ -51,17 +46,47 @@ (insert output)) (setq quickrun-option-outputter quickrun--original-outputter)))) + (defadvice! +eval--quickrun-auto-close-a (&rest _) + "Silently re-create the quickrun popup when re-evaluating." + :before '(quickrun quickrun-region) + (when-let (win (get-buffer-window quickrun--buffer-name)) + (let ((inhibit-message t)) + (quickrun--kill-running-process) + (message "")) + (delete-window win))) + (add-hook! 'quickrun-after-run-hook (defun +eval-quickrun-shrink-window-h () "Shrink the quickrun output window once code evaluation is complete." (when-let (win (get-buffer-window quickrun--buffer-name)) (with-selected-window (get-buffer-window quickrun--buffer-name) (let ((ignore-window-parameters t)) - (shrink-window-if-larger-than-buffer)))))) - - (add-hook! 'quickrun-after-run-hook + (shrink-window-if-larger-than-buffer))))) (defun +eval-quickrun-scroll-to-bof-h () "Ensures window is scrolled to BOF on invocation." (when-let (win (get-buffer-window quickrun--buffer-name)) (with-selected-window win - (goto-char (point-min))))))) + (goto-char (point-min)))))) + + ;; Display evaluation results in an overlay next to the cursor. If the output + ;; is more than 4 lines long, it is displayed in a popup. + (when (featurep! +overlay) + (defadvice! +eval--inhibit-quickrun-popup-a (buf cb) + :override #'quickrun--pop-to-buffer + (setq quickrun--original-buffer (current-buffer)) + (with-current-buffer buf + (setq quickrun-option-outputter #'ignore) + (funcall cb))) + + (advice-add #'quickrun--recenter :override #'ignore) + (add-hook! 'quickrun-after-run-hook + (defun +eval-display-in-popup-overlay-h () + (+eval-display-results + (with-current-buffer quickrun--buffer-name + (string-trim (buffer-string))) + quickrun--original-buffer))))) + + +(use-package! eros + :when (featurep! +overlay) + :hook (emacs-lisp-mode . eros-mode)) diff --git a/modules/tools/eval/packages.el b/modules/tools/eval/packages.el index f27dff025..ba755f7c2 100644 --- a/modules/tools/eval/packages.el +++ b/modules/tools/eval/packages.el @@ -2,4 +2,5 @@ ;;; tools/eval/packages.el (package! quickrun) - +(when (featurep! +overlay) + (package! eros))