-- QQdock.nvim — Persistent adaptive terminal dock -- -- 特性:持久化终端实例、自适应窗口方向(横屏右分屏/竖屏下分屏)、依赖 toggleterm.nvim -- -- 配置(可选): -- require('QQdock').setup({ -- size = { -- horizontal = 10, -- 竖屏下方终端高度(行数) -- vertical = 40, -- 横屏右侧终端宽度(列数) -- }, -- keymaps = { -- shell = { 'n', '' }, -- 普通终端 -- shell_i = { 'i', '' }, -- 插入模式也开终端 -- reasonix = { 'n', '' }, -- Reasonix -- lazygit = { 'n', 'gg' }, -- lazygit -- }, -- }) -- -- 用法: -- local Q = require('QQdock') -- Q.shell() -- 打开/关闭普通 shell -- Q.open('reasonix') -- 打开/关闭 Reasonix -- Q.open('lazygit') -- 打开/关闭 lazygit local M = {} local config = { size = { horizontal = nil, -- nil = toggleterm 默认值 vertical = nil, }, keymaps = {}, commands = { reasonix = 'reasonix', lazygit = 'lazygit', }, } local terms = {} -- 缓存终端实例,key 是命令名(nil = 普通 shell) --- 基于当前窗口宽高返回 { direction, size } ---@return string direction -- 'horizontal' | 'vertical' ---@return integer size local function get_layout() local width = vim.api.nvim_win_get_width(0) local height = vim.api.nvim_win_get_height(0) -- 足够宽且宽度大于高度 2 倍 -> 右侧分屏 if width >= 110 and width > height * 2 then local size = config.size.vertical or math.floor(width * 0.4) return 'vertical', size end -- 否则下方分屏 local size = config.size.horizontal or math.max(10, math.floor(height * 0.35)) return 'horizontal', size end ---@param opts { size?: { horizontal?: integer, vertical?: integer }, keymaps?: table, commands?: table } function M.setup(opts) config = vim.tbl_deep_extend('force', config, opts or {}) -- 注册键位 local km = config.keymaps local function safe_map(mode, lhs, fn) if mode and lhs and fn then vim.keymap.set(mode, lhs, fn, { noremap = true }) end end if km.shell then safe_map(km.shell[1], km.shell[2], M.shell) end if km.shell_i then safe_map(km.shell_i[1], km.shell_i[2], M.shell) end if km.reasonix then safe_map(km.reasonix[1], km.reasonix[2], function() local cmd = config.commands.reasonix M.open(type(cmd) == 'function' and cmd() or cmd) end) end if km.lazygit then safe_map(km.lazygit[1], km.lazygit[2], function() local cmd = config.commands.lazygit M.open(type(cmd) == 'function' and cmd() or cmd) end) end end function M.open(cmd) local direction, size = get_layout() local name = cmd or '__shell__' local opts = { direction = direction, size = size, cmd = cmd, persist_size = false, -- 不记忆旧尺寸,每次 toggle 使用最新值 hidden = true, -- 隐藏时进程继续跑,toggle() 只切显隐 } if not terms[name] then local cmd_saved = cmd terms[name] = require('toggleterm.terminal').Terminal:new(vim.tbl_extend('force', opts, { on_open = function(term) vim.keymap.set('t', '', function() M.open(cmd_saved) end, { buffer = term.bufnr, noremap = true }) end, })) end -- 每次 toggle 传入最新方向/尺寸,确保分屏后重新计算 terms[name]:toggle(size, direction) end function M.shell() M.open(nil) end return M