从撤消文件撤消更改时,可以得到通知吗?


15

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

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

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

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

有什么办法可以使这个更明确吗?例如,将其显示在某个地方,发出警告甚至要求确认。


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

Answers:


8

我有这个确切的问题。这是我添加到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 2015年

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

5

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

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问题。


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

1
我现在:earlier顺便说一下,但我仍然需要猜测;正如我在使用... 时需要猜测的那样u。在某些情况下,它可能会更好一些,但我更喜欢更明确的内容(如果可能)。
Martin Tournoij

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

在我看来,“ X”和“ Y”只是对同一问题的改写?我没有提到“周”在我的问题,但它也可能是小时或分钟(修改过的)...这不是一个不好回答这样的方式,我是(AM)只是希望有更好的东西...
马丁·图尔诺伊

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

4

更新2015-06-28:我修复了一个小错误,并将其作为插件发布。插件代码稍好一点,因为它在移动光标后会再次发出警告;我建议您使用该插件。



superjer的答案有效,但不幸的是,您只能撤消上一个Vim会话中的更改,而不能撤消所有先前的Vim会话中的更改。

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

因此,这是我的替代解决方案,当您撤消撤消文件中的更改时,它将显示一条红色的大警告消息。

这类似于Ingo Karkat的答案,但是它不需要外部插件,并且有一些细微的差异(显示警告而不是发出哔声,不需要您再按u两次)。

请注意,这只是修改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

3

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

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>

这与repeat.vim插件集成在一起;它需要我的ingo-library插件


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

@Rich:不,我们有相同的定义。我的映射并不能完全满足问题的要求,但我仍然发现它非常有用。
Ingo Karkat 2015年

2

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

>丰富

我真的很喜欢这个引用的想法,所以我下了:Revert命令。我希望您会发现与您的问题有关。

function! s:Real_seq(inner, outer) abort
  let node = a:outer
  for i in a:inner
    if has_key(i, 'alt')
      call s:Real_seq(i.alt, deepcopy(node))
    endif
    if has_key(i, 'curhead')
      return {'seq': node.seq}
    endif
    let node.seq  = i.seq
  endfor
endfunction

function! s:Get_seq(tree) abort
  let query = s:Real_seq(a:tree.entries, {'seq': 0})
  if (type(query) == 4)
    return query.seq
  else
    return undotree()['seq_cur']
  endif
endfunction

au BufReadPost,BufNewFile * if !exists('b:undofile_start') 
      \ | let b:undofile_start = s:Get_seq(undotree()) | endif

command! -bar Revert execute "undo " . get(b:, 'undofile_start', 0)

辅助功能Get_seqReal_seq基于undotree,是必要的,因为undotree()['seq_cur']有时是不够的,在查明撤销树当前位置。您可以在此处了解更多信息。


这看起来是一个很好的解决方案。但是你的错误au。罪魁祸首是其中的vimrc。只需将其删除
Naumann
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.