强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

17 - 终端集成

“The terminal inside Neovim is not just a terminal — it’s a first-class citizen.”

17.1 Neovim 内置终端

17.1.1 基本使用

:terminal              " 水平分割打开终端
:terminal bash         " 指定 shell
:vert terminal         " 垂直分割终端
:terminal ++rows=10    " 指定高度

17.1.2 终端模式切换

" 从终端模式切换到 Normal 模式
<C-\><C-n>     " 标准方式

" 在终端 Normal 模式中回到终端输入
i / a          " 进入终端插入模式

" 终端模式中的操作
<C-\><C-n>     " 回到 Normal
<C-\><C-n>:q   " 关闭终端

17.1.3 终端配置

vim.api.nvim_create_autocmd("TermOpen", {
    pattern = "*",
    callback = function()
        vim.opt_local.number = false
        vim.opt_local.relativenumber = false
        vim.opt_local.signcolumn = "no"
        vim.cmd("startinsert")
    end,
})

17.2 ToggleTerm

17.2.1 安装与配置

{ "akinsho/toggleterm.nvim",
    version = "*",
    keys = {
        { "<C-\\>", "<cmd>ToggleTerm<cr>", desc = "终端切换" },
        { "<leader>tf", "<cmd>ToggleTerm direction=float<cr>", desc = "浮动终端" },
        { "<leader>th", "<cmd>ToggleTerm direction=horizontal size=15<cr>", desc = "水平终端" },
        { "<leader>tv", "<cmd>ToggleTerm direction=vertical size=60<cr>", desc = "垂直终端" },
    },
    opts = {
        size = function(term)
            if term.direction == "horizontal" then
                return 15
            elseif term.direction == "vertical" then
                return vim.o.columns * 0.4
            end
        end,
        open_mapping = [[<C-\>]],
        hide_numbers = true,
        shade_terminals = true,
        start_in_insert = true,
        insert_mappings = true,
        terminal_mappings = true,
        persist_size = true,
        direction = "float",  -- "vertical" | "horizontal" | "tab" | "float"
        close_on_exit = true,
        shell = vim.o.shell,
        float_opts = {
            border = "curved",
            winblend = 0,
        },
    },
}

17.2.2 多终端管理

-- 在配置中添加多个终端
local Terminal = require("toggleterm.terminal").Terminal

-- Python REPL
local python = Terminal:new({ cmd = "python3", hidden = true, direction = "float" })
vim.keymap.set("n", "<leader>tp", function() python:toggle() end, { desc = "Python REPL" })

-- Node REPL
local node = Terminal:new({ cmd = "node", hidden = true, direction = "float" })
vim.keymap.set("n", "<leader>tn", function() node:toggle() end, { desc = "Node REPL" })

-- Lazygit
local lazygit = Terminal:new({ cmd = "lazygit", hidden = true, direction = "float" })
vim.keymap.set("n", "<leader>gg", function() lazygit:toggle() end, { desc = "LazyGit" })

17.2.3 终端内快捷键

-- 终端模式中的导航
function _G.set_terminal_keymaps()
    local opts = { buffer = 0 }
    vim.keymap.set("t", "<Esc>", [[<C-\><C-n>]], opts)
    vim.keymap.set("t", "<C-h>", [[<Cmd>wincmd h<CR>]], opts)
    vim.keymap.set("t", "<C-j>", [[<Cmd>wincmd j<CR>]], opts)
    vim.keymap.set("t", "<C-k>", [[<Cmd>wincmd k<CR>]], opts)
    vim.keymap.set("t", "<C-l>", [[<Cmd>wincmd l<CR>]], opts)
end

vim.cmd("autocmd! TermOpen term://*toggleterm#* lua set_terminal_keymaps()")

17.3 任务运行

17.3.1 一键运行

-- 简单的代码运行函数
function RunCode()
    local filetype = vim.bo.filetype
    local file = vim.fn.expand("%:p")
    local cmd_map = {
        python = "python3 " .. file,
        javascript = "node " .. file,
        typescript = "npx ts-node " .. file,
        go = "go run " .. file,
        rust = "cargo run",
        lua = "lua " .. file,
        sh = "bash " .. file,
    }
    local cmd = cmd_map[filetype]
    if cmd then
        require("toggleterm.terminal").Terminal
            :new({ cmd = cmd, direction = "float" })
            :toggle()
    else
        print("No runner for filetype: " .. filetype)
    end
end

vim.keymap.set("n", "<leader>r", RunCode, { desc = "运行代码" })

17.3.2 overseer.nvim(任务运行器)

{ "stevearc/overseer.nvim",
    cmd = { "OverseerRun", "OverseerToggle" },
    keys = {
        { "<leader>or", "<cmd>OverseerRun<cr>", desc = "运行任务" },
        { "<leader>ot", "<cmd>OverseerToggle<cr>", desc = "任务面板" },
    },
    opts = {
        templates = { "builtin", "user.run_script" },
    },
}

17.4 浮动终端布局

-- 自定义浮动终端样式
local float_opts = {
    border = "double",    -- "single" | "double" | "rounded" | "solid" | "shadow"
    winblend = 3,         -- 透明度
    width = function() return math.floor(vim.o.columns * 0.8) end,
    height = function() return math.floor(vim.o.lines * 0.8) end,
}

17.5 终端中的 Neovim

17.5.1 嵌套 Neovim

# 在终端模式中使用 Neovim
nvim --remote-ui  # 远程 UI 模式

17.5.2 终端中的颜色

-- 确保终端颜色正确
vim.opt.termguicolors = true

-- 设置终端颜色
vim.g.terminal_color_0 = "#1e1e2e"  -- black
vim.g.terminal_color_1 = "#f38ba8"  -- red
vim.g.terminal_color_2 = "#a6e3a1"  -- green
vim.g.terminal_color_3 = "#f9e2af"  -- yellow
vim.g.terminal_color_4 = "#89b4fa"  -- blue
vim.g.terminal_color_5 = "#f5c2e7"  -- magenta
vim.g.terminal_color_6 = "#94e2d5"  -- cyan
vim.g.terminal_color_7 = "#bac2de"  -- white

17.6 业务场景

场景方案
运行脚本ToggleTerm + 一键运行
Git 操作LazyGit(浮动终端)
REPL 交互Python/Node 浮动终端
构建任务overseer.nvim
服务器管理多终端标签页
测试运行终端 + make/test 命令

17.7 总结

功能命令/插件
内置终端:terminal
终端切换<C-\><C-n>
ToggleTerm浮动/水平/垂直终端
多终端Terminal:new()
任务运行自定义函数 / overseer.nvim

下一步第 18 章 - Docker 远程开发 → 在容器中编辑代码、远程开发配置。


扩展阅读