Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deleting a snippet does not stop completion #116

Closed
TheZoq2 opened this issue Aug 16, 2021 · 14 comments
Closed

Deleting a snippet does not stop completion #116

TheZoq2 opened this issue Aug 16, 2021 · 14 comments

Comments

@TheZoq2
Copy link

TheZoq2 commented Aug 16, 2021

I recently switched to this plugin from ultisnips and from what I've seen so far, it's really nice, however, one thing is bugging me.

I often start typing out a snippet, then change my mind, exit insert mode delete the snippet or line without going to the end of the snippet. Ultisnips would handle that gracefully, but it seems like luasnip continues expanding stuff even after that point, which I find very annoying.

Example of the behaviour, (using this snippet)

local function format_string_function(trig, fn)
    return s(trig, {
        t(fn),
        t("(\""),
        i(1),
        t("\""),
        -- Insert a comma if we insert arguments
        m(2, ".+", ", ", ""),
        i(2),
        t(")")
    })
end

ls.snippets = {
    all = {
        format_string_function("fmt", "format!"),
        format_string_function("pln", "println!"),
    }
}
Peek.2021-08-16.14-21.mp4

Is there a way of avoiding this behavour? Ideally, something like "if the snippet was deleted, abort", but I'd also be fine with exiting insert mode cancelling the snippet creation no matter what

@TheZoq2
Copy link
Author

TheZoq2 commented Aug 16, 2021

Oops, seems like this is a duplicate of #75. I managed to get the behaviour I want with

vim.api.nvim_set_keymap('i', '<esc>', '<c-o>:lua Luasnip_current_nodes[vim.api.nvim_get_current_buf()] = nil<cr><esc>', { noremap=true, silent=true })

This kind of feels like a hack though...

@L3MON4D3
Copy link
Owner

Yeah, it is a bit hacky, it'll destroy any snippet-history you might want to actually keep.
There is :LuasnipUnlinkCurrent, which leaves a snippet, but that was a bit buggy before. On current master is a version I'm fairly confident in.
(We'll probably add some setting to leave snippets as soon as the cursor has left their 'region', similar to ultisnips, that should do it).

@L3MON4D3
Copy link
Owner

Okay, that setting is implemented now, you can set region_check_events to eg. 'CursorMoved' to leave a snippet if the cursor is no longer inside it, that might work okay for leaving deleted snippets.
Another way would be to provide a function that reverses the expansion of a snippet and puts the trigger-text back, mapping that to a key seems pretty ergonomic.

@TheZoq2
Copy link
Author

TheZoq2 commented Aug 23, 2021

Great, thanks for the quick fix! I'll give it a try when I find some time to once again change my vim config :P

Regarding the other possible method, I don't think that would work well for my use case, mostly because "eh, I messed up jkdd" is very ingrained in my muscle memory and also because my snippet words are often abbreviations, so going back to the unexpanded trigger text is probably not something I'd want

@L3MON4D3
Copy link
Owner

Regarding the other possible method, I don't think that would work well for my use case, mostly because "eh, I messed up jkdd" is very ingrained in my muscle memory and also because my snippet words are often abbreviations, so going back to the unexpanded trigger text is probably not something I'd want

Yeah I completely get that, for now even with this you'll have to leave the line the snippet was on to leave it.

@L3MON4D3
Copy link
Owner

I've given it some more thought and implemented a function that can be called on delete to check if the current snippet is deleted entirely and, if so, removes it from the jumplist.
For now you'll have to eg.

nmap dd dd<Plug>luasnip-delete-check

to have it work, but maybe those maps will be added to luasnip so you won't have to set them up for all possible commands that delete text.

I did some testing and it works pretty well for eg. dd, but s in visual works only for v, not V (in V the extmarks' start- and end end up in different places, maybe it's a bug with neovim)

@Diomendius
Copy link

Diomendius commented Aug 25, 2021

I think setting region_check_events = "InsertEnter" makes more sense, as o doesn't trigger CursorMoved and jump bindings don't work outside of insert mode anyway (if for some reason you wanted them to), so you get this behaviour:

  • If you start editing a region outside the last snippet, its jumps are skipped.
  • If you leave insert mode and start it again within the snippet's bounds, its jumps are not skipped.
  • If you use the arrow keys to move outside the snippet, its jumps are still usable. This seems more like a feature than a bug to me, but maybe not if you insist on using Vim the Wrong Way and hardly ever leave insert mode.

If this is unacceptable, setting region_check_events = "CursorMoved,InsertEnter" covers all bases AFAIK.

Would running luasnip-delete-check on TextChanged and InsertLeave be too heavy?

Personally, I would like to be able to have a snippet's jumps removed from the history when its region is left. Put another way, when history = false backwards jumps are not possible even when you haven't left a snippet. It almost makes sense for this to be the default behaviour of history = false, but it relies on region_check_events being set to work correctly.

@Diomendius
Copy link

Running the deleted check in an autocommand seems to work fine for me. TextChanged doesn't seem to trigger overly aggressively. It fires exactly once for any change I've tried, including Vimscript plugins that might perform multiple individual changes (b:changedtick increments by more than one between TextChanged triggers, which I presume supports my theory).

Unless the delete check is heavier than it should be this seems fine. Here's what I used:

augroup CustomLuaSnip
	au!
	au TextChanged,InsertLeave * lua require'luasnip'.unlink_current_if_deleted()
augroup end

@L3MON4D3
Copy link
Owner

L3MON4D3 commented Aug 25, 2021

I think setting region_check_events = "InsertEnter" makes more sense, as o doesn't trigger CursorMoved and jump bindings don't work outside of insert mode anyway (if for some reason you wanted them to), so you get this behaviour:

  • If you start editing a region outside the last snippet, its jumps are skipped.
  • If you leave insert mode and start it again within the snippet's bounds, its jumps are not skipped.
  • If you use the arrow keys to move outside the snippet, its jumps are still usable. This seems more like a feature than a bug to me, but maybe not if you insist on using Vim the Wrong Way and hardly ever leave insert mode.

Oh yes, that's also pretty nice, I'll put it into the Readme as a recommendation.

Would running luasnip-delete-check on TextChanged and InsertLeave be too heavy?

No, not really, I did it this way because the specific example of jkdd was given, but thinking about it, TextChanged isn't really triggered that often.

Personally, I would like to be able to have a snippet's jumps removed from the history when its region is left. Put another way, when history = false backwards jumps are not possible even when you haven't left a snippet. It almost makes sense for this to be the default behaviour of history = false, but it relies on region_check_events being set to work correctly.

I get that, i didn't 'enable' region_check_events by default because it costs some performance and I'd like to keep luasnip as light as possible by default

@L3MON4D3
Copy link
Owner

Running the deleted check in an autocommand seems to work fine for me. TextChanged doesn't seem to trigger overly aggressively. It fires exactly once for any change I've tried, including Vimscript plugins that might perform multiple individual changes (b:changedtick increments by more than one between TextChanged triggers, which I presume supports my theory).

Unless the delete check is heavier than it should be this seems fine. Here's what I used:

augroup CustomLuaSnip
	au!
	au TextChanged,InsertLeave * lua require'luasnip'.unlink_current_if_deleted()
augroup end

Nice, I'll put that in as a setting👍

@Diomendius
Copy link

I absolutely agree that LuaSnip shouldn't do more than necessary with default settings. It's this sort of principle which is one reason I prefer (Neo)Vim over a monolithic IDE. It's hard to beat an IDE which starts in well under a second and is also ideal for editing any plain text file format in existence. LuaSnip should be just as light, and just as powerful, and there's nothing to say it can't be.

Good to hear there'll be a setting for this.

@L3MON4D3
Copy link
Owner

Whoops, forgot to comment here yesterday: 0db416c adds the setting.

@vinoff
Copy link

vinoff commented Oct 9, 2021

Sorry, but how should one go about setting region_check_events = CursorMoved in the settings? My current luasnip.lua looks like this:

require("luasnip/loaders/from_vscode").load({ include = { "python" } }) -- Load only python snippets
region_check_events = CursorMoved

Should that be working?

@Diomendius
Copy link

Put it in the table you pass to ls.config.setup() (or ls.config.set_config() as they are aliases; the docs only mention setup() but the example snippets.lua uses set_config()) like so:

local ls = require('luasnip')
ls.config.set_config({
	region_check_events = "CursorMoved",
})

set_config() should only be called once with a table containing all settings you want to change. All omitted settings are set to their defaults when you call the function.

The values for region_check_events and delete_check_events are strings passed directly to :autocmd, so you can specify multiple triggers separated by commas:

local ls = require('luasnip')
ls.config.set_config({
	region_check_events = "InsertEnter",
	delete_check_events = "TextChanged,InsertLeave",
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants