From 62882ebeb1e4d142bfbe7edcb9d9a955a037befc Mon Sep 17 00:00:00 2001 From: newbieQQ Date: Thu, 11 Jun 2026 19:20:52 +0800 Subject: [PATCH] =?UTF-8?q?init:=20QQdock.nvim=20=E2=80=94=20persistent=20?= =?UTF-8?q?adaptive=20terminal=20dock?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .busted | 13 ++++++++ .editorconfig | 8 +++++ .github/workflows/linter.yml | 24 ++++++++++++++ .github/workflows/release.yml | 20 ++++++++++++ .github/workflows/tests.yml | 22 +++++++++++++ .gitignore | 3 ++ .luacheckrc | 9 ++++++ QQdock.nvim-scm-1.rockspec | 18 +++++++++++ README.md | 61 +++++++++++++++++++++++++++++++++++ lua/QQdock/init.lua | 44 +++++++++++++++++++++++++ spec/QQdock_spec.lua | 7 ++++ 11 files changed, 229 insertions(+) create mode 100644 .busted create mode 100644 .editorconfig create mode 100644 .github/workflows/linter.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/tests.yml create mode 100644 .gitignore create mode 100644 .luacheckrc create mode 100644 QQdock.nvim-scm-1.rockspec create mode 100644 README.md create mode 100644 lua/QQdock/init.lua create mode 100644 spec/QQdock_spec.lua diff --git a/.busted b/.busted new file mode 100644 index 0000000..8c64018 --- /dev/null +++ b/.busted @@ -0,0 +1,13 @@ +return { + _all = { + coverage = false, + lpath = "lua/?.lua;lua/?/init.lua", + lua = "nlua", + }, + default = { + verbose = true + }, + tests = { + verbose = true + }, +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..72fb8ad --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*.lua] +charset = utf-8 +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 0000000..989bc78 --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,24 @@ +--- +name: Lint Code Base +on: + pull_request: ~ + push: + branches: + - master + +jobs: + build: + name: Lint Code Base + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v3 + + - name: Lint Code Base + uses: github/super-linter/slim@v4 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LINTER_RULES_PATH: / + VALIDATE_JSCPD: false + VALIDATE_PYTHON_BLACK: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..9c7786f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,20 @@ +--- +name: "Release" +on: + push: + tags: + - 'v*.*.*' + +jobs: + luarocks-release: + runs-on: ubuntu-latest + name: Luarocks Release + steps: + - name: Checkout + uses: actions/checkout@v3 + if: env.LUAROCKS_API_KEY != null + - name: Luarocks Upload + uses: nvim-neorocks/luarocks-tag-release@v7 + if: env.LUAROCKS_API_KEY != null + env: + LUAROCKS_API_KEY: ${{ secrets.LUAROCKS_API_KEY }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..39766b1 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,22 @@ +--- +name: Run tests +on: + pull_request: ~ + push: + branches: + - main + +jobs: + build: + name: Run tests + runs-on: ubuntu-latest + strategy: + matrix: + neovim_version: ['nightly'] + + steps: + - uses: actions/checkout@v3 + - name: Run tests + uses: nvim-neorocks/nvim-busted-action@v1 + with: + nvim_version: ${{ matrix.neovim_version }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d14386a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/luarocks +/lua_modules +/.luarocks diff --git a/.luacheckrc b/.luacheckrc new file mode 100644 index 0000000..dbab055 --- /dev/null +++ b/.luacheckrc @@ -0,0 +1,9 @@ +ignore = { + "631", -- max_line_length +} +read_globals = { + "vim", + "describe", + "it", + "assert" +} diff --git a/QQdock.nvim-scm-1.rockspec b/QQdock.nvim-scm-1.rockspec new file mode 100644 index 0000000..3d23878 --- /dev/null +++ b/QQdock.nvim-scm-1.rockspec @@ -0,0 +1,18 @@ +rockspec_format = '3.0' +package = 'QQdock.nvim' +version = 'scm-1' +source = { + url = 'git+https://git.qyhhh.top/newbie/QQdock.nvim' +} +dependencies = { + 'toggleterm.nvim', +} +test_dependencies = { + 'nlua', +} +build = { + type = 'builtin', + copy_directories = { + 'plugin', + }, +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..0e3fefb --- /dev/null +++ b/README.md @@ -0,0 +1,61 @@ +# QQdock.nvim + +Persistent adaptive terminal dock for Neovim. + +每次按 `` 打开 shell,聊完 Reasonix 按 `` 隐藏,再按回来——对话还在。横屏自动右侧分屏,竖屏自动下方分屏。 + +## 安装 + +```lua +-- lazy.nvim +{ + 'newbie/QQdock.nvim', + url = 'https://git.qyhhh.top/newbie/QQdock.nvim', + dependencies = { 'akinsho/toggleterm.nvim' }, + config = function() + local Q = require('QQdock') + vim.keymap.set({ 'n', 'i' }, '', Q.shell, { noremap = true }) + vim.keymap.set('n', '', function() Q.open('reasonix') end) + vim.keymap.set('n', 'gg', function() Q.open('lazygit') end) + end, +} +``` + +## 用法 + +```lua +local Q = require('QQdock') + +Q.shell() -- 普通 shell +Q.open('reasonix') -- Reasonix AI agent +Q.open('lazygit') -- lazygit +Q.open('btm') -- 系统监控 +Q.open('yazi') -- 文件管理器 +``` + +## API + +| 函数 | 参数 | 作用 | +|------|------|------| +| `Q.shell()` | — | 打开/关闭持久 shell | +| `Q.open(cmd)` | cmd | 打开/关闭指定命令的持久终端 | + +## 特性 + +- **持久化** — toggle 显隐,终端状态保留 +- **自适应** — 横屏右侧 45%,竖屏下方 40% +- **轻量** — 仅依赖 toggleterm.nvim + +## Development + +### Run tests + +```bash +luarocks test --local +# or +busted +``` + +## License + +MIT diff --git a/lua/QQdock/init.lua b/lua/QQdock/init.lua new file mode 100644 index 0000000..e09026f --- /dev/null +++ b/lua/QQdock/init.lua @@ -0,0 +1,44 @@ +-- QQdock.nvim — Persistent adaptive terminal dock +-- +-- 依赖 toggleterm.nvim +-- +-- 用法: +-- local Q = require('QQdock') +-- Q.shell() -- 打开/关闭普通 shell +-- Q.open('reasonix') -- 打开/关闭 Reasonix +-- Q.open('lazygit') -- 打开/关闭 lazygit + +local M = {} + +local terms = {} + +---Open or toggle a persistent terminal running `cmd`. +---When the window is wider than tall, the terminal opens on the right side (vertical split), +---taking 45% of the width. When taller than wide, it opens at the bottom (horizontal split), +---taking 40% of the height. +---@param cmd string|nil The command to run, or nil for a plain shell. +function M.open(cmd) + local ui = vim.api.nvim_list_uis()[1] + if not ui then + return + end + local tall = ui.height > ui.width + local name = cmd or '__shell__' + + if not terms[name] or not terms[name]:is_open() then + terms[name] = require('toggleterm.terminal').Terminal:new({ + direction = tall and 'horizontal' or 'vertical', + cmd = cmd, + size = tall and math.floor(ui.height * 0.4) or math.floor(ui.width * 0.45), + }) + end + + terms[name]:toggle() +end + +---Toggle a plain shell terminal. +function M.shell() + M.open(nil) +end + +return M diff --git a/spec/QQdock_spec.lua b/spec/QQdock_spec.lua new file mode 100644 index 0000000..4c2b747 --- /dev/null +++ b/spec/QQdock_spec.lua @@ -0,0 +1,7 @@ +describe('QQdock', function() + it('can be required without toggleterm on path', function() + -- toggleterm is not installed in test env, so we test the module loads + local ok, _ = pcall(require, 'QQdock') + assert.is_true(ok) + end) +end)