Lệnh lặp qua các gợi ý chính tả


12

Tôi ánh xạ zztới 1z=, đó là rất tốt hầu hết thời gian, nhưng tất cả bây giờ và sau đó đề nghị đầu tiên không phải là một trong những quyền.

Vì vậy, tôi muốn tiếp tục lặp lại zz(hoặc .) để duyệt qua các đề xuất khác.

Một giây zztrên cùng một từ, sau đó, sẽ hoạt động như thế u2z=, một phần ba zzsẽ hoạt động như u3z=vậy và cứ thế.

Bất kỳ ý tưởng về làm thế nào để làm điều đó?


Biên tập:

Dựa trên câu trả lời tuyệt vời của @ nobe4, tôi đã xoay sở để làm những gì tôi muốn, nhưng tôi sẽ để nó ở đây một lúc trong trường hợp có ai có bất kỳ cải tiến hoặc đề xuất nào:

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>

(Tôi đã thay đổi ánh xạ thành <c-m>vì nhận xét của @ Vitor. Ngoài ra, điều này cho phép tôi giữ các phím đó xuống và sắp xếp cuộn qua các đề xuất rất nhanh. Tôi nghĩ về nó như <c-mistake>.)


2
Tôi sẽ đề nghị bạn kiểm tra plugin này được tạo bởi người dùng của trang này. Nó thực sự cải thiện công việc kiểm tra chính tả: để bắt đầu sửa chữa bạn sử dụng :Correctlệnh: bạn sẽ có thể để di chuyển máng những lời để đúng với nN, một cửa sổ tách mở ra với tất cả những đề nghị sửa chữa, bạn có thể chỉ đơn giản là điều hướng qua chúng với jk<CR>sẽ áp dụng hiệu chỉnh.
statox

@statox Cảm ơn bạn đã gợi ý. Tôi sẽ kiểm tra nó, nhưng tôi vẫn muốn zzlệnh của mình sửa chữa những thứ cụ thể một cách nhanh chóng.
dbmrq

3
Hy vọng bạn biết rằng ban đầu zztập trung vào cửa sổ xung quanh dòng hiện tại. Đây có lẽ là một trong những phím tắt tôi sử dụng thường xuyên hơn. Bạn cũng nên kiểm tra zbzt.
Vitor

@Vitor Thú vị, tôi không biết điều đó! Tôi thường giữ scrolloffmức khá cao, nhưng điều đó vẫn có vẻ hữu ích, tôi sẽ xem xét một ánh xạ khác. Cảm ơn!
dbmrq

Tập lệnh vim này thực hiện hoàn thành từ / sửa lỗi chính tả / từ đồng nghĩa (sử dụng aspell, từ điển đồng nghĩa, từ điển) stackoverflow.com/a/46645434/476175
mosh

Câu trả lời:


6

Đây là những gì tôi nghĩ ra:

Chính tả xoay

xoay chính tả

Đặc trưng

  • Dấu '[']được sử dụng để theo dõi văn bản đang được thực hiện. Thực hiện thay đổi ở nơi khác sẽ "chấp nhận" thay đổi được đề xuất một cách hiệu quả.
  • Chấp nhận một số lượng.
  • Đi ngược lại bằng cách sử dụng zp
  • Lặp lại bằng cách sử dụng vim-repeat .
  • Hoàn tác một lần để khôi phục từ gốc bất kể có bao nhiêu đề xuất đã được đạp xe.
  • Hoạt động ở chế độ trực quan để nhận đề xuất cho các từ tách (ví dụ: "dòng tiêu đề" -> "tiêu đề")
    • Sử dụng '<'>đánh dấu để theo dõi văn bản.
    • Lưu ý : Dường như không thể lặp lại với vim-repeat .
  • Từ gốc được thay đổi được giữ trong sổ đăng ký không tên.
  • Các đề xuất ban đầu, trước đó, hiện tại và tiếp theo được hiển thị trong dòng lệnh.
  • Lệnh Naive :SpellRotateSubAllđể thay thế tất cả văn bản khớp với bản gốc bằng đề xuất hiện tại.

Plugin: sprotate.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
Wow, bây giờ chúng ta đang nói chuyện! Bạn nên biến nó thành một plugin độc lập để chúng tôi có thể giữ tất cả các thay đổi và cải tiến trong tương lai tại cùng một nơi. Hoặc tôi có thể thử làm nó nếu bạn không quan tâm.
dbmrq

@danielbmarques Đủ dễ dàng, bạn đến đây: github.com/tweekmonster/spellrotate.vim
Tommy A

Tuyệt vời, cảm ơn bạn! Tôi sẽ chấp nhận câu trả lời của bạn là câu trả lời đúng vì đó chính xác là những gì tôi muốn và hơn thế nữa, và tôi sẽ đưa tiền thưởng cho @ nobe4 cho tất cả nỗ lực và sự giúp đỡ của anh ấy.
dbmrq

@danielbmarques Không có vấn đề. Tôi tham gia vì những câu hỏi và giải pháp thú vị 😄
Tommy A

5

Như @statox đã đề xuất, bạn có thể sử dụng plugin tôi đã viết: vimc chính xác .

Về cơ bản, tôi sẽ giải thích cách thức hoạt động của nó, vì vậy nếu bạn muốn sử dụng lại một phần của nó, bạn có thể.

Để tập trung vào từ sai chính tả tiếp theo, tôi sử dụng trực tiếp ]s[skhi chúng chuyển sang trận đấu tiếp theo / trước đó. Tôi đã xác định một chức năng khớp tùy chỉnh để làm nổi bật từ hiện tại:

nhập mô tả hình ảnh ở đây

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

Thêm vào nhóm đối sánh errortừ hiện tại ở dòng / cột hiện tại (để ngăn nhiều kết hợp trên cùng một dòng).


Các spellbadword()chức năng trả về một danh sách điều chỉnh có thể cho từ dưới con trỏ.

Tôi chỉ đơn giản hiển thị danh sách này trong một bộ đệm và tôi ánh xạ <CR>để thay thế từ sai chính tả bằng dòng hiện tại (nghĩa là một từ có thể sửa được).


Tôi cũng lập bản đồ nNđể ]s[s, như tôi đang sử dụng để báo chí chúng để tìm kiếm.

q được ánh xạ để thoát khỏi plugin, đóng tách và xóa phần tô sáng.

Lưu ý : nó vẫn không ổn định cao, nhưng tôi dự định sẽ sớm thực hiện một số thay đổi. Nếu bạn cảm thấy có thể / muốn cải thiện plugin này, hãy thoải mái rẽ / mở một yêu cầu kéo.


Cảm ơn đã giải thích. Plugin của bạn trông rất tuyệt, tôi chắc chắn sẽ sử dụng nó. zzMặc dù vậy, tôi vẫn muốn lệnh của mình , vì vậy tôi có thể sửa chữa mọi thứ nhanh chóng mà không cần vào chế độ đặc biệt. Có lẽ chúng ta có thể thêm nó vào vimcorrectnếu tôi tìm ra nó. :)
dbmrq

Vâng, tôi chắc chắn cần phải thêm nhiều tùy chỉnh. Vì vậy, xác định ánh xạ tùy chỉnh có thể là một cải tiến bạn có thể thêm nếu bạn muốn :) (nếu bạn bắt đầu phát triển trong vimscript, đó có thể là một cách tốt để tìm hiểu)
nobe4

2

Đây là một chức năng nên hoạt động:

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>

Ý tưởng cơ bản là ánh xạ mọi từ đã thay đổi thành một cặp dòng / cột (để nó không chỉ hoạt động cho một phần tử) và kiểm tra xem phần tử đó đã được sửa đổi chưa.

Để thay thế, đó là khá nhiều những gì plugin của tôi làm:

  • lấy từ sai chính tả hiện tại
  • kiểm tra nếu có sửa chữa
  • thay thế từ bằng gợi ý sửa

Khi sử dụng, nếu bạn muốn quay lại từ sai chính tả, bạn chỉ cần nhấn u.

Các LoopConfirmchức năng thiết lập lại từ điển, vì vậy nếu bạn thay đổi văn bản của bạn, bạn có thể gọi nó là để ngăn chặn xung đột.

Hãy cho tôi biết nếu bạn gặp phải bất kỳ vấn đề nào / nếu bạn có thắc mắc.


Uuh, điều đó thật tuyệt. Nó vẫn còn nhiều vấn đề, mặc dù. Lấy một cụm từ như "teh qick borwn foz jums ofer teh lazi dor" và cố gắng sửa từng từ theo cách đó. Tôi không bao giờ có thể đưa "teh" thành "the", mặc dù đó là số 4 trong danh sách. "qick" hoạt động, nhưng "borwn" thay đổi thành thứ khác, ngay cả khi "màu nâu" đứng đầu trong danh sách, và sau đó nó chuyển thẳng sang "foz". Tôi chưa bao giờ vượt qua điều đó. Ngoài ra tôi không thích phần phụ z=, nhưng có lẽ tôi có thể tự tìm cách khắc phục điều đó nếu phần còn lại hoạt động. Điều này đang trở nên rất gần với những gì tôi muốn, mặc dù. Tôi sẽ tiếp tục cố gắng sửa nó. Cảm ơn!
dbmrq

Xem cập nhật của tôi, tôi thêm một gia tăng quá sớm :) Vâng tôi cũng không hài lòng với điều z=đó. Nhưng với phương pháp này, bạn cần giữ một tài liệu tham khảo về nơi bạn ở. Nhưng nếu bạn không cần phải giữ tất cả các tài liệu tham khảo cùng một lúc tôi có thể đơn giản hóa điều đó :)
nobe4

Tôi không chắc ý của bạn là gì khi "giữ tất cả các tài liệu tham khảo cùng một lúc" nhưng chúng ta không thể đặt lại từ điển bất cứ khi nào con trỏ di chuyển? Hàm sẽ kiểm tra xem con trỏ có ở cùng vị trí với lần cuối cùng được gọi không và liệu nó có được đặt lại không.
dbmrq

Ngoài ra, cách nó dường như không hoạt động chính xác khi con trỏ không ở đầu từ. Cố gắng sửa từng lỗi trong câu đó đặt con trỏ ở giữa mỗi từ. Tôi bỏ qua tiếp theo ngay lập tức.
dbmrq

1
Ok, tôi nghĩ rằng tôi đã nhận nó! Kiểm tra chỉnh sửa cuối cùng của tôi. Điều này dường như làm việc khá nhiều hoàn hảo. Tôi sẽ để câu hỏi mở lâu hơn một chút để xem có ai khác muốn thêm không, nhưng câu trả lời của bạn rất hay, cảm ơn bạn. :)
dbmrq

2

Ngoài các câu trả lời khác, thực sự có một cách được xây dựng ngay trong Vim : <C-x>s. Điều này sẽ sử dụng menu hoàn thành chế độ chèn của Vim.

Nhấn <C-x>stừ chế độ chèn sẽ sửa từ dưới con trỏ thành gợi ý đầu tiên và hiển thị menu hoàn thành với các đề xuất khác (nếu có). Bạn có thể sử dụng 'completeopt'cài đặt để tùy chỉnh một số cài đặt cho menu hoàn thành.

Có một chút khó chịu khi điều này chỉ hoạt động từ chế độ chèn và việc sử dụng <C-x><C-s>có thể có vấn đề (xem ghi chú bên dưới), vì vậy bạn có thể xác định ánh xạ của riêng mình cho việc này:

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

<C-@> là Kiểm soát + Không gian.

Cũng thấy :help ins-completion :help i_CTRL-X_s


Cá nhân tôi sử dụng một phiên bản nâng cao hơn sẽ "đoán" nếu chúng tôi muốn kiểm tra chính tả công việc hoặc sử dụng tự động hoàn thành thường xuyên cho mã:

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()

Tôi tin rằng cũng có một số plugin thực hiện những thứ gần giống nhau (như SuperTab, khá phổ biến), nhưng tôi không bao giờ có thể khiến chúng hoạt động như tôi muốn.


Hãy cẩn thận : Nếu bạn đang sử dụng Vim từ một thiết bị đầu cuối, thì <C-s>sẽ có nghĩa là "dừng đầu ra". Đây là lý do tại sao cả hai <C-x><C-s> <C-x>s được ánh xạ theo mặc định. Sử dụng <C-q>để tiếp tục đầu ra nếu bạn <C-s>vô tình nhấn . Bạn cũng có thể vô hiệu hóa <C-s>nếu bạn không sử dụng nó (xem câu hỏi này ). Nếu bạn đang sử dụng GVim, bạn có thể bỏ qua điều này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.