Handoff — 2026-09-18 — first launch: LSP dead until save + relaunch → fixed
State
The user reported that on turbo-go's first launch the LSP does not work, and that saving, quitting and relaunching fixes it. Diagnosed by reading the code, confirmed by the user (the window had started Untitled), and fixed in this session through a full /methodical-dev cycle. Not committed.
The defect: a buffer that gains its path through Save As was never announced to the language server. Language.DidOpen skips path "" (an Untitled window has nothing to announce), afterSave sent only didSave, and announceOpenDocuments runs once (a.announced) — and a server ignores didChange/didSave for a document it was never told is open, so every LSP feature stayed dead in that window until a restart reopened the file under its name.
The fix, all in app:
app/language.go— thedocumentsmap is keyed by absolute path (pathKey, the renameddiagnosticKey), soKnowsdoes not depend on how a path is spelt. Without this, the next change would re-announce a document opened relative and saved absolute.app/actions_file.go—announceSaved, called fromafterSaveso both save paths get it:didOpenfor a path the server does notKnows,didSaveotherwise. Andsaveremembers the buffer's path beforeSaveAsrewrites it;renamed(absolute comparison) triggersDidCloseof the old document on a genuine rename, so no ghost document stays open on the server.
Tests: 5 new (one in app/diagnostics_test.go, four in the new app/save_test.go), each verified by breaking the code it covers. Suite green, -race green on app. Quality run #30 PASS 0/0/0, complexity 2308. Docs EN + FR: reference/app.md (a Knows row, a paragraph on what saving sends), how-to/talk-to-a-language-server.md (a "file created inside the editor" variant), plus app/README.md.
In flight
Nothing half-written. The tree also still carries the uncommitted Windows terminal work of 2026-09-17 (disjoint files — see that day's handoff); this session's change sits on top of it on main.
Next steps
- Commit (the user does this, or asks for it): the fix, its tests, the docs, and
.memory/. - Drive it once against a real gopls: start turbo-go, type into an Untitled window, save as
x.go, complete — the one verification the fake server cannot give. - Tag and release turbo-core, then re-pin the six editors so they inherit the fix.
Open questions / blockers
- The user's report ("la 1ère fois") may also have had a second ingredient: gopls's very first run on a machine populates its caches and answers empty completions while loading, even once
LSP: readyshows. Unmeasured; worth remembering if a report comes back after this fix ships.
Watch out for
- Do not move the announcement into
Buffer.SaveAs: it would put the language server underneath the text type. Rejected on purpose. - Autosave never renames (it rewrites the buffer's own path), which is why
DidCloselives insavealone. If autosave ever learns to rename, that assumption breaks. waitForMethodin the app tests polls up to 2 s; a test asserting a notification was not sent must wait for a later one first (seeTestSaveAsToTheSamePathClosesNothing), or it asserts on a race.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|