<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Evgeni Chasnovski</title>
<link>https://echasnovski.com/blog.html</link>
<atom:link href="https://echasnovski.com/blog.xml" rel="self" type="application/rss+xml"/>
<description>Personal website of Evgeni Chasnovski</description>
<generator>quarto-1.8.24</generator>
<lastBuildDate>Fri, 13 Mar 2026 00:00:00 GMT</lastBuildDate>
<item>
  <title>A Guide to vim.pack (Neovim built-in plugin manager)</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2026-03-13-a-guide-to-vim-pack.html</link>
  <description><![CDATA[ 





<p>The upcoming Neovim 0.12 release <a href="../blog/2025-07-04-neovim-now-has-builtin-plugin-manager.html">will have a built-in plugin manager</a>. It is implemented in Lua and is available as a built-in <a href="https://neovim.io/doc/user/helptag.html?tag=vim.pack"><code>vim.pack</code></a> module (hence the name). This blog post describes the fundamentals of how <code>vim.pack</code> is intended to be used. Reading only selected sections should be fine, but it is written to be read from top to bottom.</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>Beware that, although unlikely, some information from this post can become outdated. Neovim’s own documentation is always the higher authority. From the running Neovim instance execute <code>:h vim.pack</code> to read the help and <code>:h vim.pack-examples</code> to read suggested workflows for common use cases.</p>
</div>
</div>
<p>If you are a visual learner or want to see how using <code>vim.pack</code> looks like, check out this YouTube video:</p>
<div class="callout callout-style-default callout-note callout-titled" title="A Demo of vim.pack (Neovim built-in plugin manager)">
<div class="callout-header d-flex align-content-center collapsed" data-bs-toggle="collapse" data-bs-target=".callout-2-contents" aria-controls="callout-2" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Note</span>A Demo of vim.pack (Neovim built-in plugin manager)
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-2" class="callout-2-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<div class="quarto-video ratio ratio-16x9"><iframe data-external="1" src="https://www.youtube.com/embed/J1r0vrqOMJo" title="" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe></div>
</div>
</div>
</div>
<section id="concepts" class="level2">
<h2 class="anchored" data-anchor-id="concepts">Concepts</h2>
<p>This section lists <code>vim.pack</code> adjacent information that would be beneficial to understand before using it.</p>
<section id="lua" class="level3">
<h3 class="anchored" data-anchor-id="lua">Lua</h3>
<p>The <code>vim.pack</code> module is written and is designed to be used in Lua programming language. So at least a basic understanding of its logic and syntax would be useful.</p>
<p>There are many sources online for the language itself, like <a href="https://learnxinyminutes.com/lua/">“Learn X in Y minutes where X=Lua”</a>. Neovim has its own resources: <a href="https://neovim.io/doc/user/helptag.html?tag=lua-concepts"><code>:h lua-concepts</code></a> and <a href="https://neovim.io/doc/user/helptag.html?tag=lua-guide"><code>:h lua-guide</code></a>.</p>
<p>The basic working knowledge to know for <code>vim.pack</code> is about:</p>
<ul>
<li>Tables: <code>{ 'one', 'two' }</code> and <code>{ a = 1, b = 2 }</code>.</li>
<li>Functions: <code>f({ 'one', 'two' })</code>.</li>
<li>How to execute code inside user’s config: put it in or source from <a href="https://neovim.io/doc/user/helptag.html?tag=init.lua">‘init.lua’ file</a>.</li>
</ul>
</section>
<section id="runtime-files" class="level3">
<h3 class="anchored" data-anchor-id="runtime-files">Runtime files</h3>
<p>To provide extensibility and flexibility, Neovim (and Vim) has a concept of runtime files: various support files that can be found and used when Neovim is running. Where these files are searched is controlled by the <a href="https://neovim.io/doc/user/helptag.html?tag='runtimepath'">‘runtimepath’ option</a>, which is essentially a list of directories.</p>
<p>Most commonly used types of runtime files when it comes to external plugins in Neovim are:</p>
<ul>
<li>Lua modules. Searched in <code>lua/</code> subdirectories.</li>
<li>Plugin scripts. Searched in <code>plugin/</code> subdirectories.</li>
<li>Filetype plugins. Searched in <code>ftplugin/</code> subdirectories.</li>
</ul>
<hr>
<p>For example, if <code>'runtimepath'</code> is <code>/home/user/dir,/home/user/dir-other</code>, then:</p>
<ul>
<li><p><code>require('myplug')</code> will try to look for <code>lua/myplug.lua</code> or <code>lua/myplug/init.lua</code> inside <code>/home/user/dir</code>, then <code>/home/user/dir-other</code>, and source the first one it finds.</p></li>
<li><p>All files in <code>/home/user/dir/plugin</code> and <code>/home/user/dir-other/plugin</code> are sourced in alphabetical order during startup.</p></li>
<li><p>Setting filetype <code>myft</code> will look for <code>ftplugin/myft.{vim,lua}</code> inside <code>/home/user/dir</code>, then <code>/home/user/dir-other</code>, and source all that it finds.</p></li>
</ul>
<p>The most important runtime paths for common users available by default are:</p>
<ul>
<li><p><a href="https://neovim.io/doc/user/helptag.html?tag=$XDG_CONFIG_HOME">User’s config directory</a>: <code>~/.config/nvim</code> on Unix and <code>~/AppData/Local/nvim</code> on Windows. Used for personal config. This is also known as <a href="https://neovim.io/doc/user/helptag.html?tag=standard-path">“config” standard path</a>.</p></li>
<li><p><a href="https://neovim.io/doc/user/helptag.html?tag=$XDG_DATA_HOME">The <code>site/</code> subdirectory of user’s data directory</a>: <code>~/.local/share/nvim/site</code> on Unix and <code>~/AppData/Local/nvim-data/site</code> on Windows. Used for data from plugins installed by user. The parent of <code>site</code> directory is also known as <a href="https://neovim.io/doc/user/helptag.html?tag=standard-path">“data” standard path</a>.</p></li>
<li><p>The <a href="https://neovim.io/doc/user/helptag.html?tag=after-directory"><code>after/</code> subdirectory</a> of user’s config directory. Primarily used for manual runtime files that should have the “final say” over all others, as it is usually the last ‘runtimepath’ entry.</p></li>
</ul>
<hr>
<p>When it comes to a plugin manager:</p>
<ul>
<li><p>Installing a plugin means to download and put it in the known location on the disk.</p></li>
<li><p>Loading a plugin means to make sure that its path is a proper part of <code>'runtimepath'</code>. Not at the start (where user’s config directory should be), not at the end (where user’s <code>after/</code> config subdirectory should be), but somewhere in the middle.</p></li>
</ul>
</section>
<section id="plugin-packages" class="level3">
<h3 class="anchored" data-anchor-id="plugin-packages">Plugin packages</h3>
<p>To at least somehow standardize extensibility via plugins, Neovim (and Vim) has the concept of <a href="https://neovim.io/doc/user/helptag.html?tag=packages">plugin packages</a> (a.k.a. “Vim packages” or just “packages”). It is a collection of plugins meant to be used together. For Neovim to find a plugin package, it should be put in ‘pack’ subdirectory of any path from <a href="https://neovim.io/doc/user/helptag.html?tag='packpath'"><code>'packpath'</code></a> (works similar and by default is equal to <code>'runtimepath'</code>).</p>
<p>One package can have two types of plugins:</p>
<ul>
<li><p>So called “opt” plugins are meant to be available/loaded only on demand after executing <a href="https://neovim.io/doc/user/helptag.html?tag=:packadd"><code>:packadd</code></a>. This command searches through a dedicated set of directories (controlled by ‘packpath’ option).</p></li>
<li><p>So called “start” plugins are meant to be available/loaded automatically during startup. The only way to make them not load during startup is to move them to the “opt” part of the package.</p></li>
</ul>
<hr>
<p>For example, a package named <code>bundle</code> (common name from early days of adapting this feature) might have the following structure:</p>
<pre class="tree-style"><code>bundle/
├── start/                 Directory for "start" plugins
│   ├── plug-one/          First "start" plugin
│   │   └── ftplugin/
│   │       └── myft.lua
│   └── plug-two/          Second "start" plugin
│       └── lua/
│           └── myplug.lua
└── opt/                   Directory for "opt" plugins
    └── plug-three/        The only "opt" plugin
        └── lua/
            └── three.lua</code></pre>
<p>If this package is put as <code>pack/bundle/</code> subdirectory under some known package path (the <code>~/.local/share/nvim/site</code> would be the most expected place), then:</p>
<ul>
<li><p>Plugins ‘plug-one’ and ‘plug-two’ will <em>always</em> be available after startup.</p></li>
<li><p>Plugin ‘plug-three’ is made available after executing <code>:packadd plug-three</code>.</p></li>
</ul>
</section>
</section>
<section id="install-and-load" class="level2">
<h2 class="anchored" data-anchor-id="install-and-load">Install and load</h2>
<p>Adding plugin(s) to a config is done via <a href="https://neovim.io/doc/user/helptag.html?tag=vim.pack.add()"><code>vim.pack.add()</code></a>. It acts as a “smart <code>:packadd</code>” - install if plugin is missing and load it. The design is for it to be a part of the user’s config: add with a list of all external plugins you want to use and forget about it. Like this (for more comprehensive examples see “Config organization”):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb2-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span></span>
<span id="cb2-2">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.nvim'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-3">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/neovim/nvim-lspconfig'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-4">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-treesitter/nvim-treesitter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-5"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span></code></pre></div></div>
<p>By default during initial install there is also a confirmation dialog showing which plugins are going to be installed. Press <code>y</code> to confirm, <code>n</code> to skip, <code>a</code> to allow for all <code>vim.pack.add()</code> confirmations in current session. It looks like this:</p>
<p><img src="https://echasnovski.com/blog/2026-03-13-a-guide-to-vim-pack/demo-vim-pack-add-confirm.png" class="img-fluid"></p>
<p>Adding a plugin via <code>vim.pack.add()</code> makes it “active” or “loaded” in current session.</p>
<hr>
<p>All plugins that were not previously installed by <code>vim.pack</code> are installed in parallel. They are put into a dedicated <code>core</code> plugin package as “opt” plugins (see <a href="https://neovim.io/doc/user/helptag.html?tag=vim.pack-directory"><code>:h vim.pack-directory</code></a>). There is no “start” plugin support because:</p>
<ul>
<li><p>It makes it possible to comment out the (part of) <code>vim.pack.add()</code> call and some plugins will not load in the next session. Almost as if they don’t exist at all.</p></li>
<li><p>This way the entire config acts as a blueprint of how plugins are loaded and meant to be updated. Using “start” plugins more fits the workflow like “manually install and forget about it” which is not quite “add to init.lua and forget about it”. Since all plugins are assumed to be listed in the config and are loaded with <code>vim.pack.add</code>, there is functionally no difference between “opt” and “start” plugin types.</p></li>
</ul>
<hr>
<p>Only Git repos can be managed (installed, updated, deleted) by <code>vim.pack</code>. For other ways of plugin distribution, it is suggested to manually download them into a separate, dedicated plugin package (either directly or via symlinked directory). This also includes so called “local” plugins, which users already have on the disk and want to manage themselves.</p>
<p>Plugins installed by <code>vim.pack</code> are expected to be managed/altered <strong>only by <code>vim.pack</code></strong>. Which also includes to not update/delete their code by hand. There are safeguards to handle this graciously, but in general there can be problems. To contribute to a plugin you use via <code>vim.pack</code>, the safest approach is to:</p>
<ul>
<li><p>If not already, set up a directory for “local” plugins that fits into plugin package structure. The easiest approach is a dedicated package like <code>~/.local/share/nvim/site/pack/mine/opt</code> or <code>~/.config/nvim/pack/mine/opt</code> (while adding <code>pack/</code> directory to <code>.gitignore</code>). It can also be anywhere on the disk but with a symlink to an “opt” part of a known plugin package.</p></li>
<li><p>Download it (usually by forking it on a Git forge and using <code>git clone</code>) into a directory for “local” plugins. Use a directory name that is different from the reference plugin (otherwise there would be name conflicts).</p></li>
<li><p>Comment out <code>vim.pack.add</code> for the reference plugin in the config and replace it with <code>vim.cmd.packadd('my-local-copy')</code>.</p></li>
<li><p>Use a local copy for however long you need (make changes, push/pull branches, etc.). When done, revert changes from the previous step to start using reference plugin again.</p></li>
</ul>
<div class="callout callout-style-default callout-note callout-titled" title="Well, technically ...">
<div class="callout-header d-flex align-content-center collapsed" data-bs-toggle="collapse" data-bs-target=".callout-3-contents" aria-controls="callout-3" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Note</span>Well, technically …
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-3" class="callout-3-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<p>… it is possible to update by hand a plugin directly installed by <code>vim.pack</code>. Locate it in <code>core</code> plugin package and start making changes (create branches and commits, push/pull to remotes, etc.). Just make sure to:</p>
<ul>
<li><p>Not update the plugin with <code>vim.pack</code>. It will change the state to where its <code>version</code> points, so local changes will not have effect.</p></li>
<li><p>Do not cause any big structural changes. For example, it should still be a Git repository and located at the exact path it was before.</p></li>
<li><p>Ignore any messages that this plugin is not at a state that <code>vim.pack</code> expects it to be.</p></li>
<li><p>Eventually switch back to managing by <code>vim.pack</code> with <code>vim.pack.update({ 'plugin-name' }, { offline = true })</code>.</p></li>
</ul>
<p><strong>One more time</strong>: this is definitely a “not officially supported, do on your own risk” kind of territory.</p>
</div>
</div>
</div>
<hr>
<p>A subtle but one of the key things to understand is that <code>vim.pack.add()</code> is <strong>just a function</strong>. It takes plugin specifications and acts on them immediately. After execution is done without errors, all listed plugins should be available in the current Neovim session.</p>
<p>Some consequences of this design are:</p>
<ul>
<li><p>It results into a more unified config: adding a plugin is similar to creating a mapping or an autocommand.</p></li>
<li><p>It can be called multiple times with different plugin lists (with minor caveats) for a more “modular” config.</p></li>
<li><p>Lazy loading in principle is just “call this exact function, just some time later”.</p></li>
<li><p>It can be used interactively like <code>:lua vim.pack.add({ 'https://github.com/nvim-mini/mini.nvim' })</code>.</p></li>
</ul>
<hr>
<p>By default loading plugin is done by executing <code>:packadd</code> (possibly with <code>!</code>) command, which essentially makes plugin’s runtime files known to Neovim and sources some of them (<code>plugin/</code> and <code>ftdetect/</code> scripts).</p>
<p>With <code>vim.pack.add()</code> it is also possible to have custom loading logic. This can be useful to do something more or do nothing at all. The latter is useful as a workaround for some complex lazy loading. For example:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="vim-pack-add-no-load" style="background: #f1f3f5;"><pre class="sourceCode lua code-annotation-code code-with-copy code-annotated"><code class="sourceCode lua"><a class="code-annotation-anchor" data-target-cell="vim-pack-add-no-load" data-target-annotation="1" onclick="event.preventDefault();">1</a><span id="vim-pack-add-no-load-1" class="code-annotation-target"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span></span>
<span id="vim-pack-add-no-load-2">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/neovim/nvim-lspconfig'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<a class="code-annotation-anchor" data-target-cell="vim-pack-add-no-load" data-target-annotation="2" onclick="event.preventDefault();">2</a><span id="vim-pack-add-no-load-3" class="code-annotation-target"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">load</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code></pre></div></div>
<dl class="code-annotation-container-grid">
<dt data-target-cell="vim-pack-add-no-load" data-target-annotation="1">1</dt>
<dd>
<span data-code-cell="vim-pack-add-no-load" data-code-lines="1" data-code-annotation="1">“Register” plugin, but not load it right away</span>
</dd>
<dt data-target-cell="vim-pack-add-no-load" data-target-annotation="2">2</dt>
<dd>
<span data-code-cell="vim-pack-add-no-load" data-code-lines="3" data-code-annotation="2">Do nothing instead of <code>:packadd</code> to load</span>
</dd>
</dl>
<section id="specification" class="level3">
<h3 class="anchored" data-anchor-id="specification">Specification</h3>
<p>Each plugin can be specified as a single string describing its source, i.e.&nbsp;from where to download its files (<code>git clone</code> for install and <code>git fetch</code> to update). Please use this approach if no extra tweaking is required.</p>
<p>By default the plugin will be installed as source’s repository name and will get updates following default branch (usually <code>main</code> or <code>master</code>). It is also possible to tweak this by specifying <a href="https://neovim.io/doc/user/helptag.html?tag=vim.pack.Spec">table specification</a> instead of a single source string. Like this:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="annotated-cell-3" style="background: #f1f3f5;"><pre class="sourceCode lua code-annotation-code code-with-copy code-annotated"><code class="sourceCode lua"><span id="annotated-cell-3-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-3" data-target-annotation="1" onclick="event.preventDefault();">1</a><span id="annotated-cell-3-2" class="code-annotation-target">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">src</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.nvim'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">version</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'stable'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-3" data-target-annotation="2" onclick="event.preventDefault();">2</a><span id="annotated-cell-3-3" class="code-annotation-target">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">src</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/neovim/nvim-lspconfig'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lspconfig'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-3" data-target-annotation="3" onclick="event.preventDefault();">3</a><span id="annotated-cell-3-4" class="code-annotation-target">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-treesitter/nvim-treesitter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="annotated-cell-3-5"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code></pre></div></div>
<dl class="code-annotation-container-grid">
<dt data-target-cell="annotated-cell-3" data-target-annotation="1">1</dt>
<dd>
<span data-code-cell="annotated-cell-3" data-code-lines="2" data-code-annotation="1">Use updates from <code>stable</code> Git reference (branch, tag, or commit)</span>
</dd>
<dt data-target-cell="annotated-cell-3" data-target-annotation="2">2</dt>
<dd>
<span data-code-cell="annotated-cell-3" data-code-lines="3" data-code-annotation="2">Use custom name</span>
</dd>
<dt data-target-cell="annotated-cell-3" data-target-annotation="3">3</dt>
<dd>
<span data-code-cell="annotated-cell-3" data-code-lines="4" data-code-annotation="3">Table and string specifications can be mixed</span>
</dd>
</dl>
<p>To follow semver-like named tags, use <a href="https://neovim.io/doc/user/helptag.html?tag=vim.version.range()"><code>:h vim.version.range()</code></a> as <code>version</code>:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="annotated-cell-4" style="background: #f1f3f5;"><pre class="sourceCode lua code-annotation-code code-with-copy code-annotated"><code class="sourceCode lua"><span id="annotated-cell-4-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span></span>
<span id="annotated-cell-4-2">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="annotated-cell-4-3">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">src</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.nvim'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-4" data-target-annotation="1" onclick="event.preventDefault();">1</a><span id="annotated-cell-4-4" class="code-annotation-target">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">version</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">version</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>range<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'*'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="annotated-cell-4-5">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<span id="annotated-cell-4-6">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="annotated-cell-4-7">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">src</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/neovim/nvim-lspconfig'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-4" data-target-annotation="2" onclick="event.preventDefault();">2</a><span id="annotated-cell-4-8" class="code-annotation-target">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">version</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">version</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>range<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'2.x'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="annotated-cell-4-9">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<span id="annotated-cell-4-10"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code></pre></div></div>
<dl class="code-annotation-container-grid">
<dt data-target-cell="annotated-cell-4" data-target-annotation="1">1</dt>
<dd>
<span data-code-cell="annotated-cell-4" data-code-lines="4" data-code-annotation="1">Always try installing latest semver tag</span>
</dd>
<dt data-target-cell="annotated-cell-4" data-target-annotation="2">2</dt>
<dd>
<span data-code-cell="annotated-cell-4" data-code-lines="8" data-code-annotation="2">Install latest semver tag if it is &gt;=2.0.0 and &lt;3.0.0</span>
</dd>
</dl>
<p>Use <code>data</code> field to store/pass extra information or plugin specific methods:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="annotated-cell-5" style="background: #f1f3f5;"><pre class="sourceCode lua code-annotation-code code-with-copy code-annotated"><code class="sourceCode lua"><span id="annotated-cell-5-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">selective_load</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">plug_data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-5" data-target-annotation="1" onclick="event.preventDefault();">1</a><span id="annotated-cell-5-2" class="code-annotation-target">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">plug_data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">spec</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">or</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}).</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">skip_load</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="annotated-cell-5-3">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cmd</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>packadd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">plug_data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">spec</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="annotated-cell-5-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="annotated-cell-5-5"></span>
<span id="annotated-cell-5-6"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span></span>
<span id="annotated-cell-5-7">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.nvim'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="annotated-cell-5-8">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">src</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/neovim/nvim-lspconfig'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">skip_load</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<span id="annotated-cell-5-9"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">load</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">selective_load</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code></pre></div></div>
<dl class="code-annotation-container-grid">
<dt data-target-cell="annotated-cell-5" data-target-annotation="1">1</dt>
<dd>
<span data-code-cell="annotated-cell-5" data-code-lines="2" data-code-annotation="1">Do not load if explicitly asked</span>
</dd>
</dl>
</section>
<section id="lockfile" class="level3">
<h3 class="anchored" data-anchor-id="lockfile">Lockfile</h3>
<p>On top of listing used plugins in a config (to control how they are loaded), <code>vim.pack</code> stores extra information in <a href="https://neovim.io/doc/user/helptag.html?tag=vim.pack-lockfile">its lockfile</a>: <code>nvim-pack-lock.json</code> in user’s config directory. It contains JSON encoded information about the current state of all plugins managed by <code>vim.pack</code>. It is meant to be treated like a part of the config (like tracked via version control, for example) but should <strong>not be modified by hand</strong>.</p>
<p>The lockfile serves several purposes:</p>
<ul>
<li><p>It is used as a “latest working state” reference when bootstrapping the config on the new machine. In this case during <strong>the very first <code>vim.pack.add()</code> call</strong> all plugins that are present in the lockfile but absent on disk are installed all at once.</p></li>
<li><p>As a consequence of the previous point, it makes it possible to ensure that even lazy loaded plugins are installed right away at the expected state and not when their first <code>vim.pack.add</code>ed.</p></li>
<li><p>It enables easier “revert the latest update” workflow by reverting the lockfile and updating to the lockfile’s state.</p></li>
<li><p>It contains information about plugin’s <code>version</code>, i.e.&nbsp;target state when updating. This is useful when updating if there are not-yet-active plugins (since there is no <code>vim.pack.add()</code> call yet to say which <code>version</code> it follows).</p></li>
<li><p>In future it will allow to store more information about plugins to perform more actions without much startup overhead. Like provide information about minimum expected Neovim version (per plugin) or plugin dependencies (to at least ensure that they are already loaded).</p></li>
</ul>
<p>If something is done to plugins not via <code>vim.pack</code> methods, lockfile can become out of sync with what is present on disk. Following troubleshooting steps should usually help.</p>
</section>
<section id="hooks" class="level3">
<h3 class="anchored" data-anchor-id="hooks">Hooks</h3>
<p>A common requirement for managing plugins is to be able to perform dedicated actions (usually called “plugin hooks”) whenever plugin’s state changes. Like “build/compile the plugin”, “update parsers installed by this plugin”, “perform initial registration”.</p>
<p>The suggested interface for that is by creating <a href="https://neovim.io/doc/user/helptag.html?tag=autocommand">autocommand(s)</a> for <a href="https://neovim.io/doc/user/helptag.html?tag=vim.pack-events">dedicated <code>vim.pack</code> events</a>: <code>PackChangedPre</code> (before the change) and <code>PackChanged</code> (after the change). These events are triggered whenever plugins are affected via <code>vim.pack</code> functions.</p>
<p>Autocommands for these events will receive information about affected plugin via <a href="https://neovim.io/doc/user/helptag.html?tag=event-data">event data</a>. It will contain at least plugin’s name and specification, whether it is active, and what kind of change it is. There are three major kinds of changes:</p>
<ul>
<li><code>kind=install</code> - initial plugin install, before loading.</li>
<li><code>kind=update</code> - update already installed plugin, possibly not loaded.</li>
<li><code>kind=delete</code> - delete from disk.</li>
</ul>
<hr>
<p>Here is an example of updating tree-sitter parsers whenever plugin named ‘nvim-treesitter’ is updated:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="annotated-cell-6" style="background: #f1f3f5;"><pre class="sourceCode lua code-annotation-code code-with-copy code-annotated"><code class="sourceCode lua"><span id="annotated-cell-6-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_create_autocmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PackChanged'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">callback</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="annotated-cell-6-2">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">kind</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">spec</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">kind</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-6" data-target-annotation="1" onclick="event.preventDefault();">1</a><span id="annotated-cell-6-3" class="code-annotation-target">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nvim-treesitter'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">kind</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'update'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-6" data-target-annotation="2" onclick="event.preventDefault();">2</a><span id="annotated-cell-6-4" class="code-annotation-target">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">active</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cmd</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>packadd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nvim-treesitter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="annotated-cell-6-5">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>cmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TSUpdate'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="annotated-cell-6-6">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="annotated-cell-6-7"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code></pre></div></div>
<dl class="code-annotation-container-grid">
<dt data-target-cell="annotated-cell-6" data-target-annotation="1">1</dt>
<dd>
<span data-code-cell="annotated-cell-6" data-code-lines="3" data-code-annotation="1">Update tree-sitter parsers whenever ‘nvim-treesitter’ updates</span>
</dd>
<dt data-target-cell="annotated-cell-6" data-target-annotation="2">2</dt>
<dd>
<span data-code-cell="annotated-cell-6" data-code-lines="4" data-code-annotation="2">Make sure that ‘nvim-treesitter’ is loaded to use <code>:TSUpdate</code></span>
</dd>
</dl>
<hr>
<p>The long-term plan is to move defining common hooks (like “after install” and “after update”) from user’s responsibility to plugin’s. One approach is to use some sort of standardized file in plugin root that tells plugin manager what scripts to execute on certain events. This is commonly mentioned as <a href="https://github.com/neovim/packspec/">“add <code>packspec</code> support”</a>. This should remove the need for custom hooks for most users.</p>
<hr>
<div id="hooks-install" class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>One important caveat worth mentioning is about plugin install hooks. For them to work, their autocommand has to be created <strong>before the <code>vim.pack.add()</code> call that does the installation</strong>. Otherwise Neovim can’t know about that hook (at least before there is a <code>packspec</code> support).</p>
<p>Depending on the level of robustness you want to achieve for your config, there are several degrees of handling this:</p>
<ul>
<li><p>Create an autocommand before <code>vim.pack.add()</code> that lists the plugin. This will run the hook when the plugin is installed for the very first time.</p></li>
<li><p>(Recommended) Create an autocommand before <strong>the very first <code>vim.pack.add()</code></strong>. This will run the hook even when installing the plugin based on the lockfile.</p></li>
<li><p>If the hook <em>absolutely needs</em> to have plugin’s <code>data</code> (like if it contains project build instructions), the plugin should be listed in the very first <code>vim.pack.add()</code>. If this plugin is intended to be lazy loaded, register it without loading and use <code>vim.cmd.packadd</code> when later loading.</p></li>
</ul>
</div>
</div>
</section>
</section>
<section id="config-organization" class="level2">
<h2 class="anchored" data-anchor-id="config-organization">Config organization</h2>
<section id="single-vim-pack-add" class="level3">
<h3 class="anchored" data-anchor-id="single-vim-pack-add">Single <code>vim.pack.add()</code></h3>
<p>This is the most robust approach around which <code>vim.pack</code> was designed. Have a single <code>vim.pack.add()</code> that installs+loads plugins and (if needed) create one autocommand for hooks prior to it. Also works well when “bootstrapping” config on new machine (since it automatically resolves possible installation hooks problems).</p>
<p>Here is an example:</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>init.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="annotated-cell-7" data-filename="init.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-annotation-code code-with-copy code-annotated"><code class="sourceCode lua"><a class="code-annotation-anchor" data-target-cell="annotated-cell-7" data-target-annotation="1" onclick="event.preventDefault();">1</a><span id="annotated-cell-7-1" class="code-annotation-target"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_create_autocmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PackChanged'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">callback</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="annotated-cell-7-2">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">kind</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">spec</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">kind</span></span>
<span id="annotated-cell-7-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nvim-treesitter'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">kind</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'update'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="annotated-cell-7-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">active</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cmd</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>packadd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nvim-treesitter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="annotated-cell-7-5">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>cmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TSUpdate'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="annotated-cell-7-6">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="annotated-cell-7-7"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="annotated-cell-7-8"></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-7" data-target-annotation="2" onclick="event.preventDefault();">2</a><span id="annotated-cell-7-9" class="code-annotation-target"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span></span>
<span id="annotated-cell-7-10">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.nvim'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="annotated-cell-7-11">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/neovim/nvim-lspconfig'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="annotated-cell-7-12">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-treesitter/nvim-treesitter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="annotated-cell-7-13"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="annotated-cell-7-14"></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-7" data-target-annotation="3" onclick="event.preventDefault();">3</a><span id="annotated-cell-7-15" class="code-annotation-target"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cmd</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>colorscheme<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'miniwinter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="annotated-cell-7-16"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.basics'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="annotated-cell-7-17"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.surround'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="annotated-cell-7-18"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lsp</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>enable<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lua_ls'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code></pre></div></div>
</div>
<dl class="code-annotation-container-grid">
<dt data-target-cell="annotated-cell-7" data-target-annotation="1">1</dt>
<dd>
<span data-code-cell="annotated-cell-7" data-code-lines="1" data-code-annotation="1">Define hooks via autocommand(s)</span>
</dd>
<dt data-target-cell="annotated-cell-7" data-target-annotation="2">2</dt>
<dd>
<span data-code-cell="annotated-cell-7" data-code-lines="9" data-code-annotation="2">Add (maybe install and load) all at once</span>
</dd>
<dt data-target-cell="annotated-cell-7" data-target-annotation="3">3</dt>
<dd>
<span data-code-cell="annotated-cell-7" data-code-lines="15" data-code-annotation="3">Use plugins immediately</span>
</dd>
</dl>
<p>It should be enough for most users. The two most common downsides expressed about this approach are:</p>
<ul>
<li><p>It is not “modular” enough as many people prefer spreading plugin configuration across multiple files. The usual answer is to use many <code>vim.pack.add()</code> calls.</p></li>
<li><p>It loads all plugins immediately during startup which can visibly affect startup time. It also increases ‘runtimepath’ (which can have <a href="../blog/2026-01-27-how-many-neovim-plugins-is-too-many.html">slightly negative impact</a>). The answer is to use lazy loading, but <strong>please</strong> only to a moderate extent. Extreme lazy loading usually comes with a hidden cognitive overhead both when using and maintaining the config.</p></li>
</ul>
</section>
<section id="many-vim-pack-add" class="level3">
<h3 class="anchored" data-anchor-id="many-vim-pack-add">Many <code>vim.pack.add()</code></h3>
<p>Usually very similar to a “single <code>vim.pack.add()</code>” approach but with many <code>vim.pack.add</code> calls spread across single or multiple files.</p>
<p>One way to do it is to add files inside <code>plugin/</code> directory of the config. This way they will be discovered and executed (in alphabetical order) automatically during startup.</p>
<p>Here is an example:</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>plugin/mini.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" data-filename="plugin/mini.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb3-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.nvim'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb3-2"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cmd</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>colorscheme<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'miniwinter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb3-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.basics'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb3-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.surround'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span></code></pre></div></div>
</div>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>plugin/nvim-lspconfig.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" data-filename="plugin/nvim-lspconfig.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb4-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/neovim/nvim-lspconfig'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb4-2"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lsp</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>enable<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lua_ls'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span></code></pre></div></div>
</div>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>plugin/nvim-treesitter.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" data-filename="plugin/nvim-treesitter.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb5-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_create_autocmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PackChanged'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">callback</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb5-2">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">kind</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">spec</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">kind</span></span>
<span id="cb5-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nvim-treesitter'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">kind</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'update'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb5-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">active</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cmd</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>packadd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nvim-treesitter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb5-5">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>cmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TSUpdate'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb5-6">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb5-7"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb5-8"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-treesitter/nvim-treesitter'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span></code></pre></div></div>
</div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>In general it should be fine to use <code>vim.pack.add</code> for the same plugin several times in different places. This can come up when some plugin is used as a dependency for several other plugins. The first call will load the plugin while all the next ones will be ignored (<code>vim.pack.add()</code> will do nothing for active plugin).</p>
<p>However, for clearer config I would suggest to have only a single <code>vim.pack.add</code> per plugin. Just make sure that it is executed before plugins that depend on it. In case of a <code>plugin/</code> directory, automated sourcing is alphabetical, so adjusting the file name should work here.</p>
</div>
</div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>The current single fragility of this approach occurs when “bootstrapping” from the lockfile a plugin that requires an action during install. See dedicated note about possible solutions.</p>
<p>In this particular example a solution could be to create all installation hooks in ‘init.lua’ file:</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>init.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" data-filename="init.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb6-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_create_autocmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PackChanged'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">callback</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb6-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Various installation hooks</span></span>
<span id="cb6-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="lazy-loading" class="level3">
<h3 class="anchored" data-anchor-id="lazy-loading">Lazy loading</h3>
<p>One of the ways for users to improve startup and runtime performance, is to delay loading a plugin, a.k.a. “lazy load” it. Ideally, there should not be a need for that to improve startup time: a plugin should do negligible amount of work when setting itself up. However, different people perceive time differently and use different machines, so it still is something that should be possible.</p>
<p>Functionally, there are two types of plugin lazy loading:</p>
<ul>
<li><p>“Load not during startup” - improves startup time until first draw at the cost of still loading all plugins (might slightly affect runtime performance). It is an approach that is easy to understand and maintain, though.</p></li>
<li><p>“Load just before it is needed” - improves overall performance at the cost of a more complex config.</p></li>
</ul>
<p>Please be careful when deciding which plugins to lazy load. Some functionality needs to be available during startup before first redraw: colorscheme, statusline/tabline, starter dashboard, etc.</p>
<hr>
<p>The <code>vim.pack</code> is designed with lazy loading in mind, but definitely not as a front and center use case. Use it moderately.</p>
<p>The basic idea is to call <code>vim.pack.add()</code> not during startup but register it to be called whenever you want to load the plugin.</p>
<p>The “load not during startup” approach can be done via <a href="https://neovim.io/doc/user/helptag.html?tag=vim.schedule()"><code>vim.schedule()</code></a>:</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>init.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="annotated-cell-11" data-filename="init.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-annotation-code code-with-copy code-annotated"><code class="sourceCode lua"><span id="annotated-cell-11-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>schedule<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="annotated-cell-11-2">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-11" data-target-annotation="1" onclick="event.preventDefault();">1</a><span id="annotated-cell-11-3" class="code-annotation-target">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.cmdline'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="annotated-cell-11-4">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.completion'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="annotated-cell-11-5">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="annotated-cell-11-6"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code></pre></div></div>
</div>
<dl class="code-annotation-container-grid">
<dt data-target-cell="annotated-cell-11" data-target-annotation="1">1</dt>
<dd>
<span data-code-cell="annotated-cell-11" data-code-lines="3" data-code-annotation="1">Use standalone ‘mini.nvim’ repos for <code>vim.pack.add()</code> demonstration purposes</span>
</dd>
</dl>
<p>The “load just before it is needed” approach can become complex if taken at face value. My personal suggestion is to only use basic autocommands and not rely on any complex logic (like “load on mapping”, etc.).</p>
<p>Here is an example:</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>init.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="annotated-cell-12" data-filename="init.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-annotation-code code-with-copy code-annotated"><code class="sourceCode lua"><a class="code-annotation-anchor" data-target-cell="annotated-cell-12" data-target-annotation="1" onclick="event.preventDefault();">1</a><span id="annotated-cell-12-1" class="code-annotation-target"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_create_autocmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'CmdlineEnter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">once</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">callback</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="annotated-cell-12-2">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.cmdline'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-12" data-target-annotation="2" onclick="event.preventDefault();">2</a><span id="annotated-cell-12-3" class="code-annotation-target">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.cmdline'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="annotated-cell-12-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="annotated-cell-12-5"></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-12" data-target-annotation="3" onclick="event.preventDefault();">3</a><span id="annotated-cell-12-6" class="code-annotation-target"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_create_autocmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'InsertEnter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">once</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">callback</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="annotated-cell-12-7">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.completion'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="annotated-cell-12-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.completion'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="annotated-cell-12-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code></pre></div></div>
</div>
<dl class="code-annotation-container-grid">
<dt data-target-cell="annotated-cell-12" data-target-annotation="1">1</dt>
<dd>
<span data-code-cell="annotated-cell-12" data-code-lines="1" data-code-annotation="1">Load once when entering Command-line mode</span>
</dd>
<dt data-target-cell="annotated-cell-12" data-target-annotation="2">2</dt>
<dd>
<span data-code-cell="annotated-cell-12" data-code-lines="3" data-code-annotation="2">Explicitly set up ‘mini.nvim’ module</span>
</dd>
<dt data-target-cell="annotated-cell-12" data-target-annotation="3">3</dt>
<dd>
<span data-code-cell="annotated-cell-12" data-code-lines="6" data-code-annotation="3">Load once when entering Insert mode</span>
</dd>
</dl>
<p>Both of these approaches can be unified and improved by using a dedicated <a href="https://nvim-mini.org/mini.nvim/doc/mini-misc.html#minimisc.safely"><code>safely()</code></a> wrapper from ‘mini.misc’ module of ‘mini.nvim’. With this, the config is more robust (errors will be reported as warnings to not block code execution and load all plugins) and unified:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="annotated-cell-13" style="background: #f1f3f5;"><pre class="sourceCode lua code-annotation-code code-with-copy code-annotated"><code class="sourceCode lua"><a class="code-annotation-anchor" data-target-cell="annotated-cell-13" data-target-annotation="1" onclick="event.preventDefault();">1</a><span id="annotated-cell-13-1" class="code-annotation-target"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.misc'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="annotated-cell-13-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">misc</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.misc'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="annotated-cell-13-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">later</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">f</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">misc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>safely<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'later'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">f</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="annotated-cell-13-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">on_event</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">f</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">misc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>safely<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'event:'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">f</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="annotated-cell-13-5"></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-13" data-target-annotation="2" onclick="event.preventDefault();">2</a><span id="annotated-cell-13-6" class="code-annotation-target">later<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="annotated-cell-13-7">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.cmdline'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-13" data-target-annotation="3" onclick="event.preventDefault();">3</a><span id="annotated-cell-13-8" class="code-annotation-target">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.cmdline'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="annotated-cell-13-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="annotated-cell-13-10"></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-13" data-target-annotation="4" onclick="event.preventDefault();">4</a><span id="annotated-cell-13-11" class="code-annotation-target">on_event<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'InsertEnter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="annotated-cell-13-12">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.completion'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="annotated-cell-13-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.completion'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="annotated-cell-13-14"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code></pre></div></div>
<dl class="code-annotation-container-grid">
<dt data-target-cell="annotated-cell-13" data-target-annotation="1">1</dt>
<dd>
<span data-code-cell="annotated-cell-13" data-code-lines="1" data-code-annotation="1">Use standalone ‘mini.nvim’ repos for <code>vim.pack.add()</code> demonstration purposes</span>
</dd>
<dt data-target-cell="annotated-cell-13" data-target-annotation="2">2</dt>
<dd>
<span data-code-cell="annotated-cell-13" data-code-lines="6" data-code-annotation="2">Load some time later after startup</span>
</dd>
<dt data-target-cell="annotated-cell-13" data-target-annotation="3">3</dt>
<dd>
<span data-code-cell="annotated-cell-13" data-code-lines="8" data-code-annotation="3">Explicitly set up ‘mini.nvim’ module</span>
</dd>
<dt data-target-cell="annotated-cell-13" data-target-annotation="4">4</dt>
<dd>
<span data-code-cell="annotated-cell-13" data-code-lines="11" data-code-annotation="4">Load when entering Insert mode</span>
</dd>
</dl>
<hr>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<ul>
<li><p>When adding a new lazy loaded plugin, make sure it is installed. Either trigger its loading in a new session or manually run <code>vim.pack.add()</code> with its source.</p></li>
<li><p>This also has the same “install hooks” fragility as the <a href="many-vim-pack-add">many <code>vim.pack.add()</code></a> approach with the same solutions.</p></li>
</ul>
</div>
</div>
</section>
</section>
<section id="update" class="level2">
<h2 class="anchored" data-anchor-id="update">Update</h2>
<p>Updating already installed plugins is done via <a href="https://neovim.io/doc/user/helptag.html?tag=vim.pack.update()"><code>vim.pack.update()</code></a>. There is no dedicated user command <a href="https://github.com/neovim/neovim/issues/34764">yet</a>.</p>
<p>Executing <code>:lua vim.pack.update()</code> (without arguments) will update all plugins and <code>:lua vim.pack.update({ 'mini.nvim' })</code> will update selected installed plugins specified by their name. It means:</p>
<ul>
<li>Download new changes from plugin sources.</li>
<li>Compute new target revision and all the changes (<code>git log</code>) between current and target revisions.</li>
<li>By default show a new tabpage with information about the update. This is known as a confirmation buffer. To skip the confirmation step, apply all pending updates immediately by setting <code>force = true</code> option of <code>vim.pack.update()</code>.</li>
</ul>
<p>Every update that was actually done is recorded in a dedicated <code>nvim-pack.log</code> file inside “log” <a href="https://neovim.io/doc/user/helptag.html?tag=standard-path">standard path</a>.</p>
<hr>
<p>The goal of the confirmation buffer is to show update details for the user to read, confirm (execute <code>:write</code> for that) or deny (close the window for that, like with <code>:quit</code>) the update. Here is an example of how it looks:</p>
<p><img src="https://echasnovski.com/blog/2026-03-13-a-guide-to-vim-pack/demo-confirmation-buffer.png" class="img-fluid"></p>
<p>There are several buffer-local nice things to improve user experience:</p>
<ul>
<li><p>The <code>]]</code> and <code>[[</code> mappings navigate through plugin sections forwards and backwards.</p></li>
<li><p>There is a so-called “in-process” (i.e.&nbsp;created in Neovim session with Neovim’s Lua code) LSP server enabled specifically in confirmation buffer. It provides several features in an LSP compatible way. This means that they will work both with <a href="https://neovim.io/doc/user/helptag.html?tag=lsp-defaults">default LSP mappings</a> and with any custom mappings.</p>
<p>The supported LSP methods are:</p>
<ul>
<li><p><a href="https://neovim.io/doc/user/helptag.html?tag=vim.lsp.buf.document_symbol()">‘textDocument/documentSymbol’</a> to show structure of the buffer. By default opens a location list, but will work with, for example, any picker providing LSP document symbols picker.</p></li>
<li><p><a href="https://neovim.io/doc/user/helptag.html?tag=vim.lsp.buf.hover()">‘textDocument/hover’</a> - show more information at cursor, like details of a particular pending change or newer tag. By default opens a floating window showing the change; execute the hover action again to jump into the window or move cursor for the window to disappear.</p></li>
<li><p><a href="https://neovim.io/doc/user/helptag.html?tag=vim.lsp.buf.code_action()">‘textDocument/codeAction’</a> - show code actions relevant for a “plugin at cursor”. Like “delete” (if plugin is not active; useful if you only removed plugin from config but did not delete it), “update” or “skip updating” (if there are pending updates).</p></li>
</ul></li>
</ul>
<hr>
<p>Other common ways to use <code>vim.pack.update()</code>:</p>
<ul>
<li><p><code>:lua vim.pack.update(nil, { force = true })</code> - force updates immediately without confirmation buffer. Useful when scripting.</p></li>
<li><p><code>:lua vim.pack.update(nil, { offline = true })</code> - show the current state of plugins without downloading new changes from sources. Useful to interactively explore installed plugins.</p></li>
<li><p><code>:lua vim.pack.update(nil, { target = 'lockfile' })</code> - make sure that plugin state on disk is the same as recorded in the lockfile. Useful for reverting updates: ensure the lockfile is as it was before the update and execute the command.</p></li>
</ul>
</section>
<section id="delete" class="level2">
<h2 class="anchored" data-anchor-id="delete">Delete</h2>
<p>Deleting a plugin is a relatively straightforward two step process:</p>
<ul>
<li><p>Remove from the config any logic for loading the plugin. Otherwise it will be reinstalled on the next startup.</p></li>
<li><p>Use <a href="https://neovim.io/doc/user/helptag.html?tag=vim.pack.del()"><code>vim.pack.del()</code></a> to delete plugin(s) from disk. This will also remove the plugin from the lockfile. Here is an example: <code>:lua vim.pack.del({ 'nvim-lspconfig', 'nvim-treesitter' })</code>.</p>
<p><strong>Do not delete directory with plugin code by hand</strong>. This will not adjust lockfile, which means the plugin will be reinstalled on the next startup.</p></li>
</ul>
</section>
<section id="troubleshoot" class="level2">
<h2 class="anchored" data-anchor-id="troubleshoot">Troubleshoot</h2>
<p>To err is human. When you feel there might be problems with <code>vim.pack</code>, run <a href="https://neovim.io/doc/user/helptag.html?tag=:checkhealth"><code>:checkhealth</code></a> for it. Like this: <code>:checkhealth vim.pack</code>.</p>
<p>It should report any known/common issues together with best-effort suggestions on how to fix it. For example it will:</p>
<ul>
<li><p>Detect missing or problematic lockfile entry.</p></li>
<li><p>Whether lockfile is not aligned with what is on the disk.</p></li>
<li><p>Notify if there are not active (installed but not loaded) plugins. Which might be a sign that it was removed from the config but not fully deleted.</p></li>
</ul>
</section>
<section id="migrate" class="level2">
<h2 class="anchored" data-anchor-id="migrate">Migrate</h2>
<p>There is a chance that you already use a plugin manager, in which case in order to use <code>vim.pack</code> you’d have to migrate from the previous one. And my personal suggestion would be to do it. It usually results in a simple and more “native” config than alternatives while still being enough to comfortably daily drive. It is also built-in, which means that it 1) has dedicated and knowledgeable people maintaining it; and 2) has basically the same stability guarantees as the Neovim core itself. The downside might be a slower release cycle than a regular plugin, so you’d have to wait longer for possible fixes and new features (or use Nightly releases).</p>
<p>Depending on the config complexity and the number of used plugins, it might be a tedious task. But in a nutshell:</p>
<ol type="1">
<li><p>Update the config to use <code>vim.pack</code> instead of the previous plugin manager. Make sure that there is no use of the previous plugin manager whatsoever (otherwise it will become confusing to locate problems).</p></li>
<li><p>Make sure that plugins and accompanying files from the previous plugin manager are not on disk. This might be crucial to not have the same plugin installed in different places.</p>
<p>For this, find the location of where the plugin manager installed plugins and delete the directory manually.</p></li>
</ol>
<p>Here are a couple of approaches that could make the transition easier:</p>
<ul>
<li><p>Instead of changing the “main” config, adjust a temporary one (see <a href="https://neovim.io/doc/user/helptag.html?tag=$NVIM_APPNAME"><code>:h $NVIM_APPNAME</code></a>) at your own pace without the pressure of not having the fully working setup. You can start either with a full copy of the “main” config or start fresh.</p>
<p>For example, create <code>~/.config/nvim-vim-pack</code> directory. Either empty to start fresh or by copying <code>~/.config/nvim</code>. Adjusting <code>nvim-vim-pack</code> config will have no impact on the “main” <code>nvim</code> config. Use <code>NVIM_APPNAME=nvim-vim-pack nvim</code> to start Neovim with the <code>nvim-vim-pack</code> config. When you feel ready, move the content back to <code>~/.config/nvim</code> (it will reinstall <code>vim.pack</code> plugins into a permanent <a href="https://neovim.io/doc/user/helptag.html?tag=standard-path">“data” standard path</a>).</p></li>
<li><p>Start with a simple one <code>vim.pack.add()</code> style of config and see if it fits your needs. It might be surprising and refreshing to trade the startup speed for config simplicity.</p>
<p>If it doesn’t feel right, you can start modularizing the config. And only if absolutely needed, try lazy loading some plugins.</p></li>
</ul>
<section id="mini.deps" class="level3">
<h3 class="anchored" data-anchor-id="mini.deps">mini.deps</h3>
<p>The <a href="https://nvim-mini.org/mini.nvim/readmes/mini-deps.html">‘mini.deps’</a> was initially designed with the idea of being merged as Neovim’s built-in plugin manager. The overall concept proved to be rather successful and after about 1.5 years of public testing it was used as a basis for <code>vim.pack</code>.</p>
<p>In many ways, <code>vim.pack</code> is a better and slicker version of ‘mini.deps’ which is why it will eventually be recommended instead of ‘mini.deps’. So the migration should be rather painless. But here are a couple of pointers:</p>
<ul>
<li><p>Instead of <code>MiniDeps.add('user/repo')</code> use <code>vim.pack.add({ 'https://github.com/user/repo' })</code>, i.e.&nbsp;use full URL and a list instead of a single string.</p></li>
<li><p>In table specification: <code>source</code> -&gt; <code>src</code>, <code>checkout</code> -&gt; <code>version</code>.</p></li>
<li><p>Resolve dependencies manually by listing them in <code>vim.pack.add()</code> list before target plugin. It shouldn’t be a problem to <code>vim.pack.add()</code> the same plugin several times, but it is better to resolve to the point of every plugin being added exactly once.</p></li>
<li><p>Rewrite hooks to be in autocommand form.</p></li>
<li><p>Instead of <code>MiniDeps.now()</code> and <code>MiniDeps.later()</code>, use <a href="https://nvim-mini.org/mini.nvim/doc/mini-misc.html#minimisc.safely"><code>MiniMisc.safely()</code></a>.</p></li>
<li><p><strong>Do not forget</strong> to remove plugins (located in <code>site/pack/deps</code> subdirectory of <a href="https://neovim.io/doc/user/helptag.html?tag=standard-path">“data” standard path</a>) and possible <code>mini-deps-snap</code> snapshot file. Otherwise there will be conflicts (since ‘mini.deps’ also uses plugin package approach).</p></li>
</ul>
<p>You can see an example of a real config migration <a href="https://nvim-mini.org/MiniMax/configs/diffs/nvim-0.11_nvim-0.12/">in MiniMax</a>: the main theme of moving from <code>nvim-0.11</code> to <code>nvim-0.12</code> reference config is changing a plugin manager from ‘mini.deps’ to <code>vim.pack</code>.</p>
<p>Here is a simpler example:</p>
<ul>
<li><p>‘mini.deps’ config (excluding the part of bootstrapping ‘mini.nvim’ or ‘mini.deps’):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb7-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">MiniDeps</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nvim-mini/mini.nvim'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb7-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.basics'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb7-3"></span>
<span id="cb7-4"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">MiniDeps</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span></span>
<span id="cb7-5">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">source</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nvim-treesitter/nvim-treesitter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb7-6">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">checkout</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'main'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb7-7">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">hooks</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">post_checkout</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>cmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TSUpdate'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb7-8"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span></code></pre></div></div></li>
<li><p>The translated <code>vim.pack</code> config:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb8-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.nvim'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb8-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.basics'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb8-3"></span>
<span id="cb8-4"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_create_autocmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PackChanged'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">callback</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb8-5">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">kind</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">spec</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">kind</span></span>
<span id="cb8-6">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nvim-treesitter'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">and</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">kind</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'update'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb8-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ev</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">data</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">active</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cmd</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>packadd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nvim-treesitter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb8-8">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>cmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TSUpdate'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb8-9">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb8-10"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb8-11"></span>
<span id="cb8-12"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span></span>
<span id="cb8-13">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb8-14">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">src</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-treesitter/nvim-treesitter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb8-15">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">version</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'main'</span></span>
<span id="cb8-16">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb8-17"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span></code></pre></div></div></li>
</ul>
</section>
<section id="lazy.nvim" class="level3">
<h3 class="anchored" data-anchor-id="lazy.nvim">lazy.nvim</h3>
<p>The <a href="https://lazy.folke.io/">folke/lazy.nvim</a> is the most used plugin manager at the time of this writing. And rightly so: it is very capable with lots of features. Ironically, this itself makes it not very suitable to be a part of Neovim as most of the features come with significant code and maintenance complexity. Plus the whole idea of treating lazy loading as the main goal of a plugin manager does not sit well with Neovim core team.</p>
<p>By design, not all ‘lazy.nvim’ capabilities are one-to-one reproducible in <code>vim.pack</code>. My best suggestion would be to follow both approaches suggested earlier: use temporary config and start with simple approach first to see that maybe there is nothing much to miss from ‘lazy.nvim’.</p>
<p>Couple of pointers:</p>
<ul>
<li><p>Use full URL as a source (as string or <code>src</code> field) and a single <code>version</code> instead of <code>branch</code> / <code>tag</code> / <code>commit</code> / <code>version</code> / <code>pin</code> fields.</p></li>
<li><p>Instead of the <code>opts</code> field use a dedicated way to configure a plugin (should be mentioned in plugin’s documentation/README) after <code>vim.pack.add</code>ing it. Typically it is something like <code>require('plugin').setup(opts)</code>, which ‘lazy.nvim’ does behind the scenes (but not <code>vim.pack.add()</code>).</p></li>
<li><p>There is no built-in lazy loading with <code>vim.pack</code>, so specification fields like <code>cmd</code>, <code>event</code>, <code>ft</code>, <code>keys</code> can not be translated directly. For emulating loading on event see “Lazy loading” section.</p></li>
<li><p>The directory where ‘lazy.nvim’ stores its plugins is <code>lazy</code> subdirectory of <a href="https://neovim.io/doc/user/helptag.html?tag=standard-path">“data” standard path</a>. Delete it manually before migrating.</p></li>
<li><p>If you use <a href="https://www.lazyvim.org/">LazyVim</a>, then it is probably a better idea to start from a clean config and build from there. As LazyVim is heavily based on using ‘lazy.nvim’ as its plugin manager.</p></li>
</ul>
<hr>
<p>As for a startup speed, when comparing simple configs of <code>vim.pack</code> and ‘lazy.nvim’, the latter will most certainly have faster results. Primarily because it is built around the concept of “lazy load and fast custom load whenever you can”. <em>How much</em> faster - depends on the number of plugins.</p>
<p>However, there are ways of making config with <code>vim.pack</code> have faster startup:</p>
<ul>
<li><p>The most speedup usually comes from lazy loading, at the cost of extra a more complex config. Choosing the right balance between the two is up to you.</p></li>
<li><p>For not lazy loaded parts, not trivial amount of improvement can come from adding <a href="https://neovim.io/doc/user/helptag.html?tag=vim.loader.enable()"><code>vim.loader.enable()</code></a> call as the <em>first line in ‘init.lua’</em>. It implements some dark “fast load” magic <a href="https://github.com/neovim/neovim/pull/22668">that was blessed by Folke himself</a>. After a few restarts it usually improves startup, especially if there are a lot of <code>require()</code> calls.</p>
<p>How big the result will be is hard to tell, as it depends on variety of things. In real world configs without much lazy loading just this one line can speed up as high as ~30% (I’ve seen examples of 137ms-&gt;99ms and 430ms-&gt;315ms improvement), maybe more.</p></li>
</ul>
<p>From experience, implementing both of these approaches can result in a startup at least on par with ‘lazy.nvim’, if not better. My personal choice of startup optimization is to use only a handful of plugins (less things to load) together with a very simple lazy loading (<a href="https://nvim-mini.org/MiniMax/configs/nvim-0.12/">MiniMax style</a>); no <code>vim.loader.enable()</code> (as startup time is small enough: ~38ms compared to ~34ms with it).</p>
<hr>
<p>The most recommended way of setting up ‘lazy.nvim’ plugins seems to be a so called <a href="https://lazy.folke.io/usage/structuring">“structuring plugins”</a> approach. Beware that those <code>lua/plugins/</code> plugin files are discovered and sourced by ‘lazy.nvim’ automatically. Just translating each file to use <code>vim.pack.add()</code> will not be enough, make sure to source those files during startup. One approach that I can recommend is to move them from <code>lua/plugins/</code> to <code>plugin/</code> directory (notice the singular case). The <code>plugin/</code> runtime files are sourced automatically during startup by Neovim itself.</p>
<p>Here is an example:</p>
<ul>
<li><p>‘lazy.nvim’ “structured” config:</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>init.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" data-filename="init.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb9-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Bootstrap lazy.nvim</span></span>
<span id="cb9-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lazypath</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fn</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>stdpath<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"/lazy/lazy.nvim"</span></span>
<span id="cb9-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- ...</span></span>
<span id="cb9-4"></span>
<span id="cb9-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Setup lazy.nvim</span></span>
<span id="cb9-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lazy"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span></span>
<span id="cb9-7">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">spec</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb9-8">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">import</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"plugins"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb9-9">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb9-10"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span></code></pre></div></div>
</div>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>lua/plugins/mini-hues.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" data-filename="lua/plugins/mini-hues.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb10-1"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb10-2">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nvim-mini/mini.hues'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb10-3">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lazy</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">false</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb10-4">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">priority</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb10-5">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">config</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb10-6">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cmd</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>colorscheme<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'miniwinter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb10-7">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb10-8"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
</div>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>lua/plugins/mini-completion.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb11" data-filename="lua/plugins/mini-completion.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb11-1"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb11-2">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nvim-mini/mini.completion'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb11-3">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">event</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'InsertEnter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb11-4">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">dependencies</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nvim-mini/mini.snippets'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb11-5">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">config</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb11-6">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.snippets'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb11-7">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.completion'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb11-8">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb11-9"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
</div>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>lua/plugins/mini-pairs.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" data-filename="lua/plugins/mini-pairs.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb12-1"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb12-2">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'nvim-mini/mini.pairs'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb12-3">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">opts</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb12-4">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">modes</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">command</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb12-5">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb12-6"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
</div></li>
<li><p>The translated <code>vim.pack</code> config (notice directory change <code>lua/plugins</code> -&gt; <code>plugin</code> and <code>00-mini-hues.lua</code> to force load it first):</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>init.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb13" data-filename="init.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb13-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- No special setup if 'plugin/' directory is used</span></span></code></pre></div></div>
</div>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>plugin/00-mini-hues.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb14" data-filename="plugin/00-mini-hues.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb14-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.hues'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb14-2"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">cmd</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>colorscheme<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'miniwinter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
</div>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>plugin/mini-completion.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb15" data-filename="plugin/mini-completion.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb15-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_create_autocmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'InsertEnter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb15-2">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">once</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb15-3">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">callback</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb15-4">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span></span>
<span id="cb15-5">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.snippets'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb15-6">      <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.completion'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb15-7">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb15-8">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.snippets'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb15-9">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.completion'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb15-10">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb15-11"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span></code></pre></div></div>
</div>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>plugin/mini-pairs.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb16" data-filename="plugin/mini-pairs.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb16-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://github.com/nvim-mini/mini.pairs'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb16-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mini.pairs'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>setup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span></span>
<span id="cb16-3">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">modes</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">command</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb16-4"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span></code></pre></div></div>
</div></li>
</ul>
    <bluesky-comments post="at://did:plc:sovgyj2emvmz4dp4naq7wy3l/app.bsky.feed.post/3mgxaiqbrts2y" filter-config="{&quot;filterEmptyReplies&quot;:true,&quot;mutePatterns&quot;:[],&quot;muteUsers&quot;:[]}" n-show-depth="2" header="" n-show-more="10" n-show-init="10" profile="did:plc:sovgyj2emvmz4dp4naq7wy3l"></bluesky-comments>
  


</section>
</section>

 ]]></description>
  <category>neovim</category>
  <guid>https://echasnovski.com/blog/2026-03-13-a-guide-to-vim-pack.html</guid>
  <pubDate>Fri, 13 Mar 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>How many Neovim plugins is too many</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2026-01-27-how-many-neovim-plugins-is-too-many.html</link>
  <description><![CDATA[ 





<p>First, to directly answer the implied question in the title: there is no specific number. Each Neovim user decides for themselves how many plugins bring the most joy out of using the editor. It can be as low as zero and as many as 100+.</p>
<p>What I am curious about is how the number of loaded plugins affects overall performance of using Neovim.</p>
<section id="motivation" class="level2">
<h2 class="anchored" data-anchor-id="motivation">Motivation</h2>
<p>There are at least two main reasons for me to explore this:</p>
<ul>
<li>Measure a performance benefit of using <a href="https://nvim-mini.org/mini.nvim/">‘mini.nvim’</a> as a single plugin instead of many its standalone repos.</li>
<li>Get an actual data about whether lazy loading can be objectively justified from at least performance point of view.</li>
</ul>
<p>I know there should be a performance difference in both cases since loading a plugin adds a path entry in <a href="https://neovim.io/doc/user/helptag.html?tag='runtimepath'">Neovim’s runtime</a>. This is a way to make Neovim “know” about available plugin code/data and use it whenever needed. Like when:</p>
<ul>
<li><p>Doing <code>require('module-name')</code> the first time for ‘module-name’ yields searching through all known ‘lua/’ runtime directories.</p></li>
<li><p>Assigning filetype to a buffer (which is a fairly frequent action) yields searching through ‘ftplugin/’ runtime directories to load filetype plugin script(s).</p>
<p>I don’t have an accurate estimation of how frequent this happens. Especially since it highly depends on which plugins are used (as they tend to set filetype for their internal buffers). But my quick testing on Neovim&gt;=0.12 with <code>vim._core.ui2</code> enabled hints that it can be in the vicinity of 500 per active Neovim usage session.</p></li>
<li><p>Attaching an LSP client on Neovim&gt;=0.11 yields searching through ‘lsp/’ runtime directories.</p></li>
<li><p>And so on. More information is in above link about Neovim’s runtime, plus <a href="https://neovim.io/doc/user/helptag.html?tag=:runtime"><code>:h :runtime</code></a> and <a href="https://neovim.io/doc/user/helptag.html?tag=runtime-search-path"><code>:h runtime-search-path</code></a></p></li>
</ul>
</section>
<section id="benchmark" class="level2">
<h2 class="anchored" data-anchor-id="benchmark">Benchmark</h2>
<p>The only way to answer these questions is by designing and performing benchmarks. Here I’ll describe the necessary basics of what was done, but you can find exact scripts and possibly more details <a href="https://github.com/echasnovski/curiosity-projects/tree/master/neovim-plugin-number">here</a>.</p>
<p>There are reasonably two performance aspects to benchmark: startup and runtime (i.e.&nbsp;everything after startup).</p>
<p>The main effect of loading plugins on startup performance is due to increasing ‘runtimepath’ value and immediately using it during startup. The two most common example here are: execute <code>require('plugin-name')</code> (like when using its method to enable and/or configure the plugin) and Neovim’s automatic sourcing of ‘plugin/’ files.</p>
<p>The main effect on runtime performance should be just increased ‘runtimepath’. So this is not quite plugin number specific, but installing plugins is the main way to increase the number of runtime paths.</p>
<p>With that in mind, I settled on the following benchmarking approach:</p>
<ul>
<li><p>One benchmark is done for a combination of a number of loaded plugins (<code>n_plugins</code>) and the way they are loaded (<code>config_type</code>).</p></li>
<li><p>Procedurally generate each plugin so that it has rudimentary but plausible ‘lua/’ and ‘plugin/’ code. See “Plugin code”.</p></li>
<li><p>Procedurally generate several config types describing how plugins are loaded via <a href="https://neovim.io/doc/user/helptag.html?tag=vim.pack"><code>vim.pack</code></a> (available on Neovim&gt;=0.12). The whole config is basically a single ‘init.lua’ file. See “Config types”.</p></li>
<li><p>Run the Neovim with the config once to install necessary plugins.</p></li>
<li><p>Measure startup by doing the equivalent of <code>nvim --startuptime file-{config_type}-{n_plugins}</code> 10 times to later average out. From startup log file extract:</p>
<ul>
<li>How long did it take to source ‘init.lua’.</li>
<li>How long did it take to source all ‘plugin/’ files.</li>
<li>Overall startup time.</li>
</ul></li>
<li><p>Once per benchmarked <code>config_type</code>+<code>n_plugins</code> combo set filetype and measure time it took. Repeat many times with each try for a fresh buffer and for a filetype that doesn’t have filetype scripts (to not include their source time in benchmarks). Take a median time as a benchmark result. I settled on 1001 times per each combo, which should be enough to get stable sub millisecond precision.</p></li>
<li><p>Tested loaded plugin numbers: 0, 5, 10, …, and 50 loaded plugins. Include zero for a sanity check and to get a reference for a total startup time.</p></li>
</ul>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>Benchmarks were done at the time when Neovim 0.12 is still in development. The AppImage with the following version was used:</p>
<pre><code>NVIM v0.12.0-dev-2435+g18c5f06c9f
Build type: RelWithDebInfo
LuaJIT 2.1.1771967821</code></pre>
</div>
</div>
<section id="plugin-code" class="level3">
<h3 class="anchored" data-anchor-id="plugin-code">Plugin code</h3>
<p>Each plugin has a very simple placeholder functionality and is written with “good practices” in mind. In particular, plugin number <code>NN</code> (which is a number from 01 to <code>n_plugins</code>, the total number of loaded plugins) contains:</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>lua/pluginNN.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" data-filename="lua/pluginNN.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">run</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">_G</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">value</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PluginNN"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb2-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">config</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">_G</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pluginNN</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PluginNN"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb2-3"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">config</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">config</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">run</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">run</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
</div>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>plugin/pluginNN.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" data-filename="plugin/pluginNN.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb3-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_create_user_command<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PluginNN"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pluginNN"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>run<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{})</span></span>
<span id="cb3-2"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">keymap</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>set<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"n"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"&lt;Plug&gt;(PluginNN)"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pluginNN"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>run<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div></div>
</div>
<p>It is generated inside ‘host/’ subdirectory of current working directory and installed using <code>file:///path/to/working/directory/host/pluginXX</code> as a source.</p>
</section>
<section id="config-types" class="level3">
<h3 class="anchored" data-anchor-id="config-types">Config types</h3>
<p>Three types of configs are benchmarked:</p>
<ol type="1">
<li><p><code>Grouped add()</code> - many independent plugins are installed and loaded as a group in a single <code>vim.pack.add()</code> call and later configured. This is the most robust and straightforward way to install many plugins with <code>vim.pack</code>.</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>init.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" data-filename="init.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb4-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span></span>
<span id="cb4-2">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'file:///path/to/working/directory/host/plugin01'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-3">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- ...</span></span>
<span id="cb4-4">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'file:///path/to/working/directory/host/pluginXX'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-5"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">confirm</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">false</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb4-6"></span>
<span id="cb4-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'plugin01'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb4-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- ...</span></span>
<span id="cb4-9"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pluginXX'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span></code></pre></div></div>
</div></li>
<li><p><code>Separate add()</code> - many independent plugins are installed, loaded, and configured in “sequential” manner. This installs and loads one plugin at a time while immediately configuring it. This is meant to check if having plugin entry in ‘runtimepath’ closer to its start (since <code>:packadd</code> from <code>vim.pack.add()</code> adds an entry very close to the start) adds a meaningful startup improvement (as <code>require('pluginNN')</code> then needs to traverse fewer directories). SPOILER: it’s complicated.</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>init.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" data-filename="init.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb5-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'file:///path/to/working/directory/host/plugin01'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">confirm</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">false</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb5-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'plugin01'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb5-3"></span>
<span id="cb5-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- ...</span></span>
<span id="cb5-5"></span>
<span id="cb5-6"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'file:///path/to/working/directory/host/pluginXX'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">confirm</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">false</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb5-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pluginXX'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span></code></pre></div></div>
</div></li>
</ol>
<ul>
<li><p><code>Single plugin</code> - single plugin that combines all Lua modules and plugin files of separate plugins into one. All ‘lua/pluginNN.lua’ and ‘plugin/pluginNN.lua’ files are combined under a single directory. This provides the same functionality as many plugins, but “packaged” in a single plugin. Similar to how ‘mini.nvim’ is related to its standalone repos. This only adds a single entry to ‘runtimepath’ and is also used as a reference to compare against.</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>init.lua</strong></pre>
</div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" data-filename="init.lua" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb6-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pack</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'file:///path/to/working/directory/host/singleXX'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">confirm</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">false</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb6-2"></span>
<span id="cb6-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'plugin01'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb6-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- ...</span></span>
<span id="cb6-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">require</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'pluginXX'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span>config<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span></code></pre></div></div>
</div></li>
</ul>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>All config types use <code>vim.pack.add()</code> to install and load plugins. For installed plugins it essentially executes <code>:packadd!</code> during startup, so modifies ‘runtimepath’ immediately. Other plugin managers can and do behave differently while requiring more elaborate ways of delayed execution of <code>require('pluginNN').config()</code>.</p>
</div>
</div>
</section>
<section id="prior-expectations" class="level3">
<h3 class="anchored" data-anchor-id="prior-expectations">Prior expectations</h3>
<ol type="1">
<li><p>Results for 0 loaded plugins do not depend on config type. Nothing loaded in various ways is still nothing loaded. Can be used for a sanity check and reference for total startup time.</p></li>
<li><p>Startup time is the best for <code>Single plugin</code> config type, followed by <code>Separate vim.pack.add()</code>, followed by <code>Grouped vim.pack.add()</code>.</p></li>
<li><p>Both “many plugins” approaches visibly grow with the number of plugins.</p></li>
<li><p>Runtime performance behaves the same for both “many plugins” config types and is visibly worse than for “single plugin”.</p></li>
</ol>
</section>
</section>
<section id="results" class="level2">
<h2 class="anchored" data-anchor-id="results">Results</h2>
<p><strong>Edit on 2026-02-27</strong>: initial version of this post was done on <code>v0.12.0-dev-2101+gd93e150888</code> development version of Neovim. Some observations didn’t feel right, which resulted into <a href="https://github.com/neovim/neovim/issues/37586">me suggesting an optimization upstream</a>. It was <a href="https://github.com/neovim/neovim/pull/37722">promptly addressed</a> by Neovim wizard <a href="https://github.com/bfredl"><span class="citation" data-cites="bfredl">@bfredl</span></a> (the quick turnaround is mostly because it affects the <code>vim.pack</code> in the upcoming Neovim 0.12 release). Each section has “Initial results” spoiler preserved for posterity.</p>
<section id="startup" class="level3">
<h3 class="anchored" data-anchor-id="startup">Startup</h3>
<p>Here are the results of benchmarking startup time (semi transparent points are actual times, line and text represent median times).</p>
<p><img src="https://echasnovski.com/blog/2026-01-27-how-many-neovim-plugins-is-too-many/startup-summary_init.png" class="img-fluid"></p>
<p><img src="https://echasnovski.com/blog/2026-01-27-how-many-neovim-plugins-is-too-many/startup-summary_plugin.png" class="img-fluid"></p>
<p><img src="https://echasnovski.com/blog/2026-01-27-how-many-neovim-plugins-is-too-many/startup-summary_total.png" class="img-fluid"></p>
<p>Observations:</p>
<ul>
<li><p>Having zero plugins indeed adds nothing to startup time.</p></li>
<li><p>Best performance is indeed for <code>Single plugin</code>. Having constant number of ‘runtimepath’ entries can save up to 50% of startup time for 50 plugins.</p></li>
<li><p>However, <code>Separate add()</code> is not visibly faster than <code>Grouped add()</code>. This probably has to do with the fact that ‘runtimepath’ option has special treatment: it is internally smartly cached on every <code>:packadd</code> to increase startup performance.</p></li>
<li><p>Sourcing ‘plugin/’ does not depend on config type and grows close to linearly with the number of loaded plugins. The exact numbers are rather small, though.</p></li>
<li><p>Total startup time is mostly affected by ‘init.lua’.</p></li>
</ul>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center collapsed" data-bs-toggle="collapse" data-bs-target=".callout-3-contents" aria-controls="callout-3" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Note</span>Initial results
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-3" class="callout-3-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<p><img src="https://echasnovski.com/blog/2026-01-27-how-many-neovim-plugins-is-too-many/initial-results/startup-summary_init.png" class="img-fluid"></p>
<p><img src="https://echasnovski.com/blog/2026-01-27-how-many-neovim-plugins-is-too-many/initial-results/startup-summary_plugin.png" class="img-fluid"></p>
<p><img src="https://echasnovski.com/blog/2026-01-27-how-many-neovim-plugins-is-too-many/initial-results/startup-summary_total.png" class="img-fluid"></p>
<ul>
<li><p><code>Separate add()</code> is <em>much slower</em> than <code>Grouped add()</code>. At first, I thought that this is a result of constant overhead of a <code>vim.pack.add</code> call, but similar results can be seen with <code>vim.cmd('packadd! pluginXX')</code>.</p>
<p>After digging through the Neovim code base (with the help of <a href="https://github.com/TheLeoP/">Luis Calle</a>), the reason seems to be internal caching. In particular:</p>
<ul>
<li>Searching in <code>require()</code> is done by a custom package loader <a href="https://github.com/neovim/neovim/blob/c28113dd9d09b661061d25c147e39efadc6e700b/runtime/lua/vim/_init_packages.lua#L31">that uses private <code>vim.api.nvim__get_runtime()</code></a>.</li>
<li>The <a href="https://github.com/neovim/neovim/blob/c28113dd9d09b661061d25c147e39efadc6e700b/src/nvim/api/vim.c#L652">private <code>vim.api.nvim__get_runtime()</code></a> uses <a href="https://github.com/neovim/neovim/blob/c28113dd9d09b661061d25c147e39efadc6e700b/src/nvim/runtime.c#L656">a helper</a> that does some caching of runtime files if ‘runtimepath’ has changed.</li>
</ul>
<p>So instead of the expected “Add to ‘runtimepath’” -&gt; “<code>require</code> searches small number of directories”, there is a “Do some ‘runtimepath’ caching” step in the middle. It seems to have been added with caching <code>pack/*/start/*</code> plugins in mind.</p>
<p>Although quick, it still adds a significant overhead at this millisecond scale of actions. But on the other hand, this approach allows to have more “separated” config structure, which many people like.</p></li>
<li><p>There is an overall and uniform ~10% improvement in startup speed between initial and “new” results. This might be a result of another startup improvement done within a month between benchmarks, since the startup time with zero plugins has improved by the same amount.</p>
<p>However, since there is a similar improvement in “Runtime” results, it might be due to how the benchmarking machine was feeling on a particular day.</p></li>
</ul>
</div>
</div>
</div>
</section>
<section id="runtime" class="level3">
<h3 class="anchored" data-anchor-id="runtime">Runtime</h3>
<p><img src="https://echasnovski.com/blog/2026-01-27-how-many-neovim-plugins-is-too-many/filetype-summary.png" class="img-fluid"></p>
<p>Observations:</p>
<ul>
<li><p>Indeed for both “many plugins” config types runtime performance is the same.</p></li>
<li><p>Switching to a single plugin can drastically reduce runtime overhead complexity from nearly linear to nearly constant.</p></li>
</ul>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center collapsed" data-bs-toggle="collapse" data-bs-target=".callout-4-contents" aria-controls="callout-4" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Note</span>Initial results
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-4" class="callout-4-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<p><img src="https://echasnovski.com/blog/2026-01-27-how-many-neovim-plugins-is-too-many/initial-results/filetype-summary.png" class="img-fluid"></p>
</div>
</div>
</div>
</section>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<ul>
<li><p>Loading plugins indeed adds a measurable performance overhead. Both during startup and runtime.</p></li>
<li><p>Reducing the number of loaded plugins (be it by using a single “bundle plugin” or by lazy loading plugins some time later) can measurably improve performance. The saved time grows linearly with the number of reduced plugins and can be as high as 50% of startup/runtime overhead for 50 reduced plugins.</p></li>
<li><p>There is no practical difference between “one <code>vim.pack.add()</code>” (load all necessary plugins at once and later configure in a series of <code>require()</code> calls) and “separate <code>vim.pack.add()</code>” (<code>vim.pack.add()</code> -&gt; <code>require()</code> -&gt; <code>vim.pack.add()</code> -&gt; <code>require()</code>). This seems to have to do with internal caching of ‘runtimepath’ option.</p></li>
<li><p>Are these findings useful? I’d say yes. On paper, the amount of saved time is very small: order of tens of milliseconds during startup and one millisecond during runtime.</p>
<p>However, Neovim users take pride in their instantaneous startup and runtime performance. When looking at a big picture of a general advice for users, the value of saved time (<code>number of opening Neovim</code> x <code>10 ms</code> + <code>number of runtime searching per session</code> x <code>1 ms</code> ~ 5 x 10 + 500 x 1 = 550 ms per day) can be visible if multiplied by the number of users and number of passed days.</p></li>
<li><p>My personal (very biased) recommendation would be this: if you want to optimize startup and runtime performance benchmarked here, switching from many separate plugins to one plugin that provides same/similar functionality is the best course of action here. If that is not possible, then consider doing some simple lazy loading (like after first screen draw or on <code>InsertEnter</code>/<code>CmdlineEnter</code> events).</p>
<p>It is also completely fine to not care about millisecond level overhead in favor of using plugins and structure that brings you more joy. In the end, the choice is always up to the user.</p></li>
</ul>
    <bluesky-comments post="at://did:plc:sovgyj2emvmz4dp4naq7wy3l/app.bsky.feed.post/3mdg67faaic2w" filter-config="{&quot;filterEmptyReplies&quot;:true,&quot;mutePatterns&quot;:[],&quot;muteUsers&quot;:[]}" n-show-more="10" profile="did:plc:sovgyj2emvmz4dp4naq7wy3l" header="" n-show-init="10" n-show-depth="2"></bluesky-comments>
  


</section>

 ]]></description>
  <category>neovim</category>
  <category>curiosity-project</category>
  <guid>https://echasnovski.com/blog/2026-01-27-how-many-neovim-plugins-is-too-many.html</guid>
  <pubDate>Tue, 27 Jan 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Neovim now has built-in plugin manager</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2025-07-04-neovim-now-has-builtin-plugin-manager.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/1lriv80/neovim_now_has_builtin_plugin_manager/">posted on Reddit</a></em></p>
<p>Hello, Neovim users!</p>
<p>After rounds of discussions and iterations, Neovim <a href="https://github.com/neovim/neovim/pull/34009">now has a minimal built-in plugin manager</a>. Its functionality is present only on latest <code>master</code> branch and located in <code>vim.pack</code> module. It is planned to land in 0.12 (which is still not quite soon).</p>
<p>You can read more about the design and workflow <a href="https://github.com/neovim/neovim/blob/cbfc3d1cdc199ce65368a2f40dc4b1ddc4331714/runtime/doc/lua.txt#L2529">here</a>. You can also see the demo of the latest state in the <a href="https://github.com/neovim/neovim/pull/34009#issue-3060712969">PR’s first comment</a>.</p>
<p>The overall design is based on ‘mini.deps’ module, but it is visibly reworked to fix some of its shortcomings and to fit “minimal built-in plugin manager” requirements.</p>
<p>Couple of <em>very important</em> notes:</p>
<ul>
<li><p>I can not stress this enough, this is yet a <strong>WORK IN PROGRESS</strong>. There are <a href="https://github.com/neovim/neovim/issues/34763">many planned improvements</a>. Expect breaking changes without notice. Only use it if you are comfortable fixing suddenly not working config.</p></li>
<li><p>Early testing of <em>existing features</em> is appreciated. Suggestions about new features will be met very conservatively (at least until there is an ongoing planned work).</p></li>
<li><p>It is not meant to provide all advanced plugin manager features. If you prefer to use a more capable plugin manager, it is totally normal. Probably even possible to use side-by-side with <code>vim.pack</code>.</p></li>
</ul>
<p>There is still a long road ahead and we’ll walk it one step at a time. Thanks for reading and using Neovim!</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2025-07-04-neovim-now-has-builtin-plugin-manager.html</guid>
  <pubDate>Fri, 04 Jul 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Neovim + mini.pick + nushell = CLI fuzzy picker. Why? Because why not.</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2025-06-20-neovim-minipick-nushell-cli-fuzzy-picker.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/1lg40xm/neovim_minipick_nushell_cli_fuzzy_picker_why/">posted on Reddit</a></em></p>
<div class="quarto-video"><video id="video_shortcode_videojs_video1" class="video-js vjs-default-skin vjs-fluid" controls="" preload="auto" data-setup="{}" title=""><source src="2025-06-20-neovim-minipick-nushell-cli-fuzzy-picker/demo.mp4"></video></div>
<p>Hello, Neovim users!</p>
<p>For quite some time I was interested in trying out <a href="https://www.nushell.sh/">Nushell</a> as my default shell. To be perfectly honest, I am not sure why. Probably because I am drawn to the idea of “piping structured data” and mastering a powerful tool for the future. Or maybe it is just pretty tables, who knows.</p>
<p>Several weeks ago I decided to give it a try but only in Ghostty (terminal emulator I use for regular activity; as opposed to backup <code>st</code> with Zsh). It is pretty interesting to set up from ground up and use.</p>
<p>Switching from Zsh to Nushell very much reminds me of switching from Vim to Neovim <em>just after</em> the latter got first-class Lua support. Nu (language of Nushell) is a saner language than Bash to hack the config and add custom features (very much like Lua is to Vimscript). But it is not <em>quite</em> stable yet, so expecting something to break after new release is not baseless.</p>
<hr>
<p>Anyway, while writing my prompt from scratch (as one does) I also thought that it would be an interesting challenge to try to go without <code>fzf</code> in CLI and try to use fuzzy picking I have set up in Neovim with <a href="https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-pick.md">‘mini.pick’</a>. It turned out to be not as complicated as I feared at the beginning. The only downside is that Neovim always occupies full terminal window, so it is impossible to have small-ish picker as <code>fzf</code>.</p>
<p>I believe the overall approach can be generalized to other shells and Neovim’s fuzzy pickers, so decided to share it here. Basically:</p>
<ul>
<li><p>The general idea is to manually call Neovim with custom config (it can be regular config, but separate one feels cleaner to me) to fuzzy pick things. <em>Choosing item(s) should write them into a special file</em> . After that, shell reads the file and performs necessary actions.</p></li>
<li><p>So, to fuzzy pick something like files/subdirectories and insert item at cursor:</p>
<ul>
<li>Write a global function in ‘init.lua’ that starts fuzzy picker for files (like using <code>MiniPick.builtin.files()</code>) or subdirectories (custom picker). Choosing item(s) should execute custom action and write to a dedicated file (like ‘/tmp/nvim/out-file’).</li>
<li>Write custom shell command/function that calls Neovim with a dedicated ‘init.lua’ and executes the necessary global Lua function (like with <code>-c "lua _G.pick_file_cli()"</code>). After calling <code>nvim</code>, the shell command/function should read the ‘/tmp/nvim/out-file’ file, delete it (to not reuse later), and insert its content at cursor.</li>
<li>Map dedicated keys in shell to that command/function. Currently I have <code>&lt;C-d&gt;</code> for subdirectories and <code>&lt;C-t&gt;</code> for files.</li>
</ul></li>
<li><p>To fuzzy pick from piped input, create a shell command/function that:</p>
<ul>
<li>Writes piped input to a dedicated file (like ‘/tmp/nvim/in-file’).</li>
<li>Calls Neovim’s global function that reads from that file, fuzzy picks from items, writes chosen one(s) to ‘/tmp/nvim/out-file’.</li>
<li>Reads from ‘/tmp/nvim/out-file’ and returns its content.</li>
</ul></li>
</ul>
<p>My dedicated Neovim config for this is <a href="https://github.com/echasnovski/nvim/blob/a7b3e74d439959696f16f05178377cd6f557533d/init-cli-pick.lua">here</a> (it assumes ‘mini.nvim’ is already installed as suggested in ’pack/*/start’ directory). The Nushell part of the approach is <a href="https://github.com/echasnovski/dotfiles/blob/027e1fd73a9ba9e8f73245756bba5721afe6b7d6/nushell/.config/nushell/config.nu#L164-L213">here</a>.</p>
<p>The approach is not perfect and I’d recommend to daily drive it only if you understand how it works. But maybe the whole approach would interesting to someone.</p>
<p>Thanks for reading!</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2025-06-20-neovim-minipick-nushell-cli-fuzzy-picker.html</guid>
  <pubDate>Fri, 20 Jun 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>PSA for color scheme authors: you might want to adjust PmenuSel</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2024-08-29-psa-adjust-`pmenusel`.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/1f439w8/psa_for_color_scheme_authors_you_might_want_to/">posted on Reddit</a></em></p>
<p>TL;DR: to account for possible new custom highlighting in popup menu items, you might want to switch <code>fg</code> and <code>bg</code> colors in <code>Pmenu*Sel</code> groups while adding <code>reverse</code> attribute.</p>
<hr>
<p>Neovim Nightly (0.11) recently landed new features regarding adding custom highlighting to items of built-in popup menu:</p>
<ul>
<li>Whole item via <code>hl_group</code> (<a href="https://github.com/neovim/neovim/pull/29876">thanks to glepnir</a>).</li>
<li>Only “kind” field via <code>kind_hlgroup</code> (<a href="https://github.com/neovim/neovim/pull/30128">also thanks to glepnir</a>).</li>
</ul>
<p>Both of the fields combine highlight attributes with underlying highlighting from <code>Pmenu*</code> groups. This is a great choice because it allows plugin authors to use highlight groups which modify only foreground (a.k.a. text) and it will “reuse” background of popup menu. An alternative would have been to expose special highlight groups which <strong>each color scheme</strong> would have needed to define (while only adding its own popup menu background).</p>
<p>Item highlighting usually should work well with displaying text in regular popup menu item (if it has background similar to <code>Normal</code> in terms of lightness), <strong>but</strong> might result into barely readable text when item is selected. This can be the case if color scheme chooses for <code>PmenuSel</code> (and its variants like <code>PmenuKindSel</code>, etc.) to have intentionally inverted lightness compared to <code>Pmenu</code>. I’ve encountered this with ‘mini.hues’ and default color scheme (which is <a href="https://github.com/neovim/neovim/pull/30183">planned to be fixed</a>).</p>
<p>Luckily, there is a solution, albeit a bit unintuitive one: switch <code>fg</code>&lt;-&gt;<code>bg</code> attributes and add <code>reverse</code> attribute. Here is an example from bundled ‘evening’ color scheme:</p>
<ul>
<li>Current:</li>
</ul>
<pre><code>hi PmenuSel      guifg=#000000 guibg=#bebebe gui=NONE cterm=NONE
hi PmenuMatchSel guifg=#8b008b guibg=#bebebe gui=NONE cterm=NONE</code></pre>
<ul>
<li>Adjusted <code>PmenuSel</code>:</li>
</ul>
<pre><code>hi PmenuSel      guifg=#bebebe guibg=#000000 gui=reverse cterm=reverse
hi PmenuMatchSel guifg=#bebebe guibg=#8b008b gui=reverse cterm=reverse</code></pre>
<p>Here is <a href="https://github.com/user-attachments/assets/8d2b2550-1609-4f27-aac1-ab9d2a0afef7">a screenshot</a> of before (left) and after (right)</p>
<p>This works because combining highlight attributes first combines foreground/background colors and <em>only after that</em> applies <code>reverse</code>. It will keep the same visuals if there is no highlighting, but should also work with reasonable choices of <code>hl_group</code> and <code>kind_hlgroup</code> in completion items.</p>
<hr>
<p>If you are a color scheme author or a concerned user of one, I think making this change is worth it. You can use the test code example <a href="https://github.com/neovim/neovim/pull/30183">from PR to default color scheme</a>. Hope it helps.</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2024-08-29-psa-adjust-`pmenusel`.html</guid>
  <pubDate>Thu, 29 Aug 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>You can remove padding around Neovim instance with this one simple trick…</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2024-08-01-remove-padding-around-neovim-instance.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/1ehidxy/you_can_remove_padding_around_neovim_instance/">posted on Reddit</a></em></p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://echasnovski.com/blog/2024-08-01-remove-padding-around-neovim-instance/demo.png" class="img-fluid figure-img"></p>
<figcaption>Left: with "frame" from terminal emulator; Right: without that "frame"</figcaption>
</figure>
</div>
<p>(Sorry for a slightly clickbait-y title. Always wanted to use one of those :) )</p>
<p>If you have different background color in your terminal emulator and Neovim, then chances are that you experience this weird “frame” around your Neovim instance. Like the one shown in the left part of the picture.</p>
<p>This is because CLI programs occupy screen estate based on the cell grid with cells having same width and height. If pixel dimension(s) of terminal emulator’s window are not multiple of cell pixel dimension(s), there is a gap between edge(s) of rendered CLI program and window edge(s).</p>
<p>Usual answers to this issue are:</p>
<ul>
<li>Use same background color in Neovim and terminal emulator. Works, but is too restrictive.</li>
<li>Adjust window dimensions or DPI. Works, but is too restrictive.</li>
<li>Use GUI (like Neovide). Works, but… you get the idea.</li>
</ul>
<hr>
<p>As it turns out, this can be solved by keeping terminal background’s color in sync with Neovim’s background color. This is possible thanks to a dark magic called <a href="https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands">“Operating System Commands XTerm Control Sequences”</a> or OSC control sequences for short. In particular, OSC 11 and OSC 111, which your terminal should support (most modern feature rich ones do: Kitty, WezTerm, Alacritty, etc.).</p>
<p>Just add the following snippet to your ‘init.lua’ (credit to u/gpanders from <a href="https://github.com/neovim/neovim/issues/16572#issuecomment-1954420136">this comment</a>):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb1-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_create_autocmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">({</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"UIEnter"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ColorScheme"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-2">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">callback</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb1-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">normal</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_get_hl<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Normal"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb1-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">not</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">normal</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">bg</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">io.write</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">string.format</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\027</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">]11;#%06x</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\027\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">normal</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">bg</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span></span>
<span id="cb1-6">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-7"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span>
<span id="cb1-8"></span>
<span id="cb1-9"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_create_autocmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"UILeave"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-10">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">callback</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">io.write</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\027</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">]111</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\027\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-11"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span></code></pre></div></div>
<p>And that’s it. It synchronizes on every enter/exit Neovim instance and after loading new color scheme. And it even works with <code>&lt;C-z&gt;</code> and later <code>fg</code>! Couple of caveats, though:</p>
<ul>
<li>Make sure to have this executed <strong>before</strong> you load color scheme. Otherwise there will be no event for it to sync. Alternatively, add an explicit call to the first <code>callback</code> function and it should work as is.</li>
<li>It will not sync if you manually set <code>Normal</code> highlight group. It must be followed by the <code>ColorScheme</code> event.</li>
</ul>
<hr>
<p>Also, if you want a slightly more robust, maintained, and tested version, there is now a new <a href="https://github.com/nvim-mini/mini.nvim/blob/74e6b722c91113bc70d4bf67249ed8de0642b20e/doc/mini-misc.txt#L171">setup_termbg_sync()</a> in ‘mini.misc’ module of ‘mini.nvim’. It also checks if OSC 11 is supported by terminal emulator, uses only it without OSC 111, and synchronizes immediately.</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2024-08-01-remove-padding-around-neovim-instance.html</guid>
  <pubDate>Thu, 01 Aug 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Neovim now has built-in commenting</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2024-04-05-neovim-now-has-builtin-commenting.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/1bwlvrt/neovim_now_has_builtin_commenting/">posted on Reddit</a></em></p>
<p><a href="https://github.com/neovim/neovim/pull/28176">The PR for built-in commenting</a> has been merged into Nightly builds. There is more info in the initial PR comment and <a href="https://github.com/neovim/neovim/blob/73de98256cf3932dca156fbfd0c82c1cc10d487e/runtime/doc/various.txt#L561-L597">help entry</a>, but for the lazy:</p>
<ul>
<li><p>All it does is out of the box mappings:</p>
<ul>
<li><code>gc</code> operator (Normal and Visual mode) to toggle comments.</li>
<li><code>gc</code> textobject (Operator-pending mode) as operator target.</li>
<li><code>gcc</code> for toggling comments in current line (basically a convenient <code>gc_</code> remap).</li>
</ul>
<p>Also, of course, dot-repeat, <code>[count]</code> support, etc.</p></li>
<li><p>This is basically a simplified version of <a href="https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-comment.md">‘mini.commment’</a> with <em>mostly</em> default config.</p>
<p>The <code>pad_comment_parts</code> is <code>false</code> meaning that ‘commentstring’ option is taken as is, without forcing single space padding. This is planned to be addressed by adjusting default ‘commentstring’ values some time later (at least after 0.10.0 release) or can be done by users themselves in their configs.</p></li>
<li><p>On the surface it is quite close to ‘tpope/vim-commentary’, but with some difference in how it handles blank lines: blank lines are commented but do not affect the toggle action decision. See example in <a href="https://github.com/neovim/neovim/pull/28176#issuecomment-2039299762">this comment</a>.</p></li>
</ul>
<p>So if you are using only basics of ‘mini.comment’ (no custom hooks, options, or callable ‘commentstring’s) or ’tpope/vim-commentary’, you might find the new built-in commenting on Nightly to be enough.</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2024-04-05-neovim-now-has-builtin-commenting.html</guid>
  <pubDate>Fri, 05 Apr 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Exactly 10 years ago Neovim had its first commit</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2024-01-31-neovim-10-year-anniversary.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/1afi21p/exactly_10_years_ago_neovim_had_its_first_commit/">posted on Reddit</a></em></p>
<p><a href="https://github.com/neovim/neovim/commit/72cf89bce8e4230dbc161dc5606f48ef9884ba70">A link to first commit</a>.</p>
<p>To celebrate this, Neovim team created an official store: <a href="https://store.neovim.io">https://store.neovim.io</a>. It should be live now. All profit will go to benefit Neovim project.</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2024-01-31-neovim-10-year-anniversary.html</guid>
  <pubDate>Wed, 31 Jan 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Neovim now has its own default color scheme</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2023-12-03-neovim-now-has-its-own-default-color-scheme.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/189nw6r/neovim_now_has_its_own_default_color_scheme/">posted on Reddit</a></em></p>
<p><img src="https://echasnovski.com/blog/2023-12-03-neovim-now-has-its-own-default-color-scheme/demo-dark.png" class="img-fluid"> <img src="https://echasnovski.com/blog/2023-12-03-neovim-now-has-its-own-default-color-scheme/demo-light.png" class="img-fluid"></p>
<p>See <a href="https://github.com/neovim/neovim/pull/26334">this PR</a> for more details.</p>
<p>And if you think you’ll miss magenta floating windows and completion menu, there is <code>colorscheme vim</code>.</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2023-12-03-neovim-now-has-its-own-default-color-scheme.html</guid>
  <pubDate>Sun, 03 Dec 2023 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Floating windows in Neovim can now have footer</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2023-08-26-floating-windows-in-neovim-can-now-have-footer.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/1621k2m/floating_windows_can_now_have_footer/">posted on Reddit</a></em></p>
<p><img src="https://echasnovski.com/blog/2023-08-26-floating-windows-in-neovim-can-now-have-footer/demo.png" class="img-fluid"></p>
<p>After merging <a href="https://github.com/neovim/neovim/pull/24739">this PR</a>, <code>nvim_open_win()</code> now supports <code>footer</code> and <code>footer_pos</code> options. They are symmetrical to <code>title</code> and <code>title_pos</code> options, but affect the bottom part of floating window border.</p>
<p><strong>Important</strong>: this is a part of Neovim 0.10, not current stable Neovim 0.9.1. Will also be available in next Nightly build.</p>
<p>I am excited to see how Neovm community can leverage this. It seems like an appropriate place to show some help data alongside usual title. I have a few ideas for ‘mini.nvim’ myself :)</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2023-08-26-floating-windows-in-neovim-can-now-have-footer.html</guid>
  <pubDate>Sat, 26 Aug 2023 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Average Neovim color scheme</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2023-04-24-average-color-scheme.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/12xg27j/have_you_ever_wondered_how_average_popular_neovim/">posted on Reddit</a></em></p>
<p><img src="https://echasnovski.com/blog/2023-04-24-average-color-scheme/demo-dark.png" class="img-fluid"></p>
<p><img src="https://echasnovski.com/blog/2023-04-24-average-color-scheme/demo-light.png" class="img-fluid"></p>
<p>Hello, Neovim users!</p>
<p>For quite some time I was wondering how would “average popular Neovim color scheme” look like. I mean, it would certainly contain much purple and blue, but <strong>how much exactly</strong>? It is not a trivial thing to compute.</p>
<p>Thankfully, the recent release of <a href="https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-colors.md">‘mini.colors’</a> makes this task much more manageable.</p>
<p>I decided that general approach to averaging color schemes would be as follows:</p>
<ul>
<li>Highlight group will be present in output if it is present (explicitly defined and differs from Neovim’s built-in values) in <strong>all</strong> reference color schemes.</li>
<li>Attribute of highlight group (like <code>foreground</code>, <code>background</code>, <code>underline</code>, etc.) is present if it is present in <strong>all</strong> reference color schemes.</li>
</ul>
<p>Of course, there are other ways to tackle this problem, but such a strict approach will ensure that output palette is as consistent as possible. Otherwise output will contain many different but similar colors, which doesn’t seem good.</p>
<p>For reference color schemes I decided to go through <a href="https://github.com/rockerBOO/awesome-neovim">awesome-neovim</a> and pick top 5 Lua implemented color schemes with most stars. Here is the final list (as of 2023-04-20):</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Color scheme</th>
<th>Stargazers</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><a href="https://github.com/folke/tokyonight.nvim">folke/tokyonight.nvim</a></td>
<td>3476 stars</td>
</tr>
<tr class="even">
<td><a href="https://github.com/catppuccin/nvim">catppuccin/nvim</a></td>
<td>2639 stars</td>
</tr>
<tr class="odd">
<td><a href="https://github.com/rebelot/kanagawa.nvim">rebelot/kanagawa.nvim</a></td>
<td>2219 stars</td>
</tr>
<tr class="even">
<td><a href="https://github.com/EdenEast/nightfox.nvim">EdenEast/nightfox.nvim</a></td>
<td>2055 stars</td>
</tr>
<tr class="odd">
<td><a href="https://github.com/projekt0n/github-nvim-theme">projekt0n/github-nvim-theme</a></td>
<td>1379 stars</td>
</tr>
</tbody>
</table>
<p>(Full disclosure: initially I wanted to go with “top 5 Neovim color schemes” which would have included <a href="https://github.com/sainnhe/everforest">sainnhe/everforest</a> as fifth one. But although its colors are sooooooo nice, it is quite different in terms of which attributes it defines for certain highlight groups. Including it instead of ‘projekt0n/github-nvim-theme’ resulted in not very coherent output. So in the end it was decided to take “top 5 <strong>Lua</strong> color schemes”.)</p>
<p>The result is in the post. Yes, it is blue-purple-ish, as expected. Also in my opinion it does have a quality of “looks like tokyonight/catppuccin/kanagawa, but not quite”.</p>
<p><a href="https://gist.github.com/echasnovski/283c6676bd7b29124d56b0b262b09c69">Here is a gist</a> with colorscheme files for average dark and light variants (put any of them into <code>~/.config/nvim/colors</code> and use <code>:colorscheme</code> command as usual) along with a script used to create them. Please don’t expect much from actually applying color scheme files, as they define only basic highlight groups with very limited advanced support like many plugins, tree-sitter, semantic tokens, etc.</p>
<p>Besides fulfilling general curiosity, I also plan to use this result to make a data-driven decisions for a new upcoming color scheme generator in ‘mini.nvim’.</p>
<p>Hope you enjoyed reading this!</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2023-04-24-average-color-scheme.html</guid>
  <pubDate>Mon, 24 Apr 2023 00:00:00 GMT</pubDate>
</item>
<item>
  <title>You don’t need ‘vim-rooter’ (usually) or How to set up smart autochange of current directory</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2022-12-29-you-dont-need-vimrooter-usually.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/zy5s0l/you_dont_need_vimrooter_usually_or_how_to_set_up/">posted on Reddit</a></em></p>
<p>Hello, Neovim users!</p>
<p>The <a href="https://github.com/airblade/vim-rooter">airblade/vim-rooter</a> plugin is an essential part of my Neovim workflow. It automatically changes current directory (<code>:h current-directory</code>) for every buffer to a more natural one (like to path of its Git repository). For me this has the following benefits:</p>
<ul>
<li>Most file explorers open closer to the file of current buffer and not inside directory in which Neovim was started.</li>
<li>Searching files with Telescope is more natural.</li>
<li>Built-in terminal opens in directory I usually want it to open: in root based on current buffer file.</li>
</ul>
<p>However, starting from Neovim 0.8 ‘vim-rooter’ is (almost) obsolete. Using an amazing <code>vim.fs</code> module you can set up basic autochange of current directory using these lines of code (call them somewhere during your Neovim startup):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Array of file names indicating root directory. Modify to your liking.</span></span>
<span id="cb1-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root_names</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'.git'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Makefile'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-3"></span>
<span id="cb1-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Cache to use for speed up (at cost of possibly outdated results)</span></span>
<span id="cb1-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root_cache</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">set_root</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb1-8">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Get directory path to start search from</span></span>
<span id="cb1-9">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_buf_get_name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-10">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">''</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-11">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fs</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>dirname<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-12"></span>
<span id="cb1-13">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Try cache and resort to searching upward for root directory</span></span>
<span id="cb1-14">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root_cache</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span></span>
<span id="cb1-15">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">nil</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-16">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root_file</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fs</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>find<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root_names</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">upward</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span></span>
<span id="cb1-17">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root_file</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">nil</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-18">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fs</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>dirname<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root_file</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-19">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root_cache</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">path</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root</span></span>
<span id="cb1-20">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-21"></span>
<span id="cb1-22">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Set current directory</span></span>
<span id="cb1-23">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fn</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>chdir<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-24"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-25"></span>
<span id="cb1-26"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root_augroup</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_create_augroup<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'MyAutoRoot'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{})</span></span>
<span id="cb1-27"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_create_autocmd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'BufEnter'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">group</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">root_augroup</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">callback</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">set_root</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">})</span></span></code></pre></div></div>
<p>Of course this implementation has certain limitations: - The main one is a lack of ability to use glob patterns to find root directory. However, although solvable, I think the most common use case is to define root based on some pre-determined set of actual file names, so this shouldn’t be a big issue. - It caches results to speed up computations with a downside of result possibly being outdated. Usually not an issue, though. Remove all cache related code to not do that.</p>
<p>Initially I planned to make a separate ‘mini.root’ module, but realized that it would mostly be a reimplementation of <code>vim.fs</code>. So instead I decided to add <a href="https://github.com/nvim-mini/mini.nvim/blob/bd6d1f3fd2da7741140510c2b37e2de7901b03fb/doc/mini-misc.txt#L95"><code>setup_auto_root()</code></a> function to <a href="https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-misc.md">mini.misc</a>. If you want a more tested and documented solution, check it out and tell me what you think. Thanks!</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2022-12-29-you-dont-need-vimrooter-usually.html</guid>
  <pubDate>Thu, 29 Dec 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Results of “Neovim built-in options survey”</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2022-12-08-results-of-neovim-builtin-options-survey.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/zg44mm/results_of_neovim_builtin_options_survey_more_in/">posted on Reddit</a></em></p>
<p><img src="https://echasnovski.com/blog/2022-12-08-results-of-neovim-builtin-options-survey/chart.png" class="img-fluid"></p>
<p>Hello, Neovim users!</p>
<p>Around two weeks ago I decided to make a <a href="../blog/2022-11-22-neovim-builtin-options-survey-needs-your-contribution.html">Neovim built-in options survey</a>. Now it is closed, as it doesn’t seem to have an intensive answer supply (last one was more than 24 hours ago).</p>
<p>There were total 227 legible answers. Not as many as I had hoped starting it, but it is what it is.</p>
<p>Main summary of basic options are in the post image. To answer questions in the survey announcement:</p>
<ul>
<li><code>What Leader key is used the most?</code> - Space.</li>
<li><code>Tabs or spaces?</code> - Spaces (based on 82% of <code>expandtab=true</code>)</li>
<li><code>Absolute, relative, or no line numbers?</code> - Seems like both absolute and relative. But probably more absolute ones, based on 86% of <code>number=true</code>.</li>
<li><code>Traditional or global statusline?</code> - Global, but with a tight margin.</li>
<li><code>Permanent tabline or not?</code> - Not permanent, default one.</li>
<li><code>Use persistent undo or not?</code> - Yes to persistent undo</li>
<li><code>showmode or noshowmode?</code> - <code>noshowmode</code></li>
<li><code>wrap or nowrap?</code> - <code>wrap</code>.</li>
</ul>
<p>Here is <a href="https://gist.github.com/echasnovski/fa70dc75c475369747d2a485a13303fb">a gist with full results</a> along with description of how to read them and scripts used</p>
<p>I also created a <a href="https://github.com/neovim/neovim/issues/21342">GitHub issue in Neovim repository</a> to discuss possibility of default values change. If you agree with changing options which reached 80% for some non-default value (as per <a href="https://www.reddit.com/r/neovim/comments/z1tmjg/comment/ixfp0gn/?utm_source=share&amp;utm_medium=web2x&amp;context=3">commentary of Justin M. Keys</a>), please upvote initial issue message.</p>
<p>Thanks for reading and participating!</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2022-12-08-results-of-neovim-builtin-options-survey.html</guid>
  <pubDate>Thu, 08 Dec 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Neovim built-in options survey needs your contribution</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2022-11-22-neovim-builtin-options-survey-needs-your-contribution.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/z1tmjg/neovim_builtin_options_survey_needs_your/">posted on Reddit</a></em></p>
<p>Hello, Neovim users!</p>
<p><strong>Update from 2022-12-08</strong>. Survey is closed. Here is a <a href="../blog/2022-12-08-results-of-neovim-builtin-options-survey.html">post with results</a>.</p>
<p>For a long time I have been curious about how other people use built-in Neovim settings. For example, I am almost sure that most of you set <code>termguicolors</code> to leverage modern color schemes, but I have nothing to back it up.</p>
<p>So I decided to make a survey and it needs your contribution! <strong>Here is the link to <a href="https://forms.gle/ciFiJ6z1VaQe8iN56">Google form</a>.</strong> It lists all steps needed to take part which should take at most 5 minutes of your time. Basically:</p>
<ul>
<li>You’d need to download and execute my custom script (<a href="https://gist.github.com/echasnovski/493329c67050e9dcc5546815f31179d0">with this source code</a>) inside your day-to-day Neovim config (needs at least Neovim 0.7.0). It will produce a formatted scratch buffer with all non-default values of built-in options.</li>
<li>Review content for sensible information (paths, etc.).</li>
<li>Copy all lines from created buffer and paste them into a single survey question.</li>
<li>Click “Submit”. That’s it!</li>
</ul>
<p><strong>It doesn’t require logging into your Google account and won’t track your email address</strong>. However, please, submit your results only once. I solely rely on your honesty here.</p>
<p>Other possible interesting questions this survey will help answer:</p>
<ul>
<li>What <code>Leader</code> key is used the most?</li>
<li>Tabs or spaces?</li>
<li>Absolute, relative, or no line numbers?</li>
<li>Traditional or global statusline?</li>
<li>Permanent tabline or not?</li>
<li>Use persistent undo or not?</li>
<li><code>showmode</code> or <code>noshowmode</code>?</li>
<li><code>wrap</code> or <code>nowrap</code>?</li>
<li>And maybe more…</li>
</ul>
<p>What I plan to do with results: - The summary of results will be released in some way, shape, or form after survey is closed (at least two weeks from now when there is a 24 hours without new entries). It will be announced in this sub. - Possibly use the most commonly set non-default settings to power a Neovim variant, crowd-sourced version of <a href="https://github.com/tpope/vim-sensible">tpope/vim-sensible</a>.</p>
<p>Please, spread a word about this survey to make it more objective. I will consider this survey as passable if at least 100 people will take part. Thanks!</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2022-11-22-neovim-builtin-options-survey-needs-your-contribution.html</guid>
  <pubDate>Tue, 22 Nov 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Create and apply randomly generated Base16 color scheme</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2022-09-09-random-base16-color-scheme.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/x9r5zh/create_and_apply_randomly_generated_base16_color/">posted on Reddit</a></em></p>
<div class="quarto-video"><video id="video_shortcode_videojs_video1" class="video-js vjs-default-skin vjs-fluid" controls="" preload="auto" data-setup="{}" title=""><source src="2022-09-09-random-base16-color-scheme/demo.mp4"></video></div>
<p>Hello, Neovim users!</p>
<p>I decided to share a bit silly, but fun way to choose a color scheme you like. Maybe even have this in your startup config, if you feel particularly adventurous :)</p>
<p>It uses <a href="https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-base16.md">mini.base16</a> module of <a href="https://github.com/nvim-mini/mini.nvim">mini.nvim</a> for both palette generation and color scheme application. Granted, results are not <em>that</em> different from one another (mainly because they share same highlight group definitions and idea behind making distinctive accent colors), but vary quite a bit.</p>
<p>Here is a <a href="https://gist.github.com/echasnovski/2adeb8ca809126ce35ec644918fce413">gist with code</a>. It has the instructions of how to use it.</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2022-09-09-random-base16-color-scheme.html</guid>
  <pubDate>Fri, 09 Sep 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Usage of ‘after/ftplugin’ directory for filetype-specific configuration</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2022-09-02-usage-of-after-ftplugin-directory.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/x3zp6t/usage_of_afterftplugin_directory_for/">posted on Reddit</a></em></p>
<p>Do you create any configuration that is specific to a certain file type (like setting local options or buffer-local variables, creating local mappings, running some function, etc.)?</p>
<ul>
<li><strong>No</strong>. Sooner or later you probably will. So let’s pretend that the answer is…</li>
<li><strong>Yes</strong>. Do you use autocommands with <code>FileType</code> event for this?
<ul>
<li><strong>No</strong>. Good. There is probably nothing valuable for you to read here. Sorry for taking your time.</li>
<li><strong>Yes</strong>. Although totally doable, there is another approach which is not popularized much. You can create ‘after/ftplugin’ directory within your configuration and put filetype-named files to be sourced for this file type. As a bonus, this is technically a way to create a “filetype plugin”, so you can now say that you are a plugin author and maintainer. Example: ‘after/ftplugin/lua.lua’ will be sourced for ‘lua’ file types (specifically, every time <code>filetype</code> buffer option is set to ‘lua’). Don’t forget to use local variants of setting options (<code>:setlocal</code> or <code>vim.opt_local</code>) and creating mappings (<code>vim.api.nvim_buf_set_keymap()</code>).</li>
</ul></li>
</ul>
<p>This is meant as a Friday post to make more people aware of ‘after/ftplugin’ directory, because I find this approach really more structured than using autocommands. For reference, here is <a href="https://github.com/echasnovski/nvim/tree/master/after/ftplugin">how I do it</a>.</p>
<p>Some further reading:</p>
<ul>
<li><code>:h ftplugin</code> (more in-depth about this approach; not really needed for simple use cases)</li>
<li><code>:h ftplugin-special</code> (notes about special things to use in these files)</li>
<li><code>:h lua-vim-setlocal</code> (use <code>vim.opt_local</code> to set option locally)</li>
<li><code>:h after-directory</code> (use ‘after’ directory so that these options are not overridden by defaults)</li>
</ul>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2022-09-02-usage-of-after-ftplugin-directory.html</guid>
  <pubDate>Fri, 02 Sep 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>I contributed to (mostly) 14 top-rated Neovim color schemes. Here are some observations</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2022-07-20-i-contributed-to-toprated-neovim-color-schemes.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/w3jhuc/i_contributed_to_mostly_14_toprated_neovim_color/">posted on Reddit</a></em></p>
<p>Some time ago I decided to improve user experience for my <a href="https://github.com/nvim-mini/mini.nvim">mini.nvim</a> plugin by adding its explicit support to popular color schemes. Although out of the box experience should be pretty good (most coloring is done by linking to carefully selected builtin highlight groups), having them tailored to color scheme choices is certainly better.</p>
<p>So I went to <a href="https://github.com/rockerBOO/awesome-neovim#colorscheme">rockerBoo/awesome-neovim</a> and selected a handful of color schemes subjectively judging by the number of Github stars, time since latest commit, and language of plugin (Lua preferred). It was not a very scientifically rigorous process which lead to 14 chosen color schemes.</p>
<p>Here is a table of how those contributions went. Now, I want to state right away that this is no way, shape, or form should be used to judge how actively those maintainers watch for their projects. Everyone is different and has limited amount of time in a day. This is only a data about my experience at some point in past.</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Color scheme PR</th>
<th>Language</th>
<th>Time to first reaction</th>
<th>Outcome</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><a href="https://github.com/bluz71/vim-moonfly-colors/pull/22">bluz71/vim-moonfly-colors</a></td>
<td>Vimscript</td>
<td>~ 1 day</td>
<td>Revised and accepted</td>
</tr>
<tr class="even">
<td><a href="https://github.com/bluz71/vim-nightfly-guicolors/pull/33">bluz71/vim-nightfly-guicolors</a></td>
<td>Vimscript</td>
<td>~ 1 day</td>
<td>Revised and accepted</td>
</tr>
<tr class="odd">
<td><a href="https://github.com/catppuccin/nvim/pull/166">catppuccin/nvim</a></td>
<td>Lua</td>
<td>~ 6 days</td>
<td>Merged</td>
</tr>
<tr class="even">
<td><a href="https://github.com/EdenEast/nightfox.nvim/pull/174">EdenEast/nightfox.nvim</a></td>
<td>Lua</td>
<td>~ 1 day</td>
<td>Merged</td>
</tr>
<tr class="odd">
<td><a href="https://github.com/folke/tokyonight.nvim/pull/179">folke/tokyonight.nvim</a></td>
<td>Lua</td>
<td>&gt; 14 days (no reaction yet)</td>
<td>Open</td>
</tr>
<tr class="even">
<td><a href="https://github.com/marko-cerovac/material.nvim/pull/103">marko-cerovac/material.nvim</a></td>
<td>Lua</td>
<td>~ 3 days</td>
<td>Merged</td>
</tr>
<tr class="odd">
<td><a href="https://github.com/navarasu/onedark.nvim/pull/87">navarasu/onedark.nvim</a></td>
<td>Lua</td>
<td>~ 1 day</td>
<td>Merged</td>
</tr>
<tr class="even">
<td><a href="https://github.com/projekt0n/github-nvim-theme/pull/194">projekt0n/github-nvim-theme</a></td>
<td>Lua</td>
<td>~ 1 day</td>
<td>Merged</td>
</tr>
<tr class="odd">
<td><a href="https://github.com/rebelot/kanagawa.nvim/pull/57">rebelot/kanagawa.nvim</a></td>
<td>Lua</td>
<td>~ 7 days</td>
<td>Waiting for approval</td>
</tr>
<tr class="even">
<td><a href="https://github.com/sainnhe/edge/pull/59">sainnhe/edge</a></td>
<td>Vimscript</td>
<td>~ 1 day</td>
<td>Merged</td>
</tr>
<tr class="odd">
<td><a href="https://github.com/sainnhe/everforest/pull/69">sainnhe/everforest</a></td>
<td>Vimscript</td>
<td>~ 1 day</td>
<td>Merged</td>
</tr>
<tr class="even">
<td><a href="https://github.com/sainnhe/gruvbox-material/pull/133">sainnhe/gruvbox-material</a></td>
<td>Vimscript</td>
<td>~ 1 day</td>
<td>Merged</td>
</tr>
<tr class="odd">
<td><a href="https://github.com/sainnhe/sonokai/pull/65">sainnhe/sonokai</a></td>
<td>Vimscript</td>
<td>~ 1 day</td>
<td>Merged</td>
</tr>
<tr class="even">
<td><a href="https://github.com/shaunsingh/nord.nvim/pull/99">shaunsingh/nord.nvim</a></td>
<td>Lua</td>
<td>~ 1 day</td>
<td>Merged</td>
</tr>
</tbody>
</table>
<p>Some personal observations after all this was done:</p>
<ul>
<li><p>Having the easily found documentation about how to add plugin support is really useful. Most of contributions were pretty straightforward, but I did end up searching for commits to get a sense of preferred workflow.</p></li>
<li><p>Having the ability to link new highlight groups to existing ones makes contributing considerably easier. I understand its possible absence, but nevertheless.</p></li>
<li><p>Having explicit support for many plugins really helps with adding new ones. It adds more information about design principles of color scheme.</p></li>
<li><p>My two personal favorites from aesthetic point of view are ‘Terafox’ from ‘EdenEast/nightfox.nvim’ and ‘sainnhe/everforest’. This even prompted me to create a new color scheme for ‘mini.nvim’ which I am currently testing.</p></li>
</ul>
<p>Hope it was interesting. Also, please consider adding similar ‘mini.nvim’ explicit support for other color schemes (yours or ones you are using). Thanks!</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2022-07-20-i-contributed-to-toprated-neovim-color-schemes.html</guid>
  <pubDate>Wed, 20 Jul 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>StyLua now supports collapsing simple statements</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2022-07-07-stylua-now-supports-collapsing-simple-statements.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/vtdmry/stylua_now_supports_collapsing_simple_statements/">posted on Reddit</a></em></p>
<p>Starting from version 0.14.0, <a href="https://github.com/JohnnyMorganz/StyLua">StyLua</a> (<em>the</em> Lua code formatter in Neovim world) implements option <code>collapse_simple_statement</code>. From release notes:</p>
<blockquote class="blockquote">
<p>It can take the values <code>Never</code> (default), <code>FunctionOnly</code>, <code>ConditionalOnly</code> or <code>Always</code>. When enabled, “simple” functions or if statements (ones where they only return a value or have a simple statement such as a function call) will be collapsed onto a single line where possible.</p>
</blockquote>
<p>So now with <code>collapse_simple_statement = "Always"</code> instead of this …</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">f</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb1-2">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span></span>
<span id="cb1-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-4"></span>
<span id="cb1-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">g</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb1-6">  f<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb1-7"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-8"></span>
<span id="cb1-9"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">is_bad</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-10">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span></span>
<span id="cb1-11"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-12"></span>
<span id="cb1-13"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">is_good</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb1-14">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">a</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb1-15"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div></div>
<p>… it will be formatted as …</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">f</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb2-2"></span>
<span id="cb2-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">g</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> f<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb2-4"></span>
<span id="cb2-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">is_bad</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb2-6"></span>
<span id="cb2-7"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">is_good</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">a</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div></div>
<p>This is great news for Neovim plugin authors and general users as this type of code is very common. Having it on single line improves readability (in my opinion).</p>
<p>I happily switched to this option. Although using 120 width seems to be quite high sometimes in these cases, so I might start using 100 or even 80.</p>
<p>(Note: I am not an author, <a href="https://github.com/JohnnyMorganz">JohnnyMorganz</a> is. He is a thoughtful creator and maintainer of StyLua.).</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2022-07-07-stylua-now-supports-collapsing-simple-statements.html</guid>
  <pubDate>Thu, 07 Jul 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Useful functions to explore Lua objects</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2021-08-20-useful-functions-to-explore-lua-objects.html</link>
  <description><![CDATA[ 





<p><em>Originally <a href="https://www.reddit.com/r/neovim/comments/p84iu2/useful_functions_to_explore_lua_objects/">posted on Reddit</a></em></p>
<p>To look at contents of Lua object <code>a</code> you can execute <code>:lua print(vim.inspect(a))</code>. This will print content inside command line. Following <a href="https://github.com/nanotee/nvim-lua-guide#tips-3">nvim-lua-guide’s tip</a> (<strong>edit</strong>: after making PR to nvim-lua-guide, it is currently in sync with edited version of this post), this can be wrapped into <code>_G.dump()</code> function and become <code>:lua dump(a)</code> (and even <code>:lua dump(a, b)</code>). However, in most cases it doesn’t print <code>nil</code>, which is a shame. This can be solved by sticking with single argument instead of <code>...</code>, but it proved useful in certain cases. So I came up with alternative implementation and decided to share with everyone (<strong>edit</strong>: renamed previous <code>dump</code> for a somewhat more pleasant name):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">_G</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>put<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(...)</span></span>
<span id="cb1-2">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">objects</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb1-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">i</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">...)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span></span>
<span id="cb1-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">v</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">i</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">...)</span></span>
<span id="cb1-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table.insert</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">objects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>inspect<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">v</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span></span>
<span id="cb1-6">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb1-7"></span>
<span id="cb1-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table.concat</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">objects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span></span>
<span id="cb1-9">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">...</span></span>
<span id="cb1-10"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div></div>
<p>Now <code>:lua put(nil)</code> will actually print <code>nil</code> instead of just doing nothing. Also <code>:lua put(nil, 1, nil)</code> will print <code>nil</code>, <code>1</code>, <code>nil</code> on separate lines (instead of <code>nil 1</code>).</p>
<p>But there is more. Sometimes you want to explore a big nested table (like LSP related stuff). It would be nicer to explore as regular text. And so <code>put_text()</code> was born:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">_G</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>put_text<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(...)</span></span>
<span id="cb2-2">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">objects</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb2-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">i</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'#'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">...)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span></span>
<span id="cb2-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">v</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">select</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">i</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">...)</span></span>
<span id="cb2-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table.insert</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">objects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>inspect<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">v</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span></span>
<span id="cb2-6">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb2-7"></span>
<span id="cb2-8">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lines</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>split<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table.concat</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">objects</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">),</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb2-9">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lnum</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">api</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>nvim_win_get_cursor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span></span>
<span id="cb2-10">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vim</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">fn</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>append<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">lnum</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lines</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb2-11">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">...</span></span>
<span id="cb2-12"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div></div>
<p>When called, this will try to add inspection content under the current cursor position. So now if you want to conveniently explore all fields of <code>vim.loop</code>, just execute <code>:lua put_text(vim.loop)</code>.</p>
<p>Hope this will help somebody.</p>
<p>P.S.: To use <code>put()</code> and <code>put_text()</code> inside Neovim session, you need to source this Lua code. Easiest way is to put it inside Lua files sourced on startup (‘init.lua’, for example), and you are good to go.</p>



 ]]></description>
  <category>neovim</category>
  <category>reddit</category>
  <guid>https://echasnovski.com/blog/2021-08-20-useful-functions-to-explore-lua-objects.html</guid>
  <pubDate>Fri, 20 Aug 2021 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Count bounces in table tennis world record</title>
  <dc:creator>Evgeni Chasnovski</dc:creator>
  <link>https://echasnovski.com/blog/2020-05-11-count-bounces-in-table-tennis-world-record.html</link>
  <description><![CDATA[ 





<section id="prologue" class="level1">
<h1>Prologue</h1>
<p>Dan Ives is no stranger to participating in “prolonged” table tennis activities and capturing it on camera. He once <a href="https://www.youtube.com/watch?v=6mt4_8Rd5tg">said “table tennis” 100,000 times</a>, which took him about 15 hours. With his father Peter he also set a <a href="https://www.youtube.com/watch?v=cfp5SEV3Bns">world record for the longest table tennis rally</a> which lasted for 8 hours, 40 minutes, and 10 seconds (8h40m10s as a shorter description of time period).</p>
<p>On May 7th 2020 Dan made a successful attempt to beat a world record for the <a href="https://www.guinnessworldrecords.com/world-records/table-tennis-bat-and-ball-control-duration?fb_comment_id=784092958310554_1433556316697545">longest duration to control a table tennis ball with a bat</a>. He surpassed current record duration of 5h2m37s by 18 minutes and 27 seconds for a total of 5h21m4s. He also live streamed the event on his <a href="https://www.youtube.com/channel/UC_368FANcHhkhZ7oVqkW86A">“TableTennisDaily” YouTube channel</a>, which later <a href="https://www.youtube.com/watch?v=nkgzLeNocb0">was uploaded</a> (important note for the future: this video is a result of live stream and not a “shot and uploaded” one). During cheering for Dan in real time I got curious about actual number of bounces he made.</p>
<p><strong>And thus the quest begins</strong>.</p>
<p>As counting manually is error-prone and extremely boring, I decided to do this programmatically. The idea of solution is straightforward: somehow extract audio from the world record video, detect bounces (as they have distinctive sound) and count them.</p>
<p>This post consists from two parts (if you just want to know a total count, skip right to Epilogue):</p>
<ul>
<li><strong>Detecting</strong> section describes technical details about how I approached the task of detecting bounces.</li>
<li><strong>Counting</strong> section describes difficulties I had to overcome to produce a (reasonably accurate) count of bounces.</li>
</ul>
<p>For more technical details you can look at <a href="https://github.com/echasnovski/curiosity-projects/tree/master/ttd-world-record">this project’s Git repository</a>.</p>
</section>
<section id="detecting" class="level1">
<h1>Detecting</h1>
<p>Detecting was done in two steps: get audio of world record and detect bounces.</p>
<p>I used the following tools on Ubuntu 18.04 (in order of their usage; Python packages probably best to be installed in a separate environment):</p>
<ul>
<li><a href="https://github.com/soimort/you-get">you-get</a> to download video with the lowest video quality.</li>
<li><a href="https://www.ffmpeg.org/">ffmpeg</a> to extract audio from downloaded video and split it into 1 hour chunks (except the last one). Splitting was done because of insufficient amount of RAM I have in order to analyze the whole audio file. <strong>Note</strong> that having these splits means that some bounces on the joints between consecutive audio-chunks won’t be detected.</li>
<li><a href="https://github.com/librosa/librosa">librosa</a> to detect beats that were in the period from 00:01:14 to 05:20:15 (times of first and last bounces). Timestamps of those beats were considered to be timestamps of bounces.</li>
</ul>
</section>
<section id="counting" class="level1">
<h1>Counting</h1>
<p>So the total number of <strong>detected</strong> bounces is 49923 with an average tempo of ~156.5 bounces per minute. Ant <strong>note</strong> that this doesn’t include possibly missing bounces due to splitting audio in 1 hour chunks, which introduced 5 joints between them.</p>
<p>However, YouTube footage is not a “preshot and uploaded” one, but is a direct output of live stream. This resulted into some missing footage. Total time of record based on video footage is 5h19m1s (from 00:01:14 to 05:20:15 video timestamps). On the other hand, tablet, responsible for time tracking, shows total time of 5h21m4s (from 00:00:03 to 05:21:07 at corresponding video timestamps). So there is missing 2m3s of actual bouncing. They were results of video jumps due to, most probably, internet connection issues (I encourage everyone to believe in Dan’s honesty):</p>
<ul>
<li><a href="https://youtu.be/nkgzLeNocb0?t=9144">From 02:32:24 to 02:32:25</a> in footage time there is a jump in “tablet time” from 02:31:13 to 02:31:24. This is a gap of 10 seconds.</li>
<li><a href="https://youtu.be/nkgzLeNocb0?t=9161">From 02:32:41 to 02:32:42</a> - tablet jumps from 02:31:41 to 02:32:12. Gap of 30 seconds.</li>
<li><a href="https://youtu.be/nkgzLeNocb0?t=10157">From 02:49:17 to 02:49:18</a> - tablet jumps from 02:48:48 to 02:48:59. Gap of 10 seconds.</li>
<li><a href="https://youtu.be/nkgzLeNocb0?t=10169">From 02:49:29 to 02:49:30</a> - tablet jumps from 02:49:10 to 02:49:41. Gap of 30 seconds.</li>
<li><a href="https://youtu.be/nkgzLeNocb0?t=10529">From 02:55:29 to 02:55:30</a> - tablet jumps from 02:55:41 to 02:55:52. Gap of 10 seconds.</li>
<li><a href="https://youtu.be/nkgzLeNocb0?t=10537">From 02:55:37 to 02:55:38</a> - tablet jumps from 02:55:59 to 02:56:30. Gap of 30 seconds.</li>
<li>The rest 3 seconds seems to be the result of my rounding and possibly some very small jumps.</li>
</ul>
<p>Close video timestamps and systematic length of jumps are another indicators of internet connection issues.</p>
<p>Knowing that there is 2m3s of footage missing and that average tempo was ~156.5 bounces per minute, we can add 321 bounces to detected ones.</p>
<p>Finally, the <strong>total number of bounces in Dan Ives world record can be estimated as 50244 bounces</strong> (error should be less than 100 bounces for sure).</p>
<p><strong>And thus the quest ends</strong>.</p>
</section>
<section id="epilogue" class="level1">
<h1>Epilogue</h1>
<ul>
<li>Tools such as ‘you-get’, ‘ffmpeg’, and ‘librosa’ (and Python language in general) make a task as abstract as “count number of table tennis ball bounces in 5 and a half hour long YouTube video” reasonably easy.</li>
<li>During his 5 hours, 21 minutes, and 4 seconds of world record, Dan Ives made around 50244 bounces (with error less than 100 bounces in either side).</li>
</ul>
<div class="callout callout-style-default callout-note callout-titled" title="sessionInfo()">
<div class="callout-header d-flex align-content-center collapsed" data-bs-toggle="collapse" data-bs-target=".callout-1-contents" aria-controls="callout-1" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Note</span>sessionInfo()
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-1" class="callout-1-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<pre><code>## R version 4.0.0 (2020-04-24)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.4 LTS
##
## Matrix products: default
## BLAS:   /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3
## LAPACK: /usr/lib/x86_64-linux-gnu/libopenblasp-r0.2.20.so
##
## locale:
##  [1] LC_CTYPE=ru_UA.UTF-8       LC_NUMERIC=C
##  [3] LC_TIME=ru_UA.UTF-8        LC_COLLATE=ru_UA.UTF-8
##  [5] LC_MONETARY=ru_UA.UTF-8    LC_MESSAGES=ru_UA.UTF-8
##  [7] LC_PAPER=ru_UA.UTF-8       LC_NAME=C
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C
## [11] LC_MEASUREMENT=ru_UA.UTF-8 LC_IDENTIFICATION=C
##
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base
##
## loaded via a namespace (and not attached):
##  [1] compiler_4.0.0  magrittr_1.5    bookdown_0.18   tools_4.0.0
##  [5] htmltools_0.4.0 yaml_2.2.1      Rcpp_1.0.4.6    stringi_1.4.6
##  [9] rmarkdown_2.1   blogdown_0.18   knitr_1.28      stringr_1.4.0
## [13] digest_0.6.25   xfun_0.13       rlang_0.4.6     evaluate_0.14</code></pre>
</div>
</div>
</div>


</section>

 ]]></description>
  <category>python</category>
  <category>curiosity-project</category>
  <category>questionflow</category>
  <guid>https://echasnovski.com/blog/2020-05-11-count-bounces-in-table-tennis-world-record.html</guid>
  <pubDate>Mon, 11 May 2020 00:00:00 GMT</pubDate>
</item>
</channel>
</rss>
