我已经在Vim中使用撤消文件功能了一段时间了。这是一个非常好的功能。

但是,令人烦恼的是,很容易意外撤消上次打开文件时所做的更改;可能是2分钟前,一个小时前,上周或一个月前。

例如,假设我打开一个文件,进行了一些更改,然后关闭并更改了一些其他文件,并发现不需要进行更改,或者只是一些临时调试语句。

以前,我可以按住u键,直到Vim说出“已经是最早的更改”,:wq,并完成。但是现在我必须非常小心,不要撤消上次打开文件时所做的更改。没有明显的方法可以看到您何时进行此操作。

是否有任何方法可以使此方法更明确?例如,将其显示在某个地方,发出警告甚至要求确认。

评论

自从undofile功能发布以来,我一直想知道这个问题。自从该站点发布以来,我一直想去问一个问题!希望有一个好的答案。我想我也会接受一个给出命令的命令,该命令将文件恢复为自上次打开文件以来的状态。 (或者更好,跳回该撤消状态。)

#1 楼

我有这个确切的问题。这是我添加到vimrc中为我修复的内容:

" Always write undo history, but only read it on demand
" use <leader>u to load old undo info
" modified from example in :help undo-persistence

if has('persistent_undo')
  set undodir=~/.vim/undo " location to store undofiles
  nnoremap <leader>u :call ReadUndo()<CR>
  au BufWritePost * call WriteUndo()
endif

func! ReadUndo()
  let undofile = undofile(expand('%'))
  if filereadable(undofile)
    let undofile = escape(undofile,'% ')
    exec "rundo " . undofile
  endif
endfunc

func! WriteUndo()
  let undofile = escape(undofile(expand('%')),'% ')
  exec "wundo " . undofile
endfunc


请注意,您未设置undofile选项;如果有,则需要从vimrc中删除。

现在,撤消可以作为“正常”使用。但是我们确实使用wundo中的BufWritePost命令手动写入撤消文件。

ReadUndo()函数使用rundo手动读取撤消文件并设置undofile选项。现在,我们可以使用u进一步追溯历史。我将此映射到<Leader>u

这可能更好。它会覆盖以前的撤消信息,因此您无法返回到之前编辑文件的时间。但是我自己并不需要。

评论


注意我注意到了一个问题:您仅将当前会话的内容保存到撤消文件中。这与默认行为不同,默认行为是保存上一会话的内容+撤消文件中已经存在的所有信息。解决此问题的方法是读取撤消文件,合并撤消更改,然后写入撤消文件...但是这似乎不可能...:-/

–马丁·图尔诺伊(Martin Tournoij)
15年5月2日在21:39

@Carpetsmoker我同意。如果可能的话,这样做会很好。碰巧的是,这对我来说足够长的时间了。 YMMV。

–superjer
2015年5月8日23:38

#2 楼

哦,哦,终于有机会炫耀这个漂亮的命令!

Vim可以“回到过去”。它具有一个:earlier命令...

                                                        :ea :earlier            
:earlier {count}        Go to older text state {count} times.                   
:earlier {N}s           Go to older text state about {N} seconds before.        
:earlier {N}m           Go to older text state about {N} minutes before.        
:earlier {N}h           Go to older text state about {N} hours before.          
:earlier {N}d           Go to older text state about {N} days before.           

:earlier {N}f           Go to older text state {N} file writes before.          
                        When changes were made since the last write             
                        ":earlier 1f" will revert the text to the state when    
                        it was written.  Otherwise it will go to the write      
                        before that.                                            
                        When at the state of the first file write, or when      
                        the file was not written, ":earlier 1f" will go to      
                        before the first change.                                


...,它可以将文件恢复为先前的状态。这可以有多种使用方式。



如果您可以估算出进行这些更改所花费的时间,则可以花些时间此命令。或者,例如,如果您知道在过去的一天中没有更改文件(要撤消的更改除外),则可以使用

:earlier 1d



如果您要撤消更改后仅写入(保存)一次文件,或者根本没有保存文件,则可以使用

:earlier 1f


:help文本中所述,如果您刚刚编写文件,它将恢复为先前编写的版本;如果您没有进行任何更改,则将恢复为上次保存的版本。


这不能准确回答您的问题,但听起来有点像XY问题。

评论


听起来有点像XY问题:为什么?我正在与u撤消操作,而我不小心越过了我现在所做的更改……我不确定原始的“ X问题”可能在这里吗?

–马丁·图尔诺伊(Martin Tournoij)
2015年2月23日在2:04



我现在是关于:顺便说一下,但是我仍然需要猜测;就像我在使用u时需要猜测的那样。在某些情况下,它可能会更好一些,但我希望使用更明确的内容(如果可能的话)。

–马丁·图尔诺伊(Martin Tournoij)
2015年2月23日在2:05

@Carpetsmoker“ X”是“我只想撤消最近所做的这些更改。” “ Y”是“如何撤消更改并忽略撤消文件?”您仍然需要猜测,但是您在问题中说,您所做的最后更改是上周或更早的时间,因此您可以执行:ea 5d之类的操作。您也可以使用:ea 1f方法。无论如何,它的粒度要少得多。

–门把手
2015年2月23日在2:38

对我来说,“ X”和“ Y”似乎只是对同一问题的改写?我确实在问题中提到“星期”,但也可能是数小时或数分钟(修改后)...顺便说一句,这并不是一个坏答案,我当时(过去)只是希望有更好的选择...

–马丁·图尔诺伊(Martin Tournoij)
2015年2月23日在2:57

我在这个上与@Carpetsmoker在一起。我已经知道:更早了一段时间,但是由于问题中所描述的原因,我仍然关闭了undofile。

–丰富
2015年2月23日在11:25

#3 楼

2015年6月28日更新:我修复了一个小错误,并将其作为
插件发布。插件代码稍稍更好,因为它会在移动光标后再次发出警告;我建议您使用
插件。 Vim会话,而不是以前的所有Vim会话。

这是因为wundo会覆盖撤消文件;它没有合并。据我所知,没有办法解决。

所以这是我的替代解决方案,当您撤消撤消文件中的更改时,它将显示一条红色的大警告消息。 >
这与Ingo Karkat的答案类似,但是它不需要外部插件,并且有一些细微的差别(显示警告而不是发出哔声,不需要您按u两次)。 br />请注意,这只会修改u<C-r>绑定,而不会修改U:undo:redo命令。

" Use the undo file
set undofile

" When loading a file, store the curent undo sequence
augroup undo
    autocmd!
    autocmd BufReadPost,BufCreate,BufNewFile * let b:undo_saved = undotree()['seq_cur'] | let b:undo_warned = 0
augroup end 

" Remap the keys
nnoremap u :call Undo()<Cr>u
nnoremap <C-r> <C-r>:call Redo()<Cr>


fun! Undo()
    " Don't do anything if we can't modify the buffer or there's no filename
    if !&l:modifiable || expand('%') == '' | return | endif

    " Warn if the current undo sequence is lower (older) than whatever it was
    " when opening the file
    if !b:undo_warned && undotree()['seq_cur'] <= b:undo_saved
        let b:undo_warned = 1
        echohl ErrorMsg | echo 'WARNING! Using undofile!' | echohl None
        sleep 1
    endif
endfun

fun! Redo()
    " Don't do anything if we can't modify the buffer or there's no filename
    if !&l:modifiable || expand('%') == '' | return | endif

    " Reset the warning flag
    if &l:modifiable && b:undo_warned && undotree()['seq_cur'] >= b:undo_saved
        let b:undo_warned = 0
    endif
endfun


#4 楼

我有以下内容,当撤消到达持久的缓冲区内容时,它们会停止并发出蜂鸣声。

它需要我的ingo-library插件。

评论


您是否使用“持久”来表示“加载缓冲区时文件所处的状态”?我通常希望“持久”表示当前保存到磁盘的文件状态。

–丰富
2015年3月31日14:13

@Rich:不,我们有相同的定义。我的映射不完全符合问题的要求,但我仍然发现它非常有用。

– Ingo Karkat
2015年3月31日14:28



#5 楼


我想我也会接受一个给出命令的命令,该命令将文件恢复为自上次打开文件以来的状态。 (或者更好,跳回该撤消状态。)
> Rich

我真的很喜欢引用的想法,所以我做了:Revert命令。我希望您会发现与您的问题有关。您可以在此处了解更多信息。

评论


这看起来是一个很好的解决方案。但是您在澳大利亚有一个错误。罪魁祸首是那里的vimrc。只需将其忽略

–瑙曼
17年7月23日在13:17