Skip to content

feat(lsp): bca lsp — LSP server for inline metric annotations in editors #384

@dekobon

Description

@dekobon

Motivation

The two-tier local gate (make self-scan / make self-scan-headroom)
closes the feedback loop on "before push". A pre-commit hook closes
it on "before commit". An LSP server closes it on "before save".

Inline annotations — "this function has cognitive 26, limit is 25,
refactor before commit" rendered live in the editor margin — catch
regressions at the moment they're typed, when the author still has
the test cases in their head and the function open. Every other
threshold-style tool (rust-analyzer, clippy via flycheck, ESLint,
Sonarlint) ships an LSP precisely because pre-commit is too late
for the high-iteration TDD-style refactor flow.

Proposal

bca lsp

starts a tower-lsp-based server that responds to:

  • initialize — reads bca.toml from rootUri; mirrors bca check
    config resolution.
  • textDocument/didOpen, didChange, didSave — incrementally
    re-parses the open buffer, recomputes per-function metrics, emits
    textDocument/publishDiagnostics with the offender list.
  • textDocument/codeAction — "Suppress via bca: suppress" /
    "Add to [check.exclude]" / "Refresh baseline for this function"
    as quick-fixes.
  • textDocument/hover over a function head — returns all current
    metric values, each annotated with (N% of limit).

Diagnostic severity:

  • Above hard limit → Error
  • Above soft / headroom → Warning
  • In baseline → Hint (informational, not noisy)

Wire this up in VS Code via a small extension, in Neovim via
nvim-lspconfig, in JetBrains via the LSP4IJ plugin, in Helix via
built-in LSP. None of those wrappers need bca-specific code beyond
pointing at the bca lsp binary.

What this deletes

Nothing in the book directly — LSP is strictly additive over the
existing pre-commit / CI tiers. But the question "how do I see
metrics in my editor?" comes up immediately for anyone who's used
rust-analyzer; a bca lsp answer means we don't need a
third-party shim.

Acceptance

  • bca lsp passes the LSP initialize handshake against VS Code
    and Neovim out of the box.
  • Editing a function pushes its cognitive / cyclomatic over the
    limit produces an inline Error diagnostic within ~500ms of
    keystroke.
  • Functions in .bca-baseline.toml show Hint-severity diagnostics
    (visible but not noisy).
  • The server respects [check.exclude] (feat(check): [check.exclude] — files analysed but exempt from threshold gates #378) and in-source
    suppression markers.
  • Documented integration recipes (a few lines of :LspConfig etc.)
    in the book under a new recipes/lsp.md.

Why tower-lsp

Maintained, Tokio-based, the same crate rust-analyzer uses
indirectly. Trying to hand-roll the LSP framing is a project unto
itself; tower-lsp reduces this to "implement the handler trait".

Coherence

Coherence with related issues

Hard dependencies (LSP UX depends on these)

Soft dependencies (UX improves but not blocking)

Out of scope, but related

VS Code / JetBrains / Neovim wrapper extensions live in
separate repos; this issue only ships the protocol server.
Document the wiring once per editor in the book under a new
recipes/lsp.md.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedExtra attention is needed

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions