feat: initial release
This commit is contained in:
commit
9fdd3b3133
26 changed files with 938 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-ghostty.
|
||||||
|
For bug reports, please [open an issue](https://github.com/barrettruth/blink-cmp-ghostty/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-ghostty/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-ghostty',
|
||||||
|
},
|
||||||
|
opts = {
|
||||||
|
sources = {
|
||||||
|
default = { 'ghostty' },
|
||||||
|
providers = {
|
||||||
|
ghostty = {
|
||||||
|
name = 'Ghostty',
|
||||||
|
module = 'blink-cmp-ghostty',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
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-ghostty/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-ghostty/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-ghostty
|
||||||
|
|
||||||
|
Ghostty configuration completion source for
|
||||||
|
[blink.cmp](https://github.com/saghen/blink.cmp).
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Completes Ghostty configuration keys with documentation
|
||||||
|
- Provides enum values for configuration options
|
||||||
|
- Documentation extracted from `ghostty +show-config --docs`
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Neovim 0.10.0+
|
||||||
|
- [blink.cmp](https://github.com/saghen/blink.cmp)
|
||||||
|
- [Ghostty](https://ghostty.org)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Install via
|
||||||
|
[luarocks](https://luarocks.org/modules/barrettruth/blink-cmp-ghostty):
|
||||||
|
|
||||||
|
```
|
||||||
|
luarocks install blink-cmp-ghostty
|
||||||
|
```
|
||||||
|
|
||||||
|
Or with lazy.nvim:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
{
|
||||||
|
'saghen/blink.cmp',
|
||||||
|
dependencies = {
|
||||||
|
'barrettruth/blink-cmp-ghostty',
|
||||||
|
},
|
||||||
|
opts = {
|
||||||
|
sources = {
|
||||||
|
default = { 'ghostty' },
|
||||||
|
providers = {
|
||||||
|
ghostty = {
|
||||||
|
name = 'Ghostty',
|
||||||
|
module = 'blink-cmp-ghostty',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
30
blink-cmp-ghostty-scm-1.rockspec
Normal file
30
blink-cmp-ghostty-scm-1.rockspec
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
rockspec_format = '3.0'
|
||||||
|
package = 'blink-cmp-ghostty'
|
||||||
|
version = 'scm-1'
|
||||||
|
|
||||||
|
source = {
|
||||||
|
url = 'git+https://github.com/barrettruth/blink-cmp-ghostty.git',
|
||||||
|
}
|
||||||
|
|
||||||
|
description = {
|
||||||
|
summary = 'Ghostty configuration completion source for blink.cmp',
|
||||||
|
homepage = 'https://github.com/barrettruth/blink-cmp-ghostty',
|
||||||
|
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-ghostty — Ghostty configuration 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
|
||||||
|
];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
124
lua/blink-cmp-ghostty.lua
Normal file
124
lua/blink-cmp-ghostty.lua
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
---@class blink-cmp-ghostty : blink.cmp.Source
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
---@type blink.cmp.CompletionItem[]?
|
||||||
|
local keys_cache = nil
|
||||||
|
---@type table<string, string[]>?
|
||||||
|
local enums_cache = nil
|
||||||
|
|
||||||
|
function M.new()
|
||||||
|
return setmetatable({}, { __index = M })
|
||||||
|
end
|
||||||
|
|
||||||
|
---@return boolean
|
||||||
|
function M.enabled()
|
||||||
|
return vim.bo.filetype == 'ghostty'
|
||||||
|
end
|
||||||
|
|
||||||
|
---@return blink.cmp.CompletionItem[]
|
||||||
|
local function parse_keys()
|
||||||
|
local Kind = require('blink.cmp.types').CompletionItemKind
|
||||||
|
local result = vim.system({ 'ghostty', '+show-config', '--docs' }):wait()
|
||||||
|
local items = {}
|
||||||
|
local doc_lines = {}
|
||||||
|
|
||||||
|
for line in ((result.stdout or '') .. '\n'):gmatch('(.-)\n') do
|
||||||
|
if line:match('^#') then
|
||||||
|
local stripped = line:gsub('^# ?', '')
|
||||||
|
doc_lines[#doc_lines + 1] = stripped
|
||||||
|
else
|
||||||
|
local key = line:match('^([a-z][a-z0-9-]*)%s*=')
|
||||||
|
if key then
|
||||||
|
local doc = #doc_lines > 0 and table.concat(doc_lines, '\n') or nil
|
||||||
|
items[#items + 1] = {
|
||||||
|
label = key,
|
||||||
|
kind = Kind.Property,
|
||||||
|
documentation = doc and { kind = 'markdown', value = doc } or nil,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
doc_lines = {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return items
|
||||||
|
end
|
||||||
|
|
||||||
|
---@return table<string, string[]>
|
||||||
|
local function parse_enums()
|
||||||
|
local bin = vim.fn.exepath('ghostty')
|
||||||
|
if bin == '' then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
local real = vim.uv.fs_realpath(bin)
|
||||||
|
if not real then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
local prefix = real:match('(.*)/bin/ghostty$')
|
||||||
|
if not prefix then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
local path = prefix .. '/share/bash-completion/completions/ghostty.bash'
|
||||||
|
local fd = io.open(path, 'r')
|
||||||
|
if not fd then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
local content = fd:read('*a')
|
||||||
|
fd:close()
|
||||||
|
|
||||||
|
local enums = {}
|
||||||
|
for key, values in content:gmatch('%-%-([a-z][a-z0-9-]*)%) [^\n]* compgen %-W "([^"]+)"') do
|
||||||
|
local vals = {}
|
||||||
|
for v in values:gmatch('%S+') do
|
||||||
|
vals[#vals + 1] = v
|
||||||
|
end
|
||||||
|
if #vals > 0 then
|
||||||
|
enums[key] = vals
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return enums
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param ctx blink.cmp.Context
|
||||||
|
---@param callback fun(response: blink.cmp.CompletionResponse)
|
||||||
|
---@return fun()
|
||||||
|
function M:get_completions(ctx, callback)
|
||||||
|
if not keys_cache then
|
||||||
|
keys_cache = parse_keys()
|
||||||
|
enums_cache = parse_enums()
|
||||||
|
end
|
||||||
|
|
||||||
|
local line = ctx.line
|
||||||
|
local col = ctx.cursor[2]
|
||||||
|
local eq_pos = line:find('=')
|
||||||
|
|
||||||
|
if eq_pos and col > eq_pos then
|
||||||
|
local key = vim.trim(line:sub(1, eq_pos - 1))
|
||||||
|
local vals = enums_cache[key]
|
||||||
|
if vals then
|
||||||
|
local Kind = require('blink.cmp.types').CompletionItemKind
|
||||||
|
local items = {}
|
||||||
|
for _, v in ipairs(vals) do
|
||||||
|
items[#items + 1] = {
|
||||||
|
label = v,
|
||||||
|
kind = Kind.EnumMember,
|
||||||
|
filterText = v,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
callback({
|
||||||
|
is_incomplete_forward = false,
|
||||||
|
is_incomplete_backward = false,
|
||||||
|
items = items,
|
||||||
|
})
|
||||||
|
return function() end
|
||||||
|
end
|
||||||
|
callback({ items = {} })
|
||||||
|
else
|
||||||
|
callback({
|
||||||
|
is_incomplete_forward = false,
|
||||||
|
is_incomplete_backward = false,
|
||||||
|
items = vim.deepcopy(keys_cache),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
return function() end
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
1
selene.toml
Normal file
1
selene.toml
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
std = 'vim'
|
||||||
175
spec/ghostty_spec.lua
Normal file
175
spec/ghostty_spec.lua
Normal file
|
|
@ -0,0 +1,175 @@
|
||||||
|
local helpers = require('spec.helpers')
|
||||||
|
|
||||||
|
local CONFIG_DOCS = table.concat({
|
||||||
|
'# The font family to use.',
|
||||||
|
'# This can be a comma-separated list of font families.',
|
||||||
|
'font-family = default',
|
||||||
|
'',
|
||||||
|
'# The font size in points.',
|
||||||
|
'font-size = 12',
|
||||||
|
'',
|
||||||
|
'# The cursor style.',
|
||||||
|
'cursor-style = block',
|
||||||
|
'',
|
||||||
|
}, '\n')
|
||||||
|
|
||||||
|
local BASH_COMPLETION = table.concat({
|
||||||
|
' --cursor-style) mapfile -t COMPREPLY < <( compgen -W "block bar underline" -- "$cur" ); _add_spaces ;;',
|
||||||
|
' --font-style) mapfile -t COMPREPLY < <( compgen -W "normal italic" -- "$cur" ); _add_spaces ;;',
|
||||||
|
}, '\n')
|
||||||
|
|
||||||
|
local function mock_system()
|
||||||
|
local original = vim.system
|
||||||
|
---@diagnostic disable-next-line: duplicate-set-field
|
||||||
|
vim.system = function(cmd)
|
||||||
|
if cmd[1] == 'ghostty' then
|
||||||
|
return {
|
||||||
|
wait = function()
|
||||||
|
return { stdout = CONFIG_DOCS, code = 0 }
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
wait = function()
|
||||||
|
return { stdout = '', code = 1 }
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
return function()
|
||||||
|
vim.system = original
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function mock_enums()
|
||||||
|
local original_exepath = vim.fn.exepath
|
||||||
|
local original_realpath = vim.uv.fs_realpath
|
||||||
|
local original_open = io.open
|
||||||
|
|
||||||
|
vim.fn.exepath = function(name)
|
||||||
|
if name == 'ghostty' then
|
||||||
|
return '/mock/bin/ghostty'
|
||||||
|
end
|
||||||
|
return original_exepath(name)
|
||||||
|
end
|
||||||
|
vim.uv.fs_realpath = function(path)
|
||||||
|
if path == '/mock/bin/ghostty' then
|
||||||
|
return '/mock/bin/ghostty'
|
||||||
|
end
|
||||||
|
return original_realpath(path)
|
||||||
|
end
|
||||||
|
io.open = function(path, mode)
|
||||||
|
if path:match('ghostty%.bash$') then
|
||||||
|
return {
|
||||||
|
read = function()
|
||||||
|
return BASH_COMPLETION
|
||||||
|
end,
|
||||||
|
close = function() end,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
return original_open(path, mode)
|
||||||
|
end
|
||||||
|
|
||||||
|
return function()
|
||||||
|
vim.fn.exepath = original_exepath
|
||||||
|
vim.uv.fs_realpath = original_realpath
|
||||||
|
io.open = original_open
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe('blink-cmp-ghostty', function()
|
||||||
|
local restores = {}
|
||||||
|
|
||||||
|
before_each(function()
|
||||||
|
package.loaded['blink-cmp-ghostty'] = nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
after_each(function()
|
||||||
|
for _, fn in ipairs(restores) do
|
||||||
|
fn()
|
||||||
|
end
|
||||||
|
restores = {}
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe('enabled', function()
|
||||||
|
it('returns true for ghostty filetype', function()
|
||||||
|
local bufnr = helpers.create_buffer({}, 'ghostty')
|
||||||
|
local source = require('blink-cmp-ghostty')
|
||||||
|
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-ghostty')
|
||||||
|
assert.is_false(source.enabled())
|
||||||
|
helpers.delete_buffer(bufnr)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe('get_completions', function()
|
||||||
|
it('returns config keys before =', function()
|
||||||
|
restores[#restores + 1] = mock_system()
|
||||||
|
restores[#restores + 1] = mock_enums()
|
||||||
|
local source = require('blink-cmp-ghostty').new()
|
||||||
|
local items
|
||||||
|
source:get_completions({ line = 'font', cursor = { 1, 4 } }, function(response)
|
||||||
|
items = response.items
|
||||||
|
end)
|
||||||
|
assert.is_not_nil(items)
|
||||||
|
assert.equals(3, #items)
|
||||||
|
for _, item in ipairs(items) do
|
||||||
|
assert.equals(10, item.kind)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('includes documentation from config docs', function()
|
||||||
|
restores[#restores + 1] = mock_system()
|
||||||
|
restores[#restores + 1] = mock_enums()
|
||||||
|
local source = require('blink-cmp-ghostty').new()
|
||||||
|
local items
|
||||||
|
source:get_completions({ line = '', cursor = { 1, 0 } }, function(response)
|
||||||
|
items = response.items
|
||||||
|
end)
|
||||||
|
local font_family = vim.iter(items):find(function(item)
|
||||||
|
return item.label == 'font-family'
|
||||||
|
end)
|
||||||
|
assert.is_not_nil(font_family)
|
||||||
|
assert.is_not_nil(font_family.documentation)
|
||||||
|
assert.is_truthy(font_family.documentation.value:find('font family'))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('returns enum values after =', function()
|
||||||
|
restores[#restores + 1] = mock_system()
|
||||||
|
restores[#restores + 1] = mock_enums()
|
||||||
|
local source = require('blink-cmp-ghostty').new()
|
||||||
|
local items
|
||||||
|
source:get_completions({ line = 'cursor-style = ', cursor = { 1, 15 } }, function(response)
|
||||||
|
items = response.items
|
||||||
|
end)
|
||||||
|
assert.is_not_nil(items)
|
||||||
|
assert.equals(3, #items)
|
||||||
|
for _, item in ipairs(items) do
|
||||||
|
assert.equals(20, item.kind)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('returns empty after = for unknown key', function()
|
||||||
|
restores[#restores + 1] = mock_system()
|
||||||
|
restores[#restores + 1] = mock_enums()
|
||||||
|
local source = require('blink-cmp-ghostty').new()
|
||||||
|
local items
|
||||||
|
source:get_completions({ line = 'font-family = ', cursor = { 1, 14 } }, function(response)
|
||||||
|
items = response.items
|
||||||
|
end)
|
||||||
|
assert.equals(0, #items)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('returns a cancel function', function()
|
||||||
|
restores[#restores + 1] = mock_system()
|
||||||
|
restores[#restores + 1] = mock_enums()
|
||||||
|
local source = require('blink-cmp-ghostty').new()
|
||||||
|
local cancel = source:get_completions({ line = '', cursor = { 1, 0 } }, function() end)
|
||||||
|
assert.is_function(cancel)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
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,
|
||||||
|
},
|
||||||
|
}
|
||||||
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