《vim实用技巧》笔记

=。=最近在看《vim实用技巧》
对一些内容作点简单的记录,方便以后查阅

Vim解决问题的方式

  • 多用.命令(一个微型宏)来重复一些简单的操作
  • 减少无关的移动,形成合理的撤销块
  • 善用复合命令减少操作
    A == $a,插入在行末
    C == c$,替换行末字符并持续插入
    s == cl,替换当前字符并持续插入
    S == ^c,替换前一字符并持续插入
    I == ^i,从行首开始编辑
    o == A<CR>,在下方插入新行
    O == ko,在上方插入新行
    ……
  • 尽可能使修改、移动变得可重复
  • 常用的重复与回退操作
    • 一般的修改{edit}
      .重复,u回退
    • 行内的查找[f|F|t|T]{char}
      ;重复,,回退 下
    • 文档内的查找[/|?]{pattern}<CR>
      n重复,N回退
    • 执行替换:s/target/replacement
      &重复,u回退
    • 执行一系列修改qx{changes}q
      @x重复,u回退
  • .范式
    用一个键移动,用另一个键执行的可重复修改操作

普通模式

  • 停顿思考时切换到普通模式
  • 合理地切分撤销单元(模式间的切换)
  • 如果在插入模式中移动的光标,将会产生一个新的撤销单元
  • 删除单词daw,可以解读为”delete a word”,该命令可重复
  • 简单的算术运算{num}<C-a>加法,{num}<C-x>减法
    不需要把光标移动到数字上
    运算为num加减当前光标或光标以后的数字
    注意:默认情况下0开头的数字会被当作八进制,0x开头则为十六进制
    可以通过set nrformats=关闭进制识别(都作为十进制数)
  • 重复&次数
    删除多个单词有两种风格——
    1. dw+.的重复风格
      常用风格,使用灵活,方便回退,无需数单词个数
    2. d2w2dw的次数风格
      多用于删除一整块词组,如a couple of;可以提高撤销单元的连贯性
  • 操作 = 操作符 + 动作命令{motion}
    • 操作符
      • c:修改
      • d:删除
      • y:复制到寄存器
      • g~:字母大小写反转
      • gu:字母转换为小写
      • gU:字母转换为大写
      • >:增加缩进
      • <:减小缩进
      • =:自动缩进
      • !:用外部程序过滤{motion}跨越的行
    • 动作命令
      • [h|j|k|l]:左下上右
      • [-|+]:上一行(下一行)的非空白字符
      • 0(数字):行首(含空白)
      • ^:行首(不含空白),即本行第一个非空白字符
      • $:行末
      • gg:文首
      • G:文末
      • [f|F|t|T]{char}:右侧(左侧)的第一个char字符
      • [;|,]:下一个(上一个)”f|F|t|T”的char字符
      • :{num}:至第num行
      • [w|b]:后一个(前一个)或当前单词的头部(尾部)——含符号
      • [W|B]:后一个(前一个)或当前单词的头部(尾部)——跳过符号(仅字母和数字包括负号)
      • ............................
      • 动作命令可以待有修饰符前缀
        • a:即an,表示一个非空白对象
        • i:即inner,表示一个内含对象
    • 当一个操作符被连续调用两次,就表示作用于当前行
      特例:g~~guugUU
  • 操作符待决模式
    键入操作符后vim会进入操作符待决模式,此时vim会等待一个动作命令后执行操作
    在该模式下可以按<ESC>来退回普通模式
    因为该模式的存在,使得自定义操作符及动作指令能够存在

插入模式

  • 单词输入错误,应删除整个单词再重新输入
    可以减少以后输入出错
  • 删除
    • <C-h>:删除前一个字符,相当于退格键
    • <C-w>:删除前一个单词
    • <C-u>:删除至行首
    • 注意:只能删除本次插入模式下插入的内容
    • 这些命令不是插入模式独有,也不是vim独有,在命令行模式、shell中都能使用它们
  • 切换到普通模式使用<C-[>更加方便
  • 插入-普通模式:<C-o>
    执行一个普通模式命令后,马上就可以返回到插入命令
    在插入模式下,通过<C-o>zz迅速把当前行移动到屏幕正中
  • 插入模式下的粘贴几个单词
    <C-r>{register}:将register号寄存器的内容粘贴到当前位置
    普通模式下复制文本默认保存在0号寄存器中
    注意:当文本比较多的时候,应切换到普通模式下操作比较合适
  • 运算
    <C-r>={expr}<CR>:执行expr运算并且把结果插入到当前位置
  • 用字符编码插入字符
    • 十进制ASCII字符:<C-v>{code}
      只能插入三位十进制数的ASCII码,注意高位补0
    • 十六进制unicode字符:<C-v>u{code}
      插入四位十六进制数的unicode码,注意高位补0
    • 通过二合字母插入字符
      <C-k>{char1}{char2}
      二合字母集可以通过:digraphs查看
      :digraph-table可以获得二合字母集更详细的信息
  • 查看当前字符的编码
    ga:屏幕下方会显示当前字符的十进制、十六进制、八进制编码信息
  • 虚拟替换模式
    R:替换模式,<Tab>会作为一个字符被替换
    gR:虚拟替换模式,<Tab>会作为多个字符(一般为八个)被逐个替换(直到末尾才替换掉<Tab>
    rgr同理~
    应尽量使用虚拟替换模式

可视模式

  • 三种可视模式
    1. v:操作字符文本
    2. V:操作行文本
    3. <C-v>:操作块文本
  • 该模式与其他模式不同,是先选择文本后触发命令
  • 选择模式<C-g>
    类似与windows的选择模式,输入的可见字符会替换掉选中的文本,之后vim进入插入模式
    这个模式只是为了迎合windows用户,应尽量少用
  • gv:重选上次的高亮选区
  • 该模式下的.命令有时候会出现异常
    所以应尽可能使用操作命令而不是可视命令
  • 有时候修改文本的范围很难用动作命令表达出来,这时候才用到可视命令
  • 修改多行文本时,只有第一行发生变化,只有当返回普通模式后,其他行才会发生变化
  • <C-v>不仅可以选中矩形的区域,还可以选中长短不一的块
    当在该模式下选中行末部分,可以实现长短不一的块的选择

命令行模式

  • 三种形式的命令行模式
    1. 按下:的Ex命令
    2. 按下/的查找命令
    3. <C-r>=访问表达式寄存器
  • 指定命令作用范围
    • 指定行
      :{number}....
      只包含数字的Ex命令表示跳转
      可以使用特殊符号$表示最后一行,%表示当前文件的所有行
    • 用地址来指定一个范围
      :{start},{end}....,执行命令后光标将跳转到end行
    • 用高亮选取指定范围
      先用可视模式v,V,<C-v>选取高亮区
      再按下:,此时命令行会自动填充成:'<,'>,表示作用在高亮区上
    • 用模式指定
      :/{pattern1},/{pattern2}/....
      例如::/<html>/,/<\/html>/指定了html内的所有内容(包含<html></html>
      注意:斜杠/有特殊含义,需要用反斜杠\转义
    • 地址偏移
      直接对地址进行+-运算
      如::/<html>/+1,/<\/html>/-1则排除了<html></html>而只包含了其中间的内容
      如果不加数字,默认偏移量为1
    • 特殊符号总结
      • 1:第一行
      • 0:虚拟行,位于第一行上方,常用于插入到首行等功能
      • $:最后一行
      • .:当前行
      • %:整个文件,相当于:1,$
      • 'm:包含位置标记m的行
      • '<'>:高亮选取的起始和结束行
  • 复制命令::t:co:copy
    :{range}t {address}
    与普通模式下的y命令不同,该命令不把文本保存到寄存器
  • 移动命令::move:m
    :{range}m {address}
  • 在指定范围上执行普通模式命令
    :{range}normal {commands},常用于多行的处理
    常用的命令如下:
    • :{range}normal .:对多行重复同一操作
    • :{range}normal A;:对多行末尾补上分号
    • :{range}normal i//:将多行内容注释掉
  • 重复上一条命令:@:
  • 使用<C-o>进入插入-普通模式时,命令记录会跳转到上一条命令,可以借此进行命令记录的跳转
  • 自动补全
    • <Tab>自动补全命令
      多次按<Tab>会正向遍历补全列表的内容
    • <S-Tab>反向遍历补全列表,S表示<shift>按键
    • <C-d>显示可用的补全列表
    • 自定义补全行为
      • bash shell形式:set wildmode=longest,list
      • zsh形式:set wildmenuset wildmode=full
        • wildmenu为补全导航列表
  • 将当前单词插入到命令行中
    常用于替换命令和查看帮助文档
    在命令行模式下,<C-r><C-w>会复制当前单词到命令行中
  • 回溯历史命令
    • 回溯所有命令
      :下保持提示符为空按<up>(<C-p>)和<down>(<C-n>)
      • <C-p>``<C-n><up>``<down>的区别
        前者方便,但不能过滤命令
        解决方法:
        .vim文件中创建映射项
        cnoremap <C-p> <Up>
        cnoremap <C-n> <Down>
    • 过滤回溯的命令
      :help<up>回溯以”help”开头的命令
    • 命令历史容量设置
      缺省只有20
      推荐set history=200
    • 除了Ex命令,查找命令也会记录下来并保存在另一个文件中
  • 一次性执行多条命令
    |隔开命令即可
  • 命令行窗口
    像一个常规的vim缓冲区,其中每一行是命令历史中的一个条目
    可以在该窗口下修改命令历史记录,对之前使用过的命令做调整后方便重复利用
    当打开命令行窗口时,它始终拥有焦点,除非关闭它,否则无法切换到其他窗口
    • q::打开Ex命令的命令行窗口
    • q/:打开查找命令的命令行窗口
    • <C-f>:从命令行模式切换到命令行窗口(起始命令行模式下输入的内容仍然保留下来)
  • 运行shell命令
    !{command}
    • %代表当前文件名
    • :shell可以打开一个交互式的shell会话(通过exit退出)
      更好的方法是用<C-z>挂起vim所属进程,用fp唤醒挂起的作业
      shell下的jobs命令可以查看当前的作业列表
  • 大量读取或写入命令输入输出
    :read !{cmd}将命令输出读取到当前缓冲区中
    :write !{cmd}:将当前缓冲区内容作为命令的标准输入
  • 借助shell命令过滤指定范围
    :{range}!{filter}
    如用sort命令,:2,$!sort -t ',' -k 2表示第2行到最后一行之间,以逗号为分隔符的第二字段排序
  • 常见的和操作缓冲区文本的Ex命令
    • :{range}d {x}:删除指定内容(并保存到寄存器x中)
    • :{range}y {x}:复制指定内容到寄存器x中
    • :{line}put {x}:在指定行后粘贴寄存器x中的内容
    • :{range}t {address}:复制指定内容到address处
    • :{range}m {address}:移动指定内容到address处
    • :{range}join:连接指定行内容
    • :{range}normal {commands}:对指定范围执行普通模式命令
    • :{range}s/{pattern}/{string}/{flag}:替换
    • :{range}global/{pattern}/{cmd}:对指定范围内匹配pattern的所有行执行cmd命令(Ex)

管理多个文件

缓冲区列表

文件读取后在内存缓冲区中

  • :ls命令可以列出所有被载入到内存中的缓冲区列表
    • 每个条目开头的数字为系统自动分配而不可改变的缓冲区编号
    • %:当前窗口中可见的缓冲区
    • #:轮换文件
      <C-^>可以在两个文件之间快速轮换
  • 缓冲区切换
    • 遍历缓冲区列表:
      • 正向移动::bn:bnext
      • 反向移动::bp:bprevious
    • :buffer {N}:跳转到指定编号的缓冲区
    • :buffer {bufname}:跳转到可以被bufname唯一标识的缓冲区(若多个缓冲区具有同一标识,可以通过<Tab>选择)
  • :bufdo {commands}:对所有缓冲区执行Ex命令
  • 创建快速遍历缓冲区列表的键盘映射

    nnoremap <silent> [b :bp<CR>  
    nnoremap <silent> ]b :bn<CR>  
    nnoremap <silent> [B :bfirst<CR>  
    nnoremap <silent> ]B :blast<CR>  
    
  • 删除:bd:bdelect
    :bd {N1,N2,N3....}:删除列出的缓冲区
    :{N,M} bd:删除连续的缓冲区

参数列表

对一批文件进行分组,其文件顺序可调整*

  • 初始的参数列表为启动时vim的文件列表
  • :args:查看参数列表
    其中[]表明了当前的活动文件
  • :args {arglist}:填充参数列表
    arglist可以是文件名、通配符、shell命令的输出结果等
    • 用文件名指定文件
      :args {file1,file2,....}
    • 用Glob模式指定文件
      *:表示0到无穷多个字符,但不包含子目录
      **:表示0到无穷多个字符,包含子目录
    • 用反引号结构指定文件
      将shell命令用反引号括起来,其输出将填充到相应的位置
      如::args \cat .chapters``
  • 隐藏缓冲区
    缓冲区列表中,+代表缓冲区被修改过,此时切换缓冲区会弹出错误信息,可以用感叹号强制切换,此时列表中被标记为a的为活动缓冲区(active),被标记为h的为隐藏活动区(hidden)
    • 处理隐藏缓冲区
      • :w:write:写入磁盘
      • :e:edit:从磁盘中读入到缓冲区(回滚修改操作)
      • :qa:qall:关闭所有窗口,放弃所有修改
      • :wa:wall:全部写入磁盘
    • :argdo:bufdo修改一组缓冲区
      前提:打开hidden选项
      打开后,对已修改的缓冲区执行:next,:bnext,cnext等命令无需再加感叹号

窗口

  • 分割
    • <C-w>s:水平切分(同高度),新窗口仍为当前缓冲区
    • <C-w>v:垂直切分(同宽度),新窗口仍未当前缓冲区
    • :sp {file}:split {file}:水平切分,新窗口为file内容
    • :vsp {file}:vsplit {file}:垂直切分,新窗口为file内容
  • 切换
    • <C-w>w:轮换
    • <C-w>{h|j|k|l}:切换到左(下上右)侧的窗口
    • 若为GVIM,可以直接点击对用窗口进行切换
  • 关闭
    • :clo:close<C-w>c:关闭当前窗口
    • :on:only<C-w>o:关闭其他重口
  • 改变窗口大小和重排列
    • <C-w>=:使所有窗口等宽、等高
    • <C-w>_:使当前窗口高度最大化
    • <C-w>|:使当前窗口宽度最大化
    • {N}<C-w>_:使当前窗口高度调整为N行
    • {N}<C-w>|:使当前窗口宽度调整为N列
    • 若为GVIM,可以直接用鼠标拖动窗口的分界线

标签页

对窗口进行分组

  • :lcd {path}:设置工作路径
    限定标签页的工程范围
    • 只能改变当前窗口,而不是当前标签页
    • 如果要改变标签页的所有窗口,应用:windo lcd {path}
  • 打开和关闭
    • :tabe {file}tabedit {file}:在新标签页中打开file
    • <C-w>T:将当前窗口移动到一个新标签页
    • :tabc:tabclos:关闭当前标签页及其所有窗口
    • :tabo:tabonly:关闭其他标签页及其所有窗口
  • 切换
    • 标签页从1开始编号
    • :tabn {N}:tabnext {N}{N}gt:切换到N号标签页
    • :tabn:tabnextgt:切换到下一标签页
    • :tabp:tabpreviousgT:切换到上一标签页
  • 重排列
    • :tabmove {N}:将当前标签页移动到N号标签页之后
      • :tabmove 0:表示移动到开头
      • :tabmove:表示移动到末尾
    • 若为GVIM,可以直接用鼠标拖曳

打开及保存文件