feat(forge): support custom shorthand prefixes
Problem: forge shorthand parsing hardcoded `%l%l` (exactly 2 lowercase letters), preventing custom prefixes like `github:`. Completions also hardcoded `gh:`, `gl:`, `cb:` patterns. Solution: iterate `_by_shorthand` keys dynamically in `_parse_shorthand` instead of matching a fixed pattern. Build completion patterns from `forge.backends()`. Add `shorthand` field to `ForgeInstanceConfig` so users can override prefixes via config, applied in `_ensure_instances()`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e62f2f818c
commit
61eadec87e
4 changed files with 106 additions and 8 deletions
|
|
@ -1,4 +1,5 @@
|
|||
local config = require('pending.config')
|
||||
local forge = require('pending.forge')
|
||||
|
||||
---@class pending.CompletionItem
|
||||
---@field word string
|
||||
|
|
@ -109,6 +110,17 @@ local function recur_completions()
|
|||
return result
|
||||
end
|
||||
|
||||
---@param source string
|
||||
---@return boolean
|
||||
function M._is_forge_source(source)
|
||||
for _, b in ipairs(forge.backends()) do
|
||||
if b.shorthand == source then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---@type string?
|
||||
local _complete_source = nil
|
||||
|
||||
|
|
@ -128,10 +140,10 @@ function M.omnifunc(findstart, base)
|
|||
{ vim.pesc(dk) .. ':([%S]*)$', dk },
|
||||
{ 'cat:([%S]*)$', 'cat' },
|
||||
{ vim.pesc(rk) .. ':([%S]*)$', rk },
|
||||
{ 'gh:([%S]*)$', 'gh' },
|
||||
{ 'gl:([%S]*)$', 'gl' },
|
||||
{ 'cb:([%S]*)$', 'cb' },
|
||||
}
|
||||
for _, b in ipairs(forge.backends()) do
|
||||
table.insert(checks, { vim.pesc(b.shorthand) .. ':([%S]*)$', b.shorthand })
|
||||
end
|
||||
|
||||
for _, check in ipairs(checks) do
|
||||
local start = before:find(check[1])
|
||||
|
|
@ -172,7 +184,7 @@ function M.omnifunc(findstart, base)
|
|||
table.insert(matches, { word = c.word, menu = '[' .. source .. ']', info = c.info })
|
||||
end
|
||||
end
|
||||
elseif source == 'gh' or source == 'gl' or source == 'cb' then
|
||||
elseif M._is_forge_source(source) then
|
||||
local s = require('pending.buffer').store()
|
||||
if s then
|
||||
local seen = {}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
---@field icon? string
|
||||
---@field issue_format? string
|
||||
---@field instances? string[]
|
||||
---@field shorthand? string
|
||||
|
||||
---@class pending.ForgeConfig
|
||||
---@field auto_close? boolean
|
||||
|
|
|
|||
|
|
@ -62,6 +62,14 @@ function M.backends()
|
|||
return _backends
|
||||
end
|
||||
|
||||
function M._reset_instances()
|
||||
_instances_resolved = false
|
||||
_by_shorthand = {}
|
||||
for _, b in ipairs(_backends) do
|
||||
_by_shorthand[b.shorthand] = b
|
||||
end
|
||||
end
|
||||
|
||||
local function _ensure_instances()
|
||||
if _instances_resolved then
|
||||
return
|
||||
|
|
@ -73,17 +81,27 @@ local function _ensure_instances()
|
|||
for _, inst in ipairs(forge_cfg.instances or {}) do
|
||||
_by_host[inst] = backend
|
||||
end
|
||||
if forge_cfg.shorthand and forge_cfg.shorthand ~= backend.shorthand then
|
||||
_by_shorthand[backend.shorthand] = nil
|
||||
backend.shorthand = forge_cfg.shorthand
|
||||
_by_shorthand[backend.shorthand] = backend
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param token string
|
||||
---@return pending.ForgeRef?
|
||||
function M._parse_shorthand(token)
|
||||
local prefix, rest = token:match('^(%l%l):(.+)$')
|
||||
if not prefix then
|
||||
return nil
|
||||
_ensure_instances()
|
||||
local backend, rest
|
||||
for prefix, b in pairs(_by_shorthand) do
|
||||
local candidate = token:match('^' .. vim.pesc(prefix) .. ':(.+)$')
|
||||
if candidate then
|
||||
backend = b
|
||||
rest = candidate
|
||||
break
|
||||
end
|
||||
end
|
||||
local backend = _by_shorthand[prefix]
|
||||
if not backend then
|
||||
return nil
|
||||
end
|
||||
|
|
|
|||
|
|
@ -391,6 +391,73 @@ describe('forge registry', function()
|
|||
end)
|
||||
end)
|
||||
|
||||
describe('custom forge prefixes', function()
|
||||
local config = require('pending.config')
|
||||
local complete = require('pending.complete')
|
||||
|
||||
it('parses custom-length shorthand (3+ chars)', function()
|
||||
local custom = forge.gitea_backend({
|
||||
name = 'customforge',
|
||||
shorthand = 'cgf',
|
||||
default_host = 'custom.example.com',
|
||||
})
|
||||
forge.register(custom)
|
||||
|
||||
local ref = forge._parse_shorthand('cgf:alice/proj#99')
|
||||
assert.is_not_nil(ref)
|
||||
assert.equals('customforge', ref.forge)
|
||||
assert.equals('alice', ref.owner)
|
||||
assert.equals('proj', ref.repo)
|
||||
assert.equals(99, ref.number)
|
||||
end)
|
||||
|
||||
it('parse_ref dispatches custom-length shorthand', function()
|
||||
local ref = forge.parse_ref('cgf:alice/proj#5')
|
||||
assert.is_not_nil(ref)
|
||||
assert.equals('customforge', ref.forge)
|
||||
assert.equals(5, ref.number)
|
||||
end)
|
||||
|
||||
it('find_refs finds custom-length shorthand', function()
|
||||
local refs = forge.find_refs('Fix cgf:alice/proj#12')
|
||||
assert.equals(1, #refs)
|
||||
assert.equals('customforge', refs[1].ref.forge)
|
||||
assert.equals(12, refs[1].ref.number)
|
||||
end)
|
||||
|
||||
it('completion returns entries for custom backends', function()
|
||||
assert.is_true(complete._is_forge_source('cgf'))
|
||||
end)
|
||||
|
||||
it('config shorthand override re-registers backend', function()
|
||||
vim.g.pending = {
|
||||
forge = {
|
||||
github = { shorthand = 'github' },
|
||||
},
|
||||
}
|
||||
config.reset()
|
||||
forge._reset_instances()
|
||||
|
||||
local ref = forge._parse_shorthand('github:user/repo#1')
|
||||
assert.is_not_nil(ref)
|
||||
assert.equals('github', ref.forge)
|
||||
assert.equals('user', ref.owner)
|
||||
assert.equals('repo', ref.repo)
|
||||
assert.equals(1, ref.number)
|
||||
|
||||
assert.is_nil(forge._parse_shorthand('gh:user/repo#1'))
|
||||
|
||||
vim.g.pending = nil
|
||||
config.reset()
|
||||
for _, b in ipairs(forge.backends()) do
|
||||
if b.name == 'github' then
|
||||
b.shorthand = 'gh'
|
||||
end
|
||||
end
|
||||
forge._reset_instances()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('forge diff integration', function()
|
||||
local store = require('pending.store')
|
||||
local diff = require('pending.diff')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue