[vim ] 你应该扩充的 text object

楼主: as23041248 (KAIKAIKAI)   2020-09-22 21:52:38
小弟我写了一篇文章,和各位聊聊 vim text object
网志版: https://reurl.cc/Z7WmRQ
# 前言
vim 高效率编辑的背后,operator, motion, text object 的配合功不可没。
operator 是编辑的动作, text object 就是文字区块,motion 是跳转到文件点,
透过三者的按键配合,就能达到所想及所得的编辑方式。
如果你有看过别人使用 vim ,通常会有这种想法:怎么随便按几个键就删这里删那里
复制这复制那,速度快到看不懂在干嘛,而且还不会错,因为只要想好要做什么,
按键按下去就对了,这也是为什么会高效率。说了一堆,反正就是 ""耍潮必备""。
本篇将会提到:
- operator, text object, motion 的配合用法
- 内建 text object 的不足之处
- 扩充 text object 的 plugin
- 浅谈 nvim-treesitter
# Operator & text object
Vim 定义了多个 operator 最常用的就是:
- d: delete (删除)
- c: change (更改)
- y: yank (复制)
operator 没有配合 text object 或是 motion 是没有意义的,想像一下
使用了 d 删除,但是没告诉它要删除什么,就像有了铁锤不知道要打什么。
所以需要给 operator 一个目标,让它要对谁做什么。这个谁就有两种,motion
和 text object。
motion:其实就是跳转指令,像是常用的 G,gg, w, f{char} ... 等都可以配合
operator。基本使用方法为 {operator}{motion},语意就是做这个 operator
到 motion 所到的地方
以 d operator 做举例的话 (其他 operator 以此类推):
- dG: 删除 从光标到档案的尾部
- dgg: 删除 从光标到档案的头部
- dw: 删除 从光标到下一个字
- dfz: 删除 从光标底下到达此行 z 这个字母 (如果此行无 z 则不动作)
text object: 通常是已经定义的一个范围,像是 word, quote, () block
... 等。内建的 text object 都会有 i 或 a 为前辍,i 表示 inside (不包含的概念)
、 a 表示 around (包含的概念)。
常用的 text object:
- iw :光标下的字不包含后面的空白 (英文断字使用空白)
- aw :光标下的字包含后面的空白 (英文断字使用空白)
- i" :光标下在双引号里的所有字不包含双引号
- a" :光标下在双引号里的所有字包含双引号
- i(, i) :光标下在小括号里的所有字不包含小括号
- a(, a) :光标下在小括号里的所有字包含小括号
基本使用方式为 {operator}{text object},语意就是对此 text object
做这个 operator
使用 d operator 做举例:
- diw :删除 光标下的字不包含后面的空白 (英文断字使用空白)
- daw :删除 光标下的字包含后面的空白 (英文断字使用空白)
- di :删除 光标下在双引号里的所有字不包含双引号
- da :删除 光标下在双引号里的所有字不包含双引号
- di(, di) :删除 光标下在小括号里的所有字不包含双引号
- da(, da) :删除 光标下在小括号里的所有字包含双引号
建议自己把 :help motion.txt 翻一翻,找出自己常用的 text object 看一看
,写成一个 cheat sheet
虽然 vim 定义了大量的 text object,但可能大部分都不是你想要的,那就透过
plugin 来满足需求吧。
# 简单好用的 vim-textobj-user
kana 所发展的 kana/vim-textobj-user[1] 是一个 lib,让使用者借由这个 lib 轻松的
制作属于自己的 text object,所以就有一些 plugin 基于此 lib 做出更多的
text object,这些 plugin 的名字通常都叫 vim-textobj-xxx 。
使用 plugin 的方法为:
- 安装 kana/vim-textobj-user[1]
- 在 wiki[2] 里查看自己所需的
text object plugin,并且安装
举例来说:我最常用的两个 text object 是 comment 和 funtion parameter,
所以我选定 glts/vim-textobj-comment[3] 和 sgur/vim-textobj-parameter[4]
Plug 'kana/vim-textobj-user'
Plug 'glts/vim-textobj-comment'
Plug 'sgur/vim-textobj-parameter'
vim-textobj-comment 提供了:
- ic:comment 内容
- ac:comment 内容 + comment 符号
vim-textobj-parameter 提供了:
- i,:参数
- a,:参数符号 + 分隔符号 (也就是逗号)
# 更细腻的 text object - targets.vim
wellle/targets.vim[5] 把 text object 的种类拆成四类型:
- Pair text objects - ( ) { } [ ] < >
- Quote text objects - ' " `
- Separator text objects - , . ; : + - = ~ _ * # / | \ & $
- Argument text objects
- Tag text objects
Pair 和 Quote text objects 是 vim 原本就有的概念,Separator text objects
如其名,两个 separator 之间的字就是 Separator text objects 了。
举个使用情境:url GET 参数都用 & 所隔开,如果想删除 & 之间的字那就用得上了
内建的 text object 使用了 i 和 a 做前辍,而 targets.vim 更为细腻,
提供了额外的 I 和 A 扩充原本的 i 和 a,再加上一层概念 n 和 l,
n 代表下一个,l 则代表上一个。
注:内建的 text object 都是以光标位置为准,没上一个和下一个的概念
以 ) 做个举例:
- i):包含括号里的所有字
- I):包含括号里的所有字,但括号里两边的空白不包含
- a):包含括号和括号里的所有字
- A):包含括号和括号里的所有字还有两边括号外的空白
加上 n 和 l 的话就是下一个跟上一个
. 表示光标所在位置
https://i.imgur.com/a2prq5U.png
target.vim 提供的 text object 实在太多太复杂,所以很贴心的做了 cheat sheet[6]
# syntax 相关 text object
以上所提到的 text object 都是和程式语言较无相关的 text object。
程式语言相关的 text object,比如说 function, class, structure...等,
这些相关的 text object plugin 相对来说比较少见。
vim 并没有提供一个接口直接拿取 syntax tree 的某一个 node,所以现在的所有
text object 的 plugin 都是靠 regex 或是其他字串比对的方式。假如想要一个
function 的 text object,就必须在每种语言都用 regex 或字串比对做一遍,
相当的麻烦,kana/vim-textobj-function[7] 就是一个例子,目前只提供三种语言,
并且每种语言实做一次。
一个 text object 为主的 plugin 想要集成所有的 syntax 相关 text object 变得
不太可能,所以这些 syntax 相关 text object plugin 通常都已一种语言为主,
或是附属在某些语言 plugin 底下:
- vim-go 提供了 comment (ac, ic) 和 function (af, if) text object
- sgur/vim-textobj-parameter[8] 为 python syntax 相关的 text object
- mjbrownie/django-template-textobjects[9] 为 django-template 相关的
text object
# 救世主 treesitter
一个 text object 为主的 plugin 想要集成所有的 syntax 相关 text object
真的不可能达到吗?
等到 Treesitter 被 neovim 整合完成后一切将变得简单许多。
Treesitter 简单来讲就是个 parser,可以使用它建立 syntax tree,官方介绍如下:
Tree-sitter is a parser generator tool and an incremental parsing library.
It can build a concrete syntax tree for a source file and efficiently update
the syntax tree as the source file is edited
neovim 0.5 版的目标就是要将 treesitter 整合,完成之后将可在 neovim 里使用
treesitter 相关的 api,拿到了 syntax tree, 要抓到 text object 变得容易许多。
别说做 text object plugin 了,连 syntax highlight, code folding 等相关 plugin
都可以不需倚赖 regex ,而目前已经有基于 treesitter 的 plugin 了:
nvim-treesitter/nvim-treesitter[10]
详见 :help treesitter-parsers
# 结语
wellle/targets.vim 和 kana/vim-textobj-user 在开发上使用截然不同的方式,
前者定义好大量细腻的 text object,后者则是一个 lib,由使用者以此 lib 为基础
在开发 plugin。
对我来说,内建的 text object 已经足够强大几乎满足需求,只需要在做一点补强,
像是常用的 comment 和 funtion parameter 就没有被 vim 定义。而 target.vim 大量
细腻的 text object 使用情境都比较特殊,所以我就选择了 vim-textobj-user 阵营
——只选择自己所需要的安装,不会有多余的功能。
nvim-treesitter/nvim-treesitter 倚赖 syntax tree 解决了使用 regex 开发
text object plugin 的麻烦,而且更精准,可以预见 neovim 0.5 完成后的未来,
syntax 相关的 text object plugin 将会被此 plugin 统一。
# Reference
- https://codeinthehole.com/tips/vim-text-objects/
- https://www.tandrewnichols.me/motions-operators-text-objects-introduction/
- :help 'motion.txt'
[1]: https://github.com/kana/vim-textobj-user
[2]: https://github.com/kana/vim-textobj-user/wiki
[3]: https://github.com/glts/vim-textobj-comment
[4]: https://github.com/sgur/vim-textobj-parameter
[5]: https://github.com/wellle/targets.vim
[6]: https://github.com/wellle/targets.vim/blob/master/cheatsheet.md
[7]: https://github.com/kana/vim-textobj-function
[8]: https://github.com/sgur/vim-textobj-parameter
[9]: https://github.com/mjbrownie/django-template-textobjects
[10]: https://github.com/nvim-treesitter/nvim-treesitter
作者: mars90226 (火星人)   2020-09-23 00:49:00
推推,我也很期待 treesitter
作者: mjsg (mjsg)   2020-09-24 09:05:00
虽然都知道皮毛但都没有仔细设定的部分,谢谢分享。

Links booklink

Contact Us: admin [ a t ] ucptt.com