실행 취소 파일에서 변경 사항을 취소 할 때 알림을받을 수 있습니까?


15

나는 Vim 에서 undofile 기능한동안 사용하고 있다. 아주 좋은 기능입니다.

그러나 한 가지 불편한 점은 마지막으로 파일을 열 때 변경 한 내용을 실수로 실행 취소하기가 매우 쉽다는 것입니다. 2 분 전, 1 시간 전, 지난 주 또는 1 개월 전일 수 있습니다.

예를 들어, 파일을 열고, 몇 가지 변경을하고, 다른 파일을 변경하고 변경 한 내용이 필요하지 않거나 임시 디버그 명령문 일 뿐이라는 것을 발견했다고 가정 해 보겠습니다.

이전에는 uVim이 "이미 가장 오래된 변경 사항"이라고 말할 때까지 키를 잡고있을 수있었습니다 :wq. 그러나 이제 파일을 마지막으로 열 때 변경 한 내용을 취소하지 않도록주의해야합니다. 이 작업을 수행하는 시점을 확인할 수있는 확실한 방법은 없습니다.

좀 더 명시 적으로 만들 수있는 방법이 있습니까? 예를 들어 어딘가에 표시하거나 경고를 표시하거나 확인을 요청하는 경우도 있습니다.


이것은 내가 undofile 기능을 공개 한 이후로 궁금했던 질문이며,이 사이트가 공개 된 이후로 묻고 자하는 질문이었습니다! 좋은 답변이 있기를 바랍니다. 나는 또한 파일을 마지막으로 이후의 상태로 파일을 되 돌리는 명령을 내린 대답을 받아 들일 것이라고 생각 합니다. (또는 더 나은, 그 취소 상태로 되돌아 갔다.)
Rich

답변:


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

@Carpetsmoker 동의합니다. 가능하다면 그렇게하는 것이 좋을 것입니다. 그것이 일어나면서 이것은 오랫동안 저에게 충분히 효과가있었습니다. YMMV.
superjer

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방법을 사용할 수도 있습니다 . 어쨌든 훨씬 세분화되지 않습니다.
Doorknob

"X"와 "Y"는 나에게 똑같은 문제를 나타내는 것 같아? 내 질문에 언급 "주"를했지만 또한 시간 또는 분 (즉 수정) ...이 아닌 나쁜 해답이 될 수있는 다음과 같은 방법에 의해, 난 그냥 더 나은 무언가가 바라고 있었다 (그리고 오전) ...
Martin Tournoij

저는 @Carpetsmoker와 함께 있습니다. 나는 한동안 일찍 :에 대해 알고 있었지만 여전히 질문에 설명 된 이유 때문에 undofile이 꺼져 있습니다.
Rich

4

2015-06-28 업데이트 : 작은 버그가 수정되어 플러그인으로 출시되었습니다 . 플러그인 코드는 커서를 움직 인 후 다시 경고한다는 점에서 약간 더 좋습니다. 플러그인을 사용하는 것이 좋습니다.



에서 대답 superjer는 잘 작동하지만 마지막 빔 세션의 변경, 그리고 취소 만 할 수 불행한 부작용이 모든 이전 빔 세션을.

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 플러그인 이 필요합니다 .


"persisted"를 사용하여 "버퍼가로드 될 때 파일의 상태"를 의미합니까? 일반적으로 "지속적"은 현재 디스크에 저장된 파일의 상태를 의미합니다.
Rich

@Rich : 아니요, 같은 정의를 가지고 있습니다. 내 매핑은 질문에서 요구하는 것과 정확히 일치하지 않지만 여전히 매우 유용합니다.
Ingo Karkat

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_sequndotreeReal_seq 기반 의이 필요 undotree()['seq_cur']합니다. 자세한 내용은 여기를 참조 하십시오 .


이것은 좋은 해결책처럼 보입니다. 하지만에 오류가 있습니다 au. 의 vimrc 거기는 범인입니다. 그냥 나가십시오
Naumann
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.