Skip to content

Walheimat/ship-mate

Repository files navigation

ship-mate

Coverage Status

This package tries to marry packages project and compile.

Installation

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.

Preview

Executing commands

./assets/commands.gif

Editing the environment

./assets/editenvinbuffer.gif

./assets/editenvoutside.gif

Hidden recompilation

./assets/hiddenrecompile.gif

Usage

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)))

Creating commands

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")

Using commands

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).

Setting the environment

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.

Hiding and resurfacing compilations

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.

Editing the environment and history

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.

About

Project-scoped compilation companion

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages