LuaSnip icon indicating copy to clipboard operation
LuaSnip copied to clipboard

Undo/revert/untrigger a snippet (right after triggering it)

Open Andrew15-5 opened this issue 2 years ago • 6 comments

I've had times when I accidentally (or whatever the reason might be) trigger a snippet. I also have typed some text (before triggering the snippet) without leaving insert mode in Neovim (I don't have auto save during insert mode).

If I exit insert mode and make 1 undo action, then the snippet's text and all the text that has been typed prior to the snippet will disappear! Almost always this is a disaster and the only solution (sometimes) is to just manually deleted inserted snippet's text.

There could be a situation when "trigger text" is triggered accidentally and this action will delete this "trigger text" with no way of reverting this change. (Well, I can just retype the whole thing, but we are talking about plugin for lazy people, so this is not an option.)

I need an imap shortcut which will call some function which will simply undo the triggering action and restore the text and cursor position to the state before the trigger key was pressed.

Is it possible (or maybe it is already a thing which I didn't use for so long)?

Andrew15-5 avatar Feb 27 '23 23:02 Andrew15-5

I think I disabled on-each-key-press-auto-save (in insert mode) because the undo stack would be huge and to undo one word or more I would have to play a clicker game with u button.

Andrew15-5 avatar Feb 27 '23 23:02 Andrew15-5

You could

  • get the snippet (ls.session.current_nodes[vim.api.nvim_get_current_buf()].parent.snippet)
  • get its trigger (snip.trigger)
  • get its region (snip:get_buf_position())
  • replace that region with the trigger (see :h nvim_buf_set_text)
  • (reset the cursor-position to behind the trigger?)

But it's not built-in, so you'd have to write that yourself

L3MON4D3 avatar Feb 28 '23 08:02 L3MON4D3

  • (reset the cursor-position to behind the trigger?)

If you mean behind as in to the right side of the trigger text, then yes. "Behind" and "in front of" are ambiguous positions.

Andrew15-5 avatar Feb 28 '23 09:02 Andrew15-5

Cool, now that I have a "step-by-step guide" I think I can do this. At least the API for doing every step does exist, so I better make it work.

Can this be a feature request (LuaSnip command in Neovim) which I will soon try to implement and provide as PR? We can discuss documentation and other stuff later.

I think this is a great feature. It definitely belongs in this great project to make it even greater.

Andrew15-5 avatar Feb 28 '23 09:02 Andrew15-5

If you mean behind as in to the right side of the trigger text, then yes. "Behind" and "in front of" are ambiguous positions.

True! Yes, to the right :+1:

Can this be a feature request (LuaSnip command in Neovim) which I will soon try to implement and provide as PR? We can discuss documentation and other stuff later.

For sure, seems worthwhile :+1:

L3MON4D3 avatar Feb 28 '23 10:02 L3MON4D3

It works for me

local untrigger = function()
  -- get the snippet
  local snip = require("luasnip").session.current_nodes[vim.api.nvim_get_current_buf()].parent.snippet
  -- get its trigger
  local trig = snip.trigger
  -- replace that region with the trigger
  local node_from, node_to = snip.mark:pos_begin_end_raw()
  vim.api.nvim_buf_set_text(
    0,
    node_from[1],
    node_from[2],
    node_to[1],
    node_to[2],
    { trig }
  )
  -- reset the cursor-position to ahead the trigger
  vim.fn.setpos(".", { 0, node_from[1] + 1, node_from[2] + 1 + string.len(trig) })
end


vim.keymap.set({ "i", "s" }, "<c-x>", function()
  if require("luasnip").in_snippet() then
    untrigger()
    require("luasnip").unlink_current()
  end
end, {
  desc = "Undo a snippet",
})

ghost avatar Feb 28 '24 22:02 ghost