harpoon
skewers the monotony of hooking into (mainly language) major
modes by providing a simple use-package
-like macro.
It grew out of my configuration and therefore is currently still
heavily geared towards packages I use (like corfu
and lsp-mode
). But I
aim to slowly decouple its functionality from any particular package.
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
.
Let’s take a look at a form using all currently available features.
(harpoon some-mode
:bind t
:completion (:provider corfu :prefix 1 :delay 0.1)
:before (some-fun)
:after (other-fun)
:ligatures ("::" ">>")
:lsp (:function lsp-deferred :dir-ignore-list lsp-file-watch-ignored-list :ignore-dirs (".bucket") :hints t)
:messages ("Something in the way" "She moves")
:prog-like t
:tabs t
:checker flycheck-mode
:whitespace delete
(some-other-fun)
(setq some-other-var t))
Setting :bind t
will bind the value of harpoon-bind-key
to a
symbol named some-mode-<harpoon-bind-name-suffix>
. In my
configuration I set harpoon-bind-name-suffix
to “-major”; this is a
transient
map for the current major-mode
. You can also pass a
symbol that will be bound.
The setting for :completion
is a plist configuring the
harpoon-completion-provider
(only corfu
is currently supported) to
enable automatic completion with a prefix length of 1 and a delay of
0.1. This does not set values that aren’t explicitly set. You don’t
need to set provider
if the default (harpoon-completion-provider
)
should be used.
The list of symbols passed to :before
and :after
are called on the
condition that they are bound, called at the head and at the tail end
of the created function.
The list of strings passed to :ligatures
will be set for some-mode
using package ligature
provided it can be required. Have a look at
harpoon-common-ligatures
for a list of ligatures always set up.
The plist passed to :lsp
will add directory “.bucket” to a ignore
list and call lsp-deferred
when some-mode
is enabled. Note that
you don’t need to set :function
if you set harpoon-lsp-function
,
but you could set eglot-ensure
here instead to have some other mode
use that. The ignore list will default to
harpoon-lsp-dir-ignore-list
. If you pass :hints t
inlay hints will
be enabled.
Entries in the list of strings passed to :messages
will be displayed
randomly when some-mode
is enabled.
If :prog-like
is t
, hook prog-like-hook
is run. This is useful
when some-mode
is not derived from prog-mode
but kind of like one
(think yaml-mode
) and you want to set up the same minor-modes for it
that you do for real prog modes.
The symbol passed to :tabs
can be either t
, always
or never
.
The latter two will set indent-tabs-mode
to t
or nil
. Symbol t
will setting indent-tabs-mode
to t
dependent on the value of
harpoon-prefer-tabs
which is a custom variable that should be set
using a .dir-locals.el
file.
The symbol passed to :checker
should be the name of a syntax
checker. You normally should instead just set
harpoon-checker-function
but if you have modes that should use
another checker, set it here. You can also pass symbol disabled
to
instead don’t enable any checker even if harpoon-checker-function
is
set.
Any form after the keyword arguments will also be evaluated when
some-mode
is enabled.
The macro will set up function some-mode-harpoon
that will be added
to some-mode-hook
. Note that if there is an alternative treesit
mode that can be used the hook is created for it instead. So if you
have the grammar for JavaScript, for example, and set up harpoon
for
js-mode
, the hook will be created for js-ts-mode
. Since the
pattern for mode => language, and mode => treesitter variant isn’t
uniform, this currently only works for a small number of
modes/languages.
If you don’t want this behavior, you may add a mode name
harpoon-treesit-blacklist
to ensure treesit
isn’t used for it.
If you pass :flat t
completion and syntax checking is not set up.
This can be useful if you have some configuration for a mode and
others for those derived from it.
Setting :whitespace delete
means a before-save-hook
will be
installed to call delete-trailing-whitespace
. This can also be
enabled generally by setting harpoon-whitespace
to delete
. If you
do that but want to exclude some modes, you can pass :whitespace
keep
for them.
You can set harpoon-log
to t
in your init file if you want to see
what expanding your harpoon
form(s) did. You can switch to the logs
using harpoon-pop-to-logs
.
Please also have a look, again, at my configuration for usage examples.