Skip to content

Commit 47a4d06

Browse files
16bit-ykikoclaude
andcommitted
feat: add master stderr logger, simplify build flow, wait for AST in workers
- Add stderr_logger for master server in pipe/socket modes so logs are visible - Remove scan_file, compile_graph deps check, and background indexer from build flow (not needed until PCH/PCM support is added) - Add ast_ready event to stateful worker so feature handlers wait for compilation instead of returning null immediately - Remove dirty document early-return in feature handlers (stale results > null) - Rewrite integration tests with pygls and stronger assertions for features - Format all changed files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9a7b01f commit 47a4d06

File tree

21 files changed

+983
-1058
lines changed

21 files changed

+983
-1058
lines changed

pixi.lock

Lines changed: 86 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pixi.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ scripts = ["scripts/activate_asan.bat"]
4949
[feature.test.pypi-dependencies]
5050
pytest = "*"
5151
pytest-asyncio = ">=1.1.0"
52+
pygls = ">=2.0.0"
53+
lsprotocol = ">=2024.0.0"
5254

5355
[feature.package.dependencies]
5456
xz = ">=5.8.1,<6"

src/clice.cc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ int main(int argc, const char** argv) {
7878
return 1;
7979
}
8080

81+
std::string self_path = llvm::sys::fs::getMainExecutable(argv[0], (void*)main);
82+
if(!clice::fs::init_resource_dir(self_path)) {
83+
LOG_ERROR("Cannot find the resource dir: {}", self_path);
84+
}
85+
8186
auto& mode = *opts.mode;
8287

8388
if(mode == "stateless-worker") {
@@ -90,6 +95,8 @@ int main(int argc, const char** argv) {
9095
}
9196

9297
if(mode == "pipe") {
98+
clice::logging::stderr_logger("master", clice::logging::options);
99+
93100
namespace et = eventide;
94101
et::event_loop loop;
95102

@@ -99,8 +106,6 @@ int main(int argc, const char** argv) {
99106
return 1;
100107
}
101108

102-
std::string self_path = llvm::sys::fs::getMainExecutable(argv[0], (void*)main);
103-
104109
et::ipc::JsonPeer peer(loop, std::move(*transport));
105110
clice::MasterServer server(loop, peer, std::move(self_path));
106111
server.register_handlers();
@@ -110,6 +115,8 @@ int main(int argc, const char** argv) {
110115
}
111116

112117
if(mode == "socket") {
118+
clice::logging::stderr_logger("master", clice::logging::options);
119+
113120
namespace et = eventide;
114121
et::event_loop loop;
115122

@@ -124,8 +131,6 @@ int main(int argc, const char** argv) {
124131

125132
LOG_INFO("Listening on {}:{} ...", host, port);
126133

127-
std::string self_path = llvm::sys::fs::getMainExecutable(argv[0], (void*)main);
128-
129134
auto task = [&]() -> et::task<> {
130135
auto client = co_await acceptor->accept();
131136
if(!client.has_value()) {
@@ -142,6 +147,7 @@ int main(int argc, const char** argv) {
142147
server.register_handlers();
143148

144149
co_await peer.run();
150+
peer.close();
145151
loop.stop();
146152
};
147153

src/compile/compilation.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,17 @@ std::unique_ptr<clang::CompilerInvocation>
4444

4545
std::unique_ptr<clang::CompilerInvocation> invocation;
4646

47-
/// Arguments from compilation database are already cc1
48-
if(params.arguments_from_database) {
47+
/// If the second argument is "-cc1", the arguments are already expanded
48+
/// (e.g. from compilation database + query_toolchain). Skip driver and "-cc1"
49+
/// and create invocation directly from the cc1 args.
50+
bool is_cc1 = params.arguments.size() >= 2 && llvm::StringRef(params.arguments[1]) == "-cc1";
51+
if(is_cc1) {
4952
invocation = std::make_unique<clang::CompilerInvocation>();
50-
if(!clang::CompilerInvocation::CreateFromArgs(*invocation,
51-
llvm::ArrayRef(params.arguments).drop_front(),
52-
*diagnostic_engine,
53-
params.arguments[0])) {
53+
if(!clang::CompilerInvocation::CreateFromArgs(
54+
*invocation,
55+
llvm::ArrayRef(params.arguments).drop_front(2),
56+
*diagnostic_engine,
57+
params.arguments[0])) {
5458
LOG_ERROR_RET(nullptr,
5559
" Fail to create invocation, arguments list is: {}",
5660
print_argv(params.arguments));

src/compile/compilation.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,6 @@ struct CompilationParams {
7575

7676
std::string directory;
7777

78-
bool arguments_from_database = false;
79-
8078
/// Responsible for storing the arguments.
8179
std::vector<const char*> arguments;
8280

src/compile/toolchain.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ std::vector<const char*> query_toolchain(const QueryParams& params) {
382382
query_driver(params_copy.arguments,
383383
[&](const char* driver, llvm::ArrayRef<const char*> cc1_args) {
384384
result.emplace_back(params.callback(driver));
385+
result.emplace_back(params.callback("-cc1"));
385386
for(auto arg: cc1_args) {
386387
result.emplace_back(params.callback(arg));
387388
}
@@ -435,6 +436,7 @@ std::vector<const char*> query_gcc_toolchain(const QueryParams& params) {
435436
std::vector<const char*> result;
436437
query_driver(query_arguments, [&](const char* driver, llvm::ArrayRef<const char*> cc1_args) {
437438
result.emplace_back(params.callback(driver));
439+
result.emplace_back(params.callback("-cc1"));
438440
for(auto arg: cc1_args) {
439441
result.emplace_back(params.callback(arg));
440442
}

src/server/master_server.cpp

Lines changed: 40 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88

99
#include "eventide/ipc/lsp/position.h"
1010
#include "eventide/ipc/lsp/uri.h"
11+
#include "eventide/reflection/enum.h"
1112
#include "eventide/serde/json/json.h"
1213
#include "eventide/serde/serde/raw_value.h"
14+
#include "semantic/symbol_kind.h"
1315
#include "server/protocol.h"
1416
#include "support/filesystem.h"
1517
#include "support/logging.h"
@@ -100,32 +102,18 @@ et::task<> MasterServer::run_build_drain(std::uint32_t path_id, std::string uri)
100102
doc_it->second.build_requested = false;
101103
auto gen = doc_it->second.generation;
102104

103-
// Ensure PCM/PCH dependencies are ready
104-
auto deps_ok = co_await compile_graph.compile_deps(path_id, loop);
105-
106-
// Re-lookup after co_await (map may have changed)
107-
doc_it = documents.find(path_id);
108-
if(doc_it == documents.end())
109-
co_return;
110-
111-
if(!deps_ok) {
112-
LOG_WARN("Dependency compilation failed for {}, skipping build", uri);
113-
clear_diagnostics(uri);
114-
if(!doc_it->second.build_requested) {
115-
doc_it->second.build_running = false;
116-
doc_it->second.drain_scheduled = false;
117-
co_return;
118-
}
119-
continue;
120-
}
121-
122105
// Send compile request to stateful worker
123106
worker::CompileParams params;
124107
params.path = std::string(path_pool.resolve(path_id));
125108
params.version = doc_it->second.version;
126109
params.text = doc_it->second.text;
127110
fill_compile_args(path_pool.resolve(path_id), params.directory, params.arguments);
128111

112+
LOG_DEBUG("Sending compile: path={}, args={}, gen={}",
113+
params.path,
114+
params.arguments.size(),
115+
gen);
116+
129117
auto result = co_await pool.send_stateful<worker::CompileParams>(path_id, params);
130118

131119
// Re-lookup document (may have been closed during compile)
@@ -139,6 +127,11 @@ et::task<> MasterServer::run_build_drain(std::uint32_t path_id, std::string uri)
139127
// Only publish diagnostics if the generation hasn't changed
140128
if(doc2.generation == gen) {
141129
publish_diagnostics(uri, doc2.version, result.value().diagnostics);
130+
} else {
131+
LOG_DEBUG("Generation mismatch ({} vs {}), dropping diagnostics for {}",
132+
doc2.generation,
133+
gen,
134+
uri);
142135
}
143136
} else {
144137
LOG_WARN("Compile failed for {}: {}", uri, result.error().message);
@@ -201,19 +194,6 @@ et::task<> MasterServer::load_workspace() {
201194

202195
auto updates = cdb.load_compile_database(cdb_path);
203196
LOG_INFO("Loaded CDB from {} with {} entries", cdb_path, updates.size());
204-
205-
// Scan all source files from CDB to build include graph
206-
auto all_files = cdb.files();
207-
for(auto* file: all_files) {
208-
auto path_id = path_pool.intern(file);
209-
scan_file(path_id, file);
210-
}
211-
212-
LOG_INFO("Initial scan complete, {} files in include graph", include_forward.size());
213-
214-
// Populate the index queue with all CDB files for background indexing
215-
populate_index_queue();
216-
LOG_INFO("Index queue populated with {} files", index_queue.size());
217197
}
218198

219199
void MasterServer::scan_file(std::uint32_t path_id, llvm::StringRef path) {
@@ -223,7 +203,6 @@ void MasterServer::scan_file(std::uint32_t path_id, llvm::StringRef path) {
223203

224204
auto results = scan_fuzzy(ctx.arguments,
225205
ctx.directory,
226-
/*arguments_from_database=*/true,
227206
/*content=*/{},
228207
&scan_cache);
229208

@@ -254,7 +233,7 @@ void MasterServer::scan_file(std::uint32_t path_id, llvm::StringRef path) {
254233
void MasterServer::fill_compile_args(llvm::StringRef path,
255234
std::string& directory,
256235
std::vector<std::string>& arguments) {
257-
auto ctx = cdb.lookup(path);
236+
auto ctx = cdb.lookup(path, {.resource_dir = true, .query_toolchain = true});
258237
directory = ctx.directory.str();
259238
arguments.clear();
260239
for(auto* arg: ctx.arguments) {
@@ -414,7 +393,32 @@ void MasterServer::register_handlers() {
414393

415394
// Semantic tokens
416395
protocol::SemanticTokensOptions sem_opts;
417-
sem_opts.legend = protocol::SemanticTokensLegend{{}, {}};
396+
{
397+
auto lower_first = [](std::string_view name) -> std::string {
398+
std::string s(name);
399+
if(!s.empty()) {
400+
s[0] = static_cast<char>(std::tolower(static_cast<unsigned char>(s[0])));
401+
}
402+
return s;
403+
};
404+
405+
std::vector<std::string> token_types;
406+
using SymbolKindRefl = eventide::refl::reflection<SymbolKind::Kind>;
407+
for(std::size_t i = 0; i < SymbolKindRefl::member_count; ++i) {
408+
token_types.push_back(lower_first(SymbolKindRefl::member_names[i]));
409+
}
410+
411+
std::vector<std::string> token_modifiers;
412+
using SymbolModRefl = eventide::refl::reflection<SymbolModifiers::Kind>;
413+
for(std::size_t i = 0; i < SymbolModRefl::member_count; ++i) {
414+
token_modifiers.push_back(lower_first(SymbolModRefl::member_names[i]));
415+
}
416+
417+
sem_opts.legend = protocol::SemanticTokensLegend{
418+
std::move(token_types),
419+
std::move(token_modifiers),
420+
};
421+
}
418422
sem_opts.full =
419423
protocol::variant<protocol::boolean, protocol::SemanticTokensFullDelta>{true};
420424
result.capabilities.semantic_tokens_provider = std::move(sem_opts);
@@ -452,13 +456,8 @@ void MasterServer::register_handlers() {
452456

453457
lifecycle = ServerLifecycle::Ready;
454458

455-
// Load CDB and build include graph in background
459+
// Load CDB in background
456460
loop.schedule(load_workspace());
457-
458-
// Start background indexer coroutine if enabled
459-
if(config.enable_indexing) {
460-
loop.schedule(run_background_indexer());
461-
}
462461
});
463462

464463
// === shutdown ===
@@ -502,19 +501,6 @@ void MasterServer::register_handlers() {
502501
// Reset idle timer on user activity
503502
reset_idle_timer();
504503

505-
// Scan includes and register compile unit
506-
scan_file(path_id, path);
507-
508-
// Get dependency path_ids from the forward graph
509-
llvm::SmallVector<std::uint32_t> deps;
510-
auto fwd_it = include_forward.find(path_id);
511-
if(fwd_it != include_forward.end()) {
512-
for(auto dep_id: fwd_it->second) {
513-
deps.push_back(dep_id);
514-
}
515-
}
516-
compile_graph.register_unit(path_id, deps);
517-
518504
schedule_build(path_id, td.uri);
519505
});
520506

@@ -570,10 +556,6 @@ void MasterServer::register_handlers() {
570556
// Reset idle timer on user activity
571557
reset_idle_timer();
572558

573-
// Rescan the file to update include graph
574-
scan_file(path_id, path);
575-
576-
compile_graph.update(path_id);
577559
schedule_build(path_id, params.text_document.uri);
578560
});
579561

0 commit comments

Comments
 (0)