Leave Emacs less. Relocate those frequent shell commands to configurable, dynamic, context-sensitive lists, and run them at a fraction of the keystrokes via Helm or Ivy.
Table of Contents:
The screencast below shows using run-command
to 1) create a project from a boilerplate, 2) execute a file on every save, and 3) start the test runner.
By default, commands are run in compilation-mode
. See Lightweight external command integration in Emacs via compilation mode for some notes on how to make the most of compilation-mode
.
Alternatively (and experimentally), commands can be run in term-mode
plus compilation-minor-mode
, especially useful for commands with rich output such as colors, progress bars, and screen refreshes, while preserving compilation-mode
functionality. Set run-command-run-method
to term
and please comment on issue #2 if you find issues.
The auto-completion framework is automatically detected. It can be set manually by customizing run-command-completion-method
.
- Add a "command recipe" to your init file, for example:
(defun run-command-recipe-local ()
(list
(list :command-name "say-hello"
:command-line "echo Hello, World!")
(list :command-name "serve-http-dir"
:command-line "python3 -m http.server 8000")
(when (equal (buffer-name) "README.md")
;; uses https://github.com/joeyespo/grip
(list :command-name "preview-github-readme"
:command-line "grip --browser --norefresh"))))
-
Customize
run-command-recipes
and addrun-command-recipe-local
to the list. -
Type
M-x run-command RET
.
Read more about configuration, invocation, and how to add commands, or check out some recipe examples.
Type M-x run-command
or bind run-command
to a key:
(global-set-key (kbd "C-c c") 'run-command)
Or:
(use-package run-command
:bind ("C-c c" . run-command)
When using Helm, you can edit a command before running it by typing C-u RET
instead of RET
. (See issue #1 if you can help bring that to Ivy.)
To provide a more user-friendly name for a command, use the :display
property:
(defun run-command-recipe-local ()
(list
(list :command-name "serve-http-dir"
:command-line "python3 -m http.server 8000"
:display "Serve directory over HTTP port 8000")))
A command runs by default in the current buffer's directory. You can make it run in a different directory by setting :working-dir
.
For example, you want to serve the current directory via HTTP, unless you're visiting a file that is somewhere below a public_html
directory, in which case you want to serve public_html
instead:
(defun run-command-recipe-local ()
(list
(list :command-name "serve-http-dir"
:command-line "python3 -m http.server 8000"
:display "Serve directory over HTTP port 8000"
:working-dir (let ((project-dir
(locate-dominating-file default-directory "public_html")))
(if project-dir
(concat project-dir "public_html")
default-directory)))))
See the Hugo project recipe for a recipe that uses the project's directory for all commands.
To disable a command in certain circumstances, make its recipe return nil
in its place.
For example, you want to enable a command only when a buffer's file is executable:
(defun run-command-recipe-local ()
(let* ((buffer-file (buffer-file-name))
(executable-p (and buffer-file (file-executable-p buffer-file))))
(list
(if executable-p
(list
:command-name "run-buffer-file"
:command-line buffer-file
:display "Run this buffer's file")
nil))))
See the executable file recipe for a variant that also re-runs the file on each save.
Recipes are plain old Lisp functions, so they generate commands based on e.g. project setup.
See the NPM project recipe, which uses a JavaScript's project package.json
file to generate commands, and the Make project recipe, which does the same for Makefile
projects.