Vim 基础知识(Vim / Neovim / clangd 系列) 📖
背景
最近在配置 Linux 开发环境时,遇到了 Vim 这个"老朋友"。本来想装个 VSCode,结果环境特殊装不上 —— 这才发现:SSH 远程、服务器、容器这些场景下,Vim 才是默认配置。
于是决定把 Vim 体系系统学一遍,分三部分整理:
- 📖 第一部分:Vim 入门(本文)
- 🚀 第二部分:Neovim(现代化分支,待写)
- 🛠️ 第三部分:clangd(语言服务器,待写)
第一部分:Vim 入门
1.1 Vim 简介 📖
Vim(Vi improved)由 Bram Moolenaar 于 1991 年发布,是 Unix 经典编辑器 vi 的增强版。
血统
| 年份 | 编辑器 | 关键事件 |
|---|---|---|
| 1971 | ed | Ken Thompson 写的行编辑器 |
| 1976 | vi | Bill Joy 在 ed 基础上加可视化模式 |
| 1991 | Vim | Bram Moolenaar 在 Amiga 上发布第一个版本 |
| 2006 | Vim 7.0 | 加入拼写检查、撤销分支 |
| 2016 | Vim 8.0 | 加入异步任务、channel |
| 2023 | — | Bram Moolenaar 去世,社区接管维护 |
三个核心特征
| 特征 | 说明 |
|---|---|
| 模式化编辑 | 区分"普通模式 / 插入模式 / 命令模式",同一按键在不同模式下含义不同 |
| 完全键盘操作 | 双手不离主键盘区,理论上不需要鼠标 |
| 高度可配置 | 几乎所有行为都能通过 .vimrc 修改 |
💡 Vim 是 CSAPP、SICP 这些经典教材里"理所当然"的编辑器 —— 不是因为它新潮,而是因为它就是 Unix 工作流的核心。
1.2 Vim 能做什么 🎯
基础:纯文本编辑
- 打开、编辑、保存任何文本文件(
.txt、.md、.conf、源代码……) - 改 Linux 配置文件(
.bashrc、.gitconfig、各种.conf) - 写代码(C/C++、Python、Go、JS、任何语言)
- 写 Markdown、LaTeX
进阶:组合命令
Vim 的命令是可组合的:数字 + 动作 + 范围,例如:
| 命令 | 含义 |
|---|---|
dd | 删一行 |
5dd | 删 5 行 |
d$ | 从光标删到行尾 |
y3w | 复制 3 个单词 |
>G | 从当前行缩进到文件尾 |
实战:常用操作速查
| 类别 | 命令 | 作用 |
|---|---|---|
| 光标移动 | 0 / $ | 行首 / 行尾 |
gg / G | 文件首 / 文件尾 | |
Ctrl+f / Ctrl+b | 翻页 | |
/xxx | 搜索 xxx | |
| 编辑 | i / a | 插入(光标前 / 后) |
o | 下方新建一行并进入编辑模式 | |
dd / yy / p | 删 / 复制 / 粘贴 | |
u / Ctrl+r | 撤销 / 重做 | |
. | 重复上一次操作 | |
| 文件 | :w / :q / :wq | 保存 / 退出 / 保存退出 |
:e 文件名 | 打开文件 | |
:split / :vsplit | 分屏 | |
| 查找替换 | :%s/old/new/g | 全文替换 |
:noh | 取消搜索高亮 |
高阶能力(不装插件就有的)
- 录制宏:
qa开始录制、q停止、@a回放 —— 自动化重复操作 - 正则搜索:
/v\d+\.\d+搜版本号类字符串 - 命令历史:
:后按↑调出历史命令 - 多文件 buffer:
:bn/:bp在已打开的文件间切换 - 内置 diff:
vimdiff命令可以并排对比文件
Vim 的"主场"场景
| 场景 | 为什么 Vim 是最优解 |
|---|---|
| SSH 远程服务器 | 没有图形界面,只能用 Vim |
| Docker 容器里 | 镜像通常只装 vim/nano |
| 系统救援模式 | 启动失败时 Vim 是唯一能用的编辑器 |
| Git 冲突解决 | Git 默认调用 Vim 做 merge 编辑器 |
| 服务器配置文件 | 比 SSH 进去开 IDE 快 100 倍 |
💡 CSAPP 全书的实验都在 Linux 上跑,环境越"裸"(SSH / 容器 / 救援),Vim 越有用。
1.3 Vim 的缺陷 ⚠️
Vim 不是银弹,它有非常明显的短板:
1. 学习曲线极陡 🚨
| 阶段 | 时间 | 状态 |
|---|---|---|
| 入门 | 1-2 周 | 经常按错键、想用鼠标 |
| 熟练 | 1-2 个月 | 不用想快捷键,效率接近平时 |
| 精通 | 1-2 年 | 写自己的函数、自动化脚本 |
前两周会非常痛苦。这是 Vim 被吐槽最多的地方,也是被老用户"信仰化"的原因 —— 能坚持下来的人,编辑效率远超 IDE 用户。
2. 默认配置 ≈ 1991 年
刚装的 Vim 像刚发布时那样:丑、没补全、没导航。
- ❌ 没有行号(要自己
:set number) - ❌ 没有鼠标支持(要自己
:set mouse=a) - ❌ 没有自动缩进
- ❌ 没有代码高亮(要
:syntax on)
所有"现代化功能"都要自己配,或者用别人写好的配置(spf13-vim、vim-bootstrap 等)。
3. 生态分裂
Vim 现在有两大分支:
| 分支 | 状态 | 特点 |
|---|---|---|
| Vim | 原版 | 维护者 2023 年去世,社区接管 |
| Neovim | 2014 年 fork | 异步、原生 LSP、配置用 Lua,生态更活跃 |
两者大部分配置不通用,新插件优先支持 Neovim。
👉 这就是为什么本系列第二部分要专门讲 Neovim。
4. 现代 IDE 功能"缺"(不装插件时)
- ❌ 没有现代意义的代码补全
- ❌ 没有内置 LSP(Language Server Protocol)
- ❌ 没有图形化调试器(要装 vimspector / termdebug)
- ❌ 没有 Git 集成(要装 vim-fugitive)
- ❌ 没有数据库、REST Client 等扩展
结论:Vim 是"半成品",装插件后才是"完整 IDE"。这跟 VSCode 开箱即用完全相反。
5. 配置语言古老
Vim 自带的配置语言叫 Vim script(VimL),是 1980 年代风格的脚本:
" 注释是这样写的
function! Foo()
let l:bar = 'hello'
echo l:bar
endfunction- 没有现代模块系统
- 函数调用语法奇怪
- 调试困难
Neovim 已经支持 Lua 配置(更现代),但 Vim 本身仍然只能写 VimL。
6. 不适合"短平快"任务
| 任务 | 更好的工具 |
|---|---|
| 看 100MB 日志最后几行 | tail |
| 一次性替换配置 | sed |
| 大量粘贴 5000+ 行 | 会卡死 vim |
Vim 强项是反复编辑、持续维护的文件,不是"一次性"操作。
1.4 Vim vs Neovim:怎么选?🤔
学 Vim 之前一定要搞清楚这点 —— Vim 和 Neovim 的关系,以及应该先学哪个。
核心区别
| 维度 | Vim | Neovim |
|---|---|---|
| 配置语言 | VimL(老旧) | Lua(现代主推) |
| 原生 LSP | ❌ 需要装插件 | ✅ 0.5+ 内置 |
| 异步能力 | 弱 | 强 |
| 浮动窗口 | 弱 | ✅ 内置 |
| 终端 | 基础 | ✅ 更完善 |
| Tree-sitter | 第三方 | ✅ 一等公民 |
| 插件活跃度 | 维护中 | 更活跃 |
| 系统自带 | ✅ 几乎所有 Linux | ❌ 需要自己装 |
| 二进制大小 | ~10MB | ~20MB |
| 启动速度 | 极快 | 快 |
操作层面:基本一样
| 操作 | Vim | Neovim |
|---|---|---|
模式切换 i / Esc | ✅ | ✅ |
删除 dd | ✅ | ✅ |
搜索 / | ✅ | ✅ |
保存退出 :wq | ✅ | ✅ |
命令行 :!shell | ✅ | ✅ |
💡 也就是说:你学的所有"操作"在 Neovim 里完全通用,只有"配置"不一样。
配置层面:完全不一样
| 配置内容 | Vim 写法 | Neovim 推荐写法 |
|---|---|---|
| 设置选项 | set number | vim.opt.number = true |
| 快捷键 | nnoremap ... | vim.keymap.set('n', ...) |
| 函数 | function! | function() ... end |
| 插件管理 | vim-plug | lazy.nvim |
🚨 VimL 和 Lua 是两套独立的语言,投入学 VimL 的时间 ≈ 0 回报给 Neovim。
我的建议:先学 Vim 的"操作",直接用 Neovim
推荐路径
- 用
vimtutor学基础操作(30 分钟,Vim 自带) - 直接装 Neovim(Ubuntu 18.04 通过 PPA 装)
- 配置用 Lua 写(不要碰 VimL)
- 享受现代生态(LSP、Tree-sitter、async)
为什么不建议先学"完整 Vim"
- ❌ VimL 投入 100% 带不到 Neovim
- ❌ 老插件 / 老配置学了也用不上
- ❌
:set paste、:set nocompatible等 VimL 黑魔法浪费时间 - ❌ Vim 生态在收缩,新插件优先支持 Neovim
为什么不建议完全跳过 Vim
- ✅ Neovim 完全兼容 Vim 操作
- ✅ 服务器上没装 Neovim 时,Vim 是 fallback
- ✅
vimtutor是最经典的入门教材 - ✅ 理解了"为什么这么设计",配 Neovim 才有底气
一句话总结
学"操作 Vim",用"工具 Neovim",配"用 Lua" ✅
实际场景对照
| 场景 | 该用哪个 |
|---|---|
| 日常开发(自己的电脑) | Neovim |
| SSH 进服务器 | Vim(fallback) |
| 服务器没装 nvim | Vim(保底) |
| 临时改个配置 | 哪个能用用哪个 |
| 长期投入学习 | Neovim + Lua |
一句话总结
Vim 是一座"难进易出"的编辑器 —— 前两周痛苦,一辈子受益。它在 SSH、容器、服务器场景下无可替代,是程序员工具箱里最值得投资的一个 ✌️
第二部分:Neovim
Neovim 是什么?装它能解决 Vim 的哪些问题?这一部分给一个最小可用的 Neovim 上手指南。
2.1 Neovim 简介 🚀
Neovim 是 Thiago de Arruda 于 2014 年发起的 Vim fork 项目,目标是:在保持 Vim 强大操作哲学的同时,重构内部架构,引入现代化特性。
关键时间线
| 年份 | 事件 |
|---|---|
| 2014 | 项目启动,Kickstarter 众筹 32k 美金 |
| 2019 | 0.5.0 发布,原生 LSP 支持 |
| 2021 | Lua 配置成为主推 |
| 2023 | 0.9+ 大量改进 Tree-sitter、UI |
| 2024+ | GitHub stars 反超 Vim 8.x |
核心定位
| 维度 | Vim | Neovim |
|---|---|---|
| 哲学 | 稳定保守、保持 Unix 传统 | 激进创新、推陈出新 |
| 代码 | C + VimL | C + LuaJIT |
| LSP | 第三方插件 | 官方支持 |
| 维护状态 | 社区接管 | 活跃、年轻团队 |
💡 Neovim 几乎所有 Vim 的命令都兼容,你可以把 Vim 当成"基础课",Neovim 是"升级版"。
2.2 Neovim 能做什么 🎯
Vim 能做的,Neovim 都能做
第一部分讲的所有 i、dd、: 命令完全通用,零修改迁移。
Neovim 额外提供的能力
| 能力 | 说明 |
|---|---|
| 原生 LSP | 0.5+ 内置 vim.lsp.*,直接和 clangd、pyright 等对话 |
| Lua 配置 | 整本 Lua 文档随便用,比 VimL 清晰 10 倍 |
| Tree-sitter | 增量语法解析,代码高亮比 Vim 准 10 倍 |
| 异步任务 | UI 不阻塞,跑 clangd 不会卡 |
| 浮动窗口 | 补全、文档、定义预览都能用浮窗 |
| 内置终端增强 | :terminal 支持交互式 REPL |
一个例子感受差异
同样的"代码补全"功能:
| 工具 | 实现方式 | 体验 |
|---|---|---|
| Vim + YouCompleteMe | 编译 C++ 扩展 | 难装、慢 |
| Vim + coc.nvim | 装 Node.js + coc | 凑合 |
| Neovim + 内置 LSP + clangd | 装 clangd + 10 行 Lua | 稳、快、调试容易 |
🚀 这就是为什么学 C++/CSAPP 的人都在用 Neovim + clangd。
2.3 怎么安装 🛠️
你的环境是 Ubuntu 18.04 VM,下面以 Ubuntu 为重点。
Ubuntu / Debian(PPA,推荐)
# 1. 添加 Neovim 官方 PPA
sudo add-apt-repository ppa:neovim-ppa/stable
sudo apt update
# 2. 装 Neovim
sudo apt install neovim
# 3. 验证
nvim --version
# 应该输出 NVIM v0.7.x ~ v0.9.x版本不够新?
PPA 装的可能停在 0.7 / 0.8。Lua 配置 + LSP 完整支持要 0.9+。
装不上新版本时用 AppImage(见下)。
AppImage(任何 Linux,绕过包管理器)⭐ 推荐
# 1. 下载最新版 AppImage
curl -LO https://github.com/neovim/neovim/releases/download/stable/nvim.appimage
# 2. 赋予执行权限
chmod +x nvim.appimage
# 3. 移动到 PATH
sudo mv nvim.appimage /usr/local/bin/nvim
# 4. 验证
nvim --version💡 AppImage 是单文件可执行,不依赖系统库,Ubuntu 18.04 也能装最新版。
macOS
brew install neovimWindows
# scoop(推荐)
scoop install neovim
# 或 choco
choco install neovim启动
nvim第一次启动会看到纯净的 Neovim 界面 —— 跟 Vim 长一样,但内部不一样。
2.4 怎么配置 ⚙️
Neovim 推荐用 Lua 写配置,而不是 VimL。Lua 更现代、可读、易调试。
配置文件位置
| 平台 | 路径 |
|---|---|
| Linux | ~/.config/nvim/init.lua |
| macOS | ~/.config/nvim/init.lua |
| Windows | %LOCALAPPDATA%\nvim\init.lua |
# 创建配置目录和文件
mkdir -p ~/.config/nvim
nvim ~/.config/nvim/init.lua最小可用配置(5 分钟跑起来)
把这段内容直接复制到
init.lua:
-- ========== 基础选项 ==========
vim.g.mapleader = " " -- Leader 键设为空格
vim.opt.number = true -- 显示行号
vim.opt.relativenumber = true
vim.opt.expandtab = true -- Tab 转空格
vim.opt.tabstop = 4
vim.opt.shiftwidth = 4
vim.opt.smartindent = true
vim.opt.mouse = "a" -- 启用鼠标
vim.opt.ignorecase = true -- 搜索忽略大小写
vim.opt.smartcase = true
vim.opt.termguicolors = true -- 真彩色
vim.opt.signcolumn = "yes"
-- ========== 语法高亮 ==========
vim.cmd("syntax on")
vim.cmd("filetype plugin indent on")
-- ========== 常用快捷键 ==========
-- 插入模式 jk 退出(避免按 Esc 远)
vim.keymap.set("i", "jk", "<Esc>")
-- Ctrl+s 保存
vim.keymap.set("n", "<C-s>", ":w<CR>")
-- 清屏
vim.keymap.set("n", "<C-l>", "<C-l>")保存退出后重新 nvim,基础功能就有了 ✅
安装插件管理器 lazy.nvim
lazy.nvim 是 Neovim 生态最主流的插件管理器,纯 Lua、异步、UI 美观。
在 init.lua 末尾追加:
-- ========== 插件管理:lazy.nvim ==========
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({
"git", "clone", "--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable", lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
-- ========== 插件列表 ==========
require("lazy").setup({
-- 主题
{ "folke/tokyonight.nvim", lazy = false },
-- 文件树
{ "nvim-tree/nvim-tree.lua" },
-- 模糊搜索
{ "nvim-telescope/telescope.nvim",
dependencies = { "nvim-lua/plenary.nvim" } },
})装插件
nvim第一次启动会自动拉取 lazy.nvim 和所有插件。完成后:
| 快捷键 | 作用 |
|---|---|
: | 命令行 |
<leader>l | lazy.nvim 管理界面 |
<leader>e | 打开文件树 |
<leader>ff | Telescope 模糊找文件 |
💡 第一次跑可能慢,等几秒到几分钟(取决于网速)。
验证配置生效
nvim --headless "+lua print('Config OK!')" +q看到 Config OK! 就说明配置加载正常 ✅
配置目录结构
~/.config/nvim/
├── init.lua # 主配置
├── lua/ # Lua 模块
│ ├── plugins/ # 各插件配置(可选)
│ └── lsp/ # LSP 配置
└── lazy-lock.json # 插件版本锁文件💡 建议把
~/.config/nvim推到 git 仓库,方便备份和跨机器同步:bashcd ~/.config/nvim git init git remote add origin git@gitee.com:你的用户名/nvim-config.git
一句话总结
Neovim = Vim 的"操作" + Lua 的"配置" + 原生 LSP 的"现代 IDE 体验"。学完这一部分,你就拥有了一个 .lua 配置、轻量、跟 VSCode 一样有补全 的编辑器 ✌️
第三部分:clangd
clangd 是让 Neovim 实现"VSCode 级"代码补全的关键。这一部分讲清楚 clangd 是什么、装什么、配什么。
3.1 clangd 简介 🛠️
clangd 是 LLVM 团队开发的 C/C++/Objective-C 语言服务器,是 Clang 编译器家族的一员。
什么是"语言服务器"?
LSP(Language Server Protocol)是微软 2016 年提出的协议,目的是让编辑器和服务分离:
┌──────────┐ LSP 协议(JSON-RPC) ┌────────────┐
│ 编辑器 │ <---------------------------------> │ 语言服务器 │
│ Neovim │ • 补全请求 │ clangd │
│ VSCode │ • 跳定义请求 │ pyright │
│ Sublime │ • 悬停文档请求 │ rust-analyzer│
└──────────┘ └────────────┘任何支持 LSP 的编辑器都能用任何语言服务器,协议是统一的。
为什么选 clangd
| 语言服务器 | 维护者 | 状态 |
|---|---|---|
| clangd | LLVM 官方 | ✅ 活跃维护,基于真实 Clang 编译器 |
| ccls | 社区 | ❌ 2022 年停止维护 |
| cquery | 社区 | ❌ 已被 ccls 取代,又被 clangd 取代 |
💡 clangd 用的是真正的 Clang 前端,所以它"懂"你的代码和编译器一样深。
3.2 clangd 能做什么 🎯
编辑器能直接用的功能
| 功能 | 快捷键(Neovim 默认) | 说明 |
|---|---|---|
| 代码补全 | 输入时自动弹出 | 跟 VSCode 一样 |
| 跳到定义 | gd | 光标下函数 / 变量 → 跳过去 |
| 悬停文档 | K | 弹出函数签名、注释 |
| 查找引用 | gr | 列出所有用到这个符号的地方 |
| 重命名 | <leader>rn | 全局改名(自动改所有引用) |
| 诊断信息 | 自动 | 实时显示红黄波浪线 |
| 跳到错误 | ]d / [d | 编译前就能看到错 |
| 代码格式化 | 保存时自动 | 用 .clang-format 规则 |
| 符号搜索 | <leader>fs | 工作区找函数 / 变量 |
| 悬浮参数提示 | 输入 ( 后 | 显示函数参数 |
跟 VSCode 的对比
| 功能 | VSCode C/C++ 扩展 | Neovim + clangd |
|---|---|---|
| 代码补全 | ✅ | ✅ |
| 跳定义 | F12 | gd |
| 悬停文档 | 鼠标悬停 | K |
| 重命名 | F2 | <leader>rn |
| 错误检查 | ✅ | ✅ |
| Debug | GUI 按钮 | :termdebug |
| 内存查看 | GUI | 写 gdb 命令 |
🚀 90% 的功能完全等价,只是快捷键不同。
3.3 怎么安装 🛠️
重点:你的环境是 Ubuntu 18.04 VM,并且已经加过 LLVM 官方源。
第一步:查可用版本
apt-cache search 'clangd'输出类似:
clangd-10
clangd-11
clangd-12
clangd-13⚠️ Ubuntu 18.04 上 LLVM 14+ 不再发布包,所以最高就是
clangd-13。
第二步:装最高版本
sudo apt install clangd-13第三步:让 clangd 命令直接可用
sudo update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-13 100
clangd --version看到版本号(带 Ubuntu 字样)就成功了 ✅
备选方案 A:snap(如果有 snapd 且能用)
sudo snap install clangd备选方案 B:GitHub 下载预编译二进制
LATEST=$(curl -sL https://api.github.com/repos/clangd/clangd/releases/latest \
| grep tag_name | cut -d '"' -f 4 | sed 's/^v//')
# 假设是 13.0.2
wget https://github.com/clangd/clangd/releases/download/${LATEST}/clangd-linux-${LATEST}.zip
unzip clangd-linux-${LATEST}.zip
sudo mv clangd_${LATEST}/bin/clangd /usr/local/bin/
clangd --version💡 GitHub 二进制版本更新,但需要 glibc 支持。bionic 最高能跑 clangd 16 左右。
macOS
brew install clangdWindows
scoop install llvm
# clangd 自动在 PATH 里3.4 怎么配置 ⚙️
clangd 装好后,关键是让 Neovim 调用它。这部分讲最小集成。
原理:LSP 工作流
┌─────────┐ 你按 `gd` ┌──────────┐ JSON-RPC ┌────────┐
│ Neovim │ ------------> │ LSP 客户端│ <------------> │ clangd │
│ │ <-- 弹窗/跳转--│ (内置) │ │ 进程 │
└─────────┘ └──────────┘ └────────┘
↑
读 compile_commands.json
知道项目编译参数(include 路径、宏定义等)第一步:装 LSP 插件
在 init.lua 的 lazy.nvim 配置里加这几行:
require("lazy").setup({
-- 已有插件...
-- LSP 核心
{ "neovim/nvim-lspconfig" },
-- 补全引擎
{ "hrsh7th/nvim-cmp" },
{ "hrsh7th/cmp-nvim-lsp" }, -- LSP 补全源
{ "L3MON4D3/LuaSnip" }, -- 补全片段引擎
{ "saadparwaiz1/cmp_luasnip" }, -- 桥接 cmp + LuaSnip
{ "hrsh7th/cmp-path" }, -- 路径补全
})第二步:写 LSP 配置
在 init.lua 里追加:
-- ========== LSP 配置 ==========
local cmp = require("cmp")
local lspconfig = require("lspconfig")
-- 启用 clangd
lspconfig.clangd.setup({
capabilities = require("cmp_nvim_lsp").default_capabilities(),
})
-- 补全引擎
cmp.setup({
snippet = {
expand = function(args)
require("luasnip").lsp_expand(args.body)
end,
},
mapping = cmp.mapping.preset({
["<C-Space>"] = cmp.mapping.complete(),
["<CR>"] = cmp.mapping.confirm({ select = false }),
["<Tab>"] = cmp.mapping.select_next_item(),
["<S-Tab>"] = cmp.mapping.select_prev_item(),
}),
sources = cmp.config.sources({
{ name = "nvim_lsp" }, -- 来自 clangd 的补全
{ name = "path" }, -- 文件路径补全
}),
})
-- ========== LSP 快捷键 ==========
vim.keymap.set("n", "gd", vim.lsp.buf.definition, { desc = "跳到定义" })
vim.keymap.set("n", "K", vim.lsp.buf.hover, { desc = "悬停文档" })
vim.keymap.set("n", "gr", vim.lsp.buf.references, { desc = "查找引用" })
vim.keymap.set("n", "<leader>rn", vim.lsp.buf.rename, { desc = "重命名" })
vim.keymap.set("n", "<leader>ca", vim.lsp.buf.code_action, { desc = "代码操作" })
vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, { desc = "上一个错误" })
vim.keymap.set("n", "]d", vim.diagnostic.goto_next, { desc = "下一个错误" })
-- 保存时自动格式化
vim.api.nvim_create_autocmd("BufWritePre", {
pattern = { "*.c", "*.cpp", "*.h", "*.hpp" },
callback = function()
vim.lsp.buf.format({ async = true })
end,
})第三步:生成 compile_commands.json(关键!)
clangd 需要知道项目的编译参数(include 路径、宏定义、标准版本……),通过 compile_commands.json 传递。
CMake 项目
mkdir build && cd build
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
# 会在 build/ 下生成 compile_commands.jsonMakefile / 普通项目
sudo apt install bear
cd ~/xyb/book/csapp
bear -- make
# 当前目录生成 compile_commands.json告诉 clangd 找这个文件
在项目根目录创建 .clangd:
CompileFlags:
CompilationDatabase: build💡
build是 compile_commands.json 所在的目录,相对当前项目的路径。
第四步:验证
打开一个 .c 文件,几秒后应该看到:
| 现象 | 说明 |
|---|---|
输入 printf 弹出补全列表 | ✅ LSP 工作中 |
光标在 printf 上按 K 弹文档 | ✅ hover 工作中 |
按 gd 在 main 上跳到定义 | ✅ definition 工作中 |
| 红黄波浪线提示语法错误 | ✅ diagnostic 工作中 |
🎉 全部能用 = clangd 集成成功!
常见问题
| 问题 | 原因 | 解决 |
|---|---|---|
| 补全不出现 | compile_commands.json 缺失或路径错 | 检查 .clangd 里 CompilationDatabase |
| 提示 "GLIBC 找不到" | clangd 太新 | 用 clangd-13 而不是 GitHub 最新版 |
| 跳定义跳到奇怪的地方 | include 路径没识别 | 看 :LspLog 排查 |
| 补全卡顿 | 文件太大 | :lua vim.lsp.stop_client(vim.lsp.get_active_clients()) |
一句话总结
clangd = 真实 Clang 编译器的"补全版"。装上它 + 配好 LSP + 生成
compile_commands.json,Neovim 立刻有了 VSCode 90% 的 C/C++ 体验,还更轻量、更可定制 ✌️
系列完结 🎉
到这里 Vim / Neovim / clangd 三部分就讲完了:
- 📖 第一部分:Vim 入门——理解了"为什么这样设计"
- 🚀 第二部分:Neovim——学会了现代化配置
- 🛠️ 第三部分:clangd——让编辑器有 IDE 体验
接下来学 CSAPP 时,按这个顺序走就够了:
vimtutor(30 分钟) → 装 Neovim + 配 init.lua → 装 clangd-13 + 生成 compile_commands.json
基础操作 现代化配置 跟 VSCode 一样的补全💡 工具链准备完后,所有精力都放到 CSAPP 本身——读、写、跑、调。这三件工具是"基础设施",搭好就不要再折腾了 🚀