lsp #36
No reviewers
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set.
Reference
navicore/patch-prolog-v1!36
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "lsp"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
● All green: 6 runner + 248 integration + 148 core unit + 19 new LSP = 421 tests across the workspace. prlg-lsp
MVP is shipped.
What was built:
crates/lsp/ — new workspace member, crate patch-prolog-lsp, binary prlg-lsp.
impl covering initialize, initialized, shutdown, did_open, did_change, did_close, completion, hover.
Capabilities: full sync, completion with : trigger, hover.
(post-#18, #20) into LSP Diagnostic ranges with severity Error and source prlg-lsp. 1-char range from the
position; widening to lexeme spans is a future improvement when the parser exposes structured spans.
predicates (parsed once from include_str!("../../../knowledge/stdlib.pl") behind OnceLock), and user-defined
predicates from the current buffer. Mid-edit safety: if the whole buffer fails to parse, truncate to the last
clause-ending . and retry — so completion stays useful while the user is typing.
user-defined clause head for predicates the user defined in the buffer. Same mid-edit truncation as completion.
Release-workflow updates (.forgejo/workflows/release.yml):
with the workspace.
publish.
Verified end-to-end:
]—same accuracy as prlg run's error output.
truncation, hover for built-ins, hover for user-defined predicates, no-hover on unknown words, and a regression
that internal TokenKind variant names never leak into diagnostic messages.
Review
What it does: Adds a new workspace crate
patch-prolog-lsp(binaryprlg-lsp) — a tower-lsp server with diagnostics (re-parse on change), completion (built-ins + stdlib + buffer-defined predicates), and hover (fixed doc table + user clause heads) — and extends the release workflow to bump/verify/publish the new crate.Overall the design is good: reusing the core parser so squiggles match
prlg runbyte-for-byte, wholesale diagnostic replacement so stale errors clear, mid-edit truncation fallback, logging to stderr only. The 19 tests pass locally. But there are two real bugs, one of which will break the published crate.🔴 Blocking
1. The published crate won't compile —
include_str!reaches outside the packagecrates/lsp/src/completion.rsline 19 doesinclude_str!("../../../knowledge/stdlib.pl"), butknowledge/belongs to the rootpatch-prologpackage, not this crate. Verified:No
stdlib.pl. Since the workflow publishes with--no-verify, the publish will succeed, then everycargo install patch-prolog-lspwill fail with "couldn't read ../../../knowledge/stdlib.pl" — and a published version number can't be reclaimed. Fixes, pick one:build.rsthat copiesstdlib.plintoOUT_DIR+include_str!(concat!(env!("OUT_DIR"), ...)), orSTDLIB_PLas apub constfrompatch-prolog-core(it already ships the parser;src/runner.rs:19andsrc/compiler.rs:5eachinclude_str!it separately today — this would deduplicate all three).A
cargo package -p patch-prolog-lsp(no--no-verify) step in CI would have caught this and is worth adding regardless.2. Panic on non-ASCII lines in completion
completion.rsline 164 —&line[..col]usesposition.characteras a byte index, but LSP positions default to UTF-16 code units. On a line containing any multibyte char before the cursor, the slice lands mid-char and panics (reproduced:end byte index 1 is not a char boundary; it is inside 'é'). Prolog source legitimately contains non-ASCII in quoted atoms/comments. Convert UTF-16 → byte offset (or at minimum clamp to the nearest char boundary). Notehover.rs::word_at_positionhappens to be panic-safe (it returnsNonewhen boundaries don't align) but still computes wrong words on such lines — same conversion applies.🟡 Worth addressing
completion.rsandhover.rs:last_complete_clauses_offset/last_clause_offsetandpredicate_indicator/predicate_pairare byte-identical pairs, and both files implement the same truncate-and-reparse fallback. A small shared module (e.g.src/buffer.rs) would also bring both files back under the ~200-line target (currently 235/266).did_changetakes the first change (main.rs:91). With FULL sync clients send exactly one, but if one ever sends several, the last is the authoritative full text.params.content_changes.into_iter().last()is the same cost and strictly safer.member/2in-buffer gets it twice (stdlib + user). Dedup by(label, detail-source)or prefer the user entry.trigger_characters: [":"]—:only appears in:-/?-, which isn't a predicate-completion position. Harmless but probably not what was intended; identifier typing already triggers completion in most clients.🟢 Minor / fine as-is
tokiowithfeatures = ["full"]— onlyio-std,rt,macrosare needed; trims dependency build for installers.patch-prologstep). The=0.5.0pin + workflow bump logic line up.at line N col Mis acknowledged tech debt with a sensible whole-file fallback, and there's a regression test that internalTokenKindnames don't leak. Good.warn!instead of unwrap — fine for a single-threaded server.Verdict
Solid MVP architecture and good test coverage of the logic that exists, but hold the merge until №1 is fixed — the next tagged release would publish a crate that can never compile for users. №2 is a one-line crash for any non-ASCII buffer and worth fixing in the same pass.
Review by Claude Code