This package tries to marry packages project
and compile
.
If you use straight
or quelpa
, you know what to do.
If you’re on Emacs >29, I recommend using package-vc-install
.
Alternatively, provided you have Cask, you can install the package
with make package-install
after initializing the submodule dinghy
.
Hidden recompilation
Here’s a use-package
configuration example.
(use-package ship-mate
:config
;; Create common commands.
(ship-mate-create-command build :default "make")
(ship-mate-create-command install :default "make install")
(ship-mate-create-command clean :default "make clean")
(ship-mate-create-command execute :multiple t)
(ship-mate-create-command test :default '("make test" "make coverage"))
;; This mode sets up `compilation-start' and `recompile' to play
;; nice with commands created above.
(ship-mate-mode)
;; Mode used in `ship-mate' buffers to show information about the
;; environment and bind useful commands.
(ship-mate-dinghy-global-mode)
;; If you want to bind `ship-mate-edit-history' and
;; `ship-mate-edit-environment' in `ship-mate-command-map' and
;; `ship-mate-dinghy-map'.
(ship-mate-edit-setup-bindings)
;; Allows hidden compilations that resurface after completion or at
;; will.
(ship-mate-submarine-mode)
:custom
;; The functions to advise to maybe use the appropriate `ship-mate'
;; command instead.
(ship-mate-compile-functions '(project-compile recompile))
;; The lighter used in the mode line.
(ship-mate-lighter " shp")
;; The size (per project and command) for the history.
(ship-mate-command-history-size 10)
;; The function used to check if the next compilation relates to a
;; `ship-mate' command. Returns a plist of MATCH, COUNT and INDEX on
;; a match.
(ship-mate-command-fuzzy-match-function #'ship-mate-command--fuzzy-match)
;; The function used to name `ship-mate' buffers.
(ship-matecommand-buffer-name-function-generator #'ship-mate-command--buffer-name-function)
;; Used for `ship-mate-submarine-hidden-recompile'. The number is an
;; idle delay until the user is prompted to show the result.
(ship-mate-submarine-prompt-for-hidden-buffer 2)
;; Numeric prefix used to start a hidden compilation.
(ship-mate-submarine-hidden-compilation-prefix 3)
;; Numeric prefix used to edit the environment before compilation
(ship-mate-edit-environment-compilation-prefix 5)
;; Key map `ship-mate-subcommand-map' is bound to in
;; `ship-mate-command-map'.
(ship-mate-subcommands-key "x")
;; Whether significant actions `ship-mate' makes should be logged.
(ship-mate-log t)
;; The max char length of the command name displayed in the header.
(ship-mate-dinghy-max-cmd-len 20)
;; The max char length of the environment bindings displayed in the header.
(ship-mate-dinghy-max-env-len 50)
:bind-keymap
;; All commands created above are bound in this map automatically.
(("C-c p" . ship-mate-command-map)))
The first step is to create new ship-mate
commands using macro
ship-mate-create-command
. Let’s create one for testing.
(ship-mate-create-command test)
This will create command ship-mate-test
. This command wraps
compile
but providing it a project-scoped history. On first
invocation (assuming you call it from a buffer belonging to a
project) this will prompt because there is no history and no default
command.
We could have used the following instead.
(ship-mate-create-command test :default "make test")
We’d no longer be prompted when running ship-mate-test
for the first
time. The :default
here will be the first entry in the history for
all projects. You can also pass multiple defaults.
(ship-mate-create-command test :default ("make test" "make test-all"))
Normally, a command may only have a single buffer per project. If you
have long running commands you can use :multiple
to have more than
one. If the default buffer has no process it will be re-used.
(ship-mate-create-command execute :multiple t)
If you run the command with C-u
(the universal argument) you will be
instead prompted from the history. In our last example, the history
would contain the two defined commands. If you enter a different
command it will be added to the history.
This history is the history of the command for the project. Projects do inherit the default but not the history created through usage.
While setting defaults this way is useful, you may want to use
different entries for different projects. You can do so by setting the
appropriate variable in a .dir-locals.el
file.
((nil . ((ship-mate-test-default-cmd . ("make test"
"make test-tagged"
"make test-selector"
"make test-coverage")))))
This would prep the history with four entries for this project
(assuming the .dir-locals.el
file exists at project root). Once a
history exists you can also store it directly by calling
ship-mate-store-history-as-default
.
The commands created in this way are automatically bound in map
ship-mate-command-map
. In our case since we didn’t specify a key, it
would be bound to t
in the map since the initial is t
.
Since this might lead to clashes, you can also specify the key
yourself using :key
. The value here is passed as-is to define-key
.
(ship-mate-create-command test)
(ship-mate-create-command tag :key "g")
Beyond providing a per-project history, ship-mate
commands also set
the compilation-save-buffers-predicate
to make sure you’re only
prompted to save buffers belonging to the project.
Provided you enable ship-mate-dinghy-global-mode
you will also
notice a header line. This header line is set by
ship-mate-dinghy-mode
. Its purpose is to bind commands and to show
additional information like the currently used environment variables.
You can disable this by setting ship-mate-dinghy-enable
to nil
.
Provided you enable ship-mate-mode
this package advises recompile
and project-compile
to offer the same benefits when running it (from
within or without a compilation buffer). In fact, these two commands
are the defaults in ship-mate-compile-functions
which you may want
to customize.
You can also use ship-mate-with-project-bounded-compilation
to
advise functions yourself using advice combinator :around
.
ship-mate
uses the function in
ship-mate-command-fuzzy-match-function
to check if a command belongs
to the history of a ship-mate
command and to also update the history
when using recompile
or compile
instead. For normal
ship-mate-command
invocations entries in the history are also
replaced instead of pushed out for good matches. You can check the
behavior using ship-mate-show-logs
(provided ship-mate-log
is
t
).
From a ship-mate
command buffer you can use
ship-mate-command-{next,prev}-buffer
to quickly switch between
command buffers of the same project (they’re also bound in
ship-mate-dinghy-mode
).
If you use environment variables, you can set ship-mate-environment
in your .dir-locals.el
. The value of this variable will be used to
set compilation-environment
and is safe to set (checked by
ship-mate-environment--valid-env-p
). The initial value is local to
the project.
You can also set an environment per command by using an association
list where the key is the command symbol and the value a list
considered valid by ship-mate-environment--valid-env-p
.
You can also run a ship-mate
command with numeric prefix 5 (or
whatever ship-mate-edit-environment-prefix
is set to) to edit the
environment in the minibuffer before executing it. This also works for
recompilation.
Sub-package ship-mate-submarine
provides commands to temporarily
hide running compilations or run them pre-hidden. Enable
ship-mate-submarine-mode
for this.
You can now use command ship-mate-submarine-hidden-recompile
which
will run recompile
but not display the buffer until the compilation
has finished. After compilation and idle time of
ship-mate-submarine-prompt-for-hidden-buffer
seconds, you will be
prompted to view the result. If you don’t mind a sudden pop-up as soon
as compilation finishes instead you can set
ship-mate-submarine-prompt-for-hidden-buffer
to nil
.
In the same way you can now type C-c /
or call
ship-mate-submarine-hide
in a running ship-mate
buffer to send it
to the background and make it prompt when finished. From outside you
can call ship-mate-submarine-hide-visible
to submerge a visible
compilation (bound to C-c ?
in the command map).
You can also now run any ship-mate
command with numeric prefix 3 (or
whatever ship-mate-submarine-hidden-compilation-prefix
is set to) to
run it submerged from the beginning.
To show a currently hidden compilation you can run
ship-mate-submarine-show-hidden
which will prompt you with a
selection of submerged processes.
Sub-package ship-mate-edit
provides commands
ship-mate-edit-environment
and ship-mate-edit-history
to
conveniently edit the environment or command history in a buffer,
apply the changes (if they’re valid) or clear them.
You may want to run ship-mate-edit-setup-bindings
to create bindings
in ship-mate-command-map
and ship-mate=dinghy-mode-map
.