Skip to content

refactor!: unify forge:// bufnames to host/slug/resource scheme#288

Merged
barrettruth merged 1 commit intomainfrom
refactor/bufname-scheme
Apr 17, 2026
Merged

refactor!: unify forge:// bufnames to host/slug/resource scheme#288
barrettruth merged 1 commit intomainfrom
refactor/bufname-scheme

Conversation

@barrettruth
Copy link
Copy Markdown
Owner

Problem

forge.nvim had six ad-hoc bufname formats: forge://pr/new, forge://pr/{num}/edit, forge://issue/new, forge://issue/{num}/edit, forge://log/{title}, forge://ci/{title}. The first four collide across repos (:Forge pr edit 42 in repo A vs repo=upstream pulls both to forge://pr/42/edit). The last two collide on their default 'ci' / 'summary' titles when the same CI run is opened twice — the pcall around nvim_buf_set_name was silently swallowing the failure, producing unnamed duplicate buffers. Compose/log/ci buffer naming had zero scoping.

Solution

Single scheme:

forge://{host}/{slug}/{resource}/{id-or-action}[/{sub}]
  • scope.bufpath(scope) new helper returning "{host}/{slug}" or nil
  • compose.lua gains a local resolve_bufpath(ref, forge_name) that tries the explicit scope first and falls back to forge.current_scope(forge_name) via origin remote. All 4 compose open sites use it; pcall dropped from nvim_buf_set_name. When no scope can be resolved (not in a repo, no detectable remote) compose refuses to open with a warning instead of creating a nameless buffer.
  • log.lua LogOpts / SummaryOpts drop title and gain scope + run_id. New helpers log_bufname() / summary_bufname() produce forge://{host}/{slug}/ci/{run_id}[/log|/job/{job_id}]. Both M.open and M.open_summary now look up an existing buffer by name before creating a new one, fixing the duplicate-unnamed-buffer bug.
  • ops.lua 5 callsites (3× log.open, 2× log.open_summary) thread scope = run_ref and run_id = run.id through the opts tables; drop the old title = ... composition.
  • pickers.lua 1 callsite in the PR checks picker threads scope = check_ref and run_id = run_id.

Concrete examples:

forge://github.com/barrettruth/forge.nvim/pr/42/edit
forge://github.com/barrettruth/forge.nvim/ci/987654321
forge://github.com/barrettruth/forge.nvim/ci/987654321/job/5544
forge://gitlab.com/group/subgroup/project/pr/42/edit
forge://ghe.company.com/team/app/pr/new

8 spec files updated: mocks gain current_scope, opts assertions use scope/run_id instead of title, literal bufnames updated to the new format. doc/forge.nvim.txt compose-section bufname references updated; PROSPECTIVE_CHANGES.md line 179's revisit TODO is now addressed.

Breaking: LogOpts.title and SummaryOpts.title are gone; both now require scope + run_id (scope is optional at the type level to tolerate test stubs with partial context, but production paths all supply it). Existing bufname literals anyone scripted against no longer match.

scripts/ci.sh green: stylua / selene / prettier / nix fmt / lua-language-server / vimdoc-language-server / busted (443/0).

- Replace 6 scattered bufname formats with a single
  forge://{host}/{slug}/{resource}/{id-or-action}[/{sub}] scheme,
  eliminating silent collision bugs for same-repo and cross-repo edits
  as well as the forge://log/{title} / forge://ci/{title} default-title
  collisions that the previous pcall was swallowing
- Thread scope+run_id through LogOpts/SummaryOpts and all 6 log.lua
  callers (ops.lua, pickers.lua); drop the opts.title field
- compose.lua gains a resolve_bufpath helper with current_scope
  fallback; buffers refuse to open loudly when no scope is available
- log.lua reuses an existing buffer when a bufname collides, fixing
  the duplicate unnamed-buffer case on repeat CI opens
- Update 8 spec files to match the new surface; doc/forge.nvim.txt
  compose-section references updated to the new format
@barrettruth barrettruth merged commit dba7f91 into main Apr 17, 2026
8 checks passed
@barrettruth barrettruth deleted the refactor/bufname-scheme branch April 17, 2026 17:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant