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!

  • 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. – Ingo Karkat Nov 22 '19 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. – Huw Walters Nov 22 '19 at 13:53
  • Alright; thanks for clarifying. I've added an answer. – Ingo Karkat Nov 22 '19 at 18:16
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
| improve this answer | |
  • 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? – Huw Walters Nov 23 '19 at 14:03
  • Try adding :setlocal nomodified at the end. – Ingo Karkat Nov 23 '19 at 20:27
  • Awesome, that works. Thanks again. – Huw Walters Nov 24 '19 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>
| improve this answer | |
  • 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. – Huw Walters Nov 23 '19 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 '19 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)
| improve this answer | |

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.