<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title> - Stuff</title>
    <link rel="self" type="application/atom+xml" href="https://schilk.co/blog/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://schilk.co/blog/"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-09-08T00:00:00+00:00</updated>
    <id>https://schilk.co/blog/atom.xml</id>
    <entry xml:lang="en">
        <title>NVIM: Writing Complex Macros &#x2F; Transforms in Lua</title>
        <published>2026-09-06T00:00:00+00:00</published>
        <updated>2026-09-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Philipp Schilk
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://schilk.co/blog/nvim-lua-macros/"/>
        <id>https://schilk.co/blog/nvim-lua-macros/</id>
        
        <content type="html" xml:base="https://schilk.co/blog/nvim-lua-macros/">&lt;p&gt;(Neo)Vim&#x27;s macro system is a very powerful tool for quickly applying
a sequence of transformations over and over again. The upcoming native
multicursor support in neovim is also shaping up to be an extremely ergonomic
and intuitive way of performing large, bulk edits very quickly.&lt;&#x2F;p&gt;
&lt;p&gt;However, in some rare cases, I find myself wanting a more generic way of
expressing such text tranforms, with support for conditionals and logic.
Something such as:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;If a given line contains the substring &quot;XYZ&quot; do one set of transformations,
if it contains &quot;ABC&quot; do another set of transformations, and if it contains
&quot;123&quot; delete it altogether.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This is especially the case when writing RTL in (System)Verilog, where I often
find myself needing to do structured and systematic text transformations.&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately, neovim is configured and scripted in Lua, which makes this rather
simple to implement.&lt;&#x2F;p&gt;
&lt;p&gt;This blog post contains a short guide on how to write transforms as lua
functions, explains how to register them as bindings or commands, and includes
a few real-life examples of such transforms that I have found useful at the end.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;wrapper-functions&quot;&gt;Wrapper Functions&lt;&#x2F;h2&gt;
&lt;p&gt;I rely on two simple helper functions in my neovim configuration.&lt;&#x2F;p&gt;
&lt;p&gt;The first, given a Lua text-transform function that both accepts and returns
a list(-like table) of lines, returns a function which grabs the current selection,
applies the transform function, and replaces the current selection with its output:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;-- Wrap a text-transformation function to make it simple to register&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;-- it as a visual mode text-transform mapping.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; visual_process_selection_lines&lt;&#x2F;span&gt;&lt;span&gt;(processing_func)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  return function&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    -- Retrieve selected lines:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; pos1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;getpos&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;v&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; pos2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;getpos&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;.&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; lines&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;getregion&lt;&#x2F;span&gt;&lt;span&gt;(pos1, pos2, { type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt; &amp;quot;V&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    -- Process selected lines using the provided function:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; processed_lines&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; processing_func&lt;&#x2F;span&gt;&lt;span&gt;(lines)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    -- Determine buffer and (ordered) line range selected for replacement:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; bufn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;nvim_get_current_buf&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; line_first&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; math.min&lt;&#x2F;span&gt;&lt;span&gt;(pos1[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;], pos2[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; line_last&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; math.max&lt;&#x2F;span&gt;&lt;span&gt;(pos1[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;], pos2[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    -- Replace selected lines:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;nvim_buf_set_lines&lt;&#x2F;span&gt;&lt;span&gt;(bufn, line_first&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;, line_last, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span&gt;, processed_lines)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    -- Exit visual mode:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; keys&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;nvim_replace_termcodes&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;&amp;lt;ESC&amp;gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;nvim_feedkeys&lt;&#x2F;span&gt;&lt;span&gt;(keys, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;m&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The second, again given a Lua text-transform function that both accepts and
returns a list(-like table) of lines, returns a function that accepts an &lt;code&gt;opts&lt;&#x2F;code&gt;
table as given to a &lt;code&gt;nvim_create_user_command&lt;&#x2F;code&gt; callback, and again grabs the
current selection, applies the transform function, and replaces the current
selection with its output:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;-- Wrap a text-transformation function to make it simple to register&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;-- it as a text-transforming user command.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; cmd_process_selection_lines&lt;&#x2F;span&gt;&lt;span&gt;(processing_func)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  return function&lt;&#x2F;span&gt;&lt;span&gt;(opts)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    -- Get the range from the command (line1 and line2 are 1-indexed)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; line_start&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; opts.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;line1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; line_end&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; opts.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;line2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    -- Retrieve selected lines (nvim_buf_get_lines uses 0-indexed, exclusive end)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; bufn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;nvim_get_current_buf&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; lines&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;nvim_buf_get_lines&lt;&#x2F;span&gt;&lt;span&gt;(bufn, line_start&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;, line_end, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    -- Process selected lines using the provided function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; processed_lines&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; processing_func&lt;&#x2F;span&gt;&lt;span&gt;(lines)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    -- Replace selected lines (nvim_buf_set_lines uses 0-indexed)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;nvim_buf_set_lines&lt;&#x2F;span&gt;&lt;span&gt;(bufn, line_start&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;, line_end, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;false&lt;&#x2F;span&gt;&lt;span&gt;, processed_lines)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;example-line-numbers&quot;&gt;Example: Line Numbers&lt;&#x2F;h2&gt;
&lt;p&gt;Using the utility functions above, we can take any Lua function that accepts
and returns a list(-like table) of strings, and easily register it as a
visual-mode mapping and user command to apply it to any text we are editing.
For example, consider the short example function below, which prepends a line-number
to each input line:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;local function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; prepend_line_no&lt;&#x2F;span&gt;&lt;span&gt;(lines)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  local&lt;&#x2F;span&gt;&lt;span&gt; result&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span&gt; idx, line&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; ipairs&lt;&#x2F;span&gt;&lt;span&gt;(lines) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;    table.insert&lt;&#x2F;span&gt;&lt;span&gt;(result, idx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; ..&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt; &amp;quot; | &amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span&gt; line)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span&gt; result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can register this function as a visual mode mapping and user command
as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;keymap&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;v&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;gQ&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;visual_process_selection_lines&lt;&#x2F;span&gt;&lt;span&gt;(prepend_line_no), {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  desc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt; &amp;quot;Prepend line numbers&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  silent&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  noremap&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;nvim_create_user_command&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;  &amp;quot;PrependLineNos&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;  cmd_process_selection_lines&lt;&#x2F;span&gt;&lt;span&gt;(prepend_line_no),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  { range&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;, desc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt; &amp;quot;Prepend line numbers&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, by selecting any text in visual mode and pressing &lt;code&gt;gQ&lt;&#x2F;code&gt; or typing &lt;code&gt;:&#x27;&amp;lt;,&#x27;&amp;gt;PrependLineNos&lt;&#x2F;code&gt;,
we can quickly and conveniently apply our &lt;code&gt;prepend_line_no&lt;&#x2F;code&gt; function:&lt;&#x2F;p&gt;
&lt;p&gt;Before:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;This is a sample piece&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;of input text with no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;particular meaning.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1 | This is a sample piece&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2 | of input text with no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3 | particular meaning.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;example-flip-system-verilog-port-directions&quot;&gt;Example: Flip (System)Verilog Port Directions&lt;&#x2F;h2&gt;
&lt;p&gt;I most commonly find myself writing and using such text transforms when
writing RTL code in a language like SystemVerilog.&lt;&#x2F;p&gt;
&lt;p&gt;For example, I often find myself having to change the direction of module
port declarations when routing signals through a hierarchy of modules.
This involves inverting the port direction (&lt;code&gt;input&lt;&#x2F;code&gt; &amp;lt;-&amp;gt; &lt;code&gt;output&lt;&#x2F;code&gt;), and adjusting
the port suffix (&lt;code&gt;*_i&lt;&#x2F;code&gt; &amp;lt;-&amp;gt; &lt;code&gt;*_o&lt;&#x2F;code&gt;, &lt;code&gt;*_ni&lt;&#x2F;code&gt; &amp;lt;-&amp;gt; &lt;code&gt;*_no&lt;&#x2F;code&gt;, ...).&lt;&#x2F;p&gt;
&lt;p&gt;The following Lua function describes this transformation:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; sv_flip_input_output&lt;&#x2F;span&gt;&lt;span&gt;(lines)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  local&lt;&#x2F;span&gt;&lt;span&gt; result&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span&gt; _, line&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; ipairs&lt;&#x2F;span&gt;&lt;span&gt;(lines) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; modified_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; line&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    -- Check if line contains input or output (ignoring leading whitespace)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    local&lt;&#x2F;span&gt;&lt;span&gt; trimmed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; line&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;^%s*(.-)%s*$&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; trimmed&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;^input%s&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;      -- Replace input with output&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      modified_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; line&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;gsub&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;(%s*)input(%s)&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;%1output%2&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      modified_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; modified_line&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;gsub&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_i(%s*[,%s])&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_o%1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      modified_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; modified_line&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;gsub&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_i$&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_o&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      modified_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; modified_line&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;gsub&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_ni(%s*[,%s])&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_no%1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      modified_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; modified_line&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;gsub&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_ni$&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_no&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    elseif&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; trimmed&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;^output%s&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;      -- Replace output with input&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      modified_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; line&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;gsub&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;(%s*)output(%s)&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;%1input%2&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      modified_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; modified_line&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;gsub&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_o(%s*[,%s])&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_i%1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      modified_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; modified_line&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;gsub&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_o$&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_i&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      modified_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; modified_line&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;gsub&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_no(%s*[,%s])&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_ni%1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      modified_line&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; modified_line&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;gsub&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_no$&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;_ni&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;    table.insert&lt;&#x2F;span&gt;&lt;span&gt;(result, modified_line)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span&gt; result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Consider the following example input:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;verilog&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt; logic clk_i,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt; logic rst_ni,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; === I$ interface ==&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt; logic icache_ready_i,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;output&lt;&#x2F;span&gt;&lt;span&gt; icache_req_t icache_req_o,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt; icache_rsp_t icache_rsp_i,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; === Instr. Queue interface ==&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt; logic insn_q_ready_i, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; A trailing comment!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;output&lt;&#x2F;span&gt;&lt;span&gt; logic [Param.MAX_INSN_PER_FETCH&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] insn_q_entry_valid_o,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After applying the transform above, we are left with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;verilog&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;output&lt;&#x2F;span&gt;&lt;span&gt; logic clk_o,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;output&lt;&#x2F;span&gt;&lt;span&gt; logic rst_no,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; === I$ interface ==&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;output&lt;&#x2F;span&gt;&lt;span&gt; logic icache_ready_o,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt; icache_req_t icache_req_i,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;output&lt;&#x2F;span&gt;&lt;span&gt; icache_rsp_t icache_rsp_o,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; === Instr. Queue interface ==&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;output&lt;&#x2F;span&gt;&lt;span&gt; logic insn_q_ready_o, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; A trailing comment!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt; logic [Param.MAX_INSN_PER_FETCH&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] insn_q_entry_valid_i,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;example-system-verilog-module-instantiation&quot;&gt;Example: (System)Verilog Module Instantiation&lt;&#x2F;h2&gt;
&lt;p&gt;As a more complex (but very useful!) example, consider the task
of instantiating a module in SystemVerilog.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;markdown-alert-note&quot;&gt;
&lt;p&gt;For the non-hardware people reading this:&lt;&#x2F;p&gt;
&lt;p&gt;A module declaration roughly corresponds to a function declaration, while
a module instantiation roughly corresponds to a function call.&lt;&#x2F;p&gt;
&lt;p&gt;In SystemVerilog, such modules tend to have many ports (function arguments),
and the syntax for declaring and instantiating (calling) a module is very
different.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Consider the following simple module declaration:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;verilog&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;module&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; gshare&lt;&#x2F;span&gt;&lt;span&gt; #(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  parameter&lt;&#x2F;span&gt;&lt;span&gt; fe2_cfg_t Cfg,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  parameter&lt;&#x2F;span&gt;&lt;span&gt; type ft_t,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  parameter&lt;&#x2F;span&gt;&lt;span&gt; type ftq_entry_t,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  parameter&lt;&#x2F;span&gt;&lt;span&gt; type gshare_state_info_t,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  parameter&lt;&#x2F;span&gt;&lt;span&gt; type bp_train_info_t,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  parameter&lt;&#x2F;span&gt;&lt;span&gt; type ghist_update_t&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  input&lt;&#x2F;span&gt;&lt;span&gt; logic clk_i,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  input&lt;&#x2F;span&gt;&lt;span&gt; logic rst_ni,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &#x2F;&#x2F; Prediction Inputs:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  input&lt;&#x2F;span&gt;&lt;span&gt; logic [Cfg.VLEN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] addr_i,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  input&lt;&#x2F;span&gt;&lt;span&gt; [Cfg.GSHARE_HIST_LEN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] ghist_i,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &#x2F;&#x2F; Prediction:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  output&lt;&#x2F;span&gt;&lt;span&gt; gshare_state_info_t state_o,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  output&lt;&#x2F;span&gt;&lt;span&gt; logic pred_taken_o,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  output&lt;&#x2F;span&gt;&lt;span&gt; logic hit_o,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &#x2F;&#x2F; BP Training info input:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  input&lt;&#x2F;span&gt;&lt;span&gt; logic bp_train_info_valid_i,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  input&lt;&#x2F;span&gt;&lt;span&gt; bp_train_info_t bp_train_info_i,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  input&lt;&#x2F;span&gt;&lt;span&gt; [Cfg.GSHARE_HIST_LEN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;] bp_train_ghist_i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;My module instantiation macro, whose full code you can find
&lt;a href=&quot;https:&#x2F;&#x2F;schilk.co&#x2F;blog&#x2F;nvim-lua-macros&#x2F;module_instant&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;,
converts such a declaration into an (almost) fully-formed module
instantiation:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;verilog&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;module&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; gshare&lt;&#x2F;span&gt;&lt;span&gt; #(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .Cfg( ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .ft_t( ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .ftq_entry_t( ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .gshare_state_info_t( ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .bp_train_info_t( ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .ghist_update_t( )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .clk_i( ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .rst_ni( ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &#x2F;&#x2F; Prediction Inputs:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .addr_i( ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .ghist_i( ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &#x2F;&#x2F; Prediction:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .state_o( ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .pred_taken_o( ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .hit_o( ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;  &#x2F;&#x2F; BP Training info input:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .bp_train_info_valid_i( ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .bp_train_info_i( ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .bp_train_ghist_i( )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This allows me to quickly copy the module declaration to the place I want to
instantiate it, and do the bulk of the tedious editing with a single mapping.&lt;&#x2F;p&gt;
&lt;p&gt;You can find the full transform function to achieve this
&lt;a href=&quot;https:&#x2F;&#x2F;schilk.co&#x2F;blog&#x2F;nvim-lua-macros&#x2F;module_instant&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;changes&quot;&gt;Changes&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;2026-09-08&lt;&#x2F;code&gt;:
&lt;ul&gt;
&lt;li&gt;Simplified + renamed &lt;code&gt;visual_process_selection&lt;&#x2F;code&gt; to &lt;code&gt;visual_process_selection_lines&lt;&#x2F;code&gt;. Thanks &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;neovim&#x2F;comments&#x2F;1w8w48y&#x2F;comment&#x2F;p8bwomt&#x2F;?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button&quot;&gt;justinmk&lt;&#x2F;a&gt;!&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Progressive encoding and decoding of &#x27;repeated&#x27; protobuffer fields.</title>
        <published>2026-01-24T00:00:00+00:00</published>
        <updated>2026-02-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Philipp Schilk
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://schilk.co/blog/protobuffer-repeat-append/"/>
        <id>https://schilk.co/blog/protobuffer-repeat-append/</id>
        
        <content type="html" xml:base="https://schilk.co/blog/protobuffer-repeat-append/">&lt;blockquote class=&quot;markdown-alert-note&quot;&gt;
&lt;p&gt;This post assumes a basic familiarity with the user-facing aspects of
Google&#x27;s open-source &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;protobuf.dev&#x2F;&quot;&gt;protobuffer&lt;&#x2F;a&gt; suite.&lt;&#x2F;p&gt;
&lt;p&gt;In short, protobuffer allows you to define a set of messages which you
would like to exchange using a simple DSL in a &lt;code&gt;.proto&lt;&#x2F;code&gt; file.
Using this description, the &lt;code&gt;protoc&lt;&#x2F;code&gt; compiler (or a number of alternative
implementations) can generate encoders and decoders for these messages
in a large number of different programming languages (see
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;protobuf.dev&#x2F;getting-started&#x2F;&quot;&gt;here&lt;&#x2F;a&gt; and
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;protocolbuffers&#x2F;protobuf&#x2F;blob&#x2F;main&#x2F;docs&#x2F;third_party.md&quot;&gt;here&lt;&#x2F;a&gt;),
all of which share a common binary message (&quot;wire&quot;) format.&lt;&#x2F;p&gt;
&lt;p&gt;If you are curious, have a look at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;protobuf.dev&quot;&gt;protobuf.dev&lt;&#x2F;a&gt; for
documentation and tutorials.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;motivation-interfacing-with-perfetto&quot;&gt;Motivation: Interfacing with Perfetto&lt;&#x2F;h2&gt;
&lt;p&gt;I have found Google&#x27;s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;perfetto.dev&quot;&gt;&lt;em&gt;Perfetto&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; trace viewer to be a really
useful tool to visualize arbitrary time-based traces by converting them
into the protobuffer-based format that Perfetto uses.
This is how both &lt;a href=&quot;https:&#x2F;&#x2F;schilk.co&#x2F;projects&#x2F;tonbandgeraet&#x2F;&quot;&gt;Tonbandgerät&lt;&#x2F;a&gt; and
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;schilkp&#x2F;circumspect&quot;&gt;CircumSpect&lt;&#x2F;a&gt; work.&lt;&#x2F;p&gt;
&lt;p&gt;In particular, Perfetto traces are a very long sequence of individual &lt;code&gt;TracePacket&lt;&#x2F;code&gt;
messages, which describe the tracks and the events on them.
What follows below is a greatly simplified version of this &lt;code&gt;TracePacket&lt;&#x2F;code&gt;
message. The full definition can be found in the Perfetto source code
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;perfetto&#x2F;tree&#x2F;main&#x2F;protos&#x2F;perfetto&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;proto&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; TracePacket&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  optional uint64&lt;&#x2F;span&gt;&lt;span&gt; timestamp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  oneof&lt;&#x2F;span&gt;&lt;span&gt; data {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; Different types of trace packet contents&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    TrackEvent&lt;&#x2F;span&gt;&lt;span&gt; track_event&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 11&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    TrackDescriptor&lt;&#x2F;span&gt;&lt;span&gt; track_descriptor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 60&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;the-challenge-sequential-encoding-and-decoding&quot;&gt;The Challenge: Sequential encoding and decoding&lt;&#x2F;h2&gt;
&lt;p&gt;Especially with CircumSpect, the traces I am generating quickly reach into the
millions of &lt;code&gt;TracePacket&lt;&#x2F;code&gt; messages, and upwards of a gigabyte in size.
This becomes problematic because of the fact that to bundle all these messages
into a single file, Perfetto uses a parent &lt;code&gt;Trace&lt;&#x2F;code&gt; message, which contains all
&lt;code&gt;TracePacket&lt;&#x2F;code&gt;s as a repeated field - the protobuffer equivalent of an array:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;proto&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Trace&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  repeated TracePacket&lt;&#x2F;span&gt;&lt;span&gt; packet&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Unlike in zero-copy frameworks such as &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;capnproto.org&#x2F;&quot;&gt;Cap&#x27;n Proto&lt;&#x2F;a&gt;,
protobuffer&#x27;s serialised format does not double as an in-memory representation.
Therefore, all serialisation and deserialisation operations move and convert
data between a binary buffer containing the wire representation and an
in-memory data structure with which the program interacts.&lt;&#x2F;p&gt;
&lt;p&gt;In short, this means that to serialise a large &lt;code&gt;Trace&lt;&#x2F;code&gt;, the full trace needs
to be in an in-memory representation.
This struct can then be serialised to the binary wire format by the protobuffer
library.
For reference, this looks roughly like the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; Pseudo-rust :)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;pub struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Trace&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    packet&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;TracePacket&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; collect_trace&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    let mut&lt;&#x2F;span&gt;&lt;span&gt; trace&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Trace&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    while&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; not_finished&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; pkt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; TracePacket&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; collect_trace_packet&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        trace&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;packet&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(pkt);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    trace&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;serialise_to_file&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;trace.pftrace&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For a large stream of &lt;code&gt;TracePacket&lt;&#x2F;code&gt;s reaching into the gigabytes, this requires
an incredible amount of memory, or is outright impossible.
Rather, it would be much better if &lt;code&gt;TracePacket&lt;&#x2F;code&gt;s could be written to disk
continuously as they are generated.&lt;&#x2F;p&gt;
&lt;p&gt;Because CircumSpect can post-process traces after they are recorded, I also run
into this problem in the opposite direction:
Instead of having to load a whole trace into memory by deserialising a complete
file into a &lt;code&gt;Trace&lt;&#x2F;code&gt; struct, I would much prefer to be able to read individual
packets, process them, and write them back out to disk.&lt;&#x2F;p&gt;
&lt;p&gt;This is not directly supported by most protobuffer libraries.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;protobuffer-wire-format&quot;&gt;Protobuffer wire format&lt;&#x2F;h2&gt;
&lt;p&gt;To understand how difficult this would be to achieve, we have to have a look at
how a message containing a single repeated message field is serialised.
Fortunately, the protobuf wire format for a simple message like &lt;code&gt;Trace&lt;&#x2F;code&gt; is
not all that complicated!&lt;&#x2F;p&gt;
&lt;p&gt;What follows below is an overview of the aspects of protobuffer encoding that
are relevant for achieving this &quot;streaming&quot; encoding and decoding of a &lt;code&gt;Trace&lt;&#x2F;code&gt;
message.
If you want more detailed information, have a look at the
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;protobuf.dev&#x2F;programming-guides&#x2F;encoding&#x2F;&quot;&gt;official documentation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;varints&quot;&gt;VARINTs&lt;&#x2F;h3&gt;
&lt;p&gt;At the heart of protobuffer encoding sit variable-length (&quot;varlen&quot;) encoded
64-bit integers, referred to as &lt;em&gt;varints&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This is an optimization that builds on the observation that in many applications,
while it is beneficial to support full 32- or 64-bit numbers, most of the time only
small numbers are used.
For example, in protobuffer messages, tags all the way up to

&lt;script type=&quot;math&#x2F;tex&quot;&gt;2^{29} - 1&lt;&#x2F;script&gt;
 are supported, while the majority of messages
have fewer than 100 fields.
If protobuffer were to use a fixed 32-bit field for encoding all tags, most
messages would contain a large number of redundant zeros.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, varints enable us to encode an unsigned number 
&lt;script type=&quot;math&#x2F;tex&quot;&gt;N&lt;&#x2F;script&gt;
 using

&lt;script type=&quot;math&#x2F;tex&quot;&gt;\max{\left\lparen \left\lceil \frac{\log_2(N)}{7} \right\rceil, 1 \right\rparen}&lt;&#x2F;script&gt;

bytes.
This system trades a shorter average message length for a longer worst-case
message size, assuming a relatively high frequency of small values.
For example, any value less than or equal to 127 can be encoded in a single byte, while
the value 
&lt;script type=&quot;math&#x2F;tex&quot;&gt;2^{32}-1&lt;&#x2F;script&gt;
 requires 5 bytes instead of the usual 4.&lt;&#x2F;p&gt;
&lt;p&gt;This is achieved by first splitting the value into 7-bit septets which are each
encoded, starting with the least significant septet, as an 8-bit value consisting
of the septet in the lower bits, and a control bit in the most significant
bit position.
This control bit is set to &lt;code&gt;1&lt;&#x2F;code&gt; if there are more non-zero bits to follow,
or &lt;code&gt;0&lt;&#x2F;code&gt; if this is the last septet with non-zero bits and all following bits
should be assumed to be zero.&lt;&#x2F;p&gt;
&lt;p&gt;For example, consider the 32-bit value &lt;code&gt;0x5&lt;&#x2F;code&gt;. With the scheme above, it is
encoded as a single byte:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    +---&amp;gt; First 7 bits&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ___|___&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;00000101&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+--&amp;gt; No more bits to follow.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The value &lt;code&gt;0xFF&lt;&#x2F;code&gt; requires more than seven bits and therefore is split into two bytes:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    +---&amp;gt; First 7 bits          +---&amp;gt; Next 7 bits&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ___|___                     ___|___&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;11111111                    00000001&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|                           |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+--&amp;gt; More bits to follow.   +--&amp;gt; No more bits to follow.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;basic-message-structure&quot;&gt;Basic message structure&lt;&#x2F;h3&gt;
&lt;p&gt;A protobuffer message is serialised as a simple sequence of key-value pairs, with the
key being used to identify both which field in the message is to follow, and which
encoding scheme it uses.&lt;&#x2F;p&gt;
&lt;p&gt;A field is identified using the &quot;field number&quot; which is specified in the message
description for every field, while the following encoding schemes are supported:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;ID&lt;&#x2F;th&gt;&lt;th&gt;Name&lt;&#x2F;th&gt;&lt;th&gt;Used for&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;VARINT&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;int32&lt;&#x2F;code&gt;, &lt;code&gt;int64&lt;&#x2F;code&gt;, &lt;code&gt;uint32&lt;&#x2F;code&gt;, &lt;code&gt;uint64&lt;&#x2F;code&gt;, &lt;code&gt;sint32&lt;&#x2F;code&gt;, &lt;code&gt;sint64&lt;&#x2F;code&gt;, &lt;code&gt;bool&lt;&#x2F;code&gt;, &lt;code&gt;enum&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;I64&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;fixed64&lt;&#x2F;code&gt;, &lt;code&gt;sfixed64&lt;&#x2F;code&gt;, &lt;code&gt;double&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;LEN&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;string&lt;&#x2F;code&gt;, &lt;code&gt;bytes&lt;&#x2F;code&gt;, embedded messages, packed repeated fields&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;I32&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;fixed32&lt;&#x2F;code&gt;, &lt;code&gt;sfixed32&lt;&#x2F;code&gt;, &lt;code&gt;float&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;small&gt;Table taken from the official protobuffer docs:
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;protobuf.dev&#x2F;programming-guides&#x2F;encoding&#x2F;#cheat-sheet&quot;&gt;protobuf.dev&#x2F;programming-guides&#x2F;encoding&lt;&#x2F;a&gt;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p&gt;These two values are combined into a single 32-bit value, with the lower 3 bits
containing the encoding scheme, and all other bits containing the field number:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(field_number &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span&gt; encoding_id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This 32-bit key is then encoded using the varlen scheme discussed above,
and immediately followed by the encoded field value.&lt;&#x2F;p&gt;
&lt;p&gt;For example, consider a message with the following structure:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;proto&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Msg&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  uint64&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Assume we want to encode an instance of &lt;code&gt;Msg&lt;&#x2F;code&gt; with a value of &lt;code&gt;42&lt;&#x2F;code&gt; for the &lt;code&gt;data&lt;&#x2F;code&gt; field:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; &amp;quot;data&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 42&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Serialised, it looks as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x08 0x2a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The data field has a field number of &lt;code&gt;1&lt;&#x2F;code&gt; and its &lt;code&gt;uint64&lt;&#x2F;code&gt; data type, as is
listed in the table above, is encoded using varint encoding which has an
encoding id of &lt;code&gt;0&lt;&#x2F;code&gt;. Therefore, the key value is &lt;code&gt;key = (1 &amp;lt;&amp;lt; 3) | 0 = 0x08&lt;&#x2F;code&gt;,
which is varlen-encoded as &lt;code&gt;0x08&lt;&#x2F;code&gt;, since it is less than &lt;code&gt;128&lt;&#x2F;code&gt;.
The value of &lt;code&gt;42&lt;&#x2F;code&gt; (&lt;code&gt;0x2a&lt;&#x2F;code&gt; in hex) is also directly encoded as &lt;code&gt;0x2a&lt;&#x2F;code&gt; using
the varlen scheme, as it too is less than &lt;code&gt;128&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;nested-messages&quot;&gt;Nested messages&lt;&#x2F;h3&gt;
&lt;p&gt;Now consider a new message type &lt;code&gt;Parent&lt;&#x2F;code&gt;, which contains a single &lt;code&gt;Msg&lt;&#x2F;code&gt; field
with a field number of &lt;code&gt;1&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;proto&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Msg&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  uint64&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Parent&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  Msg&lt;&#x2F;span&gt;&lt;span&gt; child&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In protobufs, such &quot;embedded&quot; messages are encoded using the &lt;code&gt;LEN&lt;&#x2F;code&gt; scheme
listed in the table above, which has an ID of &lt;code&gt;2&lt;&#x2F;code&gt;.
Quite simply, after the key value, the length of the encoded child message in
bytes is first serialised as a varlen-encoded value, followed by the normal
encoding of the child message.&lt;&#x2F;p&gt;
&lt;p&gt;For example, consider an instance of &lt;code&gt;Parent&lt;&#x2F;code&gt;, which contains a &lt;code&gt;Msg&lt;&#x2F;code&gt; instance
with &lt;code&gt;data = 42&lt;&#x2F;code&gt; as above in its &lt;code&gt;child&lt;&#x2F;code&gt; field:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; &amp;quot;child&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; &amp;quot;data&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 42&lt;&#x2F;span&gt;&lt;span&gt; } }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;From above, we know that such a &lt;code&gt;Msg&lt;&#x2F;code&gt; is encoded as &lt;code&gt;0x08 0x2a&lt;&#x2F;code&gt;, which is
of length 2, giving us the following encoding for &lt;code&gt;Parent&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;KEY   LEN   CHILD.....&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x0A  0x02  0x08  0x2a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The field &lt;code&gt;child&lt;&#x2F;code&gt; has a field number of 1 and a &lt;code&gt;LEN&lt;&#x2F;code&gt; encoding scheme, which is
of ID &lt;code&gt;2&lt;&#x2F;code&gt;, giving us a key value of &lt;code&gt;key = (1 &amp;lt;&amp;lt; 3) | 2 = 0x0A&lt;&#x2F;code&gt;. As both the
key value and length are again less than &lt;code&gt;128&lt;&#x2F;code&gt;, their varlen representation is
equal to their one-byte value.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;repeated-fields&quot;&gt;Repeated Fields&lt;&#x2F;h3&gt;
&lt;p&gt;Finally, let&#x27;s have a look at how repeated fields - the protobuffer
equivalent of arrays - are encoded.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;markdown-alert-caution&quot;&gt;
&lt;p&gt;Note that there are two encoding schemes for repeated fields, which are used
based on the type of the field that is being repeated.
I will not discuss the &quot;packed&quot; scheme, which is used for simple scalar
values and also uses a &lt;code&gt;LEN&lt;&#x2F;code&gt;-style encoding, in this post.
In older versions of protobuffer, this &quot;packed&quot; scheme was opt-in, but
in more modern versions it is the default for simple repeated scalars!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Consider the following set of definitions, where the &lt;code&gt;MultiParent&lt;&#x2F;code&gt; message
can contain multiple &lt;code&gt;Msg&lt;&#x2F;code&gt; children:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;proto&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Msg&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  uint64&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; MultiParent&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  repeated Msg&lt;&#x2F;span&gt;&lt;span&gt; children&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s have a look at how a &lt;code&gt;MultiParent&lt;&#x2F;code&gt; containing two &lt;code&gt;data = 42&lt;&#x2F;code&gt; children
would be encoded:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;  &amp;quot;children&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; &amp;quot;data&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 42&lt;&#x2F;span&gt;&lt;span&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; &amp;quot;data&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 42&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Quite simply, for repeated embedded messages, protobuffer repeats another
key-value pair with the same field number. We already know that a single embedded
&lt;code&gt;Msg&lt;&#x2F;code&gt; with &lt;code&gt;data = 42&lt;&#x2F;code&gt; is encoded as &lt;code&gt;0x0A 0x02 0x08 0x2A&lt;&#x2F;code&gt;, so the &lt;code&gt;MultiParent&lt;&#x2F;code&gt;
above is encoded as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;KEY   LEN   CHILD.....   KEY   LEN   CHILD.....&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x0A  0x02  0x08  0x2a   0x0A  0x02  0x08  0x2a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|- 1st Child --------|   |- 2nd Child --------|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote class=&quot;markdown-alert-tip&quot;&gt;
&lt;p&gt;This is as deep as we will go into protobuffer encoding in this post.
If you want to go deeper, have a look at the
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;protocolbuffers&#x2F;protoscope&#x2F;tree&#x2F;main&quot;&gt;&lt;code&gt;protoscope&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
tool and textual representation, which is a very useful higher-level
representation of raw, binary, key-value protobuffer messages.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;putting-it-together&quot;&gt;Putting it together&lt;&#x2F;h2&gt;
&lt;p&gt;Armed with this basic understanding of the protobuffer wire format, and a
&lt;code&gt;protoc&lt;&#x2F;code&gt;-generated (or equivalent) encoder and decoder of the inner
&lt;code&gt;TracePacket&lt;&#x2F;code&gt; message, we can now encode and decode a large &lt;code&gt;Trace&lt;&#x2F;code&gt; one
&lt;code&gt;TracePacket&lt;&#x2F;code&gt; at a time by doing a bit of manual legwork.&lt;&#x2F;p&gt;
&lt;p&gt;Notably, the &lt;code&gt;Trace&lt;&#x2F;code&gt; message with which we started this post is incredibly
similar to the &lt;code&gt;MultiParent&lt;&#x2F;code&gt; example above: A message with a single,
repeated, embedded message field with field number &lt;code&gt;1&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;proto&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Trace&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  repeated TracePacket&lt;&#x2F;span&gt;&lt;span&gt; packet&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This means that a Perfetto trace is simply a sequence of the following
for each &lt;code&gt;TracePacket&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The byte &lt;code&gt;0x0A&lt;&#x2F;code&gt;, which is the varlen-encoded form of the key for a field tag number 1 encoded with the &lt;code&gt;LEN&lt;&#x2F;code&gt; scheme: &lt;code&gt;(1 &amp;lt;&amp;lt; 3) | 2 = 0x0A&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;The length of the serialized &lt;code&gt;TracePacket&lt;&#x2F;code&gt; in bytes, in varlen-encoded form.&lt;&#x2F;li&gt;
&lt;li&gt;The serialized &lt;code&gt;TracePacket&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;progressive-serialisation-appending&quot;&gt;Progressive Serialisation&#x2F;Appending&lt;&#x2F;h3&gt;
&lt;p&gt;This makes progressive serialisation of a &lt;code&gt;Trace&lt;&#x2F;code&gt; quite easy to do, because we
can use the &lt;code&gt;protoc&lt;&#x2F;code&gt; generated encoding routine for an individual &lt;code&gt;TracePacket&lt;&#x2F;code&gt;,
and concatenate them together into a correctly formatted trace by prepending each
trace packet with a &lt;code&gt;0x0A&lt;&#x2F;code&gt; and the length of the &lt;code&gt;TracePacket&lt;&#x2F;code&gt; in bytes, as
a varlen-encoded value.&lt;&#x2F;p&gt;
&lt;p&gt;For example, in Rust using the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tokio-rs&#x2F;prost&quot;&gt;&lt;code&gt;prost&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
protobuffer library, this would look roughly as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F;&#x2F; Encode a u64 as a protobuffer-style varint, appended into the provided buffer.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; encode_varint&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; u64&lt;&#x2F;span&gt;&lt;span&gt;, buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;: &amp;amp;mut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    loop&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; septet&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; u8&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; (v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0x7F&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; as&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; u8&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; &amp;gt;&amp;gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; ctrl_bit&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; = if&lt;&#x2F;span&gt;&lt;span&gt; v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0x80_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt; };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(septet&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span&gt; ctrl_bit);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F;&#x2F; Append a TracePacket to the provided buffer, which contains an already encoded Trace message,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F;&#x2F; or is empty.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; append_trace_packet&lt;&#x2F;span&gt;&lt;span&gt;(pckg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;: &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;TracePacket&lt;&#x2F;span&gt;&lt;span&gt;, buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;: &amp;amp;mut&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; anyhow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;Result&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;()&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; Key: field 1, LEN encoding = (1 &amp;lt;&amp;lt; 3) | 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;    encode_varint&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;0x0A&lt;&#x2F;span&gt;&lt;span&gt;, buf);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; Length:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;    encode_varint&lt;&#x2F;span&gt;&lt;span&gt;(pckg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;encoded_len&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; as&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; u64&lt;&#x2F;span&gt;&lt;span&gt;, buf);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; Embedded Message:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pckg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;encode&lt;&#x2F;span&gt;&lt;span&gt;(buf)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;    Ok&lt;&#x2F;span&gt;&lt;span&gt;(())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote class=&quot;markdown-alert-tip&quot;&gt;
&lt;p&gt;The &lt;code&gt;prost&lt;&#x2F;code&gt; library provides builtin functions for the varlen-encoding of the
message length, which is implemented manually above for illustration.&lt;&#x2F;p&gt;
&lt;p&gt;See
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;prost&#x2F;latest&#x2F;prost&#x2F;trait.Message.html#method.encode_length_delimited&quot;&gt;&lt;code&gt;Message::encode_length_delimited()&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,
and
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;prost&#x2F;latest&#x2F;prost&#x2F;fn.encode_length_delimiter.html&quot;&gt;&lt;code&gt;encode_length_delimiter()&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.
For decoding, have a look at
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;prost&#x2F;latest&#x2F;prost&#x2F;trait.Message.html#method.decode_length_delimited&quot;&gt;&lt;code&gt;Message::decode_length_delimited()&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,
and
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;prost&#x2F;latest&#x2F;prost&#x2F;fn.decode_length_delimiter.html&quot;&gt;&lt;code&gt;decode_length_delimiter()&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;progressive-deserialisation&quot;&gt;Progressive Deserialisation&lt;&#x2F;h3&gt;
&lt;p&gt;For decoding, we similarly skip the &lt;code&gt;0x0A&lt;&#x2F;code&gt; byte, decode the varlen-encoded length
field, and then pass that number of bytes to the protobuffer-generated &lt;code&gt;TracePacket&lt;&#x2F;code&gt;
decoder.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;markdown-alert-caution&quot;&gt;
&lt;p&gt;Parsing the length of the embedded message to determine which range of bytes makes
up one &lt;code&gt;TracePacket&lt;&#x2F;code&gt; is absolutely necessary.
Protobuffer&#x27;s wire format is not self-delimiting, so if you try to decode a nested
message without trimming away the bytes of successive messages, decoding will
produce garbage data.&lt;&#x2F;p&gt;
&lt;p&gt;You also cannot simply search for all &lt;code&gt;0x0A&lt;&#x2F;code&gt; bytes and assume that they
delimit individual &lt;code&gt;TracePacket&lt;&#x2F;code&gt; messages: Encoded nested messages can
contain arbitrary bytes, including &lt;code&gt;0x0A&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;In Rust this would look roughly as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F;&#x2F; Attempt to &amp;quot;consume&amp;quot; the first byte from the buffer and advance the pointer.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; consume_byte&lt;&#x2F;span&gt;&lt;span&gt;(buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;: &amp;amp;mut &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;])&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Option&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;is_empty&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; None&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; (byte, rest)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;split_at&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    *&lt;&#x2F;span&gt;&lt;span&gt;buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; rest;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;    Some&lt;&#x2F;span&gt;&lt;span&gt;(byte[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F;&#x2F; Decode a protobuffer-style varint from the provided buffer into a u64.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; decode_varint&lt;&#x2F;span&gt;&lt;span&gt;(buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;: &amp;amp;mut &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;])&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; anyhow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;Result&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    let mut&lt;&#x2F;span&gt;&lt;span&gt; v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; u64&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    let mut&lt;&#x2F;span&gt;&lt;span&gt; offs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    loop&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Some&lt;&#x2F;span&gt;&lt;span&gt;(byte)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; consume_byte&lt;&#x2F;span&gt;&lt;span&gt;(buf)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;anyhow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;anyhow!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;Unterminated varint&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; septet&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; u8&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; byte&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0x7F&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        let&lt;&#x2F;span&gt;&lt;span&gt; ctrl_bit&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; u8&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; byte&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0x80&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; |=&lt;&#x2F;span&gt;&lt;span&gt; (septet&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; as&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; u64&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; offs;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        offs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; ctrl_bit&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;            break&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; offs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; &amp;gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 70&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;anyhow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;anyhow!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;Varint too long&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;    Ok&lt;&#x2F;span&gt;&lt;span&gt;(v)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F;&#x2F; Decode a TracePacket from the beginning of the provided buffer containing an encoded Trace message,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F;&#x2F; returning the packet and the offset of the next TracePacket in the buffer.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;pub fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; decode_next_trace_packet&lt;&#x2F;span&gt;&lt;span&gt;(buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;: &amp;amp;mut &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;])&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; anyhow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;Result&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;TracePacket&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span&gt;)&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; len_orig&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; Decode &amp;amp; validate key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; key&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; decode_varint&lt;&#x2F;span&gt;&lt;span&gt;(buf)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; key&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0x0A&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;anyhow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;anyhow!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;Incorrect Key Byte&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; Decode &amp;amp; validate length&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; decode_varint&lt;&#x2F;span&gt;&lt;span&gt;(buf)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;anyhow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;anyhow!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;Incorrect Len (zero)&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; (buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; as&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; u64&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;anyhow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;anyhow!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;Incorrect Len (more than remaining bytes)&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; Decode next &amp;quot;len&amp;quot; bytes using TracePacket::decode()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; buf_packet, buf_rest)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;split_at&lt;&#x2F;span&gt;&lt;span&gt;(len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; as&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; usize&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    *&lt;&#x2F;span&gt;&lt;span&gt;buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; buf_rest;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; pckg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; TracePacket&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;decode&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; buf_packet)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    if !&lt;&#x2F;span&gt;&lt;span&gt;buf_packet&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;is_empty&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; Err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;anyhow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;anyhow!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;Incorrect Len (bytes left after decode)&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;    Ok&lt;&#x2F;span&gt;&lt;span&gt;((pckg, len_orig&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span&gt; buf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;()))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;complete-example&quot;&gt;Complete Example&lt;&#x2F;h3&gt;
&lt;p&gt;For a complete working example including a few tests, feel free to have a look at
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;schilkp&#x2F;protobuffer_repeat_streaming_example&quot;&gt;this&lt;&#x2F;a&gt;
repository.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Working with external warnings and diagnostics in NVIM</title>
        <published>2026-01-20T00:00:00+00:00</published>
        <updated>2026-08-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Philipp Schilk
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://schilk.co/blog/nvim-external-diagnostics/"/>
        <id>https://schilk.co/blog/nvim-external-diagnostics/</id>
        
        <content type="html" xml:base="https://schilk.co/blog/nvim-external-diagnostics/">&lt;p&gt;While most modern programming languages feature very advanced editor
integrations especially through LSP server implementations, VLSI, RTL, and
(System)Verilog tooling is always a bit ... &lt;em&gt;different&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately, these tools are not inherently bad, but rather a little more
old-fashioned. This means that while they might not be as straightforward
to use, the tools and techniques for an efficient workflow are already
out there.&lt;&#x2F;p&gt;
&lt;p&gt;In particular, I was interested in being able to quickly see and navigate to
all the numerous warnings and errors they produce directly in neovim.&lt;&#x2F;p&gt;
&lt;p&gt;I will use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.veripool.org&#x2F;verilator&#x2F;&quot;&gt;verilator&lt;&#x2F;a&gt; - an open-source
SystemVerilog simulator that works by transpiling RTL models to C++ code - as
an example for this post, but these same tools and techniques apply to everything
from commercial simulators and backend tools to any tool that generates errors
and warnings that are attached to a file location.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-quickfix-list&quot;&gt;The Quickfix List&lt;&#x2F;h2&gt;
&lt;p&gt;As is so often the case, this exact feature is already supported in (neo)vim
without any external plugins.&lt;&#x2F;p&gt;
&lt;p&gt;In fact, for a simple C project using a &lt;code&gt;Makefile&lt;&#x2F;code&gt;, you don&#x27;t even have to
configure anything!
The command &lt;code&gt;:make&lt;&#x2F;code&gt; will cause vim to call &lt;code&gt;make&lt;&#x2F;code&gt; with no arguments, capture
its output and parse it into the so-called quickfix list, which you can open
with &lt;code&gt;:cwindow&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
 &lt;br&gt; 
&lt;div style=&quot;text-align: center;&quot;&gt;
    
      
      
    
    &lt;a href=&quot;make_qf.png&quot;&gt;
        &lt;img src=&quot;make_qf.png&quot;  width=&quot;70%&quot; &gt;
    &lt;&#x2F;a&gt;
    
    &lt;br&gt;
    &lt;p&gt;Errors produced by &lt;code&gt;:make&lt;&#x2F;code&gt; in the quickfix list.&lt;&#x2F;p&gt;

    
&lt;&#x2F;div&gt;
 &lt;br&gt; 
&lt;p&gt;As you scroll through the quickfix list, vim will automatically jump to the location of
the errors and warnings.
Even without opening the quickfix list, you can jump between entries using &lt;code&gt;:cn&lt;&#x2F;code&gt; and &lt;code&gt;:cp&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For more information about the quickfix list, see
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;neovim.io&#x2F;doc&#x2F;user&#x2F;quickfix.html&quot;&gt;&lt;code&gt;:h quickfix&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-makeprg-option-and-cfile&quot;&gt;The &lt;code&gt;makeprg&lt;&#x2F;code&gt; option and &lt;code&gt;cfile&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;:make&lt;&#x2F;code&gt; command and quickfix list, despite its name, is not limited to
Makefiles and their output.
The &lt;code&gt;makeprg&lt;&#x2F;code&gt; option controls which command is invoked when &lt;code&gt;:make&lt;&#x2F;code&gt; is called.
For example, the following will cause it to run &lt;code&gt;cargo build&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; makeprg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;cargo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Any arguments you provide to the &lt;code&gt;:make&lt;&#x2F;code&gt; command will be appended to the end of
&lt;code&gt;makeprg&lt;&#x2F;code&gt;, unless the &lt;code&gt;$*&lt;&#x2F;code&gt; placeholder is used to specify where exactly the
arguments should be inserted:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; makeprg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;make&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; $*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; verilate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:make MYDEFINE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;make MYDEFINE&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt; verilate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;%&lt;&#x2F;code&gt; placeholder will be replaced with the path of the current file,
which is particularly useful for single-file linters or scripts:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; makeprg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;shellcheck&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; or&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; makeprg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;python&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For long-running compilations and programs, running them directly in
vim can be a bit cumbersome.
In such cases, the &lt;code&gt;:cfile&lt;&#x2F;code&gt; command can be used to read program output that has
been written to a file:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:cfile program_output.log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The content will be used to populate the quickfix list just like the output
of the &lt;code&gt;:make&lt;&#x2F;code&gt; command.&lt;&#x2F;p&gt;
&lt;p&gt;For more information see
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;neovim.io&#x2F;doc&#x2F;user&#x2F;options.html#&amp;#x27;makeprg&amp;#x27;&quot;&gt;&lt;code&gt;:h makeprg&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;neovim.io&#x2F;doc&#x2F;user&#x2F;quickfix.html#%3Acfile&quot;&gt;&lt;code&gt;:h cfile&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-errorformat-option&quot;&gt;The &lt;code&gt;errorformat&lt;&#x2F;code&gt; option&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;errorformat&lt;&#x2F;code&gt; option, in turn, contains one or more regex-like parsing
rules used to extract the source code location and other metadata from
the &lt;code&gt;:make&lt;&#x2F;code&gt; output or &lt;code&gt;:cfile&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For example, consider the output of the aforementioned &lt;code&gt;verilator&lt;&#x2F;code&gt; tool:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;%Warning-DECLFILENAME: looong_path&#x2F;tc_clk.sv:11:8: Filename &amp;#39;tc_clk&amp;#39; does not match MODULE name: &amp;#39;tc_clk_and2&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;%Error-PINCONNECTEMPTY: other_path&#x2F;trip_counter.sv:43:10: Instance pin connected by name with empty reference: &amp;#39;overflow_o&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A parsing rule consists of literal text and &lt;code&gt;%&lt;&#x2F;code&gt;-prefixed placeholders.
For the above, a basic rule might look something like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; errorformat&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;%%%t%*[a-zA-Z]-%*[^:]:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %f:%l:%c:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It consists of the following components:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Component&lt;&#x2F;th&gt;&lt;th&gt;Function&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;%%&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Matches a single &lt;code&gt;%&lt;&#x2F;code&gt; character.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;%t&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Matches a single character which determines the error type. (&lt;strong&gt;E&lt;&#x2F;strong&gt;rror, &lt;strong&gt;W&lt;&#x2F;strong&gt;arning, &lt;strong&gt;I&lt;&#x2F;strong&gt;nfo, &lt;strong&gt;N&lt;&#x2F;strong&gt;ote)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;%*[a-zA-Z]&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Matches one or more lower or uppercase letters. This &quot;consumes&quot; the rest of E&lt;strong&gt;rror&lt;&#x2F;strong&gt;, W&lt;strong&gt;arning&lt;&#x2F;strong&gt;, I&lt;strong&gt;nfo&lt;&#x2F;strong&gt;, or N&lt;strong&gt;ote&lt;&#x2F;strong&gt;.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Matches a single &lt;code&gt;-&lt;&#x2F;code&gt; character.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;%*[^:]&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Matches one or more characters that are not a &lt;code&gt;:&lt;&#x2F;code&gt;.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;:&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Matches a single &lt;code&gt;:&lt;&#x2F;code&gt; character.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\ &lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Matches a single space (&lt;code&gt; &lt;&#x2F;code&gt;).&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;%f&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Matches a file path.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;%l&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Matches a line number.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;%c&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Matches a column number.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;%m&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Matches an error message (a string).&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;neovim.io&#x2F;doc&#x2F;user&#x2F;quickfix.html#error-file-format&quot;&gt;&lt;code&gt;:h error-file-format&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
contains documentation about how &lt;code&gt;errorformat&lt;&#x2F;code&gt; strings are interpreted, including
many more placeholders and tools.
Consider also having a look at existing compiler plugins as a reference (see below).&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;markdown-alert-note&quot;&gt;
&lt;p&gt;The above &lt;code&gt;errorformat&lt;&#x2F;code&gt; does not cover all possible verilator warnings and
errors. See below for a more complete implementation that handles warnings
without error code and without column.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;compiler-plugins&quot;&gt;Compiler Plugins&lt;&#x2F;h3&gt;
&lt;p&gt;(Neo)vim ships a set of pre-configured &lt;code&gt;makeprg&lt;&#x2F;code&gt; and &lt;code&gt;errorformat&lt;&#x2F;code&gt; values
for a number of common compilers and tools.
These take the form of so-called compiler plugins.&lt;&#x2F;p&gt;
&lt;p&gt;For a list of built-in compiler plugins, have a look at the
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;neovim&#x2F;neovim&#x2F;tree&#x2F;master&#x2F;runtime&#x2F;compiler&quot;&gt;&lt;code&gt;runtime&#x2F;compiler&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
folder of the (neo)vim source tree.
For a list of compiler plugins available in your current (neo)vim instance you can run:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; f &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; globpath&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;&amp;amp;rtp&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt; &amp;#39;compiler&#x2F;*.vim&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;) | &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; fnamemodify&lt;&#x2F;span&gt;&lt;span&gt;(f,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt; &amp;#39;:t:r&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;) | &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;endfor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In typical vim fashion, the set of compiler plugins spans from slightly older tools,
such as different &lt;code&gt;fortran&lt;&#x2F;code&gt; flavours, to slightly more modern tools such as &lt;code&gt;gleam-build&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A few that might be of interest:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cargo&lt;&#x2F;code&gt; and &lt;code&gt;rustc&lt;&#x2F;code&gt; for rust development.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;eslint&lt;&#x2F;code&gt; and &lt;code&gt;tsc&lt;&#x2F;code&gt; for webdev.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;tex&lt;&#x2F;code&gt; and &lt;code&gt;typst&lt;&#x2F;code&gt; for typesetting.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And even &lt;code&gt;modelsim_vcom&lt;&#x2F;code&gt;, which is the VHDL compiler in ModelSim!&lt;&#x2F;p&gt;
&lt;p&gt;It is worth having a look at the content of the compiler plugin file for a tool
you are intending to use.
Many of them feature extra options and settings you can control via global
variables.
For example, to determine the exact flags with which &lt;code&gt;cargo&lt;&#x2F;code&gt; is called,
the &lt;code&gt;cargo&lt;&#x2F;code&gt; compiler plugin considers the &lt;code&gt;g:cargo_makeprg_params&lt;&#x2F;code&gt; global:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; runtime&#x2F;compiler&#x2F;cargo.vim:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; exists&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;#39;g:cargo_makeprg_params&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;    execute&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt; &amp;#39;CompilerSet makeprg=cargo\ &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;.escape&lt;&#x2F;span&gt;&lt;span&gt;(g:cargo_makeprg_params,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt; &amp;#39; \|&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;#39;\ $*&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    CompilerSet &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;makeprg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;cargo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; $*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;endif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;custom-compiler-plugins-verilator&quot;&gt;Custom Compiler Plugins: Verilator&lt;&#x2F;h3&gt;
&lt;p&gt;If you find yourself often parsing the output of a tool that is not
yet included in (neo)vim&#x27;s list of built-in compiler plugins, consider
adding a custom compiler plugin in your configuration.&lt;&#x2F;p&gt;
&lt;p&gt;On Linux, new compiler plugins should be placed in &lt;code&gt;$XDG_CONFIG_HOME&#x2F;nvim&#x2F;compiler&#x2F;&lt;&#x2F;code&gt;,
while overrides to existing compiler plugins go in &lt;code&gt;$XDG_CONFIG_HOME&#x2F;nvim&#x2F;after&#x2F;compiler&#x2F;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For example, on my machine, to create a new &lt;code&gt;verilator&lt;&#x2F;code&gt; compiler plugin, I create
&lt;code&gt;~&#x2F;.config&#x2F;nvim&#x2F;compiler&#x2F;verilator.vim&lt;&#x2F;code&gt; with the following content:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; ~&#x2F;.config&#x2F;nvim&#x2F;compiler&#x2F;verilator.vim:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Verilator warnings always start with &amp;quot;%Error&amp;quot; or &amp;quot;%Warning&amp;quot;, optionally directly&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; followed by an error code. If a location is known, it may be given with or&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; without column number. Examples of errors:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; &amp;quot;%Warning: ..msg..&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; &amp;quot;%Error-DECLFORMAT: myfile:1: ..msg..&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; &amp;quot;%Error-PINCONNECT: myfile:1:2: ..msg..&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CompilerSet &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;errorformat&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;%%%t%*[a-zA-Z]-%*[^:]:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %f:%l:%c:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %m,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;			\&lt;&#x2F;span&gt;&lt;span&gt;%%%t%*[a-zA-Z]-%*[^:]:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %f:%l:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %m,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;			\&lt;&#x2F;span&gt;&lt;span&gt;%%%t%*[a-zA-Z]:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %f:%l:%c:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %m,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;			\&lt;&#x2F;span&gt;&lt;span&gt;%%%t%*[a-zA-Z]:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %f:%l:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %m,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;See
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;neovim.io&#x2F;doc&#x2F;user&#x2F;usr_41.html#write-compiler-plugin&quot;&gt;&lt;code&gt;:h write-compiler-plugin&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; for
more info.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;markdown-alert-note&quot;&gt;
&lt;p&gt;Unfortunately, the &lt;code&gt;%*[^:]&lt;&#x2F;code&gt; pattern used to match the error code causes it to not be
shown in the quickfix list.
Parsing it as a module (&lt;code&gt;%o&lt;&#x2F;code&gt;) will make it visible in the quickfix list, but hide the
file name:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CompilerSet &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;errorformat&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;%%%t%*[a-zA-Z]-%o:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %f:%l:%c:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %m,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;			\&lt;&#x2F;span&gt;&lt;span&gt;%%%t%*[a-zA-Z]-%o:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %f:%l:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %m,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;			\&lt;&#x2F;span&gt;&lt;span&gt;%%%t%*[a-zA-Z]:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %f:%l:%c:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %m,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;			\&lt;&#x2F;span&gt;&lt;span&gt;%%%t%*[a-zA-Z]:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %f:%l:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;\&lt;&#x2F;span&gt;&lt;span&gt; %m,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;diagnostics&quot;&gt;Diagnostics&lt;&#x2F;h2&gt;
&lt;p&gt;If you instead prefer to display external warnings and errors as
in-line diagnostics in the same style as LSP servers, that is also an option,
but requires a bit of lua scripting.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-vim-diagnostic-api&quot;&gt;The &lt;code&gt;vim.diagnostic&lt;&#x2F;code&gt; API&lt;&#x2F;h3&gt;
&lt;p&gt;To display a set of diagnostics, first create a namespace to contain them:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt; my_namespace&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;api&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;nvim_create_namespace&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;my_namespace&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, configure how the diagnostics in this namespace should be displayed:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;diagnostic&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    virtual_text&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    signs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    underline&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    update_in_insert&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}, my_namespace)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Collect all your diagnostics for a given buffer into a table, and use
&lt;code&gt;vim.diagnostic.set()&lt;&#x2F;code&gt; to display them:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt; bufnr&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt; diagnostics&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    bufnr&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; bufnr, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;-- buffer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    lnum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;-- line number&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    col&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;-- column&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    severity&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;diagnostic&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;severity&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;WARN&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;-- severity&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    message&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt; &amp;quot;Something went wrong!&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;-- message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;diagnostic&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span&gt;(my_namespace, bufnr, diagnostics, {})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To remove all diagnostics, including before you re-apply a new set,
use &lt;code&gt;vim.diagnostic.reset()&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;diagnostic&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;reset&lt;&#x2F;span&gt;&lt;span&gt;(my_namespace)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;implementation&quot;&gt;Implementation&lt;&#x2F;h3&gt;
&lt;p&gt;With this, you can write a lua function that parses any external source and
displays them as nvim diagnostics.&lt;&#x2F;p&gt;
&lt;p&gt;Have a look at the documentation of the tool you are using - many feature an
option for generating the diagnostics information in a machine readable format.
Verilator, for instance, can be instructed to write all errors and warnings
to a JSON file with standard SARIF formatting:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;verilator&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; --diagnostics-sarif --diagnostics-sarif-output&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt; log.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In addition to seeing the errors inline, I like to use the excellent
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;folke&#x2F;trouble.nvim&quot;&gt;trouble.nvim&lt;&#x2F;a&gt; to also show a quickfix-like
pane with all diagnostics.
If you prefer to use the quickfix list, you can also programmatically insert
the diagnostics there.&lt;&#x2F;p&gt;
&lt;p&gt;This approach, while a little bit more work, has the advantage of being
extremely flexible. For example, for my verilator output parsing, I added
simple reload and filtering capabilities:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Parse + display verilator diagnostics file:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:VerilatorDiag log.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Reload diagnostics file:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:VerilatorDiag&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Only display diagnostics that contain the string &amp;quot;frontend&amp;quot;, and remove any&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; &amp;quot;UNOPTFLAT&amp;quot; and &amp;quot;UNUSEDSIGNAL&amp;quot; diagnostics:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:VerilatorDiagFilter frontend -UNOPTFLAT -UNUSEDSIGNAL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&amp;quot; Reset&#x2F;clear the diagnostics:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:VerilatorDiagReset&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A self-contained verilator sarif output parser and diagnostic generator with
filtering as described above can be found &lt;a href=&quot;https:&#x2F;&#x2F;schilk.co&#x2F;blog&#x2F;nvim-external-diagnostics&#x2F;verilator-sarif-parser&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;notes-resources&quot;&gt;Notes &amp;amp; Resources&lt;&#x2F;h2&gt;
&lt;p&gt;You can find my complete setup in my neovim configuration
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;schilkp&#x2F;dot&#x2F;tree&#x2F;main&#x2F;neovim&#x2F;.config&#x2F;nvim&#x2F;lua&#x2F;schilk&#x2F;utils&#x2F;file_diagnostics&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;changes&quot;&gt;Changes&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;2026-08-12&lt;&#x2F;code&gt;:
&lt;ul&gt;
&lt;li&gt;Fixed small bugs in the sample implementation of &lt;code&gt;M.filter_check&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;2026-08-13&lt;&#x2F;code&gt;:
&lt;ul&gt;
&lt;li&gt;Fixed &lt;code&gt;Changes&lt;&#x2F;code&gt; section and moved verilator sarif parser to dedicated page.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Managing project-specific NVIM configuration</title>
        <published>2026-01-19T00:00:00+00:00</published>
        <updated>2026-03-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Philipp Schilk
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://schilk.co/blog/nvim-local-conf/"/>
        <id>https://schilk.co/blog/nvim-local-conf/</id>
        
        <content type="html" xml:base="https://schilk.co/blog/nvim-local-conf/">&lt;h2 id=&quot;one-size-fits-not-quite-all&quot;&gt;One size fits not quite all&lt;&#x2F;h2&gt;
&lt;p&gt;While my &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;schilkp&#x2F;dot&#x2F;tree&#x2F;main&#x2F;neovim&#x2F;.config&#x2F;nvim&quot;&gt;neovim configuration&lt;&#x2F;a&gt;
works out of the box for most of the projects I work on, I have increasingly encountered
situations where I need to adjust certain aspects on a per-project basis.&lt;&#x2F;p&gt;
&lt;p&gt;For example, while doing some work with LLVM, I wanted to make use of the
MLIR and TableGen LSP servers.
While I could install these on my machine and add them to my main neovim configuration,
it is in many ways much better to use the specific binaries built from the LLVM tree I am
currently editing - that way any changes I make to, for example, an MLIR dialect,
are immediately available in the MLIR LSP after a quick re-compile.&lt;&#x2F;p&gt;
&lt;p&gt;There is nothing stopping me from adding such edge-case checks to my
main configuration - but that does not scale nicely and inevitably leaves
behind a whole bunch of configuration snippets I don&#x27;t actively use, yet don&#x27;t
want to delete in case I go back to a project in the future.
I would much prefer a strategy that allows me to keep such per-project
configuration with the actual project.&lt;&#x2F;p&gt;
&lt;p&gt;As with anything related to neovim configuration there are about 50 different
ways this can be achieved, and because neovim is usually configured
with executable code instead of declarative config files, there are a few gotchas that
might not be immediately obvious.
Therefore I thought it might be useful to quickly write up how the setup I
landed on works, and my thoughts behind why I built it in this way.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;notable-built-in-features-plugins&quot;&gt;Notable built-in features &amp;amp; plugins&lt;&#x2F;h2&gt;
&lt;p&gt;First, a quick overview of some built-in features and plugins that
are related to this subject:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;neo-vim-s-exrc-option&quot;&gt;(Neo)Vim&#x27;s &lt;code&gt;exrc&lt;&#x2F;code&gt; option&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;exrc&lt;&#x2F;code&gt; option is the historical solution to this problem, dating all
the way back to &lt;code&gt;vi&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;viml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; exrc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On startup, when this option is set, vim will look for a &lt;code&gt;.vimrc&lt;&#x2F;code&gt; or &lt;code&gt;.exrc&lt;&#x2F;code&gt;
vimscript file in the current directory, while neovim will look for a &lt;code&gt;.nvimrc&lt;&#x2F;code&gt;
or &lt;code&gt;.exrc&lt;&#x2F;code&gt; vimscript file, or a &lt;code&gt;.nvim.lua&lt;&#x2F;code&gt; lua script file.
If one such file is found, after the system and main user configuration is
loaded, (neo)vim will &lt;code&gt;:source&lt;&#x2F;code&gt; this file, executing whatever code it contains.&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;markdown-alert-caution&quot;&gt;
&lt;p&gt;Without any additional security mechanism, this option will execute arbitrary
code when opening your editor without any prompt or confirmation.
NeoVim features some mitigation to make this less risky - see below.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Have a look at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;neovim.io&#x2F;doc&#x2F;user&#x2F;options.html#&amp;#x27;exrc&amp;#x27;&quot;&gt;&lt;code&gt;:h exrc&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; for more information.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;neovim-s-trust-list&quot;&gt;NeoVim&#x27;s &lt;code&gt;:trust&lt;&#x2F;code&gt; list&lt;&#x2F;h3&gt;
&lt;p&gt;As executing arbitrary code when opening your editor in some repository you
just cloned from the internet is not an amazing idea, neovim introduced
&lt;code&gt;vim.secure.read()&lt;&#x2F;code&gt; and the associated &lt;code&gt;trust&lt;&#x2F;code&gt; list in &lt;code&gt;v0.9.0&lt;&#x2F;code&gt;
(released in 2022 - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;neovim&#x2F;neovim&#x2F;commit&#x2F;f1922e78a1df1b1d32779769432fb5586edf5fbb&quot;&gt;&lt;code&gt;f1922e7&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;When attempting to read a file for the first time using &lt;code&gt;vim.secure.read()&lt;&#x2F;code&gt;, neovim will
prompt the user to view the file and explicitly trust it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;:lua vim.secure.read(&amp;quot;README.md&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;exrc: Found untrusted code. To enable it, choose (v)iew then run `:trust`:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;home&#x2F;schilkp&#x2F;repos&#x2F;schilkp.github.io&#x2F;README.md&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[i]gnore, (v)iew, (d)eny:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Only if the user actually marks the file as trusted, will the content be read.&lt;&#x2F;p&gt;
&lt;p&gt;The location and name of the file, a sha256 hash of its content, and the user
decision will be stored in the &lt;code&gt;trust&lt;&#x2F;code&gt; list, located at &lt;code&gt;$XDG_STATE_HOME&#x2F;nvim&#x2F;trust&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;d84ce812f0b22bf6fd2502d9deadbeef2229931192efef1abc0002091b40 &#x2F;home&#x2F;schilkp&#x2F;repos&#x2F;schilkp.github.io&#x2F;README.md&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;! &#x2F;home&#x2F;schilkp&#x2F;Downloads&#x2F;random_project&#x2F;sketchy_file_i_dont_trust.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After it has been trusted, successive secure reads of this file will complete
without a user prompt, unless the file content or location has changed.
In neovim, &lt;code&gt;vim.secure.read()&lt;&#x2F;code&gt; is used for reading the content of any file
discovered and sourced through the &lt;code&gt;exrc&lt;&#x2F;code&gt; option mechanism, making it significantly
less reckless
(&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;neovim&#x2F;neovim&#x2F;commit&#x2F;294910a1ffd11bea0081c2b92632628ef0462eb1&quot;&gt;&lt;code&gt;294910a&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;See &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;neovim.io&#x2F;doc&#x2F;user&#x2F;lua.html#vim.secure&quot;&gt;&lt;code&gt;:h vim.secure&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; for more information.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-long-list-of-plugins&quot;&gt;A long list of plugins&lt;&#x2F;h3&gt;
&lt;p&gt;Per-project configuration is a common need, and there are also quite a few
plugins available to help you manage it, including
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tpope&#x2F;vim-projectionist&quot;&gt;&lt;code&gt;tpope&#x2F;vim-projectionist&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;,
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;klen&#x2F;nvim-config-local&quot;&gt;&lt;code&gt;klen&#x2F;nvim-config-local&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, and
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;direnv&#x2F;direnv.vim&quot;&gt;&lt;code&gt;direnv&#x2F;direnv&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;my-setup&quot;&gt;My setup&lt;&#x2F;h2&gt;
&lt;p&gt;With the &lt;code&gt;vim.secure.read()&lt;&#x2F;code&gt; mechanism, the &lt;code&gt;exrc&lt;&#x2F;code&gt; option in neovim is already
fairly close to what I want.
Its one major limitation for my use is that it is sourced &lt;em&gt;after&lt;&#x2F;em&gt; my main
configuration and therefore after all plugins are configured and loaded.
This makes it tricky to do things like adding new plugins, or disabling LSP
servers and features that my main configuration enables - by the time a &lt;code&gt;.nvim.lua&lt;&#x2F;code&gt;
file is sourced, all this is already done.&lt;&#x2F;p&gt;
&lt;p&gt;For a similar reason, using one of the many plugins is also not so attractive,
as I ideally want my local configuration to be available before my plugin
manager sources all plugins.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, I opted to implement a simple version of the &lt;code&gt;exrc&lt;&#x2F;code&gt; option directly
in my configuration:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;--- local_config.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt; M&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;M.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;CONFIG_FILE_NAMES&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; { &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;.schilk.nvim.lua&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;--- Look for local config file&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; M&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;lookup&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span&gt; _, filename&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; ipairs&lt;&#x2F;span&gt;&lt;span&gt;(M.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;CONFIG_FILE_NAMES&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    filename&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;findfile&lt;&#x2F;span&gt;&lt;span&gt;(filename, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;.;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; filename&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; ~=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt; &amp;quot;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;      return&lt;&#x2F;span&gt;&lt;span&gt; vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;fnamemodify&lt;&#x2F;span&gt;&lt;span&gt;(filename, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;:p&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;--- Find &amp;amp; load local config file&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; M&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;source&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  local&lt;&#x2F;span&gt;&lt;span&gt; file&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; M.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;lookup&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  if not&lt;&#x2F;span&gt;&lt;span&gt; file&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; or&lt;&#x2F;span&gt;&lt;span&gt; file&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt; &amp;quot;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  local&lt;&#x2F;span&gt;&lt;span&gt; content&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;secure&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;read&lt;&#x2F;span&gt;&lt;span&gt;(file) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;--[[@as string|nil]]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  if not&lt;&#x2F;span&gt;&lt;span&gt; content&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;notify&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;[local_config]: local config file found but not trusted!&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;levels&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;WARN&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  local&lt;&#x2F;span&gt;&lt;span&gt; config_fn, err_load&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; loadstring&lt;&#x2F;span&gt;&lt;span&gt;(content, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;@&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span&gt; file)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  if not&lt;&#x2F;span&gt;&lt;span&gt; config_fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;notify&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;[local_config]: failed to load local config file: &amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span&gt; err_load, vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;levels&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;ERROR&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  local&lt;&#x2F;span&gt;&lt;span&gt; success, err_call&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; pcall&lt;&#x2F;span&gt;&lt;span&gt;(config_fn)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  if not&lt;&#x2F;span&gt;&lt;span&gt; success&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;notify&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;[local_config]: failed to load local config file: &amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span&gt; err_call, vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;levels&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;ERROR&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;notify&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;[local_config]: loaded local config file&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;levels&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;INFO&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; M&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This module looks for a file called &lt;code&gt;.schilk.nvim.lua&lt;&#x2F;code&gt; in the current or
any parent directories.
If one is found the &lt;code&gt;vim.secure.read()&lt;&#x2F;code&gt; function is used to load it, allowing me to
manually review and approve the content before it is actually sourced.&lt;&#x2F;p&gt;
&lt;p&gt;In my main &lt;code&gt;init.lua&lt;&#x2F;code&gt;, I can then use this module even before my plugin manager &lt;code&gt;lazy&lt;&#x2F;code&gt;
is initialized:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;-- init.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;require&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;local_config&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;source&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Because I want the &lt;code&gt;vim.notify&lt;&#x2F;code&gt; status messages to show up in the notification feed of the
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;j-hui&#x2F;fidget.nvim&quot;&gt;&lt;code&gt;fidget&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; plugin instead of the default
nvim message list, I tend to wrap the calls to &lt;code&gt;vim.notify&lt;&#x2F;code&gt; above in a &lt;code&gt;vim.defer_fn&lt;&#x2F;code&gt; with
a short timeout, to make them appear after the &lt;code&gt;fidget&lt;&#x2F;code&gt; has been loaded:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;local function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; defer_notif&lt;&#x2F;span&gt;&lt;span&gt;(msg, level)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;defer_fn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    vim.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;notify&lt;&#x2F;span&gt;&lt;span&gt;(msg, level)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  end&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;250&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That workaround is very hacky - I know.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;local-config-files&quot;&gt;Local Config Files&lt;&#x2F;h3&gt;
&lt;p&gt;While the config file can contain arbitrary code, most of the time I want to change
some setting or behaviour of my main configuration.
I do this by storing information in the global &lt;code&gt;_G&lt;&#x2F;code&gt; table, which my main configuration
then checks for and applies if it exists.
For example, to install an additional plugin, I place one or more &lt;code&gt;lazy&lt;&#x2F;code&gt; plugin
specs in &lt;code&gt;_G.SCHILK_LOCAL_PLUGINS&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;-- Extra plugins to be inserted into the lazy spec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;_G&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;SCHILK_LOCAL_PLUGINS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;    &amp;#39;schilkp&#x2F;my_cool_plugin&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In my main configuration, I then inject any plugins into the default list of
plugin specs before starting the plugin manager.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;local&lt;&#x2F;span&gt;&lt;span&gt; plugins&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    -- ... list of plugins ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;-- Inject local plugins:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;_G&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;SCHILK_LOCAL_PLUGINS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; _G&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;SCHILK_LOCAL_PLUGINS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; or&lt;&#x2F;span&gt;&lt;span&gt; {}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; _G&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;SCHILK_LOCAL_PLUGINS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span&gt; _, plugin&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; ipairs&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;_G&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;SCHILK_LOCAL_PLUGINS&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;    table.insert&lt;&#x2F;span&gt;&lt;span&gt;(plugins, plugin)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;require&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;quot;lazy&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;setup&lt;&#x2F;span&gt;&lt;span&gt;(plugins)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For reference, here are some of the things which I often do in my local config files:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Install and enable additional plugins, as shown above.&lt;&#x2F;li&gt;
&lt;li&gt;Enable additional LSP servers from &lt;code&gt;nvim-lspconfig&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Disable LSP servers that I have usually enabled.&lt;&#x2F;li&gt;
&lt;li&gt;Configure local, project-specific LSP servers, such as the aforementioned MLIR and TableGen LSPs.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;shareability&quot;&gt;Shareability&lt;&#x2F;h3&gt;
&lt;p&gt;The one big downside of this approach is that it is very tightly coupled to my neovim configuration,
and therefore these config files are not very useful to anyone else.
Unfortunately, because neovim configurations are all so incredibly different, I don&#x27;t see a
great way of changing that.&lt;&#x2F;p&gt;
&lt;p&gt;This is reflected in my choice to name the files &lt;code&gt;.schilk.nvim.lua&lt;&#x2F;code&gt;: I doubt anyone else
will directly use them.&lt;&#x2F;p&gt;
&lt;p&gt;For this reason, I also typically don&#x27;t check them into project git
repositories.
As I doubt that the LLVM project will be interested in a patch
that adds &lt;code&gt;.schilk.nvim.lua&lt;&#x2F;code&gt; to their &lt;code&gt;.gitignore&lt;&#x2F;code&gt;, to avoid having to keep
juggling that change around locally, I just ignore these files in all git repos
using a global &lt;code&gt;.gitignore&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ~&#x2F;.gitconfig:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[core]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    excludesfile = &#x2F;home&#x2F;schilkp&#x2F;.gitignore_global&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ~&#x2F;.gitignore_global:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.schilk.nvim.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;&#x2F;h2&gt;
&lt;p&gt;You can find my complete setup directly in my neovim configuration
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;schilkp&#x2F;dot&#x2F;blob&#x2F;main&#x2F;neovim&#x2F;.config&#x2F;nvim&#x2F;lua&#x2F;schilk&#x2F;local_config&#x2F;init.lua&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;changes&quot;&gt;Changes&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;2026-03-13&lt;&#x2F;code&gt;:
&lt;ul&gt;
&lt;li&gt;Fixed the version of &lt;code&gt;nvim&lt;&#x2F;code&gt; in which &lt;code&gt;vim.secure.read()&lt;&#x2F;code&gt; was introduced - thanks, justinmk!&lt;&#x2F;li&gt;
&lt;li&gt;Updated the example snippet to use the actual content read by &lt;code&gt;vim.secure.read()&lt;&#x2F;code&gt; instead of just using said function to check if the file is trusted before sourcing from the file.&lt;&#x2F;li&gt;
&lt;li&gt;Add explanation about deferred &lt;code&gt;notify&lt;&#x2F;code&gt; calls.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
</feed>
