Revision 1.1
Nate SoaresThis is the in-depth vimscript guide. If you're just a casual user looking to write a plugin, the abbreviated style guide is for you.
This rather rotund guide dives into justifications and clarifications. It provides an idealized set of rules that are rather too draconian to push on casual scripters.
It's for users who want to know why certain decisions were made in the abbreviated guide and who want to learn a thing or two about using vimscript safely.
Fair warning: Vimscript is a maddening abyss. When you gaze into it, it gazes also into you. Proceed with caution.
Vim is highly configurable. Users can change many of the default settings, including the case sensitivity, the regular expression rules, the substitution rules, and more. In order for your vimscript to work for all users, follow these guidelines:
\m
,
\v
, \M
, or \V
(prefer
tersity)
.
, *
, and {
.
magic
setting you must prefix it
with one of the magic control atoms. This future-proofs your
regular expression against other devs modifying it and forgetting
to add the control atom.
:s[ubstitute]
in scripts.
:substitute
moves the cursor.
:substitute
outputs an error message when the match
does not exist.
g
flag depends upon the
gdefault
setting. If you do use
:substitute
you must save gdefault
, set
it to 0
or 1
, perform the substitution,
and then restore it.
maktaba#buffer#Replace
.
=~#
and
=~?
, never =~
).
!~ == != > >= <
and
<=
==
and
>=
are fine for numbers, but ==#
and
>=#
must be used for strings.
=~
and friends is dependent upon the
ignorecase
setting.
ignorecase
setting. Be prepared to justify
your reasoning.
\c
or \C
.
=~#
, etc.).
ignorecase
setting.
ignorecase
setting. Be prepared to justify
your reasoning.
normal!
instead of normal
.
!
the command will use the user's
key mappings and you have literally no idea what your macro will
do.
noremap
family of commands.
map
command respects the users existing
mappings and could do anything.
catch
, match the error code rather than the
error text.
:help error-messages
.
In general, guard all commands and functions against user settings.
maktaba#error
codes found in
maktaba
.
:help error-messages
.
maktaba#error#Message
.
0 == 'foo'
evaluates to true.
is#
operator.
Otherwise, prefer maktaba#value#IsEqual
or check
type()
explicitly.
maktaba#ensure
, or check
maktaba#value
or type()
and throw your own
errors.
:unlet
for variables that may change types,
particularly those assigned inside loops.
maktaba#function
instead to create and
manipulate handles to functions.
self
parameter which access
the dict state.
All other language features are fair game.
maktaba
.
plugin-names-like-this
autoload/
subdirectory of
your plugin.
plugin/
or instant/
directory
should begin with the boilerplate
instant/flags.vim
.
call s:plugin.Flag('FLAGNAME', DEFAULT_VALUE)
.
:Glaive
command (see glaive).
plugin/
or the
ftplugin/
subdirectories.
plugin/commands.vim
or ftplugin/
files.
plugin/autocmds.vim
,
inside an augroup.
plugin/mappings.vim
and
will be disabled unless explicitly enabled by users.
plugin/settings.vim
or
instant/settings.vim
.
after/
subdirectory.
after/
should be reserved for the user.
after/
.
Many plugins provide either user functionality (commands, autocommands, etc) or an API (of autoloaded functions) but not both. This separation is encouraged, as it allows other plugins to pull in a library without also pulling in commands, setting changes, and other plugin functionality that affects the end user.
:Glaive
command.
Follow google-wide style conventions. Mimic google python style when in doubt.
Provide help files generated by vimdoc. Write documentation in .vim files in conformance with the vimdoc standards and include fields like "description" and "author" in the addon-info.json file (see the VAM documentation).
"
before the comment text.
plugin-names-like-this
,
FunctionNamesLikeThis
,
CommandNamesLikeThis
,
augroup_names_like_this
,
variable_names_like_this
.
Prefix all variables with their scope.
variable_names_like_this
g:
autoload
directories.
s:
a:
l:
l:
disambiguates between function-local and
vim-predefined variables. For example, count
refers to
v:count
, not l:count
.
v:
b:
Prefer single quoted strings. Specifically, in order of precedence:
'\s*'
is not the same as "\s*"
'example ('')'
represents the
string
example (')
\n
,
\t
, etc.) use double quotes.
'\n'
in a regex does not represent a
newline, but rather "\n". You only need to use double quotes
when you want to embed the represented character itself (e.g. a
newline) in the string.
tabstop
over
ts
).
setlocal
and &l:
instead of
set
and &
.
Vim plugins should provide any or all of the following: Commands, Autocommands, Functions, Statusline Flags, and Mappings.
plugin/commands.vim
.[!]
CommandNamesLikeThis
command
without a bang.
<bang>
,
<register>
, etc.) before argument parameters
(<f-args>
, etc.).
instant/commands.vim
file in plugins using
maktaba, or explicitly installed via an autoload function in
non-maktaba plugins.
<bang>
to functions with
'<bang>' == '!'
.
plugin/autocmds.vim
.plugin/autocmds.vim
file.
Glaive myplugin !plugin[autocmds]
.
augroup
block.
autocmd!
.
augroup
, the
augroup
name should be the same as your plugin
name, with underscores in place of any hyphens.
augroup
names should start with your
plugin name followed by an underscore.
augroup
, clear it with
autocmd!
s:
[!]
.[abort]
.FunctionNamesLikeThis
s:
abort
.
try..endtry
block
somewhere on the stack.
abort
keyword forces the function to act
consistently.
function!
with a bang.
autoload
directory.
...
for optional arguments, not for lists of
arguments.
...
for a list of arguments.
plugin/mappings.vim
.
<Plug>
mappings can be defined in
plugin/plugs.vim
(unlike mappings.vim, plugs.vim is
opt-out).
plugin/mappings.vim
, using
maktaba#plugin#MapPrefix
to get a prefix.
plugin/mappings.vim
file will be disabled by default (by the standard
maktaba#plugin#Enter()
boilerplate).
Glaive myplugin plugin[mappings]
.
<unique>
.
<Plug>
and
your plugin's name in plugin/plugs.vim
(separate from
standard key mappings).
<Plug>
is a sequence which can not be typed.
noremap <Plug>namespace#MappingName
some_key_sequence
and then users can do
noremap <leader>x
<Plug>namespace#MappingName
to take advantage of your pseudo-mapping.
plugin/mappings.vim
or they will be disabled by
default.
<Plug>
followed by your plugin name, a pound sign, and a unique mapping
name (CamelCased like a function).
noremap
family of commands. Never use
the map
family.
map
depends upon the user's existing mappings, and
could do anything.
noremap
for commands that both make a motion
and take a range.
noremap
makes mappings in normal, visual, and
operator-pending modes.
nnoremap
onoremap
or vnoremap
explicitly.
<SID>
in place of s:
when
accessing script locals in mappings.
s:
will often fail as the mapping attempts to
type a literal s and colon.
maktaba
.
Declaring dependencies in addon-info.json allows conformant plugin managers (like VAM) to ensure dependencies are installed. See the VAM documentation for details.
Calling maktaba#library#Require
from dependent code at
runtime ensures that dependencies have been installed and that they
don't include unsafe non-library files.
<plugin-name>#status#Status()
or its
finer-grained variants to provide statusline flags.
Following is a convention for exposing statusline flags to the user. A plugin should never modify the user's statusline except for when that is the only purpose of the plugin (powerline, etc.).
Info
,
Alert
,
Warning
, and
Error
functions under the
<plugin-name>#status
namespace.
Info
should provide information about the
state of the buffer.
Alert
should provide a quiet reminder
that the buffer is non-standard.
Warning
should provide a warning about
the current state of the buffer.
Error
should bring to attention a loud
issue with the buffer.
[Google]
. For example:
[$]
if
the file contains trailing whitespace
[write]
if vim
is in writing mode.
<plugin-name>#status#Status
function.
Error
,
Warning
, Alert
, or Info
.
These are commands which can only be used by a limited number of plugins, and should not in general be used by yours.
:match :2match
or :3match
matchadd()
to create a matchlevel unique to your
plugin.
echoerr
.
echoerr
does not print the red error message that you
might think it does.
echoerr
prints an error message as well as context
about the code where echoerr
was called.
echoerr
is best suited for debugging.
echohl
in tandem with echomsg
if
you want the red error bar.
echomsg
instead of echo
.
echomsg
messages can be reviewed with the
:messages
command.
echo
messages disappear permanently on redraw, which
can be very annoying to users who failed to read the message in
time.
Lay out plugin/
files in the following sections, if
applicable, separated by two blank lines:
commands.vim
file,
autocommands in autocmds.vim
file, etc.)
Lay out autoload/
files in the following sections, if
applicable, separated by two blank lines:
maktaba#library#Require
calls
This is recommended convention and is not enforced.
Use the following shortcuts:
catch
over catch /.*/
return
over return 0
when the return value
has no semantic purpose.
This section plumbs some of the darker corners of vimscript, explaining the language pathologies that you wish you didn't have to know.
When compatible
is set, many vim features are not
available. The vim feature which most commonly affects vimscript
authors is line continuations.
If you want your plugin to work in vim with vi compatibility on, you
will need to save the compatibility options at the beginning of each
plugin file, clear them, and restore them at the end of each plugin
file. See :help use-cpo-save
for details.
Plugins that depend on maktaba generally don't need to worry about compatible mode since maktaba currently just disables it, printing a warning.
Revision 1.1
Nate Soares