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次<C-w>
,也挺麻烦的。有没有什么方法可以直接定位到对应的目录,让我直接输入文件名呢?可以通过 在%
的后面加上:h
来自动去掉文件名,即输入:edit %:h<Tab>
来自动出现对应的目录。这个功能还是挺有用的,但是需要输入这么多内容,为了简化它你肯定也想到了,要给它配置快捷键。这里还是留到以后再讲解它的使用。
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的小伙伴可以试试这个方法。后续我们可以使用扩展插件来解决这个问题。