LV02-vimscript-08-execute与normal.md

本文主要是vimscript一些基础知识和操作的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows windows11
Ubuntu Ubuntu16.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
点击查看本文参考资料
点击查看相关文件下载
--- ---

一、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。这是vimrightbelow vsplittest.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"所在的位置。

这个命令将会在光标当前位置所在行的结尾加上一个;并保持光标不动。