在vim中循环遍历字符

3
我想创建一个vim宏,以执行以下操作:
如果我输入字符"a"、"e"、"o"、"i"或"u"并按下快捷键(例如F12),每次单击快捷键时,它都必须循环显示字符。
例如:
a -> F12 -> à -> F12 -> â -> F12 -> ä -> F12 -> ä -> F12 -> 再次回到"a" A -> F12 -> À -> F12 -> Â -> F12 -> Ä -> F12 -> Ä -> F12 -> 再次回到"A"
其他字符也一样: e --> eéèêëée E --> EÉÊÈËÉE i --> iîïi I --> IÎÏI o --> oôöo O --> OÔÖO u --> uûùüüu U --> UÛÙÜU
有人能帮我吗?

我认为没有简单的方法可以实现这个。你可以在命令模式下使用CTRL-a来增加字符代码,但那不是你想要的。 - hochl
你可能可以改编 unicycle.vim 来处理这些,尽管我曾经发誓已经有另一个专门用于此的插件了。但现在我找不到它了。 - Randy Morris
2个回答

4

下面是一个能够实现你想要的功能的函数。它通过获取光标下的 Unicode 字符,查看它是否存在于字符列表中,并且如果存在,则将其推进到该列表中的下一个字符。我通过复制字符、从寄存器中提取字符以及在函数结束时恢复寄存器的原始内容来以一种不太优雅的方式获取光标下的字符。肯定有更优雅的方法!

function! CycleThroughChars()
    let x_contents = getreg("x")
    let x_type = getregtype("x")
    let lists = [ ["a","à","â","ä","a"],
                \ ["A","À","Â","Ä","A"],
                \ ["e","é","è","ê","ë","e"],
                \ ["E","É","Ê","È","Ë","E"],
                \ ["i","î","ï","i"],
                \ ["I","Î","Ï","I"],
                \ ["o","ô","ö","o"],
                \ ["O","Ô","Ö","O"],
                \ ["u","û","ù","ü","u"],
                \ ["U","Û","Ù","Ü","U"] ]
    sil exe 'normal! "xyl'
    let c_char = @x
    for this_list in lists
        let c_index = index(this_list,c_char)
        if c_index != -1
            sil exe "normal! r" . this_list[c_index+1]
            break
        endif
    endfor
    call setreg("x",x_contents,x_type)
    startinsert
endfunction
inoremap <silent> <F12> <ESC>:call CycleThroughChars()<CR><right>

希望这能帮到您。
编辑:我意识到第二个for循环是多余的,所以我已经从函数中删除了它。功能未受影响,但每个列表只需要一个index()调用。

我花了太长时间来尝试回答这个问题,而我的答案最终比这个要糟糕得多。做完后,你做得非常好(未经测试 ;))。 - Randy Morris
1
应该使用 getreg()getregtype()setreg() 来修改 let @xold_paste_contents,这样就不会丢失寄存器类型(矩形、行或字符)。 - Benoit
谢谢Benoit,我已经做出了这些改变。有用的建议。 - Prince Goulash
@PrinceGoulash,我注意到你的函数在utf8编码下无法工作。你知道需要改变什么才能让它正常工作吗?这是一个多字节的问题,对吧? - Reman

0

编辑:我已经成功用matchstr()函数替换了补充函数。现在代码看起来更加简洁。

为了完整起见,这是我想出来的代码。

let g:unicode_list = [
\    [ 'a', 'à', 'â', 'ä' ],
\    [ 'A', 'À', 'Â', 'Ä' ],
\    [ 'e', 'é', 'è', 'ê', 'ë' ],
\    [ 'E', 'É', 'Ê', 'È', 'Ë' ],
\    [ 'i', 'î' ], 
\    [ 'I', 'Î', 'Ï' ],
\    [ 'o', 'ô', 'ö' ],
\    [ 'O', 'Ô', 'Ö' ],
\    [ 'u', 'û', 'ù', 'ü' ],
\    [ 'U', 'Û', 'Ù', 'Ü' ],
\]

function! CycleUnicode(mode)
    let char = matchstr(getline('.'), '.', col('.')-1)
    for sublist in g:unicode_list
        let idx = index(sublist, char)
        if idx >= 0
            try
                let char = sublist[idx+1]
            catch /E684/
                let char = sublist[0]
            endtry
            execute "normal! r" . char
            break 
        endif
    endfor
    if a:mode == 'i'
        startinsert
    endif
endfunction

inoremap <f12> <esc>:call CycleUnicode('i')<enter><right>
nnoremap <f12> :call CycleUnicode('n')<enter>

1
我们的想法是一致的!最困难的部分是提取光标下的Unicode字符...看起来很奇怪,Vim没有本地化的方法来做到这一点。 - Prince Goulash
@PrinceGoulash,你可能会对我刚刚做的修改感兴趣。我认为我找到了一种比之前更清晰地获取字符的方法。无论如何,这是未来的好参考资料。 - Randy Morris
@RandyMorris,如果编码是utf-8,你的函数对于Unicode字符也无法正常工作。 - Reman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接