2017-03-04 18:28:51 -05:00
|
|
|
;;; feature/eval/config.el
|
2017-02-13 16:57:08 -05:00
|
|
|
|
2017-03-04 18:28:51 -05:00
|
|
|
;; This module creates a centralized way of invoking/sending selections to REPLs
|
|
|
|
;; (with `repl-toggle'), building projects/files, and running code (with
|
|
|
|
;; `quickrun'), revealing its output in a popup window.
|
2017-02-13 16:57:08 -05:00
|
|
|
|
2017-03-04 18:28:51 -05:00
|
|
|
;;
|
|
|
|
;; Code building
|
|
|
|
;;
|
2017-02-13 16:57:08 -05:00
|
|
|
|
2017-03-04 18:28:51 -05:00
|
|
|
(defvar +eval-builders nil
|
|
|
|
"A nested alist, mapping major modes to build function plists. Used by
|
|
|
|
`+eval/build' and filled with the `:build' setting.")
|
2017-02-13 16:57:08 -05:00
|
|
|
|
2017-04-07 01:19:55 -04:00
|
|
|
(def-setting! :build (name modes fn &rest plist)
|
|
|
|
"Define a build function (FN) for MODES (can be major or minor) called NAME.
|
2017-03-04 18:28:51 -05:00
|
|
|
|
|
|
|
PLIST accepts the following properties:
|
|
|
|
|
|
|
|
:when FORM A predicate to determine if the builder is appropriate for this
|
|
|
|
buffer."
|
2017-04-07 01:19:55 -04:00
|
|
|
`(dolist (mode ',(if (listp modes) modes (list modes)) +eval-builders)
|
|
|
|
(unless (assq mode +eval-builders)
|
|
|
|
(push (list mode) +eval-builders))
|
|
|
|
(push (cons ',name (append (list :fn #',fn) ',plist))
|
|
|
|
(cdr (assq mode +eval-builders)))))
|
2017-03-04 18:28:51 -05:00
|
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
;; REPLs
|
|
|
|
;;
|
|
|
|
|
|
|
|
(defvar +eval-repls nil
|
|
|
|
"An alist mapping major modes to plists that describe REPLs. Used by
|
|
|
|
`+eval/repl' and filled with the `:repl' setting.")
|
|
|
|
|
|
|
|
(define-minor-mode +eval-repl-mode
|
|
|
|
"A minor mode for REPL buffers."
|
|
|
|
:init-value nil)
|
2017-02-13 16:57:08 -05:00
|
|
|
|
2017-02-23 00:06:12 -05:00
|
|
|
(def-setting! :repl (mode command)
|
2017-03-04 18:28:51 -05:00
|
|
|
"Define a REPL for a mode. MODE is a major mode and COMMAND is a function that
|
|
|
|
invokes the repl. Takes the same arguements as `rtog/add-repl'."
|
|
|
|
`(push ',(cons mode command) +eval-repls))
|
|
|
|
|
|
|
|
(set! :popup
|
|
|
|
'(:custom (lambda (b &rest _) (buffer-local-value '+eval-repl-mode b)))
|
|
|
|
:size 16 :noesc t)
|
|
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
;; Evaluation
|
|
|
|
;;
|
|
|
|
|
|
|
|
;; remove ellipsis when printing sexps in message buffer
|
|
|
|
(setq eval-expression-print-length nil
|
|
|
|
eval-expression-print-level nil)
|
2017-02-13 16:57:08 -05:00
|
|
|
|
2017-05-07 02:27:54 +02:00
|
|
|
(defvar +eval-runners-alist nil
|
|
|
|
"Alist mapping major modes to interactive runner functions.")
|
|
|
|
|
2017-02-23 00:06:12 -05:00
|
|
|
(def-setting! :eval (mode command)
|
2017-03-04 18:28:51 -05:00
|
|
|
"Define a code evaluator for major mode MODE with `quickrun'.
|
2017-02-19 18:40:52 -05:00
|
|
|
|
|
|
|
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
|
2017-03-04 18:28:51 -05:00
|
|
|
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':
|
2017-05-07 02:27:54 +02:00
|
|
|
(quickrun-add-command MODE COMMAND :mode MODE).
|
|
|
|
4. If MODE is not a string and COMMANd is a symbol, add it to
|
|
|
|
`+eval-runners-alist', which is used by `+eval/region'."
|
2017-03-04 18:28:51 -05:00
|
|
|
`(after! quickrun
|
2017-05-07 02:27:54 +02:00
|
|
|
,(cond ((symbolp command)
|
|
|
|
`(push ',(cons mode command) +eval-runners-alist))
|
|
|
|
((stringp command)
|
2017-03-19 22:50:52 -04:00
|
|
|
`(push ',(cons mode command)
|
|
|
|
,(if (stringp mode)
|
|
|
|
'quickrun-file-alist
|
|
|
|
'quickrun--major-mode-alist)))
|
|
|
|
((listp command)
|
|
|
|
`(quickrun-add-command
|
|
|
|
,(symbol-name mode)
|
|
|
|
',command :mode ',mode)))))
|
2017-02-13 16:57:08 -05:00
|
|
|
|
2017-02-23 00:06:12 -05:00
|
|
|
(def-package! quickrun
|
2017-02-13 16:57:08 -05:00
|
|
|
:commands (quickrun
|
|
|
|
quickrun-region
|
|
|
|
quickrun-with-arg
|
|
|
|
quickrun-shell
|
|
|
|
quickrun-compile-only
|
|
|
|
quickrun-replace-region)
|
2017-02-28 12:12:09 -05:00
|
|
|
:init
|
2017-03-04 18:28:51 -05:00
|
|
|
;; Use standard linum-mode for quickrun eval windows; so we can have different
|
2017-04-18 05:02:03 -04:00
|
|
|
;; rules for it. Plus, hide modeline in it.
|
|
|
|
(add-hook 'quickrun--mode-hook #'linum-mode)
|
2017-03-04 18:28:51 -05:00
|
|
|
|
2017-02-13 16:57:08 -05:00
|
|
|
:config
|
2017-04-18 05:00:54 -04:00
|
|
|
(set! :popup "*quickrun*" :size 10 :noesc t :autokill t :autoclose t)
|
2017-02-13 16:57:08 -05:00
|
|
|
|
|
|
|
;; don't auto-focus quickrun windows. Shackle handles that for us.
|
|
|
|
(setq quickrun-focus-p nil)
|
|
|
|
|
2017-03-04 18:28:51 -05:00
|
|
|
(defun +eval*quickrun-auto-close (&rest _)
|
2017-02-28 12:12:09 -05:00
|
|
|
"Allows us to silently re-run quickrun from within the quickrun buffer."
|
2017-03-04 18:28:51 -05:00
|
|
|
(when-let (win (get-buffer-window quickrun--buffer-name))
|
|
|
|
(let ((inhibit-message t))
|
|
|
|
(quickrun--kill-running-process)
|
2017-02-13 16:57:08 -05:00
|
|
|
(message ""))
|
2017-03-04 18:28:51 -05:00
|
|
|
(delete-window win)))
|
2017-04-17 02:17:10 -04:00
|
|
|
(advice-add #'quickrun :before #'+eval*quickrun-auto-close)
|
|
|
|
(advice-add #'quickrun-region :before #'+eval*quickrun-auto-close)
|
2017-02-13 16:57:08 -05:00
|
|
|
|
2017-03-04 18:28:51 -05:00
|
|
|
(defun +eval|quickrun-scroll-to-bof ()
|
2017-02-28 12:12:09 -05:00
|
|
|
"Ensures window is scrolled to BOF on invocation."
|
2017-03-04 18:28:51 -05:00
|
|
|
(with-selected-window (get-buffer-window quickrun--buffer-name)
|
2017-02-13 16:57:08 -05:00
|
|
|
(goto-char (point-min))))
|
2017-04-17 02:17:10 -04:00
|
|
|
(add-hook 'quickrun-after-run-hook #'+eval|quickrun-scroll-to-bof))
|
2017-02-13 16:57:08 -05:00
|
|
|
|