Skip to content

Creating Vim Plugins with Maktaba

Josh Hoak edited this page May 28, 2020 · 3 revisions

Table of Contents

The Basics

A maktaba plugin is a directory of vim files with basically the same file structure as any vim plugin:

myplugin/
    addon-info.json ← Declares plugin metadata and dependencies (See Plugin Metadata)
  instant/
    flags.vim ← Defines all flags (See Configuration with Glaive)
  plugin/
    settings.vim ← Configures vim setting values
    commands.vim ← Defines all commands
    autocmds.vim ← Defines all autocmds
    mappings.vim ← Defines all mappings
    stuff.vim
    morestuff.vim
  autoload/
    myplugin.vim
    myplugin/
      morestuff.vim
  doc/
    myplugin.txt ← Usually generated using Vimdoc
    tags ← Generated by vim’s `:helptags` command
  vroom/
    main.vroomVroom test / executable documentation
    morestuff.vroom
  ftplugin/
  syntax/
  

Each file under myplugin/plugin/ and myplugin/instant/ should contain this boilerplate verbatim at the top:

let [s:plugin, s:enter] = maktaba#plugin#Enter(expand('<sfile>:p'))
if !s:enter
  finish
endif

(This prevents double-sourcing and helps make your plugin more configurable. See Plugin Files for more details.)

Any flags, commands, autocmds, or mappings your plugin defines should be defined in their respective plugin/ files as indicated in the file structure above.

The plugin can now be loaded with:

call maktaba#plugin#GetOrInstall('myplugin')

That’s basically all that’s required of a maktaba plugin. Existing plugins can be converted to maktaba plugins simply by ensuring the files are laid out in the right structure and that the plugin/ files contains the boilerplate above.

The rest is about making use of the full power of maktaba (especially Glaive) and adhering to some style guidelines to avoid common vimscript pitfalls.

Points of Style

Vimscript is just full of gotchas. Will your plugin still work properly if users set ignorecase or nomagic? Will it confuse users by overriding their commands and mappings, or crash if vim sources your file twice? Can users disable features that annoy them without uninstalling your whole plugin?

Making full use of the maktaba framework helps avoid several mistakes. You should also familiarize yourself with the Vimscript Style Guide and the Full Vimscript Guide to avoid many other common pitfalls. Another great resource is Steve Losh’s book Learn Vimscript the Hard Way, which is available for free online.

## Plugin Metadata

Every plugin should include an addon-info.json file with at least the following:

{
  "name": "myplugin",
  "dependencies": {
    "maktaba": {"type": "git", "url": "git://github.com/google/maktaba"}
  }
}

This allows plugin managers to satisfy plugin dependencies, and helps maktaba to detect the plugin directory as a plugin, as opposed to just a miscellaneous directory of runtime files on the runtimepath.

See the VAM-addon-info section in the VAM documentation for more information on the addon-info.json spec.

Plugin Files

Maktaba has some special conventions for files under plugin/, but there’s nothing fundamentally different about them and any old file under plugin/ should continue to work as expected.

In general, files under plugin/ should expect to be sourced once and only once. Some shouldn’t even be sourced at all if the user opts to explicitly disable them. To give maktaba control to exit early and forbid reentry, each plugin/ file should start with the following boilerplate:

let [s:plugin, s:enter] = maktaba#plugin#Enter(expand('<sfile>:p'))
if !s:enter
  finish
endif

A few filenames are special and maktaba will explicitly source them in some cases if vim hasn’t automatically sourced them yet.

Configuration with Glaive

Maktaba integrates with a system for powerful user configuration called Glaive. Generally, maktaba plugins should avoid relying on global variables for configuration, and instead manage their configuration as Glaive flags.

Glaive flags have several advantages for users and for plugin developers:

  • A concise, readable format for users to specify configuration
  • Short names that don’t collide with flags in other plugins (every flag is namespaced under the plugin name)
  • Powerful operations like += that can be deferred until the flag is initialized
  • Less boilerplate for accessing and modifying flag values
  • Automatically documented by Vimdoc

To use Glaive flags, define them in your instant/flags.vim file:

call s:plugin.Flag('sayhello', 1)
call s:plugin.Flag('name', 'Whoever you are')

and access them from autoload files or other code via maktaba#plugin#Get:

let s:plugin = maktaba#plugin#Get('myplugin')
if s:plugin.Flag('sayhello')
  " Say hello unless user has explicitly disabled it.
endif

Users can configure Glaive flags in their .vimrc after they load maktaba with:

Glaive myplugin !sayhello name='George'

A flag value can be a number, string, list, or dict. See the Glaive documentation for more information.

NOTE: instant/flags.vim will be automatically sourced when you first try to read a flag value for your plugin, so in general you can use flags from autoload, autocmd, and other special contexts without worrying about whether they’re defined yet.

Commands, Autocmds, and Mappings

Maktaba plugins should define any commands, autocmds, and mappings in their respective plugin/ file.

plugin/commands.vim

" ...
command DoSomething call myplugin#DoSomething()

plugin/autocmds.vim

" ...
augroup myplugin
  autocmd!
  autocmd BufWritePre * DoSomething
augroup END

plugin/mappings.vim

" ...
let s:prefix = s:plugin.MapPrefix('m')
execute 'nnoremap <unique> <silent>' s:prefix . 's' :DoSomething<CR>

Maktaba provides a special dict flag for each plugin called plugin, which the user can configure to selectively disable features. For example, a user who doesn’t like the default autocmds could configure your plugin with

Glaive myplugin !plugin[autocmds]

and then the maktaba#plugin#Enter boilerplate would prevent the autocmds from being loaded at all.

Tests

Plugins can be tested using the Vroom testing system. Vroom tests are part executable test, part walkthrough-style documentation. Vroom is not part of maktaba, but all maktaba plugins should define at least a basic test that loads the plugin, so that you have an automated way to detect initialization errors:

:call maktaba#plugin#GetOrInstall('myplugin')

Documentation

All maktaba plugins should include some help files under the doc/ directory, typically at doc/myplugin.txt. These files can be generated using Vimdoc, which scans your plugins for doc comments starting with the vimdoc leader:

"" This is a vimdoc comment

and creates high-quality vim help files.

All flags, public functions, commands, and autocmds should have vimdoc comments so they’re included in the generated help files.

See the Vimdoc documentation for more information.