You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

200 lines
9.7 KiB

2 years ago
# 第一章 VimL 语言主要特点
## 1.1 Hello World 的四种写法
按惯例,我们讨论一门语言,首先看下如何写最简单的 “Hello World” (程序)。
由于 Vim 是高度自由的,VimL 也有多种不同的方式玩转 “Hello World”。
### 速观派:直接操起命令行
最快速的办法是在 Vim 命令行下用 `:echo` 命令输出 “Hello World”:
```vim
: echo 'Hello World!'
```
唯一需要注意的是,得把 “Hello World” 用引号括起来,单引号或双引号都可以。
这样再按下回车就能在 Vim 的消息区显示出 “Hello World” 这行字符串了。
由于这条消息字符串很简短,一行就能显示完整,Vim 将其直接显示在命令行的位置,并
且运行完直接返回 Vim 普通模式。如果字符串很长或多行字符串,则消息区将向上滚动
,以显示完整的消息,用户需要额外按个回车才回普通模式。
试试在命令行输入这条命令,看看有啥不同反应:
```vim
: echo "Hello World! \n Hello World! \n Hello World!"
```
好了,你已经学会了如何用 VimL 输出 “Hello World” 了。这也算编程吗?别逗了!其
实,别把编程想得那么严肃,那这就算编程!
### 正规派:建立脚本文件
把刚才在命令行输入的那条命令保存在一个 `.vim` 后缀的文本文件中,那就是一个
`vim script` 了,这是用 VimL 编程比较正常的用法。
为了方便,建议在本地建个目录,用于保存本教程的示例代码。比如:
```bash
$ cd ~/.vim
$ mkdir vimllearn
$ vim vimllearn/hello1.vim
```
这将在 `~/.vim` 目录下新建一个 `vimllearn` 目录,并用 vim 开始编辑一个名为
`hello1.vim` 的文件。vim 会为该文件新建一个缓冲区 `buffer`,在该 `buffer` 中输
入以下文本,然后输入命令 `:w` 保存:
```vim
" 文件:hello1.vim
" 用途:VimL hello world 示例
" 作者:lymslive
" 时间:2017-08
echo 'Hello World!'
finish
脚本结束了,可以随便浪~~
不管写些什么乱七八糟的都木有关系。
```
你其实可以只在该文件中写入 `echo 'Hello World!'` 这一行就够了。几点说明:
1. 前面以一个双引号 `"` 开始的行是注释,注释也可以写在行尾。
2. 在脚本文件中,`echo` 命令前不必加冒号 `:`,但是加上冒号也是允许的。
3. `finish` 表示直接结束脚本,在之后的语句都不再被 vim 解析;这是可选的,没有
遇到 `finish` 就会执行到文件最后一行。
当有了 `*.vim` 脚本文件,就可以在 vim 环境中用 `:source` 命令加载运行了:
```vim
: source ~/.vim/vimllearn/hello1.vim
```
需要将脚本文件的路径写在 `source` 命令之后作为参数。如果当前 vim 正常编辑
`hello1.vim` 这个文件,则可用 `%` 表示当前文件的路径:
```vim
: source %
```
折腾并解释了这许久,终于可以通过 `source` 一个 vim 脚本打印输出 “Hello World”
了,与此前的效果是一样一样的。当然了,用 VimL 写脚本肯定不能只满足于写 “Hello
World” 吧,所以这才是标准用法。
此外 Vim 的命令是可以简写的,`source` 可简写为 `so`。当你在写一个 vim 脚本时想
快速验证执行该脚本时,可以只输入:
```vim
: so %
```
如果还想更省键,就定义一个快捷键映射吧,比如:
```vim
: nnoremap <F5> :update<CR>:source %<CR>
```
可以将这行定义加入你的 `vimrc` 中,不过最好是放在 `~/.vim/ftplugin/vim.vim`
,并加上局部参数,让它只影响 `*.vim` 文件:
```vim
: nnoremap <buffer> <F5> :update<CR>:source %<CR>
```
### 测试派:进入 Ex 模式
直接在命令行用 `:echo` 查看一些东西其实很有用的,可以快速验证一些记不清楚的细
节。比如你想确认下在 VimL 中字符 `'0'` 是不是与数字 `0` 相等,可以这样:
```vim
: echo '0' == 0
```
但如果要连续输入多条命令并查看结果,每次都要(从普通模式)先输入个冒号,不免有
些麻烦。这时,`Ex` 模式就有用了。默认情况下(若未在 vimrc 被改键映射),在普通
模式下用 `Q` 键进入 `Ex` 模式。例如,在 `Ex` 模式下尝试各种输出 “Hell World”
的写法,看看不同引号对结果的影响:
```vim
Entering Ex mode. Type "visual" to go to Normal mode.
: echo 'Hello World!'
: echo "Hello World!"
: echo 'Hello \t World! \n Hello \t World!'
: echo "Hello \t World! \n Hello \t World!"
: vi
```
最后,按提示用 `visual` 或简写 `vi` 命令回到普通模式。
Vim 的 `Ex` 模式有点像 VimL 的交互式的解释器,不过语法完全一样(有些脚本语言的
交互式解释器与执行脚本有些不同的优化),仍然要用 `echo` 显示变量的值。
### \*索隐派:从 shell 直接运行
如果只为了运行一个 vim script 脚本,也不一定要先启动 vim 再 `source`,直接在启
动 vim 时指定特定参数也能办到。`-e` 参数表示以 `Ex` 模式启动 vim,`-S` 参数启
动后立即 source 一个脚本。因此,也可以用如下的命令来输出 “Hello World”:
```vim
$ cd ~/.vim/vimllearn
$ vim -eS hello1.vim
```
这就相当于使用 `vim` 解释器来运行 `hello.vim` 这个脚本,并且停留在交互式界面
上。此时可以用 `:q` 命令退出,或 `:vi` 以正常方式继续使用 Vim。
vim 本身的命令行启动参数其实还支持很多功能,请查阅 `:help starting`。其中还有
个特殊的参数是 `-s`,如果与 `-e` 联用,就启动静默的批处理模式,试试这个:
```vim
$ vim -eS hello1.vim -s
```
没有任何反应输出?因为 `-s` 使普通的 `echo` 提示无效,看不到任何提示!赶紧输入
`q` 回车退出 vim 回到 shell。因为如果不小心按了其他键,vim 可能就将其当作命令
来处理了,而且不会有任何错误提示,这就会让大部分人陷入不知如何退出 vim 的恐慌
虽然 `vim -e -s` 不适合来输出 “Hello World”,但如果你的脚本不是用来做这种无聊
的任务,这种模式还是有用的。比如批处理,在完全不必启动 vim 可视编辑的情况下,
批量地对一个文件或多个文件执行编辑任务。可达到类似 `sed` 的效果。而且,在 vim
脚本写好的情况下,不仅可以按批处理模式执行,也可以在正常 Vim 可视编辑某个文件
时,遇到类似需求时,也可以再手动 `:source` 脚本处理。
### 小结
运行 vim 脚本的常规方法用 `:source` 命令,而且有很多情况下并不需要手动输入
`:source` 命令,在满足一定条件下,vim 会自动帮你 source 一些脚本。vim 的启动参
`-S` 其实也是执行 `:source`
Vim 的命令行可以随时手动输入一些简短命令以验证某些语法功能,进入 `Ex` 模式则可
以连续手动输入命令并执行。`Ex` 模式虽然比较少用,但不该反感排斥,这对学用 VimL
还是大有裨益的,以后会讲到,VimL 的 debug 功能也是在 `Ex` 模式中的。
静默批处理 `vim -e -s` 本质上也是 `Ex` 模式,不过禁用或避免了交互的中断。属于
黑科技,一般的 vim 用户可先不必深究。
### \*拓展阅读:Vim 与可视化
“可视化”是个相对的概念。现在说到可视化,似乎是指功能丰富的 IDE 那种,有很多辅
助窗口展示各方面的信息,甚至有图形化来表示类层次关系与函数调用关系。还有传说中
的唯一的中文编程语言“易语言”还支持图文框拖拖拽拽就能编写代码的东东……而 vim 这
种古董,只有编辑纯文本,似乎就该归属于“不可视”。
然而,让我们回顾洪荒时代,体验一下什么叫真正的“不可视”编辑。
在 Vi 都还没诞生的时代,有一个叫 `ed` 的行编辑器,它只能通过命令以行为单位去操
作或编辑文本文件。它完全没有界面,无从知道当前编辑的是哪个文件,在哪行,当前行
是什么内容,用户只能“记住”,或用命令查询。比如用 `p` 命令打印显示当前行(不过
也可以在前面带上行地址打印多行,至今 `vim` 的大部分命令都可以带地址参数)。要
编辑当前行,请用 `a` `i``c` 命令(vimer 有点眼熟吧),不过编辑完后也无从知
晓结果是否正确,可能还需要再用 `p` 命令打印查看确证。
之后,有个 `ex` 编辑器,不过是对 `ed` 的命令进行了扩展,本质上仍是行编辑器。直
`vi` 横空出世,那才叫“屏幕编辑器”。意思是可以全屏显示文件的许多行,移动光标
实时修改某一可见行,修改结果即时显示……这才像我们现在可认知的编辑器了。
然后是 `vim``vi` 的扩展增强。事实上,`vim` 还不如 `vi` 的划时代意义,它的
增强与此前 `ex``ed` 的增强是差不多的程度,基本上是平行扩展。
可视化程度不是越高越好。 `vim``vi` 都保留与继承了 `ex` 的命令,因为 `ex`
命令确实高效,当你能确知一个命令的运行结果,就没必要关注中间过程了。比如最平凡
无奇但常用的 `ex` 命令就是 `:s` 全局替换命令。
VimL 语言就是基于 `ex` 命令的,再加上一些流程控制,就成了一种完整的脚本语言。
如果说 `vim``vi` 有什么压倒性的里程碑意义,我觉得应是丰富完善了 VimL 语言
,使得 `vim` 有了无穷的扩展与定制。利用 VimL 写的插件,既可以走增加可视化的方
向,也可以不增加可视化而偏向自动化。依每人的性格习惯不同,可能会在 Vim 的可视
化与自动化之间找到适合自己的不同的平衡点。
<!--
—— 楼上的天花乱坠地在说些什么呀
—— 不知道耶,再看看吧
-->