Giles Castel Like Snippets For Typst In Neovim

Hi all,
Using snippets with auto insertion made writing LaTex faster and the same is true for Typst!
Here are the Typst snippets I have made, which use Tree sitter to enforce the different contexts.
See here for the original idea: https://castel.dev
See here for article: LuaSnip Plugin Guide for LaTeX | Vim and LaTeX Series Part 2 | ejmastnak

local get_visual = function(args, parent)
  if #parent.snippet.env.LS_SELECT_RAW > 0 then
    return sn(nil, i(1, parent.snippet.env.LS_SELECT_RAW))
  else -- If LS_SELECT_RAW is empty, return a blank insert node
    return sn(nil, i(1))
  end
end

local line_begin = require("luasnip.extras.expand_conditions").line_begin
-- NOTE: Not in use local line_end = require("luasnip.extras.expand_conditions").line_end
local cond_obj = require("luasnip.extras.conditions")

-----------------------
-- PRESET CONDITIONS --
-----------------------
--- The wordTrig flag will only expand the snippet if
--- the proceeding character is NOT %w or `_`.
--- This is quite useful. The only issue is that the characters
--- on which we negate on hard coded. See here for the actual implementation
--- https://github.com/L3MON4D3/LuaSnip/blob/c9b9a22904c97d0eb69ccb9bab76037838326817/lua/luasnip/nodes/snippet.lua#L827
---
---
--- @param pattern string valid lua pattern
local function make_trigger_does_not_follow_char(pattern)
  local condition = function(line_to_cursor, matched_trigger)
    local line_to_trigger_len = #line_to_cursor - #matched_trigger
    if line_to_trigger_len == 0 then
      return true
    end
    return not string.sub(line_to_cursor, line_to_trigger_len, line_to_trigger_len):match(pattern)
  end
  return cond_obj.make_condition(condition)
end

local ls = require("luasnip")
local trigger_does_not_follow_alpha_num_char = make_trigger_does_not_follow_char("%w")
local trigger_does_not_follow_alpha_char = make_trigger_does_not_follow_char("%a")


--- TODO: Rename to Math mode
local MATH_NODES = {
  math = true,
  formula = true,
}

--- TODO: Rename to Content mode
local TEXT_NODES = {
  text = true,
  content = true,
}

--- TODO: Rename to Code mode
local CODE_NODES = {
  code = true,
}

local in_textzone = cond_obj.make_condition(function(check_parent)
  local node = vim.treesitter.get_node({ ignore_injections = false })
  while node do
    if node:type() == "text" then
      if check_parent then
        -- For \text{}
        local parent = node:parent()
        if parent and MATH_NODES[parent:type()] then
          return false
        end
      end

      return true
    elseif MATH_NODES[node:type()] then
      return false
    end
    node = node:parent()
  end
  return true
end)

local in_codezone = cond_obj.make_condition(function()
  local node = vim.treesitter.get_node({ ignore_injections = false })
  while node do
    if CODE_NODES[node:type()] then
      return true
    elseif TEXT_NODES[node:type()] or MATH_NODES[node:type()] then
      return false
    end
    node = node:parent()
  end
  return false
end)

local in_mathzone = cond_obj.make_condition(function()
  local node = vim.treesitter.get_node({ ignore_injections = false })
  while node do
    if MATH_NODES[node:type()] then
      return true
    elseif TEXT_NODES[node:type()] or CODE_NODES[node:type()] then
      return false
    end
    node = node:parent()
  end
  return false
end)

local iv = function(i, ...)
  return d(i, get_visual, ...)
end

-- Generating functions for Matrix/Cases - thanks L3MON4D3!
local generate_matrix = function(args, snip)
  local rows = tonumber(snip.captures[2])
  local cols = tonumber(snip.captures[3])
  local nodes = {}
  local ins_indx = 1
  for j = 1, rows do
    table.insert(nodes, r(ins_indx, tostring(j) .. "x1", i(1)))
    ins_indx = ins_indx + 1
    for k = 2, cols do
      table.insert(nodes, t(" , "))
      table.insert(nodes, r(ins_indx, tostring(j) .. "x" .. tostring(k), i(1)))
      ins_indx = ins_indx + 1
    end
    table.insert(nodes, t({ ";", "" }))
  end
  -- fix last node.
  nodes[#nodes] = t(";")
  return sn(nil, nodes)
end

-- update for cases
local generate_cases = function(args, snip)
  local rows = tonumber(snip.captures[1]) or 2 -- default option 2 for cases
  local cols = 2 -- fix to 2 cols
  local nodes = {}
  local ins_indx = 1
  for j = 1, rows do
    table.insert(nodes, r(ins_indx, tostring(j) .. "x1", i(1)))
    ins_indx = ins_indx + 1
    for k = 2, cols do
      table.insert(nodes, t(" & "))
      table.insert(nodes, r(ins_indx, tostring(j) .. "x" .. tostring(k), i(1)))
      ins_indx = ins_indx + 1
    end
    table.insert(nodes, t({ ",", "" }))
  end
  -- fix last node.
  table.remove(nodes, #nodes)
  return sn(nil, nodes)
end

return {
  -- NOTE: Remove auto snippet in the future,
  s({ trig = "toc", snippetType = "autosnippet" }, t("#outline()"), { condition = line_begin }),
  s(
    { trig = "#grid", snippetType = "autosnippet" },
    fmta(
      [[
#subpar.grid(
  columns: <>,
  inset: (top: 2em, left: 2em, right: 2em, bottom: 2em),
  gutter: 20pt,
  <>
  caption: [<>]
)<>
]],
      { i(1, "(1fr, 1fr)"), i(2), iv(3), i(0) }
    ),
    { condition = line_begin }
  ),
  s(
    { trig = "#figure", snippetType = "autosnippet" },
    fmta(
      [[
#figure(
caption: [<>],
supplement: <>,
<>
)<>
]],
      { i(1), i(2, "[Figure]"), iv(3), i(0) }
    ),
    { condition = line_begin }
  ),
  -- FIXME: This is not working reproduce by adding figure as an arg to a subgrid
  s(
    { trig = "figure", snippetType = "autosnippet" },
    fmta(
      [[
figure(
caption: [<>],
supplement: <>,
<>
)<>
]],
      { i(1), i(2, "[Figure]"), iv(3), i(0) }
    ),
    { condition = in_codezone }
  ),
  -- SUBSCRIPT
  -- s(
  --   { trig = "([%w%)%]%}|])ss", wordTrig = false, regTrig = true, snippetType = "autosnippet" },
  --   fmta("<>_(<>)", {
  --     f(function(_, snip)
  --       return snip.captures[1]
  --     end),
  --     d(1, get_visual),
  --   }),
  --   { condition = in_mathzone }
  -- ),
  s(
    {
      trig = "([%w%)%]%}|])jj",
      desc = "Subscript(no ambiguity)",
      wordTrig = false,
      regTrig = true,
      snippetType = "autosnippet",
    },
    fmta("<>_(<>)", {
      f(function(_, snip)
        return snip.captures[1]
      end),
      d(1, get_visual),
    }),
    { condition = in_mathzone }
  ),
  -- s(
  --   { trig = "([%w%)%]%}|])s([ijknmt])", wordTrig = false, regTrig = true, snippetType = "autosnippet" },
  --   fmta("<>_(<>)<>", {
  --     f(function(_, snip)
  --       return snip.captures[1]
  --     end),
  --     f(function(_, snip)
  --       return snip.captures[2]
  --     end),
  --     i(0),
  --   }),
  --   { condition = in_mathzone }
  -- ),
  s(
    {
      trig = "([%w%)%]%}|])j([ijknmtvd])",
      wordTrig = false,
      desc = "subscript",
      regTrig = true,
      snippetType = "autosnippet",
    },
    fmta("<>_(<>)<>", {
      f(function(_, snip)
        return snip.captures[1]
      end),
      f(function(_, snip)
        return snip.captures[2]
      end),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  -- SUBSCRIPT
  -- s(
  --   { trig = "([%w%)%]%}|])s(%d+)", wordTrig = false, regTrig = true, snippetType = "autosnippet" },
  --   fmta("<>_(<>)<>", {
  --     f(function(_, snip)
  --       return snip.captures[1]
  --     end),
  --     f(function(_, snip)
  --       return snip.captures[2]
  --     end),
  --     i(0),
  --   }),
  --   { condition = in_mathzone }
  -- ),
  -- SUBSCRIPT
  s(
    { trig = "([%w%)%]%}|])j(%d+)", wordTrig = false, regTrig = true, snippetType = "autosnippet" },
    fmta("<>_(<>)<>", {
      f(function(_, snip)
        return snip.captures[1]
      end),
      f(function(_, snip)
        return snip.captures[2]
      end),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  s(
    {
      trig = "([%w%)%]%}|])J",
      desc = "Subscript(no ambiguity)",
      wordTrig = false,
      regTrig = true,
      snippetType = "autosnippet",
    },
    fmta("<>_(<>)", {
      f(function(_, snip)
        return snip.captures[1]
      end),
      d(1, get_visual),
    }),
    { condition = in_mathzone }
  ),
  -- -- SUPERSCRIPT
  -- s(
  --   { trig = "([%w%)%]%}%|])aa", wordTrig = false, regTrig = true, snippetType = "autosnippet" },
  --   fmta("<>^(<>)<>", {
  --     f(function(_, snip)
  --       return snip.captures[1]
  --     end),
  --     d(1, get_visual),
  --     i(0),
  --   }),
  --   { condition = in_mathzone }
  -- ),
  s(
    { trig = "([%w%)%]%}|])kk", wordTrig = false, regTrig = true, snippetType = "autosnippet" },
    fmta("<>^(<>)", {
      f(function(_, snip)
        return snip.captures[1]
      end),
      d(1, get_visual),
    }),
    { condition = in_mathzone }
  ),
  -- s(
  --   { trig = "([%w%)%]%}|])a(%d+)", wordTrig = false, regTrig = true, snippetType = "autosnippet" },
  --   fmta("<>^(<>)<>", {
  --     f(function(_, snip)
  --       return snip.captures[1]
  --     end),
  --     f(function(_, snip)
  --       return snip.captures[2]
  --     end),
  --     i(0),
  --   }),
  --   { condition = in_mathzone }
  -- ),
  s(
    { trig = "([%w%)%]%}|])k(%d+)", wordTrig = false, regTrig = true, snippetType = "autosnippet" },
    fmta("<>^(<>)<>", {
      f(function(_, snip)
        return snip.captures[1]
      end),
      f(function(_, snip)
        return snip.captures[2]
      end),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  --- TODO: Conflicts with mat no t then
  -- s(
  --   { trig = "([%w%)%]%}|])a([ijknm])", wordTrig = false, regTrig = true, snippetType = "autosnippet" },
  --   fmta("<>^(<>)<>", {
  --     f(function(_, snip)
  --       return snip.captures[1]
  --     end),
  --     f(function(_, snip)
  --       return snip.captures[2]
  --     end),
  --     i(0),
  --   }),
  --   { condition = in_mathzone }
  -- ),
  s(
    { trig = "([%w%)%]%}|])k([ijknmtvd])", wordTrig = false, regTrig = true, snippetType = "autosnippet" },
    fmta("<>^(<>)<>", {
      f(function(_, snip)
        return snip.captures[1]
      end),
      f(function(_, snip)
        return snip.captures[2]
      end),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  s(
    { trig = "([%w%)%]%}|])K", wordTrig = false, regTrig = true, snippetType = "autosnippet" },
    fmta("<>^(<>)", {
      f(function(_, snip)
        return snip.captures[1]
      end),
      d(1, get_visual),
    }),
    { condition = in_mathzone }
  ),
  -- INVERSE
  s(
    { trig = "([%w%)%]%}])inv", wordTrig = false, regTrig = true, snippetType = "autosnippet" },
    fmta([[<>^(-1)<>]], {
      f(function(_, snip)
        return snip.captures[1]
      end),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  -- DAGGER
  s(
    { trig = "([%w%)%]%}])dagger", wordTrig = false, regTrig = true, snippetType = "autosnippet" },
    fmta([[<>^(dagger)<>]], {
      f(function(_, snip)
        return snip.captures[1]
      end),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  --- This kinda works with \infty and \int too!
  --- NOTE: This won't expand on newline but I tried a regTrig and that did not work
  --- its probably because trigger_does_not_follow_alpha_char has a bug on newlines
  -- s(
  --   { trig = "in ", wordTrig = false, snippetType = "autosnippet" },
  --   t("\\in "),
  --   { condition = in_mathzone * trigger_does_not_follow_alpha_char }
  -- ),
  s(
    { trig = "int", wordTrig = false, snippetType = "autosnippet" },
    fmta("integral_(<>)^(<>)<>", {
      d(1, get_visual),
      i(2),
      i(0),
    }),
    { condition = in_mathzone * trigger_does_not_follow_alpha_char }
  ),
  --- https://github.com/michaelfortunato/luasnip-latex-snippets.nvim/blob/main/lua/luasnip-latex-snippets/math_iA.lua
  --- Again, all of these are covered correctly by Typst!
  -- s({ trig = "RR", snippetType = "autosnippet" }, t("\\mathbb{R}"), { condition = in_mathzone }),
  -- s({ trig = "QQ", snippetType = "autosnippet" }, t("\\mathbb{Q}"), { condition = in_mathzone }),
  -- s({ trig = "NN", snippetType = "autosnippet" }, t("\\mathbb{N}"), { condition = in_mathzone }),
  -- s({ trig = "ZZ", snippetType = "autosnippet" }, t("\\mathbb{Z}"), { condition = in_mathzone }),
  --- Relations
  s({
    trig = "=",
    name = "_insert_equal_sign_as_text_node",
    desc = "Insert a text node in math mode to tab over it. It's nice!",
    hidden = true,
    snippetType = "autosnippet",
  }, t("="), { condition = in_mathzone }),
  s({ trig = "implies", snippetType = "autosnippet" }, t("==>"), { condition = in_mathzone }),
  --- For now going to make this a snippet
  s({ trig = "implies", snippetType = "autosnippet" }, t("==>"), { condition = in_mathzone }),
  s({ trig = "neq", snippetType = "autosnippet" }, t("!="), { condition = in_mathzone }),
  s({ trig = "leq", snippetType = "autosnippet" }, t("<="), { condition = in_mathzone }),
  s({ trig = "geq", snippetType = "autosnippet" }, t(">="), { condition = in_mathzone }),
  s({ trig = "isomorphism", snippetType = "autosnippet" }, t("tilde.equiv"), { condition = in_mathzone }),
  -- s({ trig = "-->", snippetType = "autosnippet" }, t(" arrow.r.long"), { condition = in_mathzone }),
  -- s({ trig = ">=", snippetType = "autosnippet" }, t("gt.eq"), { condition = in_mathzone }),
  -- s({ trig = "<=", snippetType = "autosnippet" }, t("\\leq"), { condition = in_mathzone }),
  s({ trig = "~~", snippetType = "autosnippet" }, t("tilde.op"), { condition = in_mathzone }),
  s({ trig = "sim", snippetType = "autosnippet" }, t("tilde.op"), { condition = in_mathzone }),
  s({ trig = "to ", snippetType = "autosnippet" }, t("-> "), { condition = in_mathzone }),
  --- TODO: See if I actually use these
  s({ trig = "<|", snippetType = "autosnippet" }, t("lt.tri"), { condition = in_mathzone }),
  s({ trig = "<j", snippetType = "autosnippet" }, t("lt.tri.eq"), { condition = in_mathzone }),
  -- s({ trig = "lt.tri.eq", snippetType = "autosnippet" }, t("lt.tri.eq"), { condition = in_mathzone }),
  -- s({ trig = "lt.tri", snippetType = "autosnippet" }, t("lt.tri "), { condition = in_mathzone }),
  s({ trig = "normalsubgroup", snippetType = "autosnippet" }, t("lt.tri.eq"), { condition = in_mathzone }),
  s({ trig = "normalpsubgroup", snippetType = "autosnippet" }, t("lt.tri"), { condition = in_mathzone }),
  -- Operators
  s({ trig = "||", snippetType = "autosnippet" }, fmta("norm(<>)<>", { i(1), i(0) }), { condition = in_mathzone }),
  --- FIXME: This one is tricky, I think this works though smoothly so long as I put the space back `\mid `
  s({ trig = "| ", snippetType = "autosnippet" }, t("bar.v "), { condition = in_mathzone }),
  -- Interesting...
  s(
    { trig = "|([^%s][^|]*)|", regTrig = true, snippetType = "autosnippet" },
    fmta("abs(<>)<>", { f(function(_, snip)
      return snip.captures[1]
    end), i(0) }),
    { condition = in_mathzone }
  ),
  -- --- Let "@" namespace operators
  s({ trig = "@g", snippetType = "autosnippet" }, t("nabla"), { condition = in_mathzone }),
  s({ trig = "@p", snippetType = "autosnippet" }, t("partial"), { condition = in_mathzone }),
  s({ trig = "@c", snippetType = "autosnippet" }, t("compose"), { condition = in_mathzone }),
  s(
    { trig = "dxdy", snippetType = "autosnippet" },
    fmta([[frac((d <>,d <>)<>]], {
      iv(1),
      i(2),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  s(
    { trig = "ddx", snippetType = "autosnippet" },
    fmta([[\frac{d}{d<>}<>]], {
      d(1, get_visual),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  s(
    { trig = "pxpy", snippetType = "autosnippet" },
    fmta([[\frac{\partial <>}{\partial <>}<>]], {
      d(1, get_visual),
      i(2),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  s(
    { trig = "ppx", snippetType = "autosnippet" },
    fmta([[\frac{\partial}{\partial <>}<>]], {
      iv(1),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  s(
    { trig = "lr(", wordTrig = false, snippetType = "autosnippet" },
    fmta("lr(( <> ))<>", {
      iv(1),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  s(
    { trig = "lr{", wordTrig = false, snippetType = "autosnippet" },
    fmta("lr({ <> })<>", {
      iv(1),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  s(
    { trig = "lr[", wordTrig = false, snippetType = "autosnippet" },
    fmta("lr([ <> ])<>", {
      iv(1),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  -- TODO: Really hink about if you want these vvv
  s(
    { trig = "(", wordTrig = false, desc = "Autopairs", snippetType = "autosnippet" },
    fmta("(<>)<>", {
      iv(1),
      i(0),
    }),
    { condition = -in_textzone * (in_mathzone + in_codezone) }
  ),
  s(
    { trig = "{", desc = "Autopairs", snippetType = "autosnippet" },
    fmta("{<>}<>", {
      iv(1),
      i(0),
    }),
    { condition = in_mathzone + in_codezone }
  ),
  s(
    { trig = "[", wordTrig = false, desc = "Autopairs", snippetType = "autosnippet" },
    fmta("[<>]<>", {
      iv(1),
      i(0),
    }),
    { condition = in_mathzone + in_codezone }
  ),
  -- TODO: Really hink about if you want these ^^^
  s(
    { trig = [["]], wordTrig = false, snippetType = "autosnippet" },
    fmta([["<>"<>]], {
      iv(1),
      i(0),
    }),
    { condition = trigger_does_not_follow_alpha_char * (in_mathzone + in_codezone) }
  ),
  s(
    { trig = "`", wordTrig = false, snippetType = "autosnippet" },
    fmta("`<>`<>", {
      i(1),
      i(0),
    }),
    { condition = -in_mathzone }
  ),
  -- NOTE: Typst is the same!
  -- s(
  --   { trig = "exists", wordTrig = false, snippetType = "autosnippet" },
  --   t("\\exists"),
  --   { condition = in_mathzone * trigger_does_not_follow_alpha_char }
  -- ),
  -- NOTE: Typst is the same!
  -- s(
  --   { trig = "forall", wordTrig = false, snippetType = "autosnippet" },
  --   t("\\forall"),
  --   { condition = in_mathzone * trigger_does_not_follow_alpha_char }
  -- ),
  --- Accents - Tilde
  s(
    { trig = "tilde", wordTrig = false, snippetType = "autosnippet" },
    fmta([[tilde<>]], {
      i(0),
    }),
    { condition = in_mathzone * trigger_does_not_follow_alpha_char }
  ),
  --- Accents - hat
  s(
    { trig = "hat", wordTrig = false, snippetType = "autosnippet" },
    fmta([[\hat<>]], {
      i(0),
    }),
    { condition = in_mathzone * trigger_does_not_follow_alpha_char }
  ),
  --- BAR
  --   TODO: Which is faster? These two? or the dynamic node one?
  --- Enter display mode quickly
  s(
    { trig = "MM", wordTrig = false, regTrig = false, snippetType = "autosnippet" },
    fmta(
      [[
$
  <>
$<>]],
      {
        d(1, get_visual),
        i(0),
      }
    ),
    { condition = line_begin }
  ),
  s(
    { trig = "MM", wordTrig = false, regTrig = false, snippetType = "autosnippet" },
    fmta(
      [[

$
  <>
$<>]],
      {
        d(1, get_visual),
        i(0),
      },
      { trim_empty = false }
    ),
    { condition = -line_begin * trigger_does_not_follow_alpha_char }
  ),
  --  TODO: Which is faster?
  --   s(
  --     { trig = "MM", wordTrig = false, regTrig = false, snippetType = "autosnippet" },
  --     fmta(
  --       [[<>
  --   <>
  -- $<>]],
  --       {
  --         d(1, function()
  --           local line = vim.api.nvim_get_current_line()
  --           if line:sub(1, -(2 + 1)):match("^%s*$") then
  --             return sn(nil, t({ "$" })) -- Just start of math
  --           else
  --             return sn(nil, t({ "", "$" })) -- Newline + start of math
  --           end
  --         end, {}),
  --         d(2, get_visual),
  --         i(0),
  --       }
  --     ),
  --     { condition = trigger_does_not_follow_alpha_char }
  --   ),
  --- Enter inline mathmode quickly
  s(
    { trig = "mm", wordtrig = false, snippetType = "autosnippet" },
    fmta([[$<>$<>]], {
      d(1, get_visual),
      i(0),
    }),
    { condition = trigger_does_not_follow_alpha_char }
  ),
  s(
    { trig = "(%a)mb", regTrig = true, wordTrig = false, snippetType = "autosnippet" },
    fmta([[upright(bold(<>))<>]], {
      f(function(_, snip)
        return snip.captures[1]
      end),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  s(
    { trig = "mb", wordTrig = false, snippetType = "autosnippet" },
    fmta([[upright(bold(<>))<>]], {
      d(1, get_visual),
      i(0),
    }),
    { condition = in_mathzone * trigger_does_not_follow_alpha_char }
  ),
  s(
    { trig = "mB", wordTrig = false, snippetType = "autosnippet" },
    fmta([[bb(<>)<>]], {
      d(1, get_visual),
      i(0),
    }),
    { condition = in_mathzone * trigger_does_not_follow_alpha_char }
  ),
  s(
    { trig = "(%a)mB", regTrig = true, wordTrig = false, snippetType = "autosnippet" },
    fmta([[bb(<>)<>]], {
      f(function(_, snip)
        return snip.captures[1]
      end),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  s(
    { trig = "mf", wordTrig = false, snippetType = "autosnippet" },
    fmta([[frak(<>)<>]], {
      d(1, get_visual),
      i(0),
    }),
    { condition = in_mathzone * trigger_does_not_follow_alpha_char }
  ),
  s(
    { trig = "(%a)mf", regTrig = true, wordTrig = false, snippetType = "autosnippet" },
    fmta([[frak(<>)<>]], {
      f(function(_, snip)
        return snip.captures[1]
      end),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  -- FRACTION
  s(
    { trig = "ff", wordTrig = false, snippetType = "autosnippet" },
    fmta("frac(<>,<>)<>", {
      d(1, get_visual),
      i(2),
      i(0),
    }),
    { condition = in_mathzone * trigger_does_not_follow_alpha_char }
  ),
  -- SUMMATION
  s(
    { trig = "sum", wordTrig = false, snippetType = "autosnippet" },
    fmta("sum_(<>)^(<>)<>", {
      d(1, get_visual),
      i(2),
      i(0),
    }),
    { condition = in_mathzone * trigger_does_not_follow_alpha_char }
  ),
  s(
    { trig = "mc", wordTrig = false, snippetType = "autosnippet" },
    fmta([[cal(<>)<>]], {
      d(1, get_visual),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  s(
    { trig = "mcal", wordTrig = false, snippetType = "autosnippet" },
    fmta([[cal(<>)<>]], {
      d(1, get_visual),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  s(
    { trig = "cal", wordTrig = false, snippetType = "autosnippet" },
    fmta([[cal(<>)<>]], {
      d(1, get_visual),
      i(0),
    }),
    { condition = in_mathzone }
  ),
  -- SECTION
  s(
    { trig = "h1", snippetType = "autosnippet" },
    fmta(
      [[= <> <<sec:<>>>
<>]],
      {
        iv(1),
        l(l._1:gsub("%s", "-"), 1),
        i(0),
      }
    ),
    { condition = in_textzone }
  ),
  -- SUBSECTION
  s(
    { trig = "h2", snippetType = "autosnippet" },
    fmta(
      [[== <>  <<subsec:<>>>
<>]],
      {
        iv(1),
        l(l._1:gsub("%s", "-"), 1),
        i(0),
      }
    ),
    { condition = in_textzone }
  ),
  -- SUBSUBSECTION
  s(
    { trig = "h3", snippetType = "autosnippet" },
    fmta(
      [[=== <>  <<subsubsec:<>>>
<>]],
      {
        iv(1),
        l(l._1:gsub("%s", "-"), 1),
        i(0),
      }
    ),
    { condition = in_textzone }
  ),
  s(
    { trig = "h4", snippetType = "autosnippet" },
    fmta(
      [[par(
  // leading: length,
  // spacing: length,
  // justify: bool,
  // linebreaks: autostr,
  // first-line-indent: lengthdictionary,
  // hanging-indent: length,
  <>) <<paragraph:<>>>
<>]],
      {
        iv(1),
        l(l._1:gsub("%s", "-"), 1),
        i(0),
      }
    ),
    { condition = in_textzone }
  ),
  --   Not supported in typst
  --   s(
  --     { trig = "h5", snippetType = "autosnippet" },
  --     fmta([[\subparagraph{<>}]], {
  --       d(1, get_visual),
  --     }),
  --     { condition = in_textzone }
  --   ),
  --- PART (only applicable to book document class)
  s(
    { trig = "tt", wordTrig = false, snippetType = "autosnippet" },
    fmta([["<>"<>]], {
      d(1, get_visual),
      i(0),
    }),
    { condition = trigger_does_not_follow_alpha_char * in_mathzone }
  ),
  s(
    { trig = "tii", wordTrig = false, snippetType = "autosnippet" },
    fmta([[italic(<>)<>]], {
      d(1, get_visual),
      i(0),
    }),
    { condition = trigger_does_not_follow_alpha_char * in_mathzone }
  ),
  s(
    { trig = "tii", wordTrig = false, snippetType = "autosnippet" },
    fmta([[_<>_<>]], {
      d(1, get_visual),
      i(0),
    }),
    { condition = trigger_does_not_follow_alpha_char * in_textzone }
  ),
  s(
    { trig = "tbb", wordTrig = false, snippetType = "autosnippet" },
    fmta([[bold(<>)<>]], {
      d(1, get_visual),
      i(0),
    }),
    { condition = trigger_does_not_follow_alpha_char * in_mathzone }
  ),
  s(
    { trig = "tbb", wordTrig = false, snippetType = "autosnippet" },
    fmta([[*<>*<>]], {
      d(1, get_visual),
      i(0),
    }),
    { condition = trigger_does_not_follow_alpha_char * in_textzone }
  ),
  --- GREEK BEGIN
  s({ trig = ";a", wordTrig = false, snippetType = "autosnippet" }, {
    t("alpha"),
  }),
  s({ trig = ";b", wordTrig = false, snippetType = "autosnippet" }, {
    t("beta"),
  }),
  s({ trig = ";g", wordTrig = false, snippetType = "autosnippet" }, {
    t("gamma"),
  }),
  s({ trig = ";G", wordTrig = false, snippetType = "autosnippet" }, {
    t("Gamma"),
  }),
  s({ trig = ";d", wordTrig = false, snippetType = "autosnippet" }, {
    t("delta"),
  }),
  s({ trig = ";D", wordTrig = false, snippetType = "autosnippet" }, {
    t("Delta"),
  }),
  s({ trig = ";e", wordTrig = false, snippetType = "autosnippet" }, {
    t("epsilon"),
  }),
  s({ trig = ";ve", wordTrig = false, snippetType = "autosnippet" }, {
    t("varepsilon"),
  }),
  s({ trig = ";z", wordTrig = false, snippetType = "autosnippet" }, {
    t("zeta"),
  }),
  s({ trig = ";h", wordTrig = false, snippetType = "autosnippet" }, {
    t("eta"),
  }),
  s({ trig = ";o", wordTrig = false, snippetType = "autosnippet" }, {
    t("theta"),
  }),
  s({ trig = ";vo", wordTrig = false, snippetType = "autosnippet" }, {
    t("vartheta"),
  }),
  s({ trig = ";O", wordTrig = false, snippetType = "autosnippet" }, {
    t("Theta"),
  }),
  s({ trig = ";k", wordTrig = false, snippetType = "autosnippet" }, {
    t("kappa"),
  }),
  s({ trig = ";l", wordTrig = false, snippetType = "autosnippet" }, {
    t("lambda"),
  }),
  s({ trig = ";L", wordTrig = false, snippetType = "autosnippet" }, {
    t("Lambda"),
  }),
  s({ trig = ";m", wordTrig = false, snippetType = "autosnippet" }, {
    t("mu"),
  }),
  s({ trig = ";n", wordTrig = false, snippetType = "autosnippet" }, {
    t("nu"),
  }),
  s({ trig = ";x", wordTrig = false, snippetType = "autosnippet" }, {
    t("xi"),
  }),
  s({ trig = ";X", wordTrig = false, snippetType = "autosnippet" }, {
    t("Xi"),
  }),
  s({ trig = ";i", wordTrig = false, snippetType = "autosnippet" }, {
    t("pi"),
  }),
  s({ trig = ";I", wordTrig = false, snippetType = "autosnippet" }, {
    t("Pi"),
  }),
  s({ trig = ";r", wordTrig = false, snippetType = "autosnippet" }, {
    t("rho"),
  }),
  s({ trig = ";s", wordTrig = false, snippetType = "autosnippet" }, {
    t("sigma"),
  }),
  s({ trig = ";S", wordTrig = false, snippetType = "autosnippet" }, {
    t("Sigma"),
  }),
  s({ trig = ";t", wordTrig = false, snippetType = "autosnippet" }, {
    t("tau"),
  }),
  s({ trig = ";f", wordTrig = false, snippetType = "autosnippet" }, {
    t("phi"),
  }),
  s({ trig = ";vf", wordTrig = false, snippetType = "autosnippet" }, {
    t("varphi"),
  }),
  s({ trig = ";F", wordTrig = false, snippetType = "autosnippet" }, {
    t("Phi"),
  }),
  s({ trig = ";c", wordTrig = false, snippetType = "autosnippet" }, {
    t("chi"),
  }),
  s({ trig = ";p", wordTrig = false, snippetType = "autosnippet" }, {
    t("psi"),
  }),
  s({ trig = ";P", wordTrig = false, snippetType = "autosnippet" }, {
    t("Psi"),
  }),
  s({ trig = ";w", wordTrig = false, snippetType = "autosnippet" }, {
    t("omega"),
  }),
  s({ trig = ";W", wordTrig = false, snippetType = "autosnippet" }, {
    t("Omega"),
  }),
  --   s(
  --     { trig = "al", snippetType = "autosnippet" },
  --     fmta(
  --       [[
  -- $
  --   <> & <> \
  --   <>
  -- $
  --       ]],
  --       {
  --         i(1),
  --         i(2),
  --         i(0),
  --       }
  --     ),
  --     { condition = line_begin }
  --   ),
  s(
    { trig = "bb", regTrig = true, snippetType = "autosnippet" },
    fmta(
      [[
        #<>[
<>
]<>
      ]],
      {
        i(1),
        d(2, get_visual),
        i(0),
      }
    ),
    { condition = line_begin }
  ),
  -- Matrices and Cases
  s(
    {
      trig = "([bBpvV]?)mat(%d+)x(%d+)",
      name = "[bBpvV]matrix",
      desc = "matrices",
      regTrig = true,
      snippetType = "autosnippet",
    },
    fmta(
      [[
mat(delim:<>,
<>
)<>]],
      {
        f(function(_, snip)
          local prefix = snip.captures[1] or ""
          if (prefix == "b") or (prefix == "B") then
            return '"["'
          elseif (prefix == "p") or prefix == "v" or prefix == "V" then
            return '"("'
          else
            return '"["'
          end
        end),
        d(1, generate_matrix),
        i(0),
      }
    ),
    { condition = in_mathzone }
  ),

  s(
    { trig = "(%d?)cases", name = "cases", desc = "cases", regTrig = true, snippetType = "autosnippet" },
    fmta(
      [[
cases(
<>
)<>]],
      { d(1, generate_cases), i(0) }
    ),
    { condition = in_mathzone }
  ),

  s(
    { trig = "plotf", name = "Plot Function", desc = "Plot a function using Cetz", snippetType = "autosnippet" },
    fmta(
      [[
canvas({
plot.plot(size: (5, 5), {
    plot.add(domain: (<>, <>), { x =>> <> })
})})<>]],
      { i(1, "0"), i(2, "5"), i(3, "calc.pow(x,2)"), i(0) }
    ),
    { condition = -in_mathzone }
  ),

  s(
    {
      trig = "#imagefig",
      name = "Image Function",
      desc = "Adds a figure showing an image",
      snippetType = "autosnippet",
    },
    fmta(
      [[
#figure(
  image(<>),
  caption: [<>]
)]],
      { iv(1), i(2) }
    ),
    { condition = -in_mathzone }
  ),
}
2 Likes