Pack – Neovim docs
Nvim :help
pages, generated
from source
using the tree-sitter-vimdoc parser.
Extending Nvim
Using Vim packages
plugins, a package can…
be downloaded as an archive and unpacked in its own directory, so the files
are not mixed with files of other plugins.
be a git, mercurial, etc. repository, thus easy to update.
contain multiple plugins that depend on each other.
located in “pack/*/start/*”) and ones that are only loaded when needed with
:packadd (“opt” packages, located in “pack/*/opt/*”).
‘runtimepath’, so they will not be reported by “:set rtp” or “echo &rtp”.
Scripts can use nvim_list_runtime_paths() to list all used directories, and
nvim_get_runtime_file() to query for specific files or sub-folders within
the runtime path. Example:
" List all runtime dirs and packages with Lua paths. :echo nvim_get_runtime_file("lua/", v:true)
Using a package and loading automatically
add a package from a zip archive “/tmp/foopack.zip”:
% mkdir -p ~/.local/share/nvim/site/pack/foo % cd ~/.local/share/nvim/site/pack/foo % unzip /tmp/foopack.zip
The directory name “foo” is arbitrary, you can pick anything you like.
pack/foo/README.txt pack/foo/start/foobar/plugin/foo.vim pack/foo/start/foobar/syntax/some.vim pack/foo/opt/foodebug/plugin/debugger.vim
On startup after processing your config, Nvim scans all directories in
‘packpath’ for plugins in “pack/*/start/*”, then loads the plugins.
In the example Nvim will find “pack/foo/start/foobar/plugin/foo.vim” and load
it.
find the syntax/some.vim file, because its directory is in the runtime search
path.
Nvim will also load ftdetect files, if there are any.
ones under “pack/foo/start”. See pack-add below for how the “opt” directory
is used.
see load-plugins.
To load packages earlier, so that plugin/ files are sourced:
:packloadall
This also works when loading plugins is disabled. The automatic loading will
only happen once.
‘runtimepath’, so that anything there will be loaded later.
Using a single plugin and loading it automatically
directory level:
% mkdir -p ~/.local/share/nvim/site/pack/foo/start/foobar % cd ~/.local/share/nvim/site/pack/foo/start/foobar % unzip /tmp/someplugin.zip
You would now have these files:
pack/foo/start/foobar/plugin/foo.vim pack/foo/start/foobar/syntax/some.vim
From here it works like above.
Optional plugins
pack-add
To load an optional plugin from a pack use the :packadd
command:
:packadd foodebug
This searches for “pack/*/opt/foodebug” in ‘packpath’ and will find
~/.local/share/nvim/site/pack/foo/opt/foodebug/plugin/debugger.vim and source
it.
This could be done if some conditions are met. For example, depending on
whether Nvim supports a feature or a dependency is missing.
your config:
:packadd! foodebug
The extra “!” is so that the plugin isn’t loaded if Nvim was started with
–noplugin.
It is perfectly normal for a package to only have files in the “opt”
directory. You then need to load each plugin when you want to use it.
Since color schemes, loaded with :colorscheme
, are found below
“pack/*/start” and “pack/*/opt”, you could put them anywhere. We recommend
you put them below “pack/*/opt”, for example
“~/.config/nvim/pack/mycolors/opt/dark/colors/very_dark.vim”.
found. Unless you have more than one plugin for a file type and want to
select which one to load with
:packadd
. E.g. depending on the compilerversion:
if foo_compiler_version > 34 packadd foo_new else packadd foo_old endif
The “after” directory is most likely not useful in a package. It’s not
disallowed though.
This assumes you write one or more plugins that you distribute as a package.
If you have two unrelated plugins you would use two packages, so that Vim
users can choose what they include or not. Or you can decide to use one
package with optional plugins, and tell the user to add the preferred ones with
:packadd
.
Decide how you want to distribute the package. You can create an archive or
you could use a repository. An archive can be used by more users, but is a
bit harder to update to a new version. A repository can usually be kept
up-to-date easily, but it requires a program like “git” to be available.
You can do both, github can automatically create an archive for a release.
start/foobar/plugin/foo.vim " always loaded, defines commands start/foobar/plugin/bar.vim " always loaded, defines commands start/foobar/autoload/foo.vim " loaded when foo command used start/foobar/doc/foo.txt " help for foo.vim start/foobar/doc/tags " help tags opt/fooextra/plugin/extra.vim " optional plugin, defines commands opt/fooextra/autoload/extra.vim " loaded when extra command used opt/fooextra/doc/extra.txt " help for extra.vim opt/fooextra/doc/tags " help tags
mkdir ~/.local/share/nvim/site/pack cd ~/.local/share/nvim/site/pack git clone https://github.com/you/foobar.git myfoobar
Here “myfoobar” is a name that the user can choose, the only condition is that
it differs from other packages.
to load the optional plugin:
:packadd! fooextra
You could add this packadd command in one of your plugins, to be executed when
the optional plugin is needed.
:helptags
command to generate the doc/tags file. Including thisgenerated file in the package means that the user can drop the package in the
pack directory and the help command works right away. Don’t forget to re-run
the command after changing the plugin help:
:helptags path/start/foobar/doc :helptags path/opt/fooextra/doc
Dependencies between plugins
packload-two-steps
Suppose you have two plugins that depend on the same functionality. You can
put the common functionality in an autoload directory, so that it will be
found automatically. Your package would have these files:
call foolib#getit()
pack/foo/start/two/plugin/two.vim
call foolib#getit()
pack/foo/start/lib/autoload/foolib.vim
func foolib#getit()
This works, because start packages will be searched for autoload files, when
sourcing the plugins.
WORK IN PROGRESS built-in plugin manager! Early testing of existing features
is appreciated, but expect breaking changes without notice.
$XDG_DATA_HOME/nvim/site/pack/core/opt
. $XDG_DATA_HOME/nvim/site
needs tobe part of ‘packpath’. It usually is, but might not be in cases like –clean
or setting $XDG_DATA_HOME during startup. Plugin’s subdirectory name matches
plugin’s name in specification. It is assumed that all plugins in the
directory are managed exclusively by
vim.pack
.
Uses Git to manage plugins and requires present git
executable of at least
version 2.36. Target plugins should be Git repositories with versions as named
tags following semver convention v<major>.<minor>.<patch>
.
vim.pack.add(
-- Install "plugin1" and use default branch (usually `main` or `master`)
'https://github.com/user/plugin1',
-- Same as above, but using a table (allows setting other options)
src="https://github.com/user/plugin1" ,
-- Specify plugin's name (here the plugin will be called "plugin2"
-- instead of "generic-name")
src="https://github.com/user/generic-name", name="plugin2" ,
-- Specify version to follow during install and update
version = vim.version.range('1.0'),
,
src="https://github.com/user/plugin4",
-- Git branch, tag, or commit hash
version = 'main',
,
)
-- Plugin's code can be used directly after `add()`
plugin1 = require('plugin1')
installed will be available on disk in target state after
add()
call.
To update all plugins with new changes:
show confirmation buffer in a separate tabpage.
Update ‘init.lua’ for plugin to have desired version
. Let’s say, plugin
named ‘plugin1’ has changed to vim.version.range('*')
.
Execute vim.pack.update( 'plugin1' )
.
changes in ‘init.lua’ as well or you will be prompted again next time you
run vim.pack.update().
Update ‘init.lua’ for plugin to have version
set to current commit hash.
You can get it by running vim.pack.update( 'plugin-name' )
and yanking
the word describing current state (looks like abc12345
).
Update ‘init.lua’ for plugin to have version
set to whichever version you
want it to be updated.
specs are not included in vim.pack.add() call in ‘init.lua’ or they will
be reinstalled.
Available events to hook into
kind
– one of “install” (install on disk), “update” (update existing
plugin), “delete” (delete from disk).
spec
– plugin’s specification with defaults made explicit.
path
– full path to plugin’s directory.
Fields:
src
(string
) URI from which to install and pull updates. Any
format supported by git clone
is allowed.
name
(string
) Name of plugin. Will be used as directory name.
Default: src
repository name.
version
(string|vim.VersionRange
) Version to use for install and
updates. Can be:
nil
(no value, default) to use repository’s default
branch (usually main
or master
).
String to use specific branch, tag, or commit hash.
greatest/last semver tag inside the version constraint.
data
(any
) Arbitrary data associated with a plugin.
specs
, opts
) vim.pack.add()Add plugin to current session
If exists, do nothing in this step.
If doesn’t exist, install it by downloading from src
into name
subdirectory (via git clone
) and update state to match version
(via git checkout
).
Installation is done in parallel, but waits for all to finish before
continuing next code execution.
present state. The specified
version
can be not the one actuallypresent on disk. Execute vim.pack.update() to synchronize.
Adding plugin second and more times during single session does nothing:
only the data from the first adding is registered.
Parameters:
specs
((string|vim.pack.Spec)[]
) List of plugin specifications.
String item is treated as src
.
opts
(table?
) A table with the following fields:
load
(boolean|fun(plug_data: spec: vim.pack.Spec, path: string)
)
Load plugin/
files and ftdetect/
scripts. If false
,
works like :packadd!
. If function, called with plugin
data and is fully responsible for loading plugin. Default
false
during startup and true
afterwards.
confirm
(boolean
) Whether to ask user to confirm
initial install. Default true
.
Parameters:
names
(string[]
) List of plugin names to remove from disk. Mustbe managed by vim.pack, not necessarily already added to
current session.
Return:
(table[]
) A list of objects with the following fields:
path
(string
) Plugin’s path on disk.
names
, opts
) vim.pack.update()Update plugins
Download new changes from source.
Infer update info (current/target state, changelog, etc.).
Depending on force
:
If false
, show confirmation buffer. It lists data about all set to
update plugins. Pending changes starting with >
will be applied
while the ones starting with <
will be reverted. It has special
in-process LSP server attached to provide more interactive features.
Currently supported methods:
K
via lsp-defaults orvim.lsp.buf.hover()) – show more information at cursor. Like
details of particular pending change or newer tag.
Execute :write to confirm update, execute :quit to discard the
update.
If true
, make updates right away.
stdpath().
Parameters:
names
(string[]?
) List of plugin names to update. Must be managedby vim.pack, not necessarily already added to current
session. Default: names of all plugins added to current
session via vim.pack.add().
opts
(table?
) A table with the following fields:
force
(boolean
) Whether to skip confirmation and make
updates immediately. Default false
.