免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

Vim代码补全实战:从Ctags到LSP,打造高效开发环境

Vim代码补全实战:从Ctags到LSP,打造高效开发环境 1. 项目概述为什么要在Vim里折腾代码补全在Linux环境下Vim编辑器以其高效、轻量和无处不在的特性成为无数开发者、系统管理员和极客的首选。然而对于习惯了现代IDE如IntelliJ IDEA、PyCharm那种“敲几个字母就自动弹出完整函数名和参数提示”的开发者来说Vim默认的编辑体验尤其是在编写代码时确实显得有些“原始”。很多人第一次用Vim写C或Python面对一片空白的屏幕只能靠记忆一个字母一个字母地敲出完整的变量名和函数调用效率大打折扣也容易出错。这正是“在Vim中实现代码补全”这个需求的核心驱动力。我们并不是要抛弃Vim的哲学和高效性而是希望通过合理的插件和配置将现代编码工具的部分便利性“嫁接”到Vim这个强大的本体上。这背后的深层价值在于在保留Vim全键盘操作、极速响应和高度可定制化优势的同时显著提升复杂项目中的编码效率和准确性。想象一下你在分析一个庞大的Linux内核源码树比如热词中提到的drivers/gpio/gpiolib-of.c或者为一个嵌入式Linux项目添加新功能能够像在IDE里一样轻松地补全结构体成员、函数名甚至查看函数签名这将极大地减少上下文切换和查阅文档的时间。适合阅读这篇内容的你可能是刚从IDE转向Vim/Linux开发的初学者希望提升效率长期使用Vim但苦于没有好用的补全工具的中高级用户或者是需要在服务器、虚拟机如VMware安装的Linux、WSLWindows Subsystem for Linux甚至Docker容器等纯命令行环境中进行开发的工程师。本文将围绕“代码补全”这一核心不仅教你如何配置更会深入拆解其工作原理、不同方案的选型考量并分享我十多年来在各类Linux发行版Ubuntu, CentOS/Rocky Linux, Kali Linux等上实战积累的配置心得和避坑指南。2. 核心思路与方案选型不止于OmniCppComplete提到Vim的代码补全很多资料会直接指向OmniCppComplete这个经典插件。这没错但它只是拼图中的一块。一个完整的、好用的Vim代码补全体验通常由几个核心组件协同工作构成。我们需要先理解这个生态系统才能做出合理的选型。2.1 Vim补全机制的基础认知Vim本身内置了多种补全方式通过C-nCtrln和C-pCtrlp可以触发基于当前缓冲区、其他打开缓冲区以及包含文件include的简单关键字补全。但这对于大型项目是远远不够的因为它缺乏对代码语义如变量类型、函数参数、类成员的理解。因此我们需要借助外部工具来为Vim生成一个代码“地图”或“数据库”然后让Vim插件去查询这个数据库从而实现智能补全。这个过程主要依赖两个核心工具Ctags/Universal Ctags这是一个索引生成工具。它扫描源代码文件提取出函数、类、结构体、宏、变量等符号tags并记录其名称、类型和位置生成一个名为tags的索引文件。Vim可以读取这个文件来实现符号跳转和简单的补全。它是整个体系中最基础、历史最悠久的一环。Cscope这是比Ctags更强大的代码浏览工具尤其适合C语言项目。它不仅能查找符号定义还能查找函数的调用者、被调用的函数、字符串等。它生成自己的数据库。通常与Ctags配合使用。基于这两个工具衍生出了不同的插件方案。2.2 主流插件方案对比与选型目前Vim的代码补全插件主要有两大流派传统基于Tags的插件和现代基于Language Server ProtocolLSP的插件。方案一传统Tags系插件以OmniCppComplete为代表工作原理依赖ctags生成的tags文件。插件读取这个文件在补全时提供符号列表。OmniCppComplete在此基础上通过解析C头文件需要配合ctags的特殊参数来尝试提供有限的上下文感知比如补全对象.或对象-后的成员。优点轻量、配置相对简单、对系统资源消耗小。在代码结构清晰的中小型C/C项目中表现尚可。是很多老派Vim用户的经典选择。缺点对代码的“理解”非常有限。它本质上是一个增强版的符号列表无法理解复杂的模板、命名空间嵌套也无法提供实时的语法错误提示、函数参数提示签名帮助等高级功能。对于Python、Go、Rust等现代语言的支持也较弱或需要额外配置。方案二现代LSP系插件以coc.nvim、ALE、内置LSP为代表工作原理遵循微软发起的Language Server Protocol (LSP)。LSP的核心思想是将代码的语义分析功能剥离出来由一个独立的“语言服务器”Language Server进程负责。Vim插件作为LSP客户端与这个服务器通信。服务器深度理解代码提供补全、定义跳转、悬停提示、重构、错误诊断等全套IDE级功能。优点功能强大体验接近现代IDE。支持的语言极其广泛只要该语言有对应的Language Server如clangdfor C/C,pylsp/jedifor Python,goplsfor Go,rust-analyzerfor Rust等。提供精准的补全、实时的错误和警告提示。缺点配置比传统方案复杂需要安装和配置语言服务器。会启动额外的后台进程消耗更多内存和CPU资源。选型建议新手或轻量级用户如果你的项目主要是C/C且规模不大或者你主要在服务器等资源受限环境进行简单的编辑和调试可以从OmniCppCompletectags入手。它能解决“从无到有”的问题让你初步体验补全的便利。追求现代开发体验的用户如果你日常开发涉及多种语言如热词中提到的Python/PyCharm、C、Go等或者项目庞大复杂如Linux内核开发强烈推荐直接采用基于LSP的方案如coc.nvim或Vim 8.2/Neovim内置的LSP客户端。这是目前的主流和未来方向一次配置多种语言受益。考虑到热词中提到了OmniCppComplete和ctags也提到了pycharm代码补全设置、idea代码提示自动补全这类对现代IDE功能的向往本文将采取一种渐进式的讲解思路先详细讲解传统而经典的OmniCppComplete方案让你理解Vim补全的底层机制然后会重点介绍如何配置更强大的coc.nvimclangd方案实现媲美IDE的C/C开发体验。这样无论你的需求如何都能找到适合自己的路径。3. 基础实战配置OmniCppComplete与Ctags我们先从最经典的组合开始。这个方案是很多人的Vim补全启蒙理解它有助于我们后续应对更复杂的配置。3.1 环境准备与工具安装首先确保你的系统已安装必要的工具。这里以常见的Ubuntu/Debian和CentOS/Rocky Linux为例。# Ubuntu / Debian / Kali Linux sudo apt update sudo apt install vim vim-gtk3 ctags build-essential cmake # CentOS / Rocky Linux / Fedora sudo yum install vim-enhanced ctags gcc gcc-c make cmake # 或者使用 dnf (Fedora/新版Rocky) sudo dnf install vim-enhanced ctags gcc gcc-c make cmake注意这里安装的ctags通常是Exuberant Ctags。但更推荐使用其活跃分支Universal Ctags它支持更多语言和特性。你可以从GitHub源码编译安装Universal Ctags以获得更好体验。接下来安装Vim插件。传统方法是使用Vim的插件管理器如Vundle、vim-plug或Pathogen。这里以目前最流行的vim-plug为例进行安装和管理。安装vim-plug# 在终端中执行以下命令下载插件管理器 curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim配置.vimrc声明插件 编辑你的~/.vimrc文件如果不存在就创建在文件顶部附近添加vim-plug的配置块。 ~/.vimrc call plug#begin(~/.vim/plugged) 声明要安装的插件 Plug vim-scripts/OmniCppComplete call plug#end()这里我们直接使用了OmniCppComplete在vim-scripts镜像上的版本这是一个稳定但较旧的版本。你也可以寻找GitHub上维护更积极的fork版本。安装插件 保存并退出.vimrc然后重新打开Vim执行命令:PlugInstall。vim-plug会自动从网络下载并安装声明的插件。3.2 生成与配置Tags文件插件安装好后核心是要为你的项目生成一个高质量的tags文件。为系统头文件生成Tags 为了让Vim能补全标准库如std::vector,printf中的符号我们需要先为系统头文件生成tags。这通常只需要做一次。# 为C标准库生成tags假设使用g ctags -R --c-kindsp --fieldsiaS --extraq /usr/include/c/ # 为C标准库生成tags ctags -R --c-kindsp --fieldsiaS --extraq /usr/include/执行后会在当前目录生成一个tags文件。建议将其移动到某个固定位置比如~/.vim/tags/并在.vimrc中指向它。mkdir -p ~/.vim/tags mv tags ~/.vim/tags/systags为你的项目生成Tags 进入你的项目根目录使用更详细的参数运行ctags以包含足够的信息供OmniCppComplete使用。cd /path/to/your/project ctags -R --c-kindsp --fieldsiaS --extraq --languagesc,c .-R: 递归遍历目录。--c-kindsp: 为C代码启用对函数原型prototypes的支持这对补全很重要。--fieldsiaS: 在tags中包含继承信息i、访问控制a以及函数签名S。--extraq: 增加额外信息用于增强补全。--languagesc,c: 指定语言。在Vim中配置Tags路径 在~/.vimrc中添加以下配置告诉Vim去哪里寻找tags文件。./tags表示当前目录下的tags,后面的路径是向上级目录查找最后是系统tags。 设置tags文件的搜索路径 set tags./tags,tags,~/.vim/tags/systags3.3 配置OmniCppComplete并验证效果现在配置OmniCppComplete插件本身。在你的.vimrc中call plug#end()之后添加 OmniCppComplete 配置 按下Tab键时如果补全菜单打开则选择下一个项目否则尝试进行代码片段展开或普通缩进。 function! CheckBackspace() abort let col col(.) - 1 return !col || getline(.)[col - 1] ~# \s endfunction inoremap silentexpr Tab \ coc#pum#visible() ? coc#pum#next(1) : \ CheckBackspace() ? \Tab : \ coc#refresh() 设置自动关闭补全预览窗口 set completeoptmenuone,longest,preview 以下是一些针对C/C的Omni补全设置 允许在C/C代码中使用Omni补全 autocmd FileType c,cpp set omnifuncomni#cpp#complete#Main 设置命名空间和类成员的补全方式 let OmniCpp_NamespaceSearch 1 let OmniCpp_GlobalScopeSearch 1 let OmniCpp_ShowAccess 1 let OmniCpp_ShowPrototypeInAbbr 1 在补全菜单中显示函数原型 let OmniCpp_MayCompleteDot 1 输入 . 后自动弹出补全 let OmniCpp_MayCompleteArrow 1 输入 - 后自动弹出补全 let OmniCpp_MayCompleteScope 1 输入 :: 后自动弹出补全 let OmniCpp_DefaultNamespaces [std, _GLIBCXX_STD]配置解析与实操要点completeopt这个选项控制补全菜单的行为。menuone表示即使只有一个匹配项也显示菜单longest表示只插入所有匹配项的共同前缀preview会显示一个额外的预览窗口展示函数签名等详细信息。注意preview窗口有时会遮挡代码如果你觉得烦人可以去掉它。omnifunc这行是关键它为C/C文件类型设置了Omni补全函数指向OmniCppComplete插件提供的函数。以OmniCpp_开头的变量是插件的专属配置它们控制着补全的触发时机和显示内容。保持上述设置是一个不错的起点。验证与使用打开一个C源文件.cpp或.h。确保你已经在项目根目录包含tags文件。输入一个类或结构体名然后输入.或-看看是否会自动弹出补全菜单。如果没有可以手动按下C-xC-o先按Ctrlx再按Ctrlo来触发Omni补全。使用C-n和C-p在补全菜单中上下选择按回车确认。实操心得与避坑指南Tags更新问题项目代码改动后旧的tags文件不会自动更新。你需要定期或在添加大量新符号后重新运行ctags -R ...命令。可以写一个简单的Shell脚本或使用Vim的自动命令来辅助但这始终是个痛点。补全速度与准确性对于大型项目如Linux内核生成和加载庞大的tags文件会导致Vim启动变慢补全时也可能有卡顿。且ctags对复杂C模板、宏展开的理解有限补全结果可能不准确或缺失。仅限于C/COmniCppComplete顾名思义主要服务于C/C。虽然ctags支持其他语言但补全体验远不如专门的语言服务器。系统头文件Tags为系统头文件生成tags时可能会因为路径或权限问题失败。如果遇到问题可以尝试指定更具体的GCC版本路径如/usr/include/c/11/。4. 进阶实战搭建基于LSP的现代补全环境coc.nvim clangd如果你体验了OmniCppComplete后觉得“还行但不够爽”或者你主要使用Python、Go等语言那么是时候升级到LSP方案了。这里我们以coc.nvim配合C/C的语言服务器clangd为例打造一个IDE级别的开发环境。4.1 为什么选择coc.nvim和clangdcoc.nvim这是一个功能极其丰富的Vim/Neovim插件它本身是一个LSP客户端同时也集成了大量的IDE特性如代码诊断、片段补全、列表管理、浮动窗口等。它的配置使用JSON插件生态丰富通过CocInstall安装扩展是目前Vim生态中体验最接近VSCode的解决方案之一。clangd这是LLVM项目官方维护的C/C语言服务器。它基于Clang编译器对代码的理解能力远超ctags能提供极其精准的补全、实时的错误和警告提示、代码格式化、定义/引用跳转等功能。它是开发C/C项目的首选LSP服务器。4.2 安装与配置coc.nvim安装Node.jscoc.nvim基于Node.js所以首先需要安装Node.js版本14。# Ubuntu/Debian curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt install -y nodejs # CentOS/Rocky Linux curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash - sudo yum install -y nodejs使用vim-plug安装coc.nvim 编辑你的~/.vimrc在plug#begin和plug#end之间添加Plug neoclide/coc.nvim, {branch: release}保存并运行:PlugInstall。基础coc.nvim配置 在.vimrc中添加一些基础配置这些配置能极大改善体验。建议放在plug#end()之后。 coc.nvim 基础配置 使用Tab触发补全并导航 inoremap silentexpr TAB \ coc#pum#visible() ? coc#pum#next(1) : \ CheckBackspace() ? \Tab : \ coc#refresh() inoremap exprS-TAB coc#pum#visible() ? coc#pum#prev(1) : \C-h 使用回车键确认补全 inoremap silentexpr cr coc#pum#visible() ? coc#pum#confirm() : \C-gu\CR 使用 [g 和 ]g 来导航诊断信息错误/警告 nmap silent [g Plug(coc-diagnostic-prev) nmap silent ]g Plug(coc-diagnostic-next) 跳转到定义 nmap silent gd Plug(coc-definition) 跳转到类型定义 nmap silent gy Plug(coc-type-definition) 跳转到实现 nmap silent gi Plug(coc-implementation) 跳转到引用 nmap silent gr Plug(coc-references) 显示函数签名帮助在插入模式 autocmd CursorHoldI * silent! call CocActionAsync(showSignatureHelp) 重命名符号 nmap leaderrn Plug(coc-rename) 格式化选中代码 xmap leaderf Plug(coc-format-selected) nmap leaderf Plug(coc-format-selected)这些键位映射将为你提供一套流畅的操作逻辑。leader键默认为反斜杠\你可以通过let mapleader ,来更改。4.3 安装与配置clangd语言服务器coc.nvim本身不包含语言服务器需要单独安装和配置。安装clangd方法一推荐使用包管理器# Ubuntu/Debian (通常clangd在clangd包或llvm工具链中) sudo apt install clangd-12 # 或更新版本如clangd-14, clangd-15 # 如果安装后命令未找到可能需要创建符号链接或使用版本号调用 sudo update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-12 100 # CentOS/Rocky Linux sudo yum install epel-release sudo yum install clang-tools-extra # 这个包通常包含clangd方法二下载预编译二进制从 LLVM官网 下载对应系统的预编译包解压后将bin/clangd放到PATH路径下。为coc.nvim安装coc-clangd扩展 这个扩展是coc.nvim与clangd服务器之间的桥梁。在Vim中执行命令:CocInstall coc-clangd安装完成后可能需要重启Vim。项目级配置创建compile_commands.jsonclangd要精准工作需要知道你的项目是如何编译的包含了哪些头文件路径、定义了哪些宏、使用了哪些编译选项。这些信息通常记录在compile_commands.json文件中。如果你使用CMake这是最简单的。在构建目录中使用-DCMAKE_EXPORT_COMPILE_COMMANDSON选项。mkdir build cd build cmake -DCMAKE_EXPORT_COMPILE_COMMANDSON ..这会在build目录下生成compile_commands.json文件。在项目根目录创建一个软链接指向它ln -s build/compile_commands.json .如果你使用Makefile或其他构建系统可以使用bear或compiledb这类工具来拦截编译命令并生成compile_commands.json。# 安装bear sudo apt install bear # Ubuntu sudo yum install bear # CentOS (可能需要EPEL) # 使用bear运行你的构建命令 bear -- make如果没有compile_commands.jsonclangd会尝试基于文件猜测编译参数但这对于复杂项目往往不准可能导致头文件找不到、宏未定义等问题。强烈建议生成此文件。4.4 验证与体验LSP的强大功能完成以上步骤后打开一个C/C项目文件确保项目根目录有compile_commands.json。自动补全开始输入代码例如输入std::v你应该会立刻看到一个丰富的补全菜单包含vector、void等并且有详细的信息提示。错误诊断如果你的代码有语法错误或类型不匹配左侧装订线行号旁边会出现红色或黄色的波浪线或标记光标移到错误行时底部状态栏或浮动窗口会显示错误信息。悬停提示将光标停留在一个变量、函数或类名上稍等片刻或按K键会弹出一个浮动窗口显示该符号的详细信息定义、文档注释等。跳转功能将光标放在一个函数名上按gd我们之前映射的键Vim会直接跳转到该函数的定义处。按gr可以列出所有引用此函数的地方。签名帮助当你输入函数名并输入左括号(时会自动显示一个浮动窗口展示该函数的参数列表和文档。实操心得与高级技巧性能调优对于超大型项目如Linux内核clangd首次建立索引可能会消耗较多内存和时间。你可以在项目根目录创建一个.clangd配置文件来调整# .clangd CompileFlags: # 添加额外的编译参数例如指定C标准 Add: [-stdc17] Index: # 后台建立索引的线程数根据CPU核心数调整 Background: Build Threads: 4多配置管理coc.nvim的配置位于~/.config/nvim/coc-settings.jsonNeovim或~/.vim/coc-settings.jsonVim。你可以在这里进行更细致的全局设置例如禁用某些语言的LSP或者为特定文件类型设置不同的格式化工具。扩展其他语言coc.nvim的强大之处在于其扩展系统。安装其他语言的LSP支持非常简单例如Python::CocInstall coc-pyrightGo::CocInstall coc-goRust::CocInstall coc-rust-analyzer安装后通常无需复杂配置即可工作。与传统Tags共存你完全可以同时使用coc.nvim和ctags。coc负责精准的语义补全和诊断而ctags生成的tags文件可以用于一些coc不覆盖的符号跳转或者在不支持LSP的旧项目中使用。只需在.vimrc中保留set tags...的配置即可。5. 常见问题排查与效能优化指南无论选择哪种方案在实际使用中都可能遇到各种问题。这里记录了一些典型问题及其解决方法以及进一步提升体验的技巧。5.1 OmniCppComplete Ctags 常见问题问题现象可能原因解决方案输入.、-、::后无补全菜单弹出1. tags文件未生成或路径不对。2.omnifunc未正确设置。3. 插件未加载或配置冲突。1. 检查当前目录或tags路径设置下是否存在tags文件用:!ls tags查看。2. 用:set omnifunc?检查当前文件类型的Omni函数确保是omni#cpp#complete#Main。3. 检查.vimrc中插件声明和配置是否正确用:scriptnames查看插件是否被加载。补全菜单内容不全缺少类成员或标准库函数1. 生成tags时参数不正确缺少必要信息。2. 系统头文件tags未生成或未包含。1. 使用更完整的ctags参数重新生成确保包含--c-kindsp --fieldsiaS --extraq。2. 确认系统tags文件如~/.vim/tags/systags已生成并包含在set tags路径中。Vim启动或打开文件时非常慢项目tags文件过大Vim在加载时解析耗时。1. 考虑将tags文件从项目根目录移到子目录并只对核心源码生成tags。2. 使用set tags./tags,tags;中的;表示向上搜索到根目录避免加载过多无关tags。3. 换用LSP方案其索引加载是异步的不影响启动。补全时Vim卡顿或无响应同上tags文件过大补全时需要遍历整个tags数据库。同上。这是基于tags的补全方案在大型项目上的固有缺陷考虑升级到LSP。5.2 coc.nvim clangd 常见问题问题现象可能原因解决方案打开C/C文件后底部状态栏一直显示[coc.nvim] clangd is not found或initializing...1.clangd未安装或不在PATH中。2.coc-clangd扩展未安装成功。1. 在终端运行which clangd确认命令是否存在。如果通过版本号安装如clangd-12需要在coc-settings.json中指定路径{clangd.path: /usr/bin/clangd-12}。2. 在Vim中运行:CocList extensions查看coc-clangd是否已安装并启用。头文件找不到#include下面有红色波浪线1. 缺少compile_commands.json。2.compile_commands.json中的路径是绝对路径与当前环境不符。3. 项目使用了自定义的编译配置或交叉编译工具链。1.首要任务为项目生成compile_commands.json见4.3节。2. 检查compile_commands.json内容看directory和command字段中的路径是否正确。对于CMake通常在构建目录下生成是没问题的。3. 在.clangd配置文件中使用CompileFlags的Add或Remove选项来调整编译参数例如添加-I/path/to/your/include。补全不工作但诊断错误提示工作clangd可能正在索引或遇到了问题。补全功能依赖于完整的索引。1. 稍等片刻查看clangd的日志。在Vim中执行:CocCommand workspace.showOutput然后选择clangd查看是否有错误信息。2. 检查.clangd配置文件确保没有错误语法。coc.nvim的浮动窗口签名帮助、悬停提示不显示或显示位置不对可能与你的终端模拟器、Vim版本或配色方案有关。1. 确保使用较新的Vim8.2或Neovim并启用浮动窗口特性通常默认开启。2. 尝试在.vimrc中设置set termguicolors真彩色支持和set hidden。3. 如果使用tmux确保版本较新并可能需要在.tmux.conf中设置set -g default-terminal \tmux-256color\和set -ga terminal-overrides \,*256col*:Tc\。内存占用过高大型项目clangd为建立索引会消耗较多内存。1. 在.clangd中调整Index设置如Threads数。2. 考虑使用clangd的--background-index和--compile-args-fromfilesystem选项通过coc-settings.json配置。3. 如果项目实在太大可以只对正在开发的模块生成compile_commands.json而不是整个项目。5.3 通用优化与技巧异步更新Tags传统方案如果你坚持使用ctags可以安装vim-gutentags插件它可以在你保存文件时自动异步更新tags避免手动操作。多语言支持LSP方案coc.nvim的威力在于其扩展市场。通过:CocList marketplace可以浏览和安装各种语言的扩展。对于热词中提到的Python、Go等这是最佳选择。键位映射个性化本文提供的键位映射是通用习惯。你可以根据自己最常用的IDE如IDEA、VSCode的快捷键来重新映射coc.nvim的功能减少记忆负担。例如将gd映射到Ctrl鼠标点击等虽然纯键盘环境下意义不大。在服务器或容器中使用在SSH连接到远程服务器或进入Docker容器开发时LSP方案同样有效。你需要在远程环境也安装相应的语言服务器如clangd、pyright。coc.nvim可以通过SSH与远程LSP服务器通信需要额外配置但更简单的做法是在远程环境直接安装全套工具。应对网络问题安装coc.nvim扩展或更新时可能需要访问GitHub。如果网络不畅可以配置镜像源或者直接下载扩展的vsix文件进行离线安装:CocInstall /path/to/extension.vsix。从最初的ctags手动生成索引到半自动的OmniCppComplete再到如今功能完备的coc.nvimclangdVim的代码补全能力已经发生了翻天覆地的变化。这个过程本质上是我们将外部强大的语言理解工具编译器前端、语言服务器与Vim这个高效的编辑界面深度融合的过程。选择哪种方案取决于你的项目类型、技术栈和个人对“流畅度”与“功能”的权衡。对于全新的项目我毫无保留地推荐你投入时间配置LSP方案它带来的效率提升是革命性的。而对于一些遗留的、构建系统复杂的老项目或许传统的tags方案仍是快速上手的务实选择。无论如何让工具适应你的工作流而不是相反这才是Vim哲学的精髓所在。
返回列表