115 lines
10 KiB
HTML
115 lines
10 KiB
HTML
<!doctype html>
|
|
<html lang="en"><head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
<link rel="shortcut icon" href="https://nonsense.dymc.win/favicon.ico">
|
|
<link id="stylesheet" rel="stylesheet" href="/css/light.css">
|
|
|
|
<link rel="canonical" href="https://nonsense.dymc.win/so-you-want-to-write-a-neovim-plugin-with-lua/" />
|
|
<title>So you want to write a neovim plugin with lua</title>
|
|
</head>
|
|
<body><header id="banner">
|
|
<nav class="navbar">
|
|
|
|
<a href="https://nonsense.dymc.win/" class="home">🏠</a>
|
|
|
|
<a
|
|
href="/info/"
|
|
title="👋"
|
|
>👋</a
|
|
><a
|
|
href="/search/"
|
|
title="🔎"
|
|
>🔎</a
|
|
>
|
|
|
|
<button id="toggle-button" class="toggle-button" onclick="toggleTheme()">🌚</button>
|
|
</nav>
|
|
</header>
|
|
<main id="content">
|
|
<article>
|
|
<header id="post-header">
|
|
<h2>So you want to write a neovim plugin with lua</h2>
|
|
<div>
|
|
<p>April 6, 2024</p>
|
|
</div>
|
|
</header><p>I’ve recently been messing around with writing neovim plugins.
|
|
When I initially got going I found it a little tricky to know how to get started.
|
|
There’s the <a href="https://neovim.io/doc">official neovim docs</a> which are great; but in my beginner experience exhaustive to the point of slight impenetrability.
|
|
Beyond that, the thing I found most useful was simply reading the source of some popular plugins to get an idea of how things worked.
|
|
I would recommend sticking to plugins with a smaller scope though.</p>
|
|
<p>As a demostrative MVP (minimal viable plugin) jumping-off-point, I’m going to make a very simple note-taking plugin.
|
|
It will provide a command to neovim which when run opens a file titled with the date and time in a specific notes directory.
|
|
Vamos.</p>
|
|
<p>This is what you will want your directory structure to look like.</p>
|
|
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">├── lua
|
|
</span></span><span class="line"><span class="cl">│ └── note
|
|
</span></span><span class="line"><span class="cl">│ └── init.lua
|
|
</span></span><span class="line"><span class="cl">└── plugin
|
|
</span></span><span class="line"><span class="cl"> └── note.vim
|
|
</span></span></code></pre></div><p>The <code>plugin/note.vim</code> file will look like this.</p>
|
|
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vim" data-lang="vim"><span class="line"><span class="cl"><span class="nx">command</span><span class="p">!</span> <span class="nx">Note</span> <span class="nx">lua</span> <span class="nx">require</span><span class="p">(</span><span class="s2">"note"</span><span class="p">)</span>.<span class="nx">main</span><span class="p">()</span>
|
|
</span></span></code></pre></div><p>This creates a custom command <code>Note</code> which when run will call a lua function.
|
|
Now on to where that function and the meat of the plugin logic will live: the <code>lua/note/init.lua</code> file.
|
|
With more complex plugins this section will often be split into many files but we’ve just got one here as it’s so simple.</p>
|
|
<p>First things first we create a plugin object.</p>
|
|
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="cl"><span class="kd">local</span> <span class="n">note</span> <span class="o">=</span> <span class="p">{}</span>
|
|
</span></span></code></pre></div><p>Then we will define some default options for the plugin in a table.
|
|
These are variables you want the user to be able to change when they call the setup function.</p>
|
|
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="cl"><span class="kd">local</span> <span class="n">defaults</span> <span class="o">=</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="n">note_directory</span> <span class="o">=</span> <span class="s2">"~/notes/"</span><span class="p">,</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="n">date_format</span> <span class="o">=</span> <span class="s2">"%Y-%m-%d %H:%M"</span><span class="p">,</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="n">file_extension</span> <span class="o">=</span> <span class="s2">".md"</span><span class="p">,</span>
|
|
</span></span><span class="line"><span class="cl"><span class="p">}</span>
|
|
</span></span></code></pre></div><p>Next we need the setup function.
|
|
This takes the user’s options and merges them with our default options.</p>
|
|
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="cl"><span class="kr">function</span> <span class="nc">note</span><span class="p">.</span><span class="nf">setup</span><span class="p">(</span><span class="n">user_options</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="n">options</span> <span class="o">=</span> <span class="n">vim.tbl_deep_extend</span><span class="p">(</span><span class="s2">"force"</span><span class="p">,</span> <span class="n">defaults</span><span class="p">,</span> <span class="n">user_options</span> <span class="ow">or</span> <span class="p">{})</span>
|
|
</span></span><span class="line"><span class="cl"><span class="kr">end</span>
|
|
</span></span></code></pre></div><p>This is the main function where the magic happens.</p>
|
|
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="cl"><span class="kr">function</span> <span class="nc">note</span><span class="p">.</span><span class="nf">main</span><span class="p">()</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="kd">local</span> <span class="n">dir</span> <span class="o">=</span> <span class="n">options.note_directory</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="kd">local</span> <span class="n">name</span> <span class="o">=</span> <span class="n">os.date</span><span class="p">(</span><span class="n">options.date_format</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="kd">local</span> <span class="n">ext</span> <span class="o">=</span> <span class="n">options.file_extension</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="kd">local</span> <span class="n">filename</span> <span class="o">=</span> <span class="n">string.format</span><span class="p">(</span><span class="s2">"%s%s%s"</span><span class="p">,</span> <span class="n">dir</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">ext</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="kd">local</span> <span class="n">command</span> <span class="o">=</span> <span class="n">string.format</span><span class="p">(</span><span class="s2">"edit %s"</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="n">vim.api</span><span class="p">.</span><span class="n">nvim_command</span><span class="p">(</span><span class="n">command</span><span class="p">)</span>
|
|
</span></span><span class="line"><span class="cl"><span class="kr">end</span>
|
|
</span></span></code></pre></div><p>Finally we return the plugin obect.</p>
|
|
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="cl"><span class="kr">return</span> <span class="n">note</span>
|
|
</span></span></code></pre></div><p>At this point you should have a working plugin :)
|
|
As a little coda, this is how you can use your fancy new plugin using <a href="https://github.com/folke/lazy.nvim/">lazy.nvim</a>.</p>
|
|
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="cl"><span class="n">require</span><span class="p">(</span><span class="s2">"lazy"</span><span class="p">).</span><span class="n">setup</span><span class="p">({</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="c1">-- local</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="n">dir</span> <span class="o">=</span> <span class="s2">"~/neovim-note-plugin"</span><span class="p">,</span>
|
|
</span></span><span class="line"><span class="cl">
|
|
</span></span><span class="line"><span class="cl"> <span class="c1">-- github</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="c1">-- "me/neovim-note-plugin",</span>
|
|
</span></span><span class="line"><span class="cl">
|
|
</span></span><span class="line"><span class="cl"> <span class="c1">-- alternative non github hosting</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="c1">-- url = "https://git.example.com/me/neovim note-plugin",</span>
|
|
</span></span><span class="line"><span class="cl">
|
|
</span></span><span class="line"><span class="cl"> <span class="n">config</span> <span class="o">=</span> <span class="n">fucntion</span><span class="p">()</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="n">require</span><span class="p">(</span><span class="s2">"note"</span><span class="p">).</span><span class="n">setup</span><span class="p">({</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="n">file_extension</span> <span class="o">=</span> <span class="s2">".org"</span><span class="p">,</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">})</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="kr">end</span><span class="p">,</span>
|
|
</span></span><span class="line"><span class="cl">
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
|
|
</span></span><span class="line"><span class="cl"><span class="p">})</span>
|
|
</span></span></code></pre></div><p>Hope you’ve enjoyed.</p>
|
|
</article>
|
|
</main>
|
|
<footer id="footer">
|
|
<small>
|
|
made with <a href="https://gohugo.io">hugo</a>
|
|
</small>
|
|
|
|
<script src="/js/search.js"></script>
|
|
<script src="/js/toggle.js"></script>
|
|
</footer>
|
|
|
|
</body>
|
|
</html>
|