diff --git a/doc/luasnip.txt b/doc/luasnip.txt index f62ceaa25..0b99333cb 100644 --- a/doc/luasnip.txt +++ b/doc/luasnip.txt @@ -1,4 +1,4 @@ -*luasnip.txt* For NVIM v0.8.0 Last change: 2023 January 09 +*luasnip.txt* For NVIM v0.8.0 Last change: 2023 January 14 ============================================================================== Table of Contents *luasnip-table-of-contents* diff --git a/lua/luasnip/config.lua b/lua/luasnip/config.lua index 11f8d1abf..3cef7c092 100644 --- a/lua/luasnip/config.lua +++ b/lua/luasnip/config.lua @@ -188,10 +188,16 @@ c = { "Remove buffers' nodes on deletion+wipeout. autocmd BufDelete,BufWipeout * lua current_nodes = require("luasnip").session.current_nodes if current_nodes then current_nodes[tonumber(vim.fn.expand(""))] = nil end ]] - .. (session.config.enable_autosnippets and [[ + .. ( + session.config.enable_autosnippets + -- Luasnip_just_inserted makes sure we only trigger autosnippets after we inserted characters in insert mode. + -- vim.b.Luasnip_last_changedtick allows us to compute how many changes occurred in the file between two TextChanged* events. We use this information to distinguish typing characters by hand vs using to paste multiple characters in insert mode. We want to allow expanding autosnippets in the first case and not in the second. After some investigation, this is the only way I found to distinguish the two cases. + and [[ autocmd InsertCharPre * lua Luasnip_just_inserted = true - autocmd TextChangedI,TextChangedP * lua if Luasnip_just_inserted then require("luasnip").expand_auto() Luasnip_just_inserted=nil end - ]] or "") + autocmd TextChangedI,TextChangedP * lua if Luasnip_just_inserted then Luasnip_just_inserted=nil if vim.b.Luasnip_last_changedtick == nil or vim.b.changedtick==vim.b.Luasnip_last_changedtick + 1 then require("luasnip").expand_auto() end vim.b.Luasnip_last_changedtick = vim.b.changedtick end + ]] + or "" + ) .. [[ augroup END ]], diff --git a/tests/integration/add_snippets_spec.lua b/tests/integration/add_snippets_spec.lua index 9c7b67824..cb0fb1205 100644 --- a/tests/integration/add_snippets_spec.lua +++ b/tests/integration/add_snippets_spec.lua @@ -2,6 +2,16 @@ local helpers = require("test.functional.helpers")(after_each) local exec_lua, feed, exec = helpers.exec_lua, helpers.feed, helpers.exec local ls_helpers = require("helpers") local Screen = require("test.functional.ui.screen") +local sleep = require("luv").sleep + +-- The integration tests here simulate typing into Neovim by feeding each simulated keystroke to Neovim one at a time. + +-- Neovim's TextChangedI event responds to the simulated keystrokes differently from how we would expect it to when typing normally. Specifically, we expect the TextChangedI event to occur after every keystroke in insert mode when typing into Neovim normally, but in this simulation, TextChangedI only seems to occur after a pause. +-- For example, imagine we call feed("tri") and then feed("D"). We would normally expect four TextChangedI events, one after each letter ('t', 'r', 'i', and 'D'). However, according to my investigation, it only occurs after 'i' and 'D'. It only happens consistently if we include a sleep command after each call to feed. +local function feed_wait(...) + feed(...) + sleep(100) +end describe("add_snippets", function() local screen @@ -282,7 +292,9 @@ describe("add_snippets", function() }) feed("cc") -- rewrite line - feed("triD") + -- We feed "tri" and "D" separately, because autosnippets need to have TextChangedI triggered on the character inserted before the trigger is complete or it will think that the trigger was pasted in (and therefore should not be auto-expanded) as it will appear that many characters were inserted all together. + feed_wait("tri") + feed_wait("D") -- check if snippet "d" is automatically triggered screen:expect({ grid = [[ @@ -291,6 +303,22 @@ describe("add_snippets", function() {2:-- INSERT --} |]], }) + -- Test to make sure that autosnippets do not get triggered while pasting in insert mode. + feed("dd") -- clear line + helpers.feed_command("set paste") -- disable autosnippets + helpers.insert("triD") + feed("") + helpers.feed_command("set nopaste") -- reenable autosnippets + feed("0d$") -- clear line + feed_wait([[i"]]) -- use feed_wait here to wait for any auto expanding to occur (which it shouldn't) + -- make sure snippet is not automatically triggered. Ideally, autosnippets should never get triggered when we are pasting text. In most common cases, Luasnip should correctly avoid doing so. + screen:expect({ + grid = [[ + triD^ | + {0:~ }| + {2:-- INSERT --} |]], + }) + feed("cc") -- rewrite line feed("triE") -- check if snippet "e" is NOT automatically triggered