Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fba8b75
feat(index): serve open-file header symbols from PCH preamble index
16bit-ykiko Jul 11, 2026
b7ebb11
refactor(index): offset-based document links, flatter overlay code
16bit-ykiko Jul 11, 2026
acc3794
fix(server): align overlay sources with freshness and file rules
16bit-ykiko Jul 11, 2026
3c6b68c
fix(server): guard link offsets against races and stale idx blobs
16bit-ykiko Jul 11, 2026
ec9c70a
fix(index): scope shared main-file entries, macro definition ranges
16bit-ykiko Jul 11, 2026
c62d421
refactor(index): store preamble text in blob, drop bound proxy
16bit-ykiko Jul 11, 2026
893fe90
refactor(index): drop the links cache, materialize on demand
16bit-ykiko Jul 11, 2026
debffc1
refactor(server): drop assumptions the overlay design already rules out
16bit-ykiko Jul 11, 2026
2fff047
fix(index): reach overlay headers by path/line, skip edge-less entries
16bit-ykiko Jul 12, 2026
70c46cf
revert(index): overlays answer by hash only, drop lookup_file
16bit-ykiko Jul 12, 2026
ea0a599
refactor(server): keep PCH overlays out of agentic queries
16bit-ykiko Jul 12, 2026
09a1574
fix(support): drop stale aux blobs at adoption
16bit-ykiko Jul 12, 2026
fb93330
refactor(server): agentic queries serve disk truth
16bit-ykiko Jul 12, 2026
e2473e7
fix(index): index open files too, report status from progress
16bit-ykiko Jul 12, 2026
c6e65bc
refactor(index): gate open-file indexing on agentic use
16bit-ykiko Jul 12, 2026
69642c5
test(agentic): stop paying the idle timer per fixture
16bit-ykiko Jul 12, 2026
f07df4b
test(support): use the int-FD file APIs in StaleAuxDropped
16bit-ykiko Jul 12, 2026
8e0676c
fix(server): catch up open-file shards on disk-affecting events
16bit-ykiko Jul 12, 2026
7fbbde0
fix(query): match preamble source path across separators
16bit-ykiko Jul 12, 2026
b826da3
chore(server): carry the blob write cause into build errors
16bit-ykiko Jul 12, 2026
4d8076b
test(tools): surface worker crash traces in anomaly assertions
16bit-ykiko Jul 12, 2026
f2b9c41
test(index): prove forced includes stay in the preamble blob
16bit-ykiko Jul 12, 2026
02e2e7c
fix(server): gate agentic documentSymbols behind the shard gate
16bit-ykiko Jul 12, 2026
9a5ee6f
fix(server): write the preamble blob after the PCH flush
16bit-ykiko Jul 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/en/design/incremental-parse.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ The preamble is compiled into a PCH file and cached on disk. Subsequent compilat
- A hash of the preamble content
- The preamble byte boundary (bound)
- A dependency snapshot (`DepsSnapshot`, see below)
- DocumentLink information extracted from the PCH (`#include` directive positions and targets, for the editor to display clickable links)
- A handle to the paired preamble-state blob, stored next to the PCH and sharing its lifecycle: the preamble's symbol index plus feature state extracted at build time (document links, inactive regions, the open conditional stack), opened as a memory-mapped FlatBuffer and queried lazily (see [symbol index](symbol-index.md))

### Two-Layer Invalidation Detection

Expand Down
6 changes: 2 additions & 4 deletions docs/en/design/symbol-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,6 @@ Background indexing scheduling must balance index timeliness against interferenc

The improvement direction is to build a dedicated search index over symbol names. A tokenizer is needed to split symbol names by naming conventions (`getSymbolHash` → `[get, Symbol, Hash]`, `push_back` → `[push, back]`), then build an inverted index over the tokens. For example, trigrams (three-character groups) can be used as index keys, and at query time trigram intersections produce a candidate set that is then scored precisely. clangd's Dex index uses this trigram posting list approach and serves as a useful reference implementation. Another direction is to adopt a mature full-text search library, though the cost of introducing an external dependency needs to be evaluated.

- **PCH-induced index split**. When using PCH (precompiled header) optimization, a file's compilation is effectively split into two phases: first the preamble (the `#include` directives at the top of the file) is compiled to produce the PCH, then the PCH is used to compile the rest of the file. The PCH itself is a compilation unit and produces its own index data.
- ~~**PCH-induced index split**~~ (resolved). When using PCH optimization, a file's compilation is split into two phases: the preamble is compiled into the PCH, then the PCH compiles the rest of the file. The PCH swallows everything before the preamble bound — the main file's compilation cannot see the headers' contents or the preamble region's own directives, and an open buffer's preamble may describe a compilation context that no disk translation unit was ever indexed with.

This split affects the index. Take document links (clickable `#include` directives in the editor) as an example: `#include` directives in the preamble belong to the PCH compilation phase, and the main file's compilation cannot see them. Since the index system does not currently store document link information, it cannot reconstruct the PCH portion's results through the index. The current workaround is to pre-serialize the PCH's document links as JSON during PCH construction and store it in the PCH metadata, then manually splice it into the main file's results at query time. This works but is not clean.

A better approach would be to incorporate document links into the PCH metadata system (which already stores dependency file lists and other information), or to leverage the include relationship information already present in the index to reconstruct document links. The latter has the problem that index construction takes time, and after PCH compilation completes it should be put to use as quickly as possible — waiting for indexing to complete would add latency. Neither approach is fully implemented yet.
This is now addressed by pairing each PCH with a preamble-state blob, produced by the same worker build while the freshly parsed preamble AST is still in memory (the only moment its index is obtainable without deserializing the whole PCH). The blob carries the preamble's full symbol index — every covered header plus the main file's preamble region — together with per-file content and line tables for position mapping, document links, inactive regions and the open conditional stack. It is stored, hit and evicted together with the PCH, opened as a memory-mapped FlatBuffer and queried without deserialization. Open files overlay these blobs onto index queries: set queries take the union with disk shards (identical rows collapse by location), single-answer queries prefer the overlay, and the buffer's preamble region resolves through the blob's main-file entry. This keeps navigation working for open files whose translation unit the background indexer has not (or cannot) index, and keeps results faithful to unsaved preamble edits.
2 changes: 1 addition & 1 deletion docs/zh/design/incremental-parse.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Preamble 编译为 PCH 文件后缓存在磁盘上。后续编译加载 PCH 后
- preamble 内容的哈希值
- preamble 的字节边界(bound)
- 依赖快照(`DepsSnapshot`,见下文)
- PCH 中提取的 DocumentLink 信息(`#include` 指令的位置和目标,供编辑器显示可点击链接)
- 与 PCH 配对存储、共享生命周期的 preamble 状态 blob 的句柄:构建时提取的 preamble 符号索引和功能状态(document links、非活跃区域、未闭合条件栈),以内存映射 FlatBuffer 形式打开、按需懒查询(见[符号索引](symbol-index.md))

### 两层失效检测

Expand Down
6 changes: 2 additions & 4 deletions docs/zh/design/symbol-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,6 @@ FileIndex 打开文件的实时覆盖层(来自内存中的 AST)

改进方向是为符号名建立专门的搜索索引。需要一个分词器将符号名按命名约定拆分为词元(`getSymbolHash` → `[get, Symbol, Hash]`,`push_back` → `[push, back]`),然后基于词元建立倒排索引。例如使用 trigram(三字符组)作为索引键,查询时取 trigram 交集得到候选集,再精确评分排序。clangd 的 Dex 索引采用了这种 trigram posting list 方案,是一个可参考的实现。另一个方向是引入成熟的全文搜索库,但需要评估引入外部依赖的代价。

- **PCH 导致的索引分裂**。使用 PCH(预编译头)优化时,一个文件的编译实际上被分成两个阶段:先编译 preamble 部分(文件顶部的 `#include` 指令)生成 PCH,再用 PCH 编译文件的其余部分。PCH 本身也是一个编译单元,会产生独立的索引数据。
- ~~**PCH 导致的索引分裂**~~(已解决)。使用 PCH 优化时,一个文件的编译被分成两个阶段:先把 preamble 编译成 PCH,再用 PCH 编译文件的其余部分。PCH 吞掉了 bound 之前的一切——主文件的编译既看不到头文件的内容,也看不到 preamble 区自身的指令;而且打开缓冲区的 preamble 可能描述一个任何磁盘翻译单元都未曾以之索引过的编译上下文。

这种分裂对索引产生了影响。以 document links(编辑器中可点击的 `#include` 指令)为例:preamble 中的 `#include` 指令属于 PCH 编译阶段,主文件的编译看不到它们。而索引系统目前不存储 document links 信息,因此无法通过索引来补全 PCH 部分的结果。当前的做法是在 PCH 构建时将其 document links 预序列化为 JSON 存储在 PCH 元数据中,查询时手动拼接到主文件的结果中。这种做法可以工作但不够干净。

更合理的方案是将 document links 纳入 PCH 的元数据体系(目前 PCH 元数据已经存储了依赖文件列表等信息),或者利用索引中已有的 include 关系信息来重建 document links。后者的问题在于索引构建需要时间,而 PCH 编译完成后应尽快投入使用,等待索引完成会增加延迟。目前两种方案都尚未完整实现。
现在的方案是为每个 PCH 配对一个 preamble 状态 blob,由同一次 worker 构建在刚解析完的 preamble AST 仍在内存时产出(这是唯一无需完整反序列化 PCH 就能获得其索引的时机)。blob 携带 preamble 的完整符号索引——覆盖的每个头文件加上主文件的 preamble 区——以及每文件的内容与行表(用于位置换算)、document links、非活跃区域和未闭合条件栈。它与 PCH 一同存储、一同命中、一同淘汰,以内存映射 FlatBuffer 形式打开,查询无需反序列化。打开文件把这些 blob 作为 overlay 叠加到索引查询上:集合查询与磁盘分片取并集(相同行按位置坍缩),单答案查询优先 overlay,缓冲区 preamble 区的游标经 blob 的主文件条目解析。这使得后台索引尚未(或无法)覆盖其翻译单元的打开文件仍能正常导航,查询结果也忠实于未保存的 preamble 编辑。
11 changes: 6 additions & 5 deletions src/feature/document_link.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

#include <string>

#include "kota/ipc/lsp/protocol.h"
#include "syntax/token.h"

namespace clice::feature {

/// A resolved document link: the argument range of an include-like
/// directive and the absolute path of the target file. Plain data — it
/// serializes over the worker RPC as-is and becomes an LSP DocumentLink
/// only at the reply edge.
/// directive (byte offsets in the containing file) and the absolute path
/// of the target file. Plain data — it serializes over the worker RPC and
/// the PCH's PreambleState blob as-is and becomes an LSP DocumentLink only
/// at the reply edge, where the session's line map does the conversion.
struct DocumentLink {
kota::ipc::protocol::Range range;
LocalSourceRange range;
std::string target;
};

Expand Down
9 changes: 2 additions & 7 deletions src/feature/document_links.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@

namespace clice::feature {

auto document_links(CompilationUnitRef unit, PositionEncoding encoding)
-> std::vector<DocumentLink> {
auto document_links(CompilationUnitRef unit) -> std::vector<DocumentLink> {
std::vector<DocumentLink> links;

auto interested = unit.interested_file();
Expand All @@ -20,7 +19,6 @@ auto document_links(CompilationUnitRef unit, PositionEncoding encoding)
auto content = unit.interested_content();
auto& directives = directives_it->second;
auto* lang_opts = &unit.lang_options();
LineMap map(content, unit.line_starts(), encoding);

auto add_link = [&](clang::SourceLocation loc, llvm::StringRef target) {
auto [fid, offset] = unit.decompose_location(loc);
Expand All @@ -29,10 +27,7 @@ auto document_links(CompilationUnitRef unit, PositionEncoding encoding)
auto range = find_directive_argument(content, offset, lang_opts);
if(!range)
return;
auto protocol_range = to_range(map, *range);
if(!protocol_range)
return;
links.push_back(DocumentLink{.range = *protocol_range, .target = target.str()});
links.push_back(DocumentLink{.range = *range, .target = target.str()});
};

for(const auto& include: directives.includes) {
Expand Down
5 changes: 3 additions & 2 deletions src/feature/feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,9 @@ auto inlay_hints(CompilationUnitRef unit,
const InlayHintsOptions& options,
PositionEncoding encoding) -> std::vector<protocol::InlayHint>;

auto document_links(CompilationUnitRef unit, PositionEncoding encoding = PositionEncoding::UTF16)
-> std::vector<DocumentLink>;
/// Include-directive links of the interested file, in byte offsets; the
/// reply edge converts them with the session's line map.
auto document_links(CompilationUnitRef unit) -> std::vector<DocumentLink>;

/// Go-to-definition on an include directive: when `offset` falls on the
/// argument of an #include or __has_include in the interested file, the
Expand Down
Loading
Loading