This is a mess
I'm sorry. I really wanted to improve my commit discipline. I know. I can't be fucked to comb this diff and split it into 8 properly-ordered commits, like I know I should. I'm not having a good time right now. We'll do better moving forward.
This commit is contained in:
@@ -118,6 +118,15 @@ See `syd-real-buffer-p' for details on what that means."
|
||||
(when (syd-unreal-buffer-p (window-buffer))
|
||||
(switch-to-buffer (syd-fallback-buffer)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun syd-set-buffer-realness (buffer realness)
|
||||
(with-current-buffer buffer
|
||||
(setq syd-real-buffer-p realness)))
|
||||
|
||||
;;;###autoload
|
||||
(defun syd-mark-buffer-as-real ()
|
||||
(syd-set-buffer-realness (current-buffer) t))
|
||||
|
||||
(defun syd-kill-buffer-fixup-windows (buffer)
|
||||
"Kill the BUFFER and ensure all the windows it was displayed in have switched
|
||||
to a real buffer or the fallback buffer."
|
||||
|
||||
258
users/crumb/programs/emacs/lib/syd-handle-eval.el
Normal file
258
users/crumb/programs/emacs/lib/syd-handle-eval.el
Normal file
@@ -0,0 +1,258 @@
|
||||
;;; syd-handle-eval.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar syd-eval-runners '())
|
||||
|
||||
;; Remove ellipsis when printing sexps in message buffer.
|
||||
(setq eval-expression-print-length nil
|
||||
eval-expression-print-level nil)
|
||||
|
||||
(set-popup-rule!
|
||||
"*eval*"
|
||||
:size 0.2)
|
||||
|
||||
|
||||
;; Packages
|
||||
|
||||
(use-package quickrun
|
||||
:defer t)
|
||||
|
||||
(use-package eros
|
||||
:hook (emacs-lisp-mode . eros-mode))
|
||||
|
||||
;; (with-eval-after-load quickrun
|
||||
;; (setq quickrun-focus-p nil)
|
||||
|
||||
;; (set-popup-rule! "^\\*quickrun" :size 0.3 :ttl 0)
|
||||
|
||||
;; (defadvice! +eval--quickrun-fix-evil-visual-region-a ()
|
||||
;; "Make `quickrun-replace-region' recognize evil visual selections."
|
||||
;; :override #'quickrun--outputter-replace-region
|
||||
;; (let ((output (buffer-substring-no-properties (point-min) (point-max))))
|
||||
;; (with-current-buffer quickrun--original-buffer
|
||||
;; (cl-destructuring-bind (beg . end)
|
||||
;; ;; Because `deactivate-mark', the function, was used in
|
||||
;; ;; `quickrun--region-command-common' instead of `deactivate-mark',
|
||||
;; ;; the variable, the selection is disabled by this point.
|
||||
;; (if (bound-and-true-p evil-local-mode)
|
||||
;; (cons evil-visual-beginning evil-visual-end)
|
||||
;; (cons (region-beginning) (region-end)))
|
||||
;; (delete-region beg end)
|
||||
;; (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)))))
|
||||
;; (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))))))
|
||||
|
||||
;; ;; Display evaluation results in an overlay at the end of the current line. If
|
||||
;; ;; the output is more than `+eval-popup-min-lines' (4) lines long, it is
|
||||
;; ;; displayed in a popup.
|
||||
;; (when (modulep! +overlay)
|
||||
;; (defadvice! +eval--show-output-in-overlay-a (fn)
|
||||
;; :filter-return #'quickrun--make-sentinel
|
||||
;; (lambda (process event)
|
||||
;; (funcall fn process event)
|
||||
;; (with-current-buffer quickrun--buffer-name
|
||||
;; (when (> (buffer-size) 0)
|
||||
;; (+eval-display-results
|
||||
;; (string-trim (buffer-string))
|
||||
;; quickrun--original-buffer)))))
|
||||
|
||||
;; ;; Suppress quickrun's popup window because we're using an overlay instead.
|
||||
;; (defadvice! +eval--inhibit-quickrun-popup-a (buf cb)
|
||||
;; :override #'quickrun--pop-to-buffer
|
||||
;; (setq quickrun--original-buffer (current-buffer))
|
||||
;; (save-window-excursion
|
||||
;; (with-current-buffer (pop-to-buffer buf)
|
||||
;; (setq quickrun-option-outputter #'ignore)
|
||||
;; (funcall cb))))
|
||||
|
||||
;; ;; HACK Without this, `+eval--inhibit-quickrun-popup-a' throws a
|
||||
;; ;; window-live-p error because no window exists to be recentered!
|
||||
;; (advice-add #'quickrun--recenter :override #'ignore)))
|
||||
|
||||
|
||||
|
||||
;;;###autoload
|
||||
(cl-defun syd-eval-region-as-major-mode
|
||||
(beg end &key (runner-major-mode major-mode))
|
||||
"Evaluate a region between BEG and END and display the output.
|
||||
|
||||
Evaluate as in RUNNER-MAJOR-MODE. If RUNNER-MAJOR-MODE is nil, use major-mode
|
||||
of the buffer instead."
|
||||
(if-let* ((runner (alist-get runner-major-mode syd-eval-runners)))
|
||||
(funcall runner beg end)
|
||||
(and (require 'quickrun nil t)
|
||||
(let ((quickrun-option-cmdkey
|
||||
(quickrun--command-key
|
||||
(buffer-file-name (buffer-base-buffer)))))
|
||||
(quickrun-region beg end)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun syd-eval-region (beg end)
|
||||
(interactive "r")
|
||||
;; (message "syd: %s" (pp-to-string
|
||||
;; (buffer-substring-no-properties (syd-region-beginning)
|
||||
;; (syd-region-end))))
|
||||
;; (message "r: %s" (pp-to-string (buffer-substring-no-properties beg end)))
|
||||
(syd-eval-region-as-major-mode beg end))
|
||||
|
||||
(with-eval-after-load 'evil
|
||||
(evil-define-operator syd-eval-operator (beg end)
|
||||
"Evaluate selection."
|
||||
:move-point nil
|
||||
(interactive "<r>")
|
||||
(syd-eval-region beg end))
|
||||
|
||||
(general-def
|
||||
:states 'normal
|
||||
"gR" #'syd-eval-buffer)
|
||||
|
||||
(general-def
|
||||
:states '(normal visual)
|
||||
"gr" #'syd-eval-operator))
|
||||
|
||||
;;;###autoload
|
||||
(defun set-eval-handler! (modes command)
|
||||
"Define a code evaluator for major mode MODES with `quickrun'.
|
||||
|
||||
MODES can be list of major mode symbols, or a single one.
|
||||
|
||||
1. If MODE is a string and COMMAND is the string, MODE is a file regexp and
|
||||
COMMAND is a string key for an entry in `quickrun-file-alist'.
|
||||
2. If MODE is not a string and COMMAND is a string, MODE is a major-mode symbol
|
||||
and COMMAND is a key (for `quickrun--language-alist'), and will be registered
|
||||
in `quickrun--major-mode-alist'.
|
||||
3. If MODE is not a string and COMMAND is an alist, see `quickrun-add-command':
|
||||
(quickrun-add-command MODE COMMAND :mode MODE).
|
||||
4. If MODE is not a string and COMMANd is a symbol, add it to
|
||||
`syd-eval-runners', which is used by `syd-eval-region'."
|
||||
(declare (indent defun))
|
||||
(dolist (mode (ensure-list modes))
|
||||
(cond ((symbolp command)
|
||||
(push (cons mode command) syd-eval-runners))
|
||||
((stringp command)
|
||||
(with-eval-after-load 'quickrun
|
||||
(push (cons mode command)
|
||||
(if (stringp mode)
|
||||
quickrun-file-alist
|
||||
quickrun--major-mode-alist))))
|
||||
((listp command)
|
||||
(with-eval-after-load 'quickrun
|
||||
(quickrun-add-command
|
||||
(or (cdr (assq mode quickrun--major-mode-alist))
|
||||
(string-remove-suffix "-mode" (symbol-name mode)))
|
||||
command :mode mode))))))
|
||||
|
||||
(defvar syd-eval-overlay-max-lines 4
|
||||
"The maximum number of lines allowed to be displayed in an eval overlay; any
|
||||
more and a popup buffer will be used instead.")
|
||||
|
||||
;;;###autoload
|
||||
(defun syd-eval-display-results-in-popup (output)
|
||||
"Display OUTPUT in a popup buffer."
|
||||
(let ((output-buffer (get-buffer-create "*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 (/ (frame-height) 2)
|
||||
;; nil (/ (frame-width) 2))
|
||||
)
|
||||
(select-window origin)
|
||||
output-buffer))
|
||||
|
||||
;;;###autoload
|
||||
(defun syd-eval-buffer ()
|
||||
"Evaluate the entire buffer."
|
||||
(interactive)
|
||||
(syd-eval-region (point-min) (point-max)))
|
||||
|
||||
;;;###autoload
|
||||
(defun syd-eval-buffer-or-region ()
|
||||
"Evaluate the region if it is active, or the entire buffer, or not."
|
||||
(if (use-region-p)
|
||||
(call-interactively #'syd-eval-region)
|
||||
(call-interactively #'syd-eval-buffer)))
|
||||
|
||||
;;;###autoload
|
||||
(cl-defun syd-eval-display-results-in-overlay (output &key source-buffer)
|
||||
"Display OUTPUT in a floating overlay next to the cursor."
|
||||
(require 'eros)
|
||||
(with-current-buffer (or source-buffer (current-buffer))
|
||||
(let* ((this-command #'syd-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
|
||||
(cl-defun syd-eval-display-results (output &key source-buffer force-popup)
|
||||
"Display OUTPUT in an overlay, or if it's too long, a popup buffer."
|
||||
(if (or force-popup
|
||||
;; EROS is used to display overlays. Without it, just use a popup.
|
||||
(not (require 'eros nil t))
|
||||
(with-temp-buffer
|
||||
(insert output)
|
||||
(or
|
||||
;; Too tall!
|
||||
(<= syd-eval-overlay-max-lines
|
||||
(count-lines (point-min) (point-max)))
|
||||
;; Too wide!
|
||||
(<= (window-width)
|
||||
(string-width
|
||||
(buffer-substring (point-min)
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(line-end-position))))))))
|
||||
(syd-eval-display-results-in-popup output)
|
||||
(syd-eval-display-results-in-overlay output :source-buffer source-buffer))
|
||||
output)
|
||||
|
||||
(provide 'syd-handle-eval)
|
||||
@@ -6,11 +6,59 @@
|
||||
|
||||
(require 'better-jumper)
|
||||
|
||||
(defvar syd-lookup-documentation-handlers '()
|
||||
"An list of lookup handlers used to find documentation. A lookup handler
|
||||
(defvar syd-lookup-online-documentation-backends
|
||||
`(("Kagi" . "https://kagi.com/search?q=%s")
|
||||
("DuckDuckGo" . "https://duckduckgo.com/?q=%s")
|
||||
("Nixpkgs" . "https://search.nixos.org/packages?query=%s")
|
||||
("Hackage" . "https://hackage.haskell.org/packages/search?terms=%s"))
|
||||
"A list of pairs (NAME . BACKEND) describing the various backends
|
||||
`syd-lookup-online-documentation' may delegate to.
|
||||
|
||||
NAME is a string used when speaking to the user about BACKEND.
|
||||
|
||||
If BACKEND is an interactive command, it will be called interactively.
|
||||
|
||||
If BACKEND is a procedure, it will be called with the search string as the lone
|
||||
argument.
|
||||
|
||||
If BACKEND is a string, the user's browser will be opened to the URL returned by
|
||||
(format BACKEND QUERY), where QUERY is the appropriately-encoded search
|
||||
string.")
|
||||
|
||||
(defvar syd-lookup-documentation-handlers '(syd-lookup-online-documentation)
|
||||
"A list of lookup handlers used to find documentation. A lookup handler
|
||||
receives an identifier, and is expected to return nil on failure, and non-nil on
|
||||
success. The specific return value is unused outside of the test for nil.")
|
||||
|
||||
(defun syd-lookup--prompt-for-online-backend ()
|
||||
(assoc-string
|
||||
(completing-read "Search with: "
|
||||
(mapcar #'car syd-lookup-online-documentation-backends)
|
||||
nil
|
||||
t)
|
||||
syd-lookup-online-documentation-backends))
|
||||
|
||||
(cl-defun syd-lookup--call-online-backend (backend &key query-string)
|
||||
(pcase-let ((`(,name . ,backend-fn) backend))
|
||||
(cond ((functionp backend-fn) (if (commandp backend-fn)
|
||||
(call-interactively backend-fn)
|
||||
(funcall backend-fn query-string)))
|
||||
((stringp backend-fn)
|
||||
(browse-url (format backend-fn
|
||||
(url-encode-url
|
||||
(read-string (format "Search for (on %s): "
|
||||
name)
|
||||
query-string)))))
|
||||
(t (signal 'wrong-type-argument `("backend" ,backend-fn))))))
|
||||
|
||||
;;;###autoload
|
||||
(cl-defun syd-lookup-online-documentation (backend &key query-string)
|
||||
(interactive (list (syd-lookup--prompt-for-online-backend)
|
||||
:query-string (when (use-region-p)
|
||||
(syd-thing-at-point-or-region))))
|
||||
(syd-lookup--call-online-backend (syd-lookup--prompt-for-online-backend)
|
||||
:query-string query-string))
|
||||
|
||||
;;;###autoload
|
||||
(defun syd-lookup-documentation (identifier)
|
||||
"Try to find documentation on IDENTIFIER, and "
|
||||
@@ -28,6 +76,8 @@ success. The specific return value is unused outside of the test for nil.")
|
||||
(category identifier &key (display-fn #'switch-to-buffer))
|
||||
(let* ((handlers (alist-get category syd-lookup--handlers-by-category))
|
||||
(origin (point-marker))
|
||||
;; TODO: If called with a prefix argument, prompt the user to select a
|
||||
;; handler.
|
||||
(result (run-hook-wrapped handlers #'syd-lookup--run-handler
|
||||
identifier origin)))
|
||||
(message "result wrap hok: %S" result)
|
||||
|
||||
@@ -12,4 +12,52 @@
|
||||
,todo
|
||||
(error ,todo))))
|
||||
|
||||
(cl-defun syd--lift-lambdas (forms &key with-each with-all)
|
||||
;; Call the continuation if non-nil. Wraps the return value in a singleton
|
||||
;; list for "affine" use with unquote-splicing.
|
||||
(let ((call-cont (lambda (cont)
|
||||
(if cont
|
||||
(lambda (name) (list (funcall with-each name)))
|
||||
(lambda (_) nil))))
|
||||
names)
|
||||
`(progn ,@(mapconcat (lambda (form)
|
||||
(cond ((and (symbolp form) (functionp form))
|
||||
(push form names)
|
||||
(call-cont with-each form))
|
||||
((eq (car-safe form) 'defun)
|
||||
(let ((name (nth 1 form)))
|
||||
(push name names)
|
||||
`(,form
|
||||
,@(call-cont with-each))))
|
||||
((eq (car-safe form) 'lambda)
|
||||
(let ((name (gensym "lifted-lambda")))
|
||||
(push name names)
|
||||
`((defun ,name (&rest args)
|
||||
(,form args))
|
||||
,@(call-cont with-each))))))
|
||||
(ensure-list forms))
|
||||
,@(call-cont with-all names))))
|
||||
|
||||
;; (defun syd-hform-defun (hform)
|
||||
;; "If HFORM is a defun form, return the defun's name. Otherwise, return nil"
|
||||
;; (and (listp hform)
|
||||
;; (<= 2 (length hform))
|
||||
;; (nth 1 hform)))
|
||||
|
||||
(defmacro with-transient-after (hook-or-function &rest forms)
|
||||
(let ((hook-name (gensym "transient-hook"))
|
||||
(hook-or-function* (gensym "hook-or-function")))
|
||||
`(let* ((,hook-or-function* ,hook-or-function))
|
||||
(defun ,hook-name (&rest _)
|
||||
"Transient hook defined by `with-transient-after'."
|
||||
(cond ((functionp ,hook-or-function*)
|
||||
(advice-remove ,hook-or-function* (function ,hook-name)))
|
||||
((symbolp ,hook-or-function*)
|
||||
(remove-hook ,hook-or-function* (function ,hook-name))))
|
||||
,@forms)
|
||||
(cond ((functionp ,hook-or-function*)
|
||||
(advice-add ,hook-or-function* :before (function ,hook-name)))
|
||||
((symbolp ,hook-or-function*)
|
||||
(add-hook ,hook-or-function* (function ,hook-name)))))))
|
||||
|
||||
(provide 'syd-prelude)
|
||||
|
||||
Reference in New Issue
Block a user