diff --git a/src/nvim/edit.c b/src/nvim/edit.c index fbc0b156de..c125d6c65c 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -946,25 +946,27 @@ static int insert_handle_key(InsertState *s) break; case K_PASTE_START: - paste_repeat(1); - goto check_pum; - case K_EVENT: // some event - state_handle_k_event(); - // If CTRL-G U was used apply it to the next typed key. - if (dont_sync_undo == kTrue) { - dont_sync_undo = kNone; - } - goto check_pum; - case K_COMMAND: // command - do_cmdline(NULL, getcmdkeycmd, NULL, 0); - goto check_pum; + case K_LUA: { + bufref_T save_curbuf; + const varnumber_T tick = buf_get_changedtick(curbuf); + set_bufref(&save_curbuf, curbuf); - case K_LUA: - map_execute_lua(false, false); + if (s->c == K_PASTE_START) { + paste_repeat(1); + } else if (s->c == K_EVENT) { + state_handle_k_event(); + // If CTRL-G U was used apply it to the next typed key. + if (dont_sync_undo == kTrue) { + dont_sync_undo = kNone; + } + } else if (s->c == K_COMMAND) { + do_cmdline(NULL, getcmdkeycmd, NULL, 0); + } else { + map_execute_lua(false, false); + } -check_pum: // nvim_select_popupmenu_item() can be called from the handling of // K_EVENT, K_COMMAND, or K_LUA. // TODO(bfredl): Not entirely sure this indirection is necessary @@ -983,12 +985,16 @@ check_pum: pum_want.active = false; } - if (curbuf->b_u_synced) { - // The K_EVENT, K_COMMAND, or K_LUA caused undo to be synced. - // Need to save the line for undo before inserting the next char. + if (curbuf->b_u_synced + || (bufref_valid(&save_curbuf) + && curbuf == save_curbuf.br_buf + && tick != buf_get_changedtick(curbuf))) { + // The K_EVENT, K_COMMAND, or K_LUA synced undo or changed this buffer. + // Save the cursor line before the next typed edit. ins_need_undo = true; } break; + } case K_HOME: // case K_KHOME: @@ -2196,7 +2202,9 @@ int stop_arrow(void) new_insert_skip = 2; } else if (ins_need_undo) { if (u_save_cursor() == OK) { - // A command or event may have moved the cursor after syncing undo. + // A command or event may have moved the cursor or edited the + // buffer. Update Insstart so that later edits can properly decide + // whether an extra undo entry is needed. Insstart = curwin->w_cursor; Insstart_textlen = (colnr_T)linetabsize_str(get_cursor_line_ptr()); ins_need_undo = false; diff --git a/test/old/testdir/test_undo.vim b/test/old/testdir/test_undo.vim index 0cf2ca4b37..21b6dcf970 100644 --- a/test/old/testdir/test_undo.vim +++ b/test/old/testdir/test_undo.vim @@ -938,4 +938,32 @@ func Test_undo_line_backspace_after_insert_cmd_cursor_movement() bwipe! endfunc +func Test_undo_line_backspace_after_insert_func_edit() + new + setlocal backspace=eol undolevels=100 + + let v:errmsg = '' + call feedkeys("i\" + \ .. "\call setline(2, 'abc')\" + \ .. "\\u", 'xt') + + call assert_equal('', v:errmsg) + call assert_equal([''], getline(1, '$')) + bwipe! +endfunc + +func Test_undo_line_backspace_after_insert_cmd_edit() + new + setlocal backspace=eol undolevels=100 + + let v:errmsg = '' + call feedkeys("i\" + \ .. "\s/.*/abc/\" + \ .. "\\u", 'xt') + + call assert_equal('', v:errmsg) + call assert_equal([''], getline(1, '$')) + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab