LuaSnip icon indicating copy to clipboard operation
LuaSnip copied to clipboard

dynamic_node expands after undo

Open jandamm opened this issue 3 years ago • 7 comments

Hi, I'm not sure if this issue is an issue in LuaSnip or in my snippet.

The issue occurs when I expand my snippet func and then press u to undo. I press ifunc<TAB><ESC>u (where <TAB> expands the snippet).

Expectation: Either func or an empty line.

Behaviour: M.name If I then press u again I'm in the expected state with an empty line.

Sometimes when I've been deleting the input an error occurred on every input since LuaSnip was still in snippet mode even though the snippet was removed.

This is my config/snippet:

local luasnip = require 'luasnip'

luasnip.config.setup {
	history = true,
	store_selection_keys = '<TAB>',
	updateevents = 'TextChanged,TextChangedI',
	delete_check_events = 'TextChanged,InsertLeave',
}

local snip = luasnip.snippet
local node = luasnip.snippet_node
local text = luasnip.text_node
local insert = luasnip.insert_node
local func = luasnip.function_node
local choice = luasnip.choice_node
local dynamic = luasnip.dynamic_node

local function before(snippet)
	return snippet.env.TM_CURRENT_LINE:match('^(.*)' .. snippet.dscr[1], 1)
end

luasnip.snippets = {
	lua = {
		snip('func', {
			dynamic(1, function(_, snippet)
				local line = before(snippet)
				if line == '' then
					return node(nil, choice(1, { text 'local ', text '' }))
				elseif line:match '^%s*$' then
					return node(nil, choice(1, { text '', text 'local ' }))
				end
				return node(nil, text '')
			end, {}),
			text 'function',
			dynamic(2, function(args, snippet)
				if not before(snippet):match '^%s*$' then
					return node(nil, text '')
				elseif args[1][1] ~= 'local ' then
					return node(nil, { choice(1, { text ' M.', text ' ' }), insert(2, 'name') })
				end
				return node(nil, { text ' ', insert(1, 'name') })
			end, { 1 }),
			text '(',
			insert(3, 'param'),
			text { ')', '\t' },
			dynamic(4, function(_, snippet)
		            local vis = snippet.env.TM_SELECTED_TEXT[1]
                		if vis then
			            return node(nil, { text(vis), insert(1) })
		                else
			            return insert(1, placeholder or '')
		                end
	                end, {}),
			text { '', 'end' },
		}),
	},
}

jandamm avatar Dec 13 '21 12:12 jandamm

Deleting snippets is a bit wonky :/ Setting delete_check_events = 'TextChanged,InsertLeave' is a good start, but sometimes the extmarks don't end up in the same place, which luasnip doesn't recognize as the snippet being deleted (I'll try adding some stuff to catch that, maybe that will end these problems). One way of preventing them is doing :LuasnipUnlinkCurrent before deleting the snippet, but that's not a great experience.

Sometimes when I've been deleting the input an error occurred on every input since LuaSnip was still in snippet mode even though the snippet was removed.

Could you post the errors the next time they occur? We could put the source of the error into a pcall and delete the snippet upon catching one of those.

L3MON4D3 avatar Dec 13 '21 13:12 L3MON4D3

Thanks for the hint. For now nnoremap u <CMD>LuaSnipUnlinkCurrent<CR>u works 👍

jandamm avatar Dec 13 '21 18:12 jandamm

Hah, I found another bug: in config.lua, the autocommand for updating is defined (and therefore, for TextChanged, triggered) before the one for deleting the snippet if it has no text left. Can you confirm that 21bdf39 and bdff107 fix your issue?

L3MON4D3 avatar Dec 14 '21 09:12 L3MON4D3

That looks like it fixed it 👍

jandamm avatar Dec 14 '21 11:12 jandamm

Unfortunately it didn't fix the issue. In most cases it worked but I had an issue again where M.name kept coming. ifunc<TAB><ESC>u is now working. ifunc<ESC>i<TAB><ESC>u produces func M.name where the snippet isn't unlinked. Same goes for ifunc<TAB><ESC><C-g>u basically when the trigger isn't removed by the undo.

I was also able to reproduce the mentioned error message:

Error detected while processing TextChanged Autocommands for "*":
E5108: Error executing lua ...k/packer/start/LuaSnip/lua/luasnip/nodes/dynamicNode.lua:186: attempt to index field 'snip' (a nil value)
stack traceback:
	...k/packer/start/LuaSnip/lua/luasnip/nodes/dynamicNode.lua:186: in function 'exit'
	.../pack/packer/start/LuaSnip/lua/luasnip/nodes/snippet.lua:767: in function 'exit'
	.../pack/packer/start/LuaSnip/lua/luasnip/nodes/snippet.lua:237: in function 'remove_from_jumplist'
	...nvim/site/pack/packer/start/LuaSnip/lua/luasnip/init.lua:294: in function 'unlink_current'
	...nvim/site/pack/packer/start/LuaSnip/lua/luasnip/init.lua:317: in function 'active_update_dependents'
	[string ":lua"]:1: in main chunk

jandamm avatar Dec 14 '21 12:12 jandamm

The undo-problem arises again here because extmarks are not restored properly (at least it seems like that): directly after undoing, func is inside the mark-range, so we can't detect the snippet being deleted. No idea how to catch that :/ As for the errors, more_delete_fixes should prevent them (but I'm not certain that this is the same error you were experiencing earlier, seems like this one was caused by bdff107).

L3MON4D3 avatar Dec 14 '21 13:12 L3MON4D3

Well for the most common use case ("insert, complete, undo since it's the wrong snippet") it's working. 👍

jandamm avatar Dec 14 '21 15:12 jandamm

This should no longer occur with 6e951d8

L3MON4D3 avatar Oct 04 '23 13:10 L3MON4D3