feat: initial release
This commit is contained in:
commit
a2fe68b248
26 changed files with 960 additions and 0 deletions
9
.busted
Normal file
9
.busted
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
return {
|
||||
_all = {
|
||||
lua = 'nvim -l',
|
||||
ROOT = { './spec/' },
|
||||
},
|
||||
default = {
|
||||
verbose = true,
|
||||
},
|
||||
}
|
||||
9
.editorconfig
Normal file
9
.editorconfig
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
|
||||
[*.lua]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
17
.github/DISCUSSION_TEMPLATE/q-a.yaml
vendored
Normal file
17
.github/DISCUSSION_TEMPLATE/q-a.yaml
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
title: 'Q&A'
|
||||
labels: []
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Use this space for questions, ideas, and general discussion about blink-cmp-tmux.
|
||||
For bug reports, please [open an issue](https://github.com/barrettruth/blink-cmp-tmux/issues/new/choose) instead.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Question or topic
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Context
|
||||
description: Any relevant details (Neovim version, config, screenshots)
|
||||
85
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
85
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
name: Bug Report
|
||||
description: Report a bug
|
||||
title: 'bug: '
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Prerequisites
|
||||
options:
|
||||
- label:
|
||||
I have searched [existing
|
||||
issues](https://github.com/barrettruth/blink-cmp-tmux/issues)
|
||||
required: true
|
||||
- label: I have updated to the latest version
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: 'Neovim version'
|
||||
description: 'Output of `nvim --version`'
|
||||
render: text
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: 'Operating system'
|
||||
placeholder: 'e.g. Arch Linux, macOS 15, Ubuntu 24.04'
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: What happened? What did you expect?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Minimal steps to trigger the bug
|
||||
value: |
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Minimal reproduction
|
||||
description: |
|
||||
Save the script below as `repro.lua`, edit if needed, and run:
|
||||
```
|
||||
nvim -u repro.lua
|
||||
```
|
||||
Confirm the bug reproduces with this config before submitting.
|
||||
render: lua
|
||||
value: |
|
||||
vim.env.LAZY_STDPATH = '.repro'
|
||||
load(vim.fn.system('curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua'))()
|
||||
require('lazy.nvim').setup({
|
||||
spec = {
|
||||
{
|
||||
'saghen/blink.cmp',
|
||||
dependencies = {
|
||||
'barrettruth/blink-cmp-tmux',
|
||||
},
|
||||
opts = {
|
||||
sources = {
|
||||
default = { 'tmux' },
|
||||
providers = {
|
||||
tmux = {
|
||||
name = 'Tmux',
|
||||
module = 'blink-cmp-tmux',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
validations:
|
||||
required: true
|
||||
5
.github/ISSUE_TEMPLATE/config.yaml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yaml
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Questions
|
||||
url: https://github.com/barrettruth/blink-cmp-tmux/discussions
|
||||
about: Ask questions and discuss ideas
|
||||
30
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
Normal file
30
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
name: Feature Request
|
||||
description: Suggest a feature
|
||||
title: 'feat: '
|
||||
labels: [enhancement]
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Prerequisites
|
||||
options:
|
||||
- label:
|
||||
I have searched [existing
|
||||
issues](https://github.com/barrettruth/blink-cmp-tmux/issues)
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Problem
|
||||
description: What problem does this solve?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Proposed solution
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Alternatives considered
|
||||
21
.github/workflows/luarocks.yaml
vendored
Normal file
21
.github/workflows/luarocks.yaml
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
name: luarocks
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
quality:
|
||||
uses: ./.github/workflows/quality.yaml
|
||||
|
||||
publish:
|
||||
needs: quality
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: nvim-neorocks/luarocks-tag-release@v7
|
||||
env:
|
||||
LUAROCKS_API_KEY: ${{ secrets.LUAROCKS_API_KEY }}
|
||||
89
.github/workflows/quality.yaml
vendored
Normal file
89
.github/workflows/quality.yaml
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
name: quality
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
lua: ${{ steps.changes.outputs.lua }}
|
||||
markdown: ${{ steps.changes.outputs.markdown }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
lua:
|
||||
- 'lua/**'
|
||||
- 'plugin/**'
|
||||
- '*.lua'
|
||||
- '.luarc.json'
|
||||
- '*.toml'
|
||||
markdown:
|
||||
- '*.md'
|
||||
|
||||
lua-format:
|
||||
name: Lua Format Check
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: ${{ needs.changes.outputs.lua == 'true' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: JohnnyMorganz/stylua-action@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
version: 2.1.0
|
||||
args: --check .
|
||||
|
||||
lua-lint:
|
||||
name: Lua Lint Check
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: ${{ needs.changes.outputs.lua == 'true' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Lint with Selene
|
||||
uses: NTBBloodbath/selene-action@v1.0.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --display-style quiet .
|
||||
|
||||
lua-typecheck:
|
||||
name: Lua Type Check
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: ${{ needs.changes.outputs.lua == 'true' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Run Lua LS Type Check
|
||||
uses: mrcjkb/lua-typecheck-action@v0
|
||||
with:
|
||||
checklevel: Warning
|
||||
directories: lua
|
||||
configpath: .luarc.json
|
||||
|
||||
markdown-format:
|
||||
name: Markdown Format Check
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: ${{ needs.changes.outputs.markdown == 'true' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 8
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
- name: Install prettier
|
||||
run: pnpm add -g prettier@3.1.0
|
||||
- name: Check markdown formatting with prettier
|
||||
run: prettier --check .
|
||||
22
.github/workflows/test.yaml
vendored
Normal file
22
.github/workflows/test.yaml
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
name: test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
nvim: [stable, nightly]
|
||||
name: Test (Neovim ${{ matrix.nvim }})
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: nvim-neorocks/nvim-busted-action@v1
|
||||
with:
|
||||
nvim_version: ${{ matrix.nvim }}
|
||||
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
*.log
|
||||
|
||||
.*cache*
|
||||
CLAUDE.md
|
||||
.claude/
|
||||
|
||||
node_modules/
|
||||
|
||||
result
|
||||
result-*
|
||||
.direnv/
|
||||
8
.luarc.json
Normal file
8
.luarc.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"runtime.version": "Lua 5.1",
|
||||
"runtime.path": ["lua/?.lua", "lua/?/init.lua"],
|
||||
"diagnostics.globals": ["vim", "jit"],
|
||||
"workspace.library": ["$VIMRUNTIME/lua", "${3rd}/luv/library"],
|
||||
"workspace.checkThirdParty": false,
|
||||
"completion.callSnippet": "Replace"
|
||||
}
|
||||
17
.pre-commit-config.yaml
Normal file
17
.pre-commit-config.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
minimum_pre_commit_version: '3.5.0'
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/JohnnyMorganz/StyLua
|
||||
rev: v2.3.1
|
||||
hooks:
|
||||
- id: stylua-github
|
||||
name: stylua (Lua formatter)
|
||||
files: \.lua$
|
||||
pass_filenames: true
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: v4.0.0-alpha.8
|
||||
hooks:
|
||||
- id: prettier
|
||||
name: prettier
|
||||
files: \.(md|toml|yaml|yml|sh)$
|
||||
1
.prettierignore
Normal file
1
.prettierignore
Normal file
|
|
@ -0,0 +1 @@
|
|||
node_modules/
|
||||
9
.prettierrc
Normal file
9
.prettierrc
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"proseWrap": "always",
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"trailingComma": "none",
|
||||
"semi": false,
|
||||
"singleQuote": true
|
||||
}
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2025 Raphael
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
47
README.md
Normal file
47
README.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# blink-cmp-tmux
|
||||
|
||||
Tmux command completion source for
|
||||
[blink.cmp](https://github.com/saghen/blink.cmp).
|
||||
|
||||
## Features
|
||||
|
||||
- Completes tmux commands with full usage signatures
|
||||
- Includes alias information for commands
|
||||
- Shows man page descriptions in documentation
|
||||
|
||||
## Requirements
|
||||
|
||||
- Neovim 0.10.0+
|
||||
- [blink.cmp](https://github.com/saghen/blink.cmp)
|
||||
- tmux
|
||||
|
||||
## Installation
|
||||
|
||||
Install via
|
||||
[luarocks](https://luarocks.org/modules/barrettruth/blink-cmp-tmux):
|
||||
|
||||
```
|
||||
luarocks install blink-cmp-tmux
|
||||
```
|
||||
|
||||
Or with lazy.nvim:
|
||||
|
||||
```lua
|
||||
{
|
||||
'saghen/blink.cmp',
|
||||
dependencies = {
|
||||
'barrettruth/blink-cmp-tmux',
|
||||
},
|
||||
opts = {
|
||||
sources = {
|
||||
default = { 'tmux' },
|
||||
providers = {
|
||||
tmux = {
|
||||
name = 'Tmux',
|
||||
module = 'blink-cmp-tmux',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
30
blink-cmp-tmux-scm-1.rockspec
Normal file
30
blink-cmp-tmux-scm-1.rockspec
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
rockspec_format = '3.0'
|
||||
package = 'blink-cmp-tmux'
|
||||
version = 'scm-1'
|
||||
|
||||
source = {
|
||||
url = 'git+https://github.com/barrettruth/blink-cmp-tmux.git',
|
||||
}
|
||||
|
||||
description = {
|
||||
summary = 'Tmux command completion source for blink.cmp',
|
||||
homepage = 'https://github.com/barrettruth/blink-cmp-tmux',
|
||||
license = 'MIT',
|
||||
}
|
||||
|
||||
dependencies = {
|
||||
'lua >= 5.1',
|
||||
}
|
||||
|
||||
test_dependencies = {
|
||||
'nlua',
|
||||
'busted >= 2.1.1',
|
||||
}
|
||||
|
||||
test = {
|
||||
type = 'busted',
|
||||
}
|
||||
|
||||
build = {
|
||||
type = 'builtin',
|
||||
}
|
||||
43
flake.lock
generated
Normal file
43
flake.lock
generated
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1771207753,
|
||||
"narHash": "sha256-b9uG8yN50DRQ6A7JdZBfzq718ryYrlmGgqkRm9OOwCE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d1c15b7d5806069da59e819999d70e1cec0760bf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
35
flake.nix
Normal file
35
flake.nix
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
description = "blink-cmp-tmux — tmux command completion source for blink.cmp";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
systems.url = "github:nix-systems/default";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
nixpkgs,
|
||||
systems,
|
||||
...
|
||||
}:
|
||||
let
|
||||
forEachSystem = f: nixpkgs.lib.genAttrs (import systems) (system: f nixpkgs.legacyPackages.${system});
|
||||
in
|
||||
{
|
||||
devShells = forEachSystem (pkgs: {
|
||||
default = pkgs.mkShell {
|
||||
packages = [
|
||||
(pkgs.luajit.withPackages (
|
||||
ps: with ps; [
|
||||
busted
|
||||
nlua
|
||||
]
|
||||
))
|
||||
pkgs.prettier
|
||||
pkgs.stylua
|
||||
pkgs.selene
|
||||
];
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
155
lua/blink-cmp-tmux.lua
Normal file
155
lua/blink-cmp-tmux.lua
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
---@class blink-cmp-tmux : blink.cmp.Source
|
||||
local M = {}
|
||||
|
||||
---@type blink.cmp.CompletionItem[]?
|
||||
local cache = nil
|
||||
|
||||
function M.new()
|
||||
return setmetatable({}, { __index = M })
|
||||
end
|
||||
|
||||
---@return boolean
|
||||
function M.enabled()
|
||||
return vim.bo.filetype == 'tmux'
|
||||
end
|
||||
|
||||
---@return table<string, string>
|
||||
local function parse_descriptions()
|
||||
local result = vim.system({ 'bash', '-c', 'MANWIDTH=80 man -P cat tmux 2>/dev/null' }):wait()
|
||||
local stdout = result.stdout or ''
|
||||
local lines = {}
|
||||
for line in (stdout .. '\n'):gmatch('(.-)\n') do
|
||||
lines[#lines + 1] = line
|
||||
end
|
||||
|
||||
local cmd_result = vim.system({ 'tmux', 'list-commands', '-F', '#{command_list_name}' }):wait()
|
||||
local cmds = {}
|
||||
for name in (cmd_result.stdout or ''):gmatch('[^\n]+') do
|
||||
cmds[name] = true
|
||||
end
|
||||
|
||||
local defs = {}
|
||||
for i, line in ipairs(lines) do
|
||||
local cmd = line:match('^ ([a-z][a-z-]+)')
|
||||
if cmd and cmds[cmd] then
|
||||
local rest = line:sub(8 + #cmd)
|
||||
if rest == '' or rest:match('^%s+%[') or rest:match('^%s%s+') then
|
||||
defs[#defs + 1] = { line = i, cmd = cmd }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local descs = {}
|
||||
for idx, def in ipairs(defs) do
|
||||
local block_end = (defs[idx + 1] and defs[idx + 1].line or #lines) - 1
|
||||
local j = def.line + 1
|
||||
while j <= block_end do
|
||||
local l = lines[j]
|
||||
if l:match('^%s+%(alias:') then
|
||||
j = j + 1
|
||||
elseif l:match('^ ') then
|
||||
local stripped = vim.trim(l)
|
||||
if stripped == '' or stripped:match('[%[%]]') then
|
||||
j = j + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
elseif vim.trim(l) == '' then
|
||||
j = j + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local desc_lines = {}
|
||||
for k = j, block_end do
|
||||
desc_lines[#desc_lines + 1] = lines[k]
|
||||
end
|
||||
local paragraphs = { {} }
|
||||
for _, dl in ipairs(desc_lines) do
|
||||
local stripped = vim.trim(dl)
|
||||
if stripped == '' then
|
||||
if #paragraphs[#paragraphs] > 0 then
|
||||
paragraphs[#paragraphs + 1] = {}
|
||||
end
|
||||
else
|
||||
local para = paragraphs[#paragraphs]
|
||||
para[#para + 1] = stripped
|
||||
end
|
||||
end
|
||||
local parts = {}
|
||||
for _, para in ipairs(paragraphs) do
|
||||
if #para > 0 then
|
||||
parts[#parts + 1] = table.concat(para, ' ')
|
||||
end
|
||||
end
|
||||
local desc = table.concat(parts, '\n\n')
|
||||
desc = desc:gsub('\xe2\x80\x90 ', '')
|
||||
desc = desc:gsub(' +', ' ')
|
||||
if desc ~= '' then
|
||||
descs[def.cmd] = desc
|
||||
end
|
||||
end
|
||||
return descs
|
||||
end
|
||||
|
||||
---@param output string
|
||||
---@param descs table<string, string>
|
||||
---@return blink.cmp.CompletionItem[]
|
||||
local function parse(output, descs)
|
||||
local Kind = require('blink.cmp.types').CompletionItemKind
|
||||
local items = {}
|
||||
for line in output:gmatch('[^\n]+') do
|
||||
local name, alias = line:match('^([a-z-]+)%s+%(([a-z-]+)%)')
|
||||
if not name then
|
||||
name = line:match('^([a-z-]+)')
|
||||
end
|
||||
if name then
|
||||
local doc_parts = {}
|
||||
if alias then
|
||||
doc_parts[#doc_parts + 1] = ('**alias**: `%s`\n'):format(alias)
|
||||
end
|
||||
doc_parts[#doc_parts + 1] = '```\n' .. line .. '\n```'
|
||||
if descs[name] then
|
||||
doc_parts[#doc_parts + 1] = '\n---\n\n' .. descs[name]
|
||||
end
|
||||
items[#items + 1] = {
|
||||
label = name,
|
||||
kind = Kind.Keyword,
|
||||
documentation = {
|
||||
kind = 'markdown',
|
||||
value = table.concat(doc_parts),
|
||||
},
|
||||
}
|
||||
end
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
---@param ctx blink.cmp.Context
|
||||
---@param callback fun(response: blink.cmp.CompletionResponse)
|
||||
---@return fun()
|
||||
function M:get_completions(ctx, callback)
|
||||
if not cache then
|
||||
local ok, descs = pcall(parse_descriptions)
|
||||
if not ok then
|
||||
descs = {}
|
||||
end
|
||||
local result = vim.system({ 'tmux', 'list-commands' }):wait()
|
||||
cache = parse(result.stdout or '', descs)
|
||||
end
|
||||
|
||||
local before = ctx.line:sub(1, ctx.cursor[2])
|
||||
if before:match('^%s*[a-z-]*$') then
|
||||
callback({
|
||||
is_incomplete_forward = false,
|
||||
is_incomplete_backward = false,
|
||||
items = vim.deepcopy(cache),
|
||||
})
|
||||
else
|
||||
callback({ items = {} })
|
||||
end
|
||||
return function() end
|
||||
end
|
||||
|
||||
return M
|
||||
1
selene.toml
Normal file
1
selene.toml
Normal file
|
|
@ -0,0 +1 @@
|
|||
std = 'vim'
|
||||
54
spec/helpers.lua
Normal file
54
spec/helpers.lua
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
local plugin_dir = vim.fn.getcwd()
|
||||
vim.opt.runtimepath:prepend(plugin_dir)
|
||||
|
||||
if not package.loaded['blink.cmp.types'] then
|
||||
package.loaded['blink.cmp.types'] = {
|
||||
CompletionItemKind = {
|
||||
Text = 1,
|
||||
Method = 2,
|
||||
Function = 3,
|
||||
Constructor = 4,
|
||||
Field = 5,
|
||||
Variable = 6,
|
||||
Class = 7,
|
||||
Interface = 8,
|
||||
Module = 9,
|
||||
Property = 10,
|
||||
Unit = 11,
|
||||
Value = 12,
|
||||
Enum = 13,
|
||||
Keyword = 14,
|
||||
Snippet = 15,
|
||||
Color = 16,
|
||||
File = 17,
|
||||
Reference = 18,
|
||||
Folder = 19,
|
||||
EnumMember = 20,
|
||||
Constant = 21,
|
||||
Struct = 22,
|
||||
Event = 23,
|
||||
Operator = 24,
|
||||
TypeParameter = 25,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.create_buffer(lines, filetype)
|
||||
local bufnr = vim.api.nvim_create_buf(false, true)
|
||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines or {})
|
||||
if filetype then
|
||||
vim.api.nvim_set_option_value('filetype', filetype, { buf = bufnr })
|
||||
end
|
||||
vim.api.nvim_set_current_buf(bufnr)
|
||||
return bufnr
|
||||
end
|
||||
|
||||
function M.delete_buffer(bufnr)
|
||||
if bufnr and vim.api.nvim_buf_is_valid(bufnr) then
|
||||
vim.api.nvim_buf_delete(bufnr, { force = true })
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
34
spec/minimal_init.lua
Normal file
34
spec/minimal_init.lua
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
vim.cmd([[set runtimepath=$VIMRUNTIME]])
|
||||
vim.opt.runtimepath:append('.')
|
||||
vim.opt.packpath = {}
|
||||
vim.opt.loadplugins = false
|
||||
|
||||
package.loaded['blink.cmp.types'] = {
|
||||
CompletionItemKind = {
|
||||
Text = 1,
|
||||
Method = 2,
|
||||
Function = 3,
|
||||
Constructor = 4,
|
||||
Field = 5,
|
||||
Variable = 6,
|
||||
Class = 7,
|
||||
Interface = 8,
|
||||
Module = 9,
|
||||
Property = 10,
|
||||
Unit = 11,
|
||||
Value = 12,
|
||||
Enum = 13,
|
||||
Keyword = 14,
|
||||
Snippet = 15,
|
||||
Color = 16,
|
||||
File = 17,
|
||||
Reference = 18,
|
||||
Folder = 19,
|
||||
EnumMember = 20,
|
||||
Constant = 21,
|
||||
Struct = 22,
|
||||
Event = 23,
|
||||
Operator = 24,
|
||||
TypeParameter = 25,
|
||||
},
|
||||
}
|
||||
166
spec/tmux_spec.lua
Normal file
166
spec/tmux_spec.lua
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
local helpers = require('spec.helpers')
|
||||
|
||||
local TMUX_COMMANDS = table.concat({
|
||||
'bind-key (bind) [-lnrN:T:] key command [arguments]',
|
||||
'display-message (display) [-aINpv] [-c target-client] [-d delay] [-t target-pane] [message]',
|
||||
'set-option (set) [-aFgopqsuUw] [-t target-pane] option [value]',
|
||||
}, '\n')
|
||||
|
||||
local TMUX_NAMES = 'bind-key\ndisplay-message\nset-option\n'
|
||||
|
||||
local MAN_PAGE = table.concat({
|
||||
' bind-key [-lnrN:T:] key command [arguments]',
|
||||
' (alias: bind)',
|
||||
'',
|
||||
' Bind a key to a command.',
|
||||
'',
|
||||
' display-message [-aINpv] [-c target-client] [-d delay] [-t target-pane] [message]',
|
||||
' (alias: display)',
|
||||
'',
|
||||
' Display a message.',
|
||||
'',
|
||||
' set-option [-aFgopqsuUw] [-t target-pane] option [value]',
|
||||
' (alias: set)',
|
||||
'',
|
||||
' Set a window option.',
|
||||
}, '\n')
|
||||
|
||||
local function mock_system()
|
||||
local original = vim.system
|
||||
---@diagnostic disable-next-line: duplicate-set-field
|
||||
vim.system = function(cmd)
|
||||
if cmd[1] == 'bash' then
|
||||
return {
|
||||
wait = function()
|
||||
return { stdout = MAN_PAGE, code = 0 }
|
||||
end,
|
||||
}
|
||||
elseif cmd[1] == 'tmux' and cmd[2] == 'list-commands' then
|
||||
if cmd[3] == '-F' then
|
||||
return {
|
||||
wait = function()
|
||||
return { stdout = TMUX_NAMES, code = 0 }
|
||||
end,
|
||||
}
|
||||
end
|
||||
return {
|
||||
wait = function()
|
||||
return { stdout = TMUX_COMMANDS, code = 0 }
|
||||
end,
|
||||
}
|
||||
end
|
||||
return {
|
||||
wait = function()
|
||||
return { stdout = '', code = 1 }
|
||||
end,
|
||||
}
|
||||
end
|
||||
return function()
|
||||
vim.system = original
|
||||
end
|
||||
end
|
||||
|
||||
describe('blink-cmp-tmux', function()
|
||||
local restore
|
||||
|
||||
before_each(function()
|
||||
package.loaded['blink-cmp-tmux'] = nil
|
||||
restore = mock_system()
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
if restore then
|
||||
restore()
|
||||
end
|
||||
end)
|
||||
|
||||
describe('enabled', function()
|
||||
it('returns true for tmux filetype', function()
|
||||
local bufnr = helpers.create_buffer({}, 'tmux')
|
||||
local source = require('blink-cmp-tmux')
|
||||
assert.is_true(source.enabled())
|
||||
helpers.delete_buffer(bufnr)
|
||||
end)
|
||||
|
||||
it('returns false for other filetypes', function()
|
||||
local bufnr = helpers.create_buffer({}, 'lua')
|
||||
local source = require('blink-cmp-tmux')
|
||||
assert.is_false(source.enabled())
|
||||
helpers.delete_buffer(bufnr)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('get_completions', function()
|
||||
it('returns items with Keyword kind', function()
|
||||
local source = require('blink-cmp-tmux').new()
|
||||
local items
|
||||
source:get_completions({ line = '', cursor = { 1, 0 } }, function(response)
|
||||
items = response.items
|
||||
end)
|
||||
assert.is_not_nil(items)
|
||||
assert.equals(3, #items)
|
||||
for _, item in ipairs(items) do
|
||||
assert.equals(14, item.kind)
|
||||
end
|
||||
end)
|
||||
|
||||
it('returns items on empty line', function()
|
||||
local source = require('blink-cmp-tmux').new()
|
||||
local items
|
||||
source:get_completions({ line = '', cursor = { 1, 0 } }, function(response)
|
||||
items = response.items
|
||||
end)
|
||||
assert.equals(3, #items)
|
||||
end)
|
||||
|
||||
it('returns items when typing command prefix', function()
|
||||
local source = require('blink-cmp-tmux').new()
|
||||
local items
|
||||
source:get_completions({ line = 'bind', cursor = { 1, 4 } }, function(response)
|
||||
items = response.items
|
||||
end)
|
||||
assert.is_true(#items > 0)
|
||||
end)
|
||||
|
||||
it('returns empty after command arguments', function()
|
||||
local source = require('blink-cmp-tmux').new()
|
||||
local items
|
||||
source:get_completions({ line = 'bind-key -n ', cursor = { 1, 12 } }, function(response)
|
||||
items = response.items
|
||||
end)
|
||||
assert.equals(0, #items)
|
||||
end)
|
||||
|
||||
it('includes documentation with man page description', function()
|
||||
local source = require('blink-cmp-tmux').new()
|
||||
local items
|
||||
source:get_completions({ line = '', cursor = { 1, 0 } }, function(response)
|
||||
items = response.items
|
||||
end)
|
||||
local bind = vim.iter(items):find(function(item)
|
||||
return item.label == 'bind-key'
|
||||
end)
|
||||
assert.is_not_nil(bind)
|
||||
assert.is_not_nil(bind.documentation)
|
||||
assert.is_truthy(bind.documentation.value:find('Bind a key'))
|
||||
end)
|
||||
|
||||
it('includes alias in documentation', function()
|
||||
local source = require('blink-cmp-tmux').new()
|
||||
local items
|
||||
source:get_completions({ line = '', cursor = { 1, 0 } }, function(response)
|
||||
items = response.items
|
||||
end)
|
||||
local bind = vim.iter(items):find(function(item)
|
||||
return item.label == 'bind-key'
|
||||
end)
|
||||
assert.is_truthy(bind.documentation.value:find('alias'))
|
||||
end)
|
||||
|
||||
it('returns a cancel function', function()
|
||||
local source = require('blink-cmp-tmux').new()
|
||||
local cancel = source:get_completions({ line = '', cursor = { 1, 0 } }, function() end)
|
||||
assert.is_function(cancel)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
8
stylua.toml
Normal file
8
stylua.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
column_width = 100
|
||||
line_endings = "Unix"
|
||||
indent_type = "Spaces"
|
||||
indent_width = 2
|
||||
quote_style = "AutoPreferSingle"
|
||||
call_parentheses = "Always"
|
||||
[sort_requires]
|
||||
enabled = true
|
||||
33
vim.toml
Normal file
33
vim.toml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
[selene]
|
||||
base = "lua51"
|
||||
name = "vim"
|
||||
|
||||
[vim]
|
||||
any = true
|
||||
|
||||
[jit]
|
||||
any = true
|
||||
|
||||
[bit]
|
||||
any = true
|
||||
|
||||
[assert]
|
||||
any = true
|
||||
|
||||
[describe]
|
||||
any = true
|
||||
|
||||
[it]
|
||||
any = true
|
||||
|
||||
[before_each]
|
||||
any = true
|
||||
|
||||
[after_each]
|
||||
any = true
|
||||
|
||||
[spy]
|
||||
any = true
|
||||
|
||||
[stub]
|
||||
any = true
|
||||
Loading…
Add table
Add a link
Reference in a new issue