5

Question: Is there something which is works same as i_CTRL-G_u, but for normal mode?

This would be useful in mappings (like nnoremap), because (I think, but fixme) in normal mode, if you are just typing commands (vs. a sequence mapped to a single key), then each command counts as a separate undo block.

Case in point: I'm trying to solve this exercise, from Learn Vimscript the Hard Way.

This is what I came up with, and it seems to work:

:nnoremap <leader>d ddi<C-G>u<esc>dd

While this works, it seems a bit hackish, going into insert mode just to break the undo sequence, so I was wondering if it is possible without going into insert mode.

Of course, I already tried the following variant, but all it does is deleting a single line, so it seems that the <C-G> part kind of ends the sequence:

:nnoremap <leader>d dd<C-G>udd
3
  • 2
    I nixed the spoiler—I'm not concerned about sharing the code, and it's important that the question is easy to read. If others feel strongly opposed, we can discuss – D. Ben Knoble Sep 8 '20 at 15:03
  • 1
    Not that I know of. You could try this: nnoremap <leader>d dd@=execute('let &ul = &ul')[-1]<cr>dd. But technically, it still temporarily leaves normal mode to enter the command-line (the expression one). See vi.stackexchange.com/a/26475/17449. – user938271 Sep 8 '20 at 15:09
  • 2
    "It seems a bit hackish, going into insert mode just to break the undo sequence." Welcome to Vimscript! You seem to be learning the actual lessons about it! 😂 – filbranden Sep 8 '20 at 15:14
3

Doing :let &ul=&ul breaks the undo sequence. This is documented under :h :undojoin:

Setting the value of 'undolevels' also breaks undo. Even when the new value is equal to the old value.

Using the described method, you can do the following:

nnoremap <leader>d dd:let &ul=&ul<CR>dd
2
  • 1
    This is documented at the end of :h :undoj. More specifically here. – user938271 Sep 8 '20 at 17:26
  • @user938271 thanks, I'll update my answer to reflect that. – Jake Grossman Sep 8 '20 at 18:23
0

Most elegant in my opinion:

nnoremap <leader>dd :call feedkeys("dddd",'t')<cr>

feedkeys() function with 't' parameter pretends that the user actually typed dddd.

If you press dddd in Normal mode, you can undo first dd, and then second dd. If you create a mapping for that and use it, u undoes the whole mapped sequence at once, which is the problem introduced in the question. However, once you create a mapping using feedkeys() function with 't' parameter as in my example, you can undo each individual normal mode command from a sequence of normal mode commands given as first argument to the feedkeys() function.

Of course you cannot control the "granularity" of breaking the undo-sequence using this method. But for some uses it may be more elegant and readable.

More info: :help feedkeys().

4
  • Welcome to Vi and Vim! How does this address breaking the undo-sequence, which was the main thrust of the question? – D. Ben Knoble Feb 8 at 21:42
  • If you press dddd in Normal mode, you can undo first dd, and then second dd. If you create a mapping for that and use it, u undoes the whole mapped sequence at once, which is the problem introduced in the question. However, once you create a mapping using feedkeys() function with 't' parameter as in my example, you can undo each individual normal mode command from a sequence of normal mode commands given as first argument to the feedkeys() function. – lukedrew Feb 9 at 23:17
  • Of course you cannot control the "granularity" of breaking the undo-sequence using this method. But for some uses it may be more elegant and readable. – lukedrew Feb 9 at 23:27
  • That information should really make its way into the answer; it would be much stronger that way. Feel free to edit. – D. Ben Knoble Feb 10 at 0:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.