Команда провести цикл через написання пропозицій


12

Я зіставляються zzз 1z=, який є великим більшу частину часу, але кожен зараз і тоді перше речення не є правильним.

Тому я хотів би постійно повторювати 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відкриється розділене вікно з усіма пропозиціями щодо виправлення, ви можете просто переміщатися по них за допомогою jта kі <CR>буде застосувати виправлення.
statox

@statox Дякую за пропозицію. Я перевірю це, але все одно хочу, щоб моя zzкоманда швидко виправляла конкретні речі.
dbmrq

3
Сподіваємось, вам відомо, що спочатку zzцентрується вікно навколо поточної лінії. Це, мабуть, один із ярликів, якими я частіше користуюся. Ви також повинні замовити zbі zt.
Вітор

@Vitor Цікаво, я цього не знав! Зазвичай я тримаюсь scrolloffдосить високо, але це все ще здається корисним, я буду розглядати інше відображення. Дякую!
dbmrq

Цей скрипт vim виконує доповнення слів / виправлення орфографії / синоніми (використовуючи aspell, тезаурус, словник) stackoverflow.com/a/46645434/476175
mosh

Відповіді:


6

Ось що я придумав:

Заклинання Поворот

заклинання обертати

Особливості

  • '[І ']мітки використовуються для відстеження тексту , в якому працював над. Внесення змін в іншому місці фактично "сприйме" запропоновану зміну.
  • Приймає кількість.
  • Переходить назад за допомогою zp
  • Повторюється за допомогою vim-repe .
  • Скасуйте один раз, щоб відновити початкове слово незалежно від кількості пропозицій, які були прокручені.
  • Працює у візуальному режимі, щоб отримати пропозиції щодо розділених слів (наприклад, "заголовок" -> "заголовок")
    • Використання '<та '>позначки для відстеження тексту.
    • Примітка . Схоже, це не повторюється при повторенні vim .
  • Оригінальне слово, що змінюється, зберігається в реєстрі неназваних.
  • Оригінальні, попередні, поточні та наступні пропозиції відображаються у командному рядку.
  • Наївна команда :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 Немає проблем. Мені цікаві питання та рішення Tom
Tommy A

5

Як запропонував @statox, ви можете використовувати плагін, про який я писав: vimcorrect .

Я поясню в основному, як це працює, тож якщо ви хочете повторно використовувати якусь його частину, можете.

Щоб зосередитись на наступному неправильному написаному слові, я використовую безпосередньо, ]sі [sколи вони переходять до наступного / попереднього матчу. Я визначив функцію власної відповідності для виділення поточного слова:

введіть тут опис зображення

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

Які додають до групи errorвідповідності поточне слово в поточному рядку / стовпці (щоб запобігти кратному збігу в одному рядку).


spellbadword()Функція повертає список можливої корекції для слова під курсором.

Я просто відображаю цей список у буфері, і картографую, <CR>щоб замінити неправильно написане слово поточним рядком (тобто можливим виправленим словом).


Я також карта nі Nдо, ]sі [s, як я звик натискати на них для пошуку.

q відображається, щоб вийти з плагіна, закрити спліт і видалити виділення.

Примітка : це все ще дуже нестабільно, але я планую внести деякі зміни незабаром. Якщо ви відчуваєте, що можете / хочете вдосконалити цей плагін, не соромтеся розкрутити / відкрити запит на витягування.


Дякую за пояснення. Ваш плагін виглядає чудово, я обов'язково ним користуюся. Я все ж хочу свою zzкоманду, тому я можу швидко виправляти речі, не входячи в спеціальний режим. Можливо, ми можемо додати це, vimcorrectякщо я коли-небудь зрозумію це. :)
dbmrq

Ну, мені точно потрібно додати більше налаштування. Отже, визначення власного відображення може бути покращенням, яке ви можете додати, якщо хочете :) (якщо ви почнете розробляти vimscript, це може бути хорошим способом вчитися)
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Функція скидання словника, так що якщо ви зміните текст, ви можете викликати його для запобігання зіткнень.

Повідомте мене, якщо ви зіткнулися з будь-якою проблемою / якщо у вас є питання.


Ву, це добре виглядає. Однак все ще є багато проблем. Візьміть фразу типу "teh qick Borwn foz jums ofer lazi dor" і спробуйте виправити кожне слово таким чином. Я ніколи не можу потрапити "teh" на "the", хоча це номер 4 у списку. "qick" працює, але "borwn" змінюється на щось інше, навіть якщо спочатку "список коричневих" є у списку, а потім він переходить прямо до "foz". Я ніколи цього не проходив. Крім того, мені не подобається зайва z=частина, але, мабуть, я міг би знайти спосіб, щоб сам це обійти, якби решта працювала. Це все-таки дуже близько до того, що я хочу. Я буду намагатися це виправити. Дякую!
dbmrq

Дивіться моє оновлення, я додаю приріст занадто рано :) Так, я теж не задоволений z=. Але за допомогою цього методу потрібно зберігати посилання на те, де ви знаходитесь. Але якщо вам не потрібно зберігати всі посилання одночасно, я можу спростити це :)
nobe4

Я не впевнений, що ви маєте на увазі під "зберігати всі посилання одночасно" ... але чи не могли ми просто скинути словник, коли курсор рухається? Функція перевірить, чи знаходиться курсор у тому самому місці, коли він був викликаний минулого разу, і якщо це не він, він скидається.
dbmrq

Крім того, схоже, це не працює належним чином, коли курсор не знаходиться на початку слова. Спробуйте виправити кожну помилку в цьому реченні, розміщуючи курсор посередині кожного слова. Я переходжу до наступної відразу.
dbmrq

1
Гаразд, я думаю, я це отримав! Перевірте останню редакцію. Здається, це працює дуже досконало. Залишаю питання ще трохи відкритим, щоб побачити, чи ще хтось ще може додати, але ваша відповідь була чудовою, дякую. :)
dbmrq

2

Крім інших відповідей, є насправді шлях побудований прямо в Vim: <C-x>s. Для цього буде використано меню завершення режиму вставки Vim.

Якщо натиснути <C-x>sз режиму вставки, слід виправити слово під курсором до першої пропозиції та показати меню завершення з подальшими пропозиціями (якщо такі є). Ви можете використовувати це 'completeopt'налаштування, щоб налаштувати деякі налаштування меню завершення.

Це трохи прикро, що це працює лише з режиму вставки, а використання за допомогою <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, який є досить популярним), але я ніколи не міг змусити їх поводитись так, як я хочу.


Caveat : Якщо ви використовуєте Vim з терміналу, <C-s>це означатиме "зупинити вихід". Ось чому обидва <C-x><C-s> і <C-x>s відображаються за замовчуванням. Використовуйте <C-q>для продовження виводу, якщо <C-s>випадково натискаєте . Ви також можете відключити його, <C-s>якщо ви не користуєтесь ним (див. Це питання ). Якщо ви використовуєте GVim, ви можете проігнорувати це.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.