首页
归档
友情链接
关于
Search
1
在wsl2中安装archlinux
80 阅读
2
nvim番外之将配置的插件管理器更新为lazy
58 阅读
3
2018总结与2019规划
54 阅读
4
PDF标准详解(五)——图形状态
33 阅读
5
为 MariaDB 配置远程访问权限
30 阅读
心灵鸡汤
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
archlinux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
菜谱
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
登录
Search
标签搜索
c++
c
学习笔记
windows
文本操作术
编辑器
NeoVim
Vim
win32
VimScript
Java
emacs
linux
文本编辑器
elisp
反汇编
OLEDB
数据库编程
数据结构
内核编程
Masimaro
累计撰写
308
篇文章
累计收到
27
条评论
首页
栏目
心灵鸡汤
软件与环境配置
博客搭建
从0开始配置vim
Vim 从嫌弃到依赖
archlinux
Emacs
MySQL
Git与Github
AndroidStudio
cmake
读书笔记
菜谱
编程
PDF 标准
从0自制解释器
qt
C/C++语言
Windows 编程
Python
Java
算法与数据结构
PE结构
页面
归档
友情链接
关于
搜索到
58
篇与
的结果
2022-06-13
vim 从嫌弃到依赖(17)——查找模式
最开始介绍vim的时候,提到vim有普通模式、插入模式、可视模式和命令行模式,并且已经对这几个模式做了详细的介绍了。除了这几个模式以外,vim还有一个非常强大的模式——查找模式,为什么最开始没有将其列举出来呢,这是因为我很少看到有教程将它与前面介绍的模式并列作为一个新的模式。但是在日常使用中,我又习惯将它叫做查找模式。我在这里就不深究这些了,请读者自行判断。插入模式使用我们可以在普通模式下输入 / 进入插入模式。在其后面输入想要查找的字符串,按下<CR> 进行查找。此时vim光标会自动跳转到匹配的位置,并将对应位置高亮显示( 这个是 neovim的特性,vim高亮可能需要一些配置)。使用 <Esc> 将会结束查找,退回到普通模式。在匹配模式中,可以使用 n 来跳转到下一个匹配位置,按下N 将跳转到上一个匹配位置。这个查找是循环进行的,也就说在跳转到最后一个匹配位置之后,再使用 n 将会跳转到第一个匹配位置。我们可以使用 wrapscan 这个选项关闭这一特性,例如在neovim 中使用如下代码vim.o.wrapscan = false或者在vim中使用这样的代码set nowrapscan在查找模式中,可以使用 <UP> (也就是方向键) 来遍历之前查找项。取消高亮的匹配vim 中可以使用 hlsearch 来设置将匹配项进行高亮显示( neovim 则默认支持该项) 。高亮显示匹配项这个特征在我们寻找这些匹配项的位置时十分有用,但是一旦找到想去的地方之后,这些高亮显示的内容却会干扰我们的视线,特别是匹配项过多的时候。这个时候我们可以使用 noh 来取消高亮。但是每次这么输入比较麻烦,我们可以绑定一个快捷键,快速取消高亮。这里还是等到介绍配置的时候再介绍吧。执行前预览第一处匹配在一般的vim中,一定要等到输入完完整的内容,然后按下 <CR> 键之后才会进行匹配,而执行前预览会在每次有新输入的时候更新匹配。类似于下面的效果。输入 s 的时候,所有 s 字符都被选中,输入后面的内容时再次匹配,只高亮匹配上的。vim模式并未开启这个效果,可以使用 incsearch 来激活这一效果。而neovim则默认支持这一选项。快速选中光标所在单词进行搜索这里主要为了介绍 *这个命令,当光标处于目标单词的时候,按下 * 将直接进行搜索。将光标移动到匹配的结尾默认情况下,使用匹配模式时,光标都在匹配字符串的开头位置,我们可以在搜索结尾处添加 /e 来让vim将光标移动到匹配字符串的结尾处相信通过这篇文章各位小伙伴已经初步了解了如何进行查找,但这些内容是远远不够的,vim提供了强大的搜索处理能力,在下一篇我们将慢慢展开介绍。
2022年06月13日
7 阅读
0 评论
0 点赞
2022-06-08
vim 从嫌弃到依赖(16)——宏
终于到了我第二喜欢的vim功能了(当然了,最喜欢的是.命令)。我原本计划在介绍完.命令之后介绍宏,以便让各位小伙伴们能了解到vim对于重复操作进行的强大的优化。但是由于宏本身跟寄存器息息相关,所以还是忍痛割爱,将它放到寄存器之后。废话不多说让我们开始吧。宏的基本使用我们还是以一个例子进入相应的内容。我要将下面这段代码foot = 'foot' ball = 'ball' football = foot + ball变为这样var foot = 'foot'; var ball = 'ball'; var football = foot + ball;通过分析它这三行其实做的都是同样的功能,即在每行的行首添加 var 关键字,然后在每行的行尾添加分号。我们可以利用之前介绍的.命令或者针对列的可视模式来处理,只是不管用哪种方法都需要至少两次操作。问题先放在这里,让我们先了解下什么是宏,以及怎么用宏。宏是存储在寄存器中的连续的操作指令,以便后续可以对这些指令进行回放。可以使用 q 进行录制,后面跟寄存器名称,表示将接下来的操作记录保存到这个寄存器中。例如使用 qa 表示将接下来的操作保存到 a 这个寄存器中。退出宏的录制可以直接输入 q针对上面的例子,我们可以执行 qa 进行宏的录制,然后使用 A 在行尾进入插入模式,接着输入 ; 完成行尾的操作。然后使用 I 进入行首,然后在行首输入 var 完成这部分的工作。最后使用 q 退出宏的录制。这样就将这个宏保存在了a 寄存器.我们可以使用 :reg a 来查看寄存器的内容。这个内容完全是我们之前通过键盘输入到vim中的内容,只是返回到普通模式输入的是<Esc> 而这个保存的是^[ 因为宏有自己的键盘编码方式,这个方式我觉得不需要特别去查去记,自己就可以从寄存器中查到。宏录制完成之后,可以使用 @ + 寄存器 来回放寄存器中保存的宏。在回放宏之后可以使用 @@ 来快速回放上一次回放的宏。到现在各位小伙伴可能已经发现了,它与.命令比较类似,只能机械的执行之前执行过的内容,它无法做到智能化,例如我在录制宏的过程中使用了诸如 2w之类的命令,后面在重复的时候很有可能发生错误。这就要求我们在使用宏的过程中,尽量规范化光标移动,不要搞这种特例的形式。就像写代码不要写死一样。这里我们还是手动执行了好多次同样的宏,宏与普通的operator 一行支持前面加数字表示重复,例如2@a 表示重复执行两次这个宏。上面的例子我们可以稍微做一下修改,即在最后添加一步将光标移动到下一行的操作——j。然后使用这个特性进行重复。仔细点可以发现,我们执行了3次这个宏,也就是要执行3次j 操作,但是我们是在第二行执行的宏,也就是剩下的行只允许我们执行一次j 。这里虽然有问题,但是宏还是正确的对文本进行了修改。这是因为 vim 宏在 motion 执行失败之后会终止执行,这个并不是一个 bug,而是一个特性,也就是说利用这个特性我们可以更好的使用宏。例如上述例子中,宏只执行了一次 j ,第二次执行到j 的时候出错了,于是就停下来了。这就告诉我们不用关心剩下的操作需要重复多少次,只需要给出一个足够大的数,保证已有行能正常进行修改就可以了。我们再来看一个例子将1. one 2. two 3. three 4. four 5. five 6. six 7. seven 8. eight 9. nine 10. ten改为1) One 2) Two 3) Three 4) Four 5) Five 6) Six 7) Seven 8) Eight 9) Nine 10) Ten我们可以这么归纳这个操作,从行首开始找第一个 .,然后执行替换操作将其替换为 )然后找到下一个单词,将首字母改为大写。我们可以在宏中执行 0f.r)w~j最后退出。读一下这段内容, ~之前没见过吧。之前介绍过,gU和 gu后面可以跟 motion表示将对应范围的字符转化为大写和小写。g~可以进行大小写反转。而这里的~直接将当前光标所在字符进行反转。上述命令我们首先使用 0将光标至于行首,这样就规范了每行的查找操作。另外这里由于 10 有两个字符,所以这里使用 f 来查找而不仅仅使用 l往后移动一个字符,最后我们不确定. 和单词之间会不会有空格。所以这里最好是使用 w 而不是 l 。这些细节体现了我们之前说的要更加规范的移动光标。宏录制完了之后,我们可以利用之前介绍的 motion失败会终止执行的特性,不用数需要处理多少行,直接 10@a(因为第一行已经处理了,所以这里只有9行待处理)以并行的方式执行宏我们将上述例子进行变更1. one 2. two 3. three 4. four // do something 5. five 6. six 7. seven 8. eight 9. nine 10. ten执行上次录制的宏,发现它在第5行的位置停止了,因为在第5行中未找到 .,所以它终止了,为了继续运行,需要手动跳过,然后继续执行。假设我们有多处有注释,每次遇到问题就停下来,再手工执行,会显得比较麻烦。为了解决这个问题,我们使用vim提供的另外一种执行宏的方式——以并行的方式执行。重新录制宏,与之前相比,只需要将j这个操作给去除掉。然后使用针对行的可视模式,选中待处理行,然后针对这些选中行来执行宏。我们在这里来审视一下这两种方式,并行方式需要提供重复次数,它是第一次执行完了接着执行下一次,下一次的执行依赖于上一次成功的执行。并行则不然,并行是针对选中部分,同时执行一个宏操作。即使中间有错也不影响其他行的运行。给宏追加命令还是上面的例子,假设在录制好了宏之后发现我们少了一个j,使用串行话的方式无法顺利执行。这种情况下不需要重新录制宏,只需要在对应寄存器中添加一条指令。这里补充一下寄存器相关知识。在上一篇介绍寄存器的时候我们只演示了使用小写字母的寄存器,没有提到大写字母的寄存器。根据之前的惯例,大写字母与小写字母都可以使用,大写字母的功能比小写字母要强,例如大写的标签标示全局,小写的只能用于单个文件。这里大写的寄存器与小写的寄存器是同一个寄存器,使用大写时我们可以对寄存器内容进行追加操作。宏是保存在寄存器中的,q 后面加字母表示宏的内容保存在哪个寄存器中,说到这里,聪明的你已经反应过来该如何将命令追加到寄存器中了。那就是使用 q+大写字母。针对并行操作的例子,假设已经录好其他操作只差一个j 了,我们可以使用 qA 进行追加,然后添加 j 操作即可追加前宏的内容如下: 添加完成之后,宏变成了如下内容后面就可以以串行的方式执行这个宏了配合文件参数列表使用宏之前介绍过文件参数列表,即使用 :args 可以对文件进行分组,各位小伙伴可能只知道这个,但是没找到它的使用场景。也不知道vim提供这个功能有什么用处。在这里我们就来看看它的一个使用场景。我们还是以之前的 neovim 配置文件的工程为例,我要在每个lua文件中添加一行注释 --this is add by vim macro 。打开一个 lua 文件之后,使用 :args **/*.lua 来将每个 lua 文件加入到参数列表中。然后随意打开一个 lua 文件,在录制宏的时候执行 ggO<ESC>S--this is add by vim macro 然后退出。这里还是贯彻了前面说的要是移动更加规范,我们先用 gg 移动到第一行,以便能准确的在首行插入内容。由于在 lua 文件中有注释的话使用 O 添加一行的时候它会自动添加一个注释。但是不能确保所有的 lua 文件在行首都有注释,所以我们先使用 S 删除一行并进入插入模式。当然通过配置也可以取消这个特性,等介绍到文件类型的时候再来讨论这个。此时文件已经发生了变化,如果我们直接执行宏的话,之前录制时修改的文件将会两次执行相同的命令,所以这里不能保存,可以执行 :edit! 放弃本次修改,或者如果已经修改了的,可以执行u进行回退。结合之前介绍的在命令模式中执行普通模式的命令,可以使用 :argdo normal @a 。argdo 表示循环对参数列表中的每个文件执行相同的操作。录制宏:添加参数列表:执行宏上述的操作方式采用的是并行的执行宏,我们可以对其进行一些修改,让其支持串行的方式。还记得之前介绍的怎么遍历参数列表吗,不记得也没关系。我们可以使用 :next 来访问下一个,:prev 来访问上一个。配合之前的命令可以使用 ggO<Esc>S--this is add by vim macro:next。我们无法知道参数列表中到底有多少个文件,但是可以利用失败即终止这个特性输入一个足够大的数字即可,例如 100@a即可。这样就省去了执行命令模式中命令的相关操作。对比两个宏发现我只需要在之前的宏后面添加一个 :next 指令即可,所以这里就直接执行了 qA:nextq对比上面两种方式发现,并行执行的时候中间某个缓冲区如果出错并不影响其他缓冲区的执行,这就给我们排查造成了一定的问题,一旦出错我们不得不打开每一个缓冲区查看执行的结果来找到出错的位置。而串行则会停在出错的位置,我们只要针对出错的部分做一定的调整,然后继续执行就好了。而且这个例子中列表参数并不会循环遍历,也就不用担心之前修改过的内容又被修改。编辑宏内容上面我们说到宏是保存在寄存器中的一组操作指令,既然可以利用往寄存器中追加内容的方式往宏中追加指令,那么是不是我只要更新了寄存器中的内容,在执行宏的时候命令就会改变呢?如果你能这么想,那么恭喜你都会抢答了,而且答对了!还是以上面那个添加注释的例子为例,假设我之前忘记了删除新添加的 --,也就是我录入的宏变成了 ggOthis is add by vim macro 我们会发现在第一行是注释的文本中它的表现是正常的,但是第一行不是注释,添加的就是有问题的,例如 nvim-config/lua/config/auto-session.lua。我们发现了这个问题需要对这个宏进行修改。首先我们需要将 宏从寄存器中放到编辑器中,这就要使用 :put a取出寄存器中的内容,你可能会疑惑为什么不用 "ap 呢,这是因为 p 命令默认会将寄存器中的内容放到光标所在位置的后面,而 :put 则会直接放到下一行,所以这里还是放入到当前命令之后要好。接着修改一下这个宏。在对应位置加上 S 这个操作,最后使用 0d$ 从行首粘贴到行尾,注意这里尽量不要使用 dd,它会连带着换行符一块进行粘贴,可能会破坏宏的指令。最后我们可以先删除之前粘贴的一行,再重新执行这个宏最后的叨叨宏是vim提供的很有用的功能,希望我通过本文让各位小伙伴对它有一个初步的认识,想要用好宏这个强大的工具还是需要花大量的时间去学习研究的。vim这个工具也是常用常学常新的,时不时你就能发现自己当初不知道的内容,就像有小伙伴给我留言给我介绍了一些我之前不知道的命令,在这里对所有给我留言的小伙伴表示感谢。vim的指令实在太多了,指望我把所有好用的一一介绍,文章的篇幅就显的太长了,这里我就不加了,各位小伙伴有什么好用的方式也可以留言给其他不会的小伙伴一个学习的机会。大家一起共同进步。谢谢大家
2022年06月08日
8 阅读
0 评论
0 点赞
2022-06-02
vim 从嫌弃到依赖(15)——寄存器
在计算机里面也有寄存器,计算机中的寄存器是看得见,摸得着的实体,寄存器中存储需要经常访问的一些数据。而vim中也有寄存器的概念,vim中的寄存器是一个虚拟的概念,更像是一块专门用来存储数据的内存缓冲区。在使用vim的过程中离不开寄存器,而且我们很早就用到了寄存器,只是没有发现罢了。这篇文章将深入介绍寄存器,这样我们对之前使用的命令将会有更深的认识。几种寄存器类型无名寄存器在之前介绍过,可以使用d来删除一段内容,使用p来粘贴,使用y来复制, vim中其他的带有删除功能的operator 像 x、c、s 之类的,vim在删除之前会将被删除内容先放到无名寄存器中,然后执行删除操作。严格意义上来说,他们并不是删除而是剪切。后续可以通过p 命令来粘贴之前被删除的内容例如print("hello world") print("")改为print("") print("hello world")就可以在第一行通过di",将被删除的内容存储到无名寄存器中,然后在第二行对应位置执行 p (或者P) 命令取出无名寄存器中的内容。这里在使用h 移动光标之后,光标所在位置在后一个引号的位置,为了减少一次光标移动,我直接使用P 在光标所在位置之前进行粘贴操作。这里插一个题外话,vim中的命令都是某些有意义的单词的首字母或者几个字母的缩写,像d代表delete、y代表yank,那么p又代表什么呢,粘贴的英文是paste,但是知道寄存器以及复制粘贴在vim的表现,我觉得应该是put,就是将寄存器中的内存拿出来。好在他们的首字母相同,不影响记忆。有名寄存器它是对应无名寄存器来说的,无名寄存器虽然说使用方便,但是有一个很大的问题,那就是如果我们连续两次执行了删除或者复制操作,那么前一次保存的内容将会被后一次的给覆盖掉。为了解决这个问题,一个思路就是使用有名寄存器。vim中提供了由a到z的有名寄存器,可以在使用operator 的操作前面指定需要使用的寄存器,引用一个寄存器可以使用 " + 寄存器名的格式。这个时候我们之前的公式就又可以扩展了" + regester + operator + motion例如在执行删除的时候 "add 将一行删除的内容放到a寄存器中,再次执行"bdd将内容放到b寄存器中,执行粘贴的时候,可以使用"ap和 "bp来分别使用 a和b寄存器的内容。无名寄存器有一个专用的符号,使用 "来表示。也就是说dd 命令其实等效为 ""dd。但是为了偷懒和方便,还是少输几个字符的好。复制寄存器前面说到使用 dd 之类的命令会将被删除的内容放到无名的寄存器中,它的行为有点像普通编辑器中的剪切,那它是不是剪切呢,那么多教程都把它叫做删除,是不是有问题呢。它确实是删除指定,教程说的也没错,vim中有专门存储复制内容的寄存器。普通的删除命令会把被删除的内容保存到无名寄存器中,但是这些内容不会被保存到复制寄存器中。复制寄存器使用 0来表示。即我们可以使用 "0p来将复制寄存器的内容取出。也可以通过命令 :reg 0来查看这个寄存器的内容。在上述例子中,我们先在第一行执行 yy 操作进行复制,这个时候数据会被同时保存到无名寄存器和复制寄存器。然后在第二行执行 dd 删除,这个时候第二行的数据会被保存到无名寄存器,之前保存的第一行的数据就被删除了,但是不会被保存到复制寄存器,第一行的数据仍然存储在赋值寄存器。接着立即执行p 它会从无名寄存器中中取出我们之前删除的第二行的数据。接着再执行"0p 会从复制寄存器中取数据,这个时候取出的仍然是第一行的数据。黑洞寄存器前面说到 dd会将被删除内容放入到无名寄存器中,如果这段内容我确实不想要了,也不想它占用寄存器,有没有什么办法彻底删除呢,答案是使用黑洞寄存器,顾名思义,放入该寄存器中的内容都被吸走丢失了,无法使用了。黑洞寄存器使用 _作为标识符,执行删除指令的时候可以使用 "_dd这样就再也访问不到之前删除的内容了。在上面的例子中,我们先执行普通的dd 命令,它会将删除内容放入到无名寄存器中,第二次执行的是 "_dd ,它会将内容放到黑洞寄存器中直接丢弃,后面执行p 的时候只会粘贴第一次删除的内容。有小伙伴可能会说,这个跟我使用其他有名寄存器效果是一样的。看不出什么区别,那么我们可以试试使用 :reg 命令来查看有名寄存器和黑洞寄存器的值,我们发现黑洞寄存器的值永远为空,而有名寄存器此时多了一条记录。系统剪切板之前我们在vim中复制粘贴的内容,只能在vim中使用。同样的系统中复制粘贴的内容只能在系统其它程序中使用,无法直接粘贴到vim中。我们可以在vim中使用系统剪切板。vim可以使用+来访问系统剪切板。例如使用 "+yy将内容复制到系统剪切板中,供其他程序使用。但是在有好的shell工具的加持下,我更喜欢用<Ctrl+v>这样的方式直接粘贴一大段文字到vim中。或者配合vim的可视模式,直接使用shell中的快捷键从vim中粘贴选中的内容到系统剪切板表达式寄存器前面介绍的几种寄存器都是被动的存储静态的内容,只有存储功能。表达式寄存器则可以接受一段vim脚本并执行它并输出结果。表达式寄存器使用 =来表示。例如在插入模式中可以使用 <Ctrl+r>=6*6 来进行数学计算并输出。到此已经介绍完了vim中几种主要的寄存器,是不是觉得挺抽象的,而且用起来也不是那么方便。下面我们还是以例子来展示相关用法。示例示例1:复制粘贴的使用假设我们要将如下代码print("hello world") print("hello vim")修改为print("hello world") print("hello world")可以在第一行使用 yi"来复制引号内的内容,但是如果在第二行先使用 ci"再使用 p进行粘贴的话会发现粘贴的仍然是hello vim这是因为后面使用c操作的时候,已经将原来的给覆盖掉了。现在我们来解决这个问题。第一种解法:y指令可以额外产生一个动作,它会将内容放入到复制寄存器中,那么在执行了ci"之后使用 "0p来使用复制寄存器中的内容第二种解法:可以手动指定ci"删除的内容放入到黑洞寄存器中,即执行"_ci"这样就不会产生覆盖问题。前两种方法虽然解决问题了,但是都引入了新的寄存器,按键比较繁琐,如果不想引入新寄存器,就得使用接下来介绍的第三种方法了,它也是我最喜欢的方法了。解法三:由于我们需要先删除之前的内容再复制,为了快速删除,所以会发生覆盖问题,我们只要不执行删除操作就不会覆盖了,为了一次性完成粘贴替换的操作,可以使用选择模式,之前介绍选择模式的时候说过,在选择模式下operator 会将选中部分作为操作区域。可以使用 vi" 来选中引号内容,然后直接使用 p 完成复制示例2:插入模式中使用寄存器之前已经在介绍表达式寄存器的时候已经介绍了如何在插入模式中使用寄存器,可以使用 <Ctrl + r> + register 例如上面的例子可以使用 <Ctrl + r>0来将复制寄存器中的内容写入到光标所在位置。相比上面介绍的前两种解法,它省去了切换回普通模式的步骤,相对来说更高效一点。但是我觉得它还是比不上第三种解法。示例三: 处理粘贴混乱的问题有的时候在粘贴代码的时候发现代码的格式可能会乱,这个时候可以设置 :set paste选项,设置之后复制粘贴将不再出现这个问题,但是它会使我们在其他模式下设置的快捷键失效,在粘贴完了之后可以使用 :set nopaste取消该设置。由于我使用的neovim中没有发现这个问题,就不演示了,各位使用vim的小伙伴可以自行测试。当然处理该问题的另一种方式是使用之前介绍的在vim中使用剪切板的方法,也就是使用 "+p这样的形式。
2022年06月02日
6 阅读
0 评论
0 点赞
2022-05-31
vim 从嫌弃到依赖(14)——快速跳转
之前介绍过众多的motion,根据移动范围来排序的话有 l、e、w、j等等,但是面对那么长的代码文件,仅仅使用这几个简单的motion不知道要移动多少次才能找到我想要的代码,这个速度有时候还不如我用鼠标移动光标。vim作为编辑器之神当然提供了快速移动光标的方式了,这篇文章我们就来了解一下如何使用vim在代码间进行快速跳转。利用标签,快速跳转vim中提供了标签的方式进行跳转,事先可以在对应位置设置标签,后面通过标签访问该标签所在位置可以使用m{a-z} 来在任意位置设置标记,而后使用`{a-z}来回到对应标记位置。该命令可以回到之前设置标签时光标所在行和列。vim可以支持从a到z的26个位置标记,一般来说我们用不到这么多,即使你能全部用到,可能早就忘了前面标记的在哪个位置了。这种方式有一个最大的问题就是在标记之后从显示上无法知道我们的标记位于何处。除了由用户主动使用m 来设置位置标记以外,vim还会自动为我们设置标记,例如上次修改、上次跳转、上次高亮等等。下表列举出了,如何回到这些vim自动标记所在位置位置标记含义\`\`当前文件中上次跳转动作之前所处的位置\`.上次修改的地方\`^上次进入插入模式的位置\`[上次修改或者复制的起始位置\`]上次修改或者复制的结尾位置\`<上次高亮选区的起始位置\`>上次高亮选区的结尾位置在匹配的括号间进行跳转可以使用 % 在一组括号中使用,可以跳转到下一个匹配的()、[]、{}。例如下列操作我们可以配合operator 来使用,删除括号中的内容。例如下面的代码var foo = { "obj":{ "test": "1", "arr": [1, 2, 3] } }可以使用将光标移动到对应的位置,然后使用d% 就可以删除对应的内容了。当然也可以使用文本对象来进行跳转列表浏览器中会记录浏览历史,并且提供了去到上一页和下一页的功能。vim中也提供了类似的功能,vim会记录我们每一次的跳转,可以通过相关命令来跳转到上一次跳转和下一次跳转的位置。我们先介绍什么是跳转。跳转似乎很容易理解,似乎光标每次的移动都算是一次跳转。但是vim中的跳转并不是这样的。我们可以先这样理解,motion 允许我们在一个文件中进行移动。而跳转则是不同文件间的移动。就像在浏览器中从一个页面打开另一个页面。为了类比浏览器的操作,你也可以把每次跳转记录理解成历史访问文件的记录。可以使用:jumps 来查看跳转记录。从上图中可以看到这样几个现象:跳转列表中记录了所在文件以及上次光标所在的行和列。最后几行由于我们处在当前文件中,所以没有列出文件名称来,而是直接给出光标所在行的文本内容,由于我这里打开文件之后立即查看了跳转列表,光标处于第0行这个虚拟行,所以会显示空白内容。它记录了光标所在的行列,所以后面我们在恢复的时候可以直接定位到具体位置。与浏览器类似,之前打开vim的时候访问文件的记录也在里面,它并没有随着vim的关闭而被清除。任何能改变当前窗口中活动文件的命令都可以作为跳转命令,像find、edit 之类的。了解了跳转列表之后,我们现在来访问一下这个跳转列表。可以使用<Ctrl + i> 来访问前一个跳转,<Ctrl + o> 来访问后一个跳转。在nvim-config 中随意打开一个文件,然后使用edit 打开另一个,接着就可以使用<Ctrl + i> 和 <Ctrl + o> 在两个文件中切换了我们再来联想一下浏览器中的历史记录,我们发现有时候访问同一个页面的不同位置可能会产生多条历史记录。例如访问同一页面的不同锚点。那么我们之前说的将跳转理解为历史文件访问记录可能就不对了,同一个文件也可以产生多个跳转记录。 例如gg(G)、%、\{a-z}等等。而h j k l w f之类的就不作为一次跳转。用一句话来总结就是大范围的光标移动才会被作为一次跳转。什么会被作为大范围的移动呢?我个人的理解是一次移动有能力移动至少半屏,而像50j 之类的虽然也可以移动50行,也达到半屏以上,但是前面加数字表示的是重复,它是重复了多次,并不算一次移动。我们使用 split 或者 vsplit 再打开一个新的窗口,然后在两个窗口中分别使用:jumps 发现二者并不相同。vim可以维护多套跳转列表,每个窗口都有自己的一套独立的跳转列表。这个与浏览器中的也类似,新窗口并不能进行前进和后退操作,而且只两个操作也只能跳转到由这个窗口打开的网页上。改变列表回忆一下,我们不管在文件的哪个位置,使用u撤销修改的时候光标总能跳转到对应修改的位置,或者使用\. 能回到上次修改的位置。如果以前没有注意这个细节的,也可以现在试试。vim在会话期间会维护一张表,表里记录了每个缓冲区的每一次修改。这个就是所谓的改变列表。可以使用:changes 来查看这个列表这个列表与跳转列表类似,都标记了行号与列号。我们可以通过g; 和 g, 来访问下一个和上一个记录。你可以拿;和, 来类比记忆。这两个操作符是配合f来使用的。; 移动到下一个匹配位置,, 移动到下一个匹配位置。我们可以使用\.来跳转到上一次修改的位置,而 `^则更具体一点。它代表的是上一次退出插入模式光标所在位置。如果我们在做出修改并且退出插入模式之后,移动光标查看了下其他类似代码的实现,然后想快速回到之前编辑的位置继续编辑,可以使用 `^将光标移动到对应位置,然后使用i进入插入模式,当然也可以使用gi 一步到位,直接从上次编辑位置进入插入模式。需要注意的是,vim会为每一个打开的窗口维护一个跳转列表,但是更新列表只有一个,而且跳转列表并不会随着vim的退出而消失,但是改变列表则会随着vim的退出而被清空。跳转到光标下的文件在我们将当前项目所在的所有路径加入到path中之后(即在项目根目录中执行:set path+=./**)可:set 以将光标移动到对应表示相对路径的代码上,执行gf 即可跳转到对应文件。在上面的例子中,我们只写了settings 这样的文件,它是如何知道要打开 settings.lua 文件的呢,或者说如果有类似的settings.h 或者 settings.js 在同一个位置的话,它该打开哪一个呢?比如说我们新建一个settings.h 在同样的目录中,再次执行之前的操作,发现它还是能够正确的打开settings.luavim 中有一个suffixesadd 变量,它保存的当前缓冲区中执行gf操作时,可以使用的扩展。我们可以像设置path 一样,例如:set suffixesadd+=.java 来允许打开java文件。使用gf 也是一个跳转,也会被记录到跳转列表中,后续我们可以使用之前介绍的<Ctrl + o> 和 <Ctrl + i> 来回的在两个文件中切换。使用全局书签在文件间跳转之前介绍过在文件中可以使用标记,在文件不同位置进行跳转。那个时候说到使用小写字母设置标记,小伙伴们可能会产生疑惑,那大些字母去哪了呢,为什么只能使用小写字母,而大写字母被空着呢?文章写到这里了,我可以告诉大家,大写字母被用到了全局书签里面。全局书签与之前介绍的标记使用方式一模一样,只是一个使用大写字母,一个使用小写字母。例如在上面一个例子中,我们在跳转到settings.lua 之前先使用mI 在init.lua中一个标签,在跳转之后使用 `I 快速跳转回来。好了,本篇内容就到这里了。下一次将介绍寄存器相关内容。再次感谢大家的阅读
2022年05月31日
7 阅读
0 评论
0 点赞
2022-05-25
vim 从嫌弃到依赖(13)——motion 进阶
在最开始的时候我们介绍了一些vim中的motion 包括如何在字符间、单词间、行间以及多行间移动。·但是motion中的内容可远不止我们介绍的这些,平时用到的也远不止之间介绍的那些。之所以没有一次介绍完,主要是不想搞那么复杂,一次性全都介绍完那么篇幅会显得很长,而且显的很复杂。vim入门最重要的一步就是用起来,如果初学者因为看到入门类的文章出现一堆不知道什么意思的操作命令,肯定会被吓跑的,也就无法体会到vim的魅力了。像这种进阶类的内容我想将它们放到后面,等各位小伙伴能熟练使用vim完成编辑任务之后再来考虑通过进阶内容进一步提高使用效率。vim屏幕行与实际行vim中有一个wrap 设置,表示一行文本超过多少行就会自动折行,这样就不会出现在一个屏幕上显示不全的问题了。在最开始配置neovim 的基础配置的时候已经展示过该如何启用wrap 设置,这里就不再演示了在启用自动折行的设置后,如果一行文本字符数超过设置的值会自动折行。在屏幕上显示为多行。当我们开启了显示行号的设置之后很容易区分。实际行在vim中只显示一个行号,而在屏幕上会显示多行。我们知道行间移动使用的是j、k, 他们是在实际行之间移动,如果想要在屏幕行间移动,可以使用 gj、gk。一般针对行相关的操作,只需要在前面加上g 就可以改成在屏幕行之间的操作。例如g0 是移动光标到屏幕行行首。g$ 移动到屏幕行行尾。他们与普通的行移动motion 用法类似,即可以配合数字表示重复,也可以配合operator 来执行相应的操作。单词与字串在vim中一个单词由字母、数字、下划线或者其他非空白字符组成,单词间以空白字符分割。而字串是由非空白字符序列组成。这个感觉可能很抽象,但是多多联系和尝试应该就很容易明白了。字串间的移动使用大写的W, B。下面来看一个例子e.g. there's a nvim config file in "~/.config/nvim/init.lua"我自己总结如下:区别单词应该以字母、数字、其他非空白字符进行分类字串仅仅以空白字符为区分同一类型的字符序列组成的部分作为一个单词。例如上述句子由字母、空白字符和其他非空白字符(. ' ~ /)组成, e.g. 后面是一个空白字符,因此它被划分为一个字串,而它自身经历了字母、非空字符、字母、非空字符的序列,所以vim将他们划分为了4个单词。如果这样比较麻烦,那就简单的记住:字串比单词要长,不需要细粒度的移动,可以用字串间移动。本次就说到这里了,各位可以配合一下最开始的几篇文章,配合使用,巩固一下motion相关使用。
2022年05月25日
14 阅读
0 评论
0 点赞
2022-05-18
vim 从嫌弃到依赖(12)——打开及保存文件
在前几篇文章中,我们从vim各种模式的使用着手介绍了vim如何进行文本本身的编辑。也通过缓冲区列表的介绍了解到了vim是如何进行打开文件的管理。这篇我们将会着眼于文件的打开和保存的基本操作。通过这篇的阅读,我们可以正式开始尝试将vim用做代码编辑器,而不再是像之前那样作为普通的文本编辑器。开始前的准备先来介绍一下vim的工作目录的概念。我们知道进程都有自己的工作目录,后续需要操作某个目录的时候,可以根据这个工作目录使用相对路径。这样的好处是比较灵活,只要我们的文件按照一定的规则进行组织,后续可以更换程序可执行文件所在路径而不用更新代码。vim自己也有一个工作目录的概念,可以通过:pwd 来查看当前vim的工作目录是哪个,一般来说我们是从shell中的哪一个目录中进入的vim,那么vim的工作目录就是哪个。为了展示vim是如何进行目录和文件管理的,这里我准备通过我之前在github上托管的自己的vim配置文件来进行演示,nvim-config 各位小伙伴可以下载进行实验,以便达到与教程保持相同效果。也可以采用自己的实际项目进行实验。这里我多说一句,我并不推荐各位采用这个配置,第一个原因在于这个配置并没有完全完成,算是一个半成品。第二个原因是这个配置并不能完美的符合各位的工作流和工作习惯。我们学习vim、学习vim的配置主要是为了结合自己的工作习惯和工作流形成一套符合自己习惯的操作方式,并不推荐大家照搬里面的配置。第三个原因是,在后续我想写一系列的从0开始配置vim的文章,帮助大家完成自己的配置。edit命令打开一个文件可以通过:edit {filename} (或者简写为 :e ) 。如果filename采用绝对路径,那么打开的就是绝对路径所对应的文件,如果是相对路径,那么就可以打开相对与vim工作目录的文件。例如我们想打开项目中的基础配置文件lua/basic/settings.lua,就可以执行:edit lua/basic/settings.lua。根据我们前面所学的内容,vim的命令模式是支持自动补全的,我们可以通过tab来快速补全路径假设现在已经打开了这个文件,我想打开它同级目录下的keybinds.lua 来配置快捷键的话,我要同样的输入:edit lua/basic/keybinds.lua。本来我已经打开了与它同级目录中的 settings.lua 了,我为了打开keybinds.lua 要输入这么大一堆,如果我能以当前settings.lua 的路径作为相对路径就好了。vim 在命令行中提供了一个% 作为活动缓冲区的完整路径。我们在直接介绍命令模式的时候,%是作为范围表示当前打开的整个文本。这里它作为路径参数的话,表示的是当前打开文本的完整路径。我们可以通过 :edit %<Tab> 来自动显示整个路径,然后通过<C-w> 来删除单词,直到删除到当前目录,然后再输入keybinds.lua 就可以了 用这种方法是简单了点,但是最后还要删除个文件名,上面我们按了3次` ,也挺麻烦的。有没有什么方法可以直接定位到对应的目录,让我直接输入文件名呢?可以通过 在%的后面加上:h 来自动去掉文件名,即输入:edit %:h` 来自动出现对应的目录。这个功能还是挺有用的,但是需要输入这么多内容,为了简化它你肯定也想到了,要给它配置快捷键。这里还是留到以后再讲解它的使用。find命令即使:edit 命令有% 这种操作来简便输入,但是在打开其他目录中的文件时仍然需要输入完整的目录和文件名,这个操作也是挺繁琐的。操作系统中,有一个PATH 环境变量,输入命令的时候,他会在PATH 所指定的目录中查找对应命令。vim中也有类似的概念。vim中可以使用:find,根据输入的文件名打开文件。但是使用:find 的前提是配置path 变量。它们合作完成打开文件的操作,与环境变量的用法类似。可以输入:set path+=./** 将当前工作目录以及它下面的所有子目录。然后可以直接输入:find keybinds.lua 打开这个文件了。你可能会问,如果项目中有相同的文件名呢,这个项目里面没有同名文件,这里我们在lua/basic 目录中新建一个init.lua 这样它就与根目录下的init.lua 相同了。我们输入:find init.lua ,它会打开当前文件所在目录附近的同名文件。例如如果当前打开的文件在lua/basic 目录中,那么它会打开nvim-config/lua/basic/init.lua ,如果当前打开文件在nvim-config 中,它会打开nvim-config/init.lua。也可以在输入完init.lua 之后,按下<Tab> 它会提示所有匹配到的文件。我们可以指定位置的文件打开。在我们不断使用tab来匹配会出现3个匹配项:init.lua、./init.lua、./lua/basic/init.lua。他们分别对应着上面所说的那个匹配的文件,以及其他两个不同位置的文件。vim自带的目录管理工具在一般的ide中,左侧或者右侧会以树的形式显示项目中的目录。vim中也有这样的功能。它是vim提供的一个名为netrw 插件。我们打开一个目录就可以看到,它在窗口中显示该目录中的文件结构。它与普通的缓冲区窗口一样,可以通过motion 操作来移动光标。也支持命令行模式,但是这个缓冲区是不可修改的,也无法保存。在该窗口中,随意选择一行按下回车,如果选择的是一个文件,那么它会打开该文件,如果是目录那么窗口中则会进入该目录并显示目录内容。我们可以像打开一个普通的文本文件那样打开一个目录,二者的区别仅仅在于显示的内容不同,某些行为不同而已。如果当前已经打开了一个文件,我想再继续显示这个目录呢?相信各位小伙伴已经猜到了,既然可以以打开普通文件的方式打开新的目录,那么我使用:edit 命令,在后面加入目录路径是不是就可以了。经过实验,确实是这样呢。看到没,vim就是这样,一旦理解了它的逻辑,很多东西自己就能猜到。当然vim也提供了:Explore 专门用来显示目录结构。它可以简写为:E 后面不加任何东西可以打开当前文件所在目录,也可以加上路径打开指定目录。如果我们想要像普通编辑器那样将目录结构放到左边怎么办呢?套用打开文件的方式,各位肯定能想到使用:vsplit 加上目录名。vim也提供了一组命令:Sexplore和:Vexplore 分别在水平和竖直方向打开目录。vim自带的这个目录管理工具最大的问题是我通过回车键从里面选择一个之后,会在当前窗口打开一个新的缓冲区,并且把目录树给覆盖了,这个时候我们可以快速按下<Ctrl + Shift>^ 来在新打开的缓冲区和目录树之间切换。除了浏览目录结构以外,也可以利用该插件进行文件和目录的创建、删除、修改、重命名等操作,例如,使用% 来创建文件, d 来创建目录,R 重命名或者移动目录和文件,使用 D 来删除一个目录或者文件vim自带的目录管理工具虽然提供了各种功能,但是并不是特别好用,我们有众多的第三方工具可以使用。这个留着等到介绍配置的时候再说。一次性讲太多了显得太杂,而且我想用一个悬念留住各位读者,也用它来吸引新的读者,这也算是我一点小小的私心吧。写入文件的一些小技巧写入不存在的目录中我们在原项目的基础之上打开一个新的有不存在目录的文件,例如:e random/111/test.txt。我们成功的进入了vim的编辑界面,我们也可以进行编辑,但是一旦执行写命令的时候,发现vim会提示目录不存在。它保存文件需要将文件保存到一个已经存在的目录中。我们可以退出vim,然后使用mkdir 来新建目录。这个是下下策,之前输入的内容全丢失了,再重新来一遍实在是令人恼火,不瞒各位,我之前就是这么干的,所以我养成了,新打开一个文件就立马执行:w 的习惯。还记得之前讲过怎么在vim中执行shell命令吗,不想退出vim,又想在保存前创建目录,可以使用这招, :!mkdir -p random/111, 然后再执行写入。或者可以灵活的使用在前面介绍的:%h 来快速补全相对路径强制以root用户写入文件有时候我们使用vim打开了系统文件,例如打开了/etc/hosts 文件,但是保存的时候意识到忘了加sudo 了,导致无法写入,我以前的办法是先退出,然后再用root权限打开,这样就导致之前输入的内容全都丢失了,幸亏我养成了前面说的那个习惯,打开文件之后的第一步就是执行:w,在学习了vim的命令模式之后,估计各位小伙伴已经有思路来解决这个问题了。我们以当前文件内容作为命令输入,配合shell命令,完成。我们知道可以使用tee 来将输入内容写入文件中。那么我们的命令可以是 :w !sudo tee % > /dev/null, 我们使用:w 来指定当前缓冲区的内容作为shell命令的输入。然后配合tee 来将内容写入到% 也就是当前文件。写入文件之后vim会检测到该文件已经被外部的程序修改了,本例中它被 tee 命令修改了,因此这个时候vim会提示我们文件已经被外部程序修改,需要重新载入文件还是使用当前缓冲区的内容。因为这里我们是将缓冲区内容直接覆盖到文件里面,二者的内容是一样的,使用哪个都行。由于neovim中该操作可能有问题,会报错,这里就不演示了,使用vim的小伙伴可以试试这个方法。后续我们可以使用扩展插件来解决这个问题。
2022年05月18日
8 阅读
0 评论
0 点赞
2022-05-11
vim 从嫌弃到依赖(11)——标签页操作
各位小伙伴们,你们好,我又更新了!之前介绍了vim关于多窗口的操作,vim中多窗口是将多个窗口在一个屏幕中显示,这似乎与我们常见的ide有点不一样,一般的ide都是新开一个窗口之后在新的标签页中显示,通过不同的标签页对应不同的文件。我们的浏览器就是一个典型的例子。而vim似乎不是这样的,vim管理文件采用的是缓冲区列表的方式,一个缓冲区对应一个显示窗口,而多个窗口可以显示在一个屏幕上。而vim中的标签页更像是一个容器,用来容纳这么些窗口。它更像是一个虚拟桌面,不管在功能上还是使用习惯上都像是虚拟桌面。(虚拟桌面可是个摸鱼的好东西,不过现在有更高级的摸鱼方法就是了。 有朝一日我一定要尝试用vim来摸鱼)除了使用它来摸鱼,我们再来想象这么一个场景:我们在做一个项目,已经打开了需要的代码文件,并且将它们经过了精心的布局,但是这个时候来了新的任务(以前的老项目出bug了,wtf!),我们不想在精心布置的窗口中插入这么一个第三者,总归心里有点别扭。这个时候我们新开一个标签页,在这个标签页里打开原来项目相关的文件。当我们修复完这个bug之后,直接切回到原来的标签页。之前的布局仍在原地等待着你(这么一个对你不离不弃的编辑器,多么令人感动)。我知道,看了我这么长的vim教程,很多小伙伴已经头晕脑胀了,甚至有的可能觉得最近介绍的东西,使用插件能更好的完成类似的操作,这些操作方式已经过时了。但是vim它提供了原生的操作,总有它的道理。打起精神来吧。标签页可以使用命令:tabedit {filename} 打开一个新的标签页,如果不加文件名则打开一个空的标签页。我们也可以使用tabnew 命令,参数与效果完全相同。如果当前标签页中包括多个窗口,那么可以使用<Ctrl+w>T 将当前缓冲区移动到新的标签页中。关闭标签可以使用tabc[lose] 或者使用tabo[nly] 来关闭标签页,前者是关闭当前标签页,后者是关闭所有,只保留当前激活的标签页。切换标签页在普通模式下使用gt 切换到下一个标签页,使用gT 切换到上一个标签页,也可以在命令模式中使用:tabn[ext] 和 tabp[revious] 来达到同样的效果。另外tabnext 和gt 前面都是支持添加数字编号的。这样我们可以方便的跳转到第几个标签页,这个编号是从1开始的。最后再介绍一个tabmove {n} 命令,它可以用来移动当前标签页到指定位置,后面加数字表示移动到第几个标签的位置,不加数字默认移动到结尾位置。当然如果你使用的是图形版的vim或者终端支持鼠标操作,也可以使用拖拽的方式完成这一工作。最后总结关于标签的操作,基本就这么多了。其实真要说起来,这些操作比较繁琐,记起来也麻烦,vim自带的标签功能相对比较简陋,后面我会介绍对应的插件对其进行扩充,本来我想跳过这部分的内容,毕竟有更好的插件和更好的操作方式。但是它作为vim提供的一大功能,使用频率也算比较大,想想还是说一下比较好吧。最后总结一下提到的一些命令吧::tabedit {filename} : 新建标签页,并在标签页中打开对应文件tabnew: 与tabedit 完全相同<Ctrl+w>T: 如果当前标签中有多个子窗口,它会将当前活动子窗口放到新的标签页中tabc[lose]: 关闭当前标签页tabo[nly]: 关闭除当前激活标签页的所有gt 或 :tabn[ext]: 切换到下一个标签页gT 或 tabp[revious]: 切换到上一个标签页tabmove {n}: 移动当前标签页
2022年05月11日
5 阅读
0 评论
0 点赞
2022-05-07
vim 从嫌弃到依赖(10)——缓冲区列表
之前的一系列文章主要介绍了vim文本相关的操作,并且也介绍了vim的几种模式。通过前面的内容,相信各位小伙伴们已经对vim有了一个基本的了解,同时也能够使用vim快速编辑文本,从这篇开始,我们将要介绍vim针对多个文件的操作,例如如何在多个文件中查找、跳转等等方式方法。让我们先从vim如何管理打开的多个文件开始吧缓冲区列表简介有过编程经验的小伙伴应该知道,将文件从磁盘读取到内存中时,都会事先分配一块内存缓冲区用来保存读取到的文件内容,vim同样是这么干的。vim在读取文件时会通过内存映射的方式,将磁盘中的内容映射到一块内存的缓冲中。vim可以打开多个文件,每个文件独立的占有一个缓冲区。为了管理这些打开的文件,vim中有了缓冲区列表的概念,同时也提供了一些配套的命令来操作缓冲区列表。假设现在在某个目录中有多个文件,我们使用vim同时打开,例如使用vim init.lua test.py。我们发现vim默认只展示一个文件中的内容,但是它打开了两个文件,现在有两个以文件名命名的缓冲区。通过命令:ls 查看当前打开的缓冲区。:ls 命令显示的内容每一行代表一个缓冲区的信息。它显示的信息如下::ls 1 %a ".\test.py" line 1 2 ".\init.lua" line 0第一列的数字代表缓冲区的编号,该编号由vim随机指定,第二列的%a 代表缓冲区为激活的缓冲区(active)当前窗口显示的内容为激活缓冲区的内容。第三列则是缓冲区的名称,一般vim会将文件名作为缓冲区的名称我们可以使用:bnext 按:ls 的显示顺序,显示下一个缓冲区,:bprev 显示上一个缓冲区。:blast 显示最后一个缓冲区,:bfirst显示第一个缓冲区。在切换过缓冲区之后再次执行:ls 之后发现此时显示的内容已有一些变化。现在显示的内容如下::ls 1 #h ".\test.py" line 1 2 %a ".\init.lua" line 1此时我们发现除了%a 代表当前处于激活状态的缓冲区外,另外一个缓冲区的前面多了个#h ,# 代表上一次处于激活状态的缓冲区,我们可以使用<ctrl + ^> 来切换到上次处于激活状态的缓冲区。而h 则代表隐藏缓冲区,当一个缓冲区由激活状态变为非激活状态的时候,vim会将其标记为隐藏缓冲区。除了按照顺序显示缓冲区,还可以通过缓冲区名称或者序号来指定显示某个缓冲区。例如使用:buffer 1 来显示编号为1的缓冲区。还可以更直观的使用buffer {bufname} 来显示指定缓冲区,其中{bufname} 代表的是缓冲区的名称,例如:buffer init.lua看到这里,各位小伙伴肯定会觉得不管使用:bnext 之类的命令切换还是使用:buffer 来切换缓冲区,都需要输入这么长的命令,显得既繁琐又低效,那么有没有什么办法来解决这个问题呢?答案是通过快捷键映射。后面介绍我自己的配置时会介绍如何将其映射到快捷键上如果要删除某个缓冲区可以使用:bdelete {bufname}。该命令支持前面几篇文章中提到的范围操作,即:nstart, nend bdelete 来删除编号nstart 到 nend 的所有缓冲区。缓冲区缓冲区编号是vim自己分配的,要通过编号删除得执行:ls命令,并且有时候删除了后续可能还要再次打开,再退一步说,如果暂时不想用它,vim也只显示后面打开的缓冲区,我们使用这个场景很少,除非有充足的理由,否则不会去删除它。缓冲区列表参数在实际开发项目的时候,我们会打开很多文件,如果仅仅使用上述介绍的命令会发现在管理上有诸多不便。例如项目中有ui文件、有python代码、也有c代码、甚至还有java代码,我现在要找一个名为showUserName 的函数,而且我很清楚我要的ui中的内容,但是在python、c或者java中都有类似的函数名,采用全局搜索肯定都搜出来了,但是我只想在ui文件中搜索。这就涉及到项目文件的模块化。使用上述命令肯定无法满足模块化的要求。这个工作可以使用列表参数来完成。假设现在目录有3个python 文件,5个cpp 文件,还有2个txt 文件,我们按照文件类型进行分组打开,先打开cpp 文件vim *.cpp使用 :args 显示参数列表。它输出的内容如下:[a.cpp] b.cpp c.cpp d.cpp e.cpp该列表记录了通过命令行另vim打开的所有文件缓冲区。其中使用[] 包裹起来的是当前处于激活状态也就是当前窗口显示的的缓冲。注意请不要被这个名字迷惑了,它并不是传递给vim的参数,而是作为参数传递给vim的文件的列表。也就是这条命令所打开的文件的列表。本质上仍然是一个缓冲区列表除了使用:args查看参数列表,也可以在:args 命令后添加缓冲区名称,例如:args init.lua 这样就将一个新的文件纳入之前的缓冲区列表中进行管理。后续可以将需要统一管理的缓冲区使用该命令添加进来,除了使用详细的文件名一个个添加之外,vim也支持使用通配符来进行匹配。甚至也可以在后面添加shell命令,以shell命令的输出作为缓冲区列表的参数,添加到参数列表,它的形式为:args `cmd`上述事例中,我们通过args 来将ls 输出的结果作为参数列表。再通过:ls 命令查看一下当前缓冲区列表,发现之前打开的仍然存在,只是我们将test.py 和 init.lua 这两个文件形成一组作为缓冲区的参数列表。当我们指定好了一组缓冲区列表参数之后,可以使用:next 、 :prev 、first、last 在这组缓冲区列表中进行切换。:args 命令本身也支持使用通配符来将所有匹配的文件名设置为缓冲区列表参数,例如:args *.py 将当前目录中所有py文件加入,或者使用:args **/*.py 来将当前目录下所有子目录中的py文件加入。一般来说使用shell命令或者使用通配符的方式居多,但是也有直接使用文件名的情况出现后面我们可以根据参数列表,对列表中所有的缓冲区进行统一的修改或者在这些缓冲区中进行跳转之类的操作,当然这些等我们介绍到了对应的基础知识后再进行演示。vim退出好像现在才讲到退出操作已经有点晚了,很多用上vim的小伙伴肯定也搜到如何退出了。不知道怎么退出的,应该已经退坑了。但是我在这里并不介绍使用何种命令来退出。而是介绍vim如何处理未同步到磁盘上的缓冲区的。我们随便打开多个文件,在任意一个或者多个缓冲区中执行o 或者其他能另其修改的命令。然后执行切换缓冲区的命令,例如:bnext 之类的,切换之后再次执行:ls 1 #h + ".\init.lua" line 2 2 %a ".\test.py" line 1我们发现在之前的基础之上,多了一个 + 它代表着这个缓冲区上的修改并未同步到磁盘文件中。此时如果执行:q 进行退出的话,会提示当前有缓冲区未同步到文件中,并且跳转到未同步的缓冲区。我们可以执行:w 来写入将缓冲区内容磁盘,也可以使用:q! 来忽略该缓冲区的修改,或者使用:edit!来强行的从磁盘读取内容并覆盖本次修改。这个时候vim将会切换到下一个未保存的缓冲区。如果嫌每次都这样比较麻烦,可以执行:qall! 忽略所有未修改的缓冲区并退出,或者使用:wall 来写入所有修改。总结本文到此就结束了,最后再来总结一下该文中使用到的命令和快捷键:bnext: 切换到缓冲区列表中的下一个缓冲区bprev: 切换到缓冲区列表中的下一个缓冲区blast: 切换到缓冲区列表中的最后一个缓冲区bfirst: 切换到缓冲区列表中的第一个缓冲区<Ctrl+^>: 在上一个被激活的缓冲区和当前被激活的缓冲区之间进行轮换args: 显示当前缓冲区列表参数。后面也可以跟上文件名、shell命令和通配符,设置对应的缓冲区列表参数next: 切换到缓冲区列表参数中的下一个缓冲区prev: 切换到缓冲区列表参数中的上一个缓冲区last: 切换到缓冲区列表参数中的最后一个缓冲区first: 切换到缓冲区列表参数中的第一个缓冲区
2022年05月07日
12 阅读
0 评论
0 点赞
2022-05-05
vim 从嫌弃到依赖(9)——命令模式进阶
上一篇文章更新还是在51前,最近发生了很多事情了,全国各地的疫情又有蔓延的趋势,北京朝阳区都已经开始实施居家办公。各位小伙伴请注意安全,安全平安的度过这个疫情。废话不多说了,接着上次的内容往下写。在上一个篇章中,我们介绍了命令模式的使用,也通过一些例子理解了在需要大范围操作文本或者进行光标跳转的情况下,相比于使用普通模式中的operator + motion 来说,使用范围加命令的方式更快速而且也更方便。同时也以copy 和 move 操作,介绍了操作文本命令的一搬用法。接下来就要继续往前走,介绍命令模式的其他用法了。命令行模式下使用普通模式的命令当初在第一次介绍. 命令的时候相信各位小伙伴应该有一个遗憾,怎么没有介绍.命令类似数字 + . 以达到重复执行目的的操作呢。如果有这么一个操作那岂不是如虎添翼。甚至可能有小伙伴自己亲自去尝试过,发现失败了。vim并没有提供类似的操作。那么要完成这件任务该如何来操作呢,之前的例子只有3行,每次使用. 之后使用j 来移动然后再使用. 也没几次,这个成本是可以接受的,但是如果是将文件中所有代码行的尾部都加分号,而且这个文件有上百行甚至上千行代码呢。之前针对这个例子给出了不同的解决方案,在学习. 命令的时候,是使用. 命令,在学习可视模式的时候使用处理列的可视模式。现在再介绍一种新的方式,通过在命令行模式中使用normal 关键字来告诉vim,我们将要使用普通模式的命令。它使用的方式为:range + normal + operator ,它支持范围操作,表示我们将要针对某个范围来执行普通模式的操作针对这个例子,首先要构造一个可以使用.命令的操作,即我们在首行使用A; 在行尾添加分号,接着配合命令模式的范围,加上2,$normal. 表示我们将要从第二行到尾行来执行. 命令这个在使用. 的时候,我们相当于在重复执行A; 的普通模式的命令,那么是不是可以做这样的猜想,使用:normal 也可以执行 A; 这样的命令做到同时切换输入模式并且自动输入字符,而不仅仅局限于执行operator呢?我们可以将上述修改使用2u回退,然后针对这个猜想做验证,输入:%moral A; 我们发现它确实成功完成了这样的操作。也就是说normal后是可以跟一些改变当前模式的命令并且可以指定输入的内容的。这样我们在快速删除一个文件的所有内容上,又有一种新办法了:$normal dd 但是相比起 :%d 来说要输入的字符更多罢了。他们的区别相信看到现在的小伙伴应该很熟悉了。这里就不再解释了,感兴趣的小伙伴也可以在评论区给出自己的答案。重复上次的ex命令在普通模式下. 可以重复上一次的修改,但是某些ex命令并没有对其进行修改,如果我想重复通过. 来重复上次的ex命令则无能为力了。而且通过实验也可以发现,它也无法重复由ex命令造成的修改。可以使用@: 重复上一次的命令。如果执行过 @: 进行重复,那么可以使用@@ 再次执行上次重复的命令,例如在编写代码时经常会一到的一个问题就是将当前行代码下移一行,但是也不是所有的行都会这么干,那么就可以先使用 .m.+1将当前位置的代码移动到光标的下一行,然后移动光标,在下一个需要次操作的位置执行 @: ,后面就可以直接使用 @@ 来重复上一次的操作了。这里就不再针对它来做演示了。各位小伙伴可以自己来尝试一下自动补全ex命令在使用shell 命令的时候,使用tab 可以很方便的进行补全,而在使用命令模式的时候也有这个功能vim在使用tab时会自动检索之前输入的历史进行匹配。例如,使用 :%n<tab>。它会匹配到一堆符合要求的命令。多次按下 <tab> 键则会依次按从上到下的顺序进行匹配。也可以使用 <Ctrl n> 和 <Ctrl p> 跳转到下一次匹配和上一次匹配。同样的也可以使用 <Shift Tab> 来跳转到上一次匹配默认情况下,会按照上述例子中的样式来展示匹配项,但是你也可以自定义匹配项,使用wildmode 来修改补全行为。但是需要事先打开 wildmenu 选项。可以使用 :h wildmode 和 :h wildmenu 来查看对应的帮助文档。这里我给出我习惯使用的配置vim.o.wildmenu = true vim.o.wildmode="full"set wildmenu set wildmode=full当然你不进行这样的配置也行,neovim 模式的补全模式就是这种回溯命令历史在 shell 中,可以使用上下键直接输入上次输入的命令或者在 bash_history 中记录了之前执行过的命令,vim也有同样的设计按下 : 进入到命令模式之后,可以使用方向键向上或者向下查找历史命令。除了使用 方向键以外,还可以使用 <Ctrl p> 和 <Ctrl n> 来遍历,但是使用方向键有一个好处是他们可以针对之前已经输入的内容对匹配的内容进行过滤。坏处在于,手指的移动幅度大,我们可以使用映射的方式将<Ctrl p> 和 <Ctrl n> 进行映射。这里我们仍然等到讲述快捷键映射的时候给出代码运行shell 命令在vim的命令模式中也可以执行shell命令。只需要在shell命令前面加上 ! 即可,例如执行 :!ls 将会执行ls 这个命令在vim的命令模式中,% 代表的是当前文件名,在运行某些可以传入文件名作为参数的命令时,可以使用它,例如我要执行当前的Python代码时可以使用 :!python %我们也可以将vim命令模式中的范围配合shell命令使用,这个时候范围中包含的内容将会作为shell命令的输入, 例如现在有这么一个文件,记录了一个文件列表,现在我想要按照文件名排序files: a.txt ccc.txt b.txt d.txt z.txt t.txt可以配合sort 使用 :2,$!sort,由于第一行是表头的文字不进行排序,所这里从第2行开始参与排序使用 write 和read 命令重定向vim缓冲区内容在vim配合shell命令使用的时候有时候shell会产生大量是输入或者需要一定的输出,那么就可以使用 write 和 read 来配合shell使用。read:vim从shell产生的输出中读取内容写入缓冲区write: vim将缓冲区的内容写入到shell中,作为shell的输入例如某个文件中有大量的Python代码,但是我只想执行部分,那么可以配合write使用,例如3,5write !python 执行文件中3-5行的Python代码,或者配合可视模式,执行选中的代码再比如,我现在需要获取当前目录下有多少个文件和目录,并且按照文件名顺序排列,就可以使用 :read !ls|sort。甚至配合键绑定,完成ide那种一件自动编译运行的效果。例如vim.api.nvim_set_keymap('n', '<F5>', ':write | !python %<CR>', {noremap = true, silent = true})配合文件类型识别可以做到一键执行其他类型的代码,将vim 打造成IDE不是梦想除了手工填写范围配合shell命令之外,vim提供了一种简便的方式来完成这一工作,可以使用 !{motion} 来快速形成范围,后面只需要输入命令即可,针对前面排序文件的例子,假设光标在文件的第二行,可以使用在普通模式下输入!G 来快速选中整行,vim为我们在右下角填充了:.,$! 后面只需要写上sort 之后就可以了到此为止,我们已经通过介绍不同的模式,将vim编辑文本的功能大致给展示了一下,相信各位小伙伴看到这里已经了解到了vim在编辑文本的强大。但是这并不是vim的全部,后面将详细介绍如何通过vim来组织文件、项目工程等功能。请各位敬请期待
2022年05月05日
5 阅读
0 评论
0 点赞
2022-04-27
vim 从嫌弃到依赖(8)——使用命令模式编辑文本
通过前面的文章,我们已经介绍了vim的普通模式、插入模式、可视模式。接下来让我们接着介绍vim中另一个强大的模式——命令行模式命令模式简介命令模式可以说在vim中的使用频率不亚于普通模式,像我们平时使用 :w 将缓冲区的内容写入文件,使用 :q 退出vim,这些都是在命令行模式下执行命令。vim最早是由 ed 编辑器发展而来,中间经历过了 ed --> ex --> vi --> vim 的流程,vim继承了vi的模式区分以及ex的一些处理文本的命令,这也就是为什么有时候会将vim命令行模式中执行的命令叫做ex命令在普通模式下,按下: 会切换到命令行模式,这个时候vim会等待我们输入一个命令,最后以回车(\<CR>) 结束输入并执行在vim 中有许多自带的的命令,而且我们安装第三方插件的时候,插件也会提供一些使用的命令,这里我们主要还是战士如何在命令模式中操作文本。其他相关的命令在后面结合其他功能给出在命令行中的操作与在插入模式中类似,只是插入模式会将键盘输入写入缓冲区,而命令行模式则会将输入显示在命令行位置。二者的操作符也类似,例如可以适用 <Ctrl-w> 和 <Ctrl-u>来删除至上个单词的开头和行首。也可是使用 <Ctrl-v> 和 <Ctrl-k> 来输入键盘上找不到的字符。也可是使用方向键来移动光标,或者使用退格键删除命令。如果中途不想执行输入的命令,可以使用<Esc> 退回到普通模式。在普通模式下,我们需要使用 operator +motion 来操作指定范围的文本,这通常伴随着光标的移动。在命令行模式下,可以操作任意范围内的文本,这表示在某些情况下,使用命令相对于在普通模式下有着更高的效率我们可以在一个或者多个连续行上执行命令,例如print("hello world1") print("hello world2") print("hello world3") print("hello world4") print("hello world5") print("hello world6")假设光标在第一行的行首位置,我们输入 :print ,它会打印当前行。我们看到执行print 之后会打印光标所在行配合范围使用命令与普通模式下 operator 配合一个 motion 来指定操作的文本范围类似,ex命令也可以带有一个范围值来指定操作的范围。这里我们给出一个使用范围的格式格式command = {startpoint},{endpoint} + cmd其中 startpoint 表示开始位置,endpoint表示结束位置,他们中间用,隔开,后面紧跟着一个命令。如果不加范围,则表示操作的范围是光标所在行,例如 :print 表示打印光标所在行的文本如果只输入一个数字,vim会首先将光标移动到对应的行上,然后针对该行文本执行操作,例如如果输入 :2print 它会将光标移动到第二行,然后对第二行文本执行打印操作。使用数字代表对应行下面再看一个例子:print("hello world1") print("hello world2") print("hello world3") print("hello world4") print("hello world5") print("hello world6") print("hello world7")我们要删除第三到第5行范围内的文本,就可以输入 :3,5d, 其中d 代表 delete 是删除的命令通过上述例子发现,在使用命令模式的时候,不需要在意光标所在位置,如果我们采用普通模式的解法,就需要先使用 3gg 跳转到第三行,然后使用3dd 删除三行。或者在第三行使用V 进入可视模式,然后选中3行,接着使用d 删除选中。对比这么几种方式来看,使用命令模式更加的灵活使用特殊符号代表对应行除了使用数字来代表对应行号所在行外,还是使用一些特殊符号来表达一些特殊含义,例如我们可以使用 . 来代表当前光标所在行,所以针对上述操作,我们还有一个解法:使用3gg 跳转到第三行,然后使用 :.,5d 删除当前行到第5行的内容除了使用. 来作为相对行号以外,命令模式中还有其他常用符号,这里列举一些供大家参考:.: 当前行$: 文件末尾0: 虚拟行,位于文件第一行的上方1: 文件第一行'm: 包含标记m的行<: 高亮选区的起始行>: 高亮选区的结尾行%: 整个文件,相当于 :1,$介绍了这些操作符之后,如果我们需要删除整个文件,那么有这么几种方法方法1:普通模式下,使用 0 跳转到第一行, 然后使用dG 第一行到最后一行的内容方法2: 命令模式下,使用 :1,$d 删除第一行到最后一行的内容方法3: 命令模式下,使用 :%d 删除所有使用位置偏移量来微调操作范围在 {startpoint}, {endpoint} 中二者均为绝对地址,除了使用绝对地址,我们也可以使用绝对地址+偏移地址的方式来定义操作范围。可以在绝对地址上使用 + 或者 - 来定义如何进行偏移,例如 $-3 会定位到导数第4行。假设我有超过1000行的文本,我想保留前3行和后3行,使用命令的时候可以使用:4,$-3d将可视模式的选区作为操作范围手动指定范围的时候,有时候需要我们去手工数开始行号和结尾行号,数数也算是一个比较累的体力活。除了使用之前的方式外,还可以使用可视模式。将可视模式的选区作为操作区。我们还是来看上面的删除第一行到第5行的例子,配合可视模式就可以这么做:先使用V 进入可视模式,然后使用 2j 选中两行,然后输入:d 进行删除 我们发现在选中一个选区后,按下: ,在左下角会出现 <,> 的字样,根据前面的列表知道 他们代表的是被选中的高亮选区。其他操作文本的命令在上面的例子中,我们主要使用了 d 这个命令来删除文本,除了它还有其他一些处理文本的命令,每个类型的命令接收的参数都各有千秋,但是也很好理解,这里我以 t (拷贝粘贴) 和 m (移动)为例,希望可以做到抛砖引玉的作用,帮助大家理解其他一些常用的命令。使用t 命令t 命令代表拷贝和粘贴,可以理解为 CopyTo。它需要两个参数,一个范围代表拷贝哪个范围的文本,一个位置,代表要将拷贝的内容放置在哪个位置。它的形式如下::range + t + address第一个range 代表的是范围,要将哪个范围内的文本进行粘贴,第二个address 代表的是一个行号,要将粘贴的内容放置到哪个位置这里我们给出一个示例来说明如何使用今日完成工作情况 1. fixbug 1 2. fixbug2 3. fixbug3 4. fixbug4 明日计划 5. fixbug5 6. fixbug6 7. fixbug7假设有这么一个日报,但是我今日工作完成之后发现离下班还有点时间,为了获得内卷达人的称号,我决定先看看明天的 bug5但是又不想为此加班太多,只是简单的看看,然后在工作日报上进行汇报,也就是说我要将fixbug5 复制一份放到今天的任务中。我们可以使用 :7t5 来将第7行的内容复制到第5行下方当然也可以先使用 7gg 跳转到第7行,然后使用 yy 复制该行,接着使用 5gg 跳转到第5行,最后使用p 进行粘贴。对比这种方式使用命令更加简洁,它省略了几次光标跳转的过程。由此看来,在需要大范围操作或者跳转的时候,使用命令会更加简洁也会更加高效还是以这个日报为例,随着我不要命的卷,终于在今天把bug5给修复了,虽然拉着其他同事陪我加了“一会班”,但是我超额完成了任务,老板承诺的绩效和年终奖马上要到手了,想想就觉得心里美滋滋,我要把明天修复的bug5提前到今天。想到这里我使用 :7m5 完成这一操作之后,打卡下班,未来可期如果再卷点,我能把明天要修复的bug全都在今天修完了,所以我这个时候想在工作日报中把明日计划工作全部移动到今天来,假设当前光标处于 bug5的位置,我可以执行:.+2,$m.。至此我带着出任总经理,担任CEO,迎娶白富美,走向人生巅峰的美梦沉沉睡去。总结到此为止,这篇文章的内容就完了,最后给大家总结一下主要内容命令模式是vim中又一重要的模式,使用率不亚于普通模式命令可以配合数字或者其他符号使用,代表将要操作的文本范围主要以 t 和 m 命令介绍了操作文本命令的用法最后再给出一些命令和范围的总结供大家查阅文本操作命令命令简写用途:[range]delete [x]d删除指定范围内的行[到寄存器 x 中]:[range]yank [x]y复制指定范围的行[到寄存器 x 中]:[line]put [x]pu在指定行后粘贴寄存器 x 中的内容:[range]copy {address}t把指定范围内的行拷贝到 {address} 所指定的行之下:[range]move {address}m把指定范围内的行移动到 {address} 所指定的行之下:[range]joinj连接指定范围内的行:[range]normal {commands}narm对指定范围内的每一行执行普通模式命令 {commands}:[range]substitute/{pattern}/ {string}/[flags]s把指定范围内出现{pattern}的地方替换为{string}:[range]global/{pattern}/[cmd]g对指定范围内匹配{pattern}的所有行,在其上执行Ex 命令{cmd}有些命令暂时还不知道怎么用,不着急,后面说到对应部分,自然会提到的范围符号符号用途.当前行$文件末尾0虚拟行,位于文件第一行的上方1文件第一行'm包含标记m的行<高亮选区的起始行>高亮选区的结尾行%整个文件,相当于 :1,$
2022年04月27日
7 阅读
0 评论
0 点赞
1
...
4
5
6