mcpp-language-server 0.0.8: completion shows while you type beside inline completions, a module being written stays with clangd, and what 0.0.7 left (#34) - #36
Merged
Conversation
…nline completion is installed
Since a VS Code release between 1.108 and 1.125, `editor.quickSuggestions.other` defaults to
`offWhenInlineCompletions`: with an inline-completion provider (Copilot is built into VS Code 1.132)
a keystroke first waits for it, the completion list is not opened at all while it shows grey text,
and otherwise only after it answered or 750 ms passed with the document and cursor unchanged. On the
hello111 project that was reported as "no keyword, parameter or variable completion": the server
received 24 completion requests in 18 minutes of editing, none while the person reproduced it, and
answered each in 21 ms at the median.
The extension contributes `{other: "on", comments: "off", strings: "off"}` as the language default
of `[cpp]` and `[c]` (WA-VSCODE-002): the list and the inline completion side by side, as before that
release; other languages keep the editor's own default. A language default outranks a setting that
names no language, so whoever set `editor.quickSuggestions` for every language is told once, in the
log, how to keep theirs. The diagnostic bundle and the report carry the editor settings that decide
whether completion shows (the value and where it comes from, inline suggestions, autosave, the
inline-completion extensions), and a canary fails once VS Code's own default no longer waits.
…rds, not nothing A file clangd does not serve -- set aside, taken by containment, or clangd backing off after crashes -- was answered by mcppls's own engine alone, which knows module syntax and nothing else: an empty list for `i` or `a_`, in under 2 ms. Such a completion, and one clangd answered with an error, now gets what the R-7 budget answer has: the file's words nearest first and the keywords, as an incomplete list the editor asks again for -- never on an import line, where only module names belong. The report counts them (`completion.wordsWithoutCore`).
…model's stand-ins come in one restart M-1: with autosave, a module interface saved mid-edit does not compile, and containment (RP1.1) took the module's own file and every importer from clangd: didClose, one "module did not compile" diagnostic with no position, completion answered by mcppls's engine -- and the next save handed them back, so they flipped every few seconds (92 s of writing a module: doomed 18 times, 48% of the completions in it empty). A module that fails while a source of its closure is open and was edited within two minutes is now work in progress: its files stay with clangd, which reads the one being edited from its buffer and gives an importer its own locals and keywords with an error on the import. Two minutes after the last edit, if what failed is still on disk, containment takes it as before. Completions clangd does not answer are wired to the file's words (the previous commit). M-3: an edit to a source a module being prepared is built from counts as progress, so writing that module is no longer reported as "preparation-stalled ... cannot recover by itself" with an automatic bundle; the report lists the prime units running, for how long, and clangd's status of each. P-1: clangd reports the modules it cannot find one per session -- it stops at the first import it cannot build -- so a partial model brought its stand-ins in one clangd restart each (GalTranslPP: four rounds of about 26 s). By then clangd has logged every unit it could not scan; all their modules are taken together, for one replan and one restart. R-4: on the provisional model (no cache, the build tool still to answer) only the standard library is prepared; the project's modules wait for the build tool's commands instead of being built twice, and Windows' clangd no longer crashes on the provisional ones. K-3: a crash keeps LLVM's stack dump as clangd printed it and which clangd it was (version, sha256), for an upstream report. K-6: a settled workspace turns preparing again only when a rebuild lasts 30 s. E-3: the report says when each method was last answered and how much was edited.
… and Open VSX gets ten minutes to list a release The ux budgets were widened over three rounds of the 0.0.7 pull request because the same runner type differed by up to 1.9x; setting them from what the runners measure needs the numbers over many runs. `mcppls-devtools measure budgets <dir>` reads every --measure file under a directory and prints, for each check and each number of its measure, the runs, median, 95th percentile, largest value and 1.3 times the 95th percentile; nightly's new ux-budgets job runs it over the night's three rounds. publish-openvsx.yml waited three minutes for Open VSX to list each VSIX, and 0.0.7's darwin-arm64 took longer: the check failed although the file it served was right. It waits ten.
…riting modules with autosave, and the plan The plan (.agents/docs/2026-09-30-0.0.8-plan.md) with its decisions (Q1-Q5 as recommended), its second revision of K-3 (the released clangd has no symbols: a crash keeps its stack dump and which clangd it was) and of P-1 (clangd reports one missing module per session, so the modules whose units it could not scan are taken together), and the split of the work by architecture, stability, simplicity, experience, compatibility, platforms, consistency and upgrade. The design record gains UD5 (the completion list in VS Code), RD15 (containment is for a broken module, not one being written) and RD16 (the provisional model prepares std only; stand-ins together). Troubleshooting, editors and settings, in English and Chinese, say why the list stayed closed and what the bundle shows; the changelogs and every editor plugin carry 0.0.8.
…status holds only its state
`Json words { x }` made a one-element array of the words, so a completion clangd did not answer went
out with an array among its items (failure-at-base's stress check stopped on it) and was never
empty. The settled-preparing hold (K-6) took a ready status from before clangd was serving for a
settled workspace, and held everything back while it lasted, the issue failure-at-base waits for
included: only a ready or degraded state while the core engine serves counts now, and only the state
is held. The engine's two lookups of a failing module's edited sources are one.
…eep an importer open and budget dooms, module-failed diagnostics and stalls Fix plan 0.0.8 M-4. The typing kind saved on a fixed interval only, so it could not reproduce files.autoSave afterDelay, where a half-typed statement is written to disk each time the person pauses. autosave-idle-ms saves once that long has passed since the last key and the buffer differs from what was last saved. importer opens a second file with a probe line inserted in its buffer, asks for a completion at the end of that line beside each of the typed file's, and keeps its latencies and empty answers apart. The new budgets doomed, moduleFailedDiagnostics, stalled, importerP95 and importerEmpty are measured from the report's event totals, a per-uri count of publishDiagnostics carrying code module-failed, and the status samples, and are reported with the existing fields.
…itten is taken from clangd A module interface written with autosave afterDelay, its importer open with a probe line in main(), 30 s at 10 Hz. Against 0.0.7 it fails on doomed files, module-failed diagnostics and empty importer completions; a server that keeps a module being edited in clangd passes with all of them at 0. The fixture runs in the pull request conformance job on linux, darwin, arm64 and win32 beside typing-autosave.
…mcpp and ux-xlings, and the typing keys are documented U16 types functions with half statements into a module imported by a few modules (mcpp.pack.digest with mcpp.pack.prebuilt open in mcpp; xlings.core.console with xlings.core.log open in xlings) for 90 s with autosave a second after the last key. Nothing may be doomed, no module-failed diagnostic published, no status sample say preparation-stalled, clangd restarted, or an importer completion be empty; typed-file p95 1.1 s, importer p95 1.5 s, engine share 0.75. conformance/README.md lists the fixture, the typing kind's new keys and budgets and U16 in the edits stage.
…l while stand-ins arrive one restart at a time and project modules are prepared from the provisional model Fix plan 0.0.8 P-1 and R-4. partial-scan-standins has three module interfaces whose scans fail at different times (a generated chain of headers before a missing one), so clangd names one module it cannot find per session: 0.0.7 restarts clangd twice, for a and b and then for c, and the fixture allows one. provisional-no-prime delays the mock producer by eight seconds (the delayed-producer prepare step, a shell script around the mock) and reads cxxModules/report six seconds in: 0.0.7 already wants three units for preparation, std, std.compat and the project's module, where the fixture allows two. The runner gains the report expectations at-most, max-matches and min-matches and the check key not-before-since-start, documented in conformance/README.md.
…sured before and after
…settings tables instead of sitting inside them test_settings holds docs/30-settings.md and its Chinese mirror to the renderer's output between the settings markers, byte for byte; the paragraph about WA-VSCODE-002 had been put inside.
…ts clangd names with backslashes are found M-1 kept a module that fails while it is being written with clangd, but not what containment also does for it: give up the preparation of the modules that cannot build now. A prime unit waiting on the module being written kept the primer busy and, with M-3 counting the edits as progress, the workspace "preparing" with nothing to show for it -- 140 s on ux-mcpp and 185 s on ux-xlings (U15-edits, over its 60 s). Their prime units are closed and resolved, as doomed modules' are; clangd builds them for the files that need them once they compile again. P-1 looked the units clangd could not scan up by their path key, but clangd names a unit as its command line did -- `D:\a\...\Updater\..\3rdParty\3rdModule\boost.ixx` on Windows -- and the plan's units are normalized: on GalTranslPP nothing matched and the stand-ins came one restart at a time again. Both sides are normalized.
…its budget already allows The restart a half-typed import on disk makes clangd need waits for a 3 s pause (R-8), which is when the typing ends and the refresh is measured: 14.5 s on the 0.0.7 merge, 16.3 s on this pull request, under 6 s in rounds without it. The fixture's description records it.
…rters are contained as before The first M-1 kept a failing module's whole closure with clangd while a source of it was being edited. The pull request's ux runs and xlings locally disproved it: with the importer open, every save of the module made clangd build the modules between again, the importer had no diagnostics for minutes after the typing stopped, was set aside and clangd restarted for it, and the status stayed preparing 140-185 s (U15-edits; 0.0.7 had 16-35 s). What the person writing a module needs is that module itself: it needs no BMI of its own, so clangd reads it from the editor with its real errors and completion at no cost to anything else. The unit whose compile failed is left out of the doomed files; everything else containment does is as in 0.0.7, and the importers' completion has the file's words (M-2). The deferral, its two-minute review and the guard's editing_until are gone. A new clangd's preparation progress is measured from its own start: the last clangd's made a restart report "preparation-stalled ... cannot recover" two seconds in.
…led diagnostics, and the docs follow M-1's third revision `moduleFailedDiagnostics` counts the typed file's only (a file taken from clangd gets one); the importer's are reported apart, since an importer of a module that does not compile is contained by design. U16 and module-edit-autosave drop the `doomed` budget and U16's engine share is 0.4: the importer's half of the completions is mcppls's while the module does not compile. The plan, the design record, the changelogs and troubleshooting (English and Chinese) describe the revision and why.
… not stop clangd's crashes on GalTranslPP The cross-validation (Sunrisepeak/GalTranslPP#1, run 36738002085) shows clangd still crashing four times while the provisional model serves GalTranslPP, as with 0.0.7: in the opened files' own builds, not in preparation. The comment, the changelog and the plan say what R-4 does and what stays open (#34-1).
… alone, and the 0.0.8 part 2 plan
…the word it was asked in, and GCC's own standard is read Part 2 of the 0.0.8 plan (.agents/docs/2026-10-01-0.0.8-part2-plan.md), from the GalTranslPP and xmake bundles. C-1: a prime unit is closed as soon as its module is prepared. They were held open until all preparation was idle, and clangd re-checks every open file on didSave and rebuilds the modules of those whose imports changed, so each autosave rebuilt module closures no open file needed, on the workers the typed file waited for (15 held on GalTranslPP, 70 on ux-xlings). Measured with clangd 23.1: after didClose the BMI stays in clangd's module cache and a reopened importer is diagnosed in 0.35 s against 1.66 s the first time. C-2: a completion clangd did not answer in its 1 s budget is no longer cancelled. It keeps working for up to 10 s, the requests the same word makes meanwhile wait for it, and its answer goes to them, its edits ended at each one's cursor; a request in another word cancels it. Cancelled, clangd's answer never reached anyone: the next keystroke queued behind the same rebuild and missed its budget too (GalTranslPP: 25 of 48 completions answered with the file's words). C-4: the report names the ten slowest files by request (slowestFiles) and what building each file cost clangd, from its log (engines[].details.buildTimes: preambles, imported modules, AST builds). X-3: a GCC command naming no standard is read with GCC's own default where Clang's differs (GCC 16: gnu++20; GCC 15 C: gnu23). xmake writes no -std when xmake.lua sets no language; Clang's gnu++17 could not scan GCC 16's std.cc (20 errors) while the build compiled it. Module units read below C++20 are said once (module-standard-too-old). X-4: a scan failure of the standard library's module units, or of a unit outside the workspace, is the command's, never a half-typed file's: it is reported (module-scan-failed) instead of ignored. I-1: clangd's include cleaner stays on. A new fixture, include-cleaner-modules, with a check kind diagnostic-code-lines, holds that it reports only unused headers in a module interface, an implementation unit and an importer.
…n record takes its decisions
…runs Where the server comes from (mcppls on PATH, else the installed payload, else an error that names the fix) moves to resolve.rs, which names no Zed type, so it compiles for the host as well as for wasm32-wasip2. lib.rs maps Zed's platform onto it. Six tests cover PATH winning, the payload when PATH has none, XDG_DATA_HOME, the error text, and the Windows and macOS payload paths.
…commended settings and with Zed's defaults editors/zed/tests/smoke.sh installs the extension the way release-checks does, starts the pinned Zed (ZED_VERSION in versions.env, sha256-checked) on a copy of the inferred fixture with its own HOME and XDG directories, and reads the conversation from a copy kept by a mcppls script first on PATH: within 60 s Zed initialized the server as "Zed", sent the file and got diagnostics for it. The script is also how the server gets --log-level debug, which the extension cannot pass. With the recommended settings Zed starts no clangd; with its defaults it does, beside mcppls, and that both ran is recorded. Quitting Zed must leave no mcppls process.
… change can reach it zed-unit runs the extension's tests and its wasm build on every pull request. zed-smoke.yml is the real-Zed smoke as a reusable workflow on the run's Linux payload; ci.yml calls it for a pull request that touches editors/zed, src/lsp, src/orchestrator or devtools or that belongs to a release/* branch (not again when release-checks is about to), nightly.yml calls it every night, and release-checks.yml makes it part of the release candidate.
The Zed README and the editors pages (English and Chinese) number the install as the extension and then the settings that put mcppls first and clangd off, and say what happens without the second step. The README's status section describes how the extension is tested.
…s written, not parsed for every report The report parsed clangd's whole log ring for engines[].details.buildTimes, and held the event loop 2.3 s for each cxxModules/report on ux-xlings. The times are now added up line by line on the thread that reads clangd's standard error, and a report copies the sums.
…ojects and xmake following its settings
…Verifier checks it on 2025.2 and 2026.2.3 platformVersion moves to 2026.2.3 (build 262.10968.117), the IntelliJ Platform Gradle Plugin to 2.19.0 and Kotlin to 2.4.0, which the 2026.2 jars' metadata needs. sinceBuild stays 252. pluginVerification.ides lists CLion 2025.2 and 2026.2.3, so `gradle verifyPlugin` fails on an incompatible change in either. Built against 2026.2.3, Kotlin copied the renamed LSP interface's default methods into the provider as calls to super, and the verifier found four NoSuchMethodErrors on 2025.2. Compiling with -jvm-default=no-compatibility leaves them out; both builds verify as compatible. The test task and its dependencies (the platform test framework, JUnit 4) are declared here too; the tests follow.
…ne, unless Settings | Tools | mcppls says otherwise The plugin used to start mcppls for every C and C++ file, so a CMake project got two lists of completions and two sets of diagnostics. Now a file has one engine. A project CLion models (a loaded CMake, compilation database, Makefile or open-folder workspace, asked of CidrWorkspaceManager, or a CMakeLists.txt at the root) is CLion's and mcppls does not start for it; every other project is mcppls's. The workspace classes live in CLion's C/C++ plugin, so the question is put through an extension point that mcppls-cidr.xml fills only when that plugin is there (an optional dependency): where the API is missing or has changed the plugin still loads and the CMakeLists.txt check alone decides. Settings | Tools | mcppls has one checkbox, "Also for projects CLion models" (an application-level PersistentStateComponent, off by default). With it on both engines answer, and the plugin says so once per project in a balloon.
…s the verifier on every pull request and that test where it matters The test opens a real directory project with the IntelliJ Platform test framework and starts the mcppls found first on the PATH (CI puts the payload it built there). On an mcpp package it asserts the server Running within a minute, the diagnostic for a wrong import, the module name `import hel` completes, and the process gone once the project closes. On a CMake project it asserts no server by default and, with the setting on, a server and one notice. What CLion's own engine answers for the same files is printed, not asserted, and a separate check confirms the optional workspace probe registers inside CLion. ci.yml gains clion-verify (verifyPlugin, every pull request) and clion-e2e (the test, when the change touches editors/clion, src/lsp, src/orchestrator or tools/devtools, on release branches, and on every run that is not a pull request, which covers the nightly and the release's CI). The CLion downloads are cached by version. The release checks' install test names CLion2026.2. The CLion README and docs/10-editors.md (and the Chinese mirror) drop 'not exercised in a running CLion' and describe the one-engine default, the switch and the supported versions.
…te run follows the user's own xmake f X-1 and X-2 of the 0.0.8 part 2 plan. When the workspace is trusted, mcppls.buildTool is not off and xmake is on PATH, the private xmake run is the only source: a compile_commands.json the user generated follows their last xmake project, not their xmake.lua, and two sources taking turns restart clangd (E1, the late set_languages that never reached the model). The file is read only when xmake cannot run, or when a first private run fails and none ever succeeded (a half-typed xmake.lua must not replace an xmake model with an older file's); it is watched then, and a notice says once that it is older than an xmake.lua or the user's xmake.conf, with the one command that updates it. A failure that needs a download stays a download offer. The project's .xmake/<plat>/<arch>/xmake.conf (the newest) is read as text, only top-level strings and true/false, never executed, and the private xmake f is given plat, arch, mode and the rest of what the user chose, minus xmake's own keys (E5: xmake f resets what it is not given, so a debug project was described as release). An option xmake refuses (exit 255, Invalid option) is retried once with the standard ones only and a notice names what was left out. The configuration key includes the conf's size and time, and **/xmake.lua and the conf are watched. Unit tests cover the parser on a recorded xmake.conf, the arguments, exclusions and the retry allowlist, the key and the staleness decision.
…reported, and the provisional model stops saying the workspace is untrusted X-5: a reload that finds compdb-invalid or database-invalid while a file it reads (the failing model's or the last model's watched json, or the file the error names) was written in the last two seconds is repeated a second later, up to five times, with no warning and no stale issue; the last model stays meanwhile, and a journal event model-reread records each try. After that, or once the file is two seconds old, it is reported as before. X-6: the provisional model loaded from scanned sources is untrusted only so that no program runs; it drops the untrusted-workspace issue, and the trust state is reported by the orchestrator alone.
…checks they need, run in the Linux job with xmake from xlings X-7 of the 0.0.8 part 2 plan: xmake-basic, xmake-late-config (a stale root compile_commands.json, then set_languages in xmake.lua: the engine follows within 15 s, nothing reported, the project directory unchanged), xmake-user-mode (.xmake/linux/x86_64/xmake.conf with mode=debug and a project option), xmake-no-standard (passes once X-3 lands) and compdb-midwrite (a truncated database completed 300 ms later, and by a 2.5 s writer). New runner checks: engine-command (the command clangd was given, from the engine database), status-never (no status named an issue), write-midway (a database cut and completed); prepare kinds xmake-stale-compdb and compdb-midwrite. max-matches and min-matches now count when equals is beside them, as the README says. CI pins xmake in .github/versions.env and installs it with GCC 16 from xlings for the jobs that run an xmake fixture.
…and follows xmake.lua and the user's xmake f, and compile_commands.json is read only when xmake cannot run
…s C++23, and a database being written is read again for longer X-3, second revision (decided 2026-10-01): mcppls supports `import std` by default, so a module unit -- one that imports, provides or belongs to a module, std's own unit included -- whose build names no standard is read as C++23 (gnu++23; c++23 for an MSVC target), whatever the compiler's default: Clang's gnu++17 has no modules at all. A standard any module unit names is followed instead; plan.standardAssumed says when mcppls chose. GCC's own default is given only to plain and C units now. xmake-no-standard is the reporter's project again: main.cpp alone imports std (with a module file xmake itself adds -std=c++20, which is followed), and std::println, which C++20 lacks, is found. X-5: a database written in the last 10 s (was 2 s) is read again: on a loaded machine the load itself came more than 2 s after a writer that took 2.5 s. The runner's write-midway waited for quiet between its two writes, and a server reading the file every second kept it from ever being quiet; it waits a fixed time now.
…th why they are scripts
… the include-cleaner fixture allows fewer reports C-2: a completion clangd keeps working on after mcppls answered it is detached (Engine::detach): nobody waits for it, so when its time runs out it is cancelled quietly -- no request-timeout, no "did not answer", no reason to set its file aside, and it no longer counts as the oldest unanswered request when clangd is judged stuck. I-1: clangd with the Windows kit reports none of the unused headers the fixture has; diagnostic-code-lines takes "subset", and the interface and plain files may be reported on fewer lines, never on others. The importer, the implementation unit and the member access still must have none.
…thing for minutes is restarted K-7 (plan 0.0.8 part 2). A file clangd has queued is waiting for a worker (K-5) and is not set aside for it -- but a clangd that keeps its workers busy without finishing anything never frees one: after U16's module autosave on ux-xlings it kept four cores busy for more than fifteen minutes with every open file "queued", no diagnostics, no answers, and the stuck watch, which looks for next to no CPU, did not see it; only a restart that happened to come ended it. A file queued for four minutes while clangd finished nothing for three (no diagnostics for any file, no answer, no prepared module, no background unit) now restarts clangd as a recovery, with an incident carrying its log.
…te completions, prepared units, busy-without-progress, xmake, C++23 for unstated module standards, CLion and Zed
…or five seconds Found in review. The late answer's key was the word's line and the text before it, so a word typed back (`std::ve` answered, then a backspace to `std::v`) got the list clangd had narrowed to `ve`, and a return to the same word minutes later got a list from before the file changed -- served without asking clangd, and never cleared. The key now carries what of the word was typed: an answer or a pending request serves a request only when the word has been typed on from it, a late answer is kept five seconds, and a word typed back cancels the pending request as another word does. K-7 is said once per clangd, not at every recheck while a restart is backed off. The conformance README describes xmake-no-standard as it now is.
CI run 36773996351 counted the notices one event turn after the server was running and found none: the notice goes out through the message bus, a few turns later. The test now waits for it, then gives a second one three seconds to show before asserting there is exactly one.
…asking it for --version, which it does not take
…tage uploads the server's logs CI run 36773996351 showed ux-xlings stuck after U16 for half an hour, as run 36750398125 of part 1 did, and K-7 never restarted clangd: a background unit set aside every two minutes was closed, clangd cleared its diagnostics, and that publish counted as progress; so would an error for a cancelled request. Progress is now diagnostics for a file the editor has open (not one set aside or excluded), an answer with a result, a prepared module or a built background unit. The ux job uploads the server's logs and incidents when a stage fails.
…the ux-xlings stall predates it
…re the VFS lists it CI run 36782178214: the first files of a project just opened reached fileOpened before the VFS had the root's children, so a CMake project looked unmodelled -- by default mcppls would start where CLion's own engine answers, and with the switch on nobody was told that both engines do. The root is looked at on disk as well.
…is not building restarts clangd
K-8 (plan 0.0.8 part 2). The incident K-7 wrote on CI run 36782178214 named the ux-xlings stall: three
threads "TWorker:log.cpp", each at a full core with 250-330 s of CPU -- all three workers, on log.cpp, the
importer of the module U16 rewrites, which containment closes in clangd at each autosave while its build
runs. A build clangd let go of and never stopped has nobody to answer; every open file stayed queued, and
neither the stuck watch (next to no CPU) nor the spin watch (a file clangd reports building) could see it.
clangd's worker threads are now sampled every 15 s (Linux: per-thread CPU); one at a full core for a minute
on a file clangd is not building restarts clangd, once, with an incident. worker_file reads the file from
the thread's name as Linux truncates it ("TWorker:log.cpp", "rker:doctor.cpp").
…id it was building that file meanwhile, after half a minute A worker on the file being typed is busy for minutes at a stretch, and the moment K-8 decided could fall between two rebuilds, when clangd says the file is idle. An orphan is now a thread at a full core for 30 s (sampled every 10 s) on a file clangd has not reported building at any time since -- every file's reports count, prime and background units' too -- so a real build is never taken for one, and the recovery comes within the scenario that caused it. CI run 36787135201: ux-xlings no longer stalls after U16 (U7a, U8-config and U15-edits pass), and the U16 restarts were K-8's, on the importers containment closes (log.cpp, prebuilt.cppm). U16 in both ux fixtures now allows the one recovery restart and the few requests it cuts short; its completion budgets stay. The Zed smoke waits for a debug line in any of the server's logs.
…es, changelog, design record and plan
…was building, and the Zed smoke no longer names a removed variable CI run 36792920474 restarted clangd in ux-xlings' warm stage for "eWorker:cli.cpp": cli.cpp's preamble, a long module closure, built for 31 s, and clangd says so once, at the start -- before the thread counted as busy, so "reported building since" missed it. A worker is now an orphan only if clangd's last word on its file is not "building" and it said nothing of the kind since the worker got busy; a file mcppls closes in clangd loses its last word, so a build left spinning after a close is still caught. The Zed smoke printed a variable an earlier change removed and stopped there under `set -u`; both settings pass on Zed 1.22.0 here.
…a's republish budget comes from measurements The switch-on CLion test waited for the balloon on the project's message bus, which headless CLion did not always deliver within 30 s (CI runs 36782178214, 36797333606) though the plugin had decided to tell; it now waits for that decision, once per project, and holds the balloons to at most one. U7a's budget for the importers' diagnostics was 20 s; over six CI runs of part 2 ux-mcpp measured 6.9-25.2 s (part 1: 31 s), so it is 1.3 times the 95th percentile, 33 s, the rule `measure budgets` gives, in both ux fixtures.
…overy restart comes With K-8's recovery restart in xlings' U16, clangd answered 0.20-0.31 of the completions (CI runs of part 2); the budget is 0.15, the lowest over 1.3. Completion p95, the importer's p95 and no empty completion keep their budgets; ux-mcpp's U16, which needs no restart, keeps 0.4.
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.
mcpp-language-server 0.0.8: completion that shows up, writing modules with autosave, and what 0.0.7 left (#34).
Plan, evidence and implementation record:
.agents/docs/2026-09-30-0.0.8-plan.md.Completion that shows up (E-1..E-4)
A user reported "no keyword, parameter or variable completion" in VS Code 1.132. Their own diagnostic bundles showed the server was simply not asked: 24 completion requests in 18 minutes of editing, none in the 66 s they reproduced it, while Copilot made 15 inline requests in the same minute. The server answered the 24 in 21 ms at the median.
The cause is a VS Code default. From a release between 1.108 and 1.125,
editor.quickSuggestions.otherdefaults tooffWhenInlineCompletions. With an inline-completion provider installed (Copilot is built in), a keystroke waits for the inline completion, and the list is not opened while grey text shows. Otherwise it opens only after 750 ms with the document and cursor unchanged.{other: "on"}as the[cpp]and[c]language default, so the list and the grey text show side by side. Measured on 1.132: other languages keep the editor's default, and a person's[cpp]value wins.client.editor), and the server's side of it (requests[*].lastAt,documents).Writing modules with autosave (M-1..M-4)
A module saved mid-edit does not compile. Containment (RP1.1) then took the module's own file from clangd, together with its importers, until the next save handed it back. Reproduced: in 92 s of writing a module it was doomed 18 times, and 48% of the completions in it were empty.
module-edit-autosaveand ux scenario U16.module-failedon it)What 0.0.7 left (#34)
... Fixturepartial-scan-standins.std, so the project's modules are no longer built twice. Fixtureprovisional-no-prime.mcppls-devtools measure budgetsand nightly'sux-budgetsjob give each scenario's distribution, for setting budgets from measurements.Part 2: large projects, xmake, CLion and Zed
Plan and record:
.agents/docs/2026-10-01-0.0.8-part2-plan.md. It draws on the reporter's bundles (GalTranslPP on Windows, an xmake project) and on experiments with clangd 23.1.xmake.luaand your ownxmake fare followed; nothing is written into the project.compile_commands.jsonis read only when xmake cannot run.xmake fplatform, architecture, mode, toolchain and options.import stdby default).std.cc.importcompletion and shutdown.cargo testfor the extension; a real Zed under xvfb, with the recommended settings and with Zed's defaults.Verification
cargo test) pass. The CLion tests run in a headless CLion 2026.2.3.budget-whyin the fixture):