.
675 |
676 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | SRC := $(wildcard *.el extensions/*/*.el)
2 | BIN := $(subst .el,.elc,$(SRC))
3 | EMACS ?= cask emacs \
4 | --eval '(push (concat default-directory) load-path)'
5 |
6 | .PHONY: ci/cd
7 | ci/cd: lint test
8 |
9 | .PHONY: lint
10 | lint: compile checkdoc
11 |
12 | .PHONY: checkdoc
13 | checkdoc: ## Check for missing or poorly formatted docstrings
14 | @for file in $(SRC); do \
15 | echo "[checkdoc] $$file" ;\
16 | $(EMACS) -Q --batch \
17 | --eval "(or (fboundp 'checkdoc-file) (kill-emacs))" \
18 | --eval "(setq sentence-end-double-space nil)" \
19 | --eval "(checkdoc-file \"$$file\")" 2>&1 \
20 | | grep . && exit 1 || true ;\
21 | done
22 |
23 | .PHONY: compile
24 | compile: ## Check for byte-compiler errors
25 | @for file in $(SRC); do \
26 | echo "[compile] $$file" ;\
27 | [ -e "$${file}c" ] && rm -f "$${file}c" ;\
28 | $(EMACS) -Q --batch -L . -f batch-byte-compile $$file 2>&1 \
29 | | grep -v "^Wrote" \
30 | | grep . && exit 1 || true ;\
31 | done
32 |
33 | .PHONY: clean
34 | clean: ## Remove build artifacts
35 | @echo "[clean]" $(BIN)
36 | @rm -f $(BIN)
37 |
--------------------------------------------------------------------------------
/README.org:
--------------------------------------------------------------------------------
1 | #+TITLE: compile-multi
2 | #+AUTHOR: Mohsin Kaleem
3 | # LocalWords: Makefiles alist
4 |
5 | #+html:
6 | #+html:
7 | #+html:
8 | #+html:
9 |
10 |
11 |
12 | A multi-target =M-x compile= interface inspired by [[https://github.com/ReanGD/emacs-multi-compile][multi-compile]].
13 |
14 | #+CAPTION: Obligatory screenshot of compile-multi in action.
15 | [[https://user-images.githubusercontent.com/23294780/246896395-eb920b00-1c0e-4d55-972f-1c4ac2b195cf.png]]
16 |
17 | This package provides a framework for associating actions with triggers. A trigger is
18 | any predicate that applies to the current file, project or directory. An action is a
19 | shell command or interactive function or anything that can be invoked when the
20 | associated trigger is set. You can use this to construct rich command interfaces
21 | emulating those offered by more integrated development environments. You can also
22 | plug in compilation targets directly from build frameworks or test tools, etc. See
23 | [[https://github.com/mohkale/projection#projection-multi-compile][projection-multi-compile]] for a package that plugs compile-multi into various build
24 | tools.
25 |
26 | * Table of Contents :TOC:
27 | - [[#installation][Installation]]
28 | - [[#manually][Manually]]
29 | - [[#from-melpa][From MELPA]]
30 | - [[#deviations-from-emacs-multi-compile][Deviations from emacs-multi-compile]]
31 | - [[#configuration][Configuration]]
32 | - [[#triggers][Triggers]]
33 | - [[#actions][Actions]]
34 | - [[#extensions][Extensions]]
35 | - [[#consult-multi-compile][consult-multi-compile]]
36 | - [[#compile-multi-all-the-icons][compile-multi-all-the-icons]]
37 | - [[#compile-multi-nerd-icons][compile-multi-nerd-icons]]
38 | - [[#compile-multi-embark][compile-multi-embark]]
39 |
40 | * Installation
41 | ** Manually
42 | 1. Clone the repo.
43 | 2. Add the repo path to your emacs ~load-path~.
44 | 3. Load it when needed.
45 |
46 | ** From MELPA
47 | This package is on [[https://github.com/melpa/melpa][MELPA]]. You can add this to your ~package-archives~ variable and
48 | then install through ~M-x package-install~.
49 |
50 | #+begin_src emacs-lisp
51 | (push '("melpa" . "https://melpa.org/packages/") package-archives)
52 | (package-refresh-contents)
53 | (package-install 'compile-multi)
54 | #+end_src
55 |
56 | * Deviations from emacs-multi-compile
57 | This package isn't a copy of [[https://github.com/ReanGD/emacs-multi-compile][emacs-multi-compile]], it's a lighter and more
58 | feature-full re-write. The main changes from upstream are:
59 | + No special formatting-directives/percent-sequences. Commands are lisp lists
60 | that are evaluated, shell-quoted and concatenated together smartly.
61 | + Support for dynamic command generation (such as from Makefiles) which can let you
62 | use this package as a replacement for [[https://github.com/abo-abo/helm-make][helm-make]] and as a convenient base for
63 | other such build frameworks.
64 | + Support for lisp functions as direct compilation functions. For example
65 | rustic-mode provides its own wrappers around compile, test and run and this
66 | package can let you interface with those as well.
67 |
68 | * Configuration
69 | The main configuration for ~compile-multi~ is ~compile-multi-config~. This should be an
70 | alist with the ~car~ being the something matching current file, buffer or simply a
71 | list form that can evaluates to true. The ~cdr~ should be a list of tasks/actions
72 | that users can select when the trigger fires. An action is an cons of the action
73 | name and something to be done when that action is selected.
74 |
75 | Here's an example of the general layout of the configuration variable.
76 |
77 | #+begin_src emacs-lisp
78 | (setq
79 | compile-multi-config '((trigger-1
80 | ("action1" . command-1)
81 | ("action2" . command-2))
82 | (trigger-2
83 | ("action1" . command-1)
84 | ("action2" . command-2))))
85 | #+end_src
86 |
87 | ** Triggers
88 | Triggers can be mode-symbols, strings, interpreted as regexps for the
89 | buffer-file-name or if the buffer has no file name then its buffer-name, or any
90 | lisp form that is triggered when it evaluates to true.
91 |
92 | This can be used alongside ~(setq compile-multi-default-directory #'projectile-project-root)~
93 | to setup trigger based on project files.
94 |
95 | #+begin_src emacs-lisp
96 | (push '((file-exists-p "Makefile")
97 | ("make:build" . "make build")
98 | ("make:test" . "make test")
99 | ("make:all" . "make all"))
100 | compile-multi-config)
101 | #+end_src
102 |
103 | ** Actions
104 | As a special case an action can be inserted as a function instead of an cons cell.
105 | When this is the case the function will be called and expected to return a
106 | collection of actions to be put in place of the functions position in the
107 | configuration.
108 |
109 | For example you can write a ~compile-multi-make~ that'll parse out all the targets
110 | from a Makefile and generate actions for them.
111 |
112 | #+begin_src emacs-lisp
113 | (require 'compile-multi-make)
114 |
115 | (defun compile-multi-make-targets+ ()
116 | ;; Read targets from Makefile.
117 | '(("make:foo" . "foo")))
118 |
119 | (push `((file-exists-p "Makefile")
120 | ("action-1" . command-1)
121 | ,#'compile-multi-make-targets+
122 | ("action-2" . command-2))
123 | compile-multi-config)
124 | #+end_src
125 |
126 | When written as an alist the ~car~ of an action must always be the action name. The
127 | ~cdr~ can vary depending on what the user wants.
128 |
129 | When it's a string then the string is taken as a shell command to run for
130 | compilation.
131 | When a list each argument of the list is evaluated, shell-quoted and then
132 | concatenated together.
133 | When a plist you can set the =:command= property and supply any alternative
134 | properties to customise the execution of the target. For example the ~:annotation~
135 | property sets the affixated annotation for the action in the minibuffer.
136 |
137 | *Note*: We don't shell quote strings, only evaluated lisp forms.
138 | *Note*: Symbols can be replaced instead of evaluated using ~compile-multi-forms~.
139 | For example
140 |
141 | #+begin_src emacs-lisp
142 | (push `(python-mode
143 | ("python:pylint" "python3" "-m" "pylint" (buffer-file-name)))
144 | compile-multi-config)
145 | #+end_src
146 |
147 | Lastly the action can be a function. In this case the function is called when the
148 | action is selected. For example:
149 |
150 | #+begin_src emacs-lisp
151 | (defun byte-compile-this-file+ ()
152 | (byte-compile-file (buffer-file-name)))
153 |
154 | (push `(emacs-lisp-mode
155 | ("emacs:bytecompile" . ,#'byte-compile-this-file+))
156 | compile-multi-config)
157 | #+end_src
158 |
159 | * Extensions
160 | ** consult-multi-compile
161 |
162 | #+html:
163 | #+html:
164 | #+html:
165 |
166 | Is an extension for multi-compile that runs the interactive selection of targets
167 | through consult instead of completing-read. This is very similar to the existing
168 | completing-read interface but enhances it with some useful consult features such
169 | as narrowing.
170 |
171 | #+begin_src emacs-lisp
172 | (use-package consult-compile-multi
173 | :ensure t
174 | :after compile-multi
175 | :demand t
176 | :config (consult-compile-multi-mode))
177 | #+end_src
178 |
179 | ** compile-multi-all-the-icons
180 |
181 | #+html:
182 | #+html:
183 | #+html:
184 |
185 | This extension adds a handler to [[https://github.com/iyefrat/all-the-icons-completion][all-the-icons-completion]] for affixating
186 | compile-multi with icons related to the compile-multi type. You have to setup
187 | =all-the-icons-completion= correctly before this package will work.
188 |
189 | #+begin_src emacs-lisp
190 | (use-package compile-multi-all-the-icons
191 | :ensure t
192 | :after all-the-icons-completion
193 | :after compile-multi
194 | :demand t)
195 | #+end_src
196 |
197 | ** compile-multi-nerd-icons
198 |
199 | #+html:
200 | #+html:
201 | #+html:
202 |
203 | This extension adds a handler to [[https://github.com/rainstormstudio/nerd-icons-completion][nerd-icons-completion]] for affixating
204 | compile-multi with nerd icons related to the compile-multi type. You have to setup
205 | =nerd-icons-completion= correctly before this package will work.
206 |
207 | #+begin_src emacs-lisp
208 | (use-package compile-multi-nerd-icons
209 | :ensure t
210 | :after nerd-icons-completion
211 | :after compile-multi
212 | :demand t)
213 | #+end_src
214 |
215 | ** compile-multi-embark
216 |
217 | #+html:
218 | #+html:
219 | #+html:
220 |
221 | This extension adds support between compile-multi embark. This has 2 affects:
222 | 1. Defines a new compile-multi command map for Embark. This map has a command to
223 | let you edit a compile-multi target before executing it.
224 | 2. Adds a transformer to embark so any actions you run on compile-multi through
225 | embark in the minibuffer actually route to the underlying command you wanted to
226 | run them on. For example this can be used with the =kill-new= feature to copy the
227 | compilation command compile-multi would have run.
228 |
229 |
230 | To use this extension you must install it and use enable =compile-multi-embark-mode=.
231 |
232 | #+begin_src emacs-lisp
233 | (use-package compile-multi-embark
234 | :ensure t
235 | :after embark
236 | :after compile-multi
237 | :demand t
238 | :config (compile-multi-embark-mode +1))
239 | #+end_src
240 |
--------------------------------------------------------------------------------
/compile-multi.el:
--------------------------------------------------------------------------------
1 | ;;; compile-multi.el --- A multi target interface to compile -*- lexical-binding: t; -*-
2 |
3 | ;; Copyright (C) 2022 mohsin kaleem
4 |
5 | ;; Author: mohsin kaleem
6 | ;; Keywords: tools, compile, build
7 | ;; Package-Requires: ((emacs "28.1"))
8 | ;; Version: 0.7
9 | ;; Homepage: https://github.com/mohkale/compile-multi
10 |
11 | ;; This program is free software; you can redistribute it and/or modify
12 | ;; it under the terms of the GNU General Public License as published by
13 | ;; the Free Software Foundation, either version 3 of the License, or
14 | ;; (at your option) any later version.
15 |
16 | ;; This program is distributed in the hope that it will be useful,
17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | ;; GNU General Public License for more details.
20 |
21 | ;; You should have received a copy of the GNU General Public License
22 | ;; along with this program. If not, see .
23 |
24 | ;;; Commentary:
25 |
26 | ;; Multi target interface to `compile'.
27 | ;;
28 | ;; This package exposes facilities for generating a collection of compilation
29 | ;; commands for the current buffer or project and interactively select one to
30 | ;; run. This can be plugged into various build frameworks such as Make or CMake
31 | ;; to automatically determine the list of available targets and let you
32 | ;; interactively select one to run.
33 |
34 | ;;; Code:
35 |
36 | (require 'seq)
37 | (require 'subr-x)
38 |
39 | (defgroup compile-multi nil
40 | "A multi target interface to compile."
41 | :group 'compilation)
42 |
43 |
44 |
45 | ;;; Completion interface
46 |
47 | (defcustom compile-multi-interface nil
48 | "Set the default interface for `compile-multi'.
49 | To override the interface you must define a variant of
50 | `compile-multi-read-actions' that accepts an interface argument matching the
51 | value set here."
52 | :type '(choice (const nil) symbol))
53 |
54 | (defvar compile-multi-history nil
55 | "History of completions chosen with `compile-multi'.")
56 |
57 | (defcustom compile-multi-annotate-cmds t
58 | "Affixate `compile-multi' to show the command being compiled."
59 | :type 'boolean)
60 |
61 | (defcustom compile-multi-annotate-string-cmds t
62 | "Auto annotate string based commands in `compile-multi-config'.
63 | When true if a command in `compile-multi-config' is a string or produces a
64 | string then generate an annotation for it automatically. This option only
65 | has significance when `compile-multi-annotate-cmds' is true."
66 | :type 'boolean)
67 |
68 | (defcustom compile-multi-annotate-limit 48
69 | "Truncate any annotations longer than this limit.
70 | Set to nil to disable truncation."
71 | :type '(choice (const nil) integer))
72 |
73 | (defcustom compile-multi-group-cmds 'group-and-replace
74 | "Group commands with the same `compile-multi' root prefix."
75 | :type '(choice
76 | (const :tag "Group and remove group prefix." group-and-replace)
77 | (const :tag "Group candidates." t)
78 | (const :tag "Never group candidates." nil)))
79 |
80 | (defun compile-multi--annotation-function (task)
81 | "Annotator for TASK."
82 | (when-let ((cmd (plist-get (cdr task) :annotation)))
83 | (when (and compile-multi-annotate-limit
84 | (>= (length cmd) compile-multi-annotate-limit))
85 | (setq cmd
86 | (concat
87 | (string-remove-suffix
88 | " "
89 | (substring cmd 0 compile-multi-annotate-limit))
90 | "…")))
91 | (concat " "
92 | (propertize " " 'display `(space :align-to (- right ,(+ 1 (length cmd)))))
93 | (propertize cmd 'face 'completions-annotations))))
94 |
95 | (defun compile-multi--group-function (cand transform)
96 | "Group function for `compile-multi' on CAND and TRANSFORM."
97 | (when compile-multi-group-cmds
98 | (when-let ((type (get-text-property 0 'consult--type cand))
99 | (type (symbol-name type)))
100 | (if transform
101 | (when (eq compile-multi-group-cmds 'group-and-replace)
102 | (substring cand (1+ (length type))))
103 | type))))
104 |
105 | (cl-defgeneric compile-multi-read-actions (_interface tasks)
106 | "Interactively select a `compile-multi' action from TASKS."
107 | (assoc (completing-read
108 | "Compile: "
109 | (lambda (string predicate action)
110 | (if (eq action 'metadata)
111 | `(metadata
112 | (annotation-function
113 | . ,(when compile-multi-annotate-cmds
114 | (lambda (task)
115 | (compile-multi--annotation-function
116 | (assoc task tasks)))))
117 | (group-function . ,#'compile-multi--group-function)
118 | (category . compile-multi))
119 | (complete-with-action action tasks string predicate)))
120 | nil t nil 'compile-multi-history)
121 | tasks))
122 |
123 |
124 |
125 | ;;; Task generation
126 |
127 | (defcustom compile-multi-forms
128 | '((file-name . (buffer-file-name))
129 | (file-dir . (file-name-directory (buffer-file-name)))
130 | (file-base . (file-name-nondirectory (buffer-file-name)))
131 | (file-base-no-ext . (file-name-sans-extension (file-name-nondirectory (buffer-file-name))))
132 | (file-ext . (file-name-extension (file-name-nondirectory (buffer-file-name)))))
133 | "Alist of special let-forms to replace in `compile-multi-config'.
134 | The key is a symbol that may occur in one of the actions of
135 | `compile-multi-config'. The value is a Lisp form that will be evaluated and
136 | then replace key."
137 | :type '(alist :key-type symbol :value-type (sexp :tag "Expression")))
138 |
139 | (defconst compile-multi-config-type
140 | '(alist :key-type
141 | (choice (const t :tag "Default")
142 | (symbol :tag "Major-mode")
143 | (regexp :tag "File/buffer regexp")
144 | (sexp :tag "Expression"))
145 | :value-type
146 | (repeat
147 | (choice (string :tag "Shell command")
148 | (function :tag "Shell command generator")
149 | (repeat (choice string
150 | (sexp :tag "Expression")))
151 | ;; (plist :value-type (sexp :tag "Any of the above value types"))
152 | (cons (string :tag "Command Name")
153 | (sexp :tag "Any of the above value types"))))
154 | ))
155 |
156 | (defcustom compile-multi-config nil
157 | "Alist of triggers and actions for those triggers."
158 | :type compile-multi-config-type)
159 |
160 | (defcustom compile-multi-dir-local-config nil
161 | "Variant of `compile-multi-config' to be set in .dir-locals.el ."
162 | :type compile-multi-config-type)
163 |
164 | (defun compile-multi--config-tasks ()
165 | "Select the tasks from `compile-multi-config' whose triggers are fired."
166 | (apply #'append
167 | (mapcar #'cdr
168 | (seq-filter
169 | (lambda (it)
170 | (let ((trigger (car it)))
171 | (cond
172 | ((eq trigger t) t)
173 | ((symbolp trigger)
174 | (derived-mode-p trigger))
175 | ((listp trigger)
176 | (eval trigger))
177 | ((stringp trigger)
178 | (string-match-p trigger (buffer-name)))
179 | ((functionp trigger)
180 | (funcall trigger))
181 | (t (error "Unknown trigger type: %s" trigger)))))
182 | (append compile-multi-config
183 | compile-multi-dir-local-config)))))
184 |
185 | (defun compile-multi--fill-tasks (tasks)
186 | "Convert TASKS values into shell commands.
187 | Returns a cons cell of the completion target and a plist of task properties.
188 | The plist will contain a command and an optional annotation property for task."
189 | (let (res)
190 | (dolist (task tasks)
191 | (cond
192 | ;; Generate one-or more tasks to replace this task.
193 | ((functionp task)
194 | (setq res (append (nreverse
195 | (compile-multi--fill-tasks (funcall task)))
196 | res)))
197 | ;; A full command to be called as a standalone task.
198 | ((stringp (cdr task))
199 | (push `(,(car task)
200 | :command ,(cdr task)
201 | ,@(when compile-multi-annotate-string-cmds
202 | (list :annotation (cdr task))))
203 | res))
204 | ;; Defer to a lisp-command to compile, not a shell command.
205 | ;; KLUDGE: I'm not sure about this, it might be a little too hacky.
206 | ((functionp (cdr task))
207 | (push `(,(car task)
208 | :command ,(cdr task)
209 | :annotation ,(if (eq (car-safe (cdr task)) 'lambda)
210 | "lambda"
211 | (format "%s" (cdr task))))
212 | res))
213 | ;; Command is a pre-formatted plist, nothing to be done.
214 | ((and (listp (cdr task))
215 | (keywordp (cadr task)))
216 | ;; (cl-assert (plist-get (cdr task) :command) nil
217 | ;; "Task %S has a missing command value" task)
218 | (when-let ((annotation (plist-get (cdr task) :annotation)))
219 | (plist-put (cdr task) :annotation
220 | (when compile-multi-annotate-cmds
221 | annotation)))
222 | (push `(,(car task) ,@(cdr task)) res))
223 | ;; It's a list that we need to format into a shell-command to run.
224 | ((listp (cdr task))
225 | (let ((cmd
226 | (mapconcat (lambda (it)
227 | (or
228 | (and (symbolp it)
229 | (let* ((val (or (alist-get it compile-multi-forms)
230 | it))
231 | (evaluated-value (eval val)))
232 | (unless (stringp evaluated-value)
233 | (error "Failed to stringify task argument %s" val))
234 | evaluated-value))
235 | (let ((evaluated-value (eval it)))
236 | (unless (stringp evaluated-value)
237 | (error "Failed to stringify task argument %s" it))
238 | evaluated-value)))
239 | (cdr task) " ")))
240 | (push `(,(car task)
241 | :command ,cmd
242 | ,@(when compile-multi-annotate-string-cmds
243 | (list :annotation cmd)))
244 | res)))
245 | (t (error "Unknown task type: %s" task))))
246 | (nreverse res)))
247 |
248 | (defun compile-multi--add-properties (tasks)
249 | "Attach a type property to `compile-multi' TASKS."
250 | (dolist (task tasks)
251 | (when-let* ((group-pos (string-match-p ":" (car task)))
252 | (type (intern (substring (car task) 0 group-pos))))
253 | (add-text-properties 0 1 (list 'consult--type type) (car task)))
254 | (when-let ((command (plist-get (cdr task) :command)))
255 | (add-text-properties 0 1 (list 'compile-multi--task command) (car task))))
256 | tasks)
257 |
258 |
259 |
260 | ;;; Main entrypoint
261 |
262 | (defcustom compile-multi-default-directory nil
263 | "Assign `default-directory' of a compilation in `compile-multi'.
264 | If set this function will be called prior to determining compilation triggers
265 | and actions and `default-directory' will be set to the result. If the result
266 | is nil then `default-directory' will not be changed."
267 | :type '(choice (const nil) function))
268 |
269 | (defun compile-multi--get-task ()
270 | "Generate `compile-multi' tasks and return one selected by the user."
271 | (let ((tasks (thread-first
272 | (compile-multi--config-tasks)
273 | (compile-multi--fill-tasks)
274 | (compile-multi--add-properties))))
275 | (if tasks
276 | (compile-multi-read-actions compile-multi-interface tasks)
277 | (list ""
278 | :command
279 | (read-shell-command "No tasks for compile-multi, run command: ")))))
280 |
281 | ;;;###autoload
282 | (defun compile-multi (&optional query command)
283 | "Multi-target interface to compile.
284 | With optional argument QUERY allow user to modify compilation command before
285 | running. COMMAND when set will be used instead of prompting the user for a
286 | compile-multi command."
287 | (interactive "P")
288 | (let* ((default-directory (or (and compile-multi-default-directory
289 | (funcall compile-multi-default-directory))
290 | default-directory))
291 | (compile-cmd
292 | (or command
293 | (plist-get (cdr (or (compile-multi--get-task)
294 | (user-error "compile-multi: Invalid task read from user")))
295 | :command))))
296 | (cond
297 | ((stringp compile-cmd)
298 | (when query
299 | (setq compile-cmd
300 | (compilation-read-command compile-cmd)))
301 | (compile compile-cmd (consp query)))
302 | ((functionp compile-cmd)
303 | (if query
304 | (eval-expression
305 | (read--expression "Eval: " (format "(%s)" compile-cmd)))
306 | (funcall compile-cmd)))
307 | (t (error "Don't know how to run the command %s" compile-cmd)))))
308 |
309 | (provide 'compile-multi)
310 | ;;; compile-multi.el ends here
311 |
--------------------------------------------------------------------------------
/extensions/compile-multi-all-the-icons/compile-multi-all-the-icons.el:
--------------------------------------------------------------------------------
1 | ;;; compile-multi-all-the-icons.el --- Affixate `compile-multi' with icons -*- lexical-binding: t; -*-
2 |
3 | ;; Copyright (C) 2022 mohsin kaleem
4 |
5 | ;; Author: mohsin kaleem
6 | ;; Keywords: tools, compile, build
7 | ;; Package-Requires: ((emacs "28.0") (all-the-icons-completion "0.0.1"))
8 | ;; Version: 0.7
9 | ;; Homepage: https://github.com/mohkale/compile-multi
10 |
11 | ;; This program is free software; you can redistribute it and/or modify
12 | ;; it under the terms of the GNU General Public License as published by
13 | ;; the Free Software Foundation, either version 3 of the License, or
14 | ;; (at your option) any later version.
15 |
16 | ;; This program is distributed in the hope that it will be useful,
17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | ;; GNU General Public License for more details.
20 |
21 | ;; You should have received a copy of the GNU General Public License
22 | ;; along with this program. If not, see .
23 |
24 | ;;; Commentary:
25 |
26 | ;; This extension package adds icons to `compile-multi'. This relies on the
27 | ;; external `all-the-icons-completion' package to associate the `compile-multi'
28 | ;; completion kind with an icon generation function.
29 |
30 | ;;; Code:
31 |
32 | (require 'all-the-icons)
33 | (require 'all-the-icons-completion)
34 |
35 | (defgroup compile-multi-all-the-icons nil
36 | "Icon affixation for `compile-multi' completions."
37 | :group 'compile-multi)
38 |
39 | (defcustom compile-multi-all-the-icons-alist
40 | '(;; projection-multi target generators.
41 | (cmake all-the-icons-fileicon "cmake" :face all-the-icons-red)
42 | (ctest all-the-icons-fileicon "cmake" :face all-the-icons-lorange)
43 | (gradle all-the-icons-fileicon "gradle" :face all-the-icons-blue)
44 | (make all-the-icons-fileicon "gnu" :face all-the-icons-red-alt)
45 | (npm all-the-icons-fileicon "npm" :face all-the-icons-red)
46 | (project all-the-icons-fileicon "npm" :face all-the-icons-red)
47 | (yarn all-the-icons-octicon "repo" :face all-the-icons-yellow)
48 | (tox all-the-icons-alltheicon "python" :height 1.0 :face all-the-icons-dblue)
49 | (poetry all-the-icons-alltheicon "python" :height 1.0 :face all-the-icons-dblue)
50 | ;; Types we recommend users override.
51 | (emacs all-the-icons-fileicon "elisp" :height 1.0 :v-adjust -0.1 :face all-the-icons-purple)
52 | (local all-the-icons-faicon "shield" :face all-the-icons-lblue)
53 | ;; The default. Omit this to not have any icons when none are configured.
54 | (t all-the-icons-fileicon "powershell" :face all-the-icons-blue))
55 | "Icon configuration for `compile-multi' completions."
56 | :group 'compile-multi-all-the-icons
57 | :type '(list (cons (choice (symbol :tag "Type")
58 | (const :tag "Default" t))
59 | sexp)))
60 |
61 | (cl-defmethod all-the-icons-completion-get-icon (cand (_cat (eql compile-multi)))
62 | "Return the icon for the candidate CAND of completion category `compile-multi'."
63 | (let* ((type (get-text-property 0 'consult--type cand))
64 | (icon
65 | (or (when type
66 | (alist-get type compile-multi-all-the-icons-alist))
67 | (alist-get t compile-multi-all-the-icons-alist))))
68 | (when icon
69 | (concat
70 | (apply (car icon) (cdr icon))
71 | " "))))
72 |
73 | (provide 'compile-multi-all-the-icons)
74 | ;;; compile-multi-all-the-icons.el ends here
75 |
76 |
--------------------------------------------------------------------------------
/extensions/compile-multi-embark/compile-multi-embark.el:
--------------------------------------------------------------------------------
1 | ;;; compile-multi-embark.el --- Integration for `compile-multi' and `embark' -*- lexical-binding: t; -*-
2 |
3 | ;; Author: Mohsin Kaleem
4 | ;; Keywords: project, convenience
5 | ;; Package-Requires: ((emacs "28.1") (compile-multi "0.4") (embark "0.22.1"))
6 | ;; Version: 0.7
7 | ;; Homepage: https://github.com/mohkale/compile-multi
8 |
9 | ;; Copyright (C) 2023 Mohsin Kaleem
10 |
11 | ;; This program is free software: you can redistribute it and/or modify
12 | ;; it under the terms of the GNU General Public License as published by
13 | ;; the Free Software Foundation, either version 3 of the License, or
14 | ;; (at your option) any later version.
15 |
16 | ;; This program is distributed in the hope that it will be useful,
17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | ;; GNU General Public License for more details.
20 |
21 | ;; You should have received a copy of the GNU General Public License
22 | ;; along with this program. If not, see .
23 |
24 | ;;; Commentary:
25 |
26 | ;; This package defines a keymap and embark transformer helper to integrate
27 | ;; compile-multi into embark. This lets you set command actions that will
28 | ;; run on the underlying command shown in a `compile-multi' session.
29 |
30 | ;;; Code:
31 |
32 | (require 'embark)
33 | (require 'compile-multi)
34 |
35 | (defgroup compile-multi-embark nil
36 | "Integration between `compile-multi' and `embark'."
37 | :group 'compile-multi)
38 |
39 | (defvar compile-multi-embark-command-map
40 | (let ((map (make-sparse-keymap)))
41 | (set-keymap-parent map embark-general-map)
42 | (define-key map "e" #'compile-multi-embark-edit)
43 | map)
44 | "Keymap active in `compile-multi' `embark' sessions.")
45 |
46 |
47 |
48 | (defun compile-multi-embark-transformer (type target)
49 | "Transformer for `embark' to convert a `compile-multi' TARGET into a command.
50 | TYPE should always be `compile-multi'."
51 | (cl-assert (eq type 'compile-multi) 'show-args
52 | "This transformer should only be used with `compile-multi'.")
53 | (let ((command (get-text-property 0 'compile-multi--task target)))
54 | (cl-assert command 'show-args "Encountered compile-multi candidate with no command")
55 | (cons type command)))
56 |
57 | (defun compile-multi-embark-edit (command)
58 | "Edit before running `compile' on COMMAND."
59 | (compile-multi 'query command))
60 |
61 | ;;;###autoload
62 | (define-minor-mode compile-multi-embark-mode
63 | "Minor mode enabling `embark' actions for `compile-multi' minibuffer sessions."
64 | :global t :group 'compile-multi-embark
65 | (if compile-multi-embark-mode
66 | (progn
67 | (push '(compile-multi compile-multi-embark-command-map) embark-keymap-alist)
68 | (push `(compile-multi . ,#'compile-multi-embark-transformer)
69 | embark-transformer-alist))
70 | (setq embark-keymap-alist (assq-delete-all 'compile-multi embark-keymap-alist)
71 | embark-transformer-alist (assq-delete-all 'compile-multi embark-transformer-alist))))
72 |
73 | (provide 'compile-multi-embark)
74 | ;;; compile-multi-embark.el ends here
75 |
--------------------------------------------------------------------------------
/extensions/compile-multi-nerd-icons/compile-multi-nerd-icons.el:
--------------------------------------------------------------------------------
1 | ;;; compile-multi-nerd-icons.el --- Affixate `compile-multi' with nerd icons -*- lexical-binding: t; -*-
2 |
3 | ;; Copyright (C) 2022 mohsin kaleem
4 |
5 | ;; Author: mohsin kaleem
6 | ;; Keywords: tools, compile, build
7 | ;; Package-Requires: ((emacs "28.0") (nerd-icons-completion "0.0.1"))
8 | ;; Version: 0.7
9 | ;; Homepage: https://github.com/mohkale/compile-multi
10 |
11 | ;; This program is free software; you can redistribute it and/or modify
12 | ;; it under the terms of the GNU General Public License as published by
13 | ;; the Free Software Foundation, either version 3 of the License, or
14 | ;; (at your option) any later version.
15 |
16 | ;; This program is distributed in the hope that it will be useful,
17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | ;; GNU General Public License for more details.
20 |
21 | ;; You should have received a copy of the GNU General Public License
22 | ;; along with this program. If not, see .
23 |
24 | ;;; Commentary:
25 |
26 | ;; This extension package adds nerd icons to `compile-multi'. This relies on the
27 | ;; external `nerd-icons-completion' package to associate the `compile-multi'
28 | ;; completion kind with an icon generation function.
29 |
30 | ;;; Code:
31 |
32 | (require 'nerd-icons)
33 | (require 'nerd-icons-completion)
34 |
35 | (defgroup compile-multi-nerd-icons nil
36 | "Icon affixation for `compile-multi' completions."
37 | :group 'compile-multi)
38 |
39 | (defcustom compile-multi-nerd-icons-alist
40 | '(;; projection-multi target generators.
41 | (cmake nerd-icons-sucicon "nf-seti-makefile" :face nerd-icons-red)
42 | (ctest nerd-icons-sucicon "nf-seti-makefile" :face nerd-icons-lorange)
43 | (gradle nerd-icons-sucicon "nf-seti-gradle" :face nerd-icons-blue)
44 | (make nerd-icons-devicon "nf-dev-gnu" :face nerd-icons-red-alt)
45 | (npm nerd-icons-sucicon "nf-seti-npm" :face nerd-icons-red)
46 | (project nerd-icons-sucicon "nf-seti-project" :face nerd-icons-red)
47 | (yarn nerd-icons-sucicon "nf-seti-yarn" :face nerd-icons-yellow)
48 | (tox nerd-icons-sucicon "nf-seti-python" :face nerd-icons-dblue)
49 | (poetry nerd-icons-sucicon "nf-seti-python" :face nerd-icons-dblue)
50 | ;; Types we recommend users override.
51 | (emacs nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-purple)
52 | (local nerd-icons-mdicon "nf-md-shield" :face nerd-icons-blue)
53 | ;; The default. Omit this to not have any icons when none are configured.
54 | (t nerd-icons-sucicon "nf-seti-powershell" :face nerd-icons-blue))
55 | "Icon configuration for `compile-multi' completions."
56 | :group 'compile-multi-nerd-icons
57 | :type '(list (cons (choice (symbol :tag "Type")
58 | (const :tag "Default" t))
59 | sexp)))
60 |
61 | (cl-defmethod nerd-icons-completion-get-icon (cand (_cat (eql compile-multi)))
62 | "Return the icon for the candidate CAND of completion category `compile-multi'."
63 | (let* ((type (get-text-property 0 'consult--type cand))
64 | (icon
65 | (or (when type
66 | (alist-get type compile-multi-nerd-icons-alist))
67 | (alist-get t compile-multi-nerd-icons-alist))))
68 | (when icon
69 | (concat
70 | (apply (car icon) (cdr icon))
71 | " "))))
72 |
73 | (provide 'compile-multi-nerd-icons)
74 | ;;; compile-multi-nerd-icons.el ends here
75 |
76 |
--------------------------------------------------------------------------------
/extensions/consult-compile-multi/consult-compile-multi.el:
--------------------------------------------------------------------------------
1 | ;;; consult-compile-multi.el --- Consulting read support for `compile-multi' -*- lexical-binding: t; -*-
2 |
3 | ;; Copyright (C) 2023 mohsin kaleem
4 |
5 | ;; Author: mohsin kaleem
6 | ;; Keywords: tools, compile, build
7 | ;; Package-Requires: ((emacs "28.1") (compile-multi "0.4") (consult "0.34"))
8 | ;; Version: 0.7
9 | ;; Homepage: https://github.com/mohkale/compile-multi
10 |
11 | ;; This program is free software; you can redistribute it and/or modify
12 | ;; it under the terms of the GNU General Public License as published by
13 | ;; the Free Software Foundation, either version 3 of the License, or
14 | ;; (at your option) any later version.
15 |
16 | ;; This program is distributed in the hope that it will be useful,
17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | ;; GNU General Public License for more details.
20 |
21 | ;; You should have received a copy of the GNU General Public License
22 | ;; along with this program. If not, see .
23 |
24 | ;;; Commentary:
25 |
26 | ;; This extension package allows you to run `compile-multi' with `consult--read'.
27 | ;; This provides extra functionality atop the base completing read interface such
28 | ;; as narrowing or having the ability to further customize the completion session.
29 |
30 | ;;; Code:
31 |
32 | (require 'consult)
33 | (require 'compile-multi)
34 |
35 | (defgroup consult-compile-multi nil
36 | "Run `compile-multi' through `consult'ing-read."
37 | :group 'compile-multi)
38 |
39 | (defcustom consult-compile-multi-narrow
40 | '((?p "Project" project)
41 | (?P "Pytest" pytest-file pytest-class pytest-test)
42 | (?c "CMake" cmake ctest)
43 | (?e "Emacs" emacs)
44 | (?t "Test" ctest))
45 | "Narrowing configuration for `compile-multi'.
46 | This configuration lets you filter down completion candidates exposed by
47 | `compile-multi'. Each entry should be of the form (char name types...)."
48 | :type '(alist
49 | :key-type (character :tag "Character to narrow on")
50 | :value-type
51 | (cons (string :tag "Title of narrow")
52 | (repeat (symbol :tag "compile-multi types matching narrowing config"))))
53 | :group 'consult-compile-multi)
54 |
55 | (defun consult-compile-multi--narrow ()
56 | "Calculate a `compile-multi' narrowing configuration."
57 | (list :predicate
58 | (lambda (cand)
59 | (when-let ((type-list
60 | (cdr (alist-get consult--narrow consult-compile-multi-narrow))))
61 | (member (get-text-property 0 'consult--type (car cand)) type-list)))
62 | :keys
63 | (mapcar (pcase-lambda (`(,x ,y ,_)) (cons x y))
64 | consult-compile-multi-narrow)))
65 |
66 | (cl-defmethod compile-multi-read-actions ((_interface (eql consult)) tasks)
67 | "Interactively select a `compile-multi' action from TASKS using consult."
68 | (consult--read
69 | tasks
70 | :prompt "Compile: "
71 | :category 'compile-multi
72 | :lookup #'consult--lookup-cons
73 | :history 'compile-multi-history
74 | :group #'compile-multi--group-function
75 | :narrow (consult-compile-multi--narrow)
76 | :annotate
77 | (when compile-multi-annotate-cmds
78 | (lambda (task)
79 | (compile-multi--annotation-function
80 | (consult--lookup-cons task tasks))))))
81 |
82 |
83 |
84 | ;;; Minor mode to enable consult.
85 |
86 | ;;;###autoload
87 | (define-minor-mode consult-compile-multi-mode
88 | "Run `compile-multi' with `consult'."
89 | :global t :group 'consult-compile-multi
90 | (setq compile-multi-interface
91 | (if consult-compile-multi-mode
92 | 'consult
93 | nil)))
94 |
95 | (provide 'consult-compile-multi)
96 | ;;; consult-compile-multi.el ends here
97 |
--------------------------------------------------------------------------------