Perintah untuk mengulang melalui saran ejaan


12

Saya memetakan zzke 1z=, yang sebagian besar hebat, tetapi setiap sekarang dan kemudian saran pertama bukan yang benar.

Jadi saya ingin terus mengulangi zz(atau .) mengulangi saran lainnya.

Sedetik zzpada kata yang sama, maka, akan berfungsi seperti u2z=, sepertiga zzakan bekerja seperti u3z=dan seterusnya.

Ada ide tentang bagaimana melakukan itu?


Edit:

Berdasarkan jawaban luar biasa @ nobe4, saya berhasil melakukan apa yang saya inginkan, tetapi saya akan meninggalkannya di sini untuk sementara waktu jika ada yang memiliki perbaikan atau saran:

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>

(Saya mengubah pemetaan menjadi <c-m>karena komentar @ Vitor. Juga ini memungkinkan saya untuk menahan kunci-kunci itu dan menyortir saran-saran dengan sangat cepat. Saya memikirkannya sebagai <c-mistake>.)


2
Saya sarankan Anda untuk memeriksa plugin ini yang dibuat oleh pengguna situs ini. Ini benar-benar meningkatkan alur kerja pemeriksaan ejaan: untuk mulai mengoreksi Anda menggunakan :Correctperintah: Anda akan dapat menavigasi melalui kata-kata untuk memperbaikinya ndan N, sebuah jendela terbelah terbuka dengan semua saran koreksi yang Anda dapat dengan mudah menavigasi mereka dengan jdan kdan <CR>akan terapkan koreksi.
statox

@statox Terima kasih atas sarannya. Saya akan memeriksanya, tetapi saya masih ingin zzperintah saya untuk memperbaiki hal-hal tertentu dengan cepat.
dbmrq

3
Harap Anda tahu bahwa awalnya zzmemusatkan jendela di sekitar garis saat ini. Mungkin salah satu cara pintas yang saya gunakan lebih sering. Anda juga harus checkout zbdan zt.
Vitor

@Vitor Menarik, saya tidak tahu itu! Saya biasanya menjaga scrolloffcukup tinggi, tapi itu masih berguna, saya akan mempertimbangkan pemetaan lain. Terima kasih!
dbmrq

Skrip vim ini melakukan penyelesaian kata / koreksi ejaan / sinonim (menggunakan aspell, tesaurus, kamus) stackoverflow.com/a/46645434/476175
mosh

Jawaban:


6

Inilah yang saya pikirkan:

Putar Ejaan

memutar mantra

fitur

  • Tanda '[dan ']digunakan untuk melacak teks yang sedang dikerjakan. Membuat perubahan di tempat lain secara efektif akan "menerima" perubahan yang disarankan.
  • Menerima hitungan.
  • Mundur menggunakan zp
  • Diulang menggunakan vim-repeat .
  • Batalkan sekali untuk mengembalikan kata aslinya terlepas dari berapa banyak saran yang telah didaur ulang.
  • Berfungsi dalam mode visual untuk mendapatkan saran untuk kata-kata split (mis. "Headline" -> "headline")
    • Penggunaan '<dan '>tanda untuk melacak teks.
    • Catatan : Tampaknya tidak dapat diulang dengan vim-repeat .
  • Kata asli yang diubah disimpan dalam register yang tidak disebutkan namanya.
  • Saran asli, sebelumnya, saat ini, dan berikutnya ditampilkan di baris perintah.
  • Perintah naif :SpellRotateSubAlluntuk mengganti semua teks yang cocok dengan yang asli dengan saran saat ini.

Plugin: 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
Wow, sekarang kita bicara! Anda harus mengubah ini menjadi plugin mandiri sehingga kami dapat menyimpan perubahan dan peningkatan di masa mendatang semua di tempat yang sama. Atau saya dapat mencoba melakukannya jika Anda tidak tertarik.
dbmrq

@danielbmarques Cukup mudah, ini dia: github.com/tweekmonster/spellrotate.vim
Tommy A

Fantastis, terima kasih! Saya akan menerima jawaban Anda sebagai jawaban yang tepat karena itulah yang saya inginkan dan banyak lagi, dan saya akan memberikan hadiah kepada @ nobe4 untuk semua usaha dan bantuannya.
dbmrq

@danielbmarques Tidak masalah. Saya ada di dalamnya untuk pertanyaan dan solusi menarik 😄
Tommy A

5

Seperti yang disarankan @statox, Anda dapat menggunakan plugin yang saya tulis: vimcorrect .

Saya pada dasarnya akan menjelaskan cara kerjanya, jadi jika Anda ingin menggunakan kembali sebagian dari itu, Anda bisa.

Untuk fokus pada kata yang salah eja berikutnya saya gunakan langsung ]sdan [sketika mereka melompat ke pertandingan berikutnya / sebelumnya. Saya menetapkan fungsi kecocokan khusus untuk menyorot kata saat ini:

masukkan deskripsi gambar di sini

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

Yang menambahkan ke grup yang cocok errorkata saat ini di baris / kolom saat ini (untuk mencegah beberapa pencocokan pada baris yang sama).


The spellbadword()fungsi mengembalikan daftar kemungkinan koreksi untuk kata di bawah kursor.

Saya cukup menampilkan daftar ini dalam buffer, dan saya memetakan <CR>untuk mengganti kata yang salah eja dengan baris saat ini (yaitu kata yang mungkin diperbaiki).


Saya juga memetakan ndan Nke ]sdan [s, karena saya terbiasa menekan mereka untuk mencari.

q dipetakan untuk keluar dari plugin, tutup pemisahan dan hapus sorotan.

Catatan : ini masih sangat tidak stabil, tetapi saya berencana untuk membuat beberapa perubahan segera. Jika Anda merasa ingin / ingin meningkatkan plugin ini, silakan garpu / buka permintaan tarik.


Terima kasih untuk penjelasannya. Plugin Anda terlihat hebat, saya pasti akan menggunakannya. Saya masih menginginkan zzperintah saya , jadi saya dapat memperbaiki berbagai hal dengan cepat tanpa memasuki mode khusus. Mungkin kita bisa menambahkannya vimcorrectjika saya pernah mengetahuinya. :)
dbmrq

Yah, saya pasti perlu menambahkan lebih banyak penyesuaian. Jadi mendefinisikan pemetaan khusus mungkin merupakan peningkatan yang dapat Anda tambahkan jika Anda mau :) (jika Anda mulai mengembangkan dalam vimscript, ini mungkin cara yang baik untuk belajar)
nobe4

2

Berikut adalah fungsi yang harusnya berfungsi:

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>

Ide dasarnya adalah memetakan setiap kata yang diubah ke pasangan baris / kolom (sehingga tidak akan berfungsi hanya untuk satu elemen) dan memeriksa apakah elemen tersebut sudah dimodifikasi.

Untuk melakukan penggantian, cukup banyak yang dilakukan plugin saya:

  • ambil kata yang salah eja saat ini
  • periksa apakah ada koreksi
  • ganti kata dengan saran yang diperbaiki

Saat menggunakan ini, jika Anda ingin kembali ke kata yang salah eja, Anda cukup menekan u.

The LoopConfirmFungsi ulang kamus, jadi jika Anda mengubah teks Anda, Anda dapat menyebutnya untuk mencegah tabrakan.

Beri tahu saya jika Anda mengalami masalah apa pun / jika ada pertanyaan.


Uuh, itu terlihat bagus. Namun masih memiliki banyak masalah. Ambillah ungkapan seperti "teh qick borwn foz jums ofer teh lazi dor" dan cobalah untuk memperbaiki setiap kata seperti itu. Saya tidak pernah bisa mendapatkan "the" to "the", meskipun ini nomor 4 dalam daftar. "qick" berfungsi, tetapi "borwn" berubah menjadi sesuatu yang lain, bahkan jika "coklat" adalah yang pertama dalam daftar, dan kemudian melompat langsung ke "foz". Saya tidak pernah bisa melewati itu. Saya juga tidak suka bagian ekstra z=, tetapi saya mungkin bisa menemukan cara untuk menyiasatinya sendiri jika yang lain berhasil. Ini semakin dekat dengan apa yang saya inginkan. Saya akan terus berusaha memperbaikinya. Terima kasih!
dbmrq

Lihat pembaruan saya, saya menambahkan kenaikan terlalu cepat :) Ya saya tidak senang dengan z=baik. Tetapi dengan metode ini Anda perlu menyimpan referensi di mana Anda berada. Tetapi jika Anda tidak perlu menyimpan semua referensi secara bersamaan, saya dapat menyederhanakannya :)
nobe4

Saya tidak yakin apa yang Anda maksud dengan "simpan semua referensi pada saat yang bersamaan" ... tetapi tidak bisakah kita mengatur ulang kamus setiap kali kursor bergerak? Fungsi ini akan memeriksa apakah kursor berada di tempat yang sama dengan yang terakhir kali dipanggil, dan jika tidak disetel ulang.
dbmrq

Selain itu, tampaknya tidak berfungsi dengan baik ketika kursor tidak di awal kata. Cobalah untuk memperbaiki setiap kesalahan dalam kalimat yang menempatkan kursor di tengah setiap kata. Saya melompat ke yang berikutnya segera.
dbmrq

1
Ok, saya rasa saya mengerti! Periksa hasil edit terakhir saya. Ini tampaknya bekerja dengan sangat sempurna. Saya akan membiarkan pertanyaan terbuka sedikit lebih lama untuk melihat apakah ada orang lain yang ingin ditambahkan, tetapi jawaban Anda bagus, terima kasih. :)
dbmrq

2

Selain jawaban yang lain, sebenarnya ada cara yang dibangun tepat di untuk Vim: <C-x>s. Ini akan menggunakan menu penyelesaian mode penyisipan Vim.

Menekan <C-x>sdari mode penyisipan harus memperbaiki kata di bawah kursor ke saran pertama dan menampilkan menu penyelesaian dengan saran lebih lanjut (jika ada). Anda dapat menggunakan 'completeopt'pengaturan untuk menyesuaikan beberapa pengaturan untuk menu penyelesaian.

Agak menyebalkan bahwa ini hanya bekerja dari mode insert dan menggunakan menggunakan <C-x><C-s>bisa bermasalah (lihat catatan di bawah), sehingga Anda dapat menentukan pemetaan Anda sendiri untuk ini:

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

<C-@> adalah Kontrol + Spasi.

Lihat juga :help ins-completion :help i_CTRL-X_s


Saya pribadi menggunakan versi yang lebih canggih yang akan "menebak" jika kita ingin mengeja periksa pekerjaan, atau menggunakan pelengkapan otomatis biasa untuk kode:

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

Saya percaya ada juga beberapa plugin yang melakukan hal-hal serupa (seperti SuperTab, yang cukup populer), tetapi saya tidak pernah bisa membuat mereka berperilaku seperti yang saya inginkan.


Peringatan : Jika Anda menggunakan Vim dari terminal, maka <C-s>akan berarti "hentikan output". Inilah sebabnya mengapa keduanya <C-x><C-s> dan <C-x>s dipetakan secara default. Gunakan <C-q>untuk melanjutkan keluaran jika Anda menekan <C-s>secara tidak sengaja. Anda juga dapat menonaktifkan <C-s>jika Anda tidak menggunakannya (lihat pertanyaan ini ). Jika Anda menggunakan GVim, Anda dapat mengabaikannya.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.