-
-
Notifications
You must be signed in to change notification settings - Fork 246
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(_, snippetNode)
local select = function(snip, no_move, dry_run)
if dry_run then
return
end
snip:focus()
-- make sure the inner nodes will all shift to one side when the
-- entire text is replaced.
snip:subtree_set_rgrav(true)
-- fix own extmark-gravities, subtree_set_rgrav affects them as well.
snip.mark:set_rgravs(false, 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
local original_extmarks_valid = snippetNode.extmarks_valid
function snippetNode:extmarks_valid()
-- the contents of this snippetNode are supposed to be deleted, and
-- we don't want the snippet to be considered invalid because of
-- that -> always return true.
return true
end
function snippetNode:init_dry_run_active(dry_run)
if dry_run and dry_run.active[self] == nil then
dry_run.active[self] = self.active
end
end
function snippetNode:is_active(dry_run)
return (not dry_run and self.active) or (dry_run and dry_run.active[self])
end
function snippetNode:jump_into(dir, no_move, dry_run)
self:init_dry_run_active(dry_run)
if self:is_active(dry_run) then
-- inside snippet, but not selected.
if dir == 1 then
self:input_leave(no_move, dry_run)
return self.next:jump_into(dir, no_move, dry_run)
else
select(self, no_move, dry_run)
return self
end
else
-- jumping in from outside snippet.
self:input_enter(no_move, dry_run)
if dir == 1 then
select(self, no_move, dry_run)
return self
else
return self.inner_last:jump_into(dir, no_move, dry_run)
end
end
end
-- this is called only if the snippet is currently selected.
function snippetNode:jump_from(dir, no_move, dry_run)
if dir == 1 then
if original_extmarks_valid(snippetNode) then
return self.inner_first:jump_into(dir, no_move, dry_run)
else
return self.next:jump_into(dir, no_move, dry_run)
end
else
self:input_leave(no_move, dry_run)
return self.prev:jump_into(dir, no_move, dry_run)
end
end
return snippetNode
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