用法
自定义映射
正确使用option/Alt键
option键在macOS下作为组合按键之一,对应于PC、Linux上的Alt键,但是功能不太一样。Mac上字母及一些标点符号与option组合会输出unicode字符。
原因在于按下按下option键发送的不是Escape Sequence。因此在vim,emacs等终端软件中,没法直接使用Alt键定义映射。
找到原因就好办,解决方法分为两步:
在终端中修改option/Alt键的行为
在vim,emacs等运行于终端下的软件中进行可能必要的设置
以终端程序kitty和alacritty为例,具体讨论解决方法中的第一步如何操作。
kitty
打开配置文件kitty.conf
找到选项macos_option_as_alt no,将no改为yes
alacrity
打开配置文件alacrity.yml
定位到key_bindings
添加需要的键位设置,例如 - { key: x, mods: Alt, chars: "\x1bx" }
以运行在终端下的vim为例,给出第二步中需要的具体操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
function ! Terminal_MetaMode ( mode )
set ttimeout
if $TMUX != ''
set ttimeoutlen = 30
elseif &ttimeoutlen > 80 || &ttimeoutlen <= 0
set ttimeoutlen = 80
endif
if has ( 'nvim' ) || has ( 'gui_running' ) || $TERM_PROGRAM =~ ? 'iTerm2'
return
endif
" 👆表示只有某些终端下的vim需要👇的设置
function ! s :metacode ( mode , key )
" 这个函数的作用是告诉vim,<M-x>的键盘序列码是多少
" 这样vim将按照ttimeoutlen的设置来检查是否超时
" 如果用 `noremap <ESC>x <M-x>` 然后 `noremap <M-x> ...`的方式,
" 则会使用timeoutlen来检查是否超时
" 一般timeoutlen设置的相对更大,如果用它更容易误操作,降低使用体验
if a :mode == 0
exec "set <M-" .a :key .">=\e" .a :key
else
"👇这条需要对终端进行更针对性的设置,写本节时只想到在alacrity中设置会容易些
exec "set <M-" .a :key .">=\e]{0}" .a :key ."~"
endif
endfunction
" 针对alacrity,还需设置几个功能键
if $TERM_PROGRAM =~ ? 'alacritty'
exec "set <F1>=\eOP"
exec "set <F2>=\eOQ"
exec "set <F3>=\eOR"
exec "set <F4>=\eOS"
endif
for i in range ( 10 )
call s :metacode ( a :mode , nr2char ( char2nr ( '0' ) + i ))
endfor
for i in range ( 26 )
call s :metacode ( a :mode , nr2char ( char2nr ( 'a' ) + i ))
call s :metacode ( a :mode , nr2char ( char2nr ( 'A' ) + i ))
endfor
if a :mode != 0
for c in [',' , '.' , '/' . ';' , '[' , ']' , '{' , '}' ]
call s :metacode ( a :mode , c )
endfor
for c in ['?' , ':' , '-' , '_' ]
call s :metacode ( a :mode , c )
endfor
else
for c in [',' , '.' , '/' , ';' , '{' , '}' ]
call s :metacode ( a :mode , c )
endfor
for c in ['?' , ':' , '-' , '_' ]
call s :metacode ( a :mode , c )
endfor
endif
endfunction
" 设置用户自定义命令
command ! - nargs = 0 - bang VimMetaInit call Terminal_MetaMode (< bang > 0 )
" buffer 读入后自动进行设置
augroup alt_key
autocmd !
autocmd BufReadPost * :VimMetaInit
augroup END
用户自定义事件
自定义了切换透明和背景的函数,并绑定了快捷键。同时主题栏使用的是lightline 。
我为dark和light两种背景选取不同的lightline主题,为了使背景切换之后,主题栏的切换也生效,这里使用用户自定义事件来解决问题。
当然这不是唯一的方法。
1
2
3
4
5
6
7
8
9
10
11
function ! ToggleBackground ()
" A lot of stuff is happening here.
" 定义一个自定义事件
doautocmd User ToggleBackgroundExit
endfunction
function ! ToggleTransparent ()
" A lot of stuff is happening here.
" 定义一个自定义事件
doautocmd User ToggleTransparentExit
endfunction
现在可以在切换背景和透明度执行完成后做任何想做的事:
1
autocmd User ToggleBackgroundExit call lightline #enable ()
插件
插件管理器(vim-plug)
vim-plug 是一款异步插件管理器。具有安装速度快,延迟加载等特性。
这里要讨论的是刚发现的一个特性,可以让插件按照依赖关系进行加载。
栗子🌰:我有三款用于markdown的插件,分别是
原本可以在每个插件后面,用{'for':'markdown'}使其仅在编辑.md文件时才加载。但我发现
这种方法对第二款插件无效。因此想到这里的办法。
vim-plug在调用函数plug#load()加载插件之后会以插件名定义一个用户自定义事件。可以利用这一事件触发对其有依赖的插件的调用。如下为具体的使用案例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
" 以文件类型作为加载的依据
Plug 'iamcco/markdown-preview.nvim' , {'for' : 'markdown' , 'do' : 'cd app & yarn install' }
" 下面的插件无法按照文件类型进行加载
" 故通过vim-plug 定义的用户自定义事件进行触发
Plug 'plasticboy/vim-markdown' , {'on' : []}
Plug 'jszakmeister/markdown2ctags' , {'on' : []}
augroup vimplug_load_for_markdown
autocmd !
autocmd User markdown - preview .nvim plug #load (
\ 'vim-markdown' ,
\ 'markdown2ctags' ,
\ )
\ | autocmd ! vimplug_load_for_markdown
augroup END
进一步,针对一个插件的所有配置可以做到这样:在插件被
可以这样实现
1
2
3
4
5
6
7
8
9
10
" 仍然以上面的插件为例
" 在载入 vim-markdown之后自动加载相关配置。所有配置在函数SetVimmarkdown()之中
function ! SetVimmarkdown ()
" all configurations for vim-markdown are at here
endfunction
augroup load_for_vimmarkdown
autocmd !
autocmd User vim - markdown call SetVimmarkdown () | autocmd ! load_for_vimmarkdown
augroup END
中文输入法
vim 的模式切换与中文输入法并不总能够和谐共处。
英文
中文
normal
🙂
🙁
insert
🙂
🙂
解决这个问题的方式大体上有两种,1、vim
提供中文输入法,那么这个问题就留给vim及其插件的开发者们去解决了;2、仍然使用外部中文输入法,如搜狗等,
那么关键在于以哪种方式自动切换输入法!
这里沿用第二种思路。尝试过如下几种方式:
通过 vim 内置函数模拟按键操作来切换输入法。没有成功,但不排除可行性。
调用外部程序进行输入法切换。成功,但是并不完美。
所以最终采取的方案是通过调用外部程序在进入和离开insert模式时只能切换输入法。实现方式具体看下面的vim配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
" 定义缓冲区变量,使得可以对每个缓冲区单独监控输入法状态
au BufEnter * let b :im = 0
" 为了尽量不影响体验,通过异步机制来进行处理
" 下面的函数用于在 job 进行过程中处理返回信息
fun ! IMHandler ( channel , msg )
if a :msg != ? 'com.apple.keylayout.ABC'
" 切换到英文输入法之前保存当前状态
let b :im = 1
call job_start ( ['issw' , 'com.apple.keylayout.ABC' ])
endif
endfun
fun ! Lang2en ()
let job = job_start ( ['issw' ], {"out_cb" : "IMHandler" })
endfun
" 这里中文输入法的切换用了自己写的脚本,虽然也可以用上面的 issw 命令。
fun ! Lang2zh ()
if b :im == 1
call job_start ( ['switchim' ])
endif
endfun
autocmd InsertEnter * call Lang2zh ()
autocmd BufEnter , InsertLeave * call Lang2en ()
因为不想用破解软件来修改按键映射及快捷键,导致仍有不足之处:
调用的外部程序切换输入法不够快,仍然有一定几率产生困扰。
insert 模式下,如果要用搜狗输入法,从英文切换回中文比较麻烦。