A multi-target =M-x compile= interface inspired by [[https://github.com/ReanGD/emacs-multi-compile][multi-compile]].
This package provides a framework for associating actions with triggers. A trigger is any predicate that applies to the current file, project or directory. An action is a shell command or interactive function or anything that can be invoked when the associated trigger is set. You can use this to construct rich command interfaces emulating those offered by more integrated development environments. You can also plug in compilation targets directly from build frameworks or test tools, etc. See [[https://github.com/mohkale/projection#projection-multi-compile][projection-multi-compile]] for a package that plugs compile-multi into various build tools.
Table of Contents :TOC:
[[#installation][Installation]]
[[#deviations-from-emacs-multi-compile][Deviations from emacs-multi-compile]]
[[#configuration][Configuration]]
[[#extensions][Extensions]]
Installation ** Manually
** From MELPA This package is on [[https://github.com/melpa/melpa][MELPA]]. You can add this to your ~package-archives~ variable and then install through ~M-x package-install~.
(push '("melpa" . "https://melpa.org/packages/") package-archives)
(package-refresh-contents)
(package-install 'compile-multi)
Deviations from emacs-multi-compile This package isn't a copy of [[https://github.com/ReanGD/emacs-multi-compile][emacs-multi-compile]], it's a lighter and more feature-full re-write. The main changes from upstream are:
Configuration The main configuration for ~compile-multi~ is ~compile-multi-config~. This should be an alist with the ~car~ being the something matching current file, buffer or simply a list form that can evaluates to true. The ~cdr~ should be a list of tasks/actions that users can select when the trigger fires. An action is an cons of the action name and something to be done when that action is selected.
Here's an example of the general layout of the configuration variable.
(setq compile-multi-config '((trigger-1 ("action1" . command-1) ("action2" . command-2)) (trigger-2 ("action1" . command-1) ("action2" . command-2))))
** Triggers Triggers can be mode-symbols, strings, interpreted as regexps for the buffer-file-name or if the buffer has no file name then its buffer-name, or any lisp form that is triggered when it evaluates to true.
This can be used alongside ~(setq compile-multi-default-directory #'projectile-project-root)~ to setup trigger based on project files.
(push '((file-exists-p "Makefile")
("make:build" . "make build")
("make:test" . "make test")
("make:all" . "make all"))
compile-multi-config)
** Actions As a special case an action can be inserted as a function instead of an cons cell. When this is the case the function will be called and expected to return a collection of actions to be put in place of the functions position in the configuration.
For example you can write a ~compile-multi-make~ that'll parse out all the targets from a Makefile and generate actions for them.
(require 'compile-multi-make)
(defun compile-multi-make-targets+ ()
;; Read targets from Makefile.
'(("make:foo" . "foo")))
(push `((file-exists-p "Makefile")
("action-1" . command-1)
,#'compile-multi-make-targets+
("action-2" . command-2))
compile-multi-config)
When written as an alist the ~car~ of an action must always be the action name. The ~cdr~ can vary depending on what the user wants.
When it's a string then the string is taken as a shell command to run for compilation. When a list each argument of the list is evaluated, shell-quoted and then concatenated together. When a plist you can set the =:command= property and supply any alternative properties to customise the execution of the target. For example the ~:annotation~ property sets the affixated annotation for the action in the minibuffer.
Note: We don't shell quote strings, only evaluated lisp forms. Note: Symbols can be replaced instead of evaluated using ~compile-multi-forms~. For example
(push `(python-mode
("python:pylint" "python3" "-m" "pylint" (buffer-file-name)))
compile-multi-config)
Lastly the action can be a function. In this case the function is called when the action is selected. For example:
(defun byte-compile-this-file+ ()
(byte-compile-file (buffer-file-name)))
(push `(emacs-lisp-mode
("emacs:bytecompile" . ,#'byte-compile-this-file+))
compile-multi-config)
Is an extension for multi-compile that runs the interactive selection of targets through consult instead of completing-read. This is very similar to the existing completing-read interface but enhances it with some useful consult features such as narrowing.
(use-package consult-compile-multi
:ensure t
:after compile-multi
:demand t
:config (consult-compile-multi-mode))
** compile-multi-all-the-icons
This extension adds a handler to [[https://github.com/iyefrat/all-the-icons-completion][all-the-icons-completion]] for affixating compile-multi with icons related to the compile-multi type. You have to setup =all-the-icons-completion= correctly before this package will work.
(use-package compile-multi-all-the-icons
:ensure t
:after all-the-icons-completion
:after compile-multi
:demand t)
** compile-multi-nerd-icons
This extension adds a handler to [[https://github.com/rainstormstudio/nerd-icons-completion][nerd-icons-completion]] for affixating compile-multi with nerd icons related to the compile-multi type. You have to setup =nerd-icons-completion= correctly before this package will work.
(use-package compile-multi-nerd-icons
:ensure t
:after nerd-icons-completion
:after compile-multi
:demand t)
** compile-multi-embark
This extension adds support between compile-multi embark. This has 2 affects:
Adds a transformer to embark so any actions you run on compile-multi through embark in the minibuffer actually route to the underlying command you wanted to run them on. For example this can be used with the =kill-new= feature to copy the compilation command compile-multi would have run.
To use this extension you must install it and use enable =compile-multi-embark-mode=.
(use-package compile-multi-embark :ensure t :after embark :after compile-multi :demand t :config (compile-multi-embark-mode +1))