使用Neovim打造酷炫IDE -- 快捷键配置

3,133 阅读7分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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模式
    • ...总之就是你希望按键映射生效的模式的首字母小写即可
  • lhsLeft-hand-side的缩写
  • rhsRight-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即可触发 image.png 从官方文档中可以看到,默认的<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)

效果如下: 窗口操作快捷键.gif 使用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)

效果如下: 水平窗口比例调节.gif 垂直窗口比例调节.gif


终端模式快捷键

为了保证窗口切换的统一体验,我们希望在terminal模式下,也能通过<Alt-hjkl>的方式进行窗口切换 一个直接的思路就是先退出terminal模式,回到NORMAL模式,然后再按下<Ctrl-w>hjkl进行切换 和INSERT等模式进入NORMAL模式的方式不同,terminal模式下回到NORMAL模式默认是通过<C-\><C-N> image.png 所以我们的思路就是将<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)