Practical Vim
每日Vim
规则:
操作 = 操作符 + 命令
一.模式
普通模式
无论光标在何处,删除一个单词最快
daw,记忆delete a word<C-a>命令 对数字执行加法,<C-x>命令 对数字执行减法, 在命令前加上count可以进行算数运算gu修改为小写/gU修改为大写(operator)ap表示一段a paragraph
插入模式
backspace的代替操作:<C-h>删除一个字符<C-w>删除前一个单词<C-u>删除至行首
<C-o>zz,进入插入-普通模式,zz重新绘制屏幕<C-r> {register},插入寄存器的内容,- 插入表达式寄存器的内容 = 利用表达式寄存器做计算
- 插入复制寄存器的内容 =
<C-r> 0
可视模式
v:面向字符的可视模式
V:面向行的可视模式
<C-v>:面向列的可视模式
gv:重新选择上次的high light区域
切换选区的活动端点,正常是左上的端点固定,右下的端点活动,
o使得右下的端点固定,左上的端点活动使用
o切换端点配合w:下一个单词b上一个单词e单词的词尾<C-v>切换到列模式,配合I在行首插入,和r单次替换同时修改列文本:
<C-v>切换到列模式选中区域后,c替换所有.在
<C-v>模式中i和a不在是插入,请使用I,和A
命令行模式
ex命令格式:
: [range] delete/substitute/ []/{}命令:
:[range]delete [x]删除指定行到寄存器x:[range]yank [x]复制指定范围行到寄存器x:[line]put [x]在指定行后粘贴寄存器x中的内容:[range] copy {address}把指定范围内的行拷贝到{address}所指定的行下:[range] move {address}把指定范围内的行移动到{address}所指定的行下:[range] join连接指定范围内的行:[range] normal {commands}对指定范围的每一行执行普通模式命令:[range] substitute/{pattern}/{string}/{flags}把指定范围内出现的{pattern}地方替换为{string}:[range] global/{pattern}/[cmd]对指定范围内出现匹配{pattern}的所有行,在其上执行ex命令
特殊符号含义:
- 单个数字表示行,
$表示文件尾部(在普通模式下表示行尾部),.表示当前行%表示文件中的所有行. 全局替换 :%s/待替换字符串/新字符串{address}+n表示行偏移. 显示当前行,到偏移3行后的内容: .,.+3p
地址指定范围:
- 格式:
{start},{end}
- 格式:
normal命令,(指定范围上执行普通模式命令),一般配合
.使用,进行大量重复操作,- 如果其他普通模式命令一定要和normal分开,
- normal命令会自动将光标移动到每一行的起始处
例如给指定行添加分号
:.+1,$ normal A;<C-r><C-w>将当前光标的单词插入到命令行,- 在执行ex命令时使 插入单词到command line
- 查看
vimrc文档,:h <C-r><C-w>
完整的命令行窗口:
q:打开ex命令历史的命令行窗口 (注意和退出命令是相反的,难怪有时候会按错按出来)q/:打开查找命令历史的命令行窗口<C-f>从command line mode切换到命令行窗口(保留当前输入的命令)
使用shell的几种操作
<C-z>挂起vim,然后fg回到vim:shell命令行启动shell,然后exit回到vim:!{cmd}命令行执行一条shell命令,%表示当前文件名
有关标准输入输出
:read !{cmd}将命令的标准输出插入到光标下:[range] write !{cmd},选中范围,让后将其作为命令的标准输入- 好用:
[range] write !tee xxx.file:将当前选中的buffer的内容写入到外面的一个文件中
- 好用:
- 使用命令作为过滤器(filter),(选中输入->修改->写回).
[range] !{cmd}
二.文件
buffer基本管理:
vim中buffer是文件在内存的映像
- buffer列表的基本操作:
- 显示缓冲区列表
ls, b{n}切换到buffer n,b {bufname}等价于上面bp=bprev切换到上一个buffer,bn=bnext切换到下一个buffer,bf=bfirst切换到第一个buffer,bl=blast切换到最后一个Buffer%表示当前显示的buffer,#表示轮换的Buffer(使用<C-^>可以快速切换到轮换buffer)、- 删除buffer(不影响文件,删除的内存的数据)
bdelete
- 显示缓冲区列表
- 参数列表(
args)记录了启动时传递给vim的文件列表.这个不是固定的,是可以改变的.- glob模式打开文件
args *.*打开当前模式的任意文件,arg **/*.css,打开上一层目录中所有子目录包含的css文件,所以*只能在当前目录用,**可以递归进入子目录. - 参数列表执行shell命令 :args `pwd`
- glob模式打开文件
- 隐藏缓冲区
hidden buffer:- 当修改当前buffer后不保存想要切换到另一个buffer中需要加
!强制执行,此时被修改的Buffer有h标记表示变成hidden buffer. edit!重新将磁盘文件覆盖到当前被修改的Buffer中write=w将buffer内容写回到磁盘中qa!强制退出所有的窗口wa!所有buffer写回到磁盘
- 当修改当前buffer后不保存想要切换到另一个buffer中需要加
:argdo {cmd},对所有的缓冲区执行命令cmd
window(窗口)基本管理:
窗口是显示buffer的
打开新窗口默认的buffer是上一个窗口的buffer
创建窗口:
<C-w>s:水平切割窗口 水平当做split默认记<C-w>v:竖直切割窗口verticaledit给窗口更换buffer
创建窗口+更换buffer(
<C-w>s+edit):split {filename}vsplit {filename}
窗口切换:
<C-w> {hjkl}和normal mode下的移动是一样的<C-w>w在窗口间循环切换
关闭窗口(buffer是仍然存在的)
:close命令 关闭活动窗口:only命令 关闭除活动窗口外的所有窗口<C-w>c同上<C-w>o同上
窗口大小设置
<C-w>=窗口等宽,高.
类似
:argdo {cmd},:windo {cmd}是对所有的窗口执行cmd命令.例如 设置所有窗口的当前工作目录
:windo lcd Documents/
标签页将窗口分组
vim的标签页是vim窗口的容器,将窗口组织到工作区中,类比桌面workspace
- 创建标签页
tabedit {filename} - 关闭标签页
tabc{lose} - 关闭除当前标签页外的所有标签页
tabo{nly} - 标签页切换
- ex命令(不方便) 去第n个标签页:
:tabn {N}, 下一个标签页:tabn,上一个标签页tabp - normal mode: 去第n个标签页
{N}gt, 下一个标签页gt, 上一个标签页gT
- ex命令(不方便) 去第n个标签页:
- 标签页移动
tabm{ove} {N}:方便重新给标签页排序
基本文件管理
ex命令
edit打开文件:edit {filename}配置技巧: cmd mode下
:%%得到当前文件所在目录(配合edit使用)cnoremap <expr> %% getcmdtype() == ':' ? expand('%:h').'/' : '%%'vim默认的文件管理器,
edit {path}打开文件管理器窗口:edit %,%符号表示当前文件的完整路径:edit %:h,:h会去掉当前文件,只留下路径,vim打开一个不存在的文件后如何保存:
- 先创建此文件存在的目录:
!mkdir -p %:h - 保存文件就行
:w
- 先创建此文件存在的目录:
三.快速移动和快速转跳
行之间的基本移动:
实际行和屏幕行之间的移动
j和k命令会根据实际行,gj和gk按照屏幕行来上下移动.移动到行首
0,移动到屏幕行首g0移动到行首
^((自己单独做了映射)),移动到屏幕行首g^移动到行尾
$((自己单独做映射)),移动到屏幕行尾g$基于单词和字符串的移动
- 单词(之间)的移动
w下一个单词
b上一个单词
e单词的词尾
ge上一个单词的词尾字符串对应的移动()
vim的字符串比单词更简单,非空白字符序列组成(以空白字符分割):
W下一个字符串B上一个字符串E下一个字符串词尾gE上一个字符串词尾
基于字符查找的移动
通过normal mode下的
f{char}来快速移动,所以f{char}配置,和;移动非常快N,和n是重复搜索模式的查找.;和,是重复f命令的查找最好不要将
<Leader>映射为,
通过normal mode下
t{char}快速移动到查找字符的前一个字符,类似f{char}.f记忆为find,t记忆为
till,直到查找到指定的字符为止d/c配合t使用可以删除行中的指定的一段. 例如删除句子的后半句:f,dt.通过查找进行移动
/正向查找?反向查找删除某段的基本操作:
- 利用可视模式选中某段然后d删除
v/xx<CR>d,
删除某段的高级操作(利用操作符+动作,把查找看成动作理解)
d{motion}+查找动作 =d/xxx<CR>
- 利用可视模式选中某段然后d删除
使用文本对象 (第一类: 操作分隔符或者分隔符内部文本对象)
使用模式: 在visual mode或者操作符之后(操作符待决模式 operator-pending)
永远以a或者i(inner)开头出现,
aB/iB选中区块内的文本,at/it选中tag标签内的文本a/i+{char},char表示想选中一对符号中的其中一个,a(/a<,a",a[,a{,a'使用场景例如:
快速修改头文件
ci<快速删除
const char *的内容di"快速复制
const char *的内容yi"d配合a类文本对象(因为删除前后的空格),c配合i类文本对象(只选中文本对象,不修改前后的空格)使用文本对象 (第二类: 操作文本块)
iw/aw当前单词, (iw不包含空格)iW,aW当前字符串is,as当前句子ip,ap当前段落
使用位置标记(局部/全局)
标记当前光标位置:
m{a-zA-Z},小写buffer内可用,大写全局可用.(m表mark)跳转到光标位置: 反引号调转到标记位置, 单引号跳转到标记的行的位置.
单标记技巧:
mm来标记,``m`跳转回来vim默认的位置标记
- `` 两个反引号: 表示跳转之前的光标位置
- `. 上次修改的地方
- `^ 上次插入的地方
- `[ 上次修改或复制的起始位置
- `] 上次修改或复制的结束位置
- `< 上次高亮区的起始位置
- `> 上次高亮区的结束位置
%在当前行找到和当前字符匹配的项目,{}/[],()等,利用`` 反引号快速回到另一个匹配项的位置,然后r修改遍历跳转列表 (each window)
遍历改变列表
changes(each buffer)vim会记录每次修改的地方,
:changes查看所有修改.g;和g,遍历每次修改的光标位置
查看光标下的指定文件
gf,配合跳转命令<C-o>,和<C-i>跳去跳回
四.寄存器
常用寄存器
windows中的剪切(cut),复制(copy),粘贴(paste),
对应vim中的delete(剪切),yank(复制),put(粘贴).
windows使用的系统的剪贴板,vim默认使用的无名寄存器,
无名寄存器
""x,s,d{motion},c{motion},y{motion}命令即使指定了其他寄存器,但是无名寄存器也会有内容(无名寄存器发生总是缺省的)
黑洞寄存器
"_真正的删除文本,因为没有把内容复制到其他的寄存器上去.
"_diw,真正删除一个单词
复制专用寄存器
"0``y{motion}`命令复制的文本不仅在无名寄存器中,也在复制专用寄存器中.
Numbered register 0 contains the text from the most recent yank command,unless the command specified another register with [“x].
26个有名寄存器
"a-"z,- 如果使用大写字母引用,就是将新内容追加到原有内容之后.小写字母引用是覆盖.
系统剪切板
"+或者"*,- 通过外部寄存器可以与系统剪切板交换文本
表达式寄存器
"=.- 技巧1:在插入模式中当做计算器使用:
<C-r> =使用计算功能
- 技巧1:在插入模式中当做计算器使用:
只读寄存器
"%当前文件名"#上一个文件名".上次插入的文件":上次执行的ex命令
查找寄存器
"/,- 保存的是上一次查找的内容
寄存器内容替换高亮区文本
- 基本操作:
yiw->ve->"0p - 可视模式下的p会交换无名寄存器的内容,将寄存器内容填充到高亮区域,将高亮区域内容复制到无名寄存器中.
宏
宏的读取与执行
q{register}开始录制宏,q停止录制,@{register}执行宏,@@执行上一次执行的宏
- 录制宏的修改序列会保存到寄存器上.
加次数回放宏
f+->s +<C-[>->qq;.q->22@q
在连续的文本行上修改
串行操作: 录制宏完毕后执行
n次(宏里面有换行的操作)例如:
qa0f.r)w~jq->再执行3次宏3@a并行操作:宏录制完后,可视化选中然后执行·
:normal @{register}(对所有的行进行操作)例如:
qa0f.r)w~q->VG->:normal @a
给宏追加命令
用大写字母引用寄存器录制宏就行:
qa0f.r)w~q->追加j,qAjq就行.
在一组文件中执行宏(x)
给列表编号
使用let设一个变量后使用表达式寄存器插入.
:let i=0qaI<C-r>=i<CR>) <C-[>:let i+=1//目的是标号+1q然后并行执行宏
编辑宏的内容
- 先
"{register}p粘贴到当前文档中, - 然后再文档中修改宏的内容
- 然后
V"ay就能又覆盖到a寄存器中.完成修改宏内容.
五.模式
查找
1. 基本查找操作
/正向查找,?反向查找,n跳转到下一处,N跳转到上一处.
2. 高亮查找匹配
开启
hlsearch可以高亮所有匹配项,:noh暂时关闭高亮在
重新绘制屏幕的基础上增加 noh功能的新映射项配置:nnoremap <silent> <C-l> :<C-u>noh<CR><C-l>
3. 预览第一处匹配
- 开启:
set incsearch
4. 统计匹配个数
% s///gn
5.将光标偏移到查找匹配的结尾
光标默认会匹配于首字母上,
/{pattern}/{offset}<CR>,能够控制光标定位在匹配结果的附近,例如定位在匹配结果的结尾
/{pattern}/e<CR>或者已经进行了查找操作
/{pattern}<CR>,则//e<CR>,也能重定位光标
6.对完整的查找匹配进行操作
global/{pattern}/{cmd} 可以做到,
7. 向前查找当前光标下的单词
*
替换 (substitute命令
1. 完整格式:
[range]substitute/{pattern}/{string}/{flags}常用flags总结:
g一行的所有匹配项都发生替换,而不仅是一行的第一项n不进行替换,报告匹配项目数量c确认每一匹配项是否需要替换e没有匹配项时,不报告错误.&重复上次使用的标志位
替换域的特殊字符
\r换行符\t制表符\\反斜线\{n}插入第n个子匹配\0或&插入匹配模式的所有内容~上次的{string}\={vim script},执行表达式
2. 全局替换
利用标志位
g使得每行所有匹配项都替换,%表示所有行的范围:% s/{pattern}/{string}/g,就能实现全局替换.
3.手动控制每一次的替换
利用标志位
c(confirm),同上:% s/{pattern}/{string}/gcy替换此处,
n忽略此处
q退出此处
l 替换此处后退出
a 替换后面所有退出
4.重用上次查找模式
{pattern}留空,将使用上一次的查找模式,(上一次的substitute命令和/和?都算上一次查找模式)
5.用寄存器内容替换
查找域留空,使用上一次的,但是替换域留空,则空字符串替换,等价于删除
传寄存器的值,
:%s//<C-r>{register}/g,寄存器的值会直接复制到命令行上.(特殊字符需要提前进行转义)引用寄存器.
:%s//\=@{register}/g,如上,=表示执行vim脚本,@{register}在普通模式下是执行宏,在这里表示引用某个寄存器.固定场景(充分利用寄存器):
现在文档中复制替换的字符串(到”0寄存器中).
/查找所有替换域:%s//\=@0, 利用//表示上一次查找域,@0表示引用赋值寄存器. (充分利用了vim的特性)
6.重复上一次的substitute命令
- 重复上一次s命令:
:s//~/&,//表使用上一次的查找域,~表使用上一次替换字符串,&表使用上一次标志位. g&快捷键对应:%s//~/&,比上面多一个全局的范围,弥补没有加%的单次替换
global命令
1.完整格式:
:[range] global[!]/{pattern}/ [range][cmd]缺省的范围是
%,查找域留空//也是使用上一次的查找域. cmd缺省是print命令.还有
global!和vglobal命令,vglobal在匹配的行的剩下的行上执行命令.(v表示invert)清空寄存器:
q{register}q,没有指令就是空
2.利用global提取内容到寄存器
例:提取所有注释内容到寄存器B
:global/\/\//yank B,为什么要用大写,(小写 覆盖只剩下第一条匹配的,大写追加)
例:提取所有注释内容到文件尾部
:global/\/\//t$,
3.给指定区域属性排序
给单条规则(大括号内的属性)排序:
vi{:sort,(利用文本对象)- 给所有规则排序
:global/{/ .+1,/}/-1 sort解释:- ex命令会接受 范围 作为参数(也就是接受global传来的范围)
- [cmd],准确来说是
[range][cmd],也就是在传入的范围的基础上再次展开
.+1,/}/-1符合/{pattern}/{offset}模式,也就是在查找模式下偏移光标,.,/}/去掉偏移表示 从当前行开始到}行结束,
4. global的广义形式(global与任意ex命令组合范式)
:g/{start} .,{finish} [cmd]
例如给 {} 区域内文本缩进
:global/{/ .+1,/}/-1 >
基本操作-(单字母)
因为不熟悉单独拧出来
r替代一个字符,R替换模式(插入模式的一种特例)f{char}行内字符查找,F{char}行内字符反向查找s是删除后插入,S是删除整行后插入c是d是一样的类型(操作符),d是删除,c是修改,所以c后面接命令/次数,C修改至行尾- 和
A对应的在 行首插入的是I. t/T{char}将光标定位到前/后字符,t{char}可作为{motion}使用.m{position}在当前光标位置设置标记,:marks查看设置的标记,`{position}定位到标记处
其他模式
- 普通,插入,命令,可视化,模式外,还有一种模式叫做**
operator pending mode,操作符待决模式,意思就是输入了gu/d/c/y这个操作符,在状态栏可以看到情况,等待输入command来完成一个操作** - 在插入模式下,想执行一条普通模式的命令,使用
ctrl-o进入插入-普通模式,然后执行一条命令后就自动回到了插入模式 <C-g>在可视模式和选择模式切换,选择模式就是Windows的可视模式,输入使得选中的文本被删除
奇怪场景解决办法:
(以超级用户权限保存文件)在修改权限不够的文件后无法保存,只能退出重新sudo编辑的解决办法:
:write !sudo tee %原理:
write将当前Buffer内容作为 !{cmd}的标准输入,tee命令将标准输入转为文件,%表示当前文件名,所以就很好理解:将当前修改的Buffer的内容重新以root写到当前文件.
标准语法
操作=操作符+动作motion,可以在前缀时用可视模式替换后面的动作.
我尝试做的vim配置
1 | |
Surround.vim插件可以用用
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!