diff --git a/modules/feature/eval/README.org b/modules/feature/eval/README.org index ff669433d..eb9cf3084 100644 --- a/modules/feature/eval/README.org +++ b/modules/feature/eval/README.org @@ -1,13 +1,12 @@ #+TITLE: :feature eval -This modules adds support for REPLs, build tasks and code evaluation. +This modules adds support for evaluating code from inside Emacs. This includes REPLs and direct access to the interpreters and compilers of many languages. * Table of Contents :TOC: - [[#install][Install]] - [[#usage][Usage]] - [[#configuration][Configuration]] - [[#repls][REPLs]] - - [[#build-tasks][Build Tasks]] - [[#code-evaluation][Code Evaluation]] * Install @@ -20,15 +19,8 @@ Check the README.org in that language's module for details. Invoked via: + ~:repl~ (evil ex-command) + = o r= in normal mode (or visual mode, which sends the selection to the open REPL) - + ~M-x +eval/repl~ - + ~M-x +eval/repl-send-region~ while a selection (and REPL) is active - -+ *Build Tasks* - You will be prompted to select a task. Only the ones that meet the predicate will be listed. - + ~:build~ (evil ex-command) - + =M-b= (by default) - + = o b= in normal mode - + ~M-x +eval/build~ + + ~M-x +eval/open-repl~ + + ~M-x +eval/send-region-to-repl~ while a selection (and REPL) is active + *Code Evaluation* Quickrun can be invoked via: @@ -60,35 +52,6 @@ FUNCTION must return the repl buffer. Any window changes are ignored, then hande (set! :repl 'emacs-lisp-mode #'+emacs-lisp/repl) #+END_SRC -** Build Tasks -A build task is little more than a major-mode-local interactive command that performs a task, such as compiling the current project or running unit tests. A predicate function can be supplied to ensure a command is only available when it is appropriate. - -#+BEGIN_SRC emacs-lisp -(defun +lua/run-love () - "Run the current project in love 10.0." - (async-shell-command - (format "/usr/bin/love %s" - (shell-quote-argument (doom-project-root))))) - -(defun +lua/build () - "Run a build script in the project root." - (let ((default-directory (doom-project-root))) - (compile "luajit build.lua"))) - -(defun +lua/generate-docs () - "Generate project documentation." - (let ((default-directory (doom-project-root))) - (compile "luadoc *.lua"))) - -(defun +lua-love-p () - "Returns non-nil if the current project is a love project." - (doom-project-has! (and "main.lua" "config.lua"))) - -(set! :build 'run 'lua-mode #'+lua/run-love :when (+lua-love-p)) -(set! :build 'build-project 'lua-mode #'+lua/build :when (+lua-love-p)) -(set! :build 'generate-docs 'lua-mode #'+lua/generate-docs) -#+END_SRC - ** Code Evaluation Run regions or entire buffers with [[https://github.com/syohex/emacs-quickrun][Quickrun]]. Output will be sent to a popup window. diff --git a/modules/feature/eval/autoload/build.el b/modules/feature/eval/autoload/build.el deleted file mode 100644 index cdf9c181b..000000000 --- a/modules/feature/eval/autoload/build.el +++ /dev/null @@ -1,45 +0,0 @@ -;;; feature/eval/autoload/build.el -*- lexical-binding: t; -*- - -(defvar-local +eval-last-builder nil - "The last builder run in the current buffer.") - -(defvar +eval-current-builder nil - "The spec for the currently running builder. Available from inside builder -functions.") - -(defun +eval--read-builder () - (when-let (builders - (cl-remove-if-not - (lambda (plist) - (if-let (pred (plist-get plist :when)) - (and (or (symbolp pred) - (functionp pred)) - (funcall pred)) - t)) - (cl-delete-duplicates - (reverse (cdr (assq major-mode +eval-builders))) - :key 'car) - :key 'cdr)) - (if (= (length builders) 1) - (car builders) - (when-let (builder (completing-read "Build: " (mapcar #'car builders) nil t)) - (assq (intern builder) builders))))) - -;;;###autoload -(defun +eval/build (builder) - "TODO" - (interactive - (list (or +eval-last-builder - (+eval--read-builder) - (error "No builder for this buffer")))) - (unless builder - (error "Builder not found in registered builders")) - (let ((name (car builder)) - (fn (plist-get (cdr builder) :fn))) - (message "Running %s" name) - (if (or (functionp fn) - (and (symbolp fn) (fboundp fn))) - (let ((+eval-current-builder builder)) - (funcall fn)) - (error "'%s' builder is invalid" name)))) - diff --git a/modules/feature/eval/autoload/eval.el b/modules/feature/eval/autoload/eval.el index d9d185c52..45e4ebc34 100644 --- a/modules/feature/eval/autoload/eval.el +++ b/modules/feature/eval/autoload/eval.el @@ -4,22 +4,22 @@ (defun +eval/buffer () "Evaluate the whole buffer." (interactive) - (cond ((assq major-mode +eval-runners-alist) + (cond ((assq major-mode +eval-runners) (+eval/region (point-min) (point-max))) (t (quickrun)))) ;;;###autoload (defun +eval/region (beg end) - "Evaluate a region and, if large enough, prints its output to a popup buffer (if an -elisp buffer). Otherwise forward the region to Quickrun." + "Evaluate a region between BEG and END and display the output." (interactive "r") (let ((load-file-name buffer-file-name)) - (if-let (runner (cdr (assq major-mode +eval-runners-alist))) + (if-let (runner (cdr (assq major-mode +eval-runners))) (funcall runner beg end) (quickrun-region beg end)))) ;;;###autoload (defun +eval/region-and-replace (beg end) + "Evaluation a region between BEG and END, and replace it with the result." (interactive "r") (cond ((eq major-mode 'emacs-lisp-mode) (kill-region beg end) diff --git a/modules/feature/eval/autoload/evil.el b/modules/feature/eval/autoload/evil.el index 8116867d3..00b87245c 100644 --- a/modules/feature/eval/autoload/evil.el +++ b/modules/feature/eval/autoload/evil.el @@ -18,5 +18,5 @@ :move-point nil (interactive "") (if (evil-normal-state-p) - (+eval/repl) - (+eval/repl-send-region beg end bang))) + (+eval/open-repl) + (+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 d24cc564e..8b396b172 100644 --- a/modules/feature/eval/autoload/repl.el +++ b/modules/feature/eval/autoload/repl.el @@ -25,7 +25,7 @@ t)))) ;;;###autoload -(defun +eval/repl () +(defun +eval/open-repl () "Opens (or reopens) the REPL associated with the current major-mode and place the cursor at the prompt." (interactive) @@ -36,7 +36,7 @@ the cursor at the prompt." t))) ;;;###autoload -(defun +eval/repl-send-region (beg end &optional auto-execute-p) +(defun +eval/send-region-to-repl (beg end &optional auto-execute-p) "REPL must be open! Sends a selected region to it. If AUTO-EXECUTE-P, then execute it immediately after." (interactive "r") diff --git a/modules/feature/eval/config.el b/modules/feature/eval/config.el index acf9ad80f..ab63ac021 100644 --- a/modules/feature/eval/config.el +++ b/modules/feature/eval/config.el @@ -1,39 +1,15 @@ ;;; feature/eval/config.el -*- lexical-binding: t; -*- -;; -;; Code building -;; - -(defvar +eval-builders nil - "A nested alist, mapping major modes to build function plists. Used by -`+eval/build' and filled with the `:build' setting.") - -(def-setting! :build (name modes fn &rest plist) - "Define a build function (FN) for MODES (can be major or minor) called NAME. - -PLIST accepts the following properties: - - :when FORM A predicate to determine if the builder is appropriate for this - buffer." - `(dolist (mode ',(doom-enlist (doom-unquote modes)) +eval-builders) - (unless (assq mode +eval-builders) - (push (list mode) +eval-builders)) - (cl-pushnew (cons ,name (append (list :fn ,fn) (list ,@plist))) - (cdr (assq mode +eval-builders)) - :test #'eq :key #'car))) - - ;; ;; 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.") +`+eval/open-repl' and filled with the `:repl' setting.") (define-minor-mode +eval-repl-mode - "A minor mode for REPL buffers." - :init-value nil) + "A minor mode for REPL buffers.") (def-setting! :repl (mode command) "Define a REPL for a mode. MODE is a major mode symbol and COMMAND is a @@ -53,7 +29,7 @@ function that creates and returns the REPL buffer." (setq eval-expression-print-length nil eval-expression-print-level nil) -(defvar +eval-runners-alist nil +(defvar +eval-runners nil "Alist mapping major modes to interactive runner functions.") (def-setting! :eval (mode command) @@ -67,10 +43,10 @@ function that creates and returns the REPL buffer." 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 - `+eval-runners-alist', which is used by `+eval/region'." + `+eval-runners', which is used by `+eval/region'." (let ((command (doom-unquote command))) (cond ((symbolp command) - `(push (cons ,mode ',command) +eval-runners-alist)) + `(push (cons ,mode ',command) +eval-runners)) ((stringp command) `(after! quickrun (push (cons ,mode ',command) diff --git a/modules/lang/data/config.el b/modules/lang/data/config.el index 1b46a8505..71f7078e5 100644 --- a/modules/lang/data/config.el +++ b/modules/lang/data/config.el @@ -29,12 +29,7 @@ (def-package! dockerfile-mode - :mode "/Dockerfile$" - :config - ;; TODO - ;; (set! :build 'build-image 'dockerfile-mode '+data/dockerfile-build - ;; :when '+data-dockerfile-p) - ) + :mode "/Dockerfile$") ;; For ROM hacking or debugging diff --git a/modules/lang/go/autoload.el b/modules/lang/go/autoload.el index 993de0f08..18a3e1ca6 100644 --- a/modules/lang/go/autoload.el +++ b/modules/lang/go/autoload.el @@ -1,9 +1,5 @@ ;;; lang/go/autoload.el -*- lexical-binding: t; -*- -;;;###autoload -;; TODO (defun +go/build ()) - - ;; ;; Tests ;; diff --git a/modules/lang/javascript/config.el b/modules/lang/javascript/config.el index 1fd89d322..ff9d10d8d 100644 --- a/modules/lang/javascript/config.el +++ b/modules/lang/javascript/config.el @@ -184,17 +184,3 @@ :modes (html-mode css-mode web-mode js2-mode markdown-mode) :files "package.json") -(def-project-mode! +javascript-lb6-mode - :modes (web-mode js2-mode nxml-mode markdown-mode) - :match "\\.lb\\(action\\|ext\\)/" - :init - ;; TODO - ;; (when IS-MAC - ;; (set! :build 'launchbar-action '+javascript-lb6-mode - ;; (lambda () - ;; (when-let (dir (f-traverse-upwards (lambda (f) (f-ext? f "lbaction")))) - ;; (shell-command (format "open '%s'" dir)))) - ;; :when - ;; (lambda () (f-traverse-upwards (lambda (f) (f-ext? f "lbaction")))))) - ) - diff --git a/modules/lang/lua/autoload.el b/modules/lang/lua/autoload.el index a15b4ce08..2fc165a41 100644 --- a/modules/lang/lua/autoload.el +++ b/modules/lang/lua/autoload.el @@ -7,3 +7,13 @@ (lua-start-process "lua" "lua") (pop-to-buffer lua-process-buffer)) +;;;###autoload +(defun +lua/run-love-game () + "Run the current project with Love2D." + (interactive) + (async-shell-command + (format "%s %s" + (or (executable-find "love") + (if IS-MAC "open -a love.app")) + (shell-quote-argument (doom-project-root))))) + diff --git a/modules/lang/lua/config.el b/modules/lang/lua/config.el index 51a35af72..dd5d423cb 100644 --- a/modules/lang/lua/config.el +++ b/modules/lang/lua/config.el @@ -10,7 +10,16 @@ (set! :repl 'lua-mode #'+lua/repl) ;; sp's lua-specific rules are obnoxious, so we disable them - (setq sp-pairs (delete (assq 'lua-mode sp-pairs) sp-pairs))) + (setq sp-pairs (delete (assq 'lua-mode sp-pairs) sp-pairs)) + + (def-menu! +lua/build-menu + "Build/compilation commands for `lua-mode' buffers." + '(("Run Love app" :exec +lua/run-love-game :when +lua-love-mode)) + :prompt "Build tasks: ") + + (map! :map lua-mode-map + :localleader + "b" #'+lua/build-menu)) (def-package! company-lua @@ -32,9 +41,5 @@ (def-project-mode! +lua-love-mode :modes (lua-mode markdown-mode json-mode) - :files (and "main.lua" "conf.lua") - :init - (set! :build 'run-love-app '+lua-love-mode - (lambda () - (async-shell-command (format "open -a love.app '%s'" (doom-project-root)))))) + :files (and "main.lua" "conf.lua")) diff --git a/modules/lang/rust/autoload.el b/modules/lang/rust/autoload.el index 21ceaf0ff..2b94b95de 100644 --- a/modules/lang/rust/autoload.el +++ b/modules/lang/rust/autoload.el @@ -2,4 +2,7 @@ ;; TODO (defun +rust/run-cargo () (interactive)) -;; TODO (defun +rust-cargo-project-p ()) +;;;###autoload +(defun +rust-cargo-project-p () + "Return t if this is a cargo project." + (doom-project-has! "Cargo.toml")) diff --git a/modules/lang/rust/config.el b/modules/lang/rust/config.el index 5b939b8f2..6e4a2bdba 100644 --- a/modules/lang/rust/config.el +++ b/modules/lang/rust/config.el @@ -11,8 +11,11 @@ (def-package! rust-mode :mode "\\.rs$" :config - (set! :build 'run-cargo '(rust-mode toml-mode) #'+rust/run-cargo - :when #'+rust-cargo-project-p)) + (def-menu! +rust/build-menu + "TODO" + '(("run" :exec "cargo run" :cwd t :when (+rust-cargo-project-p)) + ("build" :exec "cargo build" :cwd t :when (+rust-cargo-project-p))) + :prompt "Cargo: ")) (def-package! racer diff --git a/modules/lang/web/+css.el b/modules/lang/web/+css.el index 630a989c1..4a906a06d 100644 --- a/modules/lang/web/+css.el +++ b/modules/lang/web/+css.el @@ -36,15 +36,14 @@ :mode ("\\.scss$" . scss-mode) :config (set! :company-backend '(css-mode scss-mode) '(company-css company-yasnippet)) - (set! :build 'compile-to-css 'scss-mode #'+css/scss-build)) + (map! :map scss-mode-map :localleader "b" #'+css/scss-build)) (def-package! sass-mode :mode "\\.sass$" :config - (setq sass-command-options '("--style compressed")) (set! :company-backend 'sass-mode '(company-css company-yasnippet)) - (set! :build 'compile-to-css 'sass-mode #'+css/sass-build)) + (map! :map scss-mode-map :localleader "b" #'+css/sass-build)) (def-package! less-css-mode diff --git a/modules/private/hlissner/+bindings.el b/modules/private/hlissner/+bindings.el index 5245f91c6..b926964fe 100644 --- a/modules/private/hlissner/+bindings.el +++ b/modules/private/hlissner/+bindings.el @@ -168,7 +168,7 @@ :desc "Build tasks" :nv "b" #'+eval/build :desc "Jump to definition" :n "d" #'+jump/definition :desc "Jump to references" :n "D" #'+jump/references - :desc "Open REPL" :n "r" #'+eval/repl + :desc "Open REPL" :n "r" #'+eval/open-repl :v "r" #'+eval:repl) (:desc "file" :prefix "f" @@ -233,7 +233,7 @@ (:desc "open" :prefix "o" :desc "Default browser" :n "b" #'browse-url-of-file :desc "Debugger" :n "d" #'+debug/open - :desc "REPL" :n "r" #'+eval/repl + :desc "REPL" :n "r" #'+eval/open-repl :v "r" #'+eval:repl :desc "Neotree" :n "n" #'+neotree/toggle :desc "Terminal" :n "t" #'+term/open-popup