使用nvim打造多平台通用的ide

Posted by wsxq2 on 2025-03-29
TAGS:  vimnvimIDE

本文最后一次编辑时间:2025-03-29 11:56:30 +0800

使用 nvim 打造多平台通用的 IDE

起因

很早以前就有相关教程,将 vim 打造成 IDE,但通常仅限于 Linux/MacOS,Windows 对于 Linux 相关的工具一直以来都不太友好,包括 vim。所以即使按照教程配置好了也无法在 Windows 上正常使用。之前我采用 Linux 虚拟机的方式,通过 ssh 连接到虚拟机,然后使用 vim 进行开发,但这样依然比较麻烦,比如文件同步问题等。

我尝试完全转到 Linux,但不可否认的是 Windows 上还是有许多东西是比较好用的,包括 Office 套件、其他大量软件和工具等。因此对于 IDE,为简单起见,我都是根据需求在改变,比如开发 qt 就用 Qt Creator,开发 stm32 程序就用 Keil,开发 zynq ps 程序就用 Xilinx SDK 等。这样一来,切换不同的 IDE 非常麻烦,而且每个 IDE 都有自己的配置和快捷键,学习成本很高。部分 IDE 还格外难用,比如 Keil。

因此,我非常需要一个 Linux 和 Windows 下都能使用的 vim IDE 配置,这在以前是不可能实现的,但如今随着 neovim 的兴起,以及其相关生态的发展,还有微软提出的 LSP 和 DAP 等概念,微软官方对开源软件、Linux 软件的支持提高,这个设想才终于可以变成现实

概述

Nvim 是 NeoVim 的缩写,是 Vim 的一个分支,它的目标是改进 Vim 的可扩展性和可维护性。Nvim 有很多优点,比如支持异步任务、支持插件管理器、支持 Lua 脚本等。本文将介绍如何使用 Nvim 打造一个多平台通用的 IDE。

从头构建一个 IDE 是非常复杂和困难的,好在 nvim 中有大量插件,基于这些插件,还有大量的“发行版”,即开箱即用的配置,下面是一个知名的“发行版”列表(GitHub 搜索 nvim 的结果,按 stars 数量排序):

需要注意的是,每个人的需求不同,并且发行版通常涉及复杂的配置,如果不了解其原理,则调整起来也非常困难,所以如果你没有任何基础,建议从一个简单的配置开始,逐渐添加自己需要的插件。过程中,可以参考这些发行版的配置,尤其是前面提到的 kickstart,学习如何配置 nvim。

当然,如果你对 vim/nvim 比较熟悉,对自己的需求也比较清晰,可以直接从零开始构建自己的配置。然而,如果你想偷懒,你可以直接使用现有发行版。我就属于后者,选择的发行版是 LazyVim,因为它支持多平台(Windows、Linux、MacOS),nvim 原生,stars 数量多(20k),依赖少(34个plugin),速率快,功能强大,可配置能力强(根本原因其实是因为它的名称Lazy很符合我,hhh)。

LazyVim 有完善的文档,使用前建议先阅读。

本文将基于 Windows 11 进行相关说明,Linux/MacOS 上的配置只会更简单,不再赘述。使用的 shell 是 pwsh 7。这里安利下 pwsh 7,Windows 上最好用的 shell。

安装 wezterm

LazyVim 官方文档中明确提出,其依赖一个支持 true color 和 undercurl 的终端模拟器,以便正确显示一些插件的输出和提示信息。推荐使用 wezterm 终端模拟器,它支持多平台(Windows、Linux、MacOS),并且功能强大,配置灵活(使用 lua 配置文件),文档齐全。

参考 wezterm 的官方文档 很容易安装和配置 wezterm。在 Windows 上,你可以通过 winget 安装:

winget wezterm

。安装完成后,你可以使用以下命令来运行 wezterm:

wezterm

一个基本的配置文件如下(推荐放置在~/.config/wezterm/wezterm.lua):

1
2
3
4
5
6
7
8
local wezterm = require("wezterm")
local config = {}

config.font = wezterm.font("JetBrains Mono")
config.color_scheme = "Batman"
config.default_prog = { "pwsh", "--nologo" }

return config

安装 nvim

其次我们需要安装 nvim,安装方法请参考官方文档

我使用的是 Windows 11 自带的 winget 命令安装的 nvim,安装命令如下:

winget install Neovim.Neovim

安装 LazyVim

参考 🛠️ Installation | LazyVim 即可。

安装其他常用工具

有许多工具可以改善 LazyVim 的使用体验,如 fdripgrepfzf 等。在 Windows 下,这些工具可以通过 scoopwingetchoco 等包管理器安装。

关于这些包管理器的选择:

这些包管理器中首推 scoop,因为它是用户级的,不会污染系统环境,且更隔离方便,不会弹出安装窗口,不需要需要授权,更方便,更容易实现多版本安装,如 python 的多版本等。

其次是 winget,因为它是微软官方支持的(在新的 Windows11 版本中无需手动安装)。事实证明,Windows 上的东西还是选择微软官方的比较好,比如 C++ 编译器 MSVC,况且现在的微软不比当年,已经做了许多开源方面的贡献,如 TypeScript、.Net 开源、VS Code、WSL、powershell开源等,甚至在许多方面提出了先进的理念,比如 LSP、DAP 等,因此现在的开源社区已经不再排斥微软。

chocowinget的定位是类似的,既然选择了winget自然就不必考虑它了。

安装 scoop

查看官网 https://scoop.sh/ 可得到安装方法:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression

如果失败,添加-Proxy参数,例如:

Invoke-RestMethod -Proxy http://127.0.0.1:7890 -Uri https://get.scoop.sh | Invoke-Expression

安装 nodejs

使用官方推荐的安装方法

# Download and install fnm:
winget install Schniz.fnm

# Download and install Node.js:
fnm install 22

# Verify the Node.js version:
node -v # Should print "v22.14.0".

# Verify npm version:
npm -v # Should print "10.9.2".

如果执行node -v时失败,则需要执行:

# fnm(fast node manager) is similar to nvm. get node and npm cmd.
fnm env --use-on-cd | Out-String | Invoke-Expression

建议将其添加到 pwsh 的配置文件(如$PROFILE)中。

安装其他工具

scoop install fd ripgrep fzf

使用方法

总体参考 LazyVim 官方文档。这里有一些温馨提示

  • LazyVim 中的设置的<leader>为空格键,按该键后会提示接下可能的按键(来自插件which-key的强大魔法),几乎所有的功能都在其中,我认为这是一个好设计。
  • 几乎所有页面都有帮助,多看页面上的提示,多尝试?键。当然,如果是 vim 中的功能,多尝试:h命令,如:h 'opt, :h xxx等。
  • 如果有疑问,优先咨询 AI,如 deepseek 等,通常能在极短时间内找到解决方法。如果配置好了下面描述的 nvim 中的 AI,则使用起来会更方便,比如我写本文时遇到疑问,即可快速通过<leader>aa询问 copilot-chat,更快得到答案。
  • 多尝试,一方面是多尝试各种功能,另一方面是尝试各种解决思路,比如我遇到的 Git bash 使用时有字符错乱现象,就尝试用 pwsh,发现就无此问题了
  • 如果遇到奇怪的问题,先尝试更新插件

下面是一些个人使用情况记录。

markdown

markdown 语言的配置非常简单,在 nvim 中使用:LazyExtras命令(来自 LazyVim)安装Language下的lang.markdown组即可(使用x键安装),然后还需要安装 nodejs 和 npm,可以通过nvm安装,详情参考官网:«https://nodejs.org/zh-cn/download。>

安装后现在可以查看渲染后的效果,但没有 table 模式进行表格的格式化,但有渲染后效果已经足够了,非常好看。

LazyExtras 中的 lang.markdown 主要依赖 markdownlint-cli2markdown-tocmarksman 这三个 mason 插件。此外还依赖 render-markdown.nvimmarkdown-preview.nvim 这两个 lazy 插件。

下面是上述插件的简单说明和配置方法:

  • markdownlint-cli2:用于解析 markdown 文件,判定是否遵循 CommonMark 规范 或 GFM 规范。依赖markdownlint库,安装该插件时会自动安装,其配置文件.markdownlint.yaml可以和 markdown 文件放在同一目录下,目前就去掉了MD013 80字符的长度警告(因为太多了)和MD041 H1 相关警告:

    MD013: false
    MD041: false
    
  • markdown-toc:用于生成目录,安装后会自动在当前 markdown 文件中查找是否存在 <!-- tocx -->(注意,其中的tocx应该为toc,多加个x只是为了防止其生效,保存文件时就会执行) 注释,如果存在则生成目录。也可以手动运行:MarkdownToc命令来生成目录。

  • marksman: markdown LSP。
  • render-markdown: 在 nvim 中渲染 markdown,非常好看实用的功能,都不需要通过浏览器预览了
  • markdown-preview: 在浏览器中快速预览效果。

C

C 语言配置和 markdown 类似,使用 LazyExtras 安装 lang.clangd 组件即可。

该组件安装后,在 mason 插件方面, 安装了 clangd。clangd 作为 LSP,用于代码补全、编译错误检查、定义跳转、代码格式化。需要注意的是, 代码格式化方面,clangd本身内嵌了clang-format,不需要额外安装clang-format了,详见clangd Features,所以 LazyVim 就没有额外安装 clang-format,这样一来又省一个工具,这是极好的。

lazy 插件方面:安装了clangd_extensions.nvim。该插件是 neovim 和 clangd 的桥梁,提供了许多实用功能,如代码补全、定义跳转、符号查找等。它还支持一些额外的功能,如显示函数参数提示、代码片段等,非常实用。

安装好后,在打开一般 C/C++ 项目时就能正常使用了。

但后续在进行 STM32 应用开发时发现,在打开 STM32 工程时(由 STM32CubeMX 配置 cmake 方式生成),LSP 报很多错,包括math.h not found等。解决方法是创建一个.clangd,添加--sysroot编译参数,注意路径要给对,不要多余双引号或转义,类似如下内容是可用的:

1
2
3
CompileFlags:
  # 指定 ARM GCC 的 sysroot
  Add: [--sysroot=C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/12.2 mpacbti-rel1/arm-none-eabi]

此外,C语言的调试需要 DAP 相关内容:首先在 LazyExtras 中安装dap.core组软件,然后安装具体的调试器如codelldb(在 mason 插件中安装),然后就可以愉快使用了。使用方法是查看 lazy 中 dap 相关新增的快捷键,然后逐个尝试即可。通常最常用的是<leader>da, <leader>dc, <leader>db等。

安装好后,在打开一般 C/C++ 项目时就能正常使用了。

但如果想要用于 STM32 调试,则还需要在 lazy 中安装 nvim-dap-cortex-debug,以及在 mason 中安装cortex-debug,另外如果使用 st-link/v2 仿真器的话还应参考 stlink-org/stlink

在上述三个依赖都安装好的情况下,需要添加两个配置文件config/dap.luaplugin/dap.lua

config/dap.lua:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
local dap_cortex_debug = require("dap-cortex-debug")
local dap = require("dap")
table.insert(
  dap.configurations.c,
  dap_cortex_debug.openocd_config({
    name = "debugging with stlink-v2",
    type = "cortex-debug",
    request = "launch",
    servertype = "stlink",
    serverpath = "st-util",
    gdbPath = "arm-none-eabi-gdb",
    --toolchainPath = "C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/12.2 mpacbti-rel1/bin",
    toolchainPrefix = "arm-none-eabi",
    --runToEntryPoint = "main",
    swoConfig = { enabled = false },
    showDevDebugOutput = false,
    --gdbTarget = "localhost:4242",
    cwd = "${workspaceFolder}",
    executable = function()
      return vim.fn.input("Path to executable: ", vim.fn.getcwd(), "file")
    end,
    --stlinkPath = "C:/Program Files (x86)/stlink-1.7.0-x86_64-w64-mingw32/bin/st-util.exe",
    rttConfig = {
      address = "auto",
      decoders = {
        {
          label = "RTT:0",
          port = 0,
          type = "console",
        },
      },
      enabled = false,
    },
  })
)

plugin/dap.lua:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
return {
  {
    "jedrzejboczar/nvim-dap-cortex-debug",
    dependencies = { "mfussenegger/nvim-dap" },
    -- 在此处直接初始化DAP配置
    config = true,
    opts = {
      -- add your options that should be passed to the setup() function here
      debug = false, -- log debug messages
      -- path to cortex-debug extension, supports vim.fn.glob
      -- by default tries to guess: mason.nvim or VSCode extensions
      extension_path = nil,
      lib_extension = nil, -- shared libraries extension, tries auto-detecting, e.g. 'so' on unix
      node_path = "node", -- path to node.js executable
      dapui_rtt = false, -- register nvim-dap-ui RTT element
      -- make :DapLoadLaunchJSON register cortex-debug for C/C++, set false to disable
      dap_vscode_filetypes = { "c", "cpp" },
      rtt = {
        buftype = "Terminal", -- 'Terminal' or 'BufTerminal' for terminal buffer vs normal buffer
      },
    },
  },
}

然后,还需要在init.lua中添加对 config/dap.lua 的调用:

1
require("config.dap")

AI

AI 能帮上两个忙(目前发现的,可能实际上远远不止于此):自动补全和问题咨询。自动补全即添加相对合理的代码块(如果你在写代码)或者段落(如果你在写 Markdown),问题咨询即选中某部分代码或者其他内容,咨询选中内容的相关信息,如代码优化、了解概念、解决问题等。

得益于 LazyVim,AI 相关的部署也非常简单,在 :LazyExtras 中安装ai.copilotai.copilot-chat组件,ai.copilot组件的核心是copilot.lua插件,它也依赖 nodejs 中的node命令,ai.copilot-chat组件实现聊天功能。

这两个组件安装完成后需要执行:Copilot auth命令进行认证,根据指示认证完成后即可使用。认证会绑定你的 GitHub 账户,默认会赠送你一些 tokens。

认证后可以在 lazy 界面中查看增加的快捷键(默认以<leader>a开头),然后使用即可,通常<Space>aa即可。也可尝试:Copilot panel查看建议,但这种方式我还没用明白。

TODO

  • conform.nvim:试图在 markdown 中使用其 Inject Formatter 功能,发现用不了(至少C语言如此)
  • 目录比较,git diff 比较等。
  • windows 上有的目录(如 master )中运行 nvim 会卡一段时间,现在打开又不卡了。有的文件还是卡,比如 pwsh 中的 $PROFILE。甚至有时运行着突然就会卡住。现在在尝试 alacritty。

心得体会

mason 插件 vs lazy 插件

在使用 LazyVim 的过程,常常会将 mason 插件和 lazy 插件搞混。这里明确一下:mason 插件主要是和语言相关的,如 LSP、Formatter、Linter、DAP,且通常依赖外部可执行程序实现相应功能,配置通常需要参考具体插件相关文档(如对于 markdown-cli2 的配置是在当前目录下放置一个名为.markdownlint.yaml的 yaml 文件),而 lazy 插件通常是纯 vim 脚本或 nvim 脚本或 lua 语言实现,不依赖外部程序,且通常容易配置(如在setup时配置)