Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
39 changes: 39 additions & 0 deletions en/clice/changelog/feature-changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
12 changes: 4 additions & 8 deletions en/clice/design/incremental-parse.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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).
23 changes: 17 additions & 6 deletions en/clice/design/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,26 +77,37 @@ 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

The language server's core runtime, responsible for assembling all the layers above into a runnable service.

**`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.
Expand Down
2 changes: 1 addition & 1 deletion en/clice/dev/test-and-debug.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

Expand Down
52 changes: 41 additions & 11 deletions en/clice/guide/configuration.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -34,15 +36,7 @@ Maximum number of active files to keep in memory. **Not yet wired** — the opti
| -------- | ------------------------------------------------------- |
| `string` | `$XDG_CACHE_HOME/clice/<hash>` 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`

Expand Down Expand Up @@ -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`

Expand All @@ -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.
Expand Down
Loading
Loading