A more ergonomic snippet facility wrapping LuaSnip, with tex and Markdown snippets.
Snippets are powerful, but to utilize them maximally, one should write his own snippets. Otherwise it’s more a LSP thing.
LuaSnip has provided a good mechanism for computers to implement the snippet functionality, by structuring all information in Lua tables and breaking up the snippet into nodes. However, writing snippets directly in LuaSnip requires a lot of boilerplate. I really miss the neat format of UltiSnips.
luasnippy.nvim aims to bring back the ergonomic way of snippets’ definition. An example should help illustrate this:
return pack_snippets {
snpta("beg", "b Ce A", [[
\begin{<>}
<>
\end{<>}
]], { i(1), i(0), extras.rep(1) }),
context(is_in_math, {
snpta("//", "iA P500", "\\frac{<>}{<>}", { i(1), i(2) }),
snpta("bar", "iRv P500", "\\overline{<>}", { i(1) }),
}),
}- Grouping snippets by conditions (contexts)
- Short-hand syntax for context options
- Intuitive format-string syntax
You can use any of the plugin manager, or git clone this repo and add it to your 'rtp'. For example, install by lazy.nvim:
{
"One-In-Dark/luasnippy.nvim",
dependencies = { "L3MON4D3/LuaSnip" },
config = function(_, _)
require("luasnip.loaders.from_lua").lazy_load()
end
},The main functionality of this plugin is provided in:
luasnippy.snpt(trigger, context, body_str, body_elems, opts)Normally the second argument of snpt is a string, with a similar syntax to UltiSnips, specifying the context of the snippet.
- The common expansion conditions are provided:
istands for in-word, i.e. not matching the entire word ([%w_]+) before the cursor;bstands for beginning-of-line, i.e. only expand if the trigger word is at the beginning of the line;Cestands for endding-of-line, i.e. only expand at the end of the line.
- Commonly used is the regex matching. All three variants are supported (see
trigEnginein:h luasnip-snippets):rstands for Lua pattern, which suffices most of the time, nevertheless the support of Unicode is poor;Rvstands for Vim-regex;Restands for ECMAscript-regex.
- Another two handy options:
Astands for auto-expansion;P<num>sets the priority to<num>(seepriorityin:h luasnip-snippets).
The first argument is the trigger word. The last two arguments form a f-string in Python (for those who are unfamiliar, it’s like string interpolation in shell), as is illustrated by the example above.
The last argument can further regulate the behaviour of the string formatting, see opts in :h luasnip-extras-fmt.
A variant that uses angular brackets <> for string formatting instead of {} is provided:
luasnippy.snpta(trigger, context, body_str, body_elems, opts)luasnippy.context(cond, snippets)Conditions apply to all snippets in its scope, which makes it very easy to write now. context accepts a function or a condition object (see CONDITION OBJECTS in :h luasnip-extras-conditions), and applies it to the snippets in the second argument.
Nesting is supported. For example:
context(-is_in_math_cond, {
context(function() return is_in_env("description") end, {
snpt(" - ", "b Ce A", "\\item [{}] {}", { i(1), i(0) })
}),
}LuaSnip is the “backend” of the plugin. The function pack_snippets can “compile” LuaSnippy-style snippets:
luasnippy.pack_snippets(snippet_tuples)To maximally reduce the need to struggle with LuaSnip docs, some helper functions are provided:
-
luasnippy.make_condition({fn}): makes a condition object. Alias ofrequire("luasnip.extras.conditions").make_condition(fn)
-
luasnippy.capture_extract({indice}): returns a function that can be used in function-node to extract a indexed capture. Example:snpt([=[\([a-zA-Z\u0370-\u03ff]\)\(\d\)]=], "Rv iA", "{}_{}", { f(capture_extract(1)), f(capture_extract(2)) }),
See luasnippets/tex.lua for some powerful snippets, especially:
__: copy the multi-letter subscript from the nearest identical entity.
The snippets can be loaded by:
require("luasnip.loaders.from_lua").lazy_load()Since the plugin folder is added to 'rtp', you don't have to specify the path.