持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第24天,点击查看活动详情
上一节中我们讲了Neovim的安装和基本配置,这节我们来讲一些高效的快捷键配置
预备知识
Neovim中设置快捷键的方式
vim.api.nvim_set_keymap()设置全局快捷键vim.api.nvim_buf_set_keymap()设置Buffer快捷键
nvim_set_keymap
其用法如下
vim.api.nvim_set_keymap({mode}, {lhs}, {rhs}, {*opts})
mode是配置映射生效的模式n:NORMAL模式i:INSERT模式v:VISUAL模式...总之就是你希望按键映射生效的模式的首字母小写即可
lhs是Left-hand-side的缩写rhs是Right-hand-side的缩写
把按键映射看成一个等式,等式左边是映射前的按键,等式右边是映射后的按键
opts是一个对象,比如需要一个按键映射不要递归触发的时候,我们可以配置{noremap: true}
配置完后和vim中的按键映射配置是对应的
比如:
:call nvim_set_keymap('i', 'jk', '<Esc>', {'inoremap': v:true})
等价于在vim中
:inoremap jk <Esc>
按键的字符串注解 -- key-notation
当我们配置按键映射的时候,编写的配置是字符串的,如果是普通字符还好说,比如hjkl这些英文字母,直接编写即可
但是如果遇到特殊字符呢?比如我希望映射ESC键,回车键,空格键之类的
这就需要用到key-notation了,在命令模式下输入:
:help key-notation
即可查看到所有的按键对应的字符串注解
notation meaning equivalent decimal value(s) ~
-----------------------------------------------------------------------
<Nul> zero CTRL-@ 0 (stored as 10) *<Nul>*
<BS> backspace CTRL-H 8 *backspace*
<Tab> tab CTRL-I 9 *tab* *Tab*
*linefeed*
<NL> linefeed CTRL-J 10 (used for <Nul>)
<CR> carriage return CTRL-M 13 *carriage-return*
<Return> same as <CR> *<Return>*
<Enter> same as <CR> *<Enter>*
<Esc> escape CTRL-[ 27 *escape* *<Esc>*
<Space> space 32 *space*
<lt> less-than < 60 *<lt>*
<Bslash> backslash \ 92 *backslash* *<Bslash>*
<Bar> vertical bar | 124 *<Bar>*
<Del> delete 127
<CSI> command sequence intro ALT-Esc 155 *<CSI>*
<xCSI> CSI when typed in the GUI *<xCSI>*
<EOL> end-of-line (can be <CR>, <NL> or <CR><NL>,
depends on system and 'fileformat') *<EOL>*
<Up> cursor-up *cursor-up* *cursor_up*
<Down> cursor-down *cursor-down* *cursor_down*
<Left> cursor-left *cursor-left* *cursor_left*
<Right> cursor-right *cursor-right* *cursor_right*
<S-Up> shift-cursor-up
<S-Down> shift-cursor-down
<S-Left> shift-cursor-left
<S-Right> shift-cursor-right
<C-Left> control-cursor-left
<C-Right> control-cursor-right
<F1> - <F12> function keys 1 to 12 *function_key* *function-key*
<S-F1> - <S-F12> shift-function keys 1 to 12 *<S-F1>*
<Help> help key
<Undo> undo key
<Insert> insert key
<Home> home *home*
<End> end *end*
<PageUp> page-up *page_up* *page-up*
<PageDown> page-down *page_down* *page-down*
<kHome> keypad home (upper left) *keypad-home*
<kEnd> keypad end (lower left) *keypad-end*
<kPageUp> keypad page-up (upper right) *keypad-page-up*
<kPageDown> keypad page-down (lower right) *keypad-page-down*
<kPlus> keypad + *keypad-plus*
<kMinus> keypad - *keypad-minus*
<kMultiply> keypad * *keypad-multiply*
<kDivide> keypad / *keypad-divide*
<kEnter> keypad Enter *keypad-enter*
<kPoint> keypad Decimal point *keypad-point*
<k0> - <k9> keypad 0 to 9 *keypad-0* *keypad-9*
<S-...> shift-key *shift* *<S-*
<C-...> control-key *control* *ctrl* *<C-*
<M-...> alt-key or meta-key *meta* *alt* *<M-*
<A-...> same as <M-...> *<A-*
<D-...> command-key (Macintosh only) *<D-*
<t_xx> key with "xx" entry in termcap
-----------------------------------------------------------------------
键映射
<Leader>键作为我们个性化快捷键的前缀,可以选择将它映射到一个你认为舒服的按键上,比如我喜欢以空格键作为<Leader>键
然后如果我定义了一个<Leader> <Leader> w触发某个操作,那么就是需要按下空格 空格 w即可触发
从官方文档中可以看到,默认的
<Leader>键是反斜杠,如果你觉得反斜杠挺舒服那就可以不去更改它
如果需要更改,只需要给mapleader这个变量赋值即可
比如vim.g.mapleader = " ",这样就将空格映射成<Leader>键了
开始配置按键映射
创建~/.config/nvim/lua/key-bindings.lua,然后编写如下按键映射,已写明注释,可根据需求做出调整
还需要在~/.config/nvim/init.lua中导入key-bindings这个模块
-- ~/.config/nvim/init.lua
require('key-bindings')
窗口操作快捷键
1. 窗口基本操作
-- 分屏 sv(split vertically) sh(split horizontally)
map('n', 'sv', ':vs<CR>', opt)
map('n', 'sh', ':sp<CR>', opt)
-- 关闭当前窗口 (close)
map('n', 'sc', '<C-w>c', opt)
-- 关闭其他窗口 (close other)
map('n', 'so', '<C-w>o', opt)
-- Alt + hjkl 在窗口之间跳转
map('n', '<A-h>', '<C-w>h', opt)
map('n', '<A-j>', '<C-w>j', opt)
map('n', '<A-k>', '<C-w>k', opt)
map('n', '<A-l>', '<C-w>l', opt)
效果如下:
使用
sv开启水平分屏,并且由于前面我们配置了splitright,所以新的分屏会从右边出现
结合gd快捷键(用于跳转到变量定义的地方),使用svgd就可以指定在右边打开一个窗口显示变量定义
看完了之后再按下sc将窗口关闭,十分方便快捷!
2. 窗口比例调节
-- 左右方向键控制窗口水平比例
-- Ctrl-左右方向键 小幅度移动
map('n', '<C-Left>', ':vertical resize -2<CR>', opt)
map('n', '<C-Right>', ':vertical resize +2<CR>', opt)
-- s, s. 大幅度移动
map('n', 's,', ':vertical resize -20<CR>', opt)
map('n', 's.', ':vertical resize +20<CR>', opt)
-- 上下方向控制窗口垂直比例
-- Ctrl-上下方向键 小幅度移动
map('n', '<C-Up>', ':resize -2<CR>', opt)
map('n', '<C-Down>', ':resize +2<CR>', opt)
-- sj sk 大幅度移动
map('n', 'sj', ':resize +10<CR>', opt)
map('n', 'sk', ':resize -10<CR>', opt)
-- 窗口等比例显示
map('n', 's=', '<C-w>=', opt)
效果如下:
终端模式快捷键
为了保证窗口切换的统一体验,我们希望在terminal模式下,也能通过<Alt-hjkl>的方式进行窗口切换
一个直接的思路就是先退出terminal模式,回到NORMAL模式,然后再按下<Ctrl-w>hjkl进行切换
和INSERT等模式进入NORMAL模式的方式不同,terminal模式下回到NORMAL模式默认是通过<C-\><C-N>
所以我们的思路就是将
<Esc>映射到<C-\><C-N>,让它和INSERT模式下的回到NORMAL模式操作统一
然后将<A-hjkl>映射到<C-\><C-N><C-w>h,也就是先回到NORMAL模式,然后切换窗口
-- <leader>t 开启终端
map('n', '<leader>t', ':sp | terminal<CR>', opt)
map('n', '<leader>vt', ':vsp | terminal<CR>', opt)
-- <Esc> 退出终端
map('t', '<Esc>', '<C-\\><C-N>', opt)
-- 终端窗口中进行窗口切换
map('t', '<A-h>', [[ <C-\><C-N><C-w>h ]], opt)
map('t', '<A-j>', [[ <C-\><C-N><C-w>j ]], opt)
map('t', '<A-k>', [[ <C-\><C-N><C-w>k ]], opt)
map('t', '<A-l>', [[ <C-\><C-N><C-w>l ]], opt)
双方括号[[]]是lua的字符串,能够以字符串原本的形式存在,不需要手动转义特殊字符
NORMAL模式的一些灵活操作
-- H 移动到行首,L 移动到行尾
map('n', 'H', '^', opt)
map('n', 'L', 'g_', opt)
-- 上下滚动浏览
map('n', '<C-j>', '4j', opt)
map('n', '<C-k>', '4k', opt)
-- 修改 Ctrl-u 和 Ctrl-d 的移动幅度 从默认的移动半瓶改为移动 9 行
map('n', '<C-u>', '9k', opt)
map('n', '<C-d>', '9j', opt)
INSERT模式的一些灵活操作
- 按下
Esc或者Ctrl [回到NORMAL模式有点太麻烦了,由于jk连续字符的输入很少见,所以可以考虑将它映射成回到NORMAL模式 - 有时候想要跳到行首行尾,我们还得先切换回
NORMAL模式,再按下I或者A,这其实可以简化,用<Ctrl-h>和<Ctrl-l>代替
-- 映射 jk 为 <Esc>
map('i', 'jk', '<Esc>', opt)
-- 跳到行首行尾
map('i', '<C-h>', '<Esc>I', opt)
map('i', '<C-l>', '<Esc>A', opt)
VISUAL模式的一些灵活操作
- 有时候我们希望批量缩进代码,一个方便的操作是选中要缩进的代码后,按下
>即可 - 还有时候我们希望选中一段代码然后上下移动,可以通过
J将代码块向下移动,K将代码块向上移动,使得和普通的jk下移上移体验一致 - 默认情况下,在
VISUAL模式中粘贴文本的时候,会自动复制被粘贴的文本,这个设计实在是反人类,这会导致我想多次粘贴同一个文本的时候,每粘贴一次就要回到原处复制一次再去下一处粘贴,我们把这个问题修复一下,使用"_dP进行粘贴
上述三个功能的按键映射如下
-- 缩进代码
map('v', '<', '<gv', opt)
map('v', '>', '>gv', opt)
-- 上下移动选中的文本
map('v', 'J', ":move '>+1<CR>gv-gv", opt)
map('v', 'K', ":move '<-2<CR>gv-gv", opt)
-- VISUAL 模式中粘贴的时候默认会复制被粘贴的文本 很反人类 不需要
map('v', 'p', '"_dP', opt)
退出Neovim快捷键
默认情况下我们要退出的话是需要先进入命令模式,然后按下q然后再按下回车,要按三次键
更合乎常理的方案应当是按下q就直接退出,不需要那么繁杂的操作
-- 退出
map('n', 'q', ':q<CR>', opt)
map('n', 'qq', ':q!<CR>', opt)
map('n', 'Q', ':qa!<CR>', opt)