元に戻すファイルから変更を元に戻すときに通知を受け取ることはできますか?


15

しばらくの間、Vim の取り消しファイル機能を使用しています。これは非常に便利な機能です。

ただし、面倒な点の1つは、前回ファイルを開いたときに行った変更を誤って取り消すのが非常に簡単なことです。2分前、1時間前、先週、1か月前などです。

たとえば、ファイルを開いて、いくつかの変更を行ってから、他のファイルを変更して、変更が不要であるか、一時的なデバッグステートメントであることがわかったとします。

以前は、uVimが「最も古い変更で既に」と言うまでキーを押し続けるだけ:wqで済みました。ただし、ファイルを前回開いたときに行った変更を元に戻さないように注意する必要があります。これを行っているかどうかを確認する明確な方法はありません。

これをより明確にする方法はありますか?たとえば、どこかに表示したり、警告を発行したり、確認を求めたりすることもできます。


これは、アンドゥファイル機能の発表以来疑問に思っていた質問であり、このサイトの発表以来、私は質問に取り掛かることを意味してきました!良い答えがあることを願っています。また、ファイルを最後に開いたときから元の状態に戻すコマンドを与えた回答も受け入れると思います。(または、その元に戻す状態にジャンプして戻ります。)
リッチな

回答:


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がある場合は削除する必要があります。

元に戻すは「通常」として機能します。ただし、のコマンドを使用して手動で元に戻すファイルに書き込みます。wundoBufWritePost

このReadUndo()関数は、手動で取り消しファイルを読み取りrundoundofileオプションを設定します。これでu、履歴にさらに戻ることができます。これをにマッピングしました<Leader>u

これはおそらくより良いかもしれません。以前のアンドゥ情報が上書きされるため、ファイルを編集した以前の時間に戻ることはできません。しかし、私はそれを自分で必要としていません。


注これには問題があることに気付きました。現在のセッションの内容のみを元に戻すファイルに保存します。これは、以前のセッションの内容+元に戻すファイル内のすべての情報が保存されるデフォルトの動作とは異なります。元に戻すファイル...しかし、これは不可能のようです...:-/
Martin Tournoij

@Carpetsmoker同意します。可能であれば、それを行うといいでしょう。たまたまこれは私にとって長い間うまく機能していました。YMMV。
スーパージャー

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.                                

...ファイルを以前の状態に戻すことができます。これはさまざまな方法で使用できます。

  • これらの変更を行うのにかかった時間の概算を作成できる場合は、このコマンドに時間を入力できます。または、たとえば、過去1日間にファイルを変更していないことがわかっている場合(元に戻す変更を除く)、次を使用できます。

    :earlier 1d
    
  • 変更を取り消すためにファイルを一度だけ書き込んだ(保存した)場合、またはファイルをまったく保存していない場合は、次を使用できます。

    :earlier 1f
    

    :helpテキストで説明されているように、これはファイルを書き込んだばかりの場合は以前に書き込まれたバージョンに戻り、保存された変更がない場合は最後に保存された時点に戻ります。

これはあなたの質問に正確に答えるわけではありませんが、XY問題のように聞こえます。


1
ちょっとしたXYの問題のように聞こえます:なぜですか?で元に戻しuていますが、今行った変更を誤って過ぎてしまいました...元の「X-problem」がここにあるかどうかわかりませんか?
マーティントゥルノイ

1
私は今、程度:earlierとして、私はまだする必要があると思います。を使用するときに推測する必要があるの同じようにu...場合によってはおそらく少し改善されますが、より明確なもの(可能であれば)を好むでしょう。
マーティントゥルノイ

1
@Carpetsmoker「X」は「最近行ったこれらの変更だけを元に戻したい」です。「Y」は「変更を元に戻し、元に戻すファイルを無視するにはどうすればよいですか?」です。まだ推測する必要がありますが、質問の中で、最後に行った変更は先週またはそれ以前であると言ったので、次のようにできます:ea 5d。この:ea 1fアプローチを使用することもできます。いずれにせよ、それははるかに粒状ではありません。
ドアノブ

「X」と「Y」は同じ問題を言い換えているように思えますか?私は私の質問に言及「週間」でしたが、また、時間、または分(ことに変更された)...これではない、悪い答えかもしれないような方法によって、私はより良いものがある期待していた(と午前) ...
マーティンTournoij

これについては@Carpetsmokerと一緒です。私はしばらく前から知っていましたが、質問で説明されている正確な理由で、元に戻すファイルがオフになっています。
リッチ

4

更新2015-06-28:小さなバグを修正し、これをプラグインとしてリリースしました。プラグインのコードは、カーソルを移動した後に再び警告するという点でわずかに優れています。プラグインを使用することをお勧めします。



superjerからの回答は非常に効果的ですが、残念なことに副作用があり、元のVimセッションすべてではなく、最後のVimセッションからの変更のみを取り消すことができます。

これはwundo、取り消しファイルが上書きされるためです。マージされません。私の知る限り、これを修正する方法はありません。

だからここに私の代替ソリューションは、元に戻すファイルから変更を元に戻すときに大きな赤い警告メッセージが表示されます。

これはIngo Karkatの回答に似ていますが、外部プラグインを必要とせず、微妙な違いがあります(ビープ音の代わりに警告を表示し、u2回押す必要はありません)。

この注意のみ修正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:いいえ、同じ定義があります。私のマッピングは、質問が求めるものを正確に実行しませんが、それでも非常に便利であることがわかりました。
インゴカルカット

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)

元に戻すツリーの現在の位置を特定するには不十分な場合があるため、undotreeに基づくヘルパー関数Get_seqとが必要です。詳細については、こちらをご覧くださいReal_sequndotree()['seq_cur']


これは良い解決策のように見えます。ただし、にエラーがありますau。そこのvimrcが犯人です。単にそれを残す
ナウマン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.