-
Notifications
You must be signed in to change notification settings - Fork 720
Writing Plugins
A Kakoune plugin is just a file with the .kak
extension, living in the %val{config}/autoload
directory (~/.config/kak/autoload
by default, see Installing Plugins for details). If you have moved configuration out of your kakrc
into the autoload directory to keep things tidy, you have already created a plugin!
All commands created by plugins must live together, all options created by plugins must live together, all user-modes created by plugins must live together, etc. Some people even copy all the files used by different plugins directly into their autoload folder, side-by-side. It's a good practice to prefix everything with your plugin's name, to reduce the chance of collision with other plugins.
It's tempting to add a bunch of map
and hook
commands to your plugin so that it automatically works from the moment it's installed. However, there's not that many key combinations available, and it's quite likely that you'll stomp on some other plugin, or the user's own configuration. While it's easy for the end-user to add new mappings of their own, it's difficult for them to figure out what mappings exist or which plugin introduced a mapping that broke their workflow. So don't do it.
Instead, your plugin should present its functionality as commands, that can be searched for with Kakoune's command-line, and with docstrings the user can read. You may also want to add a user-mode with mappings relevant to your plugin, if there's a set of very-frequently-used commands. You might also include "serving suggestion" mappings in your README or other documentation that people can paste into their kakrc
and modify.
Your plugin may rely on data from an external file, or depend on an external script written in a more convenient language. Your plugin could hard-code a specific filesystem path to that data, but if your users install your plugin in a different location, things will break.
Luckily, Kakoune provides a solution, in the form of the %val{source}
expansion. Let's say you have a plugin called "MyPlugin", which requires data in a CSV file. Your plugin might wind up with a filesystem structure like this:
kakoune-my-plugin
|
+- my-plugin.kak (our plugin script)
|
+- my-plugin-data.csv (the data our plugin requires)
At the top of my-plugin.kak
, declare an option to store the path to the plugin directory. We use the -hidden
flag because end-users don't need to see or modify this option, it's purely internal:
declare-option -hidden str my_plugin_path %sh{ dirname "$kak_source" }
Now %opt{my_plugin_path}
contains the absolute path of the plugin directory, probably something like /home/somebody/.config/kak/autoload/kakoune-my-plugin
(but the whole point is that it can vary). When a shell block in your plugin needs to refer to the data file, it can say $kak_opt_my_plugin_path/my-plugin-data.csv
.
If your plugin adds highlighters for particular files or particular file-types, it can be slow and complicated to set them up from scratch in the window/
namespace every time they're needed, or tear them down when the file-type changes.
Instead, create your highlighters in the shared/
namespace when your plugin is loaded. Then when your highlighters are needed in a particular window, use the ref
highlighter to include the shared highlighters into the window scope. For example, if your plugin creates shared highlighters:
add-highlighter shared/MyPluginSharedHighlighters group
# ...plus a bunch of highlighters inside the group...
...then you can link it into the window scope with:
add-highlighter window/MyPluginWindowHighlighters ref MyPluginSharedHighlighters
Note that the last parameter is the path of the shared highlighter, without the shared/
prefix.
If your plugin needs complicated or expensive initialisation (for example, if you need to create very complex shared highlighters, or you want to collect all the executables on the user's $PATH
or something), it's a good idea to put those steps into a module that can be loaded when needed, instead of running them every time Kakoune starts. It's safe to declare options or define commands outside a module (those are fast), but using commands and especially shell blocks should probably be done in a module.
To create a module, use the provide-module
command:
provide-module MyPluginSharedHighlighters %{
# ...regular commands in here...
}
When you require the side-effects of the module (you want to use the shared highlighters it defines, or read the value of the option it sets, etc.) use the require-module
command:
require-module MyPluginSharedHighlighters
The first time Kakoune executes a require-module
command, it looks up the contents of the corresponding module and executes them, then marks that module as loaded. The second and following times Kakoune executes a require-module
command, it sees the module is already loaded, and does nothing.
- Normal mode commands
- Avoid the escape key
- Implementing user mode (Leader key)
- Kakoune explain
- Kakoune TV