Stoktan değişiklikleri geri aldığımda bildirim alabilir miyim?


15

Bir süredir Vim'deki bozulmamış özelliğini kullanıyorum . Çok güzel bir özellik.

Ancak, bir sıkıntı, dosyayı son açtığımda yaptığım değişiklikleri yanlışlıkla geri almanın çok kolay olmasıdır; 2 dakika önce, bir saat önce, geçen hafta veya bir ay önce olabilir.

Örneğin, bir dosyayı açtığımı, birkaç değişiklik yaptığımı, gidip diğer bazı dosyaları değiştirdiğimi ve değişikliklerimin gerekli olmadığını veya belki de yalnızca birkaç geçici hata ayıklama ifadesi olduğunu keşfettiğimizi varsayalım.

Önceden, uVim "Zaten en eski değişiklikte" diyene kadar anahtarı tutabildim :wqve yapılabilirdi. Ama şimdi dosyayı son açtığımda yaptığım değişiklikleri geri almamaya çok dikkat etmeliyim. Bunu ne zaman yaptığınızı görmenin açık bir yolu yoktur.

Bunu daha açık hale getirmenin herhangi bir yolu var mı? Örneğin bir yerde göstererek, bir uyarı vererek, hatta bir onay isteyerek.


Bu, bozulmamış özelliğinin ortaya çıkmasından bu yana merak ettiğim bir soru ve bu sitenin açılmasından bu yana sormak için etrafta dolaşmak istediğim bir soru! Umarım iyi bir cevap vardır. Sanırım dosyayı son açtığınız andan itibaren durumuna döndüren bir komut veren bir yanıtı da kabul ediyorum . (Ya da daha iyisi, geri alma durumuna geri döndü.)
Zengin

Yanıtlar:


8

Tam olarak bu problemi yaşadım. Benim için düzeltmek için vimrc benim ekledi:

" 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

O Not yok set undofileseçeneği; varsa vimrc'nizden kaldırmanız gerekir.

Geri al artık "normal" olarak çalışıyor. Ama biz do elle ile geri alma dosyasına yazma wundokomutunu BufWritePost.

ReadUndo()Fonksiyon manuel ile geri alma dosyasını okur rundove ayarlar undofileseçeneği. Şimdi utarihe geri dönmek için kullanabiliriz . Bunu eşledim <Leader>u.

Bu muhtemelen daha iyi olabilir. Önceki geri alma bilgilerinin üzerine yazar, böylece dosyayı düzenlediğinizde önceki bir önceki zamana geri dönemezsiniz. Ama buna ihtiyacım olmadı.


Not Bununla ilgili bir sorun fark ettim: sadece geçerli oturumun içeriğini geri al dosyasına kaydedersiniz. Bu, önceki oturumun içeriğinin + geri alma dosyasında zaten bulunan tüm bilgilerin kaydedildiği varsayılan davranıştan farklıdır ... Bunu düzeltmenin yolu, geri alma dosyasını okumak, geri alma değişikliklerini birleştirmek ve sonra yazmaktır geri alma dosyası ... Ama bu mümkün görünmüyor ...: - /
Martin Tournoij

@Carpetsmoker katılıyorum. Mümkünse bunu yapmak güzel olurdu. Olduğu gibi, bu benim için uzun süre yeterince iyi çalıştı. YMMV.
superjer

5

Oooh, ooh, nihayet bu şık komutu gösterme şansı !

Vim "zamanda geriye gidebilir". Bir :earlieremri var ...

                                                        :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.                                

... dosyayı bir önceki duruma geri döndürebilir. Bu, çeşitli şekillerde kullanılabilir.

  • Bir ballpark'ın bu değişiklikleri yapmanın ne kadar sürdüğünü tahmin edebiliyorsanız, bu komuta bir süre besleyebilirsiniz. Örneğin, son bir gün içinde dosyayı (geri almak istediğiniz değişiklikler hariç) değiştirmediğinizi biliyorsanız, aşağıdakileri kullanabilirsiniz:

    :earlier 1d
    
  • Geri almak istediğiniz değişikliklerden bu yana dosyayı yalnızca bir kez yazdıysanız (kaydettiyseniz) veya dosyayı hiç kaydetmediyseniz,

    :earlier 1f
    

    :helpMetinde açıklandığı gibi , bu dosyayı daha yeni yazdıysanız önceki yazılı sürüme veya kaydedilmiş değişiklikleriniz yoksa en son kaydedildiği süreye geri döner.

Bu, sorunuza tam olarak cevap vermiyor, ancak biraz XY problemine benziyor.


1
biraz XY sorunu gibi geliyor : Neden? Geri alıyorum uve yanlışlıkla şu anda yaptığım değişiklikleri geçiyorum ... Orijinal "X sorununun" burada ne olabileceğinden emin değilim?
Martin Tournoij

1
Şimdi :earlierbu arada, ama yine de tahmin etmeliyim ; tıpkı kullanırken tahmin etmem gerektiği gibi u... Durumlarda muhtemelen biraz daha iyi, ama (mümkünse) daha açık bir şey tercih ederim.
Martin Tournoij

1
@Carpetsmoker "X" "Ben geri almak istiyor ise sadece en yakın zamanda yaptığı bu değişiklikleri." "Y", "Değişiklikleri nasıl geri alabilirim ve el diskini yok sayabilirim?" Hala tahmin etmek zorundasınız, ancak sorunuzda yaptığınız son değişikliklerin geçen hafta veya daha erken olduğunu söylediniz, böylece sadece bir şey yapabilirsiniz :ea 5d. :ea 1fYaklaşımı da kullanabilirsiniz . Her durumda, çok daha az parçalı.
Doorknob

"X" ve "Y" aynı problemi bana yeniden anlatmış gibi mi görünüyor? Sorumda "haftalar" dan bahsettim, ama aynı zamanda saatler veya dakikalar da olabilir (değiştirildi) ... Bu arada bu kadar kötü bir cevap değil , sadece daha iyi bir şey olmasını umuyordum (ve duyuyorum) ...
Martin Tournoij

Ben bu konuda @Carpetsmoker ile birlikteyim. Ben daha önce de biliyordum: Bir süre daha, ama hala tam olarak soruda açıklanan neden için kapalı undofile var.
Zengin

4

2015-06-28 Güncellemesi : Küçük bir hatayı düzelttim ve bunu bir eklenti olarak yayınladım . Eklenti kodu biraz daha iyidir, çünkü imleci hareket ettirdikten sonra tekrar uyarır; Eklentiyi kullanmanızı tavsiye ederim.



Superjer'in cevabı harika çalışıyor, ancak önceki Vim oturumlarının tümünü değil, yalnızca son Vim oturumundaki değişiklikleri geri alabileceğiniz talihsiz bir yan etkiye sahip .

Bunun nedeni wundogeri alma dosyasının üzerine yazmasıdır; birleştirilmiş değil. Bildiğim kadarıyla bunu düzeltmenin bir yolu yok.

İşte benim alternatif çözümüm, geri alma dosyasındaki değişiklikleri geri aldığınızda büyük bir kırmızı uyarı mesajı gösterecektir.

Bu Ingo Karkat'ın cevabına benzer , ancak harici bir eklenti gerektirmez ve bazı ince farkları vardır (bip sesi yerine uyarı görüntüler, uiki kez basmanızı gerektirmez ).

Bu Not sadece değiştirir uve <C-r>bağlar ve değilU , :undove :redokomutları.

" 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

Geri alma kalıcı arabellek içeriğine ulaştığında duran ve bip sesi çıkaran aşağıdakilere sahibim.

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>

Bu repeat.vim eklentisi ile bütünleşir; benim ingo-library eklentimi gerektirir .


"Tampon yüklendiğinde dosyanın bulunduğu durum" anlamına gelmek için "kalıcı" mı kullanıyorsunuz? Genellikle "kalıcı" beklemek o anda diske kaydedilen dosyanın durumu anlamına gelir.
Zengin

@Rich: Hayır, aynı tanıma sahibiz. Haritalarım sorunun tam olarak ne istediğini yapmıyor, ama yine de çok faydalı buldum.
Ingo Karkat

2

Sanırım dosyayı son açtığınız andan itibaren durumuna döndüren bir komut veren bir yanıtı da kabul ediyorum. (Ya da daha iyisi, geri alma durumuna geri döndü.)

> Zengin

Alıntılanan fikri gerçekten beğendim, bu yüzden :Revertemir verdim . Umarım sorunuzla alakalı bulabilirsiniz.

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)

Yardımcı işlevler Get_seqve altbilgiyeReal_seq dayalı olarak gereklidir , çünkü undotree()['seq_cur']bazen geri alma ağacındaki geçerli konumu belirlemek için yeterli değildir. Burada daha fazla bilgi edinebilirsiniz .


bu iyi bir çözüm gibi görünüyor. Ama bir hata var au. içindeki vimrc suçlu. Sadece dışarıda bırakın
Naumann
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.