## Summary ### Preamble completeness check - `is_preamble_complete()` in `scan.cpp`: checks whether `#include`/`import`/`export module` directives in the preamble region are syntactically complete (have closing `>`/`"`/`;`) - `ensure_pch` defers PCH rebuild when preamble is incomplete (user still typing), reuses old PCH instead of failing ### #include / import completion - Master intercepts completion requests in `#include "..."` / `#include <...>` / `import ...` contexts before forwarding to worker - `complete_include()`: searches include paths (from compile args via `SearchConfig`) using `DirListingCache`, supports quoted/angled/multi-level paths - `complete_import()`: filters `path_to_module` map by prefix - Word boundary checks prevent false matches (e.g. `important` not treated as `import`) ### Detached compile task (rapid-edit fix) - Compile operations (`ensure_deps` + `send_stateful` + `publish_diagnostics`) run as detached tasks via `loop.schedule()`, independent of the LSP request coroutine chain - LSP `$/cancelRequest` can no longer kill in-flight compilations — previously, cancellation would destroy the `ensure_compiled` coroutine frame, leaving `doc.compiling` permanently set and hanging all subsequent requests - `CompileGuard` RAII ensures `doc.compiling` is always cleaned up even if the detached task fails - Stale feature requests (where `ast_dirty` became true after compile finished) are dropped before forwarding to worker ### Other fixes - `signal(SIGPIPE, SIG_IGN)` on POSIX: prevents server crash when LSP client disconnects mid-write - `CompilationUnitRef::file_path()` / `deps()`: null-check `FileEntryRef` to prevent segfault on invalid FileID - `stateless_worker.cpp`: log BuildPCH diagnostic errors for debuggability - Default worker counts changed to 2 stateful + 3 stateless - `logging_dir` default changed to `.clice/logs` in config ### Tests - 19 unit tests for `is_preamble_complete` (incomplete `#include`, `import`, `export module`, mixed cases) - Integration tests: `test_include_completion.py` (5 tests), `test_import_completion.py` (4 tests), `test_rapid_edit.py` (2 tests), `test_pch.py` (4 new tests) - Smoke test: `rapid_edit.jsonl` — recorded VSCode session with 40 rapid edits + 61 cancel requests ## Test plan - [x] Unit tests: 463 passed - [x] Integration tests: 104 passed - [x] Smoke test (rapid_edit.jsonl): PASS - [x] Manual VSCode testing with `#include <iostream>` project 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
251 lines
251 KiB
JSON
Generated
251 lines
251 KiB
JSON
Generated
{"ts":8,"msg":"{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":\"initialize\",\"params\":{\"processId\":1707078,\"clientInfo\":{\"name\":\"Visual Studio Code\",\"version\":\"1.114.0\"},\"locale\":\"en\",\"rootPath\":\"/home/ykiko/C++/clice/tests/data/hello_world\",\"rootUri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world\",\"capabilities\":{\"workspace\":{\"applyEdit\":true,\"workspaceEdit\":{\"documentChanges\":true,\"resourceOperations\":[\"create\",\"rename\",\"delete\"],\"failureHandling\":\"textOnlyTransactional\",\"normalizesLineEndings\":true,\"changeAnnotationSupport\":{\"groupsOnLabel\":true}},\"configuration\":true,\"didChangeWatchedFiles\":{\"dynamicRegistration\":true,\"relativePatternSupport\":true},\"symbol\":{\"dynamicRegistration\":true,\"symbolKind\":{\"valueSet\":[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]},\"tagSupport\":{\"valueSet\":[1]},\"resolveSupport\":{\"properties\":[\"location.range\"]}},\"codeLens\":{\"refreshSupport\":true},\"executeCommand\":{\"dynamicRegistration\":true},\"didChangeConfiguration\":{\"dynamicRegistration\":true},\"workspaceFolders\":true,\"foldingRange\":{\"refreshSupport\":true},\"semanticTokens\":{\"refreshSupport\":true},\"fileOperations\":{\"dynamicRegistration\":true,\"didCreate\":true,\"didRename\":true,\"didDelete\":true,\"willCreate\":true,\"willRename\":true,\"willDelete\":true},\"inlineValue\":{\"refreshSupport\":true},\"inlayHint\":{\"refreshSupport\":true},\"diagnostics\":{\"refreshSupport\":true}},\"textDocument\":{\"publishDiagnostics\":{\"relatedInformation\":true,\"versionSupport\":false,\"tagSupport\":{\"valueSet\":[1,2]},\"codeDescriptionSupport\":true,\"dataSupport\":true},\"synchronization\":{\"dynamicRegistration\":true,\"willSave\":true,\"willSaveWaitUntil\":true,\"didSave\":true},\"completion\":{\"dynamicRegistration\":true,\"contextSupport\":true,\"completionItem\":{\"snippetSupport\":true,\"commitCharactersSupport\":true,\"documentationFormat\":[\"markdown\",\"plaintext\"],\"deprecatedSupport\":true,\"preselectSupport\":true,\"tagSupport\":{\"valueSet\":[1]},\"insertReplaceSupport\":true,\"resolveSupport\":{\"properties\":[\"documentation\",\"detail\",\"additionalTextEdits\"]},\"insertTextModeSupport\":{\"valueSet\":[1,2]},\"labelDetailsSupport\":true},\"insertTextMode\":2,\"completionItemKind\":{\"valueSet\":[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]},\"completionList\":{\"itemDefaults\":[\"commitCharacters\",\"editRange\",\"insertTextFormat\",\"insertTextMode\",\"data\"]}},\"hover\":{\"dynamicRegistration\":true,\"contentFormat\":[\"markdown\",\"plaintext\"]},\"signatureHelp\":{\"dynamicRegistration\":true,\"signatureInformation\":{\"documentationFormat\":[\"markdown\",\"plaintext\"],\"parameterInformation\":{\"labelOffsetSupport\":true},\"activeParameterSupport\":true},\"contextSupport\":true},\"definition\":{\"dynamicRegistration\":true,\"linkSupport\":true},\"references\":{\"dynamicRegistration\":true},\"documentHighlight\":{\"dynamicRegistration\":true},\"documentSymbol\":{\"dynamicRegistration\":true,\"symbolKind\":{\"valueSet\":[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]},\"hierarchicalDocumentSymbolSupport\":true,\"tagSupport\":{\"valueSet\":[1]},\"labelSupport\":true},\"codeAction\":{\"dynamicRegistration\":true,\"isPreferredSupport\":true,\"disabledSupport\":true,\"dataSupport\":true,\"resolveSupport\":{\"properties\":[\"edit\"]},\"codeActionLiteralSupport\":{\"codeActionKind\":{\"valueSet\":[\"\",\"quickfix\",\"refactor\",\"refactor.extract\",\"refactor.inline\",\"refactor.rewrite\",\"source\",\"source.organizeImports\"]}},\"honorsChangeAnnotations\":true},\"codeLens\":{\"dynamicRegistration\":true},\"formatting\":{\"dynamicRegistration\":true},\"rangeFormatting\":{\"dynamicRegistration\":true,\"rangesSupport\":true},\"onTypeFormatting\":{\"dynamicRegistration\":true},\"rename\":{\"dynamicRegistration\":true,\"prepareSupport\":true,\"prepareSupportDefaultBehavior\":1,\"honorsChangeAnnotations\":true},\"documentLink\":{\"dynamicRegistration\":true,\"tooltipSupport\":true},\"typeDefinition\":{\"dynamicRegistration\":true,\"linkSupport\":true},\"implementation\":{\"dynamicRegistration\":true,\"linkSupport\":true},\"colorProvider\":{\"dynamicRegistration\":true},\"foldingRange\":{\"dynamicRegistration\":true,\"rangeLimit\":5000,\"lineFoldingOnly\":true,\"foldingRangeKind\":{\"valueSet\":[\"comment\",\"imports\",\"region\"]},\"foldingRange\":{\"collapsedText\":false}},\"declaration\":{\"dynamicRegistration\":true,\"linkSupport\":true},\"selectionRange\":{\"dynamicRegistration\":true},\"callHierarchy\":{\"dynamicRegistration\":true},\"semanticTokens\":{\"dynamicRegistration\":true,\"tokenTypes\":[\"namespace\",\"type\",\"class\",\"enum\",\"interface\",\"struct\",\"typeParameter\",\"parameter\",\"variable\",\"property\",\"enumMember\",\"event\",\"function\",\"method\",\"macro\",\"keyword\",\"modifier\",\"comment\",\"string\",\"number\",\"regexp\",\"operator\",\"decorator\"],\"tokenModifiers\":[\"declaration\",\"definition\",\"readonly\",\"static\",\"deprecated\",\"abstract\",\"async\",\"modification\",\"documentation\",\"defaultLibrary\"],\"formats\":[\"relative\"],\"requests\":{\"range\":true,\"full\":{\"delta\":true}},\"multilineTokenSupport\":false,\"overlappingTokenSupport\":false,\"serverCancelSupport\":true,\"augmentsSyntaxTokens\":true},\"linkedEditingRange\":{\"dynamicRegistration\":true},\"typeHierarchy\":{\"dynamicRegistration\":true},\"inlineValue\":{\"dynamicRegistration\":true},\"inlayHint\":{\"dynamicRegistration\":true,\"resolveSupport\":{\"properties\":[\"tooltip\",\"textEdits\",\"label.tooltip\",\"label.location\",\"label.command\"]}},\"diagnostic\":{\"dynamicRegistration\":true,\"relatedDocumentSupport\":false}},\"window\":{\"showMessage\":{\"messageActionItem\":{\"additionalPropertiesSupport\":true}},\"showDocument\":{\"support\":true},\"workDoneProgress\":true},\"general\":{\"staleRequestSupport\":{\"cancel\":true,\"retryOnContentModified\":[\"textDocument/semanticTokens/full\",\"textDocument/semanticTokens/range\",\"textDocument/semanticTokens/full/delta\"]},\"regularExpressions\":{\"engine\":\"ECMAScript\",\"version\":\"ES2020\"},\"markdown\":{\"parser\":\"marked\",\"version\":\"1.1.0\"},\"positionEncodings\":[\"utf-16\"]},\"notebookDocument\":{\"synchronization\":{\"dynamicRegistration\":true,\"executionSummarySupport\":true}}},\"trace\":\"off\",\"workspaceFolders\":[{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world\",\"name\":\"hello_world\"}]}}"}
|
||
{"ts":82,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"initialized\",\"params\":{}}"}
|
||
{"ts":87,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didOpen\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"languageId\":\"cpp\",\"version\":1,\"text\":\"#include <iostream>\\n\\nint add(int a, int b) {\\n return a + b;\\n}\\n\\nint main() {\\n std::cout << \\\"hello world\\\" << std::endl;\\n\\n int result = add(1, 2);\\n return result;\\n}\\n\"}}}"}
|
||
{"ts":144,"msg":"{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":144,"msg":"{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":9,\"character\":27},\"end\":{\"line\":9,\"character\":27}},\"context\":{\"diagnostics\":[],\"triggerKind\":2}}}"}
|
||
{"ts":144,"msg":"{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"textDocument/documentLink\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":144,"msg":"{\"jsonrpc\":\"2.0\",\"id\":4,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":12,\"character\":0}}}}"}
|
||
{"ts":226,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":4}}"}
|
||
{"ts":226,"msg":"{\"jsonrpc\":\"2.0\",\"id\":5,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":12,\"character\":0}}}}"}
|
||
{"ts":342,"msg":"{\"jsonrpc\":\"2.0\",\"id\":6,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":12,\"character\":0}}}}"}
|
||
{"ts":405,"msg":"{\"jsonrpc\":\"2.0\",\"id\":7,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":406,"msg":"{\"jsonrpc\":\"2.0\",\"id\":8,\"method\":\"textDocument/foldingRange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":438,"msg":"{\"jsonrpc\":\"2.0\",\"id\":9,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":9,\"character\":15}}}"}
|
||
{"ts":578,"msg":"{\"jsonrpc\":\"2.0\",\"id\":10,\"method\":\"textDocument/semanticTokens/full\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":842,"msg":"{\"jsonrpc\":\"2.0\",\"id\":11,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":9,\"character\":19}}}"}
|
||
{"ts":1478,"msg":"{\"jsonrpc\":\"2.0\",\"id\":12,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":9,\"character\":19}}}"}
|
||
{"ts":2350,"msg":"{\"jsonrpc\":\"2.0\",\"id\":13,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":9,\"character\":25}}}"}
|
||
{"ts":2639,"msg":"{\"jsonrpc\":\"2.0\",\"id\":14,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":9,\"character\":12}}}"}
|
||
{"ts":3694,"msg":"{\"jsonrpc\":\"2.0\",\"id\":15,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":10,\"character\":18},\"end\":{\"line\":10,\"character\":18}},\"context\":{\"diagnostics\":[],\"triggerKind\":2}}}"}
|
||
{"ts":4741,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didOpen\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/src/compile/compilation_unit.cpp\",\"languageId\":\"cpp\",\"version\":1,\"text\":\"#include \\\"compile/implement.h\\\"\\n#include \\\"index/usr.h\\\"\\n#include \\\"semantic/ast_utility.h\\\"\\n\\nnamespace clice {\\n\\nCompilationKind CompilationUnitRef::kind() {\\n return self->kind;\\n}\\n\\nCompilationStatus CompilationUnitRef::status() {\\n return self->status;\\n}\\n\\nauto CompilationUnitRef::file_id(clang::FileEntryRef entry) -> clang::FileID {\\n return self->SM().translateFile(entry);\\n}\\n\\nauto CompilationUnitRef::file_id(llvm::StringRef file) -> clang::FileID {\\n auto entry = self->SM().getFileManager().getFileRef(file);\\n if(entry) {\\n return file_id(*entry);\\n }\\n\\n return clang::FileID();\\n}\\n\\nauto CompilationUnitRef::decompose_location(clang::SourceLocation location)\\n -> std::pair<clang::FileID, std::uint32_t> {\\n assert(location.isFileID() && \\\"Decompose macro location is meaningless!\\\");\\n return self->SM().getDecomposedLoc(location);\\n}\\n\\nauto CompilationUnitRef::decompose_range(clang::SourceRange range)\\n -> std::pair<clang::FileID, LocalSourceRange> {\\n auto [begin, end] = range;\\n assert(begin.isValid() && end.isValid() && \\\"Invalid source range\\\");\\n assert(begin.isFileID() && end.isValid() && \\\"Input source range should be a file range\\\");\\n\\n if(begin == end) {\\n auto [fid, offset] = decompose_location(begin);\\n return {\\n fid,\\n {offset, offset + token_length(end)}\\n };\\n } else {\\n auto [begin_fid, begin_offset] = decompose_location(begin);\\n auto [end_fid, end_offset] = decompose_location(end);\\n\\n if(begin_fid == end_fid) {\\n end_offset += token_length(end);\\n } else {\\n auto content = file_content(begin_fid);\\n end_offset = content.size();\\n }\\n\\n return {\\n begin_fid,\\n {begin_offset, end_offset}\\n };\\n }\\n}\\n\\nauto CompilationUnitRef::decompose_expansion_range(clang::SourceRange range)\\n -> std::pair<clang::FileID, LocalSourceRange> {\\n auto [begin, end] = range;\\n if(begin == end) {\\n return decompose_range(expansion_location(begin));\\n } else {\\n return decompose_range(\\n clang::SourceRange(expansion_location(begin), expansion_location(end)));\\n }\\n}\\n\\nauto CompilationUnitRef::file_id(clang::SourceLocation location) -> clang::FileID {\\n return self->SM().getFileID(location);\\n}\\n\\nauto CompilationUnitRef::file_offset(clang::SourceLocation location) -> std::uint32_t {\\n return self->SM().getFileOffset(location);\\n}\\n\\nauto CompilationUnitRef::file_path(clang::FileID fid) -> llvm::StringRef {\\n assert(fid.isValid() && \\\"Invalid fid\\\");\\n if(auto it = self->path_cache.find(fid); it != self->path_cache.end()) {\\n return it->second;\\n }\\n\\n auto entry = self->SM().getFileEntryRefForID(fid);\\n if(!entry) {\\n return {};\\n }\\n\\n llvm::SmallString<128> path;\\n\\n /// Try to get the real path of the file.\\n auto name = entry->getName();\\n if(auto error = llvm::sys::fs::real_path(name, path)) {\\n /// If failed, use the virtual path.\\n path = name;\\n }\\n assert(!path.empty() && \\\"Invalid file path\\\");\\n\\n /// Allocate the path in the storage.\\n auto size = path.size();\\n auto data = self->path_storage.Allocate<char>(size + 1);\\n memcpy(data, path.data(), size);\\n data[size] = '\\\\0';\\n\\n auto [it, inserted] = self->path_cache.try_emplace(fid, llvm::StringRef(data, size));\\n assert(inserted && \\\"File path already exists\\\");\\n return it->second;\\n}\\n\\nauto CompilationUnitRef::file_content(clang::FileID fid) -> llvm::StringRef {\\n return self->SM().getBufferData(fid);\\n}\\n\\nauto CompilationUnitRef::interested_file() -> clang::FileID {\\n return self->SM().getMainFileID();\\n}\\n\\nauto CompilationUnitRef::interested_content() -> llvm::StringRef {\\n return file_content(interested_file());\\n}\\n\\nbool CompilationUnitRef::is_builtin_file(clang::FileID fid) {\\n // No FileEntryRef => built-in/command line/scratch.\\n if(!self->SM().getFileEntryRefForID(fid)) {\\n if(auto buffer = self->SM().getBufferOrNone(fid)) {\\n auto name = buffer->getBufferIdentifier();\\n return name == \\\"<built-in>\\\" || name == \\\"<command line>\\\" || name == \\\"<scratch space>\\\";\\n }\\n }\\n\\n return false;\\n}\\n\\nauto CompilationUnitRef::start_location(clang::FileID fid) -> clang::SourceLocation {\\n return self->SM().getLocForStartOfFile(fid);\\n}\\n\\nauto CompilationUnitRef::end_location(clang::FileID fid) -> clang::SourceLocation {\\n return self->SM().getLocForEndOfFile(fid);\\n}\\n\\nauto CompilationUnitRef::spelling_location(clang::SourceLocation loc) -> clang::SourceLocation {\\n return self->SM().getSpellingLoc(loc);\\n}\\n\\nauto CompilationUnitRef::expansion_location(clang::SourceLocation location)\\n -> clang::SourceLocation {\\n return self->SM().getExpansionLoc(location);\\n}\\n\\nauto CompilationUnitRef::file_location(clang::SourceLocation location) -> clang::SourceLocation {\\n return self->SM().getFileLoc(location);\\n}\\n\\nauto CompilationUnitRef::include_location(clang::FileID fid) -> clang::SourceLocation {\\n return self->SM().getIncludeLoc(fid);\\n}\\n\\nauto CompilationUnitRef::presumed_location(clang::SourceLocation location) -> clang::PresumedLoc {\\n return self->SM().getPresumedLoc(location, false);\\n}\\n\\nauto CompilationUnitRef::create_location(clang::FileID fid, std::uint32_t offset)\\n -> clang::SourceLocation {\\n return self->SM().getComposedLoc(fid, offset);\\n}\\n\\nauto CompilationUnitRef::spelled_tokens(clang::FileID fid) -> TokenRange {\\n return self->buffer->spelledTokens(fid);\\n}\\n\\nauto CompilationUnitRef::spelled_tokens(clang::SourceRange range) -> TokenRange {\\n auto tokens = self->buffer->spelledForExpanded(self->buffer->expandedTokens(range));\\n if(!tokens) {\\n return {};\\n }\\n\\n return *tokens;\\n}\\n\\nauto CompilationUnitRef::spelled_tokens_touch(clang::SourceLocation location) -> TokenRange {\\n return clang::syntax::spelledTokensTouching(location, *self->buffer);\\n}\\n\\nauto CompilationUnitRef::expanded_tokens() -> TokenRange {\\n return self->buffer->expandedTokens();\\n}\\n\\nauto CompilationUnitRef::expanded_tokens(clang::SourceRange range) -> TokenRange {\\n return self->buffer->expandedTokens(range);\\n}\\n\\nauto CompilationUnitRef::expansions_overlapping(TokenRange spelled_tokens)\\n -> std::vector<clang::syntax::TokenBuffer::Expansion> {\\n return self->buffer->expansionsOverlapping(spelled_tokens);\\n}\\n\\nauto CompilationUnitRef::token_length(clang::SourceLocation location) -> std::uint32_t {\\n return clang::Lexer::MeasureTokenLength(location, self->SM(), self->instance->getLangOpts());\\n}\\n\\nauto CompilationUnitRef::token_spelling(clang::SourceLocation location) -> llvm::StringRef {\\n return llvm::StringRef(self->SM().getCharacterData(location), token_length(location));\\n}\\n\\nauto CompilationUnitRef::module_name() -> llvm::StringRef {\\n return self->instance->getPreprocessor().getNamedModuleName();\\n}\\n\\nbool CompilationUnitRef::is_module_interface_unit() {\\n return self->instance->getPreprocessor().isInNamedInterfaceUnit();\\n}\\n\\nauto CompilationUnitRef::diagnostics() -> std::vector<Diagnostic>& {\\n return self->diagnostics;\\n}\\n\\nauto CompilationUnitRef::top_level_decls() -> llvm::ArrayRef<clang::Decl*> {\\n return self->top_level_decls;\\n}\\n\\nstd::chrono::milliseconds CompilationUnitRef::build_at() {\\n return self->build_at;\\n}\\n\\nstd::chrono::milliseconds CompilationUnitRef::build_duration() {\\n return self->build_duration;\\n}\\n\\nclang::LangOptions& CompilationUnitRef::lang_options() {\\n return self->instance->getLangOpts();\\n}\\n\\nstd::vector<std::string> CompilationUnitRef::deps() {\\n llvm::StringSet<> deps;\\n\\n /// FIXME: consider `#embed` and `__has_embed`.\\n\\n for(auto& [fid, directive]: directives()) {\\n for(auto& include: directive.includes) {\\n if(!include.skipped) {\\n auto path = file_path(include.fid);\\n if(!path.empty()) {\\n deps.try_emplace(path);\\n }\\n }\\n }\\n\\n for(auto& has_include: directive.has_includes) {\\n if(has_include.fid.isValid()) {\\n auto path = file_path(has_include.fid);\\n if(!path.empty()) {\\n deps.try_emplace(path);\\n }\\n }\\n }\\n }\\n\\n std::vector<std::string> result;\\n\\n for(auto& deps: deps) {\\n result.emplace_back(deps.getKey().str());\\n }\\n\\n return result;\\n}\\n\\nindex::SymbolID CompilationUnitRef::getSymbolID(const clang::NamedDecl* decl) {\\n uint64_t hash;\\n auto iter = self->symbol_hash_cache.find(decl);\\n if(iter != self->symbol_hash_cache.end()) {\\n hash = iter->second;\\n } else {\\n llvm::SmallString<128> usr;\\n index::generateUSRForDecl(decl, usr);\\n hash = llvm::xxh3_64bits(usr);\\n self->symbol_hash_cache.try_emplace(decl, hash);\\n }\\n return index::SymbolID{hash, ast::name_of(decl)};\\n}\\n\\nindex::SymbolID CompilationUnitRef::getSymbolID(const clang::MacroInfo* macro) {\\n std::uint64_t hash;\\n auto name = token_spelling(macro->getDefinitionLoc());\\n auto iter = self->symbol_hash_cache.find(macro);\\n if(iter != self->symbol_hash_cache.end()) {\\n hash = iter->second;\\n } else {\\n llvm::SmallString<128> usr;\\n index::generateUSRForMacro(name, macro->getDefinitionLoc(), self->SM(), usr);\\n hash = llvm::xxh3_64bits(usr);\\n self->symbol_hash_cache.try_emplace(macro, hash);\\n }\\n return index::SymbolID{hash, name.str()};\\n}\\n\\nconst llvm::DenseSet<clang::FileID>& CompilationUnitRef::files() {\\n if(self->all_files.empty()) {\\n /// FIXME: handle preamble and embed file id.\\n for(auto& [fid, directive]: directives()) {\\n for(auto& include: directive.includes) {\\n if(!include.skipped && include.fid.isValid()) {\\n self->all_files.insert(include.fid);\\n }\\n }\\n }\\n self->all_files.insert(self->SM().getMainFileID());\\n }\\n return self->all_files;\\n}\\n\\nclang::TranslationUnitDecl* CompilationUnitRef::tu() {\\n return self->instance->getASTContext().getTranslationUnitDecl();\\n}\\n\\nllvm::DenseMap<clang::FileID, Directive>& CompilationUnitRef::directives() {\\n return self->directives;\\n}\\n\\nTemplateResolver& CompilationUnitRef::resolver() {\\n assert(self->resolver && \\\"Template resolver is not available\\\");\\n return *self->resolver;\\n}\\n\\nclang::ASTContext& CompilationUnitRef::context() {\\n return self->instance->getASTContext();\\n}\\n\\nclang::syntax::TokenBuffer& CompilationUnitRef::token_buffer() {\\n return *self->buffer;\\n}\\n\\nCompilationUnit::~CompilationUnit() {\\n delete self;\\n}\\n\\n} // namespace clice\\n\"}}}"}
|
||
{"ts":4741,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didOpen\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/src/server/config.cpp\",\"languageId\":\"cpp\",\"version\":1,\"text\":\"#include \\\"server/config.h\\\"\\n\\n#include <algorithm>\\n#include <thread>\\n\\n#include \\\"eventide/serde/toml.h\\\"\\n#include \\\"support/filesystem.h\\\"\\n#include \\\"support/logging.h\\\"\\n\\nnamespace clice {\\n\\n/// Replace all occurrences of ${workspace} with the workspace root.\\nstatic void substitute_workspace(std::string& value, const std::string& workspace_root) {\\n constexpr std::string_view placeholder = \\\"${workspace}\\\";\\n std::string::size_type pos = 0;\\n while((pos = value.find(placeholder, pos)) != std::string::npos) {\\n value.replace(pos, placeholder.size(), workspace_root);\\n pos += workspace_root.size();\\n }\\n}\\n\\nvoid CliceConfig::apply_defaults(const std::string& workspace_root) {\\n auto cpu_count = std::thread::hardware_concurrency();\\n if(cpu_count == 0)\\n cpu_count = 4;\\n\\n if(stateful_worker_count == 0) {\\n stateful_worker_count = 2;\\n }\\n if(stateless_worker_count == 0) {\\n stateless_worker_count = 3;\\n }\\n if(worker_memory_limit == 0) {\\n worker_memory_limit = 4ULL * 1024 * 1024 * 1024; // 4GB default\\n }\\n if(cache_dir.empty() && !workspace_root.empty()) {\\n cache_dir = path::join(workspace_root, \\\".clice\\\");\\n }\\n\\n if(index_dir.empty() && !cache_dir.empty()) {\\n index_dir = path::join(cache_dir, \\\"index\\\");\\n }\\n\\n if(logging_dir.empty() && !cache_dir.empty()) {\\n logging_dir = path::join(cache_dir, \\\"logs\\\");\\n }\\n\\n // Apply variable substitution to string fields\\n substitute_workspace(compile_commands_path, workspace_root);\\n substitute_workspace(cache_dir, workspace_root);\\n substitute_workspace(index_dir, workspace_root);\\n substitute_workspace(logging_dir, workspace_root);\\n}\\n\\nstd::optional<CliceConfig> CliceConfig::load(const std::string& path,\\n const std::string& workspace_root) {\\n auto content = fs::read(path);\\n if(!content) {\\n return std::nullopt;\\n }\\n\\n auto result = eventide::serde::toml::parse<CliceConfig>(*content);\\n if(!result) {\\n LOG_WARN(\\\"Failed to parse config file {}\\\", path);\\n return std::nullopt;\\n }\\n\\n auto config = std::move(*result);\\n config.apply_defaults(workspace_root);\\n\\n LOG_INFO(\\\"Loaded config from {}\\\", path);\\n return config;\\n}\\n\\nCliceConfig CliceConfig::load_from_workspace(const std::string& workspace_root) {\\n if(!workspace_root.empty()) {\\n // Try standard config file locations\\n for(auto* name: {\\\"clice.toml\\\", \\\".clice/config.toml\\\"}) {\\n auto config_path = path::join(workspace_root, name);\\n if(llvm::sys::fs::exists(config_path)) {\\n auto config = load(config_path, workspace_root);\\n if(config)\\n return std::move(*config);\\n }\\n }\\n }\\n\\n // No config file found; use defaults\\n CliceConfig config;\\n config.apply_defaults(workspace_root);\\n LOG_INFO(\\n \\\"No clice.toml found, using default configuration \\\" \\\"(stateful={}, stateless={}, memory_limit={}MB)\\\",\\n config.stateful_worker_count,\\n config.stateless_worker_count,\\n config.worker_memory_limit / (1024 * 1024));\\n return config;\\n}\\n\\n} // namespace clice\\n\"}}}"}
|
||
{"ts":4744,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didOpen\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/src/server/master_server.cpp\",\"languageId\":\"cpp\",\"version\":1,\"text\":\"#include \\\"server/master_server.h\\\"\\n\\n#include <algorithm>\\n#include <chrono>\\n#include <format>\\n#include <optional>\\n#include <string>\\n#include <type_traits>\\n#include <variant>\\n#include <vector>\\n\\n#include \\\"command/search_config.h\\\"\\n#include \\\"eventide/ipc/json_codec.h\\\"\\n#include \\\"eventide/ipc/lsp/position.h\\\"\\n#include \\\"eventide/ipc/lsp/uri.h\\\"\\n#include \\\"eventide/reflection/enum.h\\\"\\n#include \\\"eventide/serde/json/json.h\\\"\\n#include \\\"eventide/serde/serde/raw_value.h\\\"\\n#include \\\"index/tu_index.h\\\"\\n#include \\\"semantic/symbol_kind.h\\\"\\n#include \\\"server/protocol.h\\\"\\n#include \\\"support/filesystem.h\\\"\\n#include \\\"support/logging.h\\\"\\n#include \\\"syntax/dependency_graph.h\\\"\\n#include \\\"syntax/include_resolver.h\\\"\\n#include \\\"syntax/scan.h\\\"\\n\\n#include \\\"llvm/Support/Chrono.h\\\"\\n#include \\\"llvm/Support/FileSystem.h\\\"\\n#include \\\"llvm/Support/Path.h\\\"\\n#include \\\"llvm/Support/Process.h\\\"\\n#include \\\"llvm/Support/raw_ostream.h\\\"\\n#include \\\"llvm/Support/xxhash.h\\\"\\n\\nnamespace clice {\\n\\nnamespace protocol = eventide::ipc::protocol;\\nnamespace lsp = eventide::ipc::lsp;\\nnamespace refl = eventide::refl;\\nusing et::ipc::RequestResult;\\nusing RequestContext = et::ipc::JsonPeer::RequestContext;\\n\\n/// Hash a file's content using xxh3_64bits. Returns 0 on read failure.\\nstatic std::uint64_t hash_file(llvm::StringRef path) {\\n auto buf = llvm::MemoryBuffer::getFile(path);\\n if(!buf)\\n return 0;\\n return llvm::xxh3_64bits((*buf)->getBuffer());\\n}\\n\\n/// Capture a two-layer staleness snapshot after a successful compilation.\\n/// Interns dependency paths into the PathPool and hashes each file's content.\\nstatic DepsSnapshot capture_deps_snapshot(PathPool& pool, llvm::ArrayRef<std::string> deps) {\\n DepsSnapshot snap;\\n // Capture timestamp BEFORE hashing to avoid TOCTOU: if a file is modified\\n // during hashing, its mtime will be > build_at, triggering Layer 2 re-hash.\\n snap.build_at = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());\\n snap.path_ids.reserve(deps.size());\\n snap.hashes.reserve(deps.size());\\n for(const auto& file: deps) {\\n snap.path_ids.push_back(pool.intern(file));\\n snap.hashes.push_back(hash_file(file));\\n }\\n return snap;\\n}\\n\\n/// Two-layer staleness check.\\n///\\n/// Layer 1 (fast): stat each dep file, compare mtime against build_at.\\n/// If all mtimes <= build_at → nothing changed, return false immediately.\\n///\\n/// Layer 2 (precise): for files with mtime > build_at, re-hash their content.\\n/// If the hash matches the stored hash → file was touched but not modified.\\n/// If any hash differs → truly changed, return true.\\nstatic bool deps_changed(const PathPool& pool, const DepsSnapshot& snap) {\\n for(std::size_t i = 0; i < snap.path_ids.size(); ++i) {\\n auto path = pool.resolve(snap.path_ids[i]);\\n llvm::sys::fs::file_status status;\\n if(auto ec = llvm::sys::fs::status(path, status)) {\\n // File disappeared — definitely changed.\\n if(snap.hashes[i] != 0)\\n return true;\\n continue;\\n }\\n\\n // Layer 1: mtime check (cheap, stat only).\\n auto current_mtime = llvm::sys::toTimeT(status.getLastModificationTime());\\n if(current_mtime <= snap.build_at)\\n continue;\\n\\n // Layer 2: mtime is newer — re-hash content to confirm actual change.\\n auto current_hash = hash_file(path);\\n if(current_hash != snap.hashes[i])\\n return true;\\n }\\n return false;\\n}\\n\\nMasterServer::MasterServer(et::event_loop& loop, et::ipc::JsonPeer& peer, std::string self_path) :\\n loop(loop), peer(peer), pool(loop), self_path(std::move(self_path)) {}\\n\\nMasterServer::~MasterServer() {\\n if(compile_graph) {\\n compile_graph->cancel_all();\\n }\\n}\\n\\nstd::string MasterServer::uri_to_path(const std::string& uri) {\\n auto parsed = lsp::URI::parse(uri);\\n if(parsed.has_value()) {\\n auto path = parsed->file_path();\\n if(path.has_value()) {\\n return std::move(*path);\\n }\\n }\\n return uri;\\n}\\n\\nvoid MasterServer::publish_diagnostics(const std::string& uri,\\n int version,\\n const et::serde::RawValue& diagnostics_json) {\\n std::vector<protocol::Diagnostic> diagnostics;\\n if(!diagnostics_json.empty()) {\\n auto status = et::serde::json::from_json(diagnostics_json.data, diagnostics);\\n if(!status) {\\n LOG_WARN(\\\"Failed to deserialize diagnostics JSON for {}\\\", uri);\\n }\\n }\\n protocol::PublishDiagnosticsParams params;\\n params.uri = uri;\\n params.version = version;\\n params.diagnostics = std::move(diagnostics);\\n peer.send_notification(params);\\n}\\n\\nvoid MasterServer::clear_diagnostics(const std::string& uri) {\\n protocol::PublishDiagnosticsParams params;\\n params.uri = uri;\\n params.diagnostics = {};\\n peer.send_notification(params);\\n}\\n\\n/// Serializable cache structures for cache.json persistence.\\n/// Paths are stored in a shared table and referenced by index to avoid\\n/// redundant storage (a single file can depend on thousands of headers,\\n/// many of which are shared across entries).\\nnamespace {\\n\\nstruct CacheDepEntry {\\n std::uint32_t path; // index into CacheData::paths\\n std::uint64_t hash;\\n};\\n\\nstruct CachePCHEntry {\\n std::string filename;\\n std::uint32_t source_file; // index into CacheData::paths\\n std::uint64_t hash;\\n std::uint32_t bound;\\n std::int64_t build_at;\\n std::vector<CacheDepEntry> deps;\\n};\\n\\nstruct CachePCMEntry {\\n std::string filename;\\n std::uint32_t source_file; // index into CacheData::paths\\n std::string module_name;\\n std::int64_t build_at;\\n std::vector<CacheDepEntry> deps;\\n};\\n\\nstruct CacheData {\\n std::vector<std::string> paths;\\n std::vector<CachePCHEntry> pch;\\n std::vector<CachePCMEntry> pcm;\\n};\\n\\n} // namespace\\n\\nvoid MasterServer::load_cache() {\\n if(config.cache_dir.empty())\\n return;\\n\\n auto cache_path = path::join(config.cache_dir, \\\"cache\\\", \\\"cache.json\\\");\\n auto content = fs::read(cache_path);\\n if(!content) {\\n LOG_DEBUG(\\\"No cache.json found at {}\\\", cache_path);\\n return;\\n }\\n\\n CacheData data;\\n auto status = et::serde::json::from_json(*content, data);\\n if(!status) {\\n LOG_WARN(\\\"Failed to parse cache.json\\\");\\n return;\\n }\\n\\n auto resolve = [&](std::uint32_t idx) -> llvm::StringRef {\\n return idx < data.paths.size() ? llvm::StringRef(data.paths[idx]) : \\\"\\\";\\n };\\n\\n for(auto& entry: data.pch) {\\n auto pch_path = path::join(config.cache_dir, \\\"cache\\\", \\\"pch\\\", entry.filename);\\n auto source = resolve(entry.source_file);\\n if(!llvm::sys::fs::exists(pch_path) || source.empty())\\n continue;\\n\\n DepsSnapshot deps;\\n deps.build_at = entry.build_at;\\n for(auto& dep: entry.deps) {\\n auto dep_path = resolve(dep.path);\\n if(dep_path.empty())\\n continue;\\n deps.path_ids.push_back(path_pool.intern(dep_path));\\n deps.hashes.push_back(dep.hash);\\n }\\n\\n auto path_id = path_pool.intern(source);\\n auto& st = pch_states[path_id];\\n st.path = pch_path;\\n st.hash = entry.hash;\\n st.bound = entry.bound;\\n st.deps = std::move(deps);\\n\\n LOG_DEBUG(\\\"Loaded cached PCH: {} -> {}\\\", source, pch_path);\\n }\\n\\n for(auto& entry: data.pcm) {\\n auto pcm_path = path::join(config.cache_dir, \\\"cache\\\", \\\"pcm\\\", entry.filename);\\n auto source = resolve(entry.source_file);\\n if(!llvm::sys::fs::exists(pcm_path) || source.empty())\\n continue;\\n\\n DepsSnapshot deps;\\n deps.build_at = entry.build_at;\\n for(auto& dep: entry.deps) {\\n auto dep_path = resolve(dep.path);\\n if(dep_path.empty())\\n continue;\\n deps.path_ids.push_back(path_pool.intern(dep_path));\\n deps.hashes.push_back(dep.hash);\\n }\\n\\n auto path_id = path_pool.intern(source);\\n pcm_states[path_id] = {pcm_path, std::move(deps)};\\n pcm_paths[path_id] = pcm_path;\\n\\n LOG_DEBUG(\\\"Loaded cached PCM: {} (module {}) -> {}\\\", source, entry.module_name, pcm_path);\\n }\\n\\n LOG_INFO(\\\"Loaded cache.json: {} PCH entries, {} PCM entries\\\",\\n pch_states.size(),\\n pcm_states.size());\\n}\\n\\nvoid MasterServer::save_cache() {\\n if(config.cache_dir.empty())\\n return;\\n\\n CacheData data;\\n std::unordered_map<std::string, std::uint32_t> index_map;\\n\\n auto intern = [&](std::uint32_t runtime_path_id) -> std::uint32_t {\\n auto path = std::string(path_pool.resolve(runtime_path_id));\\n auto [it, inserted] =\\n index_map.try_emplace(path, static_cast<std::uint32_t>(data.paths.size()));\\n if(inserted) {\\n data.paths.push_back(path);\\n }\\n return it->second;\\n };\\n\\n for(auto& [path_id, st]: pch_states) {\\n if(st.path.empty())\\n continue;\\n\\n CachePCHEntry entry;\\n entry.filename = std::string(path::filename(st.path));\\n entry.source_file = intern(path_id);\\n entry.hash = st.hash;\\n entry.bound = st.bound;\\n entry.build_at = st.deps.build_at;\\n for(std::size_t i = 0; i < st.deps.path_ids.size(); ++i) {\\n entry.deps.push_back({intern(st.deps.path_ids[i]), st.deps.hashes[i]});\\n }\\n data.pch.push_back(std::move(entry));\\n }\\n\\n for(auto& [path_id, st]: pcm_states) {\\n if(st.path.empty())\\n continue;\\n\\n CachePCMEntry entry;\\n entry.filename = std::string(path::filename(st.path));\\n entry.source_file = intern(path_id);\\n auto mod_it = path_to_module.find(path_id);\\n entry.module_name = mod_it != path_to_module.end() ? mod_it->second : \\\"\\\";\\n entry.build_at = st.deps.build_at;\\n for(std::size_t i = 0; i < st.deps.path_ids.size(); ++i) {\\n entry.deps.push_back({intern(st.deps.path_ids[i]), st.deps.hashes[i]});\\n }\\n data.pcm.push_back(std::move(entry));\\n }\\n\\n auto json_str = et::serde::json::to_json(data);\\n if(!json_str) {\\n LOG_WARN(\\\"Failed to serialize cache.json\\\");\\n return;\\n }\\n\\n auto cache_path = path::join(config.cache_dir, \\\"cache\\\", \\\"cache.json\\\");\\n auto tmp_path = cache_path + \\\".tmp\\\";\\n auto write_result = fs::write(tmp_path, *json_str);\\n if(!write_result) {\\n LOG_WARN(\\\"Failed to write cache.json.tmp: {}\\\", write_result.error().message());\\n return;\\n }\\n auto rename_result = fs::rename(tmp_path, cache_path);\\n if(!rename_result) {\\n LOG_WARN(\\\"Failed to rename cache.json.tmp to cache.json: {}\\\",\\n rename_result.error().message());\\n }\\n}\\n\\nvoid MasterServer::cleanup_cache(int max_age_days) {\\n if(config.cache_dir.empty())\\n return;\\n\\n auto now = std::chrono::system_clock::now();\\n auto max_age = std::chrono::hours(max_age_days * 24);\\n\\n for(auto* subdir: {\\\"cache/pch\\\", \\\"cache/pcm\\\"}) {\\n auto dir = path::join(config.cache_dir, subdir);\\n std::error_code ec;\\n for(auto it = llvm::sys::fs::directory_iterator(dir, ec);\\n !ec && it != llvm::sys::fs::directory_iterator();\\n it.increment(ec)) {\\n llvm::sys::fs::file_status status;\\n if(auto stat_ec = llvm::sys::fs::status(it->path(), status))\\n continue;\\n\\n auto mtime = status.getLastModificationTime();\\n auto age = now - mtime;\\n if(age > max_age) {\\n llvm::sys::fs::remove(it->path());\\n LOG_DEBUG(\\\"Cleaned up stale cache file: {}\\\", it->path());\\n }\\n }\\n }\\n}\\n\\net::task<> MasterServer::load_workspace() {\\n if(workspace_root.empty())\\n co_return;\\n\\n // Create cache directory if configured\\n if(!config.cache_dir.empty()) {\\n auto ec = llvm::sys::fs::create_directories(config.cache_dir);\\n if(ec) {\\n LOG_WARN(\\\"Failed to create cache directory {}: {}\\\", config.cache_dir, ec.message());\\n } else {\\n LOG_INFO(\\\"Cache directory: {}\\\", config.cache_dir);\\n }\\n\\n // Create cache/pch/ and cache/pcm/ subdirectories\\n for(auto* subdir: {\\\"cache/pch\\\", \\\"cache/pcm\\\"}) {\\n auto dir = path::join(config.cache_dir, subdir);\\n auto ec2 = llvm::sys::fs::create_directories(dir);\\n if(ec2) {\\n LOG_WARN(\\\"Failed to create {}: {}\\\", dir, ec2.message());\\n }\\n }\\n\\n // Clean up stale files first, then load — load_cache() only restores\\n // entries still listed in cache.json, so cleanup won't delete live files.\\n cleanup_cache();\\n load_cache();\\n }\\n\\n // Search for compile_commands.json\\n std::string cdb_path;\\n\\n // If the config specifies a CDB path, use it\\n if(!config.compile_commands_path.empty()) {\\n if(llvm::sys::fs::exists(config.compile_commands_path)) {\\n cdb_path = config.compile_commands_path;\\n } else {\\n LOG_WARN(\\\"Configured compile_commands_path not found: {}\\\",\\n config.compile_commands_path);\\n }\\n }\\n\\n // Otherwise auto-detect in common locations\\n if(cdb_path.empty()) {\\n for(auto* subdir: {\\\"build\\\", \\\"cmake-build-debug\\\", \\\"cmake-build-release\\\", \\\"out\\\", \\\".\\\"}) {\\n auto candidate = path::join(workspace_root, subdir, \\\"compile_commands.json\\\");\\n if(llvm::sys::fs::exists(candidate)) {\\n cdb_path = std::move(candidate);\\n break;\\n }\\n }\\n }\\n\\n if(cdb_path.empty()) {\\n LOG_WARN(\\\"No compile_commands.json found in workspace {}\\\", workspace_root);\\n co_return;\\n }\\n\\n auto count = cdb.load(cdb_path);\\n LOG_INFO(\\\"Loaded CDB from {} with {} entries\\\", cdb_path, count);\\n\\n auto report = scan_dependency_graph(cdb, path_pool, dependency_graph);\\n\\n auto unresolved = report.includes_found - report.includes_resolved;\\n double accuracy =\\n report.includes_found > 0\\n ? 100.0 * static_cast<double>(report.includes_resolved) / report.includes_found\\n : 100.0;\\n LOG_INFO(\\n \\\"Dependency scan: {}ms, {} files ({} source + {} header), \\\" \\\"{} edges, {}/{} resolved ({:.1f}%), {} waves\\\",\\n report.elapsed_ms,\\n report.total_files,\\n report.source_files,\\n report.header_files,\\n report.total_edges,\\n report.includes_resolved,\\n report.includes_found,\\n accuracy,\\n report.waves);\\n if(unresolved > 0) {\\n LOG_WARN(\\\"{} unresolved includes\\\", unresolved);\\n }\\n\\n // Build reverse mapping: path_id -> module name.\\n for(auto& [module_name, path_ids]: dependency_graph.modules()) {\\n for(auto path_id: path_ids) {\\n path_to_module[path_id] = module_name.str();\\n }\\n }\\n\\n // Load persisted index from disk.\\n load_index();\\n\\n // Build index queue from CDB entries (all source files).\\n // CDB entries use the CDB's internal path_ids; convert to server path_ids.\\n if(config.enable_indexing) {\\n for(auto& entry: cdb.get_entries()) {\\n auto file = cdb.resolve_path(entry.file);\\n auto server_id = path_pool.intern(file);\\n index_queue.push_back(server_id);\\n }\\n if(!index_queue.empty()) {\\n LOG_INFO(\\\"Queued {} files for background indexing\\\", index_queue.size());\\n for(auto sid: index_queue) {\\n LOG_INFO(\\\" queue entry: server_path_id={} path='{}'\\\", sid, path_pool.resolve(sid));\\n }\\n schedule_indexing();\\n }\\n }\\n\\n if(path_to_module.empty()) {\\n LOG_INFO(\\\"No C++20 modules detected, skipping CompileGraph\\\");\\n co_return;\\n }\\n\\n // Lazy dependency resolver: scans a module file on demand to discover imports.\\n auto resolve = [this](std::uint32_t path_id) -> llvm::SmallVector<std::uint32_t> {\\n auto file_path = path_pool.resolve(path_id);\\n auto results = cdb.lookup(file_path, {.query_toolchain = true, .suppress_logging = true});\\n if(results.empty()) {\\n return {};\\n }\\n\\n auto& ctx = results[0];\\n auto scan_result = scan_precise(ctx.arguments, ctx.directory);\\n\\n llvm::SmallVector<std::uint32_t> deps;\\n for(auto& mod_name: scan_result.modules) {\\n auto mod_ids = dependency_graph.lookup_module(mod_name);\\n if(!mod_ids.empty()) {\\n deps.push_back(mod_ids[0]);\\n }\\n }\\n\\n // Module implementation units implicitly depend on their interface unit.\\n if(!scan_result.module_name.empty() && !scan_result.is_interface_unit) {\\n auto mod_ids = dependency_graph.lookup_module(scan_result.module_name);\\n if(!mod_ids.empty()) {\\n deps.push_back(mod_ids[0]);\\n }\\n }\\n\\n return deps;\\n };\\n\\n // Dispatch: sends BuildPCM request to a stateless worker.\\n auto dispatch = [this](std::uint32_t path_id) -> et::task<bool> {\\n auto mod_it = path_to_module.find(path_id);\\n if(mod_it == path_to_module.end()) {\\n co_return false;\\n }\\n\\n auto file_path = std::string(path_pool.resolve(path_id));\\n\\n worker::BuildPCMParams pcm_params;\\n pcm_params.file = file_path;\\n if(!fill_compile_args(file_path, pcm_params.directory, pcm_params.arguments)) {\\n co_return false;\\n }\\n\\n // Compute deterministic content-addressed PCM path.\\n // Replace ':' with '-' in module name for filesystem safety.\\n // Hash includes file path AND compile arguments so that argument\\n // changes (e.g. -DFOO) invalidate the cached PCM.\\n auto safe_module_name = mod_it->second;\\n std::ranges::replace(safe_module_name, ':', '-');\\n std::string hash_input = file_path;\\n for(auto& arg: pcm_params.arguments) {\\n hash_input += arg;\\n }\\n auto args_hash = llvm::xxh3_64bits(llvm::StringRef(hash_input));\\n auto pcm_filename = std::format(\\\"{}-{:016x}.pcm\\\", safe_module_name, args_hash);\\n auto pcm_path = path::join(config.cache_dir, \\\"cache\\\", \\\"pcm\\\", pcm_filename);\\n\\n // Check if cached PCM is still valid.\\n if(auto pcm_it = pcm_states.find(path_id); pcm_it != pcm_states.end()) {\\n if(!pcm_it->second.path.empty() && llvm::sys::fs::exists(pcm_it->second.path) &&\\n !deps_changed(path_pool, pcm_it->second.deps)) {\\n pcm_paths[path_id] = pcm_it->second.path;\\n co_return true;\\n }\\n }\\n\\n pcm_params.module_name = mod_it->second;\\n pcm_params.output_path = pcm_path;\\n\\n // Clang needs ALL transitive PCM deps, not just direct imports.\\n for(auto& [pid, existing_pcm_path]: pcm_paths) {\\n auto dep_mod_it = path_to_module.find(pid);\\n if(dep_mod_it != path_to_module.end()) {\\n pcm_params.pcms[dep_mod_it->second] = existing_pcm_path;\\n }\\n }\\n\\n auto result = co_await pool.send_stateless(pcm_params);\\n if(!result.has_value() || !result.value().success) {\\n LOG_WARN(\\\"BuildPCM failed for module {}: {}\\\",\\n mod_it->second,\\n result.has_value() ? result.value().error : result.error().message);\\n co_return false;\\n }\\n\\n pcm_paths[path_id] = result.value().pcm_path;\\n pcm_states[path_id] = {result.value().pcm_path,\\n capture_deps_snapshot(path_pool, result.value().deps)};\\n LOG_INFO(\\\"Built PCM for module {}: {}\\\", mod_it->second, result.value().pcm_path);\\n\\n // Persist cache metadata after successful build.\\n save_cache();\\n\\n co_return true;\\n };\\n\\n compile_graph = std::make_unique<CompileGraph>(std::move(dispatch), std::move(resolve));\\n LOG_INFO(\\\"CompileGraph initialized with {} module(s)\\\", path_to_module.size());\\n}\\n\\nbool MasterServer::fill_compile_args(llvm::StringRef path,\\n std::string& directory,\\n std::vector<std::string>& arguments) {\\n auto results = cdb.lookup(path, {.query_toolchain = true});\\n if(results.empty()) {\\n LOG_WARN(\\\"No CDB entry for {}\\\", path);\\n return false;\\n }\\n auto& ctx = results.front();\\n directory = ctx.directory.str();\\n arguments.clear();\\n for(auto* arg: ctx.arguments) {\\n arguments.emplace_back(arg);\\n }\\n return true;\\n}\\n\\net::task<bool> MasterServer::ensure_pch(std::uint32_t path_id,\\n llvm::StringRef path,\\n const std::string& text,\\n const std::string& directory,\\n const std::vector<std::string>& arguments) {\\n auto bound = compute_preamble_bound(text);\\n if(bound == 0) {\\n // No preamble directives — PCH would be empty. Clear any stale entry.\\n pch_states.erase(path_id);\\n co_return true;\\n }\\n\\n auto preamble_hash = llvm::xxh3_64bits(llvm::StringRef(text).substr(0, bound));\\n\\n // Deterministic content-addressed PCH path.\\n auto pch_path =\\n path::join(config.cache_dir, \\\"cache\\\", \\\"pch\\\", std::format(\\\"{:016x}.pch\\\", preamble_hash));\\n\\n // Reuse existing PCH if preamble content and deps haven't changed.\\n if(auto it = pch_states.find(path_id); it != pch_states.end()) {\\n auto& st = it->second;\\n if(st.hash == preamble_hash && !st.path.empty() && !deps_changed(path_pool, st.deps)) {\\n st.bound = bound;\\n co_return true;\\n }\\n }\\n\\n // Preamble incomplete (user still typing) — defer rebuild, reuse old PCH if available.\\n if(!is_preamble_complete(text, bound)) {\\n LOG_DEBUG(\\\"Preamble incomplete for {}, deferring PCH rebuild\\\", path);\\n co_return pch_states.count(path_id) && !pch_states[path_id].path.empty();\\n }\\n\\n // If another coroutine is already building PCH for this file, wait for it.\\n if(auto it = pch_states.find(path_id); it != pch_states.end() && it->second.building) {\\n co_await it->second.building->wait();\\n co_return !pch_states[path_id].path.empty();\\n }\\n\\n // Register in-flight build so concurrent requests wait on us.\\n auto completion = std::make_shared<et::event>();\\n pch_states[path_id].building = completion;\\n\\n // Build a new PCH via stateless worker.\\n worker::BuildPCHParams pch_params;\\n pch_params.file = std::string(path);\\n pch_params.directory = directory;\\n pch_params.arguments = arguments;\\n pch_params.content = text;\\n pch_params.preamble_bound = bound;\\n pch_params.output_path = pch_path;\\n\\n LOG_DEBUG(\\\"Building PCH for {}, bound={}, output={}\\\", path, bound, pch_path);\\n\\n auto result = co_await pool.send_stateless(pch_params);\\n\\n if(!result.has_value() || !result.value().success) {\\n LOG_WARN(\\\"PCH build failed for {}: {}\\\",\\n path,\\n result.has_value() ? result.value().error : result.error().message);\\n pch_states[path_id].building.reset();\\n completion->set();\\n co_return false;\\n }\\n\\n // Update state — no need to delete old file; content-addressed names differ\\n // when content differs, and the 7-day cleanup handles orphaned files.\\n auto& st = pch_states[path_id];\\n st.path = result.value().pch_path;\\n st.bound = bound;\\n st.hash = preamble_hash;\\n st.deps = capture_deps_snapshot(path_pool, result.value().deps);\\n st.building.reset();\\n\\n LOG_INFO(\\\"PCH built for {}: {}\\\", path, result.value().pch_path);\\n\\n // Persist cache metadata after successful build.\\n save_cache();\\n\\n completion->set();\\n co_return true;\\n}\\n\\n/// Compile module dependencies, build/reuse PCH, and fill PCM paths.\\n/// Shared preparation step used by both ensure_compiled() (stateful path)\\n/// and forward_stateless() (completion/signatureHelp path).\\net::task<bool> MasterServer::ensure_deps(std::uint32_t path_id,\\n llvm::StringRef path,\\n const std::string& text,\\n const std::string& directory,\\n const std::vector<std::string>& arguments,\\n std::pair<std::string, uint32_t>& pch,\\n std::unordered_map<std::string, std::string>& pcms) {\\n // Compile C++20 module dependencies (PCMs).\\n if(compile_graph && !co_await compile_graph->compile_deps(path_id)) {\\n co_return false;\\n }\\n\\n // Scan buffer text for module imports that might not be in compile_graph yet.\\n // When a user adds `import std;` without saving, the compile_graph (disk-based)\\n // doesn't know about the new dependency. Scan the in-memory text to find them.\\n {\\n auto scan_result = scan(text);\\n for(auto& mod_name: scan_result.modules) {\\n if(mod_name.empty()) {\\n continue;\\n }\\n bool found = false;\\n for(auto& [pid, name]: path_to_module) {\\n if(name == mod_name) {\\n // If PCM not already built, try to build it.\\n if(pcm_paths.find(pid) == pcm_paths.end()) {\\n if(compile_graph && compile_graph->has_unit(pid)) {\\n co_await compile_graph->compile_deps(pid);\\n }\\n }\\n found = true;\\n break;\\n }\\n }\\n if(!found) {\\n LOG_DEBUG(\\\"Buffer imports unknown module '{}', skipping\\\", mod_name);\\n }\\n }\\n }\\n\\n // Build or reuse PCH.\\n auto pch_ok = co_await ensure_pch(path_id, path, text, directory, arguments);\\n if(pch_ok) {\\n if(auto pch_it = pch_states.find(path_id); pch_it != pch_states.end()) {\\n pch = {pch_it->second.path, pch_it->second.bound};\\n }\\n }\\n\\n // Fill all available PCM paths so clang can resolve transitive imports.\\n // Exclude the file's own PCM to avoid \\\"multiple module declarations\\\".\\n for(auto& [pid, pcm_path]: pcm_paths) {\\n if(pid == path_id)\\n continue;\\n auto mod_it = path_to_module.find(pid);\\n if(mod_it != path_to_module.end()) {\\n pcms[mod_it->second] = pcm_path;\\n }\\n }\\n\\n co_return true;\\n}\\n\\n/// Pull-based compilation entry point for user-opened files.\\n///\\n/// Called lazily by forward_stateful() / forward_stateless() before every\\n/// feature request (hover, semantic tokens, etc.). Guarantees that when it\\n/// returns true the stateful worker assigned to `path_id` holds an up-to-date\\n/// AST and diagnostics have been published to the client.\\n///\\n/// Lifecycle overview (pull-based model):\\n///\\n/// didOpen / didChange – only update DocumentState, mark ast_dirty\\n/// didSave – mark dependents dirty, queue indexing\\n/// feature request arrives – calls ensure_compiled() first\\n/// 1. Fast-path exit if AST is already clean (!ast_dirty).\\n/// 2. Compile any C++20 module dependencies (PCMs) via CompileGraph.\\n/// 3. Build / reuse the precompiled header (PCH) via ensure_pch().\\n/// 4. Send CompileParams to the stateful worker, which builds the AST.\\n/// 5. On success: publish diagnostics, clear ast_dirty, schedule indexing.\\n/// 6. On generation mismatch (user edited during compile): keep dirty,\\n/// the next feature request will trigger another compile cycle.\\n///\\n/// Only the opened file itself is remapped (its in-memory text is sent to the\\n/// worker); every other file is read from disk by the compiler.\\n///\\n/// Concurrency: multiple concurrent feature requests for the same file will\\n/// each call ensure_compiled(). The first one triggers the actual compilation;\\n/// subsequent ones observe ast_dirty == false after the first completes and\\n/// take the fast path. This is safe because forward_stateful serialises\\n/// requests per worker slot.\\net::task<bool> MasterServer::ensure_compiled(std::uint32_t path_id) {\\n auto it = documents.find(path_id);\\n if(it == documents.end()) {\\n LOG_DEBUG(\\\"ensure_compiled: doc not found for path_id={}\\\", path_id);\\n co_return false;\\n }\\n\\n auto& doc = it->second;\\n LOG_DEBUG(\\\"ensure_compiled: path_id={} version={} gen={} ast_dirty={}\\\",\\n path_id,\\n doc.version,\\n doc.generation,\\n doc.ast_dirty);\\n\\n if(!doc.ast_dirty) {\\n bool changed = false;\\n auto ast_deps_it = ast_deps.find(path_id);\\n if(ast_deps_it != ast_deps.end() && deps_changed(path_pool, ast_deps_it->second)) {\\n changed = true;\\n }\\n if(!changed) {\\n auto pch_it = pch_states.find(path_id);\\n if(pch_it != pch_states.end() && deps_changed(path_pool, pch_it->second.deps)) {\\n changed = true;\\n }\\n }\\n if(!changed) {\\n LOG_INFO(\\\"ensure_compiled: fast path, ast clean path_id={}\\\", path_id);\\n co_return true;\\n }\\n LOG_INFO(\\\"ensure_compiled: deps changed, marking dirty path_id={}\\\", path_id);\\n doc.ast_dirty = true;\\n }\\n LOG_INFO(\\\"ensure_compiled: ast_dirty=true, compiling={} path_id={}\\\",\\n (bool)doc.compiling,\\n path_id);\\n\\n // After co_await suspension points the iterator may be invalidated (the\\n // documents map could have been modified by didClose on another file).\\n auto recheck = [&]() -> bool {\\n it = documents.find(path_id);\\n return it != documents.end();\\n };\\n\\n // If another ensure_compiled() is already in flight for this file,\\n // wait for it to finish instead of sending a duplicate compile request.\\n // Loop because multiple waiters wake up simultaneously — only the first\\n // one should start a new compile; the rest must wait again.\\n while(it->second.compiling) {\\n LOG_INFO(\\\"ensure_compiled: waiting on in-flight compile for path_id={}\\\", path_id);\\n co_await it->second.compiling->wait();\\n LOG_INFO(\\\"ensure_compiled: in-flight compile done for path_id={}\\\", path_id);\\n if(!recheck())\\n co_return false;\\n if(!it->second.ast_dirty) {\\n LOG_INFO(\\\"ensure_compiled: ast clean after wait, path_id={}\\\", path_id);\\n co_return true;\\n }\\n // ast still dirty — loop back to check if someone else already\\n // started a new compile; only fall through if no one has.\\n }\\n\\n // Snapshot the generation counter *before* any co_await. After compilation\\n // we compare it with the current value to detect edits that arrived while\\n // we were suspended — if they differ, the result is stale and we must not\\n // mark the AST as clean.\\n auto gen = doc.generation;\\n\\n // Register in-flight compile so concurrent callers wait on us.\\n auto completion = std::make_shared<et::event>();\\n doc.compiling = completion;\\n LOG_INFO(\\\"ensure_compiled: starting compile path_id={} gen={}\\\", path_id, gen);\\n\\n // Signal waiters and clear compiling flag on any return path.\\n auto finish_compile = [&]() {\\n LOG_INFO(\\\"ensure_compiled: finish_compile path_id={} gen={}\\\", path_id, gen);\\n if(auto doc_it = documents.find(path_id); doc_it != documents.end()) {\\n doc_it->second.compiling.reset();\\n }\\n completion->set();\\n };\\n\\n auto file_path = std::string(path_pool.resolve(path_id));\\n auto uri = lsp::URI::from_file_path(file_path);\\n std::string uri_str = uri.has_value() ? uri->str() : file_path;\\n\\n // ── Phase 1–3: Module deps, PCH, PCM paths ─────────────────────────\\n worker::CompileParams params;\\n params.path = file_path;\\n if(!recheck()) {\\n finish_compile();\\n co_return false;\\n }\\n params.version = it->second.version;\\n params.text = it->second.text;\\n if(!fill_compile_args(path_pool.resolve(path_id), params.directory, params.arguments)) {\\n finish_compile();\\n co_return false;\\n }\\n\\n LOG_INFO(\\\"ensure_compiled: ensure_deps start path_id={} gen={}\\\", path_id, gen);\\n if(!co_await ensure_deps(path_id,\\n params.path,\\n params.text,\\n params.directory,\\n params.arguments,\\n params.pch,\\n params.pcms)) {\\n LOG_WARN(\\\"Dependency preparation failed for {}, skipping compile\\\", uri_str);\\n finish_compile();\\n co_return false;\\n }\\n\\n if(!recheck()) {\\n finish_compile();\\n co_return false;\\n }\\n\\n // ── Phase 4: Dispatch to stateful worker ────────────────────────────\\n //\\n // The stateful worker receives the full document text and compile args,\\n // builds the AST, and caches it for subsequent feature requests. The\\n // response carries diagnostics collected during compilation.\\n LOG_INFO(\\\"ensure_compiled: ensure_deps done, sending compile path_id={} gen={}\\\", path_id, gen);\\n auto result = co_await pool.send_stateful(path_id, params);\\n LOG_INFO(\\\"ensure_compiled: compile response received path_id={} gen={}\\\", path_id, gen);\\n\\n // Re-lookup: the document may have been closed while we were compiling.\\n it = documents.find(path_id);\\n if(it == documents.end()) {\\n finish_compile();\\n co_return false;\\n }\\n\\n auto& doc2 = it->second;\\n\\n // ── Phase 5: Handle result ──────────────────────────────────────────\\n //\\n // Generation mismatch means the user edited the file while we compiled.\\n // The AST we just built corresponds to an older version of the text, so\\n // we discard the diagnostics and leave ast_dirty == true. The next\\n // feature request will trigger another compile cycle with the latest text.\\n if(doc2.generation != gen) {\\n LOG_INFO(\\\"ensure_compiled: generation mismatch ({} vs {}) for {}\\\",\\n doc2.generation,\\n gen,\\n uri_str);\\n finish_compile();\\n co_return false;\\n }\\n\\n if(!result.has_value()) {\\n LOG_WARN(\\\"Compile failed for {}: {}\\\", uri_str, result.error().message);\\n // Clear stale diagnostics so the editor doesn't show errors from a\\n // previous successful compilation that no longer apply.\\n clear_diagnostics(uri_str);\\n finish_compile();\\n co_return false;\\n }\\n\\n LOG_INFO(\\\"ensure_compiled: success path_id={} gen={}, publishing diagnostics\\\", path_id, gen);\\n doc2.ast_dirty = false;\\n ast_deps[path_id] = capture_deps_snapshot(path_pool, result.value().deps);\\n finish_compile();\\n\\n // Publish diagnostics AFTER marking compile as done, so that concurrent\\n // forward_stateful() calls can proceed immediately instead of waiting\\n // for the (potentially large) diagnostics to be written to the client pipe.\\n publish_diagnostics(uri_str, doc2.version, result.value().diagnostics);\\n schedule_indexing();\\n co_return true;\\n}\\n\\n// =========================================================================\\n// Index integration\\n// =========================================================================\\n\\nvoid MasterServer::merge_index_result(const void* tu_index_data, std::size_t size) {\\n auto tu_index = index::TUIndex::from(tu_index_data);\\n\\n // Merge symbols into ProjectIndex, get TU-local path_id -> global path_id mapping.\\n auto file_ids_map = project_index.merge(tu_index);\\n\\n auto main_tu_path_id = static_cast<std::uint32_t>(tu_index.graph.paths.size() - 1);\\n\\n // Merge a single file's index into the corresponding MergedIndex shard.\\n auto merge_file_index = [&](std::uint32_t tu_path_id, index::FileIndex& file_idx) {\\n auto global_path_id = file_ids_map[tu_path_id];\\n auto& merged = merged_indices[global_path_id];\\n\\n if(tu_path_id == main_tu_path_id) {\\n // Main file (source file) gets a compilation context with include locations.\\n // Collect ALL include locations with path_ids remapped to project-level ids.\\n std::vector<index::IncludeLocation> include_locs;\\n for(auto& loc: tu_index.graph.locations) {\\n index::IncludeLocation remapped = loc;\\n remapped.path_id = file_ids_map[loc.path_id];\\n include_locs.push_back(remapped);\\n }\\n // Read the file content from disk for position mapping in queries.\\n auto file_path = project_index.path_pool.path(global_path_id);\\n llvm::StringRef file_content;\\n std::string file_content_storage;\\n auto buf = llvm::MemoryBuffer::getFile(file_path);\\n if(buf) {\\n file_content_storage = (*buf)->getBuffer().str();\\n file_content = file_content_storage;\\n }\\n merged.merge(global_path_id,\\n tu_index.built_at,\\n std::move(include_locs),\\n file_idx,\\n file_content);\\n } else {\\n // Header files get a header context keyed by include location.\\n std::uint32_t include_id = 0;\\n for(std::uint32_t i = 0; i < tu_index.graph.locations.size(); ++i) {\\n if(tu_index.graph.locations[i].path_id == tu_path_id) {\\n include_id = i;\\n break;\\n }\\n }\\n // Read header file content for position mapping in queries.\\n auto header_path = project_index.path_pool.path(global_path_id);\\n llvm::StringRef header_content;\\n std::string header_content_storage;\\n auto header_buf = llvm::MemoryBuffer::getFile(header_path);\\n if(header_buf) {\\n header_content_storage = (*header_buf)->getBuffer().str();\\n header_content = header_content_storage;\\n }\\n merged.merge(global_path_id, include_id, file_idx, header_content);\\n }\\n };\\n\\n // Merge from path_file_indices (deserialized TUIndex from IPC).\\n for(auto& [tu_path_id, file_idx]: tu_index.path_file_indices) {\\n merge_file_index(tu_path_id, file_idx);\\n }\\n\\n // Merge main file index.\\n merge_file_index(main_tu_path_id, tu_index.main_file_index);\\n\\n LOG_INFO(\\\"Merged TUIndex: {} paths, {} symbols, {} merged_shards\\\",\\n tu_index.graph.paths.size(),\\n tu_index.symbols.size(),\\n merged_indices.size());\\n for(auto& [pid, _]: merged_indices) {\\n LOG_INFO(\\\" shard proj_path_id={} path='{}'\\\", pid, project_index.path_pool.path(pid));\\n }\\n}\\n\\nvoid MasterServer::save_index() {\\n if(config.index_dir.empty())\\n return;\\n\\n auto ec = llvm::sys::fs::create_directories(config.index_dir);\\n if(ec) {\\n LOG_WARN(\\\"Failed to create index directory {}: {}\\\", config.index_dir, ec.message());\\n return;\\n }\\n\\n // Save ProjectIndex.\\n auto project_path = path::join(config.index_dir, \\\"project.idx\\\");\\n {\\n std::error_code write_ec;\\n llvm::raw_fd_ostream os(project_path, write_ec);\\n if(!write_ec) {\\n project_index.serialize(os);\\n LOG_INFO(\\\"Saved ProjectIndex to {}\\\", project_path);\\n } else {\\n LOG_WARN(\\\"Failed to save ProjectIndex: {}\\\", write_ec.message());\\n }\\n }\\n\\n // Save MergedIndex shards.\\n auto shards_dir = path::join(config.index_dir, \\\"shards\\\");\\n ec = llvm::sys::fs::create_directories(shards_dir);\\n if(ec) {\\n LOG_WARN(\\\"Failed to create shards directory: {}\\\", ec.message());\\n return;\\n }\\n\\n std::size_t saved = 0;\\n for(auto& [path_id, merged]: merged_indices) {\\n if(!merged.need_rewrite())\\n continue;\\n auto shard_path = path::join(shards_dir, std::to_string(path_id) + \\\".idx\\\");\\n std::error_code write_ec;\\n llvm::raw_fd_ostream os(shard_path, write_ec);\\n if(!write_ec) {\\n merged.serialize(os);\\n ++saved;\\n }\\n }\\n LOG_INFO(\\\"Saved {} MergedIndex shards (of {} total)\\\", saved, merged_indices.size());\\n}\\n\\nvoid MasterServer::load_index() {\\n if(config.index_dir.empty())\\n return;\\n\\n // Load ProjectIndex.\\n auto project_path = path::join(config.index_dir, \\\"project.idx\\\");\\n auto buf = llvm::MemoryBuffer::getFile(project_path);\\n if(buf) {\\n project_index = index::ProjectIndex::from((*buf)->getBufferStart());\\n LOG_INFO(\\\"Loaded ProjectIndex: {} symbols\\\", project_index.symbols.size());\\n }\\n\\n // Load MergedIndex shards.\\n auto shards_dir = path::join(config.index_dir, \\\"shards\\\");\\n std::error_code ec;\\n for(auto it = llvm::sys::fs::directory_iterator(shards_dir, ec);\\n !ec && it != llvm::sys::fs::directory_iterator();\\n it.increment(ec)) {\\n auto filename = llvm::sys::path::filename(it->path());\\n if(!filename.ends_with(\\\".idx\\\"))\\n continue;\\n\\n auto stem = filename.drop_back(4); // remove \\\".idx\\\"\\n std::uint32_t path_id = 0;\\n if(stem.getAsInteger(10, path_id))\\n continue;\\n\\n merged_indices[path_id] = index::MergedIndex::load(it->path());\\n }\\n\\n if(!merged_indices.empty()) {\\n LOG_INFO(\\\"Loaded {} MergedIndex shards\\\", merged_indices.size());\\n }\\n}\\n\\nvoid MasterServer::schedule_indexing() {\\n LOG_INFO(\\n \\\"schedule_indexing called: enable={} active={} scheduled={} queue_size={} queue_pos={}\\\",\\n config.enable_indexing,\\n indexing_active,\\n indexing_scheduled,\\n index_queue.size(),\\n index_queue_pos);\\n if(!config.enable_indexing || indexing_active || indexing_scheduled)\\n return;\\n indexing_scheduled = true;\\n\\n // Create or reset idle timer.\\n if(!index_idle_timer) {\\n index_idle_timer = std::make_shared<et::timer>(et::timer::create(loop));\\n }\\n index_idle_timer->start(std::chrono::milliseconds(config.idle_timeout_ms));\\n loop.schedule(run_background_indexing());\\n}\\n\\net::task<> MasterServer::run_background_indexing() {\\n // Wait for idle timeout before starting.\\n if(index_idle_timer) {\\n co_await index_idle_timer->wait();\\n }\\n indexing_scheduled = false;\\n\\n if(index_queue_pos >= index_queue.size()) {\\n LOG_DEBUG(\\\"Background indexing: queue exhausted\\\");\\n co_return;\\n }\\n\\n indexing_active = true;\\n std::size_t processed = 0;\\n\\n while(index_queue_pos < index_queue.size()) {\\n auto server_path_id = index_queue[index_queue_pos];\\n index_queue_pos++;\\n\\n auto file_path = std::string(path_pool.resolve(server_path_id));\\n\\n // Note: we do NOT skip open documents here. Index data is needed for\\n // cross-file features (references, call hierarchy, type hierarchy, etc.)\\n // regardless of whether the file is open.\\n\\n // Check if the index needs update by checking mtime against existing shard.\\n // If the file is not yet in the project_index path pool, it has never been\\n // indexed — always proceed. Only skip when we already have a shard that is\\n // still fresh.\\n auto cache_it = project_index.path_pool.find(file_path);\\n if(cache_it != project_index.path_pool.cache.end()) {\\n auto proj_path_id = cache_it->second;\\n auto merged_it = merged_indices.find(proj_path_id);\\n if(merged_it != merged_indices.end()) {\\n // Build path mapping for need_update check.\\n llvm::SmallVector<llvm::StringRef> path_mapping;\\n for(auto& p: project_index.path_pool.paths) {\\n path_mapping.push_back(p);\\n }\\n if(!merged_it->second.need_update(path_mapping))\\n continue;\\n }\\n }\\n\\n // Prepare IndexParams for the stateless worker.\\n worker::IndexParams params;\\n params.file = file_path;\\n if(!fill_compile_args(file_path, params.directory, params.arguments))\\n continue;\\n\\n // Fill PCM deps for module-aware indexing.\\n for(auto& [pid, pcm_path]: pcm_paths) {\\n auto mod_it = path_to_module.find(pid);\\n if(mod_it != path_to_module.end()) {\\n params.pcms[mod_it->second] = pcm_path;\\n }\\n }\\n\\n LOG_INFO(\\\"Background indexing: {}\\\", file_path);\\n\\n auto result = co_await pool.send_stateless(params);\\n if(result.has_value() && result.value().success && !result.value().tu_index_data.empty()) {\\n LOG_INFO(\\\"Background indexing got TUIndex for {}: {} bytes\\\",\\n file_path,\\n result.value().tu_index_data.size());\\n merge_index_result(result.value().tu_index_data.data(),\\n result.value().tu_index_data.size());\\n ++processed;\\n } else if(result.has_value() && !result.value().success) {\\n LOG_WARN(\\\"Background index failed for {}: {}\\\", file_path, result.value().error);\\n } else if(result.has_value() && result.value().tu_index_data.empty()) {\\n LOG_WARN(\\\"Background index returned empty TUIndex for {}\\\", file_path);\\n } else {\\n LOG_WARN(\\\"Background index IPC error for {}: {}\\\", file_path, result.error().message);\\n }\\n }\\n\\n indexing_active = false;\\n LOG_INFO(\\\"Background indexing complete: {} files processed\\\", processed);\\n\\n // Persist index to disk after a full pass.\\n save_index();\\n}\\n\\n// =========================================================================\\n// Include/import completion (handled in master)\\n// =========================================================================\\n\\nPreambleCompletionContext MasterServer::detect_completion_context(const std::string& text,\\n uint32_t offset) {\\n // Find the start of the line containing offset.\\n auto line_start = text.rfind('\\\\n', offset > 0 ? offset - 1 : 0);\\n line_start = (line_start == std::string::npos) ? 0 : line_start + 1;\\n\\n // Find the end of the line.\\n auto line_end = text.find('\\\\n', offset);\\n if(line_end == std::string::npos)\\n line_end = text.size();\\n\\n // Extract the line up to the cursor position.\\n auto line = llvm::StringRef(text).slice(line_start, offset);\\n\\n // Strip leading whitespace.\\n auto trimmed = line.ltrim();\\n\\n // Check for #include \\\"prefix or #include <prefix\\n if(trimmed.starts_with(\\\"#\\\")) {\\n auto directive = trimmed.drop_front(1).ltrim();\\n if(directive.consume_front(\\\"include\\\")) {\\n directive = directive.ltrim();\\n if(directive.consume_front(\\\"\\\\\\\"\\\")) {\\n return {CompletionContext::IncludeQuoted, directive.str()};\\n }\\n if(directive.consume_front(\\\"<\\\")) {\\n return {CompletionContext::IncludeAngled, directive.str()};\\n }\\n }\\n // Line starts with # but isn't #include — not a completion context.\\n return {};\\n }\\n\\n // Check for [export] import prefix (without trailing semicolon).\\n auto import_check = trimmed;\\n if(import_check.consume_front(\\\"export\\\")) {\\n import_check = import_check.ltrim();\\n }\\n if(import_check.consume_front(\\\"import\\\")) {\\n import_check = import_check.ltrim();\\n // Only treat as import if there's no semicolon in what follows.\\n auto rest_of_line = llvm::StringRef(text).slice(line_start, line_end);\\n if(!rest_of_line.contains(';')) {\\n return {CompletionContext::Import, import_check.str()};\\n }\\n }\\n\\n return {};\\n}\\n\\net::serde::RawValue MasterServer::complete_include(const PreambleCompletionContext& ctx,\\n llvm::StringRef path) {\\n std::string directory;\\n std::vector<std::string> arguments;\\n if(!fill_compile_args(path, directory, arguments))\\n return et::serde::RawValue{\\\"[]\\\"};\\n\\n // Convert arguments to const char* array.\\n std::vector<const char*> args_ptrs;\\n args_ptrs.reserve(arguments.size());\\n for(auto& arg: arguments) {\\n args_ptrs.push_back(arg.c_str());\\n }\\n\\n auto config = extract_search_config(args_ptrs, directory);\\n DirListingCache dir_cache;\\n auto resolved = resolve_search_config(config, dir_cache);\\n\\n // Determine search range based on context.\\n unsigned start_idx = 0;\\n if(ctx.kind == CompletionContext::IncludeAngled) {\\n start_idx = resolved.angled_start_idx;\\n }\\n\\n // Split prefix into dir_prefix and file_prefix if it contains '/'.\\n llvm::StringRef prefix_ref(ctx.prefix);\\n llvm::StringRef dir_prefix;\\n llvm::StringRef file_prefix = prefix_ref;\\n auto slash_pos = prefix_ref.rfind('/');\\n if(slash_pos != llvm::StringRef::npos) {\\n dir_prefix = prefix_ref.slice(0, slash_pos);\\n file_prefix = prefix_ref.slice(slash_pos + 1, llvm::StringRef::npos);\\n }\\n\\n std::vector<protocol::CompletionItem> items;\\n llvm::StringSet<> seen; // Deduplicate entries across search dirs.\\n\\n for(unsigned i = start_idx; i < resolved.dirs.size(); ++i) {\\n auto& search_dir = resolved.dirs[i];\\n\\n // If there's a dir_prefix, resolve the subdirectory.\\n const llvm::StringSet<>* entries = nullptr;\\n if(!dir_prefix.empty()) {\\n llvm::SmallString<256> sub_path(search_dir.path);\\n llvm::sys::path::append(sub_path, dir_prefix);\\n entries = resolve_dir(sub_path, dir_cache);\\n } else {\\n entries = search_dir.entries;\\n }\\n\\n if(!entries)\\n continue;\\n\\n for(auto& entry: *entries) {\\n auto name = entry.getKey();\\n if(!name.starts_with(file_prefix))\\n continue;\\n if(!seen.insert(name).second)\\n continue;\\n\\n // Check if this entry is a directory.\\n llvm::SmallString<256> full_path(search_dir.path);\\n if(!dir_prefix.empty()) {\\n llvm::sys::path::append(full_path, dir_prefix);\\n }\\n llvm::sys::path::append(full_path, name);\\n\\n bool is_dir = false;\\n llvm::sys::fs::is_directory(llvm::Twine(full_path), is_dir);\\n\\n protocol::CompletionItem item;\\n if(is_dir) {\\n item.label = (name + \\\"/\\\").str();\\n } else {\\n item.label = name.str();\\n }\\n item.kind = protocol::CompletionItemKind::File;\\n items.push_back(std::move(item));\\n }\\n }\\n\\n auto json = et::serde::json::to_json<et::ipc::lsp_config>(items);\\n return et::serde::RawValue{json ? std::move(*json) : \\\"[]\\\"};\\n}\\n\\net::serde::RawValue MasterServer::complete_import(const PreambleCompletionContext& ctx) {\\n std::vector<protocol::CompletionItem> items;\\n llvm::StringRef prefix_ref(ctx.prefix);\\n\\n for(auto& [path_id, module_name]: path_to_module) {\\n llvm::StringRef name_ref(module_name);\\n if(!name_ref.starts_with(prefix_ref))\\n continue;\\n\\n protocol::CompletionItem item;\\n item.label = module_name;\\n item.kind = protocol::CompletionItemKind::Module;\\n item.insert_text = module_name + \\\";\\\";\\n items.push_back(std::move(item));\\n }\\n\\n auto json = et::serde::json::to_json<et::ipc::lsp_config>(items);\\n return et::serde::RawValue{json ? std::move(*json) : \\\"[]\\\"};\\n}\\n\\n// =========================================================================\\n// Forwarding helpers\\n// =========================================================================\\n\\nusing serde_raw = et::serde::RawValue;\\n\\ntemplate <typename WorkerParams>\\nMasterServer::RawResult MasterServer::forward_stateful(const std::string& uri) {\\n auto path = uri_to_path(uri);\\n auto path_id = path_pool.intern(path);\\n\\n LOG_INFO(\\\"forward_stateful: request path={}\\\", path);\\n\\n if(!co_await ensure_compiled(path_id)) {\\n LOG_DEBUG(\\\"forward_stateful: ensure_compiled failed for {}\\\", path);\\n co_return serde_raw{\\\"null\\\"};\\n }\\n\\n WorkerParams wp;\\n wp.path = path;\\n\\n LOG_INFO(\\\"forward_stateful: sending feature to worker path={}\\\", path);\\n auto result = co_await pool.send_stateful(path_id, wp);\\n LOG_INFO(\\\"forward_stateful: feature response path={} ok={}\\\", path, result.has_value());\\n if(!result.has_value()) {\\n co_return serde_raw{};\\n }\\n co_return std::move(result.value());\\n}\\n\\ntemplate <typename WorkerParams>\\nMasterServer::RawResult MasterServer::forward_stateful(const std::string& uri,\\n const protocol::Position& position) {\\n auto path = uri_to_path(uri);\\n auto path_id = path_pool.intern(path);\\n\\n LOG_INFO(\\\"forward_stateful(pos): request path={} pos={}:{}\\\",\\n path,\\n position.line,\\n position.character);\\n\\n if(!co_await ensure_compiled(path_id)) {\\n LOG_INFO(\\\"forward_stateful(pos): ensure_compiled failed for {}\\\", path);\\n co_return serde_raw{\\\"null\\\"};\\n }\\n\\n WorkerParams wp;\\n wp.path = path;\\n\\n auto doc_it = documents.find(path_id);\\n if(doc_it != documents.end()) {\\n lsp::PositionMapper mapper(doc_it->second.text, lsp::PositionEncoding::UTF16);\\n auto offset = mapper.to_offset(position);\\n if(!offset)\\n co_return serde_raw{\\\"null\\\"};\\n wp.offset = *offset;\\n }\\n\\n LOG_INFO(\\\"forward_stateful(pos): sending feature to worker path={}\\\", path);\\n auto result = co_await pool.send_stateful(path_id, wp);\\n LOG_INFO(\\\"forward_stateful(pos): feature response path={} ok={}\\\", path, result.has_value());\\n if(!result.has_value()) {\\n co_return serde_raw{};\\n }\\n co_return std::move(result.value());\\n}\\n\\ntemplate <typename WorkerParams>\\nMasterServer::RawResult MasterServer::forward_stateless(const std::string& uri,\\n const protocol::Position& position) {\\n auto path = uri_to_path(uri);\\n auto path_id = path_pool.intern(path);\\n\\n LOG_DEBUG(\\\"forward_stateless: {} path={} pos={}:{}\\\",\\n \\\"request\\\",\\n path,\\n position.line,\\n position.character);\\n\\n auto doc_it = documents.find(path_id);\\n if(doc_it == documents.end()) {\\n LOG_DEBUG(\\\"forward_stateless: doc not found for {}\\\", path);\\n co_return serde_raw{};\\n }\\n\\n auto& doc = doc_it->second;\\n\\n WorkerParams wp;\\n wp.path = path;\\n wp.version = doc.version;\\n wp.text = doc.text;\\n if(!fill_compile_args(path, wp.directory, wp.arguments)) {\\n LOG_DEBUG(\\\"forward_stateless: no CDB for {}\\\", path);\\n co_return serde_raw{};\\n }\\n\\n // Ensure module deps, PCH, and PCM paths are ready for stateless compilation.\\n if(!co_await ensure_deps(path_id, path, wp.text, wp.directory, wp.arguments, wp.pch, wp.pcms)) {\\n LOG_DEBUG(\\\"forward_stateless: ensure_deps failed for {}\\\", path);\\n co_return serde_raw{};\\n }\\n\\n lsp::PositionMapper mapper(wp.text, lsp::PositionEncoding::UTF16);\\n auto offset = mapper.to_offset(position);\\n if(!offset)\\n co_return serde_raw{\\\"null\\\"};\\n wp.offset = *offset;\\n\\n auto result = co_await pool.send_stateless(wp);\\n if(!result.has_value()) {\\n LOG_DEBUG(\\\"forward_stateless: worker error for {}: {}\\\", path, result.error().message);\\n co_return serde_raw{};\\n }\\n LOG_DEBUG(\\\"forward_stateless: done {}\\\", path);\\n co_return std::move(result.value());\\n}\\n\\n// Serialize a value to a JSON RawValue using LSP config.\\ntemplate <typename T>\\nstatic serde_raw to_raw(const T& value) {\\n auto json = et::serde::json::to_json<et::ipc::lsp_config>(value);\\n return serde_raw{json ? std::move(*json) : \\\"null\\\"};\\n}\\n\\nMasterServer::RawResult MasterServer::query_index_relations(const std::string& uri,\\n const protocol::Position& position,\\n RelationKind kind) {\\n auto path = uri_to_path(uri);\\n auto server_path_id = path_pool.intern(path);\\n\\n // Need document text for position-to-offset conversion.\\n auto doc_it = documents.find(server_path_id);\\n if(doc_it == documents.end())\\n co_return serde_raw{\\\"null\\\"};\\n\\n lsp::PositionMapper mapper(doc_it->second.text, lsp::PositionEncoding::UTF16);\\n auto offset_opt = mapper.to_offset(position);\\n if(!offset_opt)\\n co_return serde_raw{\\\"null\\\"};\\n auto offset = *offset_opt;\\n\\n // Find the project-level path_id for this file.\\n auto proj_cache_it = project_index.path_pool.find(path);\\n if(proj_cache_it == project_index.path_pool.cache.end()) {\\n LOG_DEBUG(\\\"query_index_relations: path '{}' not in project_index\\\", path);\\n co_return serde_raw{\\\"null\\\"};\\n }\\n auto proj_path_id = proj_cache_it->second;\\n\\n // Lookup occurrence at offset in this file's MergedIndex.\\n auto merged_it = merged_indices.find(proj_path_id);\\n if(merged_it == merged_indices.end()) {\\n LOG_DEBUG(\\\"query_index_relations: no MergedIndex for proj_path_id={}\\\", proj_path_id);\\n co_return serde_raw{\\\"null\\\"};\\n }\\n\\n index::SymbolHash symbol_hash = 0;\\n merged_it->second.lookup(offset, [&](const index::Occurrence& o) {\\n symbol_hash = o.target;\\n return false; // stop after first match\\n });\\n\\n if(symbol_hash == 0) {\\n LOG_DEBUG(\\\"query_index_relations: no occurrence at offset {} in '{}'\\\", offset, path);\\n co_return serde_raw{\\\"null\\\"};\\n }\\n\\n // Get reference files from ProjectIndex.\\n auto sym_it = project_index.symbols.find(symbol_hash);\\n if(sym_it == project_index.symbols.end()) {\\n LOG_DEBUG(\\\"query_index_relations: symbol {} not in project_index\\\", symbol_hash);\\n co_return serde_raw{\\\"null\\\"};\\n }\\n\\n // Query each referenced file's MergedIndex for relations of the requested kind.\\n std::vector<protocol::Location> locations;\\n\\n for(auto file_id: sym_it->second.reference_files) {\\n auto file_merged_it = merged_indices.find(file_id);\\n if(file_merged_it == merged_indices.end())\\n continue;\\n\\n auto file_path = project_index.path_pool.path(file_id);\\n auto file_uri = lsp::URI::from_file_path(file_path);\\n if(!file_uri)\\n continue;\\n auto file_uri_str = file_uri->str();\\n\\n // Use stored content from MergedIndex for offset-to-position conversion.\\n auto file_content = file_merged_it->second.content();\\n if(file_content.empty())\\n continue;\\n\\n lsp::PositionMapper file_mapper(file_content, lsp::PositionEncoding::UTF16);\\n\\n file_merged_it->second.lookup(symbol_hash, kind, [&](const index::Relation& r) {\\n auto start = file_mapper.to_position(r.range.begin);\\n auto end = file_mapper.to_position(r.range.end);\\n if(start && end) {\\n protocol::Location loc;\\n loc.uri = file_uri_str;\\n loc.range = protocol::Range{*start, *end};\\n locations.push_back(std::move(loc));\\n }\\n return true; // continue collecting\\n });\\n }\\n\\n if(locations.empty())\\n co_return serde_raw{\\\"null\\\"};\\n\\n co_return to_raw(locations);\\n}\\n\\nprotocol::SymbolKind MasterServer::to_lsp_symbol_kind(SymbolKind kind) {\\n switch(kind) {\\n case SymbolKind::Namespace: return protocol::SymbolKind::Namespace;\\n case SymbolKind::Class: return protocol::SymbolKind::Class;\\n case SymbolKind::Struct: return protocol::SymbolKind::Struct;\\n case SymbolKind::Union: return protocol::SymbolKind::Class;\\n case SymbolKind::Enum: return protocol::SymbolKind::Enum;\\n case SymbolKind::Type: return protocol::SymbolKind::TypeParameter;\\n case SymbolKind::Field: return protocol::SymbolKind::Field;\\n case SymbolKind::EnumMember: return protocol::SymbolKind::EnumMember;\\n case SymbolKind::Function: return protocol::SymbolKind::Function;\\n case SymbolKind::Method: return protocol::SymbolKind::Method;\\n case SymbolKind::Variable: return protocol::SymbolKind::Variable;\\n case SymbolKind::Parameter: return protocol::SymbolKind::Variable;\\n case SymbolKind::Macro: return protocol::SymbolKind::Function;\\n case SymbolKind::Concept: return protocol::SymbolKind::Interface;\\n case SymbolKind::Module: return protocol::SymbolKind::Module;\\n case SymbolKind::Operator: return protocol::SymbolKind::Operator;\\n default: return protocol::SymbolKind::Variable;\\n }\\n}\\n\\net::task<std::optional<SymbolInfo>>\\n MasterServer::lookup_symbol_at_position(const std::string& uri,\\n const protocol::Position& position) {\\n auto path = uri_to_path(uri);\\n auto server_path_id = path_pool.intern(path);\\n\\n // Need document text for position-to-offset conversion.\\n auto doc_it = documents.find(server_path_id);\\n if(doc_it == documents.end())\\n co_return std::nullopt;\\n\\n lsp::PositionMapper mapper(doc_it->second.text, lsp::PositionEncoding::UTF16);\\n auto offset_opt = mapper.to_offset(position);\\n if(!offset_opt)\\n co_return std::nullopt;\\n auto offset = *offset_opt;\\n\\n // Find the project-level path_id for this file.\\n auto proj_cache_it = project_index.path_pool.find(path);\\n if(proj_cache_it == project_index.path_pool.cache.end()) {\\n LOG_WARN(\\\"lookup_symbol: path '{}' not in project_index (pool has {} entries)\\\",\\n path,\\n project_index.path_pool.paths.size());\\n co_return std::nullopt;\\n }\\n auto proj_path_id = proj_cache_it->second;\\n\\n // Lookup occurrence at offset in this file's MergedIndex.\\n auto merged_it = merged_indices.find(proj_path_id);\\n if(merged_it == merged_indices.end()) {\\n LOG_WARN(\\\"lookup_symbol: no MergedIndex for proj_path_id={} (have {} shards)\\\",\\n proj_path_id,\\n merged_indices.size());\\n co_return std::nullopt;\\n }\\n\\n index::SymbolHash symbol_hash = 0;\\n index::Range occ_range{};\\n merged_it->second.lookup(offset, [&](const index::Occurrence& o) {\\n symbol_hash = o.target;\\n occ_range = o.range;\\n return false; // stop after first match\\n });\\n\\n if(symbol_hash == 0) {\\n LOG_WARN(\\\"lookup_symbol: no occurrence at offset {} in '{}'\\\", offset, path);\\n co_return std::nullopt;\\n }\\n\\n // Get symbol info from ProjectIndex.\\n auto sym_it = project_index.symbols.find(symbol_hash);\\n if(sym_it == project_index.symbols.end())\\n co_return std::nullopt;\\n\\n // Convert occurrence range to LSP Range.\\n auto start = mapper.to_position(occ_range.begin);\\n auto end = mapper.to_position(occ_range.end);\\n if(!start || !end)\\n co_return std::nullopt;\\n\\n SymbolInfo info;\\n info.hash = symbol_hash;\\n info.name = sym_it->second.name;\\n info.kind = sym_it->second.kind;\\n info.uri = uri;\\n info.range = protocol::Range{*start, *end};\\n co_return info;\\n}\\n\\nstd::optional<protocol::Location>\\n MasterServer::find_symbol_definition_location(index::SymbolHash hash) {\\n auto sym_it = project_index.symbols.find(hash);\\n if(sym_it == project_index.symbols.end())\\n return std::nullopt;\\n\\n // Search reference files for a Definition relation.\\n for(auto file_id: sym_it->second.reference_files) {\\n auto file_merged_it = merged_indices.find(file_id);\\n if(file_merged_it == merged_indices.end())\\n continue;\\n\\n auto file_path = project_index.path_pool.path(file_id);\\n auto file_uri = lsp::URI::from_file_path(file_path);\\n if(!file_uri)\\n continue;\\n\\n // Use stored content from MergedIndex for offset-to-position conversion.\\n auto file_content = file_merged_it->second.content();\\n if(file_content.empty())\\n continue;\\n lsp::PositionMapper file_mapper(file_content, lsp::PositionEncoding::UTF16);\\n\\n std::optional<protocol::Location> result;\\n file_merged_it->second.lookup(hash,\\n RelationKind::Definition,\\n [&](const index::Relation& r) {\\n auto start = file_mapper.to_position(r.range.begin);\\n auto end = file_mapper.to_position(r.range.end);\\n if(start && end) {\\n protocol::Location loc;\\n loc.uri = file_uri->str();\\n loc.range = protocol::Range{*start, *end};\\n result = std::move(loc);\\n return false; // found it, stop\\n }\\n return true;\\n });\\n\\n if(result)\\n return result;\\n }\\n\\n return std::nullopt;\\n}\\n\\nprotocol::CallHierarchyItem MasterServer::build_call_hierarchy_item(const SymbolInfo& info) {\\n protocol::CallHierarchyItem item;\\n item.name = info.name;\\n item.kind = to_lsp_symbol_kind(info.kind);\\n item.uri = info.uri;\\n item.range = info.range;\\n item.selection_range = info.range;\\n // Store the symbol hash in data for later use in incoming/outgoing calls.\\n item.data = protocol::LSPAny(static_cast<std::int64_t>(info.hash));\\n return item;\\n}\\n\\nprotocol::TypeHierarchyItem MasterServer::build_type_hierarchy_item(const SymbolInfo& info) {\\n protocol::TypeHierarchyItem item;\\n item.name = info.name;\\n item.kind = to_lsp_symbol_kind(info.kind);\\n item.uri = info.uri;\\n item.range = info.range;\\n item.selection_range = info.range;\\n item.data = protocol::LSPAny(static_cast<std::int64_t>(info.hash));\\n return item;\\n}\\n\\net::task<std::optional<SymbolInfo>>\\n MasterServer::resolve_hierarchy_item(const std::string& uri,\\n const protocol::Range& range,\\n const std::optional<protocol::LSPAny>& data) {\\n // Try to extract symbol hash from the stored data field first.\\n if(data) {\\n if(auto* int_val = std::get_if<std::int64_t>(&*data)) {\\n auto hash = static_cast<index::SymbolHash>(*int_val);\\n auto sym_it = project_index.symbols.find(hash);\\n if(sym_it != project_index.symbols.end()) {\\n SymbolInfo info;\\n info.hash = hash;\\n info.name = sym_it->second.name;\\n info.kind = sym_it->second.kind;\\n info.uri = uri;\\n info.range = range;\\n co_return info;\\n }\\n }\\n }\\n\\n // Fallback: re-lookup from position (requires document to be open).\\n co_return co_await lookup_symbol_at_position(uri, range.start);\\n}\\n\\nvoid MasterServer::register_handlers() {\\n // === initialize ===\\n peer.on_request([this](RequestContext& ctx, const protocol::InitializeParams& params)\\n -> RequestResult<protocol::InitializeParams> {\\n if(lifecycle != ServerLifecycle::Uninitialized) {\\n co_return et::outcome_error(protocol::Error{\\\"Server already initialized\\\"});\\n }\\n\\n // Extract workspace root\\n auto& init = params.lsp__initialize_params;\\n if(init.root_uri.has_value()) {\\n workspace_root = uri_to_path(*init.root_uri);\\n }\\n\\n lifecycle = ServerLifecycle::Initialized;\\n\\n LOG_INFO(\\\"Initialized with workspace: {}\\\", workspace_root);\\n\\n // Build capabilities\\n protocol::InitializeResult result;\\n\\n // Text document sync: incremental\\n protocol::TextDocumentSyncOptions sync_opts;\\n sync_opts.open_close = true;\\n sync_opts.change = protocol::TextDocumentSyncKind::Incremental;\\n sync_opts.save = protocol::variant<protocol::boolean, protocol::SaveOptions>{true};\\n result.capabilities.text_document_sync = std::move(sync_opts);\\n\\n // Feature capabilities\\n result.capabilities.hover_provider = true;\\n result.capabilities.completion_provider = protocol::CompletionOptions{};\\n result.capabilities.signature_help_provider = protocol::SignatureHelpOptions{};\\n result.capabilities.definition_provider = true;\\n result.capabilities.references_provider = true;\\n result.capabilities.document_symbol_provider = true;\\n result.capabilities.document_link_provider = protocol::DocumentLinkOptions{};\\n result.capabilities.code_action_provider = true;\\n result.capabilities.folding_range_provider = true;\\n result.capabilities.inlay_hint_provider = true;\\n result.capabilities.call_hierarchy_provider = true;\\n result.capabilities.type_hierarchy_provider = true;\\n result.capabilities.workspace_symbol_provider = true;\\n\\n // Semantic tokens\\n protocol::SemanticTokensOptions sem_opts;\\n {\\n auto lower_first = [](std::string_view name) -> std::string {\\n std::string s(name);\\n if(!s.empty()) {\\n s[0] = static_cast<char>(std::tolower(static_cast<unsigned char>(s[0])));\\n }\\n return s;\\n };\\n\\n auto to_names = [&](auto names) {\\n return std::ranges::to<std::vector>(names | std::views::transform(lower_first));\\n };\\n\\n sem_opts.legend = protocol::SemanticTokensLegend{\\n to_names(refl::reflection<SymbolKind::Kind>::member_names),\\n to_names(refl::reflection<SymbolModifiers::Kind>::member_names),\\n };\\n }\\n sem_opts.full = true;\\n result.capabilities.semantic_tokens_provider = std::move(sem_opts);\\n\\n // Server info\\n protocol::ServerInfo info;\\n info.name = \\\"clice\\\";\\n info.version = \\\"0.1.0\\\";\\n result.server_info = std::move(info);\\n\\n co_return result;\\n });\\n\\n // === initialized ===\\n peer.on_notification([this](const protocol::InitializedParams& params) {\\n // Load configuration from workspace\\n config = CliceConfig::load_from_workspace(workspace_root);\\n\\n // Switch master to file logging under a session-timestamped directory\\n if(!config.logging_dir.empty()) {\\n auto now = std::chrono::system_clock::now();\\n auto pid = llvm::sys::Process::getProcessId();\\n auto session_dir =\\n path::join(config.logging_dir, std::format(\\\"{:%Y-%m-%d_%H-%M-%S}_{}\\\", now, pid));\\n logging::file_logger(\\\"master\\\", session_dir, logging::options);\\n session_log_dir = session_dir;\\n }\\n\\n LOG_INFO(\\\"Server ready (stateful={}, stateless={}, idle={}ms)\\\",\\n config.stateful_worker_count,\\n config.stateless_worker_count,\\n config.idle_timeout_ms);\\n\\n // Start worker pool\\n WorkerPoolOptions pool_opts;\\n pool_opts.self_path = self_path;\\n pool_opts.stateful_count = config.stateful_worker_count;\\n pool_opts.stateless_count = config.stateless_worker_count;\\n pool_opts.worker_memory_limit = config.worker_memory_limit;\\n pool_opts.log_dir = session_log_dir;\\n if(!pool.start(pool_opts)) {\\n LOG_ERROR(\\\"Failed to start worker pool\\\");\\n return;\\n }\\n\\n lifecycle = ServerLifecycle::Ready;\\n\\n // Load CDB in background\\n loop.schedule(load_workspace());\\n });\\n\\n // === shutdown ===\\n peer.on_request(\\n [this](RequestContext& ctx,\\n const protocol::ShutdownParams& params) -> RequestResult<protocol::ShutdownParams> {\\n lifecycle = ServerLifecycle::ShuttingDown;\\n LOG_INFO(\\\"Shutdown requested\\\");\\n co_return nullptr;\\n });\\n\\n // === exit ===\\n peer.on_notification([this](const protocol::ExitParams& params) {\\n lifecycle = ServerLifecycle::Exited;\\n LOG_INFO(\\\"Exit notification received\\\");\\n\\n // Persist index and cache state before stopping.\\n save_index();\\n save_cache();\\n\\n // Graceful shutdown: cancel compilations, stop workers, then stop loop\\n loop.schedule([this]() -> et::task<> {\\n co_await pool.stop();\\n loop.stop();\\n }());\\n });\\n\\n // === textDocument/didOpen ===\\n peer.on_notification([this](const protocol::DidOpenTextDocumentParams& params) {\\n if(lifecycle != ServerLifecycle::Ready)\\n return;\\n\\n auto& td = params.text_document;\\n auto path = uri_to_path(td.uri);\\n auto path_id = path_pool.intern(path);\\n\\n auto& doc = documents[path_id];\\n doc.version = td.version;\\n doc.text = td.text;\\n doc.generation++;\\n\\n LOG_DEBUG(\\\"didOpen: {} (v{})\\\", path, td.version);\\n });\\n\\n // === textDocument/didChange ===\\n peer.on_notification([this](const protocol::DidChangeTextDocumentParams& params) {\\n if(lifecycle != ServerLifecycle::Ready)\\n return;\\n\\n auto path = uri_to_path(params.text_document.uri);\\n auto path_id = path_pool.intern(path);\\n\\n auto it = documents.find(path_id);\\n if(it == documents.end())\\n return;\\n\\n auto& doc = it->second;\\n doc.version = params.text_document.version;\\n\\n // Apply content changes.\\n for(auto& change: params.content_changes) {\\n std::visit(\\n [&](auto& c) {\\n using T = std::remove_cvref_t<decltype(c)>;\\n if constexpr(std::is_same_v<T,\\n protocol::TextDocumentContentChangeWholeDocument>) {\\n doc.text = c.text;\\n } else {\\n // Incremental change: replace range\\n auto& range = c.range;\\n lsp::PositionMapper mapper(doc.text, lsp::PositionEncoding::UTF16);\\n auto start = mapper.to_offset(range.start);\\n auto end = mapper.to_offset(range.end);\\n if(start && end && *start <= *end) {\\n doc.text.replace(*start, *end - *start, c.text);\\n }\\n }\\n },\\n change);\\n }\\n\\n doc.generation++;\\n doc.ast_dirty = true;\\n\\n LOG_DEBUG(\\\"didChange: path={} version={} gen={}\\\", path, doc.version, doc.generation);\\n\\n // Notify the owning stateful worker so it marks the document dirty\\n worker::DocumentUpdateParams update;\\n update.path = path;\\n update.version = doc.version;\\n pool.notify_stateful(path_id, update);\\n });\\n\\n // === textDocument/didClose ===\\n peer.on_notification([this](const protocol::DidCloseTextDocumentParams& params) {\\n if(lifecycle != ServerLifecycle::Ready)\\n return;\\n\\n auto path = uri_to_path(params.text_document.uri);\\n auto path_id = path_pool.intern(path);\\n\\n // Cancel in-flight module compilations for this file.\\n if(compile_graph && compile_graph->has_unit(path_id)) {\\n compile_graph->update(path_id);\\n }\\n\\n documents.erase(path_id);\\n pch_states.erase(path_id);\\n ast_deps.erase(path_id);\\n\\n // Clear diagnostics for closed file\\n clear_diagnostics(params.text_document.uri);\\n\\n LOG_DEBUG(\\\"didClose: {}\\\", path);\\n });\\n\\n // === textDocument/didSave ===\\n peer.on_notification([this](const protocol::DidSaveTextDocumentParams& params) {\\n if(lifecycle != ServerLifecycle::Ready)\\n return;\\n\\n auto path = uri_to_path(params.text_document.uri);\\n auto path_id = path_pool.intern(path);\\n\\n // Invalidate this file and cascade to dependents in the compile graph.\\n if(compile_graph) {\\n auto dirtied = compile_graph->update(path_id);\\n // Remove stale PCMs for all invalidated units.\\n for(auto dirty_id: dirtied) {\\n pcm_paths.erase(dirty_id);\\n pcm_states.erase(dirty_id);\\n }\\n // Mark ast_dirty for open documents that depend on the saved file.\\n for(auto dirty_id: dirtied) {\\n auto doc_it = documents.find(dirty_id);\\n if(doc_it != documents.end()) {\\n doc_it->second.ast_dirty = true;\\n }\\n }\\n }\\n\\n // Trigger background indexing after save.\\n schedule_indexing();\\n\\n LOG_DEBUG(\\\"didSave: {}\\\", params.text_document.uri);\\n });\\n\\n // =========================================================================\\n // Feature requests routed to stateful workers (RawValue passthrough)\\n // =========================================================================\\n\\n // --- textDocument/hover ---\\n peer.on_request([this](RequestContext& ctx, const protocol::HoverParams& params) -> RawResult {\\n co_return co_await forward_stateful<worker::HoverParams>(\\n params.text_document_position_params.text_document.uri,\\n params.text_document_position_params.position);\\n });\\n\\n // --- textDocument/semanticTokens/full ---\\n peer.on_request([this](RequestContext& ctx,\\n const protocol::SemanticTokensParams& params) -> RawResult {\\n co_return co_await forward_stateful<worker::SemanticTokensParams>(params.text_document.uri);\\n });\\n\\n // --- textDocument/inlayHint ---\\n peer.on_request(\\n [this](RequestContext& ctx, const protocol::InlayHintParams& params) -> RawResult {\\n co_return co_await forward_stateful<worker::InlayHintsParams>(params.text_document.uri);\\n });\\n\\n // --- textDocument/foldingRange ---\\n peer.on_request([this](RequestContext& ctx,\\n const protocol::FoldingRangeParams& params) -> RawResult {\\n co_return co_await forward_stateful<worker::FoldingRangeParams>(params.text_document.uri);\\n });\\n\\n // --- textDocument/documentSymbol ---\\n peer.on_request([this](RequestContext& ctx,\\n const protocol::DocumentSymbolParams& params) -> RawResult {\\n co_return co_await forward_stateful<worker::DocumentSymbolParams>(params.text_document.uri);\\n });\\n\\n // --- textDocument/documentLink ---\\n peer.on_request([this](RequestContext& ctx,\\n const protocol::DocumentLinkParams& params) -> RawResult {\\n co_return co_await forward_stateful<worker::DocumentLinkParams>(params.text_document.uri);\\n });\\n\\n // --- textDocument/codeAction ---\\n peer.on_request(\\n [this](RequestContext& ctx, const protocol::CodeActionParams& params) -> RawResult {\\n co_return co_await forward_stateful<worker::CodeActionParams>(params.text_document.uri);\\n });\\n\\n // --- textDocument/definition ---\\n peer.on_request(\\n [this](RequestContext& ctx, const protocol::DefinitionParams& params) -> RawResult {\\n auto& uri = params.text_document_position_params.text_document.uri;\\n auto& pos = params.text_document_position_params.position;\\n\\n // Try index-based lookup first.\\n auto result = co_await query_index_relations(uri, pos, RelationKind::Definition);\\n if(result.has_value() && !result.value().empty() && result.value().data != \\\"null\\\") {\\n co_return std::move(result).value();\\n }\\n\\n // Fall back to stateful worker AST query.\\n co_return co_await forward_stateful<worker::GoToDefinitionParams>(uri, pos);\\n });\\n\\n // --- textDocument/references ---\\n peer.on_request(\\n [this](RequestContext& ctx, const protocol::ReferenceParams& params) -> RawResult {\\n auto& uri = params.text_document_position_params.text_document.uri;\\n auto& pos = params.text_document_position_params.position;\\n\\n auto refs = co_await query_index_relations(uri, pos, RelationKind::Reference);\\n\\n if(params.context.include_declaration) {\\n // Also include Definition locations when the client requests the declaration.\\n auto defs = co_await query_index_relations(uri, pos, RelationKind::Definition);\\n if(defs.has_value() && !defs.value().empty() && defs.value().data != \\\"null\\\") {\\n if(!refs.has_value() || refs.value().empty() || refs.value().data == \\\"null\\\") {\\n co_return std::move(defs).value();\\n }\\n // Merge: parse both JSON arrays and concatenate.\\n auto& ref_json = refs.value().data;\\n auto& def_json = defs.value().data;\\n // Both are JSON arrays like \\\"[...]\\\". Merge them.\\n if(ref_json.size() > 2 && def_json.size() > 2) {\\n // Remove trailing ']' from refs, add comma, add def content without leading\\n // '['\\n std::string merged = ref_json.substr(0, ref_json.size() - 1);\\n merged += ',';\\n merged += def_json.substr(1);\\n co_return serde_raw{std::move(merged)};\\n }\\n }\\n }\\n\\n co_return refs;\\n });\\n\\n // =========================================================================\\n // Feature requests routed to stateless workers\\n // =========================================================================\\n\\n // --- textDocument/completion ---\\n peer.on_request(\\n [this](RequestContext& ctx, const protocol::CompletionParams& params) -> RawResult {\\n auto uri = params.text_document_position_params.text_document.uri;\\n auto position = params.text_document_position_params.position;\\n\\n // Check if cursor is on an #include or import line.\\n auto path = uri_to_path(uri);\\n auto path_id = path_pool.intern(path);\\n auto doc_it = documents.find(path_id);\\n if(doc_it != documents.end()) {\\n lsp::PositionMapper mapper(doc_it->second.text, lsp::PositionEncoding::UTF16);\\n auto offset = mapper.to_offset(position);\\n if(offset) {\\n auto pctx = detect_completion_context(doc_it->second.text, *offset);\\n if(pctx.kind == CompletionContext::IncludeQuoted ||\\n pctx.kind == CompletionContext::IncludeAngled) {\\n co_return complete_include(pctx, path);\\n }\\n if(pctx.kind == CompletionContext::Import) {\\n co_return complete_import(pctx);\\n }\\n }\\n }\\n\\n // Default: forward to stateless worker.\\n co_return co_await forward_stateless<worker::CompletionParams>(uri, position);\\n });\\n\\n // --- textDocument/signatureHelp ---\\n peer.on_request(\\n [this](RequestContext& ctx, const protocol::SignatureHelpParams& params) -> RawResult {\\n co_return co_await forward_stateless<worker::SignatureHelpParams>(\\n params.text_document_position_params.text_document.uri,\\n params.text_document_position_params.position);\\n });\\n\\n // =========================================================================\\n // Hierarchy and workspace symbol handlers (index-based)\\n // =========================================================================\\n\\n // --- textDocument/prepareCallHierarchy ---\\n peer.on_request([this](RequestContext& ctx,\\n const protocol::CallHierarchyPrepareParams& params) -> RawResult {\\n auto info = co_await lookup_symbol_at_position(\\n params.text_document_position_params.text_document.uri,\\n params.text_document_position_params.position);\\n if(!info)\\n co_return serde_raw{\\\"null\\\"};\\n\\n // Only functions/methods are valid for call hierarchy.\\n if(!(info->kind == SymbolKind::Function || info->kind == SymbolKind::Method))\\n co_return serde_raw{\\\"null\\\"};\\n\\n std::vector<protocol::CallHierarchyItem> items;\\n items.push_back(build_call_hierarchy_item(*info));\\n co_return to_raw(items);\\n });\\n\\n // --- callHierarchy/incomingCalls ---\\n peer.on_request([this](RequestContext& ctx,\\n const protocol::CallHierarchyIncomingCallsParams& params) -> RawResult {\\n // Re-lookup the symbol from the item.\\n auto info =\\n co_await resolve_hierarchy_item(params.item.uri, params.item.range, params.item.data);\\n if(!info)\\n co_return serde_raw{\\\"null\\\"};\\n\\n auto sym_it = project_index.symbols.find(info->hash);\\n if(sym_it == project_index.symbols.end())\\n co_return serde_raw{\\\"null\\\"};\\n\\n // Collect all Caller relations across reference files.\\n // Caller relation: on the callee symbol, target_symbol is the caller's hash.\\n std::vector<protocol::CallHierarchyIncomingCall> results;\\n\\n // Group call sites by caller symbol hash.\\n llvm::DenseMap<index::SymbolHash, std::vector<protocol::Range>> caller_ranges;\\n\\n for(auto file_id: sym_it->second.reference_files) {\\n auto file_merged_it = merged_indices.find(file_id);\\n if(file_merged_it == merged_indices.end())\\n continue;\\n\\n // Use stored content from MergedIndex for offset-to-position conversion.\\n auto file_content = file_merged_it->second.content();\\n if(file_content.empty())\\n continue;\\n\\n lsp::PositionMapper file_mapper(file_content, lsp::PositionEncoding::UTF16);\\n\\n file_merged_it->second.lookup(info->hash,\\n RelationKind::Caller,\\n [&](const index::Relation& r) {\\n auto start = file_mapper.to_position(r.range.begin);\\n auto end = file_mapper.to_position(r.range.end);\\n if(start && end) {\\n caller_ranges[r.target_symbol].push_back(\\n protocol::Range{*start, *end});\\n }\\n return true;\\n });\\n }\\n\\n // Build incoming call items from grouped caller symbols.\\n for(auto& [caller_hash, ranges]: caller_ranges) {\\n auto def_loc = find_symbol_definition_location(caller_hash);\\n auto caller_sym_it = project_index.symbols.find(caller_hash);\\n if(caller_sym_it == project_index.symbols.end())\\n continue;\\n\\n if(!def_loc)\\n continue;\\n\\n protocol::CallHierarchyItem caller_item;\\n caller_item.name = caller_sym_it->second.name;\\n caller_item.kind = to_lsp_symbol_kind(caller_sym_it->second.kind);\\n caller_item.uri = def_loc->uri;\\n caller_item.range = def_loc->range;\\n caller_item.selection_range = def_loc->range;\\n caller_item.data = protocol::LSPAny(static_cast<std::int64_t>(caller_hash));\\n\\n protocol::CallHierarchyIncomingCall call;\\n call.from = std::move(caller_item);\\n call.from_ranges = std::move(ranges);\\n results.push_back(std::move(call));\\n }\\n\\n if(results.empty())\\n co_return serde_raw{\\\"null\\\"};\\n co_return to_raw(results);\\n });\\n\\n // --- callHierarchy/outgoingCalls ---\\n peer.on_request([this](RequestContext& ctx,\\n const protocol::CallHierarchyOutgoingCallsParams& params) -> RawResult {\\n auto info =\\n co_await resolve_hierarchy_item(params.item.uri, params.item.range, params.item.data);\\n if(!info)\\n co_return serde_raw{\\\"null\\\"};\\n\\n auto sym_it = project_index.symbols.find(info->hash);\\n if(sym_it == project_index.symbols.end())\\n co_return serde_raw{\\\"null\\\"};\\n\\n // Collect Callee relations (outgoing calls from this function).\\n // Group call sites by callee symbol hash.\\n llvm::DenseMap<index::SymbolHash, std::vector<protocol::Range>> callee_ranges;\\n\\n for(auto file_id: sym_it->second.reference_files) {\\n auto file_merged_it = merged_indices.find(file_id);\\n if(file_merged_it == merged_indices.end())\\n continue;\\n\\n // Use stored content from MergedIndex for offset-to-position conversion.\\n auto file_content = file_merged_it->second.content();\\n if(file_content.empty())\\n continue;\\n\\n lsp::PositionMapper file_mapper(file_content, lsp::PositionEncoding::UTF16);\\n\\n file_merged_it->second.lookup(info->hash,\\n RelationKind::Callee,\\n [&](const index::Relation& r) {\\n auto start = file_mapper.to_position(r.range.begin);\\n auto end = file_mapper.to_position(r.range.end);\\n if(start && end) {\\n callee_ranges[r.target_symbol].push_back(\\n protocol::Range{*start, *end});\\n }\\n return true;\\n });\\n }\\n\\n std::vector<protocol::CallHierarchyOutgoingCall> results;\\n for(auto& [callee_hash, ranges]: callee_ranges) {\\n auto def_loc = find_symbol_definition_location(callee_hash);\\n auto callee_sym_it = project_index.symbols.find(callee_hash);\\n if(callee_sym_it == project_index.symbols.end())\\n continue;\\n\\n if(!def_loc)\\n continue;\\n\\n protocol::CallHierarchyItem callee_item;\\n callee_item.name = callee_sym_it->second.name;\\n callee_item.kind = to_lsp_symbol_kind(callee_sym_it->second.kind);\\n callee_item.uri = def_loc->uri;\\n callee_item.range = def_loc->range;\\n callee_item.selection_range = def_loc->range;\\n callee_item.data = protocol::LSPAny(static_cast<std::int64_t>(callee_hash));\\n\\n protocol::CallHierarchyOutgoingCall call;\\n call.to = std::move(callee_item);\\n call.from_ranges = std::move(ranges);\\n results.push_back(std::move(call));\\n }\\n\\n if(results.empty())\\n co_return serde_raw{\\\"null\\\"};\\n co_return to_raw(results);\\n });\\n\\n // --- textDocument/prepareTypeHierarchy ---\\n peer.on_request([this](RequestContext& ctx,\\n const protocol::TypeHierarchyPrepareParams& params) -> RawResult {\\n auto info = co_await lookup_symbol_at_position(\\n params.text_document_position_params.text_document.uri,\\n params.text_document_position_params.position);\\n if(!info)\\n co_return serde_raw{\\\"null\\\"};\\n\\n // Only class-like types are valid for type hierarchy.\\n if(!(info->kind == SymbolKind::Class || info->kind == SymbolKind::Struct ||\\n info->kind == SymbolKind::Enum || info->kind == SymbolKind::Union))\\n co_return serde_raw{\\\"null\\\"};\\n\\n std::vector<protocol::TypeHierarchyItem> items;\\n items.push_back(build_type_hierarchy_item(*info));\\n co_return to_raw(items);\\n });\\n\\n // --- typeHierarchy/supertypes ---\\n peer.on_request([this](RequestContext& ctx,\\n const protocol::TypeHierarchySupertypesParams& params) -> RawResult {\\n auto info =\\n co_await resolve_hierarchy_item(params.item.uri, params.item.range, params.item.data);\\n if(!info)\\n co_return serde_raw{\\\"null\\\"};\\n\\n auto sym_it = project_index.symbols.find(info->hash);\\n if(sym_it == project_index.symbols.end())\\n co_return serde_raw{\\\"null\\\"};\\n\\n // Find Base relations: supertypes of this class.\\n std::vector<protocol::TypeHierarchyItem> results;\\n\\n for(auto file_id: sym_it->second.reference_files) {\\n auto file_merged_it = merged_indices.find(file_id);\\n if(file_merged_it == merged_indices.end())\\n continue;\\n\\n file_merged_it->second.lookup(\\n info->hash,\\n RelationKind::Base,\\n [&](const index::Relation& r) {\\n auto base_hash = r.target_symbol;\\n auto base_sym_it = project_index.symbols.find(base_hash);\\n if(base_sym_it == project_index.symbols.end())\\n return true;\\n\\n // Find the definition location of the base class.\\n auto def_loc = find_symbol_definition_location(base_hash);\\n if(!def_loc)\\n return true;\\n\\n protocol::TypeHierarchyItem item;\\n item.name = base_sym_it->second.name;\\n item.kind = to_lsp_symbol_kind(base_sym_it->second.kind);\\n item.uri = def_loc->uri;\\n item.range = def_loc->range;\\n item.selection_range = def_loc->range;\\n item.data = protocol::LSPAny(static_cast<std::int64_t>(base_hash));\\n results.push_back(std::move(item));\\n return true;\\n });\\n }\\n\\n if(results.empty())\\n co_return serde_raw{\\\"null\\\"};\\n co_return to_raw(results);\\n });\\n\\n // --- typeHierarchy/subtypes ---\\n peer.on_request([this](RequestContext& ctx,\\n const protocol::TypeHierarchySubtypesParams& params) -> RawResult {\\n auto info =\\n co_await resolve_hierarchy_item(params.item.uri, params.item.range, params.item.data);\\n if(!info)\\n co_return serde_raw{\\\"null\\\"};\\n\\n auto sym_it = project_index.symbols.find(info->hash);\\n if(sym_it == project_index.symbols.end())\\n co_return serde_raw{\\\"null\\\"};\\n\\n // Find Derived relations across all reference files: subtypes of this class.\\n std::vector<protocol::TypeHierarchyItem> results;\\n\\n for(auto file_id: sym_it->second.reference_files) {\\n auto file_merged_it = merged_indices.find(file_id);\\n if(file_merged_it == merged_indices.end())\\n continue;\\n\\n file_merged_it->second.lookup(\\n info->hash,\\n RelationKind::Derived,\\n [&](const index::Relation& r) {\\n auto derived_hash = r.target_symbol;\\n auto derived_sym_it = project_index.symbols.find(derived_hash);\\n if(derived_sym_it == project_index.symbols.end())\\n return true;\\n\\n auto def_loc = find_symbol_definition_location(derived_hash);\\n if(!def_loc)\\n return true;\\n\\n protocol::TypeHierarchyItem item;\\n item.name = derived_sym_it->second.name;\\n item.kind = to_lsp_symbol_kind(derived_sym_it->second.kind);\\n item.uri = def_loc->uri;\\n item.range = def_loc->range;\\n item.selection_range = def_loc->range;\\n item.data = protocol::LSPAny(static_cast<std::int64_t>(derived_hash));\\n results.push_back(std::move(item));\\n return true;\\n });\\n }\\n\\n if(results.empty())\\n co_return serde_raw{\\\"null\\\"};\\n co_return to_raw(results);\\n });\\n\\n // --- workspace/symbol ---\\n peer.on_request(\\n [this](RequestContext& ctx, const protocol::WorkspaceSymbolParams& params) -> RawResult {\\n auto query = llvm::StringRef(params.query);\\n std::vector<protocol::SymbolInformation> results;\\n\\n // Case-insensitive substring match on symbol names.\\n std::string query_lower = query.lower();\\n\\n for(auto& [hash, symbol]: project_index.symbols) {\\n if(results.size() >= 100)\\n break;\\n\\n // Skip non-indexable symbol kinds (punctuation, literals, etc.)\\n // Skip non-indexable symbol kinds using a positive check instead.\\n auto sk = symbol.kind;\\n if(!(sk == SymbolKind::Namespace || sk == SymbolKind::Class ||\\n sk == SymbolKind::Struct || sk == SymbolKind::Union ||\\n sk == SymbolKind::Enum || sk == SymbolKind::Type || sk == SymbolKind::Field ||\\n sk == SymbolKind::EnumMember || sk == SymbolKind::Function ||\\n sk == SymbolKind::Method || sk == SymbolKind::Variable ||\\n sk == SymbolKind::Parameter || sk == SymbolKind::Macro ||\\n sk == SymbolKind::Concept || sk == SymbolKind::Module ||\\n sk == SymbolKind::Operator || sk == SymbolKind::MacroParameter ||\\n sk == SymbolKind::Label || sk == SymbolKind::Attribute))\\n continue;\\n\\n if(symbol.name.empty())\\n continue;\\n\\n // Check case-insensitive substring match.\\n std::string name_lower = llvm::StringRef(symbol.name).lower();\\n if(!query_lower.empty() && name_lower.find(query_lower) == std::string::npos)\\n continue;\\n\\n auto def_loc = find_symbol_definition_location(hash);\\n if(!def_loc)\\n continue;\\n\\n protocol::SymbolInformation info;\\n info.name = symbol.name;\\n info.kind = to_lsp_symbol_kind(symbol.kind);\\n info.location = std::move(*def_loc);\\n results.push_back(std::move(info));\\n }\\n\\n if(results.empty())\\n co_return serde_raw{\\\"null\\\"};\\n co_return to_raw(results);\\n });\\n}\\n\\n} // namespace clice\\n\"}}}"}
|
||
{"ts":4744,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didOpen\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/src/server/master_server.h\",\"languageId\":\"cpp\",\"version\":1,\"text\":\"#pragma once\\n\\n#include <cstdint>\\n#include <memory>\\n#include <string>\\n\\n#include \\\"command/command.h\\\"\\n#include \\\"eventide/async/async.h\\\"\\n#include \\\"eventide/ipc/lsp/protocol.h\\\"\\n#include \\\"eventide/ipc/peer.h\\\"\\n#include \\\"eventide/serde/serde/raw_value.h\\\"\\n#include \\\"index/merged_index.h\\\"\\n#include \\\"index/project_index.h\\\"\\n#include \\\"semantic/relation_kind.h\\\"\\n#include \\\"server/compile_graph.h\\\"\\n#include \\\"server/config.h\\\"\\n#include \\\"server/worker_pool.h\\\"\\n#include \\\"support/path_pool.h\\\"\\n#include \\\"syntax/dependency_graph.h\\\"\\n\\n#include \\\"llvm/ADT/DenseMap.h\\\"\\n#include \\\"llvm/ADT/SmallVector.h\\\"\\n#include \\\"llvm/ADT/StringMap.h\\\"\\n#include \\\"llvm/ADT/StringRef.h\\\"\\n\\nnamespace clice {\\n\\nnamespace et = eventide;\\nnamespace protocol = et::ipc::protocol;\\n\\nenum class CompletionContext { None, IncludeQuoted, IncludeAngled, Import };\\n\\nstruct PreambleCompletionContext {\\n CompletionContext kind = CompletionContext::None;\\n std::string prefix;\\n};\\n\\nstruct DocumentState {\\n int version = 0;\\n\\n std::string text;\\n\\n std::uint64_t generation = 0;\\n\\n bool ast_dirty = true;\\n\\n /// Non-null while a compile is in flight. Other ensure_compiled() calls\\n /// wait on this instead of sending duplicate compile requests.\\n std::shared_ptr<et::event> compiling;\\n};\\n\\n/// Two-layer staleness snapshot for compilation artifacts (PCH, AST, etc.).\\n///\\n/// Layer 1 (fast): compare each file's current mtime against build_at.\\n/// If all mtimes <= build_at, the artifact is fresh (zero I/O beyond stat).\\n///\\n/// Layer 2 (precise): for files whose mtime changed, re-hash their content\\n/// and compare against the stored hash. If the hash matches, the file was\\n/// \\\"touched\\\" but not actually modified — skip the rebuild.\\n///\\n/// This avoids unnecessary recompilation from timestamp-only changes (e.g.\\n/// git checkout, touch, backup restore) while remaining cheap in the common\\n/// case where nothing changed.\\nstruct DepsSnapshot {\\n /// File path IDs interned via PathPool.\\n llvm::SmallVector<std::uint32_t> path_ids;\\n\\n /// xxh3_64bits of file content at build time.\\n llvm::SmallVector<std::uint64_t> hashes;\\n\\n /// time_t when this snapshot was captured.\\n std::int64_t build_at = 0;\\n};\\n\\n/// Cached PCH state for a single source file.\\nstruct PCHState {\\n /// Built PCH file path.\\n std::string path;\\n\\n /// Preamble byte offset used when building.\\n std::uint32_t bound = 0;\\n\\n /// xxh3 hash of preamble content.\\n std::uint64_t hash = 0;\\n\\n /// Dependency snapshot for staleness detection.\\n DepsSnapshot deps;\\n\\n /// Non-null while a build is in flight.\\n std::shared_ptr<et::event> building;\\n};\\n\\n/// Cached PCM state for a single module file.\\nstruct PCMState {\\n /// Built PCM file path.\\n std::string path;\\n\\n /// Dependency snapshot for staleness detection.\\n DepsSnapshot deps;\\n};\\n\\n/// Information about a symbol at a given position.\\nstruct SymbolInfo {\\n /// Unique hash identifying this symbol across the project.\\n index::SymbolHash hash = 0;\\n\\n /// Human-readable symbol name.\\n std::string name;\\n\\n /// Symbol kind (function, class, variable, etc.).\\n SymbolKind kind;\\n\\n /// URI of the file containing this symbol.\\n std::string uri;\\n\\n /// Source range of the symbol's identifier.\\n protocol::Range range;\\n};\\n\\nenum class ServerLifecycle : std::uint8_t {\\n Uninitialized,\\n Initialized,\\n Ready,\\n ShuttingDown,\\n Exited,\\n};\\n\\nclass MasterServer {\\npublic:\\n MasterServer(et::event_loop& loop, et::ipc::JsonPeer& peer, std::string self_path);\\n ~MasterServer();\\n\\n void register_handlers();\\n\\nprivate:\\n /// Event loop for scheduling async tasks.\\n et::event_loop& loop;\\n\\n /// JSON-RPC peer for LSP communication.\\n et::ipc::JsonPeer& peer;\\n\\n /// Pool of stateful/stateless worker processes.\\n WorkerPool pool;\\n\\n /// Interning pool for file paths (path string -> uint32_t ID).\\n PathPool path_pool;\\n\\n /// Current server lifecycle state.\\n ServerLifecycle lifecycle = ServerLifecycle::Uninitialized;\\n\\n /// Path to the clice binary itself.\\n std::string self_path;\\n\\n /// Root directory of the opened workspace.\\n std::string workspace_root;\\n\\n /// User/project configuration.\\n CliceConfig config;\\n\\n /// Session-specific log directory (e.g. .clice/logs/2026-04-05_10-30-00/).\\n std::string session_log_dir;\\n\\n /// Compilation database (compile_commands.json).\\n CompilationDatabase cdb;\\n\\n /// Include/module dependency graph built from fast lexer scanning.\\n DependencyGraph dependency_graph;\\n\\n /// Module compilation graph (lazy dependency resolution).\\n std::unique_ptr<CompileGraph> compile_graph;\\n\\n /// path_id -> built PCM output path (set after successful module build).\\n llvm::DenseMap<std::uint32_t, std::string> pcm_paths;\\n\\n /// path_id -> module name (for files that provide a module interface).\\n llvm::DenseMap<std::uint32_t, std::string> path_to_module;\\n\\n /// path_id -> cached PCH state (path, preamble hash, deps, build event).\\n llvm::DenseMap<std::uint32_t, PCHState> pch_states;\\n\\n /// path_id -> cached PCM state (path, deps).\\n llvm::DenseMap<std::uint32_t, PCMState> pcm_states;\\n\\n // === Index state ===\\n\\n /// Global symbol table and path mapping for the project.\\n index::ProjectIndex project_index;\\n\\n /// Per-file merged index shards (keyed by project-level path_id).\\n llvm::DenseMap<std::uint32_t, index::MergedIndex> merged_indices;\\n\\n /// Files queued for background indexing (server-level path_ids from CDB).\\n std::vector<std::uint32_t> index_queue;\\n\\n /// Index of next file to process in index_queue.\\n std::size_t index_queue_pos = 0;\\n\\n /// Whether background indexing is currently in progress.\\n bool indexing_active = false;\\n\\n /// Whether a background indexing coroutine has been scheduled (waiting on timer).\\n bool indexing_scheduled = false;\\n\\n /// Timer for idle-triggered background indexing.\\n std::shared_ptr<et::timer> index_idle_timer;\\n\\n /// path_id -> open document state (text, version, generation, dirty flag).\\n llvm::DenseMap<std::uint32_t, DocumentState> documents;\\n\\n /// Per-file dependency snapshots from last successful AST compilation.\\n llvm::DenseMap<std::uint32_t, DepsSnapshot> ast_deps;\\n\\n // === Helpers ===\\n\\n /// Convert a file:// URI to a local file path.\\n std::string uri_to_path(const std::string& uri);\\n\\n /// Publish diagnostics to the LSP client.\\n void publish_diagnostics(const std::string& uri,\\n int version,\\n const eventide::serde::RawValue& diagnostics_json);\\n\\n /// Clear diagnostics for a file (publish empty array).\\n void clear_diagnostics(const std::string& uri);\\n\\n /// Pull-based compilation entry point. Ensures AST is up-to-date.\\n et::task<bool> ensure_compiled(std::uint32_t path_id);\\n\\n /// Load CDB and build initial include/module dependency graph.\\n et::task<> load_workspace();\\n\\n /// Fill compile arguments from CDB for a given file.\\n bool fill_compile_args(llvm::StringRef path,\\n std::string& directory,\\n std::vector<std::string>& arguments);\\n\\n /// Build or reuse PCH for a source file. Returns true if PCH is available.\\n et::task<bool> ensure_pch(std::uint32_t path_id,\\n llvm::StringRef path,\\n const std::string& text,\\n const std::string& directory,\\n const std::vector<std::string>& arguments);\\n\\n /// Compile module dependencies, build/reuse PCH, and fill PCM paths.\\n /// Shared preparation step for ensure_compiled() and forward_stateless().\\n et::task<bool> ensure_deps(std::uint32_t path_id,\\n llvm::StringRef path,\\n const std::string& text,\\n const std::string& directory,\\n const std::vector<std::string>& arguments,\\n std::pair<std::string, uint32_t>& pch,\\n std::unordered_map<std::string, std::string>& pcms);\\n\\n /// Schedule background indexing when idle.\\n void schedule_indexing();\\n\\n /// Background indexing coroutine: picks files from queue and dispatches to workers.\\n et::task<> run_background_indexing();\\n\\n /// Merge a TUIndex result into ProjectIndex and MergedIndex shards.\\n void merge_index_result(const void* tu_index_data, std::size_t size);\\n\\n /// Persist index state to disk.\\n void save_index();\\n\\n /// Load index state from disk.\\n void load_index();\\n\\n /// Load PCH/PCM cache metadata from cache.json.\\n void load_cache();\\n\\n /// Save PCH/PCM cache metadata to cache.json.\\n void save_cache();\\n\\n /// Clean up stale cache files older than max_age_days.\\n void cleanup_cache(int max_age_days = 7);\\n\\n // === Include/import completion (handled in master) ===\\n\\n /// Detect whether the cursor is on an #include or import line.\\n PreambleCompletionContext detect_completion_context(const std::string& text, uint32_t offset);\\n\\n /// Complete #include paths by enumerating search directories.\\n et::serde::RawValue complete_include(const PreambleCompletionContext& ctx,\\n llvm::StringRef path);\\n\\n /// Complete import module names from the known module map.\\n et::serde::RawValue complete_import(const PreambleCompletionContext& ctx);\\n\\n // === Feature request forwarding ===\\n\\n using RawResult = et::task<et::serde::RawValue, et::ipc::Error>;\\n\\n /// Forward a simple stateful request (path-only worker params).\\n template <typename WorkerParams>\\n RawResult forward_stateful(const std::string& uri);\\n\\n /// Forward a stateful request with position-to-offset conversion.\\n template <typename WorkerParams>\\n RawResult forward_stateful(const std::string& uri, const protocol::Position& position);\\n\\n /// Forward a stateless request with document content and compile args.\\n template <typename WorkerParams>\\n RawResult forward_stateless(const std::string& uri, const protocol::Position& position);\\n\\n // === Index query helpers ===\\n\\n /// Query index for symbol relations (GoToDefinition, FindReferences, etc.).\\n RawResult query_index_relations(const std::string& uri,\\n const protocol::Position& position,\\n RelationKind kind);\\n\\n /// Look up a symbol at a position, returning its hash, name, kind, and range.\\n et::task<std::optional<SymbolInfo>>\\n lookup_symbol_at_position(const std::string& uri, const protocol::Position& position);\\n\\n /// Find the definition location (uri + range) of a symbol by its hash.\\n std::optional<protocol::Location> find_symbol_definition_location(index::SymbolHash hash);\\n\\n /// Convert clice::SymbolKind to LSP protocol::SymbolKind.\\n static protocol::SymbolKind to_lsp_symbol_kind(SymbolKind kind);\\n\\n /// Build a CallHierarchyItem from a SymbolInfo.\\n protocol::CallHierarchyItem build_call_hierarchy_item(const SymbolInfo& info);\\n\\n /// Build a TypeHierarchyItem from a SymbolInfo.\\n protocol::TypeHierarchyItem build_type_hierarchy_item(const SymbolInfo& info);\\n\\n /// Resolve SymbolInfo from a hierarchy item's stored data (symbol hash).\\n et::task<std::optional<SymbolInfo>>\\n resolve_hierarchy_item(const std::string& uri,\\n const protocol::Range& range,\\n const std::optional<protocol::LSPAny>& data);\\n};\\n\\n} // namespace clice\\n\"}}}"}
|
||
{"ts":4744,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didOpen\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/src/server/stateless_worker.cpp\",\"languageId\":\"cpp\",\"version\":1,\"text\":\"#include \\\"server/stateless_worker.h\\\"\\n\\n#include <chrono>\\n\\n#include \\\"compile/compilation.h\\\"\\n#include \\\"eventide/async/async.h\\\"\\n#include \\\"eventide/ipc/json_codec.h\\\"\\n#include \\\"eventide/ipc/peer.h\\\"\\n#include \\\"eventide/ipc/transport.h\\\"\\n#include \\\"eventide/serde/json/serializer.h\\\"\\n#include \\\"eventide/serde/serde/raw_value.h\\\"\\n#include \\\"feature/feature.h\\\"\\n#include \\\"index/tu_index.h\\\"\\n#include \\\"server/protocol.h\\\"\\n#include \\\"support/logging.h\\\"\\n\\n#include \\\"llvm/Support/raw_ostream.h\\\"\\n\\nnamespace clice {\\n\\nnamespace et = eventide;\\nusing et::ipc::RequestResult;\\nusing RequestContext = et::ipc::BincodePeer::RequestContext;\\n\\nstruct ScopedTimer {\\n std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();\\n\\n long long ms() const {\\n return std::chrono::duration_cast<std::chrono::milliseconds>(\\n std::chrono::steady_clock::now() - start)\\n .count();\\n }\\n};\\n\\nstatic void fill_args(CompilationParams& cp,\\n const std::string& directory,\\n const std::vector<std::string>& arguments) {\\n cp.directory = directory;\\n for(auto& arg: arguments) {\\n cp.arguments.push_back(arg.c_str());\\n }\\n}\\n\\ntemplate <typename T>\\nstatic et::serde::RawValue to_raw(const T& value) {\\n auto json = et::serde::json::to_json<et::ipc::lsp_config>(value);\\n return et::serde::RawValue{json ? std::move(*json) : \\\"null\\\"};\\n}\\n\\nint run_stateless_worker_mode(const std::string& worker_name, const std::string& log_dir) {\\n logging::stderr_logger(worker_name, logging::options);\\n if(!log_dir.empty()) {\\n logging::file_logger(worker_name, log_dir, logging::options);\\n }\\n\\n LOG_INFO(\\\"Starting stateless worker\\\");\\n\\n et::event_loop loop;\\n\\n auto transport_result = et::ipc::StreamTransport::open_stdio(loop);\\n if(!transport_result) {\\n LOG_ERROR(\\\"Failed to open stdio transport\\\");\\n return 1;\\n }\\n\\n et::ipc::BincodePeer peer(loop, std::move(*transport_result));\\n\\n // === BuildPCH ===\\n peer.on_request(\\n [&](RequestContext& ctx,\\n const worker::BuildPCHParams& params) -> RequestResult<worker::BuildPCHParams> {\\n LOG_INFO(\\\"BuildPCH request: file={}\\\", params.file);\\n\\n auto result = co_await et::queue([&]() -> worker::BuildPCHResult {\\n ScopedTimer timer;\\n\\n CompilationParams cp;\\n cp.kind = CompilationKind::Preamble;\\n fill_args(cp, params.directory, params.arguments);\\n cp.add_remapped_file(params.file, params.content, params.preamble_bound);\\n\\n // When output_path is set, write to .tmp then rename — avoids\\n // Windows file-lock failures when the target is held by another\\n // process. When empty, fall back to a temporary file.\\n std::string tmp_path;\\n bool has_output = !params.output_path.empty();\\n if(has_output) {\\n tmp_path = params.output_path + \\\".tmp\\\";\\n } else {\\n auto tmp = fs::createTemporaryFile(\\\"clice-pch\\\", \\\"pch\\\");\\n if(!tmp) {\\n LOG_ERROR(\\\"BuildPCH: failed to create temp file\\\");\\n return {false, \\\"Failed to create temporary PCH file\\\", \\\"\\\"};\\n }\\n tmp_path = *tmp;\\n }\\n cp.output_file = tmp_path;\\n\\n PCHInfo pch_info;\\n auto unit = compile(cp, pch_info);\\n bool success = unit.completed();\\n\\n // Extract error messages before destroying the unit.\\n std::string errors;\\n if(!success) {\\n for(auto& diag: unit.diagnostics()) {\\n if(diag.id.level >= DiagnosticLevel::Error) {\\n if(!errors.empty())\\n errors += \\\"; \\\";\\n errors += diag.message;\\n }\\n }\\n }\\n\\n // Destroy CompilationUnit to flush PCH file to disk\\n // (EndSourceFile serializes the AST on destruction).\\n unit = CompilationUnit(nullptr);\\n\\n if(success) {\\n std::string final_path;\\n if(has_output) {\\n auto ec = fs::rename(tmp_path, params.output_path);\\n if(ec) {\\n final_path = params.output_path;\\n } else {\\n LOG_WARN(\\\"BuildPCH: rename {} -> {} failed: {}\\\",\\n tmp_path,\\n params.output_path,\\n ec.error().message());\\n final_path = tmp_path;\\n }\\n } else {\\n final_path = tmp_path;\\n }\\n LOG_INFO(\\\"BuildPCH done: file={}, output={}, {}ms\\\",\\n params.file,\\n final_path,\\n timer.ms());\\n worker::BuildPCHResult pch_result{true, \\\"\\\", std::move(final_path)};\\n pch_result.deps = pch_info.deps;\\n return pch_result;\\n } else {\\n LOG_WARN(\\\"BuildPCH failed: file={}, {}ms, errors=[{}]\\\",\\n params.file,\\n timer.ms(),\\n errors);\\n fs::remove(tmp_path);\\n return {false, errors.empty() ? \\\"PCH compilation failed\\\" : errors, \\\"\\\"};\\n }\\n });\\n co_return result.value();\\n });\\n\\n // === BuildPCM ===\\n peer.on_request(\\n [&](RequestContext& ctx,\\n const worker::BuildPCMParams& params) -> RequestResult<worker::BuildPCMParams> {\\n LOG_INFO(\\\"BuildPCM request: file={}, module={}\\\", params.file, params.module_name);\\n\\n auto result = co_await et::queue([&]() -> worker::BuildPCMResult {\\n ScopedTimer timer;\\n\\n CompilationParams cp;\\n cp.kind = CompilationKind::ModuleInterface;\\n fill_args(cp, params.directory, params.arguments);\\n for(auto& [name, path]: params.pcms) {\\n cp.pcms.try_emplace(name, path);\\n }\\n\\n std::string tmp_path;\\n bool has_output = !params.output_path.empty();\\n if(has_output) {\\n tmp_path = params.output_path + \\\".tmp\\\";\\n } else {\\n auto tmp = fs::createTemporaryFile(\\\"clice-pcm\\\", \\\"pcm\\\");\\n if(!tmp) {\\n LOG_ERROR(\\\"BuildPCM: failed to create temp file\\\");\\n return {false, \\\"Failed to create temporary PCM file\\\", \\\"\\\"};\\n }\\n tmp_path = *tmp;\\n }\\n cp.output_file = tmp_path;\\n\\n PCMInfo pcm_info;\\n auto unit = compile(cp, pcm_info);\\n bool success = unit.completed();\\n\\n std::string errors;\\n if(!success) {\\n for(auto& diag: unit.diagnostics()) {\\n if(diag.id.level >= DiagnosticLevel::Error) {\\n if(!errors.empty())\\n errors += \\\"; \\\";\\n errors += diag.message;\\n }\\n }\\n }\\n\\n unit = CompilationUnit(nullptr);\\n\\n if(success) {\\n std::string final_path = tmp_path;\\n if(has_output) {\\n auto ec = fs::rename(tmp_path, params.output_path);\\n if(ec) {\\n final_path = params.output_path;\\n } else {\\n LOG_WARN(\\\"BuildPCM: rename {} -> {} failed: {}\\\",\\n tmp_path,\\n params.output_path,\\n ec.error().message());\\n }\\n }\\n LOG_INFO(\\\"BuildPCM done: module={}, {}ms\\\", params.module_name, timer.ms());\\n worker::BuildPCMResult pcm_result{true, \\\"\\\", std::move(final_path)};\\n pcm_result.deps = pcm_info.deps;\\n return pcm_result;\\n } else {\\n LOG_WARN(\\\"BuildPCM failed: module={}, {}ms, errors=[{}]\\\",\\n params.module_name,\\n timer.ms(),\\n errors);\\n fs::remove(tmp_path);\\n return {false, errors.empty() ? \\\"PCM compilation failed\\\" : errors, \\\"\\\"};\\n }\\n });\\n co_return result.value();\\n });\\n\\n // === Completion ===\\n peer.on_request(\\n [&](RequestContext& ctx,\\n const worker::CompletionParams& params) -> RequestResult<worker::CompletionParams> {\\n LOG_DEBUG(\\\"Completion request: path={}, offset={}\\\", params.path, params.offset);\\n\\n auto result = co_await et::queue([&]() -> et::serde::RawValue {\\n ScopedTimer timer;\\n\\n CompilationParams cp;\\n cp.kind = CompilationKind::Completion;\\n fill_args(cp, params.directory, params.arguments);\\n if(!params.pch.first.empty()) {\\n cp.pch = params.pch;\\n }\\n for(auto& [name, path]: params.pcms) {\\n cp.pcms.try_emplace(name, path);\\n }\\n cp.add_remapped_file(params.path, params.text);\\n cp.completion = {params.path, params.offset};\\n\\n auto items = feature::code_complete(cp);\\n LOG_DEBUG(\\\"Completion done: {} items, {}ms\\\", items.size(), timer.ms());\\n return to_raw(items);\\n });\\n co_return result.value();\\n });\\n\\n // === SignatureHelp ===\\n peer.on_request([&](RequestContext& ctx, const worker::SignatureHelpParams& params)\\n -> RequestResult<worker::SignatureHelpParams> {\\n LOG_DEBUG(\\\"SignatureHelp request: path={}, offset={}\\\", params.path, params.offset);\\n\\n auto result = co_await et::queue([&]() -> et::serde::RawValue {\\n ScopedTimer timer;\\n\\n CompilationParams cp;\\n cp.kind = CompilationKind::Completion;\\n fill_args(cp, params.directory, params.arguments);\\n if(!params.pch.first.empty()) {\\n cp.pch = params.pch;\\n }\\n for(auto& [name, path]: params.pcms) {\\n cp.pcms.try_emplace(name, path);\\n }\\n cp.add_remapped_file(params.path, params.text);\\n cp.completion = {params.path, params.offset};\\n\\n auto help = feature::signature_help(cp);\\n LOG_DEBUG(\\\"SignatureHelp done: {}ms\\\", timer.ms());\\n return to_raw(help);\\n });\\n co_return result.value();\\n });\\n\\n // === Index ===\\n peer.on_request([&](RequestContext& ctx,\\n const worker::IndexParams& params) -> RequestResult<worker::IndexParams> {\\n LOG_INFO(\\\"Index request: file={}\\\", params.file);\\n\\n auto result = co_await et::queue([&]() -> worker::IndexResult {\\n ScopedTimer timer;\\n\\n CompilationParams cp;\\n cp.kind = CompilationKind::Indexing;\\n fill_args(cp, params.directory, params.arguments);\\n for(auto& [name, path]: params.pcms) {\\n cp.pcms.try_emplace(name, path);\\n }\\n\\n auto unit = compile(cp);\\n\\n if(!unit.completed()) {\\n LOG_WARN(\\\"Index failed: file={}, {}ms\\\", params.file, timer.ms());\\n return {false, \\\"Index compilation failed\\\", \\\"\\\"};\\n }\\n\\n auto tu_index = index::TUIndex::build(unit);\\n\\n std::string serialized;\\n llvm::raw_string_ostream os(serialized);\\n tu_index.serialize(os);\\n\\n LOG_INFO(\\\"Index done: file={}, {} symbols, {}ms\\\",\\n params.file,\\n tu_index.symbols.size(),\\n timer.ms());\\n return {true, \\\"\\\", std::move(serialized)};\\n });\\n co_return result.value();\\n });\\n\\n LOG_INFO(\\\"Stateless worker ready, waiting for requests\\\");\\n loop.schedule(peer.run());\\n auto ret = loop.run();\\n LOG_INFO(\\\"Stateless worker exiting with code {}\\\", ret);\\n return ret;\\n}\\n\\n} // namespace clice\\n\"}}}"}
|
||
{"ts":4745,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didOpen\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/src/server/worker_pool.cpp\",\"languageId\":\"cpp\",\"version\":1,\"text\":\"#include \\\"server/worker_pool.h\\\"\\n\\n#include <csignal>\\n#include <string>\\n\\n#include \\\"eventide/ipc/transport.h\\\"\\n#include \\\"support/logging.h\\\"\\n\\nnamespace clice {\\n\\nnamespace {\\n\\n/// Coroutine that drains a worker's stderr pipe.\\n/// Workers write their own log files, so this only captures unexpected output\\n/// (crash stacktraces, assertion failures, etc.) that bypasses spdlog.\\net::task<> drain_stderr(et::pipe stderr_pipe, std::string prefix) {\\n std::string buffer;\\n while(true) {\\n auto result = co_await stderr_pipe.read();\\n if(!result.has_value()) {\\n break;\\n }\\n auto& chunk = result.value();\\n if(chunk.empty())\\n break;\\n\\n buffer += chunk;\\n\\n std::size_t pos = 0;\\n while(true) {\\n auto nl = buffer.find('\\\\n', pos);\\n if(nl == std::string::npos)\\n break;\\n auto line = buffer.substr(pos, nl - pos);\\n if(!line.empty()) {\\n LOG_DEBUG(\\\"{} {}\\\", prefix, line);\\n }\\n pos = nl + 1;\\n }\\n buffer.erase(0, pos);\\n }\\n\\n if(!buffer.empty()) {\\n LOG_DEBUG(\\\"{} {}\\\", prefix, buffer);\\n }\\n}\\n\\n} // namespace\\n\\nbool WorkerPool::spawn_worker(const std::string& self_path,\\n bool stateful,\\n std::uint64_t memory_limit) {\\n auto& workers = stateful ? stateful_workers : stateless_workers;\\n auto worker_index = workers.size();\\n std::string worker_name = std::string(stateful ? \\\"SF-\\\" : \\\"SL-\\\") + std::to_string(worker_index);\\n\\n et::process::options opts;\\n opts.file = self_path;\\n if(stateful) {\\n opts.args = {self_path,\\n \\\"--mode\\\",\\n \\\"stateful-worker\\\",\\n \\\"--worker-memory-limit\\\",\\n std::to_string(memory_limit)};\\n } else {\\n opts.args = {self_path, \\\"--mode\\\", \\\"stateless-worker\\\"};\\n }\\n\\n opts.args.push_back(\\\"--worker-name\\\");\\n opts.args.push_back(worker_name);\\n\\n if(!log_dir_.empty()) {\\n opts.args.push_back(\\\"--log-dir\\\");\\n opts.args.push_back(log_dir_);\\n }\\n\\n opts.streams = {\\n et::process::stdio::pipe(true, false), // stdin: child reads\\n et::process::stdio::pipe(false, true), // stdout: child writes\\n et::process::stdio::pipe(false, true), // stderr: child writes\\n };\\n\\n auto result = et::process::spawn(opts, loop);\\n if(!result) {\\n LOG_ERROR(\\\"Failed to spawn {} worker: {}\\\",\\n stateful ? \\\"stateful\\\" : \\\"stateless\\\",\\n result.error().message());\\n return false;\\n }\\n\\n auto& spawn = *result;\\n\\n // StreamTransport: input = child's stdout (parent reads), output = child's stdin (parent\\n // writes)\\n auto transport = std::make_unique<et::ipc::StreamTransport>(std::move(spawn.stdout_pipe),\\n std::move(spawn.stdin_pipe));\\n auto peer = std::make_unique<et::ipc::BincodePeer>(loop, std::move(transport));\\n\\n // Schedule stderr log collection\\n std::string prefix = \\\"[\\\" + worker_name + \\\"]\\\";\\n loop.schedule(drain_stderr(std::move(spawn.stderr_pipe), prefix));\\n\\n workers.push_back(WorkerProcess{\\n .proc = std::move(spawn.proc),\\n .peer = std::move(peer),\\n .owned_documents = 0,\\n });\\n\\n auto& w = workers.back();\\n w.peer->set_logger(\\n [prefix](et::ipc::LogLevel, std::string_view msg) {\\n LOG_INFO(\\\"{} ipc: {}\\\", prefix, msg);\\n },\\n et::ipc::LogLevel::debug);\\n loop.schedule(w.peer->run());\\n\\n return true;\\n}\\n\\nbool WorkerPool::start(const WorkerPoolOptions& options) {\\n log_dir_ = options.log_dir;\\n\\n for(std::uint32_t i = 0; i < options.stateless_count; ++i) {\\n if(!spawn_worker(options.self_path, false, 0)) {\\n return false;\\n }\\n }\\n\\n for(std::uint32_t i = 0; i < options.stateful_count; ++i) {\\n if(!spawn_worker(options.self_path, true, options.worker_memory_limit)) {\\n return false;\\n }\\n }\\n\\n // Register evicted notification handler for each stateful worker\\n for(std::size_t i = 0; i < stateful_workers.size(); ++i) {\\n stateful_workers[i].peer->on_notification([this](const worker::EvictedParams& params) {\\n if(on_evicted) {\\n on_evicted(params.path);\\n }\\n });\\n }\\n\\n LOG_INFO(\\\"WorkerPool started: {} stateless, {} stateful workers\\\",\\n stateless_workers.size(),\\n stateful_workers.size());\\n return true;\\n}\\n\\net::task<> WorkerPool::stop() {\\n LOG_INFO(\\\"WorkerPool stopping...\\\");\\n\\n // Close output pipes to signal workers to exit gracefully\\n for(auto& w: stateless_workers) {\\n w.peer->close_output();\\n }\\n for(auto& w: stateful_workers) {\\n w.peer->close_output();\\n }\\n\\n // Send SIGTERM to all workers\\n for(auto& w: stateless_workers) {\\n w.proc.kill(SIGTERM);\\n }\\n for(auto& w: stateful_workers) {\\n w.proc.kill(SIGTERM);\\n }\\n\\n // Wait for all worker processes to exit\\n for(auto& w: stateless_workers) {\\n co_await w.proc.wait();\\n }\\n for(auto& w: stateful_workers) {\\n co_await w.proc.wait();\\n }\\n\\n LOG_INFO(\\\"WorkerPool stopped\\\");\\n}\\n\\nstd::size_t WorkerPool::assign_worker(std::uint32_t path_id) {\\n auto it = owner.find(path_id);\\n if(it != owner.end()) {\\n // Already assigned; touch LRU\\n auto lru_it = owner_lru_index.find(path_id);\\n if(lru_it != owner_lru_index.end()) {\\n owner_lru.erase(lru_it->second);\\n }\\n owner_lru.push_front(path_id);\\n owner_lru_index[path_id] = owner_lru.begin();\\n return it->second;\\n }\\n\\n // New assignment: pick the least-loaded worker\\n auto selected = pick_least_loaded();\\n owner[path_id] = selected;\\n stateful_workers[selected].owned_documents++;\\n owner_lru.push_front(path_id);\\n owner_lru_index[path_id] = owner_lru.begin();\\n return selected;\\n}\\n\\nstd::size_t WorkerPool::pick_least_loaded() {\\n std::size_t best = 0;\\n for(std::size_t i = 1; i < stateful_workers.size(); ++i) {\\n if(stateful_workers[i].owned_documents < stateful_workers[best].owned_documents) {\\n best = i;\\n }\\n }\\n return best;\\n}\\n\\nvoid WorkerPool::remove_owner(std::uint32_t path_id) {\\n auto it = owner.find(path_id);\\n if(it == owner.end())\\n return;\\n\\n auto worker_idx = it->second;\\n stateful_workers[worker_idx].owned_documents--;\\n owner.erase(it);\\n\\n auto lru_it = owner_lru_index.find(path_id);\\n if(lru_it != owner_lru_index.end()) {\\n owner_lru.erase(lru_it->second);\\n owner_lru_index.erase(lru_it);\\n }\\n}\\n\\nvoid WorkerPool::clear_owner(std::size_t worker_index) {\\n llvm::SmallVector<std::uint32_t> to_remove;\\n for(auto& [pid, widx]: owner) {\\n if(widx == worker_index) {\\n to_remove.push_back(pid);\\n }\\n }\\n for(auto pid: to_remove) {\\n remove_owner(pid);\\n }\\n}\\n\\n} // namespace clice\\n\"}}}"}
|
||
{"ts":4745,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didOpen\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/src/syntax/scan.cpp\",\"languageId\":\"cpp\",\"version\":1,\"text\":\"#include \\\"syntax/scan.h\\\"\\n\\n#include <deque>\\n\\n#include \\\"syntax/lexer.h\\\"\\n\\n#include \\\"llvm/ADT/StringSet.h\\\"\\n#include \\\"llvm/Support/MemoryBuffer.h\\\"\\n#include \\\"clang/Basic/DiagnosticOptions.h\\\"\\n#include \\\"clang/Basic/FileEntry.h\\\"\\n#include \\\"clang/Basic/FileManager.h\\\"\\n#include \\\"clang/Basic/SourceManager.h\\\"\\n#include \\\"clang/Frontend/CompilerInstance.h\\\"\\n#include \\\"clang/Frontend/FrontendActions.h\\\"\\n#include \\\"clang/Lex/PPCallbacks.h\\\"\\n#include \\\"clang/Lex/Preprocessor.h\\\"\\n#include \\\"clang/Lex/PreprocessorOptions.h\\\"\\n#include \\\"clang/Tooling/CompilationDatabase.h\\\"\\n\\nnamespace clice {\\n\\nScanResult scan(llvm::StringRef content) {\\n namespace dds = clang::dependency_directives_scan;\\n\\n ScanResult result;\\n\\n llvm::SmallVector<dds::Token> tokens;\\n llvm::SmallVector<dds::Directive> directives;\\n\\n if(clang::scanSourceForDependencyDirectives(content, tokens, directives)) {\\n return result;\\n }\\n\\n // Most source files have 10-30 includes; pre-allocate to avoid reallocs.\\n result.includes.reserve(std::min<std::size_t>(directives.size(), 32));\\n\\n int conditional_depth = 0;\\n\\n for(auto& dir: directives) {\\n switch(dir.Kind) {\\n case dds::pp_if:\\n case dds::pp_ifdef:\\n case dds::pp_ifndef: {\\n conditional_depth++;\\n break;\\n }\\n case dds::pp_endif: {\\n if(conditional_depth > 0) {\\n conditional_depth--;\\n }\\n break;\\n }\\n case dds::pp_elif:\\n case dds::pp_elifdef:\\n case dds::pp_elifndef:\\n case dds::pp_else: {\\n break;\\n }\\n case dds::pp_include:\\n case dds::pp_include_next:\\n case dds::pp___include_macros: {\\n // Find the header token (string_literal or header_name).\\n for(auto& tok: dir.Tokens) {\\n if(tok.is(clang::tok::header_name) || tok.is(clang::tok::string_literal)) {\\n auto name = content.substr(tok.Offset, tok.Length);\\n // Strip <> or \\\"\\\" delimiters.\\n if(name.size() >= 2) {\\n bool angled = name.front() == '<';\\n ScanResult::IncludeInfo info;\\n info.path = std::string(name.substr(1, name.size() - 2));\\n info.conditional = conditional_depth > 0;\\n info.is_angled = angled;\\n info.is_include_next = dir.Kind == dds::pp_include_next;\\n result.includes.push_back(std::move(info));\\n }\\n break;\\n }\\n }\\n break;\\n }\\n case dds::cxx_module_decl:\\n case dds::cxx_export_module_decl: {\\n if(conditional_depth > 0) {\\n result.need_preprocess = true;\\n return result;\\n }\\n\\n // Collect module name from tokens: skip keywords, then\\n // collect identifiers, '.', ':'.\\n std::string module_name;\\n bool seen_module_keyword = false;\\n for(auto& tok: dir.Tokens) {\\n if(!seen_module_keyword) {\\n if(tok.is(clang::tok::raw_identifier)) {\\n auto spelling = content.substr(tok.Offset, tok.Length);\\n if(spelling == \\\"module\\\") {\\n seen_module_keyword = true;\\n }\\n }\\n continue;\\n }\\n if(tok.is(clang::tok::raw_identifier)) {\\n module_name += content.substr(tok.Offset, tok.Length);\\n } else if(tok.is(clang::tok::period)) {\\n module_name += '.';\\n } else if(tok.is(clang::tok::colon)) {\\n module_name += ':';\\n }\\n }\\n\\n result.module_name = std::move(module_name);\\n result.is_interface_unit = (dir.Kind == dds::cxx_export_module_decl);\\n break;\\n }\\n default: {\\n break;\\n }\\n }\\n }\\n\\n return result;\\n}\\n\\nnamespace {\\n\\nclass ScanDirectivesGetter : public clang::DependencyDirectivesGetter {\\npublic:\\n ScanDirectivesGetter(SharedScanCache* cache, clang::FileManager& file_mgr) :\\n cache(cache), file_mgr(&file_mgr) {}\\n\\n std::unique_ptr<clang::DependencyDirectivesGetter>\\n cloneFor(clang::FileManager& new_file_mgr) override {\\n return std::make_unique<ScanDirectivesGetter>(cache, new_file_mgr);\\n }\\n\\n std::optional<llvm::ArrayRef<clang::dependency_directives_scan::Directive>>\\n operator()(clang::FileEntryRef file) override {\\n auto path = file.getFileEntry().tryGetRealPathName();\\n if(path.empty()) {\\n path = file.getName();\\n }\\n\\n // Check cache first.\\n if(cache) {\\n auto it = cache->entries.find(path);\\n if(it != cache->entries.end()) {\\n return llvm::ArrayRef(it->second.directives);\\n }\\n }\\n\\n // Read the file content.\\n auto buffer = file_mgr->getBufferForFile(file);\\n if(!buffer) {\\n return std::nullopt;\\n }\\n\\n auto source = (*buffer)->getBuffer().str();\\n\\n // Create entry in its final location first, then scan into it.\\n // Directive::Tokens are ArrayRefs pointing into the tokens SmallVector,\\n // so the entry must not be moved after scanning.\\n SharedScanCache::CachedEntry* entry_ptr;\\n if(cache) {\\n auto [it, _] = cache->entries.try_emplace(path);\\n entry_ptr = &it->second;\\n } else {\\n local_entries.emplace_back();\\n entry_ptr = &local_entries.back();\\n }\\n\\n entry_ptr->source = std::move(source);\\n\\n if(clang::scanSourceForDependencyDirectives(entry_ptr->source,\\n entry_ptr->tokens,\\n entry_ptr->directives)) {\\n // Scan failed — remove the entry.\\n if(cache) {\\n cache->entries.erase(path);\\n } else {\\n local_entries.pop_back();\\n }\\n return std::nullopt;\\n }\\n\\n return llvm::ArrayRef(entry_ptr->directives);\\n }\\n\\nprivate:\\n SharedScanCache* cache;\\n clang::FileManager* file_mgr;\\n std::deque<SharedScanCache::CachedEntry> local_entries;\\n};\\n\\n/// PPCallbacks for precise mode: single ScanResult with accurate\\n/// conditional tracking via preprocessor callbacks.\\nclass PreciseScanPPCallbacks : public clang::PPCallbacks {\\npublic:\\n explicit PreciseScanPPCallbacks(ScanResult& result) : result(result) {}\\n\\n void InclusionDirective(clang::SourceLocation,\\n const clang::Token& include_tok,\\n llvm::StringRef file_name,\\n bool is_angled,\\n clang::CharSourceRange,\\n clang::OptionalFileEntryRef file,\\n llvm::StringRef,\\n llvm::StringRef,\\n const clang::Module*,\\n bool,\\n clang::SrcMgr::CharacteristicKind) override {\\n bool not_found = !file.has_value();\\n std::string resolved_path;\\n if(file) {\\n resolved_path = file->getFileEntry().tryGetRealPathName().str();\\n } else {\\n resolved_path = file_name.str();\\n }\\n\\n ScanResult::IncludeInfo info;\\n info.path = std::move(resolved_path);\\n info.conditional = conditional_depth > 0;\\n info.not_found = not_found;\\n info.is_angled = is_angled;\\n info.is_include_next =\\n include_tok.getIdentifierInfo() &&\\n include_tok.getIdentifierInfo()->getPPKeywordID() == clang::tok::pp_include_next;\\n result.includes.push_back(std::move(info));\\n }\\n\\n void If(clang::SourceLocation, clang::SourceRange, ConditionValueKind) override {\\n conditional_depth++;\\n }\\n\\n void Ifdef(clang::SourceLocation, const clang::Token&, const clang::MacroDefinition&) override {\\n conditional_depth++;\\n }\\n\\n void Ifndef(clang::SourceLocation,\\n const clang::Token&,\\n const clang::MacroDefinition&) override {\\n conditional_depth++;\\n }\\n\\n void Endif(clang::SourceLocation, clang::SourceLocation) override {\\n if(conditional_depth > 0) {\\n conditional_depth--;\\n }\\n }\\n\\n void moduleImport(clang::SourceLocation,\\n clang::ModuleIdPath names,\\n const clang::Module*) override {\\n std::string name;\\n for(auto& part: names) {\\n if(!name.empty()) {\\n name += '.';\\n }\\n name += part.getIdentifierInfo()->getName();\\n }\\n result.modules.emplace_back(std::move(name));\\n }\\n\\nprivate:\\n ScanResult& result;\\n int conditional_depth = 0;\\n};\\n\\n/// Create and configure a CompilerInstance for scanning.\\n/// If content is non-empty, it is used as remapped source for the main file.\\nstd::unique_ptr<clang::CompilerInstance>\\n create_scan_instance(llvm::ArrayRef<const char*> arguments,\\n llvm::StringRef directory,\\n llvm::StringRef content,\\n llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs) {\\n clang::DiagnosticOptions diag_opts;\\n auto diag_engine = clang::CompilerInstance::createDiagnostics(*vfs,\\n diag_opts,\\n new clang::IgnoringDiagConsumer(),\\n true);\\n\\n std::unique_ptr<clang::CompilerInvocation> invocation;\\n\\n bool is_cc1 = arguments.size() >= 2 && llvm::StringRef(arguments[1]) == \\\"-cc1\\\";\\n if(is_cc1) {\\n invocation = std::make_unique<clang::CompilerInvocation>();\\n if(!clang::CompilerInvocation::CreateFromArgs(*invocation,\\n llvm::ArrayRef(arguments).drop_front(2),\\n *diag_engine,\\n arguments[0])) {\\n return nullptr;\\n }\\n } else {\\n clang::CreateInvocationOptions options = {\\n .Diags = diag_engine,\\n .VFS = vfs,\\n .ProbePrecompiled = false,\\n };\\n invocation = clang::createInvocation(arguments, options);\\n if(!invocation) {\\n return nullptr;\\n }\\n }\\n\\n invocation->getFrontendOpts().DisableFree = false;\\n invocation->getFileSystemOpts().WorkingDir = directory.str();\\n\\n if(!content.empty()) {\\n auto& inputs = invocation->getFrontendOpts().Inputs;\\n if(!inputs.empty()) {\\n auto main_file = inputs[0].getFile();\\n // Use an overlay VFS to inject the remapped content. This ensures\\n // both the preprocessor and the DependencyDirectivesGetter see it.\\n auto overlay = llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(vfs);\\n auto mem_fs = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();\\n mem_fs->addFile(main_file, 0, llvm::MemoryBuffer::getMemBufferCopy(content, main_file));\\n overlay->pushOverlay(std::move(mem_fs));\\n vfs = std::move(overlay);\\n }\\n }\\n\\n auto instance = std::make_unique<clang::CompilerInstance>(std::move(invocation));\\n instance->createDiagnostics(*vfs, new clang::IgnoringDiagConsumer(), true);\\n instance->getDiagnostics().setSuppressAllDiagnostics(true);\\n instance->createFileManager(vfs);\\n\\n return instance;\\n}\\n\\n} // namespace\\n\\nScanResult scan_precise(llvm::ArrayRef<const char*> arguments,\\n llvm::StringRef directory,\\n llvm::StringRef content,\\n SharedScanCache* cache,\\n llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs) {\\n ScanResult result;\\n\\n if(!vfs) {\\n vfs = llvm::vfs::createPhysicalFileSystem();\\n }\\n\\n auto instance = create_scan_instance(arguments, directory, content, vfs);\\n if(!instance) {\\n return result;\\n }\\n\\n auto getter = std::make_unique<ScanDirectivesGetter>(cache, instance->getFileManager());\\n instance->setDependencyDirectivesGetter(std::move(getter));\\n\\n if(!instance->createTarget()) {\\n return result;\\n }\\n\\n auto action = std::make_unique<clang::PreprocessOnlyAction>();\\n\\n if(!action->BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0])) {\\n return result;\\n }\\n\\n instance->getPreprocessor().addPPCallbacks(std::make_unique<PreciseScanPPCallbacks>(result));\\n\\n if(auto error = action->Execute()) {\\n llvm::consumeError(std::move(error));\\n }\\n\\n action->EndSourceFile();\\n\\n // Get module name from preprocessor.\\n auto& pp = instance->getPreprocessor();\\n if(pp.isInNamedModule()) {\\n result.module_name = pp.getNamedModuleName();\\n result.is_interface_unit = pp.isInNamedInterfaceUnit();\\n }\\n\\n return result;\\n}\\n\\nScanResult scan_module_decl(llvm::ArrayRef<const char*> arguments,\\n llvm::StringRef directory,\\n llvm::StringRef content,\\n SharedScanCache* cache,\\n llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs) {\\n ScanResult result;\\n\\n if(!vfs) {\\n vfs = llvm::vfs::createPhysicalFileSystem();\\n }\\n\\n auto instance = create_scan_instance(arguments, directory, content, vfs);\\n if(!instance) {\\n return result;\\n }\\n\\n auto getter = std::make_unique<ScanDirectivesGetter>(cache, instance->getFileManager());\\n instance->setDependencyDirectivesGetter(std::move(getter));\\n\\n if(!instance->createTarget()) {\\n return result;\\n }\\n\\n auto action = std::make_unique<clang::PreprocessOnlyAction>();\\n\\n if(!action->BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0])) {\\n return result;\\n }\\n\\n // Instead of action->Execute() which processes the entire file,\\n // manually lex tokens and stop as soon as the module declaration is found.\\n auto& pp = instance->getPreprocessor();\\n pp.EnterMainSourceFile();\\n\\n clang::Token tok;\\n do {\\n pp.Lex(tok);\\n if(pp.isInNamedModule()) {\\n result.module_name = pp.getNamedModuleName();\\n result.is_interface_unit = pp.isInNamedInterfaceUnit();\\n break;\\n }\\n } while(tok.isNot(clang::tok::eof));\\n\\n action->EndSourceFile();\\n\\n return result;\\n}\\n\\nstd::uint32_t compute_preamble_bound(llvm::StringRef content) {\\n auto result = compute_preamble_bounds(content);\\n if(result.empty()) {\\n return 0;\\n } else {\\n return result.back();\\n }\\n}\\n\\nstd::vector<std::uint32_t> compute_preamble_bounds(llvm::StringRef content) {\\n std::vector<std::uint32_t> result;\\n\\n Lexer lexer(content, true, nullptr, false);\\n\\n while(true) {\\n auto token = lexer.advance();\\n if(token.is_eof()) {\\n break;\\n }\\n\\n if(token.is_at_start_of_line) {\\n if(token.kind == clang::tok::hash) {\\n /// For preprocessor directive, consume the whole directive.\\n lexer.advance_until(clang::tok::eod);\\n auto last = lexer.last();\\n\\n /// Append the token before the eod.\\n result.push_back(last.range.end);\\n } else if(token.is_identifier() && token.text(content) == \\\"module\\\") {\\n /// If we encounter a module keyword at the start of a line, it may be\\n /// a module declaration or global module fragment.\\n auto next = lexer.next();\\n\\n if(next.kind == clang::tok::semi) {\\n /// If next token is `;`, it is a global module fragment.\\n /// we just continue.\\n lexer.advance();\\n\\n /// Append it to bounds.\\n result.push_back(next.range.end);\\n } else {\\n break;\\n }\\n } else {\\n break;\\n }\\n }\\n }\\n\\n return result;\\n}\\n\\n/// Check if a preprocessor #include/#import directive line is complete.\\nstatic bool is_include_directive_complete(llvm::StringRef directive) {\\n if(directive.contains('\\\"')) {\\n auto after_keyword = directive.drop_front(directive.starts_with(\\\"import\\\") ? 6 : 7);\\n return after_keyword.count('\\\"') >= 2;\\n }\\n if(directive.contains('<')) {\\n return directive.contains('>');\\n }\\n // No \\\" or < — might be a macro (#include FOO) or just incomplete (#include ).\\n auto after_keyword = directive.drop_front(directive.starts_with(\\\"import\\\") ? 6 : 7).ltrim();\\n return !after_keyword.empty();\\n}\\n\\n/// Check if a C++20 module statement line (import/export module) is complete.\\n/// A complete statement must end with ';'.\\nstatic bool is_module_statement_complete(llvm::StringRef trimmed) {\\n return trimmed.rtrim().ends_with(\\\";\\\");\\n}\\n\\nbool is_preamble_complete(llvm::StringRef content, std::uint32_t bound) {\\n auto preamble = content.substr(0, bound);\\n\\n while(!preamble.empty()) {\\n auto [line, rest] = preamble.split('\\\\n');\\n preamble = rest;\\n\\n auto trimmed = line.ltrim();\\n\\n // Preprocessor directive: #include or #import\\n if(trimmed.starts_with(\\\"#\\\")) {\\n auto directive = trimmed.drop_front(1).ltrim();\\n if(directive.starts_with(\\\"include\\\") || directive.starts_with(\\\"import\\\")) {\\n if(!is_include_directive_complete(directive)) {\\n return false;\\n }\\n }\\n continue;\\n }\\n\\n // C++20 module statements: import, export module, export import\\n // Check word boundary to avoid matching identifiers like \\\"important\\\".\\n auto is_keyword = [](llvm::StringRef s, llvm::StringRef keyword) {\\n return s.starts_with(keyword) &&\\n (s.size() == keyword.size() || !llvm::isAlnum(s[keyword.size()]));\\n };\\n if(is_keyword(trimmed, \\\"import\\\") || is_keyword(trimmed, \\\"export\\\")) {\\n if(!is_module_statement_complete(trimmed)) {\\n return false;\\n }\\n }\\n }\\n\\n return true;\\n}\\n\\n} // namespace clice\\n\"}}}"}
|
||
{"ts":4745,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didOpen\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/src/syntax/scan.h\",\"languageId\":\"cpp\",\"version\":1,\"text\":\"#pragma once\\n\\n#include <cstdint>\\n#include <string>\\n#include <vector>\\n\\n#include \\\"llvm/ADT/ArrayRef.h\\\"\\n#include \\\"llvm/ADT/IntrusiveRefCntPtr.h\\\"\\n#include \\\"llvm/ADT/StringMap.h\\\"\\n#include \\\"llvm/ADT/StringRef.h\\\"\\n#include \\\"llvm/Support/VirtualFileSystem.h\\\"\\n#include \\\"clang/Lex/DependencyDirectivesScanner.h\\\"\\n\\nnamespace clice {\\n\\nstruct ScanResult {\\n /// Module name (empty if not a module unit).\\n std::string module_name;\\n\\n /// Whether this is an interface unit (has `export module`).\\n bool is_interface_unit = false;\\n\\n /// Whether module declaration is inside conditional directive,\\n /// signaling caller should fall back to preprocessor-based scan.\\n bool need_preprocess = false;\\n\\n struct IncludeInfo {\\n /// Resolved file path (fuzzy/precise scan) or raw header name (lexer scan).\\n std::string path;\\n\\n /// Whether this include is inside a conditional directive context.\\n bool conditional = false;\\n\\n /// Whether the included file was not found during resolution.\\n bool not_found = false;\\n\\n /// Whether this is an angled include (<...>) vs quoted (\\\"...\\\").\\n bool is_angled = false;\\n\\n /// Whether this is an #include_next directive.\\n bool is_include_next = false;\\n };\\n\\n /// Include file names.\\n /// From lexer scan these are the raw header names;\\n /// from preprocessor scan these are resolved file paths.\\n std::vector<IncludeInfo> includes;\\n\\n /// Dependent module names.\\n std::vector<std::string> modules;\\n};\\n\\n/// Shared cache for dependency directives across multiple scan invocations.\\nstruct SharedScanCache {\\n struct CachedEntry {\\n /// The source content of the file (kept alive for token references).\\n std::string source;\\n\\n /// Scanned tokens.\\n llvm::SmallVector<clang::dependency_directives_scan::Token> tokens;\\n\\n /// Scanned directives (referencing tokens above).\\n llvm::SmallVector<clang::dependency_directives_scan::Directive> directives;\\n };\\n\\n /// path -> cached scan result.\\n llvm::StringMap<CachedEntry> entries;\\n};\\n\\n/// Quick lexer-based scan for module name and include file names.\\n/// If module declaration is inside #if/#ifdef, sets need_preprocess=true\\n/// and module_name will be empty.\\nScanResult scan(llvm::StringRef content);\\n\\n/// Precise preprocessing-based scan. Keeps all directives including #define\\n/// and conditionals. Used for lazy module dependency resolution.\\nScanResult scan_precise(llvm::ArrayRef<const char*> arguments,\\n llvm::StringRef directory,\\n llvm::StringRef content = {},\\n SharedScanCache* cache = nullptr,\\n llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs = nullptr);\\n\\n/// Lightweight preprocessor-based fallback for resolving module declarations\\n/// inside conditional directives (#if/#ifdef). When the quick `scan()` detects\\n/// `need_preprocess=true`, this function runs clang's preprocessor to evaluate\\n/// the conditions and extract the actual module name.\\n///\\n/// Much cheaper than `scan_precise()`: stops lexing as soon as the module\\n/// declaration is found, so it only processes the file preamble (global module\\n/// fragment + conditionals around the module declaration). Only populates\\n/// `module_name` and `is_interface_unit` in the returned ScanResult.\\nScanResult scan_module_decl(llvm::ArrayRef<const char*> arguments,\\n llvm::StringRef directory,\\n llvm::StringRef content = {},\\n SharedScanCache* cache = nullptr,\\n llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs = nullptr);\\n\\n/// Compute preamble bound (moved from compile/preamble).\\nstd::uint32_t compute_preamble_bound(llvm::StringRef content);\\n\\nstd::vector<std::uint32_t> compute_preamble_bounds(llvm::StringRef content);\\n\\n/// Check if the preamble region contains only syntactically complete directives.\\n/// Returns false if any #include/#import has an unclosed \\\"\\\" or <>, or any\\n/// C++20 module statement (import/export) is missing a trailing ';',\\n/// indicating the user is still typing and PCH/PCM rebuild should be deferred.\\nbool is_preamble_complete(llvm::StringRef content, std::uint32_t bound);\\n\\n} // namespace clice\\n\"}}}"}
|
||
{"ts":4745,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didOpen\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/unit/syntax/scan_tests.cpp\",\"languageId\":\"cpp\",\"version\":1,\"text\":\"#include \\\"test/test.h\\\"\\n#include \\\"syntax/scan.h\\\"\\n\\nnamespace clice::testing {\\nnamespace {\\n\\nTEST_SUITE(Scan) {\\n\\n// === scan() tests ===\\n\\nTEST_CASE(BasicIncludes) {\\n auto result = scan(R\\\"(\\n#include <vector>\\n#include \\\"foo/bar.h\\\"\\nint x = 1;\\n)\\\");\\n\\n ASSERT_EQ(result.includes.size(), 2u);\\n EXPECT_EQ(result.includes[0].path, \\\"vector\\\");\\n EXPECT_TRUE(result.includes[0].is_angled);\\n EXPECT_FALSE(result.includes[0].conditional);\\n EXPECT_EQ(result.includes[1].path, \\\"foo/bar.h\\\");\\n EXPECT_FALSE(result.includes[1].is_angled);\\n EXPECT_FALSE(result.includes[1].conditional);\\n EXPECT_TRUE(result.module_name.empty());\\n}\\n\\nTEST_CASE(ConditionalIncludes) {\\n auto result = scan(R\\\"(\\n#include <always.h>\\n#ifdef FOO\\n#include <conditional.h>\\n#endif\\n#include <after.h>\\n)\\\");\\n\\n ASSERT_EQ(result.includes.size(), 3u);\\n EXPECT_EQ(result.includes[0].path, \\\"always.h\\\");\\n EXPECT_FALSE(result.includes[0].conditional);\\n EXPECT_EQ(result.includes[1].path, \\\"conditional.h\\\");\\n EXPECT_TRUE(result.includes[1].conditional);\\n EXPECT_EQ(result.includes[2].path, \\\"after.h\\\");\\n EXPECT_FALSE(result.includes[2].conditional);\\n}\\n\\nTEST_CASE(NestedConditionals) {\\n auto result = scan(R\\\"(\\n#ifdef A\\n#ifdef B\\n#include <nested.h>\\n#endif\\n#include <outer.h>\\n#endif\\n#include <top.h>\\n)\\\");\\n\\n ASSERT_EQ(result.includes.size(), 3u);\\n EXPECT_EQ(result.includes[0].path, \\\"nested.h\\\");\\n EXPECT_TRUE(result.includes[0].conditional);\\n EXPECT_EQ(result.includes[1].path, \\\"outer.h\\\");\\n EXPECT_TRUE(result.includes[1].conditional);\\n EXPECT_EQ(result.includes[2].path, \\\"top.h\\\");\\n EXPECT_FALSE(result.includes[2].conditional);\\n}\\n\\nTEST_CASE(ModuleDeclaration) {\\n auto result = scan(R\\\"(\\nmodule;\\n#include <header.h>\\nexport module my.module;\\n)\\\");\\n\\n EXPECT_EQ(result.module_name, \\\"my.module\\\");\\n EXPECT_TRUE(result.is_interface_unit);\\n EXPECT_FALSE(result.need_preprocess);\\n ASSERT_EQ(result.includes.size(), 1u);\\n EXPECT_EQ(result.includes[0].path, \\\"header.h\\\");\\n EXPECT_TRUE(result.includes[0].is_angled);\\n}\\n\\nTEST_CASE(ModulePartition) {\\n auto result = scan(R\\\"(\\nmodule my.module:part;\\n)\\\");\\n\\n EXPECT_EQ(result.module_name, \\\"my.module:part\\\");\\n EXPECT_FALSE(result.is_interface_unit);\\n}\\n\\nTEST_CASE(ModuleImplementation) {\\n auto result = scan(R\\\"(\\nmodule my.module;\\n)\\\");\\n\\n EXPECT_EQ(result.module_name, \\\"my.module\\\");\\n EXPECT_FALSE(result.is_interface_unit);\\n}\\n\\nTEST_CASE(ConditionalModule) {\\n auto result = scan(R\\\"(\\n#ifdef USE_MODULES\\nexport module foo;\\n#endif\\n)\\\");\\n\\n EXPECT_TRUE(result.module_name.empty());\\n EXPECT_TRUE(result.need_preprocess);\\n}\\n\\nTEST_CASE(GlobalModuleFragment) {\\n auto result = scan(R\\\"(\\nmodule;\\nexport module test;\\n)\\\");\\n\\n EXPECT_EQ(result.module_name, \\\"test\\\");\\n EXPECT_TRUE(result.is_interface_unit);\\n}\\n\\nTEST_CASE(EmptyContent) {\\n auto result = scan(\\\"\\\");\\n EXPECT_TRUE(result.includes.empty());\\n EXPECT_TRUE(result.module_name.empty());\\n EXPECT_FALSE(result.need_preprocess);\\n}\\n\\nTEST_CASE(NoDirectives) {\\n auto result = scan(R\\\"(\\nint main() {\\n return 0;\\n}\\n)\\\");\\n\\n EXPECT_TRUE(result.includes.empty());\\n EXPECT_TRUE(result.module_name.empty());\\n EXPECT_FALSE(result.is_interface_unit);\\n EXPECT_FALSE(result.need_preprocess);\\n}\\n\\n// === scan_precise() tests ===\\n\\nTEST_CASE(PreciseBasic) {\\n auto vfs = llvm::makeIntrusiveRefCnt<TestVFS>();\\n auto main_path = TestVFS::path(\\\"main.cpp\\\");\\n vfs->add(\\\"main.cpp\\\", R\\\"(\\n#include \\\"header.h\\\"\\nint main() {}\\n)\\\");\\n vfs->add(\\\"header.h\\\", R\\\"(\\n#pragma once\\nint x = 1;\\n)\\\");\\n\\n auto args = std::vector<const char*>{\\\"clang++\\\", \\\"-std=c++20\\\", main_path.c_str()};\\n auto result = scan_precise(args, TestVFS::root(), {}, nullptr, vfs);\\n\\n ASSERT_EQ(result.includes.size(), 1u);\\n EXPECT_FALSE(result.includes[0].not_found);\\n EXPECT_FALSE(result.includes[0].conditional);\\n}\\n\\nTEST_CASE(PreciseConditionalWithDefine) {\\n auto vfs = llvm::makeIntrusiveRefCnt<TestVFS>();\\n auto main_path = TestVFS::path(\\\"main.cpp\\\");\\n vfs->add(\\\"main.cpp\\\", R\\\"(\\n#define USE_FOO\\n#ifdef USE_FOO\\n#include \\\"foo.h\\\"\\n#endif\\n#ifndef USE_FOO\\n#include \\\"bar.h\\\"\\n#endif\\n)\\\");\\n vfs->add(\\\"foo.h\\\");\\n vfs->add(\\\"bar.h\\\");\\n\\n auto args = std::vector<const char*>{\\\"clang++\\\", \\\"-std=c++20\\\", main_path.c_str()};\\n auto result = scan_precise(args, TestVFS::root(), {}, nullptr, vfs);\\n\\n // Precise mode evaluates conditionals: only foo.h should be included.\\n ASSERT_EQ(result.includes.size(), 1u);\\n EXPECT_TRUE(result.includes[0].conditional);\\n EXPECT_TRUE(result.includes[0].path.find(\\\"foo.h\\\") != std::string::npos);\\n}\\n\\nTEST_CASE(PreciseWithContent) {\\n auto vfs = llvm::makeIntrusiveRefCnt<TestVFS>();\\n auto main_path = TestVFS::path(\\\"main.cpp\\\");\\n vfs->add(\\\"main.cpp\\\");\\n vfs->add(\\\"header.h\\\");\\n\\n auto args = std::vector<const char*>{\\\"clang++\\\", \\\"-std=c++20\\\", main_path.c_str()};\\n auto result = scan_precise(args, TestVFS::root(), R\\\"(#include \\\"header.h\\\")\\\", nullptr, vfs);\\n\\n ASSERT_EQ(result.includes.size(), 1u);\\n EXPECT_FALSE(result.includes[0].not_found);\\n}\\n\\n}; // TEST_SUITE(Scan)\\n\\nTEST_SUITE(PreambleBound) {\\n\\nTEST_CASE(Empty) {\\n EXPECT_EQ(compute_preamble_bound(\\\"\\\"), 0u);\\n}\\n\\nTEST_CASE(NoDirectives) {\\n EXPECT_EQ(compute_preamble_bound(\\\"int x = 1;\\\"), 0u);\\n}\\n\\nTEST_CASE(SingleInclude) {\\n llvm::StringRef src = R\\\"(\\n#include <vector>\\nint x;\\n)\\\";\\n auto bound = compute_preamble_bound(src);\\n EXPECT_TRUE(bound > 0u);\\n EXPECT_TRUE(bound <= src.find(\\\"int\\\"));\\n}\\n\\nTEST_CASE(MultipleDirectives) {\\n llvm::StringRef src = R\\\"(\\n#include <vector>\\n#include <string>\\n#define FOO 1\\nint x;\\n)\\\";\\n auto bound = compute_preamble_bound(src);\\n EXPECT_TRUE(bound > src.find(\\\"#define\\\"));\\n}\\n\\nTEST_CASE(GlobalModuleFragment) {\\n llvm::StringRef src = R\\\"(\\nmodule;\\n#include <vector>\\nexport module foo;\\n)\\\";\\n auto bound = compute_preamble_bound(src);\\n EXPECT_TRUE(bound > 0u);\\n EXPECT_TRUE(bound < src.size());\\n}\\n\\nTEST_CASE(BoundsVector) {\\n llvm::StringRef src = R\\\"(\\n#include <a>\\n#include <b>\\nint x;\\n)\\\";\\n auto bounds = compute_preamble_bounds(src);\\n ASSERT_EQ(bounds.size(), 2u);\\n EXPECT_TRUE(bounds[0] < bounds[1]);\\n}\\n\\nTEST_CASE(BoundsWithModuleFragment) {\\n llvm::StringRef src = R\\\"(\\nmodule;\\n#include <a>\\n#include <b>\\nexport module foo;\\n)\\\";\\n auto bounds = compute_preamble_bounds(src);\\n // module; + two #include = 3 bounds.\\n ASSERT_EQ(bounds.size(), 3u);\\n EXPECT_TRUE(bounds[0] < bounds[1]);\\n EXPECT_TRUE(bounds[1] < bounds[2]);\\n}\\n\\nTEST_CASE(StopsAtCode) {\\n llvm::StringRef src = R\\\"(\\n#include <a>\\nint x;\\n#include <b>\\n)\\\";\\n auto bounds = compute_preamble_bounds(src);\\n ASSERT_EQ(bounds.size(), 1u);\\n}\\n\\nTEST_CASE(ConditionalDirectives) {\\n llvm::StringRef src = R\\\"(\\n#ifndef GUARD\\n#define GUARD\\n#include <a>\\n#endif\\nint x;\\n)\\\";\\n auto bound = compute_preamble_bound(src);\\n EXPECT_TRUE(bound > src.find(\\\"#endif\\\"));\\n}\\n\\n}; // TEST_SUITE(PreambleBound)\\n\\nTEST_SUITE(PreambleComplete) {\\n\\n// --- #include completeness ---\\n\\nTEST_CASE(CompleteQuotedInclude) {\\n llvm::StringRef content = \\\"#include \\\\\\\"foo.h\\\\\\\"\\\\nint x;\\\";\\n auto bound = compute_preamble_bound(content);\\n EXPECT_TRUE(is_preamble_complete(content, bound));\\n}\\n\\nTEST_CASE(CompleteAngledInclude) {\\n llvm::StringRef content = \\\"#include <vector>\\\\nint x;\\\";\\n auto bound = compute_preamble_bound(content);\\n EXPECT_TRUE(is_preamble_complete(content, bound));\\n}\\n\\nTEST_CASE(IncompleteQuotedInclude) {\\n llvm::StringRef content = \\\"#include \\\\\\\"foo\\\\nint x;\\\";\\n auto bound = compute_preamble_bound(content);\\n EXPECT_FALSE(is_preamble_complete(content, bound));\\n}\\n\\nTEST_CASE(IncompleteAngledInclude) {\\n llvm::StringRef content = \\\"#include <sys/\\\\nint x;\\\";\\n auto bound = compute_preamble_bound(content);\\n EXPECT_FALSE(is_preamble_complete(content, bound));\\n}\\n\\nTEST_CASE(IncludeWithNoPath) {\\n llvm::StringRef content = \\\"#include \\\\nint x;\\\";\\n auto bound = compute_preamble_bound(content);\\n EXPECT_FALSE(is_preamble_complete(content, bound));\\n}\\n\\nTEST_CASE(IncludeMacroUsage) {\\n llvm::StringRef content = \\\"#include FOO\\\\nint x;\\\";\\n auto bound = compute_preamble_bound(content);\\n EXPECT_TRUE(is_preamble_complete(content, bound));\\n}\\n\\nTEST_CASE(MultipleIncludesAllComplete) {\\n llvm::StringRef content = \\\"#include <vector>\\\\n#include \\\\\\\"foo.h\\\\\\\"\\\\nint x;\\\";\\n auto bound = compute_preamble_bound(content);\\n EXPECT_TRUE(is_preamble_complete(content, bound));\\n}\\n\\nTEST_CASE(MultipleIncludesLastIncomplete) {\\n llvm::StringRef content = \\\"#include <vector>\\\\n#include \\\\\\\"foo\\\\nint x;\\\";\\n auto bound = compute_preamble_bound(content);\\n EXPECT_FALSE(is_preamble_complete(content, bound));\\n}\\n\\n// --- C++20 module statements ---\\n// Note: compute_preamble_bound does not include import/export lines in its\\n// bound, so we pass manual bounds covering the relevant lines.\\n\\nTEST_CASE(CompleteImport) {\\n llvm::StringRef content = \\\"import std;\\\\nint x;\\\";\\n // Bound covers \\\"import std;\\\\n\\\".\\n EXPECT_TRUE(is_preamble_complete(content, 12));\\n}\\n\\nTEST_CASE(ImportMissingSemicolon) {\\n llvm::StringRef content = \\\"import std\\\\nint x;\\\";\\n // Bound covers \\\"import std\\\\n\\\".\\n EXPECT_FALSE(is_preamble_complete(content, 11));\\n}\\n\\nTEST_CASE(ImportWithNothing) {\\n llvm::StringRef content = \\\"import \\\\nint x;\\\";\\n // Bound covers \\\"import \\\\n\\\".\\n EXPECT_FALSE(is_preamble_complete(content, 8));\\n}\\n\\nTEST_CASE(CompleteExportModule) {\\n llvm::StringRef content = \\\"export module foo;\\\\nint x;\\\";\\n // Bound covers \\\"export module foo;\\\\n\\\".\\n EXPECT_TRUE(is_preamble_complete(content, 19));\\n}\\n\\nTEST_CASE(ExportModuleMissingSemicolon) {\\n llvm::StringRef content = \\\"export module foo\\\\nint x;\\\";\\n // Bound covers \\\"export module foo\\\\n\\\".\\n EXPECT_FALSE(is_preamble_complete(content, 18));\\n}\\n\\nTEST_CASE(CompleteExportImport) {\\n llvm::StringRef content = \\\"export import std;\\\\nint x;\\\";\\n // Bound covers \\\"export import std;\\\\n\\\".\\n EXPECT_TRUE(is_preamble_complete(content, 19));\\n}\\n\\n// --- Edge cases ---\\n\\nTEST_CASE(EmptyPreamble) {\\n llvm::StringRef content = \\\"int x;\\\";\\n EXPECT_TRUE(is_preamble_complete(content, 0));\\n}\\n\\nTEST_CASE(NonImportIncludeLinesIgnored) {\\n llvm::StringRef content = \\\"#define FOO 1\\\\n#ifdef BAR\\\\n#endif\\\\nint x;\\\";\\n auto bound = compute_preamble_bound(content);\\n EXPECT_TRUE(is_preamble_complete(content, bound));\\n}\\n\\nTEST_CASE(ImportantDoesNotMatchImport) {\\n // \\\"important\\\" starts with \\\"import\\\" but should NOT be treated as an import.\\n llvm::StringRef content = \\\"#include <vector>\\\\nint x;\\\";\\n auto bound = compute_preamble_bound(content);\\n // Manually test with content that has \\\"important\\\" within the preamble region.\\n // Since compute_preamble_bound won't include non-directive lines, we test\\n // is_preamble_complete directly with a crafted bound.\\n llvm::StringRef crafted = \\\"important = 1;\\\\n\\\";\\n EXPECT_TRUE(is_preamble_complete(crafted, crafted.size()));\\n}\\n\\nTEST_CASE(PreprocessorDirectivesIgnored) {\\n llvm::StringRef content = \\\"#ifdef FOO\\\\n#define BAR 1\\\\n#endif\\\\nint x;\\\";\\n auto bound = compute_preamble_bound(content);\\n EXPECT_TRUE(is_preamble_complete(content, bound));\\n}\\n\\nTEST_CASE(MixedIncludeAndImportAllComplete) {\\n llvm::StringRef content = \\\"#include <vector>\\\\nimport std;\\\\nint x;\\\";\\n auto bound = compute_preamble_bound(content);\\n EXPECT_TRUE(is_preamble_complete(content, bound));\\n}\\n\\n}; // TEST_SUITE(PreambleComplete)\\n\\n} // namespace\\n} // namespace clice::testing\\n\"}}}"}
|
||
{"ts":4746,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didOpen\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/include_completion/main.cpp\",\"languageId\":\"cpp\",\"version\":1,\"text\":\"#include \\\"\\n\"}}}"}
|
||
{"ts":4746,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didOpen\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/include_completion/myheader.h\",\"languageId\":\"cpp\",\"version\":1,\"text\":\"#pragma once\\nint my_func();\\n\"}}}"}
|
||
{"ts":4746,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didOpen\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/include_completion/subdir/nested.h\",\"languageId\":\"cpp\",\"version\":1,\"text\":\"#pragma once\\nint nested_func();\\n\"}}}"}
|
||
{"ts":4886,"msg":"{\"jsonrpc\":\"2.0\",\"id\":16,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":9,\"character\":27},\"end\":{\"line\":9,\"character\":27}},\"context\":{\"diagnostics\":[],\"triggerKind\":2}}}"}
|
||
{"ts":4978,"msg":"{\"jsonrpc\":\"2.0\",\"id\":17,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":12,\"character\":0}}}}"}
|
||
{"ts":5179,"msg":"{\"jsonrpc\":\"2.0\",\"id\":18,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":12,\"character\":0}}}}"}
|
||
{"ts":5181,"msg":"{\"jsonrpc\":\"2.0\",\"id\":19,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":9,\"character\":27},\"end\":{\"line\":9,\"character\":27}},\"context\":{\"diagnostics\":[],\"triggerKind\":2}}}"}
|
||
{"ts":5278,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":2},\"contentChanges\":[{\"range\":{\"start\":{\"line\":9,\"character\":27},\"end\":{\"line\":9,\"character\":27}},\"rangeLength\":0,\"text\":\"\\n \"}]}}"}
|
||
{"ts":5278,"msg":"{\"jsonrpc\":\"2.0\",\"id\":20,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":5517,"msg":"{\"jsonrpc\":\"2.0\",\"id\":21,\"method\":\"textDocument/foldingRange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":5606,"msg":"{\"jsonrpc\":\"2.0\",\"id\":22,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":5666,"msg":"{\"jsonrpc\":\"2.0\",\"id\":23,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":5666,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":3},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":4},\"end\":{\"line\":10,\"character\":4}},\"rangeLength\":0,\"text\":\"s\"}]}}"}
|
||
{"ts":5666,"msg":"{\"jsonrpc\":\"2.0\",\"id\":24,\"method\":\"textDocument/completion\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":10,\"character\":5},\"context\":{\"triggerKind\":1}}}"}
|
||
{"ts":5666,"msg":"{\"jsonrpc\":\"2.0\",\"id\":25,\"method\":\"textDocument/semanticTokens/full\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":5680,"msg":"{\"jsonrpc\":\"2.0\",\"id\":26,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":5775,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":4},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":5},\"end\":{\"line\":10,\"character\":5}},\"rangeLength\":0,\"text\":\"t\"}]}}"}
|
||
{"ts":5818,"msg":"{\"jsonrpc\":\"2.0\",\"id\":27,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":5954,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":5},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":6},\"end\":{\"line\":10,\"character\":6}},\"rangeLength\":0,\"text\":\"d\"}]}}"}
|
||
{"ts":5964,"msg":"{\"jsonrpc\":\"2.0\",\"id\":28,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":6202,"msg":"{\"jsonrpc\":\"2.0\",\"id\":29,\"method\":\"textDocument/semanticTokens/full\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":6202,"msg":"{\"jsonrpc\":\"2.0\",\"id\":30,\"method\":\"textDocument/foldingRange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":6293,"msg":"{\"jsonrpc\":\"2.0\",\"id\":31,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":6294,"msg":"{\"jsonrpc\":\"2.0\",\"id\":32,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":10,\"character\":7},\"end\":{\"line\":10,\"character\":7}},\"context\":{\"diagnostics\":[{\"range\":{\"start\":{\"line\":10,\"character\":4},\"end\":{\"line\":10,\"character\":7}},\"message\":\"unexpected namespace name 'std': expected expression\",\"code\":\"err_unexpected_namespace\",\"severity\":1,\"source\":\"clang\"},{\"range\":{\"start\":{\"line\":10,\"character\":7},\"end\":{\"line\":10,\"character\":7}},\"message\":\"expected ';' after expression\",\"code\":\"err_expected_semi_after_expr\",\"severity\":1,\"source\":\"clang\"}],\"triggerKind\":2}}}"}
|
||
{"ts":6294,"msg":"{\"jsonrpc\":\"2.0\",\"id\":33,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":6473,"msg":"{\"jsonrpc\":\"2.0\",\"id\":34,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":10,\"character\":7},\"end\":{\"line\":10,\"character\":7}},\"context\":{\"diagnostics\":[{\"range\":{\"start\":{\"line\":10,\"character\":4},\"end\":{\"line\":10,\"character\":7}},\"message\":\"unexpected namespace name 'std': expected expression\",\"code\":\"err_unexpected_namespace\",\"severity\":1,\"source\":\"clang\"},{\"range\":{\"start\":{\"line\":10,\"character\":7},\"end\":{\"line\":10,\"character\":7}},\"message\":\"expected ';' after expression\",\"code\":\"err_expected_semi_after_expr\",\"severity\":1,\"source\":\"clang\"}],\"triggerKind\":2}}}"}
|
||
{"ts":6473,"msg":"{\"jsonrpc\":\"2.0\",\"id\":35,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":10,\"character\":7},\"end\":{\"line\":10,\"character\":7}},\"context\":{\"diagnostics\":[{\"range\":{\"start\":{\"line\":10,\"character\":4},\"end\":{\"line\":10,\"character\":7}},\"message\":\"unexpected namespace name 'std': expected expression\",\"code\":\"err_unexpected_namespace\",\"severity\":1,\"source\":\"clang\"},{\"range\":{\"start\":{\"line\":10,\"character\":7},\"end\":{\"line\":10,\"character\":7}},\"message\":\"expected ';' after expression\",\"code\":\"err_expected_semi_after_expr\",\"severity\":1,\"source\":\"clang\"}],\"triggerKind\":2}}}"}
|
||
{"ts":6474,"msg":"{\"jsonrpc\":\"2.0\",\"id\":36,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":10,\"character\":7},\"end\":{\"line\":10,\"character\":7}},\"context\":{\"diagnostics\":[{\"range\":{\"start\":{\"line\":10,\"character\":4},\"end\":{\"line\":10,\"character\":7}},\"message\":\"unexpected namespace name 'std': expected expression\",\"code\":\"err_unexpected_namespace\",\"severity\":1,\"source\":\"clang\"},{\"range\":{\"start\":{\"line\":10,\"character\":7},\"end\":{\"line\":10,\"character\":7}},\"message\":\"expected ';' after expression\",\"code\":\"err_expected_semi_after_expr\",\"severity\":1,\"source\":\"clang\"}],\"triggerKind\":2}}}"}
|
||
{"ts":6480,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":34}}"}
|
||
{"ts":6480,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":35}}"}
|
||
{"ts":6522,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":36}}"}
|
||
{"ts":6522,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":6},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":7},\"end\":{\"line\":10,\"character\":7}},\"rangeLength\":0,\"text\":\":\"}]}}"}
|
||
{"ts":6533,"msg":"{\"jsonrpc\":\"2.0\",\"id\":37,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":6649,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":7},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":8},\"end\":{\"line\":10,\"character\":8}},\"rangeLength\":0,\"text\":\":\"}]}}"}
|
||
{"ts":6677,"msg":"{\"jsonrpc\":\"2.0\",\"id\":38,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":6802,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":8},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":9},\"end\":{\"line\":10,\"character\":9}},\"rangeLength\":0,\"text\":\"c\"}]}}"}
|
||
{"ts":6811,"msg":"{\"jsonrpc\":\"2.0\",\"id\":39,\"method\":\"textDocument/completion\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":10,\"character\":10},\"context\":{\"triggerKind\":1}}}"}
|
||
{"ts":6841,"msg":"{\"jsonrpc\":\"2.0\",\"id\":40,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":6966,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":9},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":10},\"end\":{\"line\":10,\"character\":10}},\"rangeLength\":0,\"text\":\"o\"}]}}"}
|
||
{"ts":7013,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":40}}"}
|
||
{"ts":7013,"msg":"{\"jsonrpc\":\"2.0\",\"id\":41,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":7014,"msg":"{\"jsonrpc\":\"2.0\",\"id\":42,\"method\":\"textDocument/semanticTokens/full\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":7095,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":10},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":11},\"end\":{\"line\":10,\"character\":11}},\"rangeLength\":0,\"text\":\"u\"}]}}"}
|
||
{"ts":7138,"msg":"{\"jsonrpc\":\"2.0\",\"id\":43,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":7240,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":11},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":12},\"end\":{\"line\":10,\"character\":12}},\"rangeLength\":0,\"text\":\"t\"}]}}"}
|
||
{"ts":7282,"msg":"{\"jsonrpc\":\"2.0\",\"id\":44,\"method\":\"textDocument/completion\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":10,\"character\":13},\"context\":{\"triggerKind\":1}}}"}
|
||
{"ts":7282,"msg":"{\"jsonrpc\":\"2.0\",\"id\":45,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":7282,"msg":"{\"jsonrpc\":\"2.0\",\"id\":46,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":10,\"character\":13},\"end\":{\"line\":10,\"character\":13}},\"context\":{\"diagnostics\":[],\"triggerKind\":2}}}"}
|
||
{"ts":7282,"msg":"{\"jsonrpc\":\"2.0\",\"id\":47,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":7598,"msg":"{\"jsonrpc\":\"2.0\",\"id\":48,\"method\":\"textDocument/foldingRange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":7598,"msg":"{\"jsonrpc\":\"2.0\",\"id\":49,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":7598,"msg":"{\"jsonrpc\":\"2.0\",\"id\":50,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":10,\"character\":13},\"end\":{\"line\":10,\"character\":13}},\"context\":{\"diagnostics\":[{\"range\":{\"start\":{\"line\":10,\"character\":13},\"end\":{\"line\":10,\"character\":13}},\"message\":\"expected ';' after expression\",\"code\":\"err_expected_semi_after_expr\",\"severity\":1,\"source\":\"clang\"}],\"triggerKind\":2}}}"}
|
||
{"ts":7670,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":12},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":13},\"end\":{\"line\":10,\"character\":13}},\"rangeLength\":0,\"text\":\" \"}]}}"}
|
||
{"ts":7677,"msg":"{\"jsonrpc\":\"2.0\",\"id\":51,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":7710,"msg":"{\"jsonrpc\":\"2.0\",\"id\":52,\"method\":\"textDocument/semanticTokens/full\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":7966,"msg":"{\"jsonrpc\":\"2.0\",\"id\":53,\"method\":\"textDocument/foldingRange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":8014,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":53}}"}
|
||
{"ts":8014,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":13},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":14},\"end\":{\"line\":10,\"character\":14}},\"rangeLength\":0,\"text\":\"<\"}]}}"}
|
||
{"ts":8014,"msg":"{\"jsonrpc\":\"2.0\",\"id\":54,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":8014,"msg":"{\"jsonrpc\":\"2.0\",\"id\":55,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":8014,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":54}}"}
|
||
{"ts":8182,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":14},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":15},\"end\":{\"line\":10,\"character\":15}},\"rangeLength\":0,\"text\":\"<\"}]}}"}
|
||
{"ts":8184,"msg":"{\"jsonrpc\":\"2.0\",\"id\":56,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":8411,"msg":"{\"jsonrpc\":\"2.0\",\"id\":57,\"method\":\"textDocument/semanticTokens/full\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":8478,"msg":"{\"jsonrpc\":\"2.0\",\"id\":58,\"method\":\"textDocument/foldingRange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":8526,"msg":"{\"jsonrpc\":\"2.0\",\"id\":59,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":8526,"msg":"{\"jsonrpc\":\"2.0\",\"id\":60,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":10,\"character\":16},\"end\":{\"line\":10,\"character\":16}},\"context\":{\"diagnostics\":[],\"triggerKind\":2}}}"}
|
||
{"ts":8630,"msg":"{\"jsonrpc\":\"2.0\",\"id\":61,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":8838,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":15},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":16},\"end\":{\"line\":10,\"character\":16}},\"rangeLength\":0,\"text\":\" \"}]}}"}
|
||
{"ts":8838,"msg":"{\"jsonrpc\":\"2.0\",\"id\":62,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":9101,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":16},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":17},\"end\":{\"line\":10,\"character\":17}},\"rangeLength\":0,\"text\":\"\\\"\\\"\"}]}}"}
|
||
{"ts":9158,"msg":"{\"jsonrpc\":\"2.0\",\"id\":63,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":9258,"msg":"{\"jsonrpc\":\"2.0\",\"id\":64,\"method\":\"textDocument/semanticTokens/full\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":9434,"msg":"{\"jsonrpc\":\"2.0\",\"id\":65,\"method\":\"textDocument/foldingRange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":9482,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":65}}"}
|
||
{"ts":9482,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":17},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":18},\"end\":{\"line\":10,\"character\":18}},\"rangeLength\":0,\"text\":\"H\"}]}}"}
|
||
{"ts":9482,"msg":"{\"jsonrpc\":\"2.0\",\"id\":66,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":9482,"msg":"{\"jsonrpc\":\"2.0\",\"id\":67,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":9482,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":66}}"}
|
||
{"ts":9778,"msg":"{\"jsonrpc\":\"2.0\",\"id\":68,\"method\":\"textDocument/foldingRange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":9830,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":68}}"}
|
||
{"ts":9830,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":18},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":19},\"end\":{\"line\":10,\"character\":19}},\"rangeLength\":0,\"text\":\"e\"}]}}"}
|
||
{"ts":9830,"msg":"{\"jsonrpc\":\"2.0\",\"id\":69,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":9837,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":69}}"}
|
||
{"ts":9838,"msg":"{\"jsonrpc\":\"2.0\",\"id\":70,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":9910,"msg":"{\"jsonrpc\":\"2.0\",\"id\":71,\"method\":\"textDocument/semanticTokens/full\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":10016,"msg":"{\"jsonrpc\":\"2.0\",\"id\":72,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":10,\"character\":20},\"end\":{\"line\":10,\"character\":20}},\"context\":{\"diagnostics\":[{\"range\":{\"start\":{\"line\":10,\"character\":20},\"end\":{\"line\":10,\"character\":20}},\"message\":\"expected ';' after expression\",\"code\":\"err_expected_semi_after_expr\",\"severity\":1,\"source\":\"clang\"}],\"triggerKind\":2}}}"}
|
||
{"ts":10083,"msg":"{\"jsonrpc\":\"2.0\",\"id\":73,\"method\":\"textDocument/foldingRange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":10131,"msg":"{\"jsonrpc\":\"2.0\",\"id\":74,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":10153,"msg":"{\"jsonrpc\":\"2.0\",\"id\":75,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":10428,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":72}}"}
|
||
{"ts":10429,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":73}}"}
|
||
{"ts":10429,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":19},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":20},\"end\":{\"line\":10,\"character\":20}},\"rangeLength\":0,\"text\":\"l\"}]}}"}
|
||
{"ts":10476,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":70}}"}
|
||
{"ts":10476,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":74}}"}
|
||
{"ts":10476,"msg":"{\"jsonrpc\":\"2.0\",\"id\":76,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":10603,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":20},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":21},\"end\":{\"line\":10,\"character\":21}},\"rangeLength\":0,\"text\":\"l\"}]}}"}
|
||
{"ts":10640,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":76}}"}
|
||
{"ts":10640,"msg":"{\"jsonrpc\":\"2.0\",\"id\":77,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":10890,"msg":"{\"jsonrpc\":\"2.0\",\"id\":78,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":10,\"character\":22},\"end\":{\"line\":10,\"character\":22}},\"context\":{\"diagnostics\":[],\"triggerKind\":2}}}"}
|
||
{"ts":10938,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":78}}"}
|
||
{"ts":10938,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":21},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":22},\"end\":{\"line\":10,\"character\":22}},\"rangeLength\":0,\"text\":\"o\"}]}}"}
|
||
{"ts":10986,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":77}}"}
|
||
{"ts":10986,"msg":"{\"jsonrpc\":\"2.0\",\"id\":79,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":10986,"msg":"{\"jsonrpc\":\"2.0\",\"id\":80,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":10986,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":80}}"}
|
||
{"ts":11158,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":22},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":23},\"end\":{\"line\":10,\"character\":23}},\"rangeLength\":0,\"text\":\" \"}]}}"}
|
||
{"ts":11158,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":79}}"}
|
||
{"ts":11158,"msg":"{\"jsonrpc\":\"2.0\",\"id\":81,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":11330,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":23},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":24},\"end\":{\"line\":10,\"character\":24}},\"rangeLength\":0,\"text\":\"w\"}]}}"}
|
||
{"ts":11345,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":81}}"}
|
||
{"ts":11345,"msg":"{\"jsonrpc\":\"2.0\",\"id\":82,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":11542,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":24},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":25},\"end\":{\"line\":10,\"character\":25}},\"rangeLength\":0,\"text\":\"o\"}]}}"}
|
||
{"ts":11542,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":82}}"}
|
||
{"ts":11542,"msg":"{\"jsonrpc\":\"2.0\",\"id\":83,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":11646,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":25},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":26},\"end\":{\"line\":10,\"character\":26}},\"rangeLength\":0,\"text\":\"r\"}]}}"}
|
||
{"ts":11649,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":83}}"}
|
||
{"ts":11649,"msg":"{\"jsonrpc\":\"2.0\",\"id\":84,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":11715,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":26},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":27},\"end\":{\"line\":10,\"character\":27}},\"rangeLength\":0,\"text\":\"l\"}]}}"}
|
||
{"ts":11759,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":84}}"}
|
||
{"ts":11759,"msg":"{\"jsonrpc\":\"2.0\",\"id\":85,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":11901,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":27},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":28},\"end\":{\"line\":10,\"character\":28}},\"rangeLength\":0,\"text\":\"d\"}]}}"}
|
||
{"ts":11902,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":85}}"}
|
||
{"ts":11902,"msg":"{\"jsonrpc\":\"2.0\",\"id\":86,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":12158,"msg":"{\"jsonrpc\":\"2.0\",\"id\":87,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":10,\"character\":29},\"end\":{\"line\":10,\"character\":29}},\"context\":{\"diagnostics\":[],\"triggerKind\":2}}}"}
|
||
{"ts":12158,"msg":"{\"jsonrpc\":\"2.0\",\"id\":88,\"method\":\"textDocument/foldingRange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":12222,"msg":"{\"jsonrpc\":\"2.0\",\"id\":89,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":12267,"msg":"{\"jsonrpc\":\"2.0\",\"id\":90,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":12466,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":87}}"}
|
||
{"ts":12466,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":88}}"}
|
||
{"ts":12466,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":28},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":30},\"end\":{\"line\":10,\"character\":30}},\"rangeLength\":0,\"text\":\" \"}]}}"}
|
||
{"ts":12558,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":86}}"}
|
||
{"ts":12558,"msg":"{\"jsonrpc\":\"2.0\",\"id\":91,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":12558,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":89}}"}
|
||
{"ts":12814,"msg":"{\"jsonrpc\":\"2.0\",\"id\":92,\"method\":\"textDocument/foldingRange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":12845,"msg":"{\"jsonrpc\":\"2.0\",\"id\":93,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":12852,"msg":"{\"jsonrpc\":\"2.0\",\"id\":94,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":12931,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":92}}"}
|
||
{"ts":12931,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":29},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":31},\"end\":{\"line\":10,\"character\":31}},\"rangeLength\":0,\"text\":\"<\"}]}}"}
|
||
{"ts":13022,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":91}}"}
|
||
{"ts":13022,"msg":"{\"jsonrpc\":\"2.0\",\"id\":95,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":13022,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":93}}"}
|
||
{"ts":13130,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":30},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":32},\"end\":{\"line\":10,\"character\":32}},\"rangeLength\":0,\"text\":\"<\"}]}}"}
|
||
{"ts":13130,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":95}}"}
|
||
{"ts":13130,"msg":"{\"jsonrpc\":\"2.0\",\"id\":96,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":13450,"msg":"{\"jsonrpc\":\"2.0\",\"id\":97,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":10,\"character\":33},\"end\":{\"line\":10,\"character\":33}},\"context\":{\"diagnostics\":[],\"triggerKind\":2}}}"}
|
||
{"ts":13525,"msg":"{\"jsonrpc\":\"2.0\",\"id\":98,\"method\":\"textDocument/foldingRange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":13559,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":97}}"}
|
||
{"ts":13560,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":98}}"}
|
||
{"ts":13560,"msg":"{\"jsonrpc\":\"2.0\",\"id\":99,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":13560,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":31},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":33},\"end\":{\"line\":10,\"character\":33}},\"rangeLength\":0,\"text\":\" \"}]}}"}
|
||
{"ts":13614,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":96}}"}
|
||
{"ts":13614,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":99}}"}
|
||
{"ts":13614,"msg":"{\"jsonrpc\":\"2.0\",\"id\":100,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":13614,"msg":"{\"jsonrpc\":\"2.0\",\"id\":101,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":13710,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":32},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":34},\"end\":{\"line\":10,\"character\":34}},\"rangeLength\":0,\"text\":\"s\"}]}}"}
|
||
{"ts":13710,"msg":"{\"jsonrpc\":\"2.0\",\"id\":102,\"method\":\"textDocument/completion\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":10,\"character\":35},\"context\":{\"triggerKind\":1}}}"}
|
||
{"ts":13710,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":100}}"}
|
||
{"ts":13710,"msg":"{\"jsonrpc\":\"2.0\",\"id\":103,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":13846,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":33},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":35},\"end\":{\"line\":10,\"character\":35}},\"rangeLength\":0,\"text\":\"t\"}]}}"}
|
||
{"ts":13846,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":103}}"}
|
||
{"ts":13846,"msg":"{\"jsonrpc\":\"2.0\",\"id\":104,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":13998,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":34},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":36},\"end\":{\"line\":10,\"character\":36}},\"rangeLength\":0,\"text\":\"d\"}]}}"}
|
||
{"ts":13998,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":104}}"}
|
||
{"ts":13998,"msg":"{\"jsonrpc\":\"2.0\",\"id\":105,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":14242,"msg":"{\"jsonrpc\":\"2.0\",\"id\":106,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":10,\"character\":37},\"end\":{\"line\":10,\"character\":37}},\"context\":{\"diagnostics\":[],\"triggerKind\":2}}}"}
|
||
{"ts":14262,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":106}}"}
|
||
{"ts":14262,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":35},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":37},\"end\":{\"line\":10,\"character\":37}},\"rangeLength\":0,\"text\":\":\"}]}}"}
|
||
{"ts":14305,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":105}}"}
|
||
{"ts":14306,"msg":"{\"jsonrpc\":\"2.0\",\"id\":107,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":14446,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":36},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":38},\"end\":{\"line\":10,\"character\":38}},\"rangeLength\":0,\"text\":\":\"}]}}"}
|
||
{"ts":14446,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":107}}"}
|
||
{"ts":14446,"msg":"{\"jsonrpc\":\"2.0\",\"id\":108,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":14598,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":37},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":39},\"end\":{\"line\":10,\"character\":39}},\"rangeLength\":0,\"text\":\"e\"}]}}"}
|
||
{"ts":14598,"msg":"{\"jsonrpc\":\"2.0\",\"id\":109,\"method\":\"textDocument/completion\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":10,\"character\":40},\"context\":{\"triggerKind\":1}}}"}
|
||
{"ts":14598,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":108}}"}
|
||
{"ts":14598,"msg":"{\"jsonrpc\":\"2.0\",\"id\":110,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":14718,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":38},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":40},\"end\":{\"line\":10,\"character\":40}},\"rangeLength\":0,\"text\":\"n\"}]}}"}
|
||
{"ts":14718,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":110}}"}
|
||
{"ts":14718,"msg":"{\"jsonrpc\":\"2.0\",\"id\":111,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":14858,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":39},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":41},\"end\":{\"line\":10,\"character\":41}},\"rangeLength\":0,\"text\":\"d\"}]}}"}
|
||
{"ts":14858,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":111}}"}
|
||
{"ts":14858,"msg":"{\"jsonrpc\":\"2.0\",\"id\":112,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":14989,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":40},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":42},\"end\":{\"line\":10,\"character\":42}},\"rangeLength\":0,\"text\":\"l\"}]}}"}
|
||
{"ts":14990,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":112}}"}
|
||
{"ts":14991,"msg":"{\"jsonrpc\":\"2.0\",\"id\":113,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":15174,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"textDocument/didChange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\",\"version\":41},\"contentChanges\":[{\"range\":{\"start\":{\"line\":10,\"character\":43},\"end\":{\"line\":10,\"character\":43}},\"rangeLength\":0,\"text\":\";\"}]}}"}
|
||
{"ts":15195,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":113}}"}
|
||
{"ts":15195,"msg":"{\"jsonrpc\":\"2.0\",\"id\":114,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":15454,"msg":"{\"jsonrpc\":\"2.0\",\"id\":115,\"method\":\"textDocument/codeAction\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":10,\"character\":44},\"end\":{\"line\":10,\"character\":44}},\"context\":{\"diagnostics\":[],\"triggerKind\":2}}}"}
|
||
{"ts":15466,"msg":"{\"jsonrpc\":\"2.0\",\"id\":116,\"method\":\"textDocument/foldingRange\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":15515,"msg":"{\"jsonrpc\":\"2.0\",\"id\":117,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":15566,"msg":"{\"jsonrpc\":\"2.0\",\"id\":118,\"method\":\"textDocument/documentSymbol\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":15966,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":114}}"}
|
||
{"ts":15966,"msg":"{\"jsonrpc\":\"2.0\",\"id\":119,\"method\":\"textDocument/inlayHint\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"range\":{\"start\":{\"line\":0,\"character\":0},\"end\":{\"line\":13,\"character\":0}}}}"}
|
||
{"ts":16677,"msg":"{\"jsonrpc\":\"2.0\",\"id\":120,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":11,\"character\":12}}}"}
|
||
{"ts":16677,"msg":"{\"jsonrpc\":\"2.0\",\"id\":121,\"method\":\"textDocument/documentLink\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"}}}"}
|
||
{"ts":18279,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":120}}"}
|
||
{"ts":18510,"msg":"{\"jsonrpc\":\"2.0\",\"id\":122,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":7,\"character\":9}}}"}
|
||
{"ts":19831,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":122}}"}
|
||
{"ts":20030,"msg":"{\"jsonrpc\":\"2.0\",\"id\":123,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":9,\"character\":12}}}"}
|
||
{"ts":21092,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":123}}"}
|
||
{"ts":21285,"msg":"{\"jsonrpc\":\"2.0\",\"id\":124,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":9,\"character\":20}}}"}
|
||
{"ts":21404,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":124}}"}
|
||
{"ts":21662,"msg":"{\"jsonrpc\":\"2.0\",\"id\":125,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":7,\"character\":39}}}"}
|
||
{"ts":23066,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":125}}"}
|
||
{"ts":23422,"msg":"{\"jsonrpc\":\"2.0\",\"id\":126,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":9,\"character\":18}}}"}
|
||
{"ts":24724,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":126}}"}
|
||
{"ts":24922,"msg":"{\"jsonrpc\":\"2.0\",\"id\":127,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":9,\"character\":10}}}"}
|
||
{"ts":26768,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":127}}"}
|
||
{"ts":26966,"msg":"{\"jsonrpc\":\"2.0\",\"id\":128,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":7,\"character\":9}}}"}
|
||
{"ts":28269,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":128}}"}
|
||
{"ts":28606,"msg":"{\"jsonrpc\":\"2.0\",\"id\":129,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":7,\"character\":41}}}"}
|
||
{"ts":30260,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":129}}"}
|
||
{"ts":30462,"msg":"{\"jsonrpc\":\"2.0\",\"id\":130,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":9,\"character\":13}}}"}
|
||
{"ts":30565,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":130}}"}
|
||
{"ts":30758,"msg":"{\"jsonrpc\":\"2.0\",\"id\":131,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":9,\"character\":12}}}"}
|
||
{"ts":30866,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":131}}"}
|
||
{"ts":31066,"msg":"{\"jsonrpc\":\"2.0\",\"id\":132,\"method\":\"textDocument/hover\",\"params\":{\"textDocument\":{\"uri\":\"file:///home/ykiko/C%2B%2B/clice/tests/data/hello_world/main.cpp\"},\"position\":{\"line\":11,\"character\":14}}}"}
|
||
{"ts":31251,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"$/cancelRequest\",\"params\":{\"id\":132}}"}
|
||
{"ts":33730,"msg":"{\"jsonrpc\":\"2.0\",\"id\":133,\"method\":\"shutdown\"}"}
|
||
{"ts":33774,"msg":"{\"jsonrpc\":\"2.0\",\"method\":\"exit\"}"}
|