zz
映射到1z=
,这在大多数情况下是很好的,但是时不时地,第一个建议不是正确的建议。所以我想继续重复
zz
(或.
)循环浏览其他建议。同一个单词上的第二个
zz
就像u2z=
一样工作,第三个zz
就像u3z=
一样工作,依此类推。任何有关如何执行此操作的想法?如果有人有任何改进或建议,请花一会儿:
向下滚动并快速浏览建议。我认为它是
<c-m>
。)#1 楼
这是我想到的:咒语旋转
功能
'[
标记用于跟踪正在处理的文本。在其他地方进行更改将有效地“接受”建议的更改。接受计数。
使用
']
向后退使用vim-repeat可重复。
撤消一次以无论循环了多少建议,都可以恢复原始单词。 >使用
zp
和'<
标记来跟踪文本。注意:vim-repeat似乎不可重复。被更改的内容将保留在未命名的寄存器中。
原始,上一个,当前和下一个建议显示在命令行中。
天真命令
'>
会将所有与原始文本匹配的文本替换为当前建议。 br /> 插件: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)
评论
哇,现在我们在说话!您应该将其变成一个独立的插件,以便我们将来可以将所有更改和改进都放在同一位置。如果您不感兴趣,也可以尝试。
–dbmrq
16年7月13日在3:44
@danielbmarques足够简单,到这里开始:github.com/tweekmonster/spellrotate.vim
–汤米A
16年7月13日在4:41
太好了,谢谢!我会接受您的答案是正确的答案,因为这正是我想要的,还有更多,我将感谢@ nobe4的所有努力和帮助。
–dbmrq
16年7月13日在5:12
@danielbmarques没问题。我正在寻找有趣的问题和解决方案😄
–汤米A
16年7月13日在5:16
#2 楼
正如@statox所建议的那样,您可以使用我编写的插件:vimcorrect。为了专注于下一个拼写错误的单词,我直接使用
]s
和[s
跳转到下一个/上一个匹配项。我定义了一个自定义匹配函数来突出显示当前单词:当前行/列(以防止同一行上出现多个匹配项)。
error
函数返回光标下方单词的可能校正列表。我只在缓冲区中显示此列表,然后将
spellbadword()
映射为用当前行替换拼写错误的单词(即可能的已纠正单词)。 <CR>
和n
,就像我常按它们进行搜索一样。高度不稳定,但我打算尽快进行一些更改。如果您觉得可以/想要改进此插件,请随意分叉/打开请求请求。评论
感谢您的解释。您的插件看起来很棒,我一定会使用它。不过,我仍然需要我的zz命令,因此我可以快速修复问题,而无需进入特殊模式。如果我知道的话,也许可以将其添加到vimcorrect中。 :)
–dbmrq
16年7月9日在17:46
好吧,我绝对需要添加更多的自定义。因此,定义自定义映射可能是一种改进,您可以根据需要添加:)(如果您开始使用vimscript进行开发,则可能是学习的一种好方法)
– nobe4
16年7月9日在17:49
#3 楼
除了其他答案,实际上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),但我永远无法让它们表现出我想要的样子。
注意:如果从终端使用Vim,则
<C-s>
表示“停止输出”。这就是为什么默认情况下同时映射<C-x><C-s>
和<C-x>s
的原因。如果意外按下<C-q>
,请使用<C-s>
继续输出。如果您不使用<C-s>
,也可以将其禁用(请参阅此问题)。如果您使用的是GVim,则可以忽略它。#4 楼
这是一个应该起作用的函数: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
即可。 br /> LoopConfirm
函数会重置字典,因此,如果您更改文本,可以调用它以防止发生冲突。 />评论
嗯,看起来不错。但是,它仍然存在许多问题。采取“像这样的短语”这样的短语,并尝试以这种方式纠正每个单词。我永远都不会把“ the”变成“ the”,尽管它在清单上是第4位。 “快速”有效,但是“无聊”更改为其他内容,即使“棕色”首先在列表中,然后直接跳至“ foz”。我从来没有过去。同样,我不喜欢多余的z =部分,但如果其余部分可行的话,我可能可以找到一种解决该问题的方法。不过,这已经非常接近我想要的了。我会继续尝试修复它。谢谢!
–dbmrq
16年7月12日在17:36
看到我的更新,我太快增加了一个增量:)是的,我对z =也不满意。但是,使用这种方法,您需要保留自己所在位置的参考。但是,如果您不需要同时保留所有引用,那么我可以简化一下:)
– nobe4
16年7月12日在17:46
我不确定“同时保留所有引用”是什么意思……但是,只要光标移动,我们是否不能仅重置字典?该函数将检查游标是否与上次调用时位于同一位置,如果不是,则将其重置。
–dbmrq
16年7月12日在18:00
同样,当光标不在单词开头时,它似乎无法正常工作。尝试纠正该句子中的每个错误,将光标置于每个单词的中间。我马上跳到下一个。
–dbmrq
16年7月12日在18:07
好吧,我想我明白了!检查我的上一次编辑。这似乎非常完美。我将问题悬而未决,看看是否还有其他人要添加,但是您的回答很好,谢谢。 :)
–dbmrq
16年7月12日在20:02
评论
我建议您检查由该站点的用户制作的此插件。它确实改善了拼写检查的工作流程:使用:Correct命令开始更正:您将能够通过n和N来浏览要更正的单词,将打开一个拆分窗口,其中包含所有更正建议,您可以在其中轻松浏览j和k与@statox感谢您的建议。我会检查出来,但我仍然希望我的zz命令能够快速修复特定问题。
希望您知道最初zz将窗口围绕当前行居中。这可能是我经常使用的快捷方式之一。您还应该结帐zb和zt。
@Vitor有趣,我不知道!我通常将滚动率保持在很高的水平,但这仍然很有用,我将考虑其他映射。谢谢!
此vim脚本执行单词补全/拼写校正/同义词(使用aspell,词库,词典)stackoverflow.com/a/46645434/476175