L3MON4D3 / LuaSnip

Snippet Engine for Neovim written in Lua.
Apache License 2.0
3.49k stars 245 forks source link

E438: u_undo: line numbers wrong #1248

Open tomtomjhj opened 3 weeks ago

tomtomjhj commented 3 weeks ago

Using jump(-1) in $0 position and then making some edits may trigger E438. This is an internal error, so ideally it should be reported in nvim. But I don't have time to investigate and produce a minimal reproducer, so I'm reporting here instead.

repro.vim

set rtp^=/path/to/LuaSnip

imap <silent><expr> <Tab> luasnip#expand_or_jumpable() ? '<Plug>luasnip-expand-or-jump' : '<Tab>' 
inoremap <silent> <S-Tab> <cmd>lua require'luasnip'.jump(-1)<Cr>

lua << EOF
require("luasnip.loaders.from_vscode").load_standalone{path = "/path/to/repro.code-snippets"}
require("luasnip").config.setup{}
EOF

repro.code-snippets

{
    "global snippet": {
        "prefix": "item",
        "body": [
          "\\begin{itemize}",
          "$0",
          "\\end{itemize}"
        ]
    }
}

Run nvim as nvim --clean -u repro.vim (tested with 0.10.2 and current master), then type this sequence of keys: i<CR><CR><CR><CR>item<Tab><S-Tab><BS><BS><BS><Esc>u. Result: image. Specifically, top == bot == 5 at this point https://github.com/neovim/neovim/blob/7bf3a616e18205d353d9c4a44e8c2f885d700129/src/nvim/undo.c#L2290-L2293

When this happens in real usage, this corrupts the undo history.

I believe this happens due to interaction between extmarks and undo. I don't have concrete evidence for that, but I've already seen some odd stuff that might be related (https://github.com/neovim/neovim/issues/26499)

L3MON4D3 commented 3 weeks ago

Damn, I hadn't seen that one before :grimacing: Has this only now started to happen? Have you tried older versions of luasnip?

It only seems to occur if there are no empty lines after the snippet (ah, as suggested by your observation of top==bot==5), and the $0 isn't that important, I could also reproduce it with another snippet where I jumped back from a $1. I could not reproduce it when leaving doing an <Esc>i after jumping.

A brief check

:lua =ls.session.current_nodes[1].parent.snippet:subtree_do({pre=function(node) if node.mark then I({node.mark:pos_begin_end_raw()}) end end, post = function()
 end})

shows that the extmarks are all properly inside the buffer.

I'll try to instrument the luasnip-code to print all relevant operations (shifting gravity of marks, feeding input to nvim) to first reproduce the error without luasnip, and then hopefully find a minimal repro :crossed_fingers: