-
-
Notifications
You must be signed in to change notification settings - Fork 267
Nice Configs
Using ext_opts it's possible to add virtual text to nodes:
local types = require("luasnip.util.types")
require'luasnip'.config.setup({
ext_opts = {
[types.choiceNode] = {
active = {
virt_text = {{"●", "GruvboxOrange"}}
}
},
[types.insertNode] = {
active = {
virt_text = {{"●", "GruvboxBlue"}}
}
}
},
})This adds an orange dot to the end of the line if inside a choiceNode, and a blue one if inside an insertNode:

local util = require("luasnip.util.util")
local node_util = require("luasnip.nodes.util")
ls.setup({
parser_nested_assembler = function(_, snippet)
local select = function(snip, no_move)
snip:focus()
-- upon deletion, extmarks of inner nodes should shift to end of
-- placeholder-text.
snip:subtree_set_rgrav(true)
-- SELECT all text inside the snippet.
if not no_move then
vim.api.nvim_feedkeys(
vim.api.nvim_replace_termcodes("<Esc>", true, false, true),
"n",
true
)
node_util.select_node(snip)
end
end
function snippet:jump_into(dir, no_move)
if self.active then
-- inside snippet, but not selected.
if dir == 1 then
self:input_leave()
return self.next:jump_into(dir, no_move)
else
select(self, no_move)
return self
end
else
-- jumping in from outside snippet.
self:input_enter()
if dir == 1 then
select(self, no_move)
return self
else
return self.inner_last:jump_into(dir, no_move)
end
end
end
-- this is called only if the snippet is currently selected.
function snippet:jump_from(dir, no_move)
if dir == 1 then
return self.inner_first:jump_into(dir, no_move)
else
self:input_leave()
return self.prev:jump_into(dir, no_move)
end
end
return snippet
end
})The main reason for this not being the default is that it
- requires a lot of modification to the resulting snippets
- Doesn't work perfectly(yet): if the entire placeholder is replaced, the nested tabstops won't be skipped.
Example with "test: ${1: this is ${2:nested} ${3:text}} ${4:yay!}":

A slight change to the recommended nvim-cmp setup where we replace luasnip.expand_or_jumpable() with luasnip.expand_or_locally_jumpable() to only jump to a snippet field if we are currently in a snippet.
example setup:
cmp.setup({
-- ... Your other configuration ...
mapping = {
-- ... Your other mappings ...
["<Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_next_item()
elseif luasnip.expand_or_locally_jumpable() then
luasnip.expand_or_jump()
elseif has_words_before() then
cmp.complete()
else
fallback()
end
end, { "i", "s" }),
}
}Similar to the above, but this is for setting the same keymap for changing choice if there's an active choicenode or using external update dynamic node. Since there are a lot of keymaps already, it might be nice to overload them and use the same keymap for mutually exclusive events. Set it up as follows:
-- feel free to change the keys to new ones, those are just my current mappings
vim.keymap.set("i", "<C-f>", function ()
if ls.choice_active() then
return ls.change_choice(1)
else
return _G.dynamic_node_external_update(1) -- feel free to update to any index i
end
end, { noremap = true })
vim.keymap.set("s", "<C-f>", function ()
if ls.choice_active() then
return ls.change_choice(1)
else
return _G.dynamic_node_external_update(1)
end
end, { noremap = true })
vim.keymap.set("i", "<C-d>", function ()
if ls.choice_active() then
return ls.change_choice(-1)
else
return _G.dynamic_node_external_update(2)
end
end, { noremap = true })
vim.keymap.set("s", "<C-d>", function ()
if ls.choice_active() then
return ls.change_choice(-1)
else
return _G.dynamic_node_external_update(2)
end
end, { noremap = true })Also see:
- this discussion for more context
- this wiki page for more information on external update dynamic node