使用折叠
查看 :h fold.txt 手册了解 Vim 中的折叠功能。
折叠方式
Vim 的 foldmethod 有以下 6 种折叠方式
| foldmethod | value | description |
|---|---|---|
| fold-manual | manual | 手动建立折叠。 |
| fold-indent | indent | 相同缩进距离的行构成折叠。 |
| fold-expr | expr | ‘foldexpr’ 给出每行的折叠级别。 |
| fold-marker | marker | 标志用于指定折叠。 |
| fold-syntax | syntax | 语法高亮项目指定折叠。 |
| fold-diff | diff | 没有改变的文本构成折叠。 |
比如: 为 json 文本创建折叠
set ft=json
syntax on
set fdm=syntax
查看 :h 'fold-methods', :h 'foldmethod' 了解折叠方式的详细说明。
折叠命令
所有的折叠命令用 z 开头。如果你从侧面看 z 像一张叠起来的纸。foldlevel 用来设置折叠层数,高于该值的层数会被折叠,foldlevel=0,会关闭所有折叠,数字越大,关闭的折叠越少。
打开关闭折叠
| 命令 | 效果 |
|---|---|
zo |
打开光标下折叠 (open) |
zO |
循环打开光标下所有折叠 (Open) |
zc |
关闭光标下折叠 (close) |
zC |
循环关闭光标下所有折叠 (Close) |
za |
切换光标下折叠 (打开或关闭) |
zA |
切换光标下所有折叠 (循环打开或循环关闭) |
zv |
仅打开足够的折叠使光标所在的行不被折叠 (view) |
zx |
更新折叠,恢复原来的 foldlevel, 然后使用 zv 查看光标所在行 |
zX |
恢复被打开和关闭的折叠, 重置 foldlevel |
zm |
foldlevel 减 1,折叠更多层 (more) |
zM |
关闭所有折叠,foldlevel 设置为 0 |
zr |
foldlevel 加 1,减少折叠 (reduce) |
zR |
打开所有折叠,foldlevel 设置为最高 |
查看 :h fold-commands 了解更多折叠命令。
character-classes 和 collection
Vim 与其它正则引擎有点不同的是,不支持将字符类 (:h /character-classes,如 \i, \w, \f\ \p 等) 放入到集合中 (:h /collction 即 []),例如不支持 [\w\s]\+ 这种语法。但支持在集合中使用 POSIX character class expressions (如 [:alnum:]),因此我们可以使用以下格式来匹配常用字符
" Match UUID, [:alnum:] equlas [A-Za-z0-9]
g/[[:alnum:]-]\+/
将多行合并为一行并用逗号分隔
使用 paste 命令
%!paste -sd, -
在 vim 中格式化 xml 文本
使用 xmllint 命令 (macOS 系统自带)
%!xmllint --format -
在 vim 中格式化 json 文本
安装 jq 命令
brew install jq
使用 vim 打开 json 文件,在 vim 使用下面的命令。
:%!jq .
tabstop, softtabstop, expandtab, shiftwidth 和 retab 的关系
- tabstop
- 打开文件时,将一个 TAB 字符显示成几个空格的长度。
- softtabstop
- 在 Insert 模式下,按下 Tab 键后,应当插入的空格的数量;
- 如果未设置 expandtab,插入的仍会是 TAB 字符。
- expandtab
- 告诉 Vim 在按下 Tab 键时插入空格而不是 TAB 字符。
- shiftwidth
- 在换行时,自动缩进的空格长度,
- 使用
>,<或=做缩进操作时的空格长度。
- retab
- 重置 TAB 字符,将文件中的 TAB 字符转换为空格。
总结一下,softtabstop 控制着 TAB 和退格键的表现,而 expandtab 决定了是否将 TAB 转换为空格。当两者结合使用时,可以创建一个只使用空格,而不使用 TAB 字符的编辑环境,并且能够精确控制缩进的大小。
Vim Modeline
Modeline 有两种写法,第一种形式是 vi: 后以 set 开始,遇到第一个冒号 : 后结束,中间的选项以空格分隔
# vi: set ff=unix ts=2 sw=2 :
第二种形式是 vi: 后直接跟选项列表,选项之间以冒号 : 或空格分隔
# vi: ff=unix ft=sh ts=4 sw=4 expandtab
# 或
# vi: ff=nnix:ft=sh:ts=4:sw=4:et
具体语法查看 Vim 文档 :h modeline
比如在 Jenkinsfile 中,想让 Vim 打开文件时自动识别文件类型为 groovy,可以在文件顶部加入下面的注释
// vi: ft=groovy
注意:在不同的文件类型内,要用对应的注释语句,比如在 python 文件内应该使用
# vi: ft=python
类似的还可以设置文件的缩进等,比如为 shell 文件设置缩进为 4
# vi: ts=4 sw=4 expandtab
在 Vim 中插入当前文件名
在 Insert 模式中,按下 Ctrl-R,然后再按 % 即可直接插入当前文件名。
Ctrl-R 的作用是插入寄存器中的内容,当按下 CTRL-R 时,屏幕会显示一个 " 字符,提示你输入一个寄存器的名字。下面是 Vim 中的特殊寄存器:
'"' 无名寄存器,包含最近一次删除或复制的内容
'%' 当前文件名
'#' 轮换文件名
'*' 剪贴板的内容 (X11: 主选择区)
'+' 剪贴板的内容
'/' 最近一次的查找模式
':' 最近一次在命令行输入的命令
'-' 最近一次小的 (少于一行) 删除
'.' 最近插入的文本
'=' 表达式寄存器: 会提示你输入一个表达式。
使用 :h <c-r> 查看该命令帮助文档,使用 :h registers 查看寄存器帮助文档。
Vim 中 dos 换行符与 unix 换行符相互转换
set ff=unix
set ff=dos
将查找到的字符串改为大(小)写形式
" 全部大写
:g/string/s//\U\0\E/
" 首字母大写
:g/string/s//\u&/
\0或&表示引用整个匹配字符串,\u表示下一个字符变为大写,\U表示其后字符变为大写,直到\e或\E出现。具体内容可以查看帮助:h :s\=。
执行外部命令
比如需要运行当前编辑的 python 代码
:!python %
!{cmd}在 Vim 中执行外部命令(查看帮助:h :!),%为当前编辑的文件名(查看帮助:h cmdline-special或:h :_%)。
使用 sudo 强制更新文件
:w !sudo tee %
w !{cmd}将整个 buffer 作为标准输入执行{cmd}(查看帮助:h :w_c),%为当前编辑的文件名,tee从标准输入读取内容后再将内容写到标准输出及文件中(类似 T 型三通)
排序,去重
" 倒序
:sort!
" 按数字排序
:sort n
" 去重
:sort u
" 忽略大小写
:sort iu
统计个数
" 查看count-items帮助
:h count-items
" 查看s_flags了解替换标志
:h s_flags
" 使用substitute命令
:%s/./&/gn " characters
:%s/\i\+/&/gn " words
:%s/^//n " lines
:%s/the/&/gn " 'the' anywhere
:%s/\<the\>/&/gn " 'the' as a word
将 g/pattern/搜索到的行写入新文件
:redir > match.txt
:g/regex/
:redir END
要注意的是,:g/regex/w match.txt并不会将匹配的行写入新文件,而是在每次匹配到的行上执行w match.txt命令,并且是将当前 buffer 的所有内容写入新文件。
给每行自动编号
使用 Vim 内置命令 line(),用法可以查看帮助 :h line()和:h :.
:%s/^/\=line('.') . '、'/
'.'表示所在行的行号。当:s 命令的替换字符串以"\="开头时,表示以表达式的计算结果作为替换值,.用于连接字符串。
多行匹配(multiline match)
Vim 中默认是单行匹配,比如/hello\sworld/,只能匹配单行中 “hello world”,其中 \s 匹配空格或 tab。如果希望多行匹配,可以使用/hello\_sworld/,这里的 \_s 表示匹配空格、tab 和换行符。
搜索 /^hello 会在行首匹配到 hello,搜索 /hello\$ 会在行尾匹配到 hello。但是在模式 /hello^world 和 /hello\$world 里的 ^ 和 $ 只是普通字符,没有特殊含义。
\na newline character (line ending)\_sa whitespace (space or tab) or newline character\_^the beginning of a line (zero width)\_$the end of a line (zero width)\_.any character including a newline
例如,搜索
-
/hello\n*world- Finds hello followed by zero or more newlines then world.
- Finds helloworld or hello followed by blank lines and world.
- The blank lines have to be empty (no space or tab characters).
-
/hello\_s*world- Finds hello followed by any whitespace or newlines then world.
- Finds helloworld or hello followed by blank lines and world.
- The blank lines can contain any number of space or tab characters.
- There may be whitespace after hello or before world.
-
/hello\_$\_s*world- Finds hello at end-of-line followed by any whitespace or newlines then world.
- There must be no characters (other than a newline) following hello.
- There can be any number of space, tab or newline characters before world.
-
/hello\_s*\_^world- Finds hello followed by any whitespace or newlines then world where world begins a line.
- There must be no characters (other than a newline) before world.
- There can be any number of space, tab or newline characters after hello.
-
/hello\_$world
Finds nothing because \_$ is “zero width” so the search is looking for helloworld where hello is also at end-of-line (which cannot occur). -
/hello\_^world
Finds nothing because \_^ is “zero width” so the search is looking for helloworld where world is also at beginning-of-line (which cannot occur). -
/hello\_.\{-}world- Finds hello followed by any characters or newlines (as few as possible) then world.
- Finds helloworld or hello followed by any characters then world.
-
/hello\(\_s.*\)\{0,18\}\_sworld- Finds a block of 0 to 18 lines enclosed by hello and world.
- limiting the number of lines is important, replacing this by a star will cause vim to consume 100% CPU.