doomemacs/modules/tools/eval/autoload/eval.el
2026-03-10 21:59:14 -04:00

163 lines
5.6 KiB
EmacsLisp

;;; tools/eval/autoload/eval.el -*- lexical-binding: t; -*-
(defvar quickrun-option-cmdkey)
(defvar eros-overlays-use-font-lock)
;;
;;; Library
;;;###autoload
(defun +eval-display-results-in-popup (output &optional _source-buffer)
"Display OUTPUT in a popup buffer at the bottom of the screen."
(let ((output-buffer (get-buffer-create "*doom eval*")))
(with-current-buffer output-buffer
(setq-local scroll-margin 0)
(erase-buffer)
(save-excursion (insert output))
(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 (/ (frame-height) 2)
nil (/ (frame-width) 2)))
output-buffer))
;;;###autoload
(defun +eval-display-results-in-overlay (output &optional source-buffer)
"Display OUTPUT in a floating overlay next to or below the cursor."
(require 'eros)
(with-current-buffer (or source-buffer (current-buffer))
(let* ((this-command #'+eval/buffer-or-region)
(prefix eros-eval-result-prefix)
(lines (split-string output "\n"))
(prefixlen (length prefix))
(len (+ (apply #'max (mapcar #'length lines))
prefixlen))
(next-line? (or (cdr lines)
(< (- (window-width)
(save-excursion (goto-char (line-end-position))
(- (current-column)
(window-hscroll))))
len)))
(pad (if next-line?
(+ (window-hscroll) prefixlen)
0))
eros-overlays-use-font-lock)
(eros--make-result-overlay
(concat (make-string (max 0 (- pad prefixlen)) ?\s)
prefix
(string-join lines (concat hard-newline (make-string pad ?\s))))
:where (if next-line?
(line-beginning-position 2)
(line-end-position))
:duration eros-eval-result-duration
:format "%s"))))
;;;###autoload
(defun +eval-display-results (output &optional source-buffer)
"Display OUTPUT in an overlay or a popup buffer."
(funcall (if (or current-prefix-arg
(with-temp-buffer
(insert output)
(or (>= (count-lines (point-min) (point-max))
+eval-popup-min-lines)
(>= (string-width
(buffer-substring (point-min)
(save-excursion
(goto-char (point-min))
(line-end-position))))
(window-width))))
(not (require 'eros nil t)))
#'+eval-display-results-in-popup
#'+eval-display-results-in-overlay)
output source-buffer)
output)
;;
;;; Eval handlers
;;;###autoload
(defun +eval-with-mode-handler-fn (beg end &optional _type mode)
"Evaluate the selection/buffer using a mode appropriate handler.
Uses whatever handler's been registered for MODE (or the current major-mode)
with `set-eval-handler!'."
(when-let* ((fn (alist-get (or mode major-mode) +eval-handler-alist)))
(funcall fn beg end)))
;;;###autoload
(defun +eval-with-quickrun-fn (beg end &optional type)
"Evaluate the region or buffer with `quickrun'."
(when (require 'quickrun nil t)
(pcase type
(`buffer (quickrun))
(`region (quickrun-region beg end))
(`replace (quickrun-replace-region beg end)))
t))
;;
;;; Commands
;;;###autoload
(defun +eval/buffer ()
"Evaluate the whole buffer and display the output.
See `+eval-handler-functions' for order of backends this uses. By default, falls
back to `quickrun'."
(interactive)
(run-hook-with-args-until-success
'+eval-handler-functions (point-min) (point-max) 'buffer))
;;;###autoload
(defun +eval/region (beg end)
"Evaluate a region between BEG and END and display the output.
If a REPL is open, code will be executed there, otherwise mode-specific handlers
will be used, falling back to `quickrun' otherwise.
See `+eval-handler-functions' for order of backends this uses. By default, falls
back to `quickrun'."
(interactive "r")
(run-hook-with-args-until-success
'+eval-handler-functions beg end 'region))
;;;###autoload
(defun +eval/line-or-region ()
"Evaluate the current line or selected region.
If a REPL is open, code will be executed there, otherwise mode-specific handlers
will be used, falling back to `quickrun' otherwise."
(interactive)
(if (use-region-p)
(call-interactively #'+eval/region)
(+eval/region (pos-bol) (pos-eol))))
;;;###autoload
(defun +eval/buffer-or-region ()
"Execute `+eval/region' if a selection is active, otherwise `+eval/buffer'."
(interactive)
(call-interactively
(if (doom-region-active-p)
#'+eval/region
#'+eval/buffer)))
;;;###autoload
(defun +eval/region-and-replace (beg end)
"Evaluate a region between BEG and END, and replace it with the result.
Uses `quickrun', unless in an `emacs-lisp-mode' buffer, in which case uses the
return value of `eval'."
(interactive "r")
(if (not (derived-mode-p 'emacs-lisp-mode))
(quickrun-replace-region beg end)
(kill-region beg end)
(condition-case nil
(prin1 (eval (read (current-kill 0)))
(current-buffer))
(error (message "Invalid expression")
(insert (current-kill 0))))))
;;; eval.el ends here