Skip to main content
  1. Blog/

Local Snippets in Neovim With Blink Cmp

·578 words·3 mins·

Context
#

I’m using neovim for my daily tasks like programming, writing and for this blog post. This blog is built with hugo, though you can use archetypes for pre-templated articles, sometimes I want to add just a small piece of code/text/markdown into a post.

Snippets to the rescue! But how?

What I Did
#

As mentioned above, I am using neovim. And for completion I use a plugin called blink.nvim. blink.nvim does have the capability to use snippets and configure them in ~/.config/nvim/snippets, but this will force me to store all snippets in my neovim configuration.

I want to allow storing snippets in projects to keep local snippets as well as global snippets. I searched the blink.nvim documentation and found the custom-snippets section. It says, if I want to add additional folders I have to use sources.providers.snippets.opts.search_paths. Looking into the blink-reference documentation, it seems that search_paths is a list of strings.

Lua configuration
#

I came up with a solution. If there is a .snippets directory in the current working directory load it into the snippets.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
snippets = {
  score_offset = 80,
  opts = {
    search_paths = (function()
      local paths = { vim.fn.stdpath("config") .. "/snippets" }
      local cwd_snippets = vim.fn.getcwd() .. "/.snippets"
      if vim.fn.isdirectory(cwd_snippets) == 1 then
        table.insert(paths, cwd_snippets)
      end
      return paths
    end)(),
  },
},
  1. Setting paths to ~/.config/nvim/snippets which is the default config directory of neovim appended with /snippets.
  2. Get the current working directory and append it with /.snippets and store it in cwd_snippets
  3. Check if cwd_snippets is a directory, if yes insert it into paths
  4. return paths

This is all wrapped into a function and called in advance, cause search_paths is of type []string not a function

Project snippet configuration
#

Now, that I am able to load custom projects snippets, it is time to configure one snippet. Since the documentation states, that for now, only VSCode style snippets are supported lets check out how they work VSCode Snippets Documentation and nvim-scissors.

I started to create the ./.snippets/package.json and added it’s configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "name": "personal-snippets",
  "contributes": {
    "snippets": [
      {
        "language": "markdown",
        "path": "./markdown.json"
      }
    ]
  }
}

The name is not important, but the snippets property specifies where to find the snippets for a specific language.

I also created markdown.json for the actual snippet configuration.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "Podcast Recommendation": {
    "prefix": "podcast",
    "body": [
      "## ${1:Podcast Name}",
      "",
      "- **Topics:** ${2:Topic1, Topic2, Topic3}",
      "- **Language:** ${3:German}",
      "- **Links**: [ Website](${4:https://example.com/})",
      "",
      "> ${0:Description of the podcast.}"
    ],
    "description": "Insert a podcast recommendation"
  }
}

The prefix is the actual keyword that you have to type to get the snippet completion from blink.nvim. The body is the actuall snippet that gets inserted at your cursor position.

There is a special syntax $1 or ${1:Text} this is where the cursor will be to override the sample value. It starts at 1 and goes to the next number. Zero has special meaning, it always comes last.

Takeaway
#

Now I am able to use local defined snippets in all my projects, as well as global snippets in neovim’s configuration directory as configured in Lua Configuration. Each time I type podcast in neovim I get a snippet completion:

Snippet Completion

Useful Links#

Bitfoo
Author
Bitfoo
I wrangle Kubernetes clusters and automate infrastructure by day.
At night, I run self-hosted services to keep control over my data.
I write about real DevOps challenges and the tools I actually use.
Sometimes things break. That’s when I learn the most.