철자 제안을 반복하는 명령


12

나는 매핑 zz1z=대부분의 시간을 매우 중요하지만, 모든 이제 다음 첫 번째 제안은 올바른하지 않은.

그래서 다른 제안을 반복하기 위해 반복 zz(또는 .) 을 계속하고 싶습니다 .

zz같은 단어에서 두 번째 는 다음과 같이 작동 u2z=하고 세 번째 zz는 같은 방식으로 작동 u3z=합니다.

그렇게하는 방법에 대한 아이디어가 있습니까?


편집하다:

@ nobe4의 멋진 답변을 바탕으로 내가 원하는 것을 할 수 있었지만 누군가 개선이나 제안이있는 경우 잠시 동안 여기에 남겨 둘 것입니다.

let s:spell_position = []
let s:spell_count = 0
let s:spell_word = ""

function! LoopSpell()

    if s:spell_position != getpos('.') ||
            \ (s:spell_count > 0 && s:spell_word !~ expand("<cword>"))
        let s:spell_count = 0
        let s:spell_position = getpos('.')
    endif

    if s:spell_count > 0
        silent execute "normal! u"
    endif

    let s:current_word = expand("<cword>")
    if len(s:current_word) <= 0
        return
    endif

    let s:spell_suggestions = spellsuggest(expand(s:current_word))
    if len(s:spell_suggestions) <= 0
        return
    endif

    if s:spell_count >= len(s:spell_suggestions)
        let s:spell_word = s:current_word
        let s:spell_count = 0
    else
        let s:spell_word = s:spell_suggestions[s:spell_count]
        let s:spell_count += 1
    endif
    silent execute "normal! ciw" . s:spell_word
    let s:spell_position = getpos('.')

endfunction

nnoremap <c-m> :call LoopSpell()<CR>

( <c-m>@Vitor의 의견 때문에 매핑을 변경했습니다 . 또한 키를 누른 채 제안을 정말 빠르게 스크롤 할 수 있습니다 <c-mistake>. 로 생각합니다 .)


2
이 사이트의 사용자가 만든 플러그인 을 확인하는 것이 좋습니다 . 당신이 사용하는 교정 시작 : 그것은 정말 맞춤법 검사 워크 플로우를 향상 :Correct당신이 올바른에 단어를 저점 탐색 할 수 있습니다 : 명령을 n하고 N, 분할 된 창을 모두 수정 제안 할 수있는 간단하게 탐색 그들을 통해와 함께 열립니다 jk<CR>것 수정을 적용하십시오.
statox

@statox 제안 해 주셔서 감사합니다. 확인해 볼 것이지만 여전히 zz특정 명령을 빠르게 수정하기 위해 내 명령을 원합니다 .
dbmrq

3
원래 zz는 현재 줄을 중심으로 창을 중앙에두고 있습니다. 아마 내가 더 자주 사용하는 지름길 중 하나 일 것입니다. 또한 체크 아웃해야 zb하고 zt.
Vitor

@Vitor 흥미로운, 나는 그것을 몰랐다! 나는 보통 scrolloff꽤 높게 유지 하지만 여전히 유용 해 보입니다. 다른 매핑을 고려할 것입니다. 감사!
dbmrq

이 vim 스크립트는 단어 완성 / 맞춤법 교정 / 동의어 (aspell, 동의어 사전, 사전 사용) stackoverflow.com/a/46645434/476175
mosh

답변:


6

내가 생각해 낸 것은 다음과 같습니다.

철자 회전

철자 회전

풍모

  • '[']마크에 근무중인 텍스트를 추적하는 데 사용됩니다. 다른 곳에서 변경하면 제안 된 변경을 효과적으로 "수락"합니다.
  • 카운트를 받아들입니다.
  • 를 사용하여 뒤로 이동 zp
  • vim-repeat를 사용하여 반복 가능 합니다.
  • 반복 된 제안 수에 관계없이 원래 단어를 복원하려면 한 번 실행 취소하십시오.
  • 분할 단어에 대한 제안을 얻기 위해 시각적 모드에서 작동합니다 (예 : "head line"-> "headline")
    • 텍스트를 추적하기 위해 사용 '<하고 '>표시합니다.
    • 참고 : vim-repeat로 반복 가능한 것으로 보이지 않습니다 .
  • 변경되는 원래 단어는 이름이없는 레지스터에 유지됩니다.
  • 원본, 이전, 현재 및 다음 제안이 명령 행에 표시됩니다.
  • :SpellRotateSubAll원본과 일치하는 모든 텍스트를 현재 제안으로 바꾸려면 순진한 명령 입니다.

플러그인 : spellrotate.vim

function! s:spell_rotate(dir, visual) abort
  if a:visual
    " Restore selection.  This line is seen throughout the function if the
    " selection is cleared right before a potential return.
    normal! gv
    if getline("'<") != getline("'>")
      echo 'Spell Rotate: can''t give suggestions for multiple lines'
      return
    endif
  endif

  if !&spell
    echo 'Spell Rotate: spell not enabled.'
    return
  endif

  " Keep the view to restore after a possible jump using the change marks.
  let view = winsaveview()
  let on_spell_word = 0

  if exists('b:_spell') && getline("'[") == getline("']")
    let bounds = b:_spell.bounds
    " Confirm that the cursor is between the bounds being tracked.
    let on_spell_word = bounds[0][0] == bounds[1][0]
          \ && view.lnum == bounds[0][0]
          \ && view.col >= bounds[0][1]
          \ && view.col <= bounds[1][1]
  endif

  " Make sure the correct register is used
  let register = &clipboard == 'unnamed'
        \ ? '*' : &clipboard == 'unnamedplus'
        \ ? '+' : '"'

  " Store the text in the unnamed register.  Note that yanking will clear
  " the visual selection.
  if on_spell_word
    if a:visual
      keepjumps normal! y
    else
      keepjumps normal! `[v`]y
    endif
    call winrestview(view)
  elseif a:visual
    keepjumps normal! y
  else
    keepjumps normal! viwy
  endif

  let cword = getreg(register)

  if !on_spell_word || b:_spell.alts[b:_spell.index] != cword
    " Start a new list of suggestions.  The word being replaced will
    " always be at index 0.
    let spell_list = [cword] + spellsuggest(cword)
    let b:_spell = {
          \ 'index': 0,
          \ 'bounds': [[0, 0], [0, 0]],
          \ 'cword': cword,
          \ 'alts': spell_list,
          \ 'n_alts': len(spell_list),
          \ }

    if len(b:_spell.alts) > 1
      " Do something to change the buffer and force a new undo point to be
      " created.  This is because `undojoin` is used below and it won't
      " work if we're not at the last point of the undo history.
      if a:visual
        normal! xP
      else
        normal! ix
        normal! x
      endif
    endif
  endif

  if a:visual
    normal! gv
  endif

  if len(b:_spell.alts) < 2
    echo 'Spell Rotate: No suggestions'
    return
  endif

  " Force the next changes to be part of the last undo point
  undojoin

  " Setup vim-repeat if it exists.
  silent! call repeat#set(printf("\<Plug>(SpellRotate%s%s)",
        \ a:dir < 0 ? 'Backward' : 'Forward', a:visual ? 'V' : ''))

  " Get the suggested, previous, and next text
  let i = (b:_spell.index + (a:dir * v:count1)) % b:_spell.n_alts
  if i < 0
    let i += b:_spell.n_alts
  endif

  let next = (i + 1) % b:_spell.n_alts
  let prev = (i - 1) % b:_spell.n_alts
  if prev < 0
    let prev += b:_spell.n_alts
  endif

  let next_word = b:_spell.alts[next]
  let prev_word = b:_spell.alts[prev]

  let b:_spell.index = i
  call setreg(register, b:_spell.alts[i])

  if a:visual
    normal! p`[v`]
  else
    keepjumps normal! gvp
  endif

  " Keep the original word in the unnamed register
  call setreg(register, b:_spell.cword)

  let b:_spell.bounds = [
        \ getpos(a:visual ? "'<" : "'[")[1:2],
        \ getpos(a:visual ? "'>" : "']")[1:2],
        \ ]

  echon printf('Suggestion %*s of %s for "', strlen(b:_spell.n_alts - 1), b:_spell.index, b:_spell.n_alts - 1)
  echohl Title
  echon b:_spell.cword
  echohl None
  echon '":  '

  if a:dir < 0
    echohl String
  else
    echohl Comment
  endif
  echon prev_word
  echohl None

  echon ' < '

  echohl Keyword
  echon b:_spell.alts[i]
  echohl None

  echon ' > '

  if a:dir > 0
    echohl String
  else
    echohl Comment
  endif
  echon next_word
  echohl None

  redraw
endfunction


function! s:spell_rotate_suball() abort
  if !exists('b:_spell') || len(b:_spell.alts) < 2
    return
  endif
  execute '%s/'.b:_spell.cword.'/'.b:_spell.alts[b:_spell.index].'/g'
endfunction


command! SpellRotateSubAll call s:spell_rotate_suball()

nnoremap <silent> <Plug>(SpellRotateForward) :<c-u>call <sid>spell_rotate(v:count1, 0)<cr>
nnoremap <silent> <Plug>(SpellRotateBackward) :<c-u>call <sid>spell_rotate(-v:count1, 0)<cr>
vnoremap <silent> <Plug>(SpellRotateForwardV) :<c-u>call <sid>spell_rotate(v:count1, 1)<cr>
vnoremap <silent> <Plug>(SpellRotateBackwardV) :<c-u>call <sid>spell_rotate(-v:count1, 1)<cr>

nmap <silent> zz <Plug>(SpellRotateForward)
nmap <silent> zp <Plug>(SpellRotateBackward)
vmap <silent> zz <Plug>(SpellRotateForwardV)
vmap <silent> zp <Plug>(SpellRotateBackwardV)

1
와우, 지금 얘기 중이야! 향후 변경 및 개선 사항을 모두 동일한 위치에 유지할 수 있도록 이것을 독립형 플러그인으로 바꿔야합니다. 아니면 관심이 없다면 할 수도 있습니다.
dbmrq

@danielbmarques 충분히 쉽게, 여기 당신은 간다 : github.com/tweekmonster/spellrotate.vim
Tommy A

환상적입니다, 감사합니다! 나는 그것이 내가 원했던 것보다 더 정확하기 때문에 당신의 대답을 올바른 것으로 받아 들일 것이며, 그의 노력과 도움을 위해 @ nobe4에 현상금을 줄 것입니다.
dbmrq

@danielbmarques 문제 없습니다. 흥미로운 질문과 해결책을 원합니다. 😄
Tommy A

5

@statox가 제안한 것처럼, 당신은 내가 쓴 플러그인을 사용할 수 있습니다 vimcorrect를 .

기본적으로 어떻게 작동하는지 설명하겠습니다. 따라서 일부를 재사용하려면 할 수 있습니다.

내가 직접 사용하는 다음 맞춤법이 틀린 단어에 집중 ]s하고 [s그들이 이전 / 다음 경기로 이동한다. 현재 단어를 강조 표시하기 위해 맞춤 검색 기능을 정의했습니다.

여기에 이미지 설명을 입력하십시오

matchadd('error', '\%'.line('.').'l'.'\%'.col('.').'c'.s:current_word)

일치 error줄에 현재 줄 / 열의 현재 단어를 추가합니다 (같은 줄에서 여러 개의 일치를 방지하기 위해).


spellbadword()함수는 커서 아래의 단어에 대한 가능한 수정 목록을 반환합니다.

이 목록을 버퍼에 간단히 표시 <CR>하고 철자가 틀린 단어를 현재 줄 (예 : 가능한 수정 된 단어)로 바꾸도록 매핑 합니다.


또한지도 nN]s[s내가 검색을 눌러 사용하고 있습니다로.

q 플러그인을 종료하고 분할을 닫고 강조 표시를 제거하도록 매핑되었습니다.

참고 : 여전히 불안정하지만 곧 변경할 계획입니다. 이 플러그인을 개선하고 싶거나 풀 요청을 자유롭게 열거 나 열고 싶다면


설명 주셔서 감사합니다. 플러그인이 멋지게 보입니다. 확실히 사용하겠습니다. 그래도 여전히 내 zz명령을 원 하므로 특수 모드로 들어 가지 않고 신속하게 문제를 해결할 수 있습니다. 어쩌면 vimcorrect내가 알아 내면 추가 할 수 있습니다 . :)
dbmrq

글쎄, 나는 분명히 더 많은 사용자 정의를 추가해야합니다. 커스텀 매핑을 정의하는 것은 개선 할 수 있도록 (당신이 그것을 배울 수있는 좋은 방법이 될 수 있습니다 vim 스크립트에 개발을 시작할 경우) : 원하는 경우 추가 할 수 있습니다
nobe4

2

작동해야하는 기능은 다음과 같습니다.

let s:last_spell_changedtick = {}

function! LoopSpell()
  " Save current line and column
  let l:line = line('.')
  let l:col = col('.')

  " check if the current line/column is already in the last_spell_changedtick
  if has_key(s:last_spell_changedtick, l:line) == 0
    let s:last_spell_changedtick[l:line] = {}
  endif

  if has_key(s:last_spell_changedtick[l:line], l:col) == 0
    let s:last_spell_changedtick[l:line][l:col] = 0
  endif

  " If the value already exists, undo the change
  if s:last_spell_changedtick[l:line][l:col] != 0
    normal u
  endif

  " Get the current word
  let l:current_word = spellbadword()
  if len(l:current_word) == 0
    call <SID>Quit()
  endif

  " Get suggestions for the current word
  let s:current_word = l:current_word[0]
  let l:suggestions = spellsuggest(expand(s:current_word))

  " If the current word present no spelling suggestions, pass
  if len(suggestions) <= 0
    return
  endif

  " Replace the word with suggestion
  silent execute "normal! ce" . l:suggestions[s:last_spell_changedtick[l:line][l:col]]
  normal! b

  " Increment the count
  let s:last_spell_changedtick[l:line][l:col] = s:last_spell_changedtick[l:line][l:col] + 1

endfunction

function! LoopConfirm()
  let s:last_spell_changedtick = {}
endfunction

nnoremap zz :call LoopSpell()<CR>
nnoremap z= :call LoopConfirm()<CR>

기본 아이디어는 변경된 모든 단어를 한 행에 대해서만 작동하지 않도록 한 행 / 열 쌍에 매핑하고 요소가 이미 수정되었는지 확인하는 것입니다.

교체를 수행하려면 플러그인이 수행하는 작업이 거의 같습니다.

  • 현재 철자가 틀린 단어를 가져옵니다
  • 수정이 있는지 확인
  • 올바른 제안으로 단어 교체

이 단어를 사용할 때 철자가 틀린 단어로 돌아가려면을 누르기 만하면 u됩니다.

LoopConfirm기능은 사전을 재설정하므로 텍스트를 변경하면 충돌을 방지하기 위해 사전을 호출 할 수 있습니다.

문제가 발생하거나 질문이있는 경우 알려주십시오.


어, 좋아 보인다 그래도 여전히 많은 문제가 있습니다. "qick borwn foz jums ofer teh lazi dor"와 같은 문구를 사용하여 각 단어를 수정하십시오. 나는 목록에서 4 번이지만 "teh"를 "the"로 가져올 수는 없습니다. "qick"은 작동하지만 "brown"이 목록에있는 첫 번째 항목 인 경우에도 "borwn"이 다른 것으로 변경되고 "foz"로 바로 건너 뜁니다. 나는 그것을 지나치지 않았다. 또한 나는 여분의 z=부분을 좋아하지 않지만 나머지 부분이 효과가 있다면 그 문제를 해결할 수있는 방법을 찾을 수 있습니다. 그래도 이것은 내가 원하는 것에 매우 가까워지고 있습니다. 계속 고치려고 노력하겠습니다. 감사!
dbmrq

내 업데이트를 참조하십시오. 너무 빨리 증가 z=합니다. :) 그래도 나에게 만족하지 않습니다 . 그러나이 방법을 사용하면 현재 위치를 참조해야합니다. 그러나 모든 참조를 동시에 유지할 필요가 없다면 간단히 단순화 할 수 있습니다. :)
nobe4

"모든 참조를 동시에 유지"한다는 것이 무슨 의미인지 잘 모르겠지만… 커서가 움직일 때마다 사전을 재설정 할 수 없었습니까? 이 함수는 커서가 마지막으로 호출 된 시점과 동일한 위치에 있는지 확인하고 재설정되지 않았는지 확인합니다.
dbmrq

또한 커서가 단어의 시작 부분에 있지 않을 때 제대로 작동하지 않는 것 같습니다. 커서를 각 단어의 중간에 놓으면 해당 문장의 모든 실수를 수정하십시오. 나는 바로 다음으로 건너 뜁니다.
dbmrq

1
알았어, 알았어! 마지막 편집을 확인하십시오. 이것은 거의 완벽하게 작동하는 것 같습니다. 다른 사람이 추가 할 것이 있는지 확인하기 위해 질문을 조금 더 열어 두겠습니다.하지만 귀하의 답변이 훌륭했습니다. 감사합니다. :)
dbmrq

2

다른 답변 외에도 실제로 Vim에 내장 된 방법이 <C-x>s있습니다. Vim의 삽입 모드 완료 메뉴를 사용합니다.

<C-x>s삽입 모드에서 누르면 커서 아래의 단어가 첫 번째 제안으로 수정되고 추가 제안 (있는 경우)이있는 완료 메뉴가 표시됩니다. 'completeopt'설정을 사용하여 완료 메뉴의 일부 설정을 사용자 정의 할 수 있습니다 .

이것은 삽입 모드에서만 작동하고 using을 사용하는 <C-x><C-s>데 문제가 될 수 있으므로 약간 성가 시므로 (아래 참고 참조) 이에 대한 고유 한 매핑을 정의 할 수 있습니다.

inoremap <expr> <C-@>  pumvisible() ?  "\<C-n>" : "\<C-x>s"
nnoremap <expr> <C-@> pumvisible() ?  "i\<C-n>" : "i\<C-x>s"

<C-@> Control + Space입니다.

참조 :help ins-completion :help i_CTRL-X_s


필자는 개인적으로 작업의 철자를 확인하거나 코드에 대해 정기적 인 자동 완성을 사용하려는 경우 "추측"할 수있는 고급 버전을 개인적으로 사용합니다.

fun! GuessType()
    " Use omnicomplete for Go
    if &filetype == 'go'
        let l:def = "\<C-x>\<C-o>"
    " Keyword complete for anything else
    else
        let l:def = "\<C-x>\<C-n>"
    endif

    " If we have spell suggestions for the current word, use that. Otherwise use
    " whatever we figured out above.
    try
        if spellbadword()[1] != ''
            return "\<C-x>s"
        else
            return l:def
        endif
    catch
        return l:def
    endtry
endfun

inoremap <expr> <C-@>  pumvisible() ?  "\<C-n>" : GuessType()
inoremap <expr> <Down> pumvisible() ? "\<C-n>" : "\<Down>"
inoremap <expr> <Up> pumvisible() ? "\<C-p>" : "\<Up>"
nnoremap <expr> <C-@> pumvisible() ?  "i\<C-n>" : 'i' . GuessType()

나는 거의 비슷한 것을하는 플러그인도 있다고 생각하지만 (SuperTab과 같이 매우 인기가 있습니다), 나는 내가 원하는대로 작동하도록 할 수 없었습니다.


주의 사항 : 터미널에서 Vim을 사용하는 경우 <C-s>"출력 중지"를 의미합니다. 이런 이유로 모두 <C-x><C-s> <C-x>s 기본적으로 매핑됩니다. 실수로 <C-q>누르면 출력을 계속하는 데 사용 합니다 <C-s>. <C-s>사용하지 않으면 비활성화 할 수도 있습니다 ( 이 질문 참조 ). GVim을 사용하는 경우이를 무시할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.