fix(fsharp): hover honors the live editor buffer (didChange overlay)#117
Merged
Merged
Conversation
F# hover resolved positions against the on-disk file because the F# sidecar was excluded from document sync: notify_did_change was hardcoded to the C# sidecar, the F# sidecar registered no textDocument/didChange, and getHover read source via File.ReadAllText. The instant the editor buffer diverged from disk, hover misaligned and returned the wrong symbol or null. Route didOpen/didChange to the document's own sidecar by language; the F# sidecar now keeps an in-memory overlay (applyDidChange/readSource) that every per-file analysis reads, falling back to disk only when no buffer is open. Restores F# to parity with C#'s in-place Roslyn updates. [FS-DIDCHANGE-OVERLAY]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TLDR
F# hover (and every per-file F# analysis) now resolves against the live editor buffer instead of stale on-disk text, fixing broken/empty F# hover that occurred the moment you started typing.
Details
Root cause. The F# sidecar was excluded from document sync.
notify_did_changeinsrc/main.rswas hardcoded to the C# sidecar, the F# sidecar registered notextDocument/didChangehandler, andFSharpWorkspace.getHoverread source viaFile.ReadAllText. Once the editor buffer diverged from disk, the editor's line/char pointed into edited text while FCS parsed the old file — so hover returned the wrong symbol ornull. C# was unaffected because Roslyn's workspace is updated in place ondidChange; this restores F# to parity (CLAUDE.md aim #2).Modified behaviour
src/main.rs: newsidecar_for_urihelper.didOpen/didChangenow route the text sync to the document's own sidecar by language (F#→F#, C#→C#) — previously every edit went to the C# sidecar.pick_sidecarandtrigger_diagnosticsnow reusesidecar_for_uri, removing the duplicated language→sidecarmatch.sidecars/SharpLsp.Sidecar.FSharp/FSharpWorkspace.fs:FSharpWorkspaceStategains a thread-safeOverlaysmap; newapplyDidChange+readSource.getHoverandcheckFileWithParseread source viareadSource(so hover, definition, completion, signature help, … all see live edits), falling back to disk only when no buffer is open.sidecars/SharpLsp.Sidecar.FSharp/FSharpSidecar.fs: registerstextDocument/didChange→applyDidChange.New files / types / deps: none. New wire type
DidChangeRequestinFSharpWire.fs(positional MessagePack, mirrors the RustSidecarDidChangeReqand C#DidChangeRequest). No new dependencies. No deletions.Spec:
docs/specs/HOVER-SPEC.md§5.4 documents the live-buffer requirement, tagged[FS-DIDCHANGE-OVERLAY](cross-referenced in the code and tests).How Do The Automated Tests Prove It Works?
e2e_modules::fsharp::test_full_stack_fsharp_hover_reflects_live_edit: opens the F# fixture, sends adidChangeaddingsubtractEdited(a binding that exists only in the buffer, never on disk), then hovers on it. Verified test-first: before the fix it fails — host log showsSidecar response … method=textDocument/hover … bytes=1andHover: sidecar returned null; after the fix it passes —method=textDocument/didChange … bytes=3(ok) followed byHover: sidecar returned content.FSharpExtraCoverageTests.fs:getHover reads the didChange overlay instead of on-disk source— isolated real workspace, overlays a file withoverlayOnlyBinding, assertsgetHoverresolves it from the overlay (provingapplyDidChange+readSource).textDocument/didChangeadded to the malformed-payloadTheory, exercising the handler'swith ex -> Failurebranch (and that the sidecar still answerspingafterward).test_did_change_then_definition_exercises_notify_pathandtest_definition_cache_invalidated_on_change. F# sidecar 323 passed, C# 394, Common 63 (coverage F# 94.77% / C# 94.16% / Common 96.02%, all gates ✓). C#hovermodule 8 passed incl.test_hover_edit_hover_cycle(no C# regression).document_sync13 passed._lint-rust(fmt + clippy-D warnings),csharpier check, and_lint-dotnet(0 warn / 0 err, warnaserror) all clean; deslop reports no new duplication.