Skip to content

Snippets

Ben Garren edited this page Jul 11, 2025 · 2 revisions

Snippets API is available in v0.10+

Integration with a snippet engine, e.g. LuaSnip can amplify your checkmate.nvim workflow.

Instead of having to manually create write combinations of text and metadata that you may use often, you can define snippets to quickly insert 'templated' todo items, saving keystrokes and maintaining consistency.

Why use snippets?

Without snippets (multiple steps):

  1. Create todo: - □
  2. Type description
  3. Add priority: @priority(high)
  4. Add assignee: @assigned(john)

With snippets (one step):

  • Type: .task
  • Get: - □ Task: |cursor| @priority(medium) @assigned(me)

You can create additional snippets for features, bugs, notes/topics, etc. The possibilities are endless!

Getting started

Follow the LuaSnip documentation for loading/adding snippets. Remember, these can also be stored in separate files and loaded en bloc (see Lua loader).

Here's a minimal example:

local ls = require("luasnip")

ls.add_snippets("markdown", {

  -- Adds a simple text node with regular Markdown checkbox (checkmate.nvim
  -- will automatically convert this upon leaving insert mode)
  ls.s({ trig = ".todo", desc = "Basic Todo" }, { ls.t("- [ ] New TODO") }),

})

Using Checkmate's Snippets API

checkmate.nvim exposes a snippet API to reduce some boilerplate of creating todo snippets. See checkmate.snippets.

checkmate.snippets.todo(opts)

Returns a LuaSnip snippet that expands to a custom todo string

Options

See checkmate.TodoSnippetOpts for full opts, but includes:

  • trigger (string) - the string used as the LuaSnip trig

  • text? (string) - default string to add (before any metadata). Will fallback to use desc if nil.

  • metadata? (table) - where each key is a metadata tag/name and the value is one of the following (see checkmate.MetadataSnippetType) which determines how the metadata's default value is obtained:

    • boolean Will place a text node with the metadata's get_value() returning the string
    • string Will place a text node with this string as the node text
    • number Will place an insert node at this position. See InsertNode.
    • function(captures: any): string Will place a text node based on the return of this function. Captures are returned when the trigger is interpreted as a Lua pattern with capture groups. See trigEngine in LuaSnip documentation.
  • ls_context? (table) - the context table passed to LuaSnip snippet. Will override trigger and desc above, if defined.

  • ls_opts? (table) - the opts table passed to LuaSnip snippet.

Example 1: Define a "bug" todo with @bug and @priority metadata

local cms = require("checkmate.snippets")
local ls = require("luasnip")

ls.add_snippets("markdown", {
  -- use checkmate.snippet's todo helper
  cms.todo({
    trigger = ".bug",
    text = "New BUG",
    metadata = {
      bug = "",
      priority = true,
    },
    ls_context = {
      snippetType = "autosnippet",
    },
  }),
})

With this setup, you can now type ".bug" can get the following behavior:

  • LuaSnip expansion to - □ New BUG @bug() @priority(medium)
  • The @bug tag's value is set as empty and the @priority tag's value is computed from its get_value function.

Example 2: Define a "issue" todo with capture of the issue # from the trigger

local cms = require("checkmate.snippets")
local ls = require("luasnip")

ls.add_snippets("markdown", {
  cms.todo({
    trigger = "%.i(%d+)", -- ".i" followed by a number (captured)
    desc = "New ISSUE",
    metadata = {
      issue = function(captures)
        local issue_num = captures[1] or ""
        return "#" .. issue_num
      end,
    },
    ls_context = {
      snippetType = "snippet",
      regTrig = true,
    },
  }),
}

With this setup, you can now type ".i45" can get the following behavior:

  • LuaSnip expansion to - □ New ISSUE @issue(#45)
  • The @issue tag obtains its value from the capture group from the regTrig trigger

checkmate.snippets.metadata(opts)

Returns a LuaSnip snippet that expands to a metadata @tag(value) string

Options

See checkmate.MetadataSnippetOpts for full opts, but includes:

  • tag (string) - Metadata tag name
  • value? (string) - Metadata value to insert. If nil, will use the metadata's get_value function
  • auto_select? - Selects the metadata's value on insert. Otherwise, moves cursor to the end. Default: false.

Example 1: Use @p as a trigger for @priority

local cms = require("checkmate.snippets")
local ls = require("luasnip")

ls.add_snippets("markdown", {
  cms.metadata({
    trigger = "@p",
    tag = "priority",
    desc = "@priority",
    auto_select = true,
    ls_context = { snippetType = "autosnippet" }
  })
})

Will insert a @priority(<default>) tag where <default> is the value obtained from the get_value function, or "".

Recipes

My Issue Tracker

local cms = require("checkmate.snippets")
cms.todo({
  trigger = "%.i(%d+)",
  desc = "New ISSUE",
  metadata = {
    issue = function(captures)
      local issue_num = captures[1] or ""
      return "#" .. issue_num
    end,
    url = function(captures)
      local repo = vim.fn
        .system("git remote get-url origin")
        :gsub("\n", "")
        :gsub("%.git$", "")
        :gsub("^.*:", "https://github.com/")
      return string.format("%s/issues/%s", repo, captures[1])
    end,
  },
  ls_context = {
    snippetType = "snippet",
    regTrig = true,
  },
})

Expanding ".i500" will result in:

- □ New ISSUE @url(https://github.com/bngarren/checkmate.nvim/issues/500) @issue(#500)