2

Each time I want to save my work while editing a text file, I enter :write to save the file, and :edit to reload the file, with the side effect of resetting the undo/redo buffer.

However, an unwanted side effect of running :edit is that the line under the cursor is recentered. Can anyone tell me either (i) how to prevent :edit from recentering the line, or (ii) if there's a different way of resetting the undo/redo buffer?

Thanks!

3
  • 1
    So you're expressly using :edit in order to reset undo information? You could follow :help clear-undo to do this without :edit; I would define a custom :Write command that combines both. Nov 22, 2019 at 9:29
  • Re "So you're expressly using :edit in order to reset undo information?" Yes, that's exactly what I'm doing. Thanks for the suggestion; I'll try rewriting the :we command in my .vimrc file to do that instead of :edit. If you'd like to put that into an answer, I'll mark it as accepted. Nov 22, 2019 at 13:53
  • Alright; thanks for clarifying. I've added an answer. Nov 22, 2019 at 18:16

3 Answers 3

3

As you're expressly using :edit in order to reset the undo information, you could follow :help clear-undo to do this without :edit.

I would define a custom :Write command that combines both:

command! -bar Write
\ write |
\ let old_undolevels = &undolevels |
\ set undolevels=-1 |
\ exe "normal a \<BS>\<Esc>" |
\ let &undolevels = old_undolevels |
\ unlet old_undolevels |
\ setlocal nomodified
3
  • Thanks. Only one further question: After running your Write command, Vim has clearly written the buffer to the file, because I can reload the file and the changes are saved; but if I run :quit instead, I get an "E37: No write since last change (add ! to override)" error. Any ideas how to prevent this? Nov 23, 2019 at 14:03
  • Try adding :setlocal nomodified at the end. Nov 23, 2019 at 20:27
  • Awesome, that works. Thanks again. Nov 24, 2019 at 18:12
2

I guess your motivation of clearing the undo information on writes is to avoid going beyond the saved buffer state when undoing many steps (uuuu...). I personally use a different approach: I've tweaked the u command to stop and beep once when reaching the saved buffer state. I need to u once more to go beyond.

My customization integrates with the repeat.vim plugin; It also requires some utility functions from my ingo-library plugin (it's now also available on GitHub).

runtime autoload/repeat.vim " Must load the plugin now so that the plugin's mappings can be overridden.
let s:undoPosition = []
function! s:StopAtSavedPosition( action )
    " Buffers of type "nofile" and "nowrite" never are 'modified', so only do
    " the check for normal buffers representing files. (Otherwise, the warning
    " annoyingly happens on every undo.)
    if ingo#buffer#IsPersisted() && ! &l:modified && s:undoPosition != ingo#record#PositionAndLocation(1)
        " We've reached the undo position where the buffer contents correspond
        " to the persisted file. Stop and beep, and only continue when undo is
        " pressed again at the same position.
        call ingo#msg#WarningMsg(a:action . ' reached saved buffer state')
        execute "normal! \<C-\>\<C-n>\<Esc>" | " Beep.

        let s:undoPosition = ingo#record#PositionAndLocation(1)
        return 1
    else
        let s:undoPosition = []
        return 0
    endif
endfunction
nnoremap <silent> u     :<C-U>if ! &l:modifiable<Bar>execute 'normal! u'<Bar>elseif ! <SID>StopAtSavedPosition('Undo')<Bar>call repeat#wrap('u',v:count)<Bar>endif<CR>
nnoremap <silent> <C-R> :<C-U>if ! &l:modifiable<Bar>execute "normal! \<lt>C-R>"<Bar>elseif ! <SID>StopAtSavedPosition('Redo')<Bar>call repeat#wrap("\<Lt>C-R>",v:count)<Bar>endif<CR>
2
  • That is my motivation, yes. You have an interesting approach; but when I save the buffer state, I want to clear the entire undo history, so I can't accidentally undo beyond that. Nov 23, 2019 at 9:36
  • @HuwWalters See also this older question, which has pretty much the same root motivation as yours: vi.stackexchange.com/questions/2115/… and which has several different solutions.
    – Rich
    Nov 25, 2019 at 9:28
1

I'll let @IngoKarkat write the answer that solves your real problem.

However, for the benefit of future readers, you can also achieve what was originally requested by saving the view before executing :edit and then restoring it afterwards:

:let v = winsaveview()
:edit
:call winrestview(v)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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