将 Vim 作为主力编辑器也有大半年了。 得益于非中文的使用环境,期间并没有遇到太多的问题。 最近开始写博客后自然希望能在 Vim 里输入中文。 然而 Vim 以及命令行环境中显然对中文输入并不是非常友好。 这次粗略地记录几则问题与自己的解决方案。

Vim 的中文输入

Vim 中的输入法切换

在插入模式中输入完中文后需要手动切换会英文输入法进行排版或者移动操作。 非常的繁琐,极大了影响了 Vim 中行云流水般的文字编辑体验。 在一番搜索中发现有 VimIM 尝试解决这个问题,但是已经很久没有更新。 可能不是一个理想的解决方案。 而在另一处论坛中发现对于 fcitx 输入引擎有如下教程

第 10 章 通过命令控制 Fcitx

fcitx 提供了一个基于 socket 的工具,fcitx-remote 可以用于控制 fcitx

具体命令参数参见 fcitx-remote -h 和 man

一个实用的例子是用它自动控制 vim 的输入状态

let g:input_toggle = 1
function! Fcitx2en()
   let s:input_status = system("fcitx-remote")
   if s:input_status == 2
      let g:input_toggle = 1
      let l:a = system("fcitx-remote -c")
   endif
endfunction

function! Fcitx2zh()
   let s:input_status = system("fcitx-remote")
   if s:input_status != 2 && g:input_toggle == 1
      let l:a = system("fcitx-remote -o")
      let g:input_toggle = 0
   endif
endfunction

set timeoutlen=150
autocmd InsertLeave * call Fcitx2en()
" autocmd InsertEnter * call Fcitx2zh()

将上面的代码加入 ~/.vimrc 中,可以实现退出插入模式时自动关闭输入法。去掉最后一行的注释可以实现进入插入模式自动启用输入法。

从原理上看并不复杂。在离开插入模式是切换会英文输入;进入插入模式时切换为中文输入即可。 只是上述方案有一个问题,若是上次离开插入模式时为英文输入,再次进入时仍会切换为中文输入法。

恰好我使用的 ibus 也有类似的通过命令行切换输入法的功能:

# 返回当前输入法:
$ ibus engine
# 显示可选输入法:
$ ibus list-engine
# 切换为指定输入法:
$ ibus engine 

于是可以通过如下配置解决输入法的问题:

" vim input method controller
let g:input_toggle = 1
let g:input_default = "xkb:us::eng"
let g:input_last = ""
function! Ibus2default()
    if g:input_toggle == 1
        let l:status = system("ibus engine")
        if g:input_default != l:status
            let g:input_last = l:status
            let l:a = system("ibus engine " . g:input_default )
        endif
    endif
endfunction

function! Ibus2last()
    if g:input_toggle == 1 && g:input_last != ""
        let l:a = system("ibus engine " . g:input_last )
    endif
endfunction

autocmd InsertLeave * call Ibus2default()
autocmd InsertEnter * call Ibus2last()
  • input_toggle 变量控制是否开启此功能。
  • input_default 填写默认的输入法,即 Vim 普通模式中的输入法,通常为英文输入。
  • input_last 用于保存上次退出普通模式时的输入法状态。

Vim 配置文件的写法可以参考 Vim scripting cheatsheet 这篇文章。




XKB 键位设置

由于个人习惯,我把 CapsLock 映射为 Control 并交换了 左侧 Alt 和 Win 的位置。 之前一直使用了 xmodmap 来实现。

配置如下:

clear lock
clear control
keycode 66 = Control_L
add control = Control_L Control_R

remove mod1 = Alt_L
remove mod4 = Super_L
keysym Alt_L = Super_L
keysym Super_L = Alt_L
add mod1 = Alt_L
add mod4 = Super_L

如此设置的弊端是:如果你同时有多种键盘的布局需要使用,则必须在 ibus-setup 中的 Advanced 下勾选 “Use system keyboard layout” 选项。 否则在使用上述 ibus enigne 命令切换输入引擎后 xmodmap 的设置会被覆写。

例如:

默认为英文输入模式下,使用 ibus engine rime 切换至中文输入法,CapsLock 键就不再是 Control 了。

解决方案为使用 XKB 中的 setxkbmap 命令。 对于像我这样的简单需求,XKB 中已经内置了选项。

# 将 CapsLock 替换为 Control
$ setxkbmap -option ctrl:nocaps
# 交换左侧 Win 与 Alt
$ setxkbmap -option altwin:swap_lalt_lwin

更特殊的需求以及详细的 XKB 教程可以参考 A simple, humble but comprehensive guide to XKB for linux 这篇文章。

总结

使用 Vim 进行中文的文本编辑总体来说时吃力不讨好的行为。 使用 VS Code 代替似乎是一个不错的想法。 但是 「无需离开命令行」的体验一旦习惯了便也让人有点难以放弃。 Vim 的使用一旦过了一个坎,也是快感大于痛苦。 就暂且如此吧。😇