nv Neovim 实战指南 2026
// 从「用过很久但不深」到「真正的主力编辑器」

正确地把 Neovim 用起来

这份教程从零搭一套现代、模块化、可按需裁剪的 Neovim 配置:先讲心法,再讲插件体系,然后用 React 与 Python 两个完整实例把整条链路跑通,最后告诉你怎么扩展任意语言、怎么只加载想要的功能、怎么塞进你自己的配置。

Neovim 0.12 lazy.nvim Mason 原生 vim.lsp blink.cmp Treesitter conform.nvim Telescope

00 心法与目标

很多人「用过很久 Vim/Neovim」却没进入高强度状态,卡点几乎都不在配置,而在两件事没建立起来:

  • 模态编辑的肌肉记忆。真正的效率来自 motion + operator 的组合(diw、ci"、ya}),而不是插件。配置只是放大器——肌肉记忆是本金。
  • 「编辑器即配置」的心智模型。Neovim 的一切都是可被 Lua 读写的状态。理解「插件管理器 → 语言服务器 → 语法树 → 补全」这四层各自负责什么,配置就不再是抄来的黑魔法。

所以本教程刻意采用从零手搭、模块化的方式,而不是直接套用 LazyVim 这类发行版。发行版能让你五分钟有个 IDE,但你想要的是「能扩展、能裁剪、能看懂每一行」——那必须自己搭一遍。

🧠 现代 Neovim 的四层模型

① 插件管理器(lazy.nvim)决定装什么、何时加载 → ② LSP(vim.lsp + Mason)提供跳转/补全/诊断/重命名 → ③ Treesitter 提供精确的语法高亮与文本对象 → ④ 补全引擎(blink.cmp)把 LSP 的候选项渲染成菜单。后面所有内容都是在填这四个格子。

01 安装与目录结构

先确认版本。本教程依赖 Neovim 0.11+ 的原生 LSP APIvim.lsp.config / vim.lsp.enable),0.12 还自带了 vim.pack 插件管理器与 :lsp 命令组。你是 Arch 用户,直接上仓库版即可:

shell
# Arch
sudo pacman -S neovim ripgrep fd git
nvim --version   # 确认 ≥ 0.11,最好 0.12

# macOS(你的 M3 Max 那台)
brew install neovim ripgrep fd

ripgrep(rg)和 fd 是后面全局搜索/找文件的后端,强烈建议一起装。再装一个 Nerd Font(如 JetBrainsMono Nerd Font)让图标正常显示。

目录结构:一个文件一个职责

所有配置都在 ~/.config/nvim/。入口是 init.lua,但我们让它只负责「按顺序 require 各模块」,真正的内容拆进 lua/ 下。这样删一个文件就等于删一块功能。

~/.config/nvim/ 目录树
~/.config/nvim/
├── init.lua                # 唯一入口,只做 require
├── lua/
│   ├── config/
│   │   ├── options.lua     # 选项 + leader 键
│   │   ├── keymaps.lua     # 全局快捷键
│   │   ├── autocmds.lua    # 自动命令
│   │   └── lazy.lua        # 引导插件管理器
│   └── plugins/            # 每个文件 = 一个/一组插件,自动加载
│       ├── treesitter.lua
│       ├── telescope.lua
│       ├── lsp.lua
│       ├── completion.lua
│       ├── formatting.lua
│       ├── ui.lua
│       ├── lang-react.lua  # 语言专属,可整文件增删
│       └── lang-python.lua
└── after/
    └── ftplugin/           # 按文件类型的局部设置
        └── python.lua
init.lua
-- 顺序很重要:options 里设了 leader,必须早于插件加载
require("config.options")
require("config.keymaps")
require("config.autocmds")
require("config.lazy")     -- 最后引导 lazy.nvim

02 基础配置(先不碰插件)

在装任何插件之前,先把裸 Neovim 调舒服。这能帮你分清「哪些行为是内置的,哪些是插件给的」。

lua/config/options.lua
-- Leader 键必须在加载插件前设置,否则插件按键映射会用错前缀
vim.g.mapleader = " "          -- 空格作为 leader
vim.g.maplocalleader = "\\"

local opt = vim.opt
opt.number = true              -- 行号
opt.relativenumber = true      -- 相对行号(配合 5j / 3k 跳转)
opt.mouse = "a"
opt.clipboard = "unnamedplus"  -- 与系统剪贴板打通
opt.expandtab = true           -- Tab 转空格
opt.shiftwidth = 2
opt.tabstop = 2
opt.smartindent = true
opt.ignorecase = true          -- 搜索忽略大小写……
opt.smartcase = true           -- ……但含大写时区分
opt.termguicolors = true       -- 真彩色,主题正常显示的前提
opt.signcolumn = "yes"         -- 常驻标记列,避免诊断图标抖动
opt.scrolloff = 8              -- 光标上下保留 8 行
opt.undofile = true            -- 持久化撤销历史
opt.splitright = true
opt.splitbelow = true
lua/config/keymaps.lua
local map = vim.keymap.set

map("n", "<leader>w", "<cmd>w<cr>", { desc = "保存" })
map("n", "<leader>q", "<cmd>q<cr>", { desc = "退出" })
map("n", "<Esc>", "<cmd>nohlsearch<cr>", { desc = "清除搜索高亮" })

-- 窗口间移动
map("n", "<C-h>", "<C-w>h"); map("n", "<C-l>", "<C-w>l")
map("n", "<C-j>", "<C-w>j"); map("n", "<C-k>", "<C-w>k")

-- 可视模式下移动选中行
map("v", "J", ":m '>+1<cr>gv=gv")
map("v", "K", ":m '<-2<cr>gv=gv")
为什么 leader 选空格

空格在普通模式下默认无用、位置居中、双手都能按,是社区事实标准。后面所有自定义命令都会挂在 Space 后面,形成一套你自己的命令树。

03 插件管理器:lazy.nvim

lazy.nvim 是目前的主流选择,核心卖点是惰性加载(lazy-loading):插件默认不在启动时加载,而是在某个事件、命令、按键或文件类型触发时才加载。这正是「只加载想要的功能」的底层机制。

lua/config/lazy.lua
-- 自动 clone lazy.nvim 到 data 目录(首次启动)
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
  vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable",
    "https://github.com/folke/lazy.nvim.git", lazypath })
end
vim.opt.rtp:prepend(lazypath)

require("lazy").setup({
  spec = {
    -- 关键:自动导入 lua/plugins/ 下的每一个文件作为插件规格
    { import = "plugins" },
  },
  install = { colorscheme = { "habamax" } },
  checker = { enabled = true, notify = false },  -- 后台检查更新
})

有了 { import = "plugins" }lua/plugins/ 里每个返回插件表的 .lua 文件都会被自动收录。新增语言 = 新建一个文件;移除 = 删掉它。这就是模块化的好处。

常用命令::Lazy 打开管理面板,:Lazy sync 安装/更新/清理,:Lazy profile 看每个插件的启动耗时。

💡 0.12 也内置了 vim.pack

Neovim 0.12 自带 vim.pack.add{...},足以管理插件且零依赖。但它目前还缺 lazy.nvim 那套成熟的惰性加载与 UI,所以本教程仍以 lazy.nvim 为主。知道有这个选项即可。

04 核心插件(与语言无关)

这些插件无论你写什么语言都用得上,先把它们配好。每个都是 lua/plugins/ 下独立的一个文件。

Treesitter — 精确语法树

它用真正的语法解析器替代正则高亮,带来更准的高亮、缩进,以及基于语法的文本对象(如「选中整个函数」)。

lua/plugins/treesitter.lua
return {
  "nvim-treesitter/nvim-treesitter",
  branch = "master",            -- 经典稳定分支(main 分支正在重写中)
  build = ":TSUpdate",
  event = { "BufReadPost", "BufNewFile" },  -- 打开文件时才加载
  opts = {
    ensure_installed = { "lua", "vim", "vimdoc", "bash", "markdown" },
    highlight = { enable = true },
    indent = { enable = true },
  },
  config = function(_, opts)
    require("nvim-treesitter.configs").setup(opts)
  end,
}

Telescope — 模糊查找一切

找文件、全局搜内容、找缓冲区、搜帮助……都靠它。后端用前面装的 rgfd

lua/plugins/telescope.lua
return {
  "nvim-telescope/telescope.nvim",
  dependencies = {
    "nvim-lua/plenary.nvim",
    { "nvim-telescope/telescope-fzf-native.nvim", build = "make" },
  },
  cmd = "Telescope",            -- 按命令惰性加载
  keys = {                      -- 也可按键触发;按下才加载
    { "<leader>ff", "<cmd>Telescope find_files<cr>", desc = "查找文件" },
    { "<leader>fg", "<cmd>Telescope live_grep<cr>",  desc = "全局搜索" },
    { "<leader>fb", "<cmd>Telescope buffers<cr>",    desc = "缓冲区" },
    { "<leader>fh", "<cmd>Telescope help_tags<cr>",  desc = "帮助文档" },
  },
  config = function()
    require("telescope").setup({})
    pcall(require("telescope").load_extension, "fzf")
  end,
}

其余必备件

把这些丢进一个 ui.lua 里。这里只列清单和用途,配置都很短,按各自 README 抄即可:

插件作用
folke/which-key.nvim按下 leader 后弹出可用快捷键提示,新手期的救命稻草
nvim-lualine/lualine.nvim状态栏
lewis6991/gitsigns.nvim行内 git 变更标记、blame
stevearc/oil.nvim把目录当成可编辑的 buffer 来管理文件(比传统侧边栏更顺手)
echasnovski/mini.nvim一个模块合集:mini.pairs 自动补括号、mini.surround 包裹/修改成对符号等
catppuccin/nvim配色主题,挑一个 vim.cmd.colorscheme(...)

05 LSP 系统:跳转、补全、诊断、重命名

这是从「文本编辑器」升级到「IDE 级」的关键一层。先理清三个常被混淆的角色:

客户端(Neovim 自带)

Neovim 内置的 vim.lsp 模块,负责和语言服务器对话、处理跳转/诊断/重命名/悬浮等。这部分不需要插件。

服务器(第三方程序)

lua-language-serverpyrightvtsls。它们是独立可执行文件,Neovim 不会自带,要单独装。

安装器 + 配置仓库

Mason 帮你下载服务器二进制;nvim-lspconfig 提供各服务器的默认配置(命令、文件类型、根目录标记),供原生 vim.lsp.enable() 读取。

0.11 起的原生流程极简:用 vim.lsp.config(name, {...}) 写/改配置,用 vim.lsp.enable(name) 启用。nvim-lspconfig 现在的职责主要就是提供这些预置配置,你只需覆盖想改的部分。

lua/plugins/lsp.lua
return {
  "neovim/nvim-lspconfig",
  dependencies = {
    { "mason-org/mason.nvim", opts = {} },     -- 安装器
    "mason-org/mason-lspconfig.nvim",          -- 桥接 mason 与 lspconfig
    "saghen/blink.cmp",                        -- 补全(提供 capabilities)
  },
  event = { "BufReadPre", "BufNewFile" },
  config = function()
    -- ① 给所有 server 注入补全能力(来自 blink.cmp)
    vim.lsp.config("*", {
      capabilities = require("blink.cmp").get_lsp_capabilities(),
    })

    -- ② 让 Mason 确保这些 server 已安装,装好后自动 enable
    require("mason-lspconfig").setup({
      ensure_installed = { "lua_ls" },   -- 通用的放这;语言专属的放各自文件
      automatic_enable = true,
    })

    -- ③ 针对单个 server 覆盖默认配置
    vim.lsp.config("lua_ls", {
      settings = { Lua = { diagnostics = { globals = { "vim" } } } },
    })

    -- ④ 快捷键:只在 LSP 真正挂到某个 buffer 时才绑定
    vim.api.nvim_create_autocmd("LspAttach", {
      callback = function(args)
        local m = function(k, fn, d)
          vim.keymap.set("n", k, fn, { buffer = args.buf, desc = "LSP: " .. d })
        end
        m("gd", vim.lsp.buf.definition, "跳转到定义")
        m("gD", vim.lsp.buf.declaration, "跳转到声明")
        m("<leader>ca", vim.lsp.buf.code_action, "代码操作")
        m("<leader>rn", vim.lsp.buf.rename, "重命名")
        m("<leader>d", vim.diagnostic.open_float, "查看诊断")
      end,
    })

    -- ⑤ 诊断显示样式(可选)
    vim.diagnostic.config({ virtual_text = true, severity_sort = true })
  end,
}
💡 0.11 已内置一批 LSP 默认键

无需配置即可用:K 悬浮文档、grn 重命名、gra 代码操作、grr 查找引用、gri 跳实现、<C-s>(插入模式)签名帮助。上面只是再补几个你顺手的别名。

调试 LSP 的命令::checkhealth vim.lsp 看哪些配置已启用、是否挂载成功;:Mason 看/装服务器;:lsp restart(0.12)重启服务器;:LspLog 看日志。

06 补全引擎:blink.cmp

LSP 产出候选项,补全引擎负责把它们渲染成菜单并处理按键。blink.cmp 是当前的现代选择:Rust 写的模糊匹配、每次按键 0.5–4ms、开箱即用。老牌的 nvim-cmp 也很好,但要拼装一堆 source 插件,blink 更省心。

lua/plugins/completion.lua
return {
  "saghen/blink.cmp",
  dependencies = { "rafamadriz/friendly-snippets" },
  version = "1.*",              -- 用稳定的 v1;v2 仍在大改
  event = "InsertEnter",        -- 进入插入模式才加载
  opts = {
    keymap = { preset = "default" },  -- <C-y> 确认, <C-n/p> 选择, <C-e> 关闭
    appearance = { nerd_font_variant = "mono" },
    completion = {
      documentation = { auto_show = true, auto_show_delay_ms = 250 },
    },
    sources = {
      -- 来源顺序即优先级:LSP 最先
      default = { "lsp", "path", "snippets", "buffer" },
    },
    fuzzy = { implementation = "prefer_rust_with_warning" },
  },
}

注意 lsp.lua 里那行 require("blink.cmp").get_lsp_capabilities()——它把「我支持哪些补全特性」告诉每个语言服务器,两者就此打通。如果换 nvim-cmp,对应换成 cmp_nvim_lsp 的 capabilities 即可。

07 格式化与 Lint

LSP 有时也能格式化,但用专门工具更可控。conform.nvim 负责格式化(保存时自动跑),nvim-lint 负责跑独立 linter。两者都按文件类型映射工具,扩展语言时只需往表里加一行。

lua/plugins/formatting.lua
return {
  "stevearc/conform.nvim",
  event = "BufWritePre",
  cmd = "ConformInfo",
  opts = {
    formatters_by_ft = {
      lua = { "stylua" },
      -- 各语言的格式化器,在下面两个实例里继续填
    },
    -- 保存时格式化;某文件类型没配工具就回退到 LSP 自带的格式化
    format_on_save = { timeout_ms = 1000, lsp_format = "fallback" },
  },
}
格式化器也由 Mason 安装

styluaprettierdruff 这些工具同样可以在 :Mason 里搜索安装,或用 mason-tool-installer 自动装。conform/lint 会在 PATH 里找它们。

08 实例一:React 前端环境

目标链路:TS/TSX 类型与跳转 + ESLint 诊断 + Tailwind 类名补全 + Emmet 展开 + Prettier 保存即格式化。把语言专属的东西集中到一个文件,这样整套前端能力就是「一个文件的存在与否」。

① 安装服务器与工具(Mason)

:Mason 里安装,或写进 ensure_installed

角色工具
TS/JS 语言服务器vtsls(或 ts_ls
ESLinteslint(LSP 形态,可保存自动修复)
Tailwindtailwindcss
Emmetemmet_language_server
HTML / CSShtml, cssls
格式化prettierd(快,常驻进程)

② 语言专属配置文件

lua/plugins/lang-react.lua
return {
  "neovim/nvim-lspconfig",     -- 复用同一插件,lazy 会合并配置
  opts = function()
    -- 让 Mason 确保这些已装
    vim.list_extend(require("mason-lspconfig").get_installed_servers and {} or {}, {})
  end,
  config = function()
    -- ESLint:保存时自动 EslintFixAll
    vim.lsp.config("eslint", {
      on_attach = function(_, bufnr)
        vim.api.nvim_create_autocmd("BufWritePre", {
          buffer = bufnr, command = "EslintFixAll",
        })
      end,
    })

    -- 启用这一组前端服务器
    vim.lsp.enable({
      "vtsls", "eslint", "tailwindcss",
      "emmet_language_server", "html", "cssls",
    })
  end,
}
⚠ 关于多文件配置同一插件

lazy.nvim 会把多个 spec 的 opts 合并,但 config 函数只会执行最后一个。所以更稳妥的做法:把 vim.lsp.enable 的服务器列表统一放进主 lsp.lua,或在各语言文件里用 init/独立的非冲突插件来挂钩子。下面 Python 实例演示更干净的「独立文件」写法。

③ 补上 Treesitter 解析器与格式化器

treesitter.luaensure_installed 加上:tsx, typescript, javascript, html, css, json。在 formatting.luaformatters_by_ft 加上:

formatting.lua(片段)
local prettier = { "prettierd", "prettier", stop_after_first = true }
formatters_by_ft = {
  lua = { "stylua" },
  javascript = prettier,  javascriptreact = prettier,
  typescript = prettier,  typescriptreact = prettier,
  css = prettier,  html = prettier,  json = prettier,
}

打开一个 Vite + React 项目里的 .tsxvtsls 会基于 package.json/tsconfig.json 自动定位项目根并启动。gd 跳组件定义、K 看类型、Tailwind 类名自动补全、保存自动 Prettier+ESLint。

09 实例二:Python 环境

现代 Python 组合是类型检查 + 极速 lint/format 分工basedpyright(或 pyright)负责类型与跳转,ruff 负责 lint、格式化、整理 import。ruff 自带 LSP(ruff server),一个工具顶过去一堆。

① Mason 安装

basedpyrightruff。(旧的 ruff-lsp 已废弃,直接用 ruff 即可。)

② 用「独立文件 + 独立插件」干净挂钩子

这次不去和主 lsp.luaconfig。我们用一个轻量插件 nvim-lspconfig 之外的钩子方式——直接在文件里写 vim.lsp.config 覆盖、再 enable,并通过一个一次性的 init 完成。最稳的写法其实是把所有 vim.lsp.enable 收进主文件,但若想保持「一个语言一个文件」,可用如下自成一体的写法:

lua/plugins/lang-python.lua
return {
  "neovim/nvim-lspconfig",
  init = function()
    -- init 在插件加载前运行,可叠加而不互相覆盖
    -- basedpyright:类型检查交给它
    vim.lsp.config("basedpyright", {
      settings = {
        basedpyright = {
          analysis = { typeCheckingMode = "standard" },
        },
      },
    })

    -- ruff:关掉它的 hover,让 basedpyright 提供文档,避免重复
    vim.lsp.config("ruff", {
      on_attach = function(client)
        client.server_capabilities.hoverProvider = false
      end,
    })

    vim.lsp.enable({ "basedpyright", "ruff" })
  end,
}
💡 为什么用 init 而不是 config

lazy 中每个插件的 init 都会执行(不会被覆盖),且早于插件加载;而同插件多个 config 只保留最后一个。用 initvim.lsp.config/enable 既安全又能保持「一个语言一个文件」。

③ Treesitter 与格式化

ensure_installedpython, toml。格式化交给 ruff:

formatting.lua(片段)
formatters_by_ft = {
  -- ……前面的
  python = { "ruff_organize_imports", "ruff_format" },
}

打开 .py 文件(项目里有 pyproject.toml.git 即可定位根目录),basedpyright 给类型提示与跳转,ruff 标出 lint 问题、保存时整理 import 并格式化。要调试可再加 mfussenegger/nvim-dap + debugpy,按需即可。

10 扩展任意自己的语言(通用配方)

看完两个实例,你应该已经发现:加一门语言永远是同样的四步。把这个配方背下来,以后加 Go、Rust、Zig 都是机械操作。

装语言服务器

:Mason 搜索安装(或写进 ensure_installed)。不知道叫什么?去 nvim-lspconfig 的 lsp/ 目录或 Mason 列表里查。

启用(必要时覆盖配置)

新建 lua/plugins/lang-xxx.lua,在 initvim.lsp.enable("server");要改设置就先 vim.lsp.config("server", {...})

加 Treesitter 解析器

把语言名加进 ensure_installed,获得高亮、缩进与文本对象。

挂格式化器 / linter

在 conform 的 formatters_by_ft(必要时 nvim-lint)里加一行映射。

用你正在学的 Rust 走一遍——Rust 比较特殊,社区推荐用 rustaceanvim 这个封装插件,它内部驱动 rust-analyzer 并加上 inlay hints、cargo 集成等,不要再手动 vim.lsp.enable("rust_analyzer")

lua/plugins/lang-rust.lua
return {
  "mrcjkb/rustaceanvim",
  version = "^6",
  lazy = false,                -- 它是 ftplugin,自己管理加载
  -- 装好 rustup + rust-analyzer 后开箱即用
  -- 自定义放 vim.g.rustaceanvim = { ... }
}

再加 Treesitter 的 rust 解析器、conform 里 rust = { "rustfmt" }——三步搞定。这说明配方里的「启用方式」可以替换成插件,但语法树、格式化两步永远一致

11 如何只加载想要的功能

「只加载想要的」有两个层次:结构上只装你需要的插件,以及运行时只在需要时才加载。后者靠 lazy.nvim 的触发条件实现。

四种惰性加载触发器

字段含义例子
event某事件发生时加载event = "InsertEnter"(补全)
ft打开某类型文件时加载ft = { "rust" }
cmd执行某命令时加载cmd = "Telescope"
keys按下某快捷键时加载keys = { "<leader>ff" }

原则:UI/补全/LSP 用 event,工具类用 cmd/keys,语言专属用 ft例如某个 Markdown 预览插件配 ft = "markdown",你不写 Markdown 时它根本不会进内存。

结构上的裁剪

  • 删文件即删功能。不写 Python 了?删掉 lang-python.lua,下次 :Lazy sync 自动清理。
  • 临时禁用而不删除:在某个 spec 里加 enabled = false
  • 条件加载:enabled = function() return vim.fn.has("mac") == 1 end——只在某台机器装。你 macOS 和 Arch 两台机器共用同一份配置时很有用。
  • 分析启动开销::Lazy profile 看谁拖慢启动,把它改成惰性加载。健康的纯配置应在几十毫秒内启动。
💡 项目级按需

语言服务器本身就是「按需」的:只有当你打开对应文件类型、且向上能找到根目录标记(.gitpackage.jsonpyproject.toml 等)时才启动。所以即便你装了十种语言,进一个纯前端项目时也只有前端那几个服务器在跑。

12 如何添加自己的配置

三种粒度,从全局到单文件类型到单项目。

全局:autocmds 与 keymaps

自动命令是 Neovim 的事件钩子。两个高频例子:

lua/config/autocmds.lua
local aug = vim.api.nvim_create_augroup("user", { clear = true })

-- 复制时高亮被复制的内容
vim.api.nvim_create_autocmd("TextYankPost", {
  group = aug,
  callback = function() vim.hl.on_yank() end,  -- 0.11+ 用 vim.hl
})

-- 保存时去掉行尾空白
vim.api.nvim_create_autocmd("BufWritePre", {
  group = aug,
  callback = function()
    local v = vim.fn.winsaveview()
    vim.cmd([[keeppatterns %s/\s\+$//e]])
    vim.fn.winrestview(v)
  end,
})

按文件类型:after/ftplugin/

想「只在 Python 文件里」改某些设置,放 after/ftplugin/python.lua。打开 .py 时它会自动执行,且作用域是当前 buffer(用 vim.opt_local):

after/ftplugin/python.lua
vim.opt_local.colorcolumn = "88"   -- ruff 默认行宽参考线
vim.opt_local.shiftwidth = 4
vim.opt_local.tabstop = 4

-- 只在 python buffer 生效的按键
vim.keymap.set("n", "<leader>rr", "<cmd>!python %<cr>",
  { buffer = true, desc = "运行当前文件" })

按项目:exrc / 项目本地配置

options.luavim.o.exrc = true,Neovim 会加载项目根目录下的 .nvim.lua(首次会提示你信任该文件)。适合放「这个项目专用」的设置,比如某个 monorepo 的特殊路径——你的 UoA-TreasureDex 那种 pnpm monorepo 就很合适。

⚠ exrc 的安全性

它会执行项目目录里的代码。Neovim 0.9+ 加了信任机制(首次询问、记住选择),但仍只对你信任的仓库开启。

13 速查与学习路径

练肌肉必做的事

  • :Tutor 完整过一遍(30 分钟,回报极高)
  • 强迫自己用 w/b/e 而非方向键移动
  • 练 operator+motion:ciw di" ya} cap
  • . 重复、f/t 行内跳、% 配对跳
  • 遇到不会的就 :help 关键词

排错出问题先看这些

  • :checkhealth — 总体体检
  • :checkhealth vim.lsp — LSP 是否挂载
  • :Mason — 服务器/工具装了没
  • :Lazy — 插件是否加载、报错
  • :ConformInfo — 格式化器找到没
  • :LspLog — 服务器日志

推荐的推进节奏

  1. 第一周:只用第 2 节的裸配置 + 第 4 节的 Telescope/which-key/treesitter,专注练 motion。别急着上 LSP。
  2. 第二周:接入 LSP + 补全(第 5、6 节),先只配一门你最常用的语言。
  3. 之后:按第 10 节的配方逐步加语言,按第 11 节把启动调快,按第 12 节沉淀你自己的习惯。
💡 想偷懒看现成的

官方的 kickstart.nvim 是「单文件、带注释、教学向」的参考配置,思路和本教程一致,适合对照阅读。想直接要成品 IDE 体验则看 LazyVim——但建议你先按本教程手搭一遍,再决定。