Ubuntu 24.04 环境的 Neovim 源码编译与格式化全家桶部署教程

在 Ubuntu 24.04 上源码编译 Neovim 稳定版,并部署 vim-plug、文件树、主题、OSC 52 远程复制和 Conform 格式化配置。

本文记录在 Ubuntu 24.04 环境中,从源码编译安装 Neovim 稳定版,并部署一套实用的编辑器全家桶配置。

这套配置包含基础显示、文件树、OneDark 主题、OSC 52 远程复制,以及基于 conform.nvimprettier 的代码格式化。适合新服务器、新桌面环境,或者需要统一 Neovim 使用体验的场景。

第一步:安装依赖并源码编译 Neovim

在全新 Ubuntu 24.04 系统中,先安装编译 Neovim 所需的基础工具和系统依赖。

sudo apt update
sudo apt install ninja-build gettext cmake unzip curl build-essential git -y

拉取 Neovim 源码,并切换到稳定版分支。使用 stable 分支可以规避开发版中可能出现的临时问题。

git clone https://github.com/neovim/neovim.git ~/neovim-src
cd ~/neovim-src
git checkout stable

开始编译并全局安装:

make CMAKE_BUILD_TYPE=Release -j$(nproc)
sudo make install

清理 shell 路径缓存,并验证 Neovim 版本:

hash -r
nvim -v

如果系统里原本安装过旧版 Neovim,可以额外确认实际调用路径:

which nvim
nvim --version

第二步:安装格式化所需环境

conform.nvim 本身负责调度格式化,但真正执行排版的是系统中的外部工具。这里安装 Node.js、npm 和全局 Prettier。

sudo apt install -y nodejs npm xclip jq
sudo npm install -g prettier

安装完成后验证:

node -v
npm -v
jq --version
prettier -v

三、写入统一 Lua 配置

下面这份 init.lua 可同时用于 Alpine、Debian/Ubuntu 和 macOS。

远程 SSH 终端里不要直接粘贴超长 cat << EOF 脚本,容易出现粘贴错乱。先运行短命令清理并打开配置文件:

# 1. 清理旧环境
rm -rf ~/.config/nvim ~/.local/share/nvim ~/.local/state/nvim ~/.cache/nvim

# 2. 创建配置目录并打开 init.lua
mkdir -p ~/.config/nvim
nvim ~/.config/nvim/init.lua

进入空文件后按 i 进入插入模式,复制下面这段纯 init.lua 内容粘贴进去,然后按 Esc,输入 :wq 保存退出。

-- Basic settings
vim.g.mapleader = ";"
local opt = vim.opt
opt.number = true
opt.relativenumber = true
opt.cursorline = true
opt.termguicolors = true
opt.encoding = "utf-8"
opt.mouse = "a"
opt.timeoutlen = 800
opt.splitright = true
opt.splitbelow = true

-- Install lazy.nvim
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",
    "https://github.com/folke/lazy.nvim.git",
    "--branch=stable",
    lazypath,
  })
end
vim.opt.rtp:prepend(lazypath)

-- Plugins
require("lazy").setup({
  spec = {
    -- 1. Theme
    {
      "navarasu/onedark.nvim",
      lazy = false,
      priority = 1000,
      config = function()
        require("onedark").setup({ style = "dark" })
        require("onedark").load()

        local hl = vim.api.nvim_set_hl
        hl(0, "Normal", { bg = "#1e2127", fg = "#abb2bf" })
        hl(0, "NonText", { bg = "#1e2127", fg = "#3b4048" })
        hl(0, "CursorLine", { bg = "#2c313a" })
        hl(0, "Visual", { bg = "#3e4452" })
        hl(0, "Search", { bg = "#61afef", fg = "#1e2127" })
        hl(0, "IncSearch", { bg = "#98c379", fg = "#1e2127" })
      end,
    },

    -- 2. File tree
    {
      "nvim-tree/nvim-tree.lua",
      dependencies = { "nvim-tree/nvim-web-devicons" },
      config = function()
        require("nvim-tree").setup({
          view = { width = 30, side = "left" },
          renderer = { indent_markers = { enable = true } },
        })
      end,
    },

    -- 3. Remote clipboard (OSC 52)
    {
      "ojroques/nvim-osc52",
      config = function()
        require("osc52").setup()
        vim.api.nvim_create_autocmd("TextYankPost", {
          callback = function()
            if vim.v.event.operator == "y" and vim.v.event.regname == "" then
              require("osc52").copy_register("")
            end
          end,
        })
      end,
    },

    -- 4. Formatting
    {
      "stevearc/conform.nvim",
      lazy = false,
      config = function()
        require("conform").setup({
          formatters_by_ft = {
            lua = { "stylua" },
            json = { "jq" },
            yaml = { "prettier" },
            html = { "prettier" },
            css = { "prettier" },
            javascript = { "prettier" },
            typescript = { "prettier" },
            markdown = { "prettier" },
          },
          formatters = {
            jq = {
              command = "jq",
              args = { "--indent", "2", "." },
              stdin = true,
            },
          },
          format_on_save = {
            timeout_ms = 3000,
            lsp_format = "fallback",
          },
          notify_on_error = true,
        })
      end,
    },
  },
})

-- Keymaps
local map = vim.keymap.set

map("n", "<leader>w", ":w<CR>", { silent = true })
map("n", "<leader>q", ":q<CR>", { silent = true })
map("n", "<CR>", ":noh<CR><CR>", { silent = true })

-- Toggle or focus file tree: ;t
map("n", "<leader>t", function()
  local view = require("nvim-tree.view")
  if view.is_visible() then
    if vim.api.nvim_get_current_win() == view.get_winnr() then
      vim.cmd("wincmd p")
    else
      vim.cmd("NvimTreeFocus")
    end
  else
    vim.cmd("NvimTreeToggle")
  end
end, { silent = true })

-- Format manually: ;f
map({ "n", "v" }, "<leader>f", function()
  require("conform").format({
    async = false,
    timeout_ms = 3000,
    lsp_format = "fallback",
  }, function(err)
    if err then
      vim.notify("Format failed: " .. err, vim.log.levels.ERROR)
    else
      vim.notify("Format done", vim.log.levels.INFO)
    end
  end)
end, { silent = true })

-- Direct format shortcut: F3
map({ "n", "v" }, "<F3>", function()
  require("conform").format({
    async = false,
    timeout_ms = 3000,
    lsp_format = "fallback",
  }, function(err)
    if err then
      vim.notify("Format failed: " .. err, vim.log.levels.ERROR)
    else
      vim.notify("Format done", vim.log.levels.INFO)
    end
  end)
end, { silent = true })

-- Window navigation
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")

第四步:初始化插件

在终端输入以下命令打开 Neovim:

nvim

此时会自动安装插件

手动安装插件可执行:(可选)

:PlugInstall

等待左侧窗口提示安装完成

如有的插件后面显示的是updates available话,是提示升级,此时,请输入大写的U,即可自动升级

退出:

:qa!

然后重新打开 Neovim,让插件配置完整加载。

第五步:验证格式化功能

创建一个 JSON 文件测试:

nvim test.json

写入一段未格式化的内容:

{"name":"ubuntu","version":"24.04","editor":"neovim"}

在普通模式下输入:

;f

如果配置正常,JSON 会被 Prettier 自动格式化。也可以直接保存:

;w

保存时 conform.nvim 会自动触发格式化。

检查格式化工具状态:

:ConformInfo

这个命令会弹出状态面板,显示当前文件匹配到的格式化工具,例如 prettier,以及该工具在 Ubuntu 系统中是否可用。

常用快捷键

  • ;w:保存当前文件
  • F3:格式化当前文件或选中范围
  • ;q:退出当前窗口
  • ;fl:打开或关闭文件树
  • ;f:格式化当前文件或选中范围
  • Enter:清除搜索高亮

排错建议

如果 :PlugInstall 下载失败,通常是网络无法访问 GitHub。确认网络后重新执行 :PlugInstall

如果 JSON 格式化没有反应,先检查 jq 是否可用:

which jq
jq --version

如果 :ConformInfo 显示 prettier 不可用,先检查命令是否存在:

which prettier
prettier -v

如果 nvim 仍然调用旧版本,检查路径优先级:

which -a nvim
hash -r

源码安装默认会把 Neovim 放到 /usr/local/bin/nvim,通常应优先于系统仓库中的 /usr/bin/nvim