LV02-vimscript-08-execute与normal.md
本文主要是vimscript一些基础知识和操作的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows | windows11 |
Ubuntu | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
点击查看本文参考资料
参考方向 | 参考原文 |
Learn vimscript the Hard Way | https://learnvimscriptthehardway.stevelosh.com/ |
vim在线文档 | http://vimcdoc.sourceforge.net/ |
VIM 中文帮助 | https://vimcdoc.sourceforge.net/doc/help.html |
vim教程 | https://www.w3cschool.cn/vim/ |
一、execute
命令
在vim
中有这么一个命令,可以将字符串作为Ex
命令执行。它就是execute
命令,详情也可以查看中文在线文档:VIM: eval - execute
1. 基本格式
1 | :exe[cute] {expr1} .. |
计算 {expr1}
,返回的字符串作为 Ex
命令执行。多个参数用空格连接。如果不想有额外的空格,使用 .
操作符来连接字符串使之成为一个参数。
【注意】
(1){expr1}
用作被处理的命令,命令行编辑的键不会被识别,后面不能跟注释。
(2)双引号内部尽量不要套双引号,否则可能会被识别为变量从而产生错误信息。
(3)最好还是使用双引号,单引号似乎有很大的问题,至少我在测试的时候是这个样子。
2. 基本用法
在命令模式中执行:
1 | :execute "echo 'Hello, world!'" |
输出结果如下:
1 | Hello, world! |
vim
把字符串"echo 'Hello, world!'"
当作一个命令来执行了。 Execute
是一个非常强大的工具,因为它允许我们用任意字符串来创造命令。
我们同样可以使用.
来连接两个字符串,使其成为一个参数,在命令模式中执行:
1 | :execute "rightbelow vsplit " . "test.py" |
vim
将在当前缓冲区窗口的右边打开一个竖直分割窗口(vertical split
)并创建了一个新的缓冲区,名字为test.py
。这是vim
将rightbelow vsplit
和test.py
连接在一起,创建了一个新的字符串"rightbelow vsplit test.py"
,这时候execute
将该字符串作为命令执行后就产生了刚才的结果。
二、normal
命令
我们已经接触了很多vim
命令了,但都跟日常中在normal
模式下处理文本的方式无关。 有没有一种办法能把我们的脚本跟日常的文本编辑命令结合起来呢?vim
已经帮我们想到了,并为我们提供了方法,那就是normal
命令,详情也可以查看中文在线文档:VIM: various - normal
1. 基本格式
1 | :norm[al][!] {commands} " 执行若干普通模式命令 {commands}。 |
! | 如果给出 [!],不使用映射。如果没有,如果一个不可重新映射的映射 ( :noremap ) 调用该命令,它的参数就因而还是有可能被重新映射。 |
{commands} | {commands} 必须是完整的命令。如果 {commands} 没有完整 给出一个命令,未完成的最后那个命令会被终止,如同键入了<Esc>或 <C-C> 一样。 |
【注意】
(1){commands}
不能以空格开始,如果要,前面加个计数 1(one)
。1
就是一个空格。
(2)该命令后面不能跟其他命令。因为任何|
都被认为是命令的一部分。
(3)该命令可以递归使用,但是深度不能超过maxmapdepth
(最大次数的映射次数,缺省为 1000)。
(4)一个替代normal
的方法是使用execute
,它可以用表达式作为参数。这样就可使用可显示字符来代表特殊字符。
2. 基本用法
在命令模式中执行:
1 | :normal G |
会发现,光标移动到了文件最后一行,就跟在normal
模式中按下了G
一样。然后我们使用execute
命令来替代normal
试一下效果,在命令模式中执行:
1 | :execute "normal G" |
会发现,光标依然定位到了最后一行。
3. 避免映射
在命令模式下执行:
1 | :nnoremap G dd |
这是一个映射,将G
的功能改为了删除当前行,此时按下G
的时候,会发现当前行被删除了。
现在在命令模式中执行:
1 | :normal G |
此时,光标不会定位到最后一行了,而是把当前行删除了。也就是说normal
命令会顾及当前的所有映射。这意味着我们需要给normal
提供类似于nnoremap
之于nmap
的版本, 否则我们没法使用它。前边介绍这个命令的时候有一个!
,这下,它就派上了用场,在命令模式中执行:
1 | :normal! G |
此时光标被移动到文件最后一行,而并没有删除当前行,然而,当我们在普通模式中按下G
的时候,当前行依然被删掉了。
所以为了避免映射对我们造成影响,我们应该总是使用normal!
,永不使用normal
。不要对自己在~/.vimrc
中的映射有那么大自信。
4. 特殊字符
接下来,我们来尝试以下命令,在命令模式中执行:
1 | :normal! /group<cr> |
理论上来说,它应该会开始搜索group
,但实际上看到的却是它不会正常工作。 问题就在于normal!
不会解析像<cr>
那样的特殊字符序列。所以vim
会意识到我们要进行搜索,但是它不会意识到我们也按下了回车来进行搜索,那么这个问题怎么解决呢?
以前我们经常用到转义字符\
,我们是否可以使用\
来使vim
识别特殊的按键呢?在命令模式中执行:
1 | :normal! gg/group\<cr>dd |
但是似乎问题依然没有都得到解决,我们想到,以前使用转义字符都是在字符串中使用,这里又不是字符串,那要是命令变成字符串不就可以了吗?那么我们再来尝试加上execute
再来试试,在命令模式中执行:
1 | :execute "normal! gg/group\<cr>dd" |
然后我们惊奇的发现,可以了,它找到了首次出现group
的行,然后把这行删除了。
5. 行尾加分号
接下来我们进行一个实践操作,这个操作将会很有用。在命令模式中执行:
1 | :execute "normal! mqA;\<esc>`q" |
点击查看命令分析
mq | 保存当前位置到标记"q"。 |
A | 移动到当前行的末尾并在最后一个字符后进入insert模式。 |
; | 我们现在位于insert模式,所以仅仅是写入了一个";"。 |
\<esc> | 这是一个表示Esc键的转义字符串序列,把我们带离insert模式。 |
`q | 回到标记"q"所在的位置。 |
这个命令将会在光标当前位置所在行的结尾加上一个;
并保持光标不动。