草庐IT

vim 从嫌弃到依赖(22)——自动补全

aluluka 2024-02-21 原文

这篇文章我们将讨论 vim 自带的自动补全功能。当然,针对自动补全功能有许多好用的插件,但是了解vim自带的功能有助于我们更好的用来插件的补全功能。因为我见过有的配置文件将插件的功能配置的比原有的更难用,而且只用基本的功能不一定有原版的好用。所以这里也介绍一下原始版本用法,算是帮助各位在以后的配置中提供一个标杆。

make 命令

在了解自动补全之前,让我们先简单聊聊 :make 这个命令,它与上一篇文章中介绍的 :grep 命令类似,也是对 shell 命令的一个封装。它默认封装的是 make 命令。

我们对 c/c++ 语言执行 :make 也就是在调用 shell 中的 make 命令。它会将编译产生的错误信息存储在 quickfix 列表中。我们上一节中介绍了如何操作 quickfix 列表。也介绍了如何对 :grep 命令进行改造。同样的 :make 也支持使用相同的方法进行改造。

:make 命令中,使用 makeprg 来执行外部命令,使用 errorformat 来格式化输出到 quickfix 中。它们默认的值如下:

makeprg="make"

errorformag="errorformat=%*[^"]"%f"%*\D%l: %m,"%f"%*\D%l: %m,%-G%f:%l: (Each undeclared identifier is reported only once,%-G%f:%l:
for each function it appears in.),%-GIn file included from %f:%l:%c:,%-GIn file included from %f:%l:%c\,,%-GIn file incl
uded from %f:%l:%c,%-GIn file included from %f:%l,%-G%*[ ]from %f:%l:%c,%-G%*[ ]from %f:%l:,%-G%*[ ]from %f:%l\,,%-G%*[
]from %f:%l,%f:%l:%c:%m,%f(%l):%m,%f:%l:%m,"%f"\, line %l%*\D%c%*[^ ] %m,%D%*\a[%*\d]: Entering directory %*[`']%f',%X%*
\a[%*\d]: Leaving directory %*[`']%f',%D%*\a: Entering directory %*[`']%f',%X%*\a: Leaving directory %*[`']%f',%DMaking
%*\a in %f,%f|%l| %m"

可以调整它们的值来适配不同的外部命令。这里就不再详细展开了,相信阅读过上一篇文章的小伙伴对这个应该不陌生。本来 :make 命令是vim中十分有用的一个命令,应该单独写一篇文章的。但是它于 :grep 重复度太高了,所以我决定在介绍其他内容的时候一笔带过。想了解详细信息的可以参考vim的用户手册。

自动补全

自动补全可以在插入模式下触发,当我们触发补全功能的时候,vim会根据当前编辑会话中所有缓冲区的内容建立一张补全列表,然后根据当前光标左侧的字符进行检测,看在表中能否找到单词的一部分,能找到则会用这个未完成的单词对补全列表进行过滤,所以不是以它为开头的单词都被过滤掉,剩余的组成一个弹出式菜单供用户选择。效果如下:

上述例子中,因为以 re 开头的原本只有 require 一项,为了展示补全效果这里我们新增一个以 re 开头的 return

我们使用 <Ctrl +p><Ctrl + n> 来切换补全菜单中的上一条和下一条。除了这个,我们还有其他的用于操作补全菜单的快捷键。

  • <Ctrl - n> : 使用来自补全列表中的下一项内容(next)
  • <Ctrl - p> : 使用来自补全列表中的上一项内容(prev)
  • <Down> : 与 <Ctrl -n> 相同
  • <Up>: 与 <Ctrl - p> 相同
  • <Ctrl -y> : 确认使用当前选中的匹配项
  • <Ctrl - e> : 还原最初的输入项
  • <Ctrl -h> : 从当前匹配项中删除一个字符
  • <Ctrl - l> : 从当前匹配项中增加一个字符

一般在输入字符的时候,如果有匹配项可以匹配vim会自动弹出,或者也可以手动使用 <Ctrl - n> 弹出匹配项菜单。在确定要使用的匹配后可以使用 <Ctrl-y> 来确认

有时候虽然弹出了匹配项菜单,但是匹配项太多了,而你需要的单词又在列表的太后面,这个时候可以使用 <Ctrl - e> 来退出菜单,手动输入几个字符使匹配项更加精确。或者也可以输入 <Ctrl -p> 到达最开始的项,即我们目前的输入,然后再次输入字符来精简菜单项,接着使用 <Ctrl - n> 弹出菜单。使用这种方式来一步一步的逼近我们想要的结果

自定义补全项来源

默认情况下,vim 补全项主要来源于以下几个地方:

  1. 缓冲区列表:vim补全项最基本的来源就是当前的缓冲区列表。它可以通过 <Ctrl - x><Ctrl - n> 来触发该项。
  2. 包含文件,所有的编程语言都有包含文件的概念,例如 c/c++中的 #include , python 中的 import 。使用 <Ctrl-x><Ctrl-i> 可以触发这个选项,让vim从被包含文件中提取补全项。vim本身使用 c 语言编写的,它能够识别 c/c++ 语言中的关键字,我们可以指定 include 项来使 vim认识其他不同的关键字。一般常用的编程语言 vim 都能够识别,因此不需要修改 include 项。
  3. 标签文件,我们使用 ctags 或者类似的插件的时候会生成一个标签文件,该文件会将扫描到代码中的关键字、函数、变量等的索引放入到一个文件中以供后续进行跳转。同时他们也会产生一系列的补全项到补全列表中。可以使用 <Ctrl+x><Ctrl+]> 来触发

一般直接使用 <Ctrl + n> 触发的是当前缓冲区列表中的补全项,使用 <Ctrl+x> 作为前缀,可以触发其他类型的补全项。这么做有一个好处是尽量精简补全列表,减少了我们手动遍历的过程。但是有时候我们并不知道我想要的内容该从哪里来,有没有什么办法能做到,用 <Ctrl + n> 这个按钮就可以调用其他所有来源的补全项呢?

要做到这点,可以使用 complete 这个配置项。该项包含一组由逗号分隔的单个字符表示的参数,当参数出现时表示需要扫描该参数代表的位置。使用 set complete? 可以看到,缺省项为 complete=.,w,b,u,t 。我们可以使用 set complete-=i 或者 set complete+=k 来删除或者添加某个扫描位置。常见的位置参数如下所示:

  • . : 表示当前以打开的缓冲区
  • w : 当前打开的窗口
  • b : 当前缓冲区列表
  • u : 当前处于缓冲区列表中,但是未打开的缓冲区
  • t : 当前标签文件
  • U : 当前打开的,不属于缓冲区列表中的缓冲区
  • k : 从字典文件中加载的补全项
  • i : 从当前文件和包含文件中读取
  • d : 从当前文件和包含文件中读取使用 define定义的宏

完整的内容可以使用 :h 'complete' 来查看。

使用字典文件

在上面的论述中,我们可以知道 vim 是可以自定义补全的字典文件,然后从字典中产生匹配的。我们可以使用 <Ctrl-x><Ctrl-k> 来加载字典中的匹配项。

我们可以使用 set spell来启动拼写检查,拼写检查也会产生新的字典文件。如果不想使用该项,也可以使用 set dictionary来指定含有一个或者多个单词的字典文件。

在这个例子中我们在 nvim-config 目录中新建一个 spell.txt 文件,我们在里面写入如下内容

require
return
request

然后使用 set dictionary=./spell.txt ,接着删除 init.lua 中的 return ,输入 re 然后使用 <Ctrl+x><Ctrl+k> 这个时候我们发现它已经加载了

补全整行

除了补全单词,vim还可以补全整行的内容,使用 <Ctrl+x><Ctrl+l> 可以触发补全整行的操作。
补全行的补全项来源与补全单词相同,需要注意的是补全行的操作会自动忽略行首的缩进。

补全行的操作与之前介绍的 yy 或者 :t 产生的效果相同,我们应该要根据实际情况分别使用。

补全文件名

在 shell中输入命令可以使用 <Tab> 键来自动补全文件路径,vim中使用 <Ctrl+x><Ctrl+f> 来对文件路径和文件名进行补全。

需要注意的是当我们使用相对路径来补全文件名时,使用的是工作目录,也就是你从哪个目录中进入的vim。我们可以在 vim中使用:cd来切换工作目录。例如我在 nvim-config这个工程的根目录执行 nvim init.lua,我们在这个文件中希望快速补全 basic/settings.lua这项,我们发现它在补全的时候报错

这个时候我们可以使用 :cd lua 来切换工作目录到 nvim-config/lua 。这个时候再执行补全命令就可以了。

根据具体编程语言生成补全

上述补全在编辑普通文本的时候显的有点用处,但是作为程序员平时在写代码如果只能使用上述方式进行补全肯定会抓狂的。好在vim 提供了像其他IDE那样的基于编程语言的补全方式。使用该补全方式的快捷键为 <Ctrl+x><Ctrl+o> 要启用该方式,需要启动文件类型识别。

nvim 中已经启用了这一特性,因此不必特意进行设置,但是这里我还是给出它的配置。

vim.o.filetype="plugin"

或者vim中可以使用如下代码

set filetype=plugin
set nocompatiable # 设置与vi 不兼容

例如我们可以尝试着在 css 文件中使用补全

vim 本身也确实支持很多语言的自动补全,但是为了获得完整的体验还是推荐使用各种专门的补全插件获得更好的体验

最后的总结

在这边文章中,介绍了vim中补全项主要的几个来源分别是:当前缓冲区和缓冲区列表、包含文件、外部程序生成的标签等等。同时也介绍了如何使用快捷键来进行不同项的补全,现在对这些快捷键总结如下:

  • <Ctrl + n> : 普通关键字补全,主要来源自缓冲区列表和当前缓冲区
  • <Ctrl+x><Ctrl+n> : 与 <Ctrl+n>作用相同
  • <Ctrl+x><Ctrl+i> : 从包含文件中获取补全项
  • <Ctrl+x><Ctrl+]> : 从外部标签中获取补全项
  • <Ctrl+x><Ctrl+k> : 从字典文件中获取补全项
  • <Ctrl+x><Ctrl+l> : 补全整行
  • <Ctrl+x><Ctrl+f> : 补全文件名
  • <Ctrl+x><Ctrl+o> : 根据编程语言来进行补全

有关vim 从嫌弃到依赖(22)——自动补全的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  3. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

    我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

  4. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  5. ruby-on-rails - 从应用程序中自定义文件夹内的命名空间自动加载 - 2

    我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty

  6. ruby-on-rails - 有没有一种工具可以在编码时自动保存对文件的增量更改? - 2

    我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功

  7. ruby - 从 Rakefile 打开 Vim? - 2

    我正在为个人笔记创建一个日志应用程序,并且在我的Rakefile中包含以下内容:task:newdoentry_name="Entries/#{Time.now.to_s.gsub(/[-\:]+/,'.').gsub(/.0500+/,'')}.md"`touch#{entry_name}``echo"#$(date)">>#{entry_name}`end我想包括的最后一部分是Vim文本编辑器的打开,但我不知道如何打开它,就像我直接从bash终端调用它一样。我试过:vim#{entry_name}但不幸的是,我认为它们都将其作为后台进程打开。我一直在引用“6WaystoRunShe

  8. ruby - 有什么方法可以告诉 sidekiq 一项工作依赖于另一项工作 - 2

    有什么方法可以告诉sidekiq一项工作依赖于另一项工作,并且在后者完成之前无法开始? 最佳答案 仅使用Sidekiq;答案是否定的。正如DickieBoy所建议的那样,您应该能够在依赖作业完成时将其启动。像这样。#app/workers/hard_worker.rbclassHardWorkerincludeSidekiq::Workerdefperform()puts'Doinghardwork'LazyWorker.perform_async()endend#app/workers/lazy_worker.rbclassLaz

  9. ruby - 在 ruby​​ 中使用自动创建插入数组 - 2

    我想知道是否可以通过自动创建数组来插入数组,如果数组不存在的话,就像在PHP中一样:$toto[]='titi';如果尚未定义$toto,它将创建数组并将“titi”压入。如果已经存在,它只会推送。在Ruby中我必须这样做:toto||=[]toto.push('titi')可以一行完成吗?因为如果我有一个循环,它会测试“||=”,除了第一次:Person.all.eachdo|person|toto||=[]#with1billionofperson,thislineisuseless999999999times...toto.push(person.name)你有更好的解决方案吗?

  10. ruby-on-rails - Textmate 'Go to symbol' 相当于 Vim - 2

    在Railcasts上,我注意到一个非常有趣的功能“转到符号”窗口。它像Command-T一样工作,但显示当前文件中可用的类和方法。如何在vim中获取它? 最佳答案 尝试:helptags有各种程序和脚本可以生成标记文件。此外,标记文件格式非常简单,因此很容易将sed(1)或类似的脚本组合在一起,无论您使用何种语言,它们都可以生成标记文件。轻松获取标记文件(除了下载生成器之外)的关键在于格式化样式而不是实际解析语法。 关于ruby-on-rails-Textmate'Gotosymbol

随机推荐