From 697c0f40cb86b749a6ca131a6c6c32dc67a6546b Mon Sep 17 00:00:00 2001 From: 16bit-ykiko <119843247+16bit-ykiko@users.noreply.github.com> Date: Fri, 10 Jul 2026 06:56:02 +0000 Subject: [PATCH] docs: sync clice --- en/clice/changelog/feature-changelog.md | 39 ++++++++++++++++ en/clice/design/incremental-parse.md | 12 ++--- en/clice/design/overview.md | 23 +++++++--- en/clice/dev/test-and-debug.md | 2 +- en/clice/guide/configuration.md | 52 +++++++++++++++++----- en/clice/guide/editors.md | 4 +- zh/clice/changelog/feature-changelog.md | 59 +++++++++++++++++++++++++ zh/clice/design/incremental-parse.md | 12 ++--- zh/clice/design/overview.md | 23 +++++++--- zh/clice/dev/test-and-debug.md | 2 +- zh/clice/guide/configuration.md | 58 ++++++++++++++++++------ zh/clice/guide/editors.md | 4 +- 12 files changed, 231 insertions(+), 59 deletions(-) create mode 100644 zh/clice/changelog/feature-changelog.md diff --git a/en/clice/changelog/feature-changelog.md b/en/clice/changelog/feature-changelog.md index 53e23bf4..0e0e0e6a 100644 --- a/en/clice/changelog/feature-changelog.md +++ b/en/clice/changelog/feature-changelog.md @@ -18,3 +18,42 @@ This file tracks user-facing feature changes across clice releases. Each release ### Removed - ... --> + +## v1.0.0 (upcoming) + +v1.0 ships first as rolling beta releases (`v1.0.0-beta.1`, `beta.2`, …) for a public trial period; fixes land continuously in small versions with no code freeze, and the final `v1.0.0` is tagged once the trial settles. This entry summarizes everything user-visible since the `v0.1.0-alpha` series. + +### Added + +- **Multi-process architecture.** Compilation runs in worker subprocesses coordinated by a master process, so a compiler crash on one translation unit no longer takes down the whole session — the crashed worker is respawned and its documents recover on demand. Stateful workers cap resident documents with LRU eviction, and the pool sheds background load under system memory pressure. +- **Compilation contexts for headers.** Opening a header compiles it in the context of a source file that includes it: clice reconstructs the include chain into a synthesized preamble (and a synthesized suffix for X-macro/`.def` fragments), so symbols that depend on the includer's macros resolve correctly. Editors can list and switch the active context through the `clice/queryContext`, `clice/currentContext`, and `clice/switchContext` extensions — the same mechanism switches between multiple compile-database entries for one file. Self-contained headers are detected and compiled directly. +- **LSP feature surface.** Hover (definition printing, documentation, record layout with size/offset/padding, expression values, `auto`/`decltype` deduction); code completion with signature details, parameter snippets, deprecation strikethrough, and `#include`/`import` path completion; signature help; go-to definition (including on `#include` lines and module names), declaration, implementation, type definition, and find references, served from the project index; document symbols; semantic tokens with rich modifiers; inlay hints; folding ranges; document links (including inside the preamble, and `#embed`); `.clang-format`-based formatting and range formatting; call hierarchy and type hierarchy; workspace symbol search; published diagnostics; inactive-region greying for code disabled by `#if` (`clice/inactiveRegions` extension). +- **Background indexing.** A persistent project-wide index powers cross-file features without opening every file. Indexing piggybacks on compilations that already happen, runs concurrently at low priority, pauses for interactive requests, reports LSP `$/progress`, and survives restarts. Two-layer staleness detection (mtime, then content hash) keeps `touch` and `git checkout` from triggering needless rebuilds. +- **Out-of-band change tracking.** A stat-polling file tracker picks up changes made outside the editor — a regenerated `compile_commands.json`, a `git checkout`, code generators — without restarting the server. +- **C++20 named modules.** Module interfaces are compiled on demand through a pull-based dependency graph with PCM caching; `import` completion and go-to-definition on module names included. +- **Unified on-disk cache.** PCH, PCM, and index artifacts live in one content-addressed store with crash-safe writes, shared across sessions and restarts; the rebuildable artifacts (PCH/PCM) are evicted under a size bound. +- **Configuration.** `clice.toml` (or `.clice/config.toml`) plus LSP `initializationOptions` overlay; per-file `[[rules]]` with glob patterns to append/remove compile flags; `[tracker]` polling intervals; XDG-based cache paths with `${workspace}` substitution. Malformed configuration is reported with line/column as diagnostics on the config file. +- **Tooling API.** A JSON-RPC API over TCP for AI agents and external tools: project files, symbol search, reading full symbol bodies, definitions/references, call graph, and type hierarchy — plus the `clice query` CLI. +- **Editor extensions.** In-repo extensions for VS Code (published on the Marketplace), Neovim, and Zed. +- **Operability.** Per-session file logging with crash capture, user-facing guidance via `window/logMessage` when the setup is broken (e.g. no compilation database), LSP session recording for replay (`--record`), and an accurate `--version` that matches the release tag. + +### Changed + +- **Configuration file location.** The `config` CLI option is gone; configuration is read from `${workspace}/clice.toml` (or `${workspace}/.clice/config.toml`). +- **Config key rename.** `compile_commands_dirs` is now `compile_commands_paths`; the old key is ignored. +- **Upgrading from 0.x rebuilds caches.** The on-disk cache and index formats changed; the first launch after upgrading discards old artifacts and re-indexes the project once. This also retires PCHs produced by older versions whose cache key ignored compile flags — those could serve results with the wrong macro configuration. +- **Toolchain baseline.** clice now builds against LLVM/Clang 21.1.8, with prebuilt release binaries for Linux, macOS, and Windows on both x64 and arm64. + +### Fixed + +- Rapid consecutive edits no longer produce spurious "redefinition" errors from a compile/update race. +- Several worker crashes on malformed input (null AST consumer, invalid file IDs, missing cache directories) fixed; crashes that do happen are contained by process isolation. +- Documents evicted from a worker's LRU no longer silently lose hover/semantic tokens — they recompile on the next request. +- Lifecycle edge cases: a `didOpen` racing ahead of the `initialize` handshake is accepted; unknown enum values from newer LSP clients no longer fail the handshake; diagnostics produced before the client was ready are replayed after `initialized`. +- Saving a header now correctly reindexes closed files that include it, keeping cross-file references fresh. + +### Known gaps + +- Code completion, navigation, document links, and diagnostics are functional but not yet complete (see the feature overview pages for per-feature status). +- Code actions are not implemented yet (and not advertised). +- clang-tidy integration is planned; the `clang_tidy` config option is parsed but has no effect. diff --git a/en/clice/design/incremental-parse.md b/en/clice/design/incremental-parse.md index d8fb12db..b1f693b7 100644 --- a/en/clice/design/incremental-parse.md +++ b/en/clice/design/incremental-parse.md @@ -79,13 +79,13 @@ When the user edits a file (`didChange`), the master process only updates the in The benefit of this model is avoiding wasteful compilations during rapid successive keystrokes. The user may trigger a dozen `didChange` events per second, but compilation only executes when an actual result is needed -- such as a hover or completion request. -> Note that "external file changes" and "user edits" are two independent dirty-marking paths. User edits mark `ast_dirty` via `didChange`; external file changes (e.g., a dependency header modified on disk) are discovered dynamically via two-layer invalidation detection before compilation. +> Note that "external file changes" and "user edits" are two independent dirty-marking paths. User edits mark `ast_dirty` via `didChange`. External file changes (e.g., a dependency header modified on disk) are discovered proactively: a stat-polling file tracker feeds change events to the invalidation engine, which marks the affected files dirty. The two-layer detection before compilation remains as the defensive backstop for anything the polls have not seen yet. ### Content-Addressed PCH Storage -PCH files on disk are named by the hash of the preamble content (e.g., `a3f7e8c1d2b4f6e9.pch`), implementing content-addressed storage. This provides two benefits: +PCH files on disk are named by a hash of the preamble content together with the frontend-relevant compile flags, directories, and clang version (e.g., `a3f7e8c1d2b4f6e9.pch`), implementing content-addressed storage. This provides two benefits: -- **Disk sharing**: Different files with identical preamble content naturally share the same PCH file on disk, with no additional deduplication logic needed. +- **Disk sharing**: Different files whose preamble content and compile configuration agree naturally share the same PCH file on disk, with no additional deduplication logic needed. - **Cross-session persistence**: PCH cache metadata (path, hash, boundary, dependency snapshot) is serialized to a `cache.json` file on disk. On server restart, this metadata is loaded and each PCH's validity is verified through two-layer invalidation detection, avoiding the need to rebuild all PCHs on a cold start. When preamble content changes, the new PCH uses a different hash for its filename and the old file becomes orphaned. A cleanup mechanism periodically reclaims orphaned PCH files that have not been used beyond a certain age. @@ -188,12 +188,8 @@ After loading the cache on startup, all PCH entries are validated through two-la ## Known Limitations -- **Per-file independent caching**. The PCH cache is keyed by file path identifier. Even if two files have identical preamble content, they have independent cache entries -- each performing its own invalidation detection and build. While the PCH files on disk are shared through content-addressed naming, cache metadata (dependency snapshots, build state, etc.) is not shared. The improvement direction is to key the cache by preamble content hash plus compilation flags, enabling cross-file cache metadata sharing. - - **Full rebuild**. Any content change in a dependency file triggers a full PCH rebuild, with no way to rebuild only the affected portion. The improvement direction is to adopt chained PCH (see FAQ), limiting the rebuild scope to the chain links after the point of change. -- **Compilation flags not part of cache key**. PCH disk filenames and cache lookups do not consider compilation flags. When two files have the same preamble text but different compilation flags (e.g., `-D`), they may incorrectly share a PCH. The improvement direction is to include preprocessing-relevant compilation flags in the cache key. - - **Incomplete preamble completeness check**. The current completeness check only covers unclosed quotes and missing semicolons in `#include`/`import` directives. Other types of incomplete edits (e.g., typing a `#define` value) are not detected. The impact of building a PCH from such an incomplete preamble on subsequent compilation has not been thoroughly tested. Further investigation is needed into Clang's behavior when processing incomplete preprocessor directives, to determine whether the completeness check scope should be extended. -- **No proactive diagnostics push after header save**. Under the current pure pull-based model, after a user saves a header file, open source files that depend on it do not immediately update diagnostics -- the user must trigger an action on the source file (e.g., hover, edit) for the two-layer invalidation detection to discover the change and trigger recompilation. The improvement direction is to check affected open sessions on `didSave` and proactively trigger compilation for them (a hybrid push/pull model). +- **No proactive recompilation after a header save**. Saving a header (or a change discovered by the file tracker) proactively marks dependent open files dirty, but recompilation stays pull-triggered: their diagnostics refresh on the next request against that file (e.g., hover, edit) rather than immediately. The improvement direction is to proactively trigger compilation for the affected open sessions (a hybrid push/pull model). diff --git a/en/clice/design/overview.md b/en/clice/design/overview.md index 34a8fceb..0892130c 100644 --- a/en/clice/design/overview.md +++ b/en/clice/design/overview.md @@ -77,7 +77,7 @@ Concrete implementations of LSP features. Each feature takes a `CompilationUnitR Includes: code completion, hover information, signature help, semantic highlighting, inlay hints, document symbols, document links, folding ranges, formatting, diagnostics, etc. -> `feature/` only covers single-file, AST-based feature implementations. Cross-file navigation features (go to definition, find references, etc.) are handled by the `Indexer` using index data. Some features involve multi-phase processing -- for example, include path completion in code completion can be resolved at the syntax layer without full compilation. +> `feature/` only covers single-file, AST-based feature implementations. Cross-file navigation features (go to definition, find references, etc.) are served from index data by the server's `service/` layer (`FeatureRouter`/`IndexQuery`). Some features involve multi-phase processing -- for example, include path completion in code completion can be resolved at the syntax layer without full compilation. ### `src/server/` — Server Runtime @@ -85,18 +85,29 @@ The language server's core runtime, responsible for assembling all the layers ab **`protocol/`** — Protocol definitions. Describes the message formats for communication between the master process and worker processes, as well as between the server and clients. Includes Worker protocol (compilation/query/build requests), LSP extension protocol (compilation context switching, etc.), and the agentic protocol for AI agents. -**`workspace/`** — Project-level global state. `Workspace` holds the compilation database, toolchain, path pool, dependency graph, PCH/PCM cache, project index, and all other project-level state. Core invariant: unsaved buffer contents of open files never modify the `Workspace` -- it only reflects the state on disk. +**`state/`** — Project and document state, plus the invalidation machinery. + +- `Workspace`: Project-level global state — the compilation database, toolchain, path pool, dependency graph, cache store, and project index. Core invariant: unsaved buffer contents of open files never modify the `Workspace` -- it only reflects the state on disk +- `Session` / `SessionStore`: The editing state for each open file (buffer contents, document version, in-memory index, PCH reference, etc.), created on didOpen and destroyed on didClose; `SessionStore` owns the table of open sessions and the buffer-synchronization logic +- `Invalidator`: The invalidation engine — folds file events (buffer opens/saves, on-disk changes, compilation-database reloads, worker crashes) into a deduplicated set of invalidation effects +- `FileTracker`: Stat-polling discovery of changes that happen outside the editor (a regenerated `compile_commands.json`, `git checkout`), feeding events to the `Invalidator` +- `Config`: Loading and merging of `clice.toml` and LSP `initializationOptions` **`compiler/`** — Compilation scheduling and index management. - `Compiler`: The scheduler for compilation lifecycles. Coordinates the ordering of PCH builds, module dependency resolution, and AST compilation, dispatching compilation tasks to worker processes - `CompileGraph`: The DAG scheduler for C++20 module compilation. Uses reference counting for interest tracking, supporting dependency cascade cancellation -- `Indexer`: Handles background indexing scheduling and serves as the entry point for cross-file queries. Combines `ProjectIndex`, `MergedIndex`, and in-memory indexes for open files to provide query results +- `ContextResolver`: Resolves the compile command and includer context a file is compiled under, owning header-context state and synthesized preambles +- `Indexer`: Background indexing scheduling — enqueues stale files, dispatches index builds to workers, and merges the resulting shards + +**`service/`** — Read-side services consuming compilation and index results. + +- `FeatureRouter`: Routes feature requests to the compiler (AST-backed features) or the index (cross-file navigation), merging both where needed +- `IndexQuery`: The query facade over `ProjectIndex`, `MergedIndex`, and the in-memory indexes of open files -**`service/`** — Service entry point and session management. +**`transport/`** — Protocol endpoints driving the server. -- `MasterServer`: The top-level coordinator. Holds `Workspace`, `Session` map, `WorkerPool`, `Compiler`, and `Indexer`, routing LSP requests to the appropriate handling logic -- `Session`: The editing state for each open file (buffer contents, compilation version number, in-memory index, PCH reference, etc.). Created on didOpen, destroyed on didClose +- `MasterServer`: The composition root. Owns the `Workspace`, `SessionStore`, `WorkerPool`, and all services above, and executes the `Invalidator`'s effects through its single dispatch entry point - `LSPClient` / `AgentClient`: Request handlers for the LSP protocol and agentic protocol **`worker/`** — Worker process management. diff --git a/en/clice/dev/test-and-debug.md b/en/clice/dev/test-and-debug.md index 8b5df6bf..f9c85645 100644 --- a/en/clice/dev/test-and-debug.md +++ b/en/clice/dev/test-and-debug.md @@ -51,7 +51,7 @@ pixi run smoke-test Debug # debug build Equivalent to: ```bash -python tests/replay.py tests/smoke/*.jsonl \ +python tests/tools/replay.py tests/smoke/*.jsonl \ --clice=./build/RelWithDebInfo/bin/clice ``` diff --git a/en/clice/guide/configuration.md b/en/clice/guide/configuration.md index 15880fdf..ff6fd4f3 100644 --- a/en/clice/guide/configuration.md +++ b/en/clice/guide/configuration.md @@ -1,6 +1,8 @@ # Configuration -clice reads configuration from `clice.toml` in the workspace root. Configuration can also be passed via LSP `initializationOptions` (JSON format). +clice reads configuration from `clice.toml` in the workspace root, or from `.clice/config.toml` if the former does not exist. Configuration can also be passed via LSP `initializationOptions` (JSON format); values from `initializationOptions` override the config file, and defaults fill in whatever remains unset after the merge. + +Configuration is read once at server startup. Changing it — either file — requires restarting the server; there is no hot reload. ## Variable Substitution @@ -34,15 +36,7 @@ Maximum number of active files to keep in memory. **Not yet wired** — the opti | -------- | ------------------------------------------------------- | | `string` | `$XDG_CACHE_HOME/clice/` or `${workspace}/.clice` | -Directory for storing PCH and PCM cache files. The default uses XDG_CACHE_HOME (or `~/.cache`) with a workspace-specific hash subdirectory. Falls back to `${workspace}/.clice` if the XDG directory cannot be created. - -### `project.index_dir` - -| Type | Default | -| -------- | -------------------- | -| `string` | `${cache_dir}/index` | - -Directory for storing index files. +Directory for the unified on-disk cache (PCH, PCM, and index artifacts all live here). The default uses XDG_CACHE_HOME (or `~/.cache`) with a workspace-specific hash subdirectory. Falls back to `${workspace}/.clice` if the XDG directory cannot be created. ### `project.logging_dir` @@ -90,7 +84,23 @@ Number of stateful worker processes. These hold ASTs in memory and serve queries | -------- | ----------------- | | `uint32` | `max(cores/2, 2)` | -Number of stateless worker processes. These handle ephemeral tasks (PCH/PCM builds, completion, signature help). +Number of stateless worker processes spawned at startup. These handle ephemeral tasks (PCH/PCM builds, completion, signature help). + +### `project.min_stateless_worker_count` + +| Type | Default | +| -------- | ---------- | +| `uint32` | `0` (auto) | + +Lower bound for dynamic scale-down of stateless workers. `0` resolves to an automatic minimum. + +### `project.max_stateless_worker_count` + +| Type | Default | +| -------- | ---------- | +| `uint32` | `0` (auto) | + +Upper bound for dynamic scale-up of stateless workers. `0` resolves to the CPU core count. ### `project.worker_memory_limit` @@ -100,6 +110,26 @@ Number of stateless worker processes. These handle ephemeral tasks (PCH/PCM buil Per-worker memory limit in bytes. **Not yet enforced** — the option is parsed but memory-based eviction/restart is not implemented yet. +## Tracker + +The file tracker polls for changes that happen outside the editor (a `git checkout`, a regenerated `compile_commands.json`, code generators writing headers) so the server picks them up without a restart. Setting an interval to `0` disables that polling loop. + +### `tracker.cdb_poll_seconds` + +| Type | Default | +| -------- | ------- | +| `uint32` | `3` | + +Interval for re-checking the compilation database file. + +### `tracker.workspace_poll_seconds` + +| Type | Default | +| -------- | ------- | +| `uint32` | `30` | + +Interval for sweeping workspace files for on-disk changes. + ## Rules `[[rules]]` is an array of rule objects. Rules are matched in declaration order — later rules override earlier ones. diff --git a/en/clice/guide/editors.md b/en/clice/guide/editors.md index fbf0a692..81418984 100644 --- a/en/clice/guide/editors.md +++ b/en/clice/guide/editors.md @@ -5,7 +5,7 @@ clice implements the [Language Server Protocol](https://microsoft.github.io/lang All setups assume: - The `clice` executable is on your `PATH` (or use an absolute path in the snippets below). -- Your project provides a `compile_commands.json` (by default clice searches the workspace root and `build/`). +- Your project provides a `compile_commands.json` (by default clice searches the workspace root, then each of its immediate subdirectories). ## Official Plugins @@ -96,7 +96,7 @@ With [vim-lsp](https://github.com/prabirshrestha/vim-lsp): if executable('clice') au User lsp_setup call lsp#register_server({ \ 'name': 'clice', - \ 'cmd': {server_info->['clice', 'server']}, + \ 'cmd': {server_info->['clice', 'serve']}, \ 'allowlist': ['c', 'cpp'], \ }) endif diff --git a/zh/clice/changelog/feature-changelog.md b/zh/clice/changelog/feature-changelog.md new file mode 100644 index 00000000..9e3a9c16 --- /dev/null +++ b/zh/clice/changelog/feature-changelog.md @@ -0,0 +1,59 @@ +# Feature Changelog + +本文件记录 clice 各版本面向用户的功能变化。每个版本章节记录新功能、破坏性变更与废弃项。 + + + + +## v1.0.0(即将发布) + +v1.0 会先以滚动的测试版发布(`v1.0.0-beta.1`、`beta.2`……)公开试跑一段时间;修复以小版本持续发布、不设代码冻结窗口,试跑稳定后打正式的 `v1.0.0`。本条目汇总自 `v0.1.0-alpha` 系列以来所有用户可见的变化。 + +### Added + +- **多进程架构。** 编译在主进程协调下的工作子进程中执行,单个翻译单元的编译器崩溃不再拖垮整个会话——崩溃的工作进程会被重新拉起,其负责的文档按需恢复。有状态工作进程以 LRU 淘汰驻留文档,进程池在系统内存压力下会卸载后台负载。 +- **头文件的编译上下文。** 打开头文件时,clice 会在某个包含它的源文件的上下文中编译它:重建 include 链合成 preamble(对 X-macro/`.def` 片段还会合成 suffix),使依赖 includer 宏的符号正确解析。编辑器可以通过 `clice/queryContext`、`clice/currentContext`、`clice/switchContext` 扩展列出并切换活跃上下文——同一机制也用于在一个文件的多个编译数据库条目之间切换。自包含的头文件会被识别并直接编译。 +- **LSP 功能面。** Hover(定义打印、文档注释、含 size/offset/padding 的结构布局、表达式求值、`auto`/`decltype` 推导);带签名详情、参数 snippet、废弃符号删除线以及 `#include`/`import` 路径补全的代码补全;签名帮助;跳转到定义(含 `#include` 行与模块名)、声明、实现、类型定义与查找引用(由项目索引提供);文档符号;带丰富修饰符的语义高亮;inlay hints;折叠区间;文档链接(含 preamble 内与 `#embed`);基于 `.clang-format` 的全文与区间格式化;调用层级与类型层级;工作区符号搜索;诊断发布;`#if` 关闭代码的置灰(`clice/inactiveRegions` 扩展)。 +- **后台索引。** 持久化的项目级索引支撑跨文件功能,无需逐个打开文件。索引搭编译的便车、以低优先级并发执行、遇到交互请求会让路、通过 LSP `$/progress` 汇报进度,并跨重启复用。两层过期检测(先 mtime 后内容哈希)使 `touch` 和 `git checkout` 不会触发无谓重建。 +- **编辑器之外的变化追踪。** stat 轮询的文件追踪器可以发现编辑器外发生的变化——重新生成的 `compile_commands.json`、`git checkout`、代码生成器——无需重启服务器。 +- **C++20 命名模块。** 模块接口经由拉取式依赖图按需编译并缓存 PCM;支持 `import` 补全与模块名上的跳转定义。 +- **统一磁盘缓存。** PCH、PCM 与索引产物存放在同一个内容寻址存储中,写入崩溃安全,跨会话与重启复用;可重建的产物(PCH/PCM)按大小上限淘汰。 +- **配置。** `clice.toml`(或 `.clice/config.toml`)加 LSP `initializationOptions` 覆盖;带 glob 模式的按文件 `[[rules]]` 追加/移除编译标志;`[tracker]` 轮询间隔;基于 XDG 的缓存路径与 `${workspace}` 替换。配置文件格式错误会以带行列号的诊断报告在配置文件上。 +- **工具 API。** 面向 AI agent 与外部工具的 TCP JSON-RPC API:项目文件、符号搜索、读取完整符号体、定义/引用、调用图、类型层级——以及 `clice query` 命令行。 +- **编辑器扩展。** 仓库内维护的 VS Code(已发布到 Marketplace)、Neovim 与 Zed 扩展。 +- **可运维性。** 按会话的文件日志与崩溃现场捕获;环境有问题(如找不到编译数据库)时通过 `window/logMessage` 给出指引;LSP 会话录制回放(`--record`);`--version` 输出与发布 tag 一致。 + +### Changed + +- **配置文件位置。** `config` 命令行选项已移除;配置从 `${workspace}/clice.toml`(或 `${workspace}/.clice/config.toml`)读取。 +- **配置键更名。** `compile_commands_dirs` 更名为 `compile_commands_paths`;旧键会被忽略。 +- **从 0.x 升级会重建缓存。** 磁盘缓存与索引格式已变化;升级后首次启动会丢弃旧产物并对项目重新索引一次。这同时淘汰了旧版本生成的 PCH——旧缓存键不含编译标志,可能用错误的宏配置提供结果。 +- **工具链基线。** clice 现基于 LLVM/Clang 21.1.8 构建,并为 Linux、macOS、Windows 的 x64 与 arm64 提供预编译二进制。 + +### Fixed + +- 快速连续编辑不再因编译/更新竞态产生虚假的"重定义"错误。 +- 修复了多个畸形输入导致的工作进程崩溃(空 AST consumer、无效文件 ID、缺失缓存目录);仍发生的崩溃由进程隔离兜住。 +- 被工作进程 LRU 淘汰的文档不再无声失去 hover/语义高亮——下次请求时重新编译。 +- 生命周期边界:早于 `initialize` 握手到达的 `didOpen` 会被受理;较新 LSP 客户端的未知枚举值不再导致握手失败;客户端就绪前产生的诊断会在 `initialized` 后补发。 +- 保存头文件现在会正确地重索引包含它的已关闭文件,保持跨文件引用最新。 + +### Known gaps + +- 代码补全、导航、文档链接与诊断可用但尚不完整(各功能状态见 feature overview 页面)。 +- Code action 尚未实现(也未在 capabilities 中宣告)。 +- clang-tidy 集成在计划中;`clang_tidy` 配置项会被解析但当前无效果。 diff --git a/zh/clice/design/incremental-parse.md b/zh/clice/design/incremental-parse.md index 9bbdf38d..6ac39676 100644 --- a/zh/clice/design/incremental-parse.md +++ b/zh/clice/design/incremental-parse.md @@ -79,13 +79,13 @@ clice 采用拉取式(pull-based)编译模型:编译不在文件变更时 这种模型的好处是避免了用户快速连续输入时的无效编译。用户每秒可能触发十几次 `didChange`,但只有当鼠标悬停、请求补全等实际需要编译结果时,才执行一次编译。 -> 注意"外部文件变化"和"用户编辑"是两条独立的脏标记路径。用户编辑通过 `didChange` 标记 `ast_dirty`;外部文件变化(如依赖的头文件被修改)通过两层失效检测在编译前动态发现。 +> 注意"外部文件变化"和"用户编辑"是两条独立的脏标记路径。用户编辑通过 `didChange` 标记 `ast_dirty`;外部文件变化(如依赖的头文件被修改)由 stat 轮询的文件追踪器主动发现,其事件经失效引擎折叠后把受影响文件标脏。编译前的两层失效检测仍然保留,作为轮询尚未覆盖到的变化的兜底。 ### 内容寻址 PCH 存储 -PCH 文件在磁盘上以 preamble 内容的哈希值命名(如 `a3f7e8c1d2b4f6e9.pch`),实现内容寻址。这带来两个好处: +PCH 文件在磁盘上以 preamble 内容连同影响前端的编译标志、目录与 clang 版本共同计算的哈希值命名(如 `a3f7e8c1d2b4f6e9.pch`),实现内容寻址。这带来两个好处: -- **磁盘共享**:具有相同 preamble 内容的不同文件自然共享同一个 PCH 磁盘文件,无需额外的去重逻辑。 +- **磁盘共享**:preamble 内容与编译配置一致的不同文件自然共享同一个 PCH 磁盘文件,无需额外的去重逻辑。 - **跨会话持久化**:PCH 缓存的元数据(路径、哈希、边界、依赖快照)序列化到磁盘上的 `cache.json` 文件。服务器重启时加载这些元数据,通过两层失效检测验证 PCH 是否仍然有效,避免冷启动时重建所有 PCH。 当 preamble 内容变化时,新的 PCH 使用不同的哈希命名,旧文件成为孤立文件。清理机制定期回收超过一定期限未使用的孤立 PCH 文件。 @@ -188,12 +188,8 @@ PCH 和 PCM 的缓存元数据通过 `cache.json` 文件持久化到磁盘。每 ## 已知局限 -- **每文件独立缓存**。PCH 缓存以文件的路径标识为键,即使两个文件具有完全相同的 preamble 内容,它们在缓存中也是独立的条目——各自执行失效检测和构建。虽然磁盘上的 PCH 文件通过内容寻址命名实现了共享,但缓存的元数据(依赖快照、构建状态等)没有共享。改进方向是以 preamble 内容哈希加编译标志为键,实现跨文件的缓存元数据共享。 - - **完全重建**。任何一个依赖文件的内容变化都触发 PCH 的完全重建,无法做到只重建受影响的部分。改进方向是引入链式 PCH(见 FAQ),将重建范围限制在变化点之后的链节。 -- **编译标志不参与缓存键**。PCH 的磁盘文件名和缓存查找都不考虑编译标志。当两个文件具有相同的 preamble 文本但不同的编译标志(如 `-D`)时,可能错误地共享 PCH。改进方向是将影响预处理的编译标志纳入缓存键。 - - **Preamble 完整性检查不完整**。当前的完整性检查只覆盖了 `#include`/`import` 指令中的未闭合引号和缺失分号。其他类型的不完整编辑(如正在输入 `#define` 的值)不会被检测到。如果这类不完整的 preamble 被构建为 PCH,对后续编译的影响尚未充分测试。需要进一步研究 Clang 在处理不完整预处理指令时的行为,以确定是否需要扩展完整性检查的范围。 -- **头文件保存后不主动推送诊断更新**。当前的纯拉取式模型下,用户保存一个头文件后,依赖该头文件的已打开源文件不会立即更新诊断——需要用户在源文件上触发操作(如 hover、编辑)才会通过两层失效检测发现变化并重编译。改进方向是在 `didSave` 时检查已打开的 session 是否受影响,为它们主动触发一次编译(混合推/拉模型)。 +- **头文件保存后不主动重编译**。保存头文件(或文件追踪器发现的磁盘变化)会主动把依赖它的已打开文件标脏,但重编译仍是拉取触发的:诊断要等到对该文件的下一次请求(如 hover、编辑)才刷新,而不是立即更新。改进方向是为受影响的已打开 session 主动触发一次编译(混合推/拉模型)。 diff --git a/zh/clice/design/overview.md b/zh/clice/design/overview.md index 946b9968..f2e93345 100644 --- a/zh/clice/design/overview.md +++ b/zh/clice/design/overview.md @@ -77,7 +77,7 @@ LSP 功能的具体实现。每个功能接收一个 `CompilationUnitRef`,返 包括:代码补全、悬停信息、签名帮助、语义高亮、内嵌提示、文档符号、文档链接、折叠范围、格式化、诊断等。 -> `feature/` 只涵盖单文件、基于 AST 的特性实现。跨文件的导航功能(go to definition、find references 等)由 `Indexer` 基于索引数据完成。部分功能存在多阶段处理——例如代码补全中的 include 路径补全在语法层就能完成,不需要完整编译。 +> `feature/` 只涵盖单文件、基于 AST 的特性实现。跨文件的导航功能(go to definition、find references 等)由服务器的 `service/` 层(`FeatureRouter`/`IndexQuery`)基于索引数据提供。部分功能存在多阶段处理——例如代码补全中的 include 路径补全在语法层就能完成,不需要完整编译。 ### `src/server/` — 服务器运行时 @@ -85,18 +85,29 @@ LSP 功能的具体实现。每个功能接收一个 `CompilationUnitRef`,返 **`protocol/`** — 协议定义。描述主进程与工作进程之间、以及与客户端之间的通信消息格式。包括 Worker 协议(编译/查询/构建请求)、LSP 扩展协议(编译上下文切换等)、以及面向 AI agent 的 agentic 协议。 -**`workspace/`** — 项目级全局状态。`Workspace` 持有编译数据库、工具链、路径池、依赖图、PCH/PCM 缓存、项目索引等全部项目级状态。核心不变量:打开文件的未保存缓冲区内容不会修改 `Workspace`,它只反映磁盘上的状态。 +**`state/`** — 项目与文档状态,以及失效机制。 + +- `Workspace`:项目级全局状态——编译数据库、工具链、路径池、依赖图、缓存存储、项目索引。核心不变量:打开文件的未保存缓冲区内容不会修改 `Workspace`,它只反映磁盘上的状态 +- `Session` / `SessionStore`:每个打开文件的编辑状态(缓冲区内容、文档版本号、内存索引、PCH 引用等),在 didOpen 时创建,didClose 时销毁;`SessionStore` 拥有打开会话表和缓冲区同步逻辑 +- `Invalidator`:失效引擎——把文件事件(打开/保存、磁盘变化、编译数据库重载、工作进程崩溃)折叠成一组去重后的失效效果 +- `FileTracker`:以 stat 轮询发现编辑器之外发生的变化(重新生成的 `compile_commands.json`、`git checkout`),把事件交给 `Invalidator` +- `Config`:`clice.toml` 与 LSP `initializationOptions` 的加载与合并 **`compiler/`** — 编译调度与索引管理。 - `Compiler`:编译生命周期的调度器,协调 PCH 构建、模块依赖解析、AST 编译的先后顺序,将编译任务分发给工作进程 - `CompileGraph`:C++20 模块编译的 DAG 调度器,基于引用计数实现兴趣追踪,支持依赖级联取消 -- `Indexer`:后台索引调度和跨文件查询的入口,综合 `ProjectIndex`、`MergedIndex` 和打开文件的内存索引提供查询结果 +- `ContextResolver`:解析文件的编译命令与 includer 上下文,拥有头文件上下文状态与合成 preamble +- `Indexer`:后台索引调度——将过期文件入队、把索引构建分发给工作进程并合并产出的分片 + +**`service/`** — 消费编译与索引结果的读侧服务。 + +- `FeatureRouter`:把 feature 请求路由到编译器(依赖 AST 的功能)或索引(跨文件导航),必要时合并两者 +- `IndexQuery`:`ProjectIndex`、`MergedIndex` 与打开文件内存索引之上的查询门面 -**`service/`** — 服务入口与会话管理。 +**`transport/`** — 驱动服务器的协议端点。 -- `MasterServer`:顶层协调器,持有 `Workspace`、`Session` 映射、`WorkerPool`、`Compiler`、`Indexer`,将 LSP 请求路由到对应的处理逻辑 -- `Session`:每个打开文件的编辑状态(缓冲区内容、编译版本号、内存索引、PCH 引用等),在 didOpen 时创建,didClose 时销毁 +- `MasterServer`:组合根。持有 `Workspace`、`SessionStore`、`WorkerPool` 及上述全部服务,并通过唯一的 dispatch 入口执行 `Invalidator` 的失效效果 - `LSPClient` / `AgentClient`:LSP 协议和 agentic 协议的请求处理器 **`worker/`** — 工作进程管理。 diff --git a/zh/clice/dev/test-and-debug.md b/zh/clice/dev/test-and-debug.md index 9d5a1cd4..fec65a08 100644 --- a/zh/clice/dev/test-and-debug.md +++ b/zh/clice/dev/test-and-debug.md @@ -51,7 +51,7 @@ pixi run smoke-test Debug # debug 构建 等价于: ```bash -python tests/replay.py tests/smoke/*.jsonl \ +python tests/tools/replay.py tests/smoke/*.jsonl \ --clice=./build/RelWithDebInfo/bin/clice ``` diff --git a/zh/clice/guide/configuration.md b/zh/clice/guide/configuration.md index 11fce19d..f8e2aeb0 100644 --- a/zh/clice/guide/configuration.md +++ b/zh/clice/guide/configuration.md @@ -1,6 +1,8 @@ # Configuration -clice 从工作区根目录的 `clice.toml` 中读取配置。配置也可以通过 LSP `initializationOptions`(JSON 格式)传入。 +clice 从工作区根目录的 `clice.toml` 中读取配置;若该文件不存在,则尝试 `.clice/config.toml`。配置也可以通过 LSP `initializationOptions`(JSON 格式)传入:`initializationOptions` 中的值会覆盖配置文件,合并后仍未设置的项再由默认值填充。 + +配置只在服务器启动时读取一次。修改配置(无论哪个文件)都需要重启服务器,没有热重载。 ## 变量替换 @@ -18,7 +20,7 @@ clice 从工作区根目录的 `clice.toml` 中读取配置。配置也可以通 | ------ | ------- | | `bool` | `false` | -启用实验性的 clang-tidy 诊断。 +启用实验性的 clang-tidy 诊断。**尚未接线**——该选项会被解析,但当前没有任何效果。 ### `project.max_active_file` @@ -26,7 +28,7 @@ clice 从工作区根目录的 `clice.toml` 中读取配置。配置也可以通 | ----- | ------ | | `int` | `8` | -内存中保持的最大活跃文件数。超过限制时,最近最少使用的文件会被淘汰。 +内存中保持的最大活跃文件数。**尚未接线**——该选项会被解析,但工作进程仍使用硬编码的上限。 ### `project.cache_dir` @@ -34,15 +36,7 @@ clice 从工作区根目录的 `clice.toml` 中读取配置。配置也可以通 | -------- | ------------------------------------------------------- | | `string` | `$XDG_CACHE_HOME/clice/` 或 `${workspace}/.clice` | -PCH 和 PCM 缓存文件的存储目录。默认使用 XDG_CACHE_HOME(或 `~/.cache`)下的工作区专用哈希子目录。如果 XDG 目录无法创建,则回退到 `${workspace}/.clice`。 - -### `project.index_dir` - -| 类型 | 默认值 | -| -------- | -------------------- | -| `string` | `${cache_dir}/index` | - -索引文件的存储目录。 +统一磁盘缓存的存储目录(PCH、PCM 与索引产物都在这里)。默认使用 XDG_CACHE_HOME(或 `~/.cache`)下的工作区专用哈希子目录。如果 XDG 目录无法创建,则回退到 `${workspace}/.clice`。 ### `project.logging_dir` @@ -90,7 +84,23 @@ PCH 和 PCM 缓存文件的存储目录。默认使用 XDG_CACHE_HOME(或 `~/. | -------- | ----------------- | | `uint32` | `max(cores/2, 2)` | -无状态工作进程数量。处理临时任务(PCH/PCM 构建、补全、签名帮助)。 +启动时创建的无状态工作进程数量。处理临时任务(PCH/PCM 构建、补全、签名帮助)。 + +### `project.min_stateless_worker_count` + +| 类型 | 默认值 | +| -------- | ----------- | +| `uint32` | `0`(自动) | + +无状态工作进程动态缩容的下限。`0` 表示自动确定最小值。 + +### `project.max_stateless_worker_count` + +| 类型 | 默认值 | +| -------- | ----------- | +| `uint32` | `0`(自动) | + +无状态工作进程动态扩容的上限。`0` 表示使用 CPU 核心数。 ### `project.worker_memory_limit` @@ -98,7 +108,27 @@ PCH 和 PCM 缓存文件的存储目录。默认使用 XDG_CACHE_HOME(或 `~/. | -------- | -------------------- | | `uint64` | `4294967296`(4 GB) | -每个工作进程的内存限制(字节)。超过限制的工作进程会被重启。 +每个工作进程的内存限制(字节)。**尚未强制执行**——该选项会被解析,但基于内存的淘汰/重启尚未实现。 + +## Tracker + +文件追踪器轮询编辑器之外发生的变化(`git checkout`、重新生成的 `compile_commands.json`、代码生成器写出的头文件),使服务器无需重启即可感知。将间隔设为 `0` 可禁用对应的轮询循环。 + +### `tracker.cdb_poll_seconds` + +| 类型 | 默认值 | +| -------- | ------ | +| `uint32` | `3` | + +重新检查编译数据库文件的间隔(秒)。 + +### `tracker.workspace_poll_seconds` + +| 类型 | 默认值 | +| -------- | ------ | +| `uint32` | `30` | + +扫描工作区文件磁盘变化的间隔(秒)。 ## Rules diff --git a/zh/clice/guide/editors.md b/zh/clice/guide/editors.md index abbc79b9..aba78bfd 100644 --- a/zh/clice/guide/editors.md +++ b/zh/clice/guide/editors.md @@ -5,7 +5,7 @@ clice 实现了 [Language Server Protocol](https://microsoft.github.io/language- 所有配置的前提: - `clice` 可执行文件在 `PATH` 中(或在下面的片段中使用绝对路径)。 -- 项目提供 `compile_commands.json`(clice 默认搜索工作区根目录和 `build/`)。 +- 项目提供 `compile_commands.json`(clice 默认先搜索工作区根目录,再依次搜索其各个直接子目录)。 ## Official Plugins @@ -96,7 +96,7 @@ language-servers = ["clice"] if executable('clice') au User lsp_setup call lsp#register_server({ \ 'name': 'clice', - \ 'cmd': {server_info->['clice', 'server']}, + \ 'cmd': {server_info->['clice', 'serve']}, \ 'allowlist': ['c', 'cpp'], \ }) endif