<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Go on Clément Joly – Open-Source, Rust &amp; SQLite</title><link>https://joly.pw/tags/go/</link><description>Recent content in Go on Clément Joly – Open-Source, Rust &amp; SQLite</description><image><title>Clément Joly – Open-Source, Rust &amp; SQLite</title><url>https://joly.pw/images/open-graph-home-original.png</url><link>https://joly.pw/images/open-graph-home-original.png</link></image><generator>Hugo -- 0.154.3</generator><language>en</language><copyright>Clément Joly</copyright><lastBuildDate>Wed, 11 Mar 2026 03:32:38 +0000</lastBuildDate><atom:link href="https://joly.pw/tags/go/index.xml" rel="self" type="application/rss+xml"/><item><title>Luasnip and Treesitter for Smarter Snippets</title><link>https://joly.pw/blog/luasnip-and-treesitter-for-smarter-snippets/</link><pubDate>Wed, 30 Aug 2023 13:28:14 +0100</pubDate><guid>https://joly.pw/blog/luasnip-and-treesitter-for-smarter-snippets/</guid><description>An example on Go error handling.</description><content:encoded><![CDATA[



  
  
  
  

  <div class="alert alert-tldr">
    <p class="alert-heading">
      ⚡
      
        TL;DR
      
    </p>
    <p>A context-aware snippet for Go error handling code, returning the right types, with the default values.</p>
<ul>
<li><a href="#demo">Demo</a></li>
<li><a href="#code">Snippet</a></li>
</ul>
  </div>







  
  
  
  

  <div class="alert alert-edit">
    <p class="alert-heading">
      ✏
      
        Edit
      
    </p>
    <p>TJ DeVries made a <a href="https://www.youtube.com/watch?v=aNWx-ym7jjI">video</a> explaining an improved version of this snippet. You may still find the discussion on Go errors in this post interesting.</p>
  </div>



<h2 id="introduction">Introduction</h2>
<p><a href="https://go.dev">Golang’s</a> error handling is notoriously verbose. It was also the top pain point in the <a href="https://go.dev/blog/survey2022-q2-results">Go Developer Survey Q2 2022</a>. <a href="https://github.com/golang/go/issues/56165">Numerous</a> <a href="https://github.com/golang/go/issues/32437">proposals</a> <a href="https://github.com/golang/go/issues/37141">to simplify</a> error handling have been written, but at the time of writing, none have been accepted.</p>
<p>So we have to live with the current state of things. It’s ok, Neovim with Treesitter has a good “understanding” of code, so we can use it to generate the error handling code.</p>
<h3 id="treesitter">Treesitter</h3>
<p>One of <a href="https://github.com/neovim/neovim/releases/tag/v0.5.0">Neovim 0.5</a> most exciting features was the introduction of Treesitter.
This new parsing system gives the editor a basic understanding of the code at hand: the editor “knows” what the function name is, where a variable is defined…
It enables great plugins, <a href="https://github.com/SmiteshP/nvim-gps">showing the context</a> around some code, <a href="https://github.com/nvim-treesitter/nvim-treesitter-textobjects">improved selection</a>, <a href="https://github.com/nvim-treesitter/nvim-treesitter-refactor">better renaming and navigation</a> and more!
In this post, we will look into how Treesitter can be combined with <a href="https://github.com/L3MON4D3/LuaSnip">LuaSnip</a> for smarter snippets.</p>
<h2 id="error-handling-in-go">Error Handling in Go</h2>




  
  
  
  

  <div class="alert alert-note">
    <p class="alert-heading">
      ℹ️
      
        Note
      
    </p>
    <p>Feel free to <a href="#clever">skip</a> this section if you already know about Go error handling.</p>
  </div>



<p>In <a href="https://go.dev">Golang</a>, errors are handled by returning a value of type <code>error</code>, sometimes along the types returned when everything goes well. For instance, the <a href="https://pkg.go.dev/time#Parse"><code>time.Parse</code></a> function has the following signature:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#c678dd">func</span> <span style="color:#61afef;font-weight:bold">Parse</span>(<span style="color:#e06c75">layout</span>, <span style="color:#e06c75">value</span> <span style="color:#e5c07b">string</span>) (<span style="color:#e06c75">Time</span>, <span style="color:#e5c07b">error</span>)
</span></span></code></pre></div><p><code>time.Parse</code> will try to parse a string with the given format.
If it’s successful, it’ll return a value of type <code>Time</code> and the error will be <code>nil</code>.
If a date can’t be parsed, then the error won’t be <code>nil</code>.
And so it’s common in Go to check for errors like so:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#e06c75">timeStr</span> <span style="color:#56b6c2">:=</span> <span style="color:#98c379">&#34;Aug 6, 2022 @ 7:54pm&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#e06c75">t</span>, <span style="color:#e06c75">err</span> <span style="color:#56b6c2">:=</span> <span style="color:#e06c75">time</span>.<span style="color:#61afef;font-weight:bold">Parse</span>(<span style="color:#98c379">&#34;Jan 2, 2006 @ 3:04pm&#34;</span>, <span style="color:#e06c75">timeStr</span>)
</span></span><span style="display:flex;"><span><span style="color:#c678dd">if</span> <span style="color:#e06c75">err</span> <span style="color:#56b6c2">!=</span> <span style="color:#e5c07b">nil</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">log</span>.<span style="color:#61afef;font-weight:bold">Fatal</span>(<span style="color:#e06c75">err</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#7f848e">// Now, we can safely use t</span>
</span></span></code></pre></div><p>In the example above, we just log the error and panic. But if we are in a function, we will likely return an error to the caller, wrapping the error returned by <code>time.Parse</code>. For instance:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;"><code class="language-go" data-lang="go"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">1</span><span><span style="color:#c678dd">func</span> <span style="color:#61afef;font-weight:bold">parseLong</span>(<span style="color:#e06c75">timeStr</span> <span style="color:#e5c07b">string</span>) (<span style="color:#e06c75">Time</span>, <span style="color:#e5c07b">error</span>) {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">2</span><span>    <span style="color:#e06c75">t</span>, <span style="color:#e06c75">err</span> <span style="color:#56b6c2">:=</span> <span style="color:#e06c75">time</span>.<span style="color:#61afef;font-weight:bold">Parse</span>(<span style="color:#98c379">&#34;Jan 2, 2006 @ 3:04pm&#34;</span>, <span style="color:#e06c75">timeStr</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">3</span><span>    <span style="color:#c678dd">if</span> <span style="color:#e06c75">err</span> <span style="color:#56b6c2">!=</span> <span style="color:#e5c07b">nil</span> {
</span></span><span style="display:flex; background-color:#3d4148"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">4</span><span>        <span style="color:#c678dd">return</span> <span style="color:#e06c75">t</span>, <span style="color:#e06c75">fmt</span>.<span style="color:#61afef;font-weight:bold">Errorf</span>(<span style="color:#98c379">&#34;couldn’t parse %v: %v&#34;</span>, <span style="color:#e06c75">timeStr</span>, <span style="color:#e06c75">err</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">5</span><span>    }
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">6</span><span>    <span style="color:#c678dd">return</span> <span style="color:#e06c75">t</span>, <span style="color:#e5c07b">nil</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">7</span><span>}
</span></span></code></pre></div><p>The key takeaway here is that the <code>return</code> line in the error case (line 4 above) depends on the return type of the function and so can vary significantly.</p>
<p>This is covered in more details in this <a href="https://go.dev/blog/error-handling-and-go">post</a> on the Go blog.</p>
<h2 id="clever">Clever Snippets with LuaSnip and Treesitter</h2>
<p>As we have seen, error handling code varies depending on the number and type of the values returned by the parent function.
So we are very often writing variations of the following in our Go code:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#c678dd">func</span> <span style="color:#61afef;font-weight:bold">f</span>(<span style="color:#e06c75">arg1</span> <span style="color:#e5c07b">string</span>, <span style="color:#e06c75">arg2</span> <span style="color:#e5c07b">string</span>) (…, <span style="color:#e5c07b">error</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">val</span>, <span style="color:#e06c75">err</span> <span style="color:#56b6c2">:=</span> <span style="color:#61afef;font-weight:bold">someFunction</span>(<span style="color:#e06c75">arg1</span>, <span style="color:#e06c75">arg2</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#c678dd">if</span> <span style="color:#e06c75">err</span> <span style="color:#56b6c2">!=</span> <span style="color:#e5c07b">nil</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#c678dd">return</span> …, <span style="color:#e06c75">err</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    …
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Or with 3 return values:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#c678dd">func</span> <span style="color:#61afef;font-weight:bold">f</span>(<span style="color:#e06c75">arg</span> <span style="color:#e5c07b">string</span>) (…, …, <span style="color:#e5c07b">error</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#e06c75">val</span>, <span style="color:#e06c75">err</span> <span style="color:#56b6c2">:=</span> <span style="color:#61afef;font-weight:bold">someFunction</span>(<span style="color:#e06c75">arg</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#c678dd">if</span> <span style="color:#e06c75">err</span> <span style="color:#56b6c2">!=</span> <span style="color:#e5c07b">nil</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#c678dd">return</span> …, …, <span style="color:#e06c75">err</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    …
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>It would be handy to have a snippet that would adjust the <code>return</code>’s shape depending on the return type of the function that contains it.</p>
<h3 id="demo">Demo</h3>
<p>Here is a short asciicast demonstration<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> of the snippet we are going to build. It is called <code>smart_err</code>:</p>

    <script src="https://joly.pw/js/asciinema-player.min.0a355ec0e0db21622c1aa829f4ffd49e.js"></script>
    <link rel="stylesheet" type="text/css" href="https://joly.pw/css/asciinema-player.min.b76f6c28744857ba1315b54d09acafff.css" /><div id="demo1"></div>
<script>
AsciinemaPlayer.create("/blog/luasnip-and-treesitter-for-smarter-snippets/demo.json", document.getElementById('demo1'), {
"idleTimeLimit":  0.4 ,"loop":  true ,"poster": "npt:0:31","speed":  1.2 ,
});
</script>
<noscript><blockquote><p>To run this asciicast without javascript, use <code>asciinema play https://joly.pw/blog/luasnip-and-treesitter-for-smarter-snippets/demo.json</code> with <a href="https://asciinema.org/">Asciinema</a></p></blockquote></noscript>

<p>The snippet inserted (line 11 in the asciicast) is</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#e06c75">myVal</span>, <span style="color:#e06c75">myErr</span> <span style="color:#56b6c2">:=</span> <span style="color:#61afef;font-weight:bold">anotherFunc</span>(<span style="color:#e06c75">arg1</span>, <span style="color:#e06c75">arg2</span>)
</span></span><span style="display:flex;"><span><span style="color:#c678dd">if</span> <span style="color:#e06c75">myErr</span> <span style="color:#56b6c2">!=</span> <span style="color:#e5c07b">nil</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#c678dd">return</span> <span style="color:#e5c07b">false</span>, <span style="color:#e06c75">fmt</span>.<span style="color:#61afef;font-weight:bold">Errorf</span>(<span style="color:#98c379">&#34;anotherFunc: %v&#34;</span>, <span style="color:#e06c75">myErr</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>when the return type of the function was <code>(bool, error)</code>.</p>
<p>And</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#e06c75">val</span>, <span style="color:#e06c75">err</span> <span style="color:#56b6c2">:=</span> <span style="color:#61afef;font-weight:bold">f</span>()
</span></span><span style="display:flex;"><span><span style="color:#c678dd">if</span> <span style="color:#e06c75">err</span> <span style="color:#56b6c2">!=</span> <span style="color:#e5c07b">nil</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#c678dd">return</span> <span style="color:#e5c07b">false</span>, <span style="color:#e06c75">fmt</span>.<span style="color:#61afef;font-weight:bold">Errorf</span>(<span style="color:#98c379">&#34;f: %v&#34;</span>, <span style="color:#e06c75">err</span>), <span style="color:#d19a66">0</span>, <span style="color:#98c379">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>when the return type was <code>(bool, error, int, string)</code>.</p>
<p>And it even works in nested functions:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#c678dd">func</span> <span style="color:#61afef;font-weight:bold">myFunc</span>() (<span style="color:#56b6c2">*</span><span style="color:#e06c75">MyStruct</span>, <span style="color:#e5c07b">error</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#7f848e">// ...</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e06c75">a</span> <span style="color:#56b6c2">:=</span> <span style="color:#c678dd">func</span>() (<span style="color:#e5c07b">bool</span>, <span style="color:#e5c07b">error</span>, <span style="color:#e5c07b">int</span>, <span style="color:#e5c07b">string</span>) {
</span></span><span style="display:flex;"><span>		<span style="color:#7f848e">// The snippet detected that we need 4 values here,</span>
</span></span><span style="display:flex;"><span>		<span style="color:#7f848e">// and not 2 as in the outer function</span>
</span></span><span style="display:flex;"><span>		<span style="color:#c678dd">return</span> <span style="color:#e06c75">v</span>, <span style="color:#e5c07b">nil</span>, <span style="color:#d19a66">0</span>, <span style="color:#98c379">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>	}
</span></span></code></pre></div><p>Also note that we can choose to wrap the containing error, or not, with a keystroke (bound to <code>require(&quot;luasnip&quot;).change_choice(1)</code>). The snippet switches between the following 3 forms (line 18 in the asciicast):</p>
<ol>
<li>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#c678dd">return</span> <span style="color:#e5c07b">false</span>, <span style="color:#e06c75">err</span>
</span></span></code></pre></div></li>
<li>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#c678dd">return</span> <span style="color:#e5c07b">false</span>, <span style="color:#e06c75">fmt</span>.<span style="color:#61afef;font-weight:bold">Errorf</span>(<span style="color:#98c379">&#34;f: %v&#34;</span>, <span style="color:#e06c75">err</span>)
</span></span></code></pre></div></li>
<li>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#c678dd">return</span> <span style="color:#e5c07b">false</span>, <span style="color:#e06c75">errors</span>.<span style="color:#61afef;font-weight:bold">Wrap</span>(<span style="color:#e06c75">err</span>, <span style="color:#98c379">&#34;f&#34;</span>)
</span></span></code></pre></div></li>
</ol>
<p>That’s pretty cool! Let’s see how to add it to your Neovim configuration.</p>
<h3 id="code">Code</h3>
<p>The code to define this snippet was initially written by <a href="https://github.com/tjdevries">TJ DeVries</a><sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>. I’ve only slightly adapted it so that it fits in one file. I believe the author welcomes this<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>:</p>




  <figure>
    <blockquote cite="https://github.com/tjdevries/config_manager#readme">
      <p>This is TJ&rsquo;s configuration repo. Feel free to use whatever you would like from it! It&rsquo;d be great if you mentioned where it came from if you think it&rsquo;s cool.</p>

    </blockquote>
    
      <figcaption class="blockquote-caption">
        
          <cite style="text-align: right"><a href="https://github.com/tjdevries/config_manager#readme">https://github.com/tjdevries/config_manager#readme</a></cite>
          <br/>
        
        
      </figcaption>
    
  </figure>



<p>Copy this alongside your other LuaSnip snippets, for instance in <a href="./go.lua"><code>~/.config/nvim/snippets/go.lua</code></a>:</p>
<div class="highlight" id="luasnip"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;display:grid;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">  1</span><span><span style="color:#c678dd">local</span> <span style="color:#e06c75">ls</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">require</span> <span style="color:#98c379">&#34;luasnip&#34;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">  2</span><span><span style="color:#c678dd">local</span> <span style="color:#e06c75">f</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">ls.function_node</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">  3</span><span><span style="color:#c678dd">local</span> <span style="color:#e06c75">s</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">ls.s</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">  4</span><span><span style="color:#c678dd">local</span> <span style="color:#e06c75">i</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">ls.insert_node</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">  5</span><span><span style="color:#c678dd">local</span> <span style="color:#e06c75">t</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">ls.text_node</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">  6</span><span><span style="color:#c678dd">local</span> <span style="color:#e06c75">d</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">ls.dynamic_node</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">  7</span><span><span style="color:#c678dd">local</span> <span style="color:#e06c75">c</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">ls.choice_node</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">  8</span><span><span style="color:#c678dd">local</span> <span style="color:#e06c75">snippet_from_nodes</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">ls.sn</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">  9</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 10</span><span><span style="color:#c678dd">local</span> <span style="color:#e06c75">ts_locals</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">require</span> <span style="color:#98c379">&#34;nvim-treesitter.locals&#34;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 11</span><span><span style="color:#c678dd">local</span> <span style="color:#e06c75">ts_utils</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">require</span> <span style="color:#98c379">&#34;nvim-treesitter.ts_utils&#34;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 12</span><span><span style="color:#c678dd">local</span> <span style="color:#e06c75">get_node_text</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">vim.treesitter</span>.<span style="color:#e06c75">get_node_text</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 13</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 14</span><span><span style="color:#7f848e">-- Adapted from https://github.com/tjdevries/config_manager/blob/1a93f03dfe254b5332b176ae8ec926e69a5d9805/xdg_config/nvim/lua/tj/snips/ft/go.lua</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 15</span><span><span style="color:#c678dd">local</span> <span style="color:#c678dd">function</span> <span style="color:#61afef;font-weight:bold">same</span>(<span style="color:#e06c75">index</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 16</span><span>  <span style="color:#c678dd">return</span> <span style="color:#e06c75">f</span>(<span style="color:#c678dd">function</span>(<span style="color:#e06c75">args</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 17</span><span>    <span style="color:#c678dd">return</span> <span style="color:#e06c75">args</span>[<span style="color:#d19a66">1</span>]
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 18</span><span>  <span style="color:#c678dd">end</span>, { <span style="color:#e06c75">index</span> })
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 19</span><span><span style="color:#c678dd">end</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 20</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 21</span><span><span style="color:#7f848e">-- Adapted from https://github.com/tjdevries/config_manager/blob/1a93f03dfe254b5332b176ae8ec926e69a5d9805/xdg_config/nvim/lua/tj/snips/ft/go.lua</span>
</span></span><span style="display:flex; background-color:#3d4148"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 22</span><span><span style="color:#e06c75">vim.treesitter</span>.<span style="color:#e06c75">query.set</span>(
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 23</span><span>  <span style="color:#98c379">&#34;go&#34;</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 24</span><span>  <span style="color:#98c379">&#34;LuaSnip_Result&#34;</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 25</span><span>  <span style="color:#98c379">[[ [
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 26</span><span><span style="color:#98c379">    (method_declaration result: (_) @id)
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 27</span><span><span style="color:#98c379">    (function_declaration result: (_) @id)
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 28</span><span><span style="color:#98c379">    (func_literal result: (_) @id)
</span></span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 29</span><span><span style="color:#98c379">  ] ]]</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 30</span><span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 31</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 32</span><span><span style="color:#7f848e">-- Adapted from https://github.com/tjdevries/config_manager/blob/1a93f03dfe254b5332b176ae8ec926e69a5d9805/xdg_config/nvim/lua/tj/snips/ft/go.lua</span>
</span></span><span style="display:flex; background-color:#3d4148"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 33</span><span><span style="color:#c678dd">local</span> <span style="color:#e06c75">transform</span> <span style="color:#56b6c2">=</span> <span style="color:#c678dd">function</span>(<span style="color:#e06c75">text</span>, <span style="color:#e06c75">info</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 34</span><span>  <span style="color:#c678dd">if</span> <span style="color:#e06c75">text</span> <span style="color:#56b6c2">==</span> <span style="color:#98c379">&#34;int&#34;</span> <span style="color:#c678dd">then</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 35</span><span>    <span style="color:#c678dd">return</span> <span style="color:#e06c75">t</span> <span style="color:#98c379">&#34;0&#34;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 36</span><span>  <span style="color:#c678dd">elseif</span> <span style="color:#e06c75">text</span> <span style="color:#56b6c2">==</span> <span style="color:#98c379">&#34;error&#34;</span> <span style="color:#c678dd">then</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 37</span><span>    <span style="color:#c678dd">if</span> <span style="color:#e06c75">info</span> <span style="color:#c678dd">then</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 38</span><span>      <span style="color:#e06c75">info.index</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">info.index</span> <span style="color:#56b6c2">+</span> <span style="color:#d19a66">1</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 39</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 40</span><span>      <span style="color:#c678dd">return</span> <span style="color:#e06c75">c</span>(<span style="color:#e06c75">info.index</span>, {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 41</span><span>        <span style="color:#e06c75">t</span>(<span style="color:#e06c75">string.format</span>(<span style="color:#98c379">&#39;fmt.Errorf(&#34;%s: %%v&#34;, %s)&#39;</span>, <span style="color:#e06c75">info.func_name</span>, <span style="color:#e06c75">info.err_name</span>)),
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 42</span><span>        <span style="color:#e06c75">t</span>(<span style="color:#e06c75">info.err_name</span>),
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 43</span><span>        <span style="color:#7f848e">-- Be cautious with wrapping, it makes the error part of the API of the</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 44</span><span>        <span style="color:#7f848e">-- function, see https://go.dev/blog/go1.13-errors#whether-to-wrap</span>
</span></span><span style="display:flex; background-color:#3d4148"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 45</span><span>        <span style="color:#e06c75">t</span>(<span style="color:#e06c75">string.format</span>(<span style="color:#98c379">&#39;fmt.Errorf(&#34;%s: %%w&#34;, %s)&#39;</span>, <span style="color:#e06c75">info.func_name</span>, <span style="color:#e06c75">info.err_name</span>)),
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 46</span><span>        <span style="color:#7f848e">-- Old style (pre 1.13, see https://go.dev/blog/go1.13-errors), using</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 47</span><span>        <span style="color:#7f848e">-- https://github.com/pkg/errors</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 48</span><span>        <span style="color:#e06c75">t</span>(<span style="color:#e06c75">string.format</span>(<span style="color:#98c379">&#39;errors.Wrap(%s, &#34;%s&#34;)&#39;</span>, <span style="color:#e06c75">info.err_name</span>, <span style="color:#e06c75">info.func_name</span>)),
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 49</span><span>      })
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 50</span><span>    <span style="color:#c678dd">else</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 51</span><span>      <span style="color:#c678dd">return</span> <span style="color:#e06c75">t</span> <span style="color:#98c379">&#34;err&#34;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 52</span><span>    <span style="color:#c678dd">end</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 53</span><span>  <span style="color:#c678dd">elseif</span> <span style="color:#e06c75">text</span> <span style="color:#56b6c2">==</span> <span style="color:#98c379">&#34;bool&#34;</span> <span style="color:#c678dd">then</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 54</span><span>    <span style="color:#c678dd">return</span> <span style="color:#e06c75">t</span> <span style="color:#98c379">&#34;false&#34;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 55</span><span>  <span style="color:#c678dd">elseif</span> <span style="color:#e06c75">text</span> <span style="color:#56b6c2">==</span> <span style="color:#98c379">&#34;string&#34;</span> <span style="color:#c678dd">then</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 56</span><span>    <span style="color:#c678dd">return</span> <span style="color:#e06c75">t</span> <span style="color:#98c379">&#39;&#34;&#34;&#39;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 57</span><span>  <span style="color:#c678dd">elseif</span> <span style="color:#e06c75">string.find</span>(<span style="color:#e06c75">text</span>, <span style="color:#98c379">&#34;*&#34;</span>, <span style="color:#d19a66">1</span>, <span style="color:#e5c07b">true</span>) <span style="color:#c678dd">then</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 58</span><span>    <span style="color:#c678dd">return</span> <span style="color:#e06c75">t</span> <span style="color:#98c379">&#34;nil&#34;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 59</span><span>  <span style="color:#c678dd">end</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 60</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 61</span><span>  <span style="color:#c678dd">return</span> <span style="color:#e06c75">t</span>(<span style="color:#e06c75">text</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 62</span><span><span style="color:#c678dd">end</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 63</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 64</span><span><span style="color:#c678dd">local</span> <span style="color:#e06c75">handlers</span> <span style="color:#56b6c2">=</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 65</span><span>  [<span style="color:#98c379">&#34;parameter_list&#34;</span>] <span style="color:#56b6c2">=</span> <span style="color:#c678dd">function</span>(<span style="color:#e06c75">node</span>, <span style="color:#e06c75">info</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 66</span><span>    <span style="color:#c678dd">local</span> <span style="color:#e06c75">result</span> <span style="color:#56b6c2">=</span> {}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 67</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 68</span><span>    <span style="color:#c678dd">local</span> <span style="color:#e06c75">count</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">node</span>:<span style="color:#e06c75">named_child_count</span>()
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 69</span><span>    <span style="color:#c678dd">for</span> <span style="color:#e06c75">idx</span> <span style="color:#56b6c2">=</span> <span style="color:#d19a66">0</span>, <span style="color:#e06c75">count</span> <span style="color:#56b6c2">-</span> <span style="color:#d19a66">1</span> <span style="color:#c678dd">do</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 70</span><span>      <span style="color:#e06c75">table.insert</span>(<span style="color:#e06c75">result</span>, <span style="color:#e06c75">transform</span>(<span style="color:#e06c75">get_node_text</span>(<span style="color:#e06c75">node</span>:<span style="color:#e06c75">named_child</span>(<span style="color:#e06c75">idx</span>), <span style="color:#d19a66">0</span>), <span style="color:#e06c75">info</span>))
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 71</span><span>      <span style="color:#c678dd">if</span> <span style="color:#e06c75">idx</span> <span style="color:#56b6c2">~=</span> <span style="color:#e06c75">count</span> <span style="color:#56b6c2">-</span> <span style="color:#d19a66">1</span> <span style="color:#c678dd">then</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 72</span><span>        <span style="color:#e06c75">table.insert</span>(<span style="color:#e06c75">result</span>, <span style="color:#e06c75">t</span> { <span style="color:#98c379">&#34;, &#34;</span> })
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 73</span><span>      <span style="color:#c678dd">end</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 74</span><span>    <span style="color:#c678dd">end</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 75</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 76</span><span>    <span style="color:#c678dd">return</span> <span style="color:#e06c75">result</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 77</span><span>  <span style="color:#c678dd">end</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 78</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 79</span><span>  [<span style="color:#98c379">&#34;type_identifier&#34;</span>] <span style="color:#56b6c2">=</span> <span style="color:#c678dd">function</span>(<span style="color:#e06c75">node</span>, <span style="color:#e06c75">info</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 80</span><span>    <span style="color:#c678dd">local</span> <span style="color:#e06c75">text</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">get_node_text</span>(<span style="color:#e06c75">node</span>, <span style="color:#d19a66">0</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 81</span><span>    <span style="color:#c678dd">return</span> { <span style="color:#e06c75">transform</span>(<span style="color:#e06c75">text</span>, <span style="color:#e06c75">info</span>) }
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 82</span><span>  <span style="color:#c678dd">end</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 83</span><span>}
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 84</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 85</span><span><span style="color:#7f848e">-- Adapted from https://github.com/tjdevries/config_manager/blob/1a93f03dfe254b5332b176ae8ec926e69a5d9805/xdg_config/nvim/lua/tj/snips/ft/go.lua</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 86</span><span><span style="color:#c678dd">local</span> <span style="color:#c678dd">function</span> <span style="color:#61afef;font-weight:bold">go_result_type</span>(<span style="color:#e06c75">info</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 87</span><span>  <span style="color:#c678dd">local</span> <span style="color:#e06c75">cursor_node</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">ts_utils.get_node_at_cursor</span>()
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 88</span><span>  <span style="color:#c678dd">local</span> <span style="color:#e06c75">scope</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">ts_locals.get_scope_tree</span>(<span style="color:#e06c75">cursor_node</span>, <span style="color:#d19a66">0</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 89</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 90</span><span>  <span style="color:#c678dd">local</span> <span style="color:#e06c75">function_node</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 91</span><span>  <span style="color:#c678dd">for</span> <span style="color:#e06c75">_</span>, <span style="color:#e06c75">v</span> <span style="color:#c678dd">in</span> <span style="color:#e06c75">ipairs</span>(<span style="color:#e06c75">scope</span>) <span style="color:#c678dd">do</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 92</span><span>    <span style="color:#c678dd">if</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 93</span><span>      <span style="color:#e06c75">v</span>:<span style="color:#e06c75">type</span>() <span style="color:#56b6c2">==</span> <span style="color:#98c379">&#34;function_declaration&#34;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 94</span><span>      <span style="color:#56b6c2">or</span> <span style="color:#e06c75">v</span>:<span style="color:#e06c75">type</span>() <span style="color:#56b6c2">==</span> <span style="color:#98c379">&#34;method_declaration&#34;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 95</span><span>      <span style="color:#56b6c2">or</span> <span style="color:#e06c75">v</span>:<span style="color:#e06c75">type</span>() <span style="color:#56b6c2">==</span> <span style="color:#98c379">&#34;func_literal&#34;</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 96</span><span>    <span style="color:#c678dd">then</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 97</span><span>      <span style="color:#e06c75">function_node</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">v</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 98</span><span>      <span style="color:#c678dd">break</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f"> 99</span><span>    <span style="color:#c678dd">end</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">100</span><span>  <span style="color:#c678dd">end</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">101</span><span>
</span></span><span style="display:flex; background-color:#3d4148"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">102</span><span>  <span style="color:#c678dd">local</span> <span style="color:#e06c75">query</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">vim.treesitter</span>.<span style="color:#e06c75">query.get</span>(<span style="color:#98c379">&#34;go&#34;</span>, <span style="color:#98c379">&#34;LuaSnip_Result&#34;</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">103</span><span>  <span style="color:#c678dd">for</span> <span style="color:#e06c75">_</span>, <span style="color:#e06c75">node</span> <span style="color:#c678dd">in</span> <span style="color:#e06c75">query</span>:<span style="color:#e06c75">iter_captures</span>(<span style="color:#e06c75">function_node</span>, <span style="color:#d19a66">0</span>) <span style="color:#c678dd">do</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">104</span><span>    <span style="color:#c678dd">if</span> <span style="color:#e06c75">handlers</span>[<span style="color:#e06c75">node</span>:<span style="color:#e06c75">type</span>()] <span style="color:#c678dd">then</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">105</span><span>      <span style="color:#c678dd">return</span> <span style="color:#e06c75">handlers</span>[<span style="color:#e06c75">node</span>:<span style="color:#e06c75">type</span>()](<span style="color:#e06c75">node</span>, <span style="color:#e06c75">info</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">106</span><span>    <span style="color:#c678dd">end</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">107</span><span>  <span style="color:#c678dd">end</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">108</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">109</span><span>  <span style="color:#c678dd">return</span> { <span style="color:#e06c75">t</span> <span style="color:#98c379">&#34;nil&#34;</span> }
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">110</span><span><span style="color:#c678dd">end</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">111</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">112</span><span><span style="color:#7f848e">-- Adapted from https://github.com/tjdevries/config_manager/blob/1a93f03dfe254b5332b176ae8ec926e69a5d9805/xdg_config/nvim/lua/tj/snips/ft/go.lua</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">113</span><span><span style="color:#c678dd">local</span> <span style="color:#e06c75">go_ret_vals</span> <span style="color:#56b6c2">=</span> <span style="color:#c678dd">function</span>(<span style="color:#e06c75">args</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">114</span><span>  <span style="color:#c678dd">return</span> <span style="color:#e06c75">snippet_from_nodes</span>(
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">115</span><span>    <span style="color:#e5c07b">nil</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">116</span><span>    <span style="color:#e06c75">go_result_type</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">117</span><span>      <span style="color:#e06c75">index</span> <span style="color:#56b6c2">=</span> <span style="color:#d19a66">0</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">118</span><span>      <span style="color:#e06c75">err_name</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">args</span>[<span style="color:#d19a66">1</span>][<span style="color:#d19a66">1</span>],
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">119</span><span>      <span style="color:#e06c75">func_name</span> <span style="color:#56b6c2">=</span> <span style="color:#e06c75">args</span>[<span style="color:#d19a66">2</span>][<span style="color:#d19a66">1</span>],
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">120</span><span>    }
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">121</span><span>  )
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">122</span><span><span style="color:#c678dd">end</span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">123</span><span>
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">124</span><span><span style="color:#c678dd">return</span> {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">125</span><span>  <span style="color:#7f848e">-- Adapted from https://github.com/tjdevries/config_manager/blob/1a93f03dfe254b5332b176ae8ec926e69a5d9805/xdg_config/nvim/lua/tj/snips/ft/go.lua</span>
</span></span><span style="display:flex; background-color:#3d4148"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">126</span><span>  <span style="color:#e06c75">s</span>(<span style="color:#98c379">&#34;smart_err&#34;</span>, {
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">127</span><span>    <span style="color:#e06c75">i</span>(<span style="color:#d19a66">1</span>, { <span style="color:#98c379">&#34;val&#34;</span> }),
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">128</span><span>    <span style="color:#e06c75">t</span> <span style="color:#98c379">&#34;, &#34;</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">129</span><span>    <span style="color:#e06c75">i</span>(<span style="color:#d19a66">2</span>, { <span style="color:#98c379">&#34;err&#34;</span> }),
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">130</span><span>    <span style="color:#e06c75">t</span> <span style="color:#98c379">&#34; := &#34;</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">131</span><span>    <span style="color:#e06c75">i</span>(<span style="color:#d19a66">3</span>, { <span style="color:#98c379">&#34;f&#34;</span> }),
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">132</span><span>    <span style="color:#e06c75">t</span> <span style="color:#98c379">&#34;(&#34;</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">133</span><span>    <span style="color:#e06c75">i</span>(<span style="color:#d19a66">4</span>),
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">134</span><span>    <span style="color:#e06c75">t</span> <span style="color:#98c379">&#34;)&#34;</span>,
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">135</span><span>    <span style="color:#e06c75">t</span> { <span style="color:#98c379">&#34;&#34;</span>, <span style="color:#98c379">&#34;if &#34;</span> },
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">136</span><span>    <span style="color:#e06c75">same</span>(<span style="color:#d19a66">2</span>),
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">137</span><span>    <span style="color:#e06c75">t</span> { <span style="color:#98c379">&#34; != nil {&#34;</span>, <span style="color:#98c379">&#34;</span><span style="color:#98c379">\t</span><span style="color:#98c379">return &#34;</span> },
</span></span><span style="display:flex; background-color:#3d4148"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">138</span><span>    <span style="color:#e06c75">d</span>(<span style="color:#d19a66">5</span>, <span style="color:#e06c75">go_ret_vals</span>, { <span style="color:#d19a66">2</span>, <span style="color:#d19a66">3</span> }),
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">139</span><span>    <span style="color:#e06c75">t</span> { <span style="color:#98c379">&#34;&#34;</span>, <span style="color:#98c379">&#34;}&#34;</span> },
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">140</span><span>    <span style="color:#e06c75">i</span>(<span style="color:#d19a66">0</span>),
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">141</span><span>  }),
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">142</span><span>}
</span></span></code></pre></div><p>We start by importing and aliasing some LuaSnip functions. The snippet itself is defined at the end (line 126). Most of those functions were covered in the <a href="https://joly.pw/blog/generating-snippets-with-luasnip/#3-generating-snippets-variants">previous post</a>, see there for calls to <code>s</code>, <code>i</code> and <code>t</code>. The clever part of this snippet is the <a href="https://github.com/L3MON4D3/LuaSnip/blob/master/DOC.md#dynamicnode">dynamic node</a> <code>d</code> on line 138. There, we call a function that queries (line 22 and 102) Treesitter to find the return types of the current function in Go code. Depending on the types found, default values for the type are used (line 33).</p>
<h3 id="treesitter-query">Treesitter Query</h3>
<p>The Treesitter query is where the magic happens, so let’s take a deeper look.</p>
<p>Treesitter parses code and builds a tree with node for various parts of the code. Each node can have children, like a function definition has a name, a body… This tree can be queried in a Lisp-like language (s-expressions). For instance, in our snippet definition, we use this query:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-scheme" data-lang="scheme"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">1</span><span>[
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">2</span><span>    (<span style="color:#61afef;font-weight:bold">method_declaration</span> <span style="color:#e06c75">result:</span> (<span style="color:#61afef;font-weight:bold">_</span>) <span style="color:#e06c75">@id</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">3</span><span>    (<span style="color:#61afef;font-weight:bold">function_declaration</span> <span style="color:#e06c75">result:</span> (<span style="color:#61afef;font-weight:bold">_</span>) <span style="color:#e06c75">@id</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">4</span><span>    (<span style="color:#61afef;font-weight:bold">func_literal</span> <span style="color:#e06c75">result:</span> (<span style="color:#61afef;font-weight:bold">_</span>) <span style="color:#e06c75">@id</span>)
</span></span><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#55595f">5</span><span>]
</span></span></code></pre></div><p>The <a href="https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries">bracket syntax</a> returns the nodes that match any of the patterns inside the brackets. So it’s effectively the union of all the nodes matched by any of the 3 patterns (on lines 2 to 4). Let’s take a concrete example and put the <a href="https://gist.github.com/cljoly/0b754259df036ba0163f2cdaad48e048#file-main-go">Go code</a> in the <a href="https://tree-sitter.github.io/tree-sitter/playground">Treesitter playground</a>, with a trimmed down version of the query:</p>
<p>
<img alt="The Treesitter playground with the example Go code above inserted at the top, the query in the middle and the tree at the bottom" loading="lazy" src="/blog/luasnip-and-treesitter-for-smarter-snippets/treesitter-playground.png"></p>
<p>The tree built by Treesitter is at the bottom, with the corresponding code at the top and the query in the middle. The <code>function_declaration</code> node is highlighted in gray in the tree, like the corresponding part of the code (from line 13 to line 22). This node has a number of children, with the function <code>name</code>, the <code>parameters</code> of the function, a <code>result</code> node for the return type and <code>body</code> for the body of the function between curly braces.</p>
<p>Taking the first pattern on the playground, slightly modified:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-scheme" data-lang="scheme"><span style="display:flex;"><span>    (<span style="color:#61afef;font-weight:bold">function_declaration</span> <span style="color:#e06c75">result:</span> (<span style="color:#61afef;font-weight:bold">_</span>) <span style="color:#e06c75">@id2</span>)
</span></span></code></pre></div><p>The part it captures is highlighted in blue in the Go code: <code>(*MyStruct, error)</code>. It makes sense, since the <code>function_declaration</code> (the part on the gray background) has a <code>result</code> child, that’s captured by <code>@id</code>.</p>
<p>Now, on to the second pattern:</p>
<div class="highlight"><pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-scheme" data-lang="scheme"><span style="display:flex;"><span>    (<span style="color:#61afef;font-weight:bold">func_literal</span> <span style="color:#e06c75">result:</span> (<span style="color:#61afef;font-weight:bold">_</span>) <span style="color:#e06c75">@id3</span>)
</span></span></code></pre></div><p>Similarly, further down in the <code>body</code> of that function, the return type <code>(bool, error, int, string)</code> of the anonymous function is matched.</p>
<h2 id="conclusion">Conclusion</h2>
<p>I started writing this post over a year ago. The snippet has been very stable and kept working as without changes, which is a testament to the stability of the LuaSnip (and Treesitter) APIs. I’m still using it when I write Go code, even if some corner cases (like custom structs) aren’t handled. The snippet is quite complicated and niche, so I’m not sure that I would have invested the time to write it myself. I probably don’t write enough Go code to <a href="https://xkcd.com/1205/">justify the investment</a>, but finding it shared by someone buried in their config file made it worth it.
I hope you have found this port useful, either to copy this particular snippet or as an example of advanced snippets.</p>
<p>This is the last post in a <a href="https://joly.pw/tags/luasnip/">series on LuaSnip</a>.</p>
<h2 id="resources">Resources</h2>
<p>If you want to dig deeper:</p>
<ul>
<li><a href="https://go.dev/blog/go1.13-errors">Working with Errors in Go 1.13</a></li>
<li><a href="https://github.com/L3MON4D3/LuaSnip/blob/master/DOC.md">LuaSnip documentation</a></li>
<li>Explore the Treesitter tree for any Neovim buffer where it is active with <code>:lua vim.treesitter.inspect_tree()</code></li>
<li>Treesitter’s <a href="https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries">Pattern Matching with Queries</a></li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>The test code is available as <a href="https://gist.github.com/cljoly/0b754259df036ba0163f2cdaad48e048#file-main-go">gist</a>.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>By the way, he has a very interesting <a href="https://www.twitch.tv/teej_dv">Twitch channel</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>At the time of writing at least. See <a href="https://perma.cc/XZW9-B2UA">perma.cc</a> and <a href="https://web.archive.org/web/20221202063059/https://github.com/tjdevries/config_manager/blob/master/README.md">the wayback machine</a> for a snapshot.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item></channel></rss>