Commit Graph

13 Commits

Author SHA1 Message Date
ykiko
17e68010a0 feat(server): improve configuration file handling (#423)
## Summary

- **`[[rules]]`**: TOML array-of-tables config for per-file compilation
flag rules with glob pattern matching (`append`/`remove`). Patterns are
pre-compiled at config load time. Rules whose patterns all fail to
compile are dropped entirely (no silent no-op entries), and rules now
apply uniformly to every compilation — including the header-context
fallback path used when editing a header without its own CDB entry.
- **CDB auto-scan**: Default search scans workspace root + all immediate
subdirectories for `compile_commands.json`, replacing the hardcoded
directory list.
- **LSP `initializationOptions`**: Clients can pass config as JSON via
the LSP initialize request; priority is `initializationOptions >
clice.toml > defaults`.
- **XDG cache paths**: Default cache/index/logging paths prefer
`$XDG_CACHE_HOME/clice/<workspace-hash>/`; fall back to
`$HOME/.cache/clice/<hash>/`, then `<workspace>/.clice/`.
- **`${workspace}` substitution**: supported in `cache_dir`,
`index_dir`, `logging_dir`, and every `compile_commands_paths` entry.
No-op when `workspace_root` is empty.
- **Partial config support**: All TOML/JSON fields are optional via
`kota::meta::defaulted<T>`, so minimal config files work correctly.
- **Detailed diagnostics**: malformed `clice.toml` now logs line, column
and parser description (via toml++ direct parse); a malformed workspace
config surfaces a clear fallback warning instead of silently reverting
to defaults.

## Test plan

- [x] 28 unit tests for config (full suite 545 unit tests pass, Debug)
- [x] 119 integration tests pass
- [x] 2 smoke tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* XDG-based, workspace-scoped project cache (PCH/PCM and header caches
moved under project cache) with workspace fallback
* Initialization options JSON can override config (takes precedence over
file/defaults)
* Per-file pattern rules to append/remove compile flags; expanded
discovery of compilation databases (multiple paths)

* **Refactor**
* Configuration fields reorganized under a project scope; runtime
behavior now respects project-scoped values

* **Tests**
* New unit and integration tests for config parsing, rule matching, and
persistent cache behavior

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 00:21:31 +08:00
ykiko
418e190fa0 chore(deps): migrate from eventide to kotatsu (#428)
## Summary

- The `eventide` dep was renamed to
[kotatsu](https://github.com/clice-io/kotatsu) with a broad rename of
CMake identifiers, namespaces, header paths, and a few module reorgs
(`serde` → `codec`, `reflection` → `meta`, `common` → `support`). Align
clice to the new names.
- CMake: FetchContent target, option prefix (`ETD_*` → `KOTA_*`,
`ETD_SERDE_*` → `KOTA_CODEC_*`), target names
(`eventide::{ipc::lsp,serde::toml,deco,zest}` →
`kota::{ipc::lsp,codec::toml,deco,zest}`).
- Namespaces: `eventide::` → `kota::`, `eventide::serde::` →
`kota::codec::`, `eventide::refl::` → `kota::meta::`. The short `et`
alias is dropped — all usages now spell `kota::` directly.
- Headers: `eventide/*` → `kota/*`, including special cases
`serde/serde/raw_value.h` → `codec/raw_value.h`, `ipc/json_codec.h` →
`ipc/codec/json.h`, `common/meta.h` → `support/type_traits.h`,
`common/ranges.h` → `support/ranges.h`.
- Kotatsu split `JsonPeer` / `BincodePeer` out of `ipc/peer.h` into the
codec-specific headers; added `kota/ipc/codec/{json,bincode}.h` includes
where those types are used.
- Depends on clice-io/kotatsu#110 (already merged) to prevent `-Wall
-Wextra -Werror` from transitively propagating out of
`kota::project_options`.

## Test plan

- [x] `pixi run unit-test RelWithDebInfo` — 518/518 pass (9 skipped,
unchanged from main)
- [x] `pixi run integration-test RelWithDebInfo` — 119/119 pass
- [x] `pixi run smoke-test RelWithDebInfo` — 2/2 pass
- [x] `pixi run format` clean

## Notes

- `tests/smoke/rapid_edit.jsonl` was intentionally left untouched: the
embedded `#include "eventide/..."` strings are frozen snapshots of file
contents the client sent at record time, not clice source.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated internal dependencies from `eventide` to `kota`, including
async runtime, IPC transport, serialization codec, and metadata
libraries.
* Updated build configuration and CMake variables to align with the new
dependency.

* **Refactor**
* Migrated internal implementation to use `kota` namespace and APIs
throughout the codebase.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:49:07 +08:00
ykiko
d42d9d5b29 refactor(document links): use Lexer for unified directive argument scanning (#421)
## Summary
- Replace hand-written character scanning in `document_links.cpp` with
the project's `Lexer` class for finding filename arguments in
preprocessor directives
- Extend `Lexer` to activate `header_name` mode for
`#embed`/`#include_next`, and expose `set_header_name_mode()` for
`__has_include`/`__has_embed` contexts
- Remove unused `Include::filename_range` field (had a latent assert
crash on macro-expanded includes)
- Add `MacroInclude` unit test covering `#include MACRO` scenario

## Test plan
- [x] 498 unit tests pass (including new `MacroInclude` test)
- [x] 119 integration tests pass
- [x] 2/2 smoke tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Document links now resolve includes written via macros; directive
parsing recognizes include, include_next, embed and __has_* patterns
more reliably using lexer-driven argument detection.

* **Refactor**
* Removed an internal filename-range field previously stored for include
directives.

* **Tests**
* Added unit tests covering directive argument extraction and
macro-based include linking.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 17:17:10 +08:00
ykiko
2bbdf6c02b refactor(command): split CompilationContext into ResolvedFlags → CompileCommand → to_argv() (#408)
## Summary

- Replace flat `CompilationContext { directory, arguments }` with a
three-layer abstraction: `ResolvedFlags` (file-independent flags) →
`CompileCommand` (+ source file) → `to_argv()` (full argv on demand)
- `ResolvedFlags.flags` never contains source file path or
`-main-file-name`, making it directly usable as a clean cache key input
(e.g. PCH sharing across files with identical preambles)
- `to_argv()` handles `-main-file-name` insertion for cc1 mode
automatically — consumers no longer need to search/replace in the
argument list
- Eliminates the pollute-then-clean anti-pattern in `lookup()` and the
manual source-file replacement in `fill_header_context_args()`

## Test plan

- [x] `pixi run format` — no changes
- [x] `pixi run unit-test` — 481 passed
- [x] `pixi run integration-test` — 113 passed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Unified compile-command handling across the server and tools for more
consistent argument and flag behavior (driver vs frontend modes).
* **New Features**
* Added an LRU-backed in-memory cache to improve performance and
eviction control.
* **Chores**
* Added an option to control injection of resource-directory flags
(enabled by default).
* **Tests**
* Updated unit and integration tests to adopt the new command
representation and verify cache behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 22:18:25 +08:00
ykiko
9c9e6b0bcb refactor: introduce Workspace/Session state model and clarify component responsibilities (#406)
## Summary

Introduces a two-layer state model that cleanly separates disk-based
project state from per-open-file editing state, and redistributes
responsibilities across server components so each has a single, clear
role.

## New types

**Workspace** — all persistent, project-wide shared state:
- CompilationDatabase, PathPool, DependencyGraph, CompileGraph
- path_to_module mapping, PCH cache, PCM cache, PCM paths
- ProjectIndex, MergedIndex shards
- CliceConfig
- Methods: on_file_saved(), on_file_closed(), load/save/cleanup_cache(),
build_module_map(), fill_pcm_deps(), cancel_all()

**Session** — volatile per-open-file editing state:
- text, version, generation, ast_dirty
- pch_ref (references Workspace.pch_cache), ast_deps, header_context
- file_index (OpenFileIndex for unsaved buffer)
- path_id member for self-identification

## Component responsibilities after refactor

| Component | Role | Owns state? |
|-----------|------|-------------|
| **Workspace** | Disk truth + shared caches | Yes (all project state) |
| **Session** | One open file editing state | Yes (per-file only) |
| **Compiler** | Compilation pipeline, worker communication | No
(references only) |
| **Indexer** | Index queries + background indexing scheduling |
Scheduling state only |
| **MasterServer** | LSP protocol dispatch + lifecycle coordination |
sessions map |

## What moved where

**Into Workspace** (from Compiler/MasterServer):
- PCH/PCM cache management (load_cache, save_cache, cleanup_cache)
- Module map building (build_module_map, fill_pcm_deps)
- File lifecycle hooks (on_file_saved, on_file_closed)
- cancel_all, OpenFileIndex/MergedIndexShard type definitions

**Into Session** (from Compiler documents map):
- Document text, version, generation, ast_dirty
- PCH reference, dependency snapshot, header context

**Into Indexer** (from MasterServer):
- Background indexing queue, scheduling state, idle timer
- schedule(), enqueue(), run_background_indexing()

**Into syntax/completion.h** (from Compiler):
- detect_completion_context() — pure text parsing
- complete_module_import() — prefix match on module names
- complete_include_path() — directory listing against search paths

**Inlined into MasterServer** (from Compiler):
- didOpen/didChange/didClose/didSave handlers
- switchContext/currentContext
- publish_diagnostics/clear_diagnostics

**Deleted from Compiler** (9 methods):
- open_document, apply_changes, close_document, on_save
- switch_context, get_active_context, invalidate_host_contexts
- on_file_closed, on_file_saved, complete_include, complete_import

## Tests

- 481 tests pass (465 existing + 16 new completion tests)
- New: tests/unit/syntax/completion_tests.cpp

## Diff stats

15 files changed, +1857, -1555

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Enhanced completion support for include paths and module imports with
improved context detection.
* Added background indexing system for automatic project symbol
indexing.

* **Bug Fixes**
* Improved reliability of document change tracking and compilation state
management.
  * Better handling of header file compilation contexts.

* **Tests**
* Added unit tests for completion context detection and module/include
path completion.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 14:03:39 +08:00
ykiko
836f415e50 feat: header context protocol — queryContext, currentContext, switchContext (#398)
## Summary

Add three LSP protocol extensions that allow users to manage compilation
contexts for header files and source files with multiple CDB entries.

### Protocol extensions (`protocol.h`)

| Command | Purpose |
|---------|---------|
| `clice/queryContext` | List all possible contexts for a file. Headers
→ host source files; sources → CDB entries. Paginated (10 per page,
`offset` param). |
| `clice/currentContext` | Query the active context override for a file
(null if default). |
| `clice/switchContext` | Set the active context, invalidate caches,
trigger recompilation. |

### Header context resolution (`master_server.cpp`,
`dependency_graph.cpp`)

- `find_host_sources()`: BFS the reverse include graph to find source
files that transitively include a header
- `find_include_chain()`: BFS the forward include graph to find the
shortest include chain from host to header
- `resolve_header_context()`: walks the include chain, extracts content
before each `#include` directive, concatenates with `#line` markers into
a preamble file (hash-addressed under `.clice/header_context/`)
- `fill_header_context_args()`: uses the host source's CDB entry,
replaces source path with header path, injects `-include preamble.h`

### Compilation flow

- Default: headers compile as standalone files (no context)
- After `switchContext`: `fill_compile_args` checks `active_contexts`
first → uses host's CDB entry + preamble injection
- Fallback: if no CDB entry and no active context, auto-resolves via
`resolve_header_context`
- `#include` directive matching uses precise filename extraction from
`"..."` / `<...>`, not substring matching

### Source file multiple contexts (`multi_context` workspace)

- `queryContext` on a source file returns all CDB entries with
distinguishing labels (extracted from `-D`, `-O`, `-std=` flags)

### Test data

- `header_context/`: non-self-contained 3-level chain (`main.cpp` →
`utils.h` → `inner.h`), `types.h` provides `Point` struct
- `multi_context/`: single source with two CDB entries (`-DCONFIG_A`,
`-DCONFIG_B`)

### Tests (9 integration tests)

- queryContext returns host sources for headers
- queryContext returns CDB entries for source files
- currentContext defaults to null
- switchContext sets active context, currentContext reflects it
- Full flow: open → query → switch → hover works in non-self-contained
header
- Deep nested: switchContext + hover on `inner.h` (3 levels deep)
- Multiple CDB entries: queryContext returns both CONFIG_A and CONFIG_B

## Test plan
- [x] Unit tests: 465 passed
- [x] Integration tests: 113 passed (9 new header context tests)
- [x] Smoke test: 1/1 passed
- [ ] Manual VSCode testing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:55:06 +08:00
ykiko
e239b0d32c feat: smart PCH rebuild, #include/import completion, rapid-edit robustness (#394)
## 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>
2026-04-06 14:49:09 +08:00
ykiko
a536865fca feat: add scan_module_decl() fallback for conditional module declarations (#373)
## Summary

- Add `scan_module_decl()` — a lightweight preprocessor-based fallback
that resolves module declarations inside `#if`/`#ifdef` conditionals.
When `scan()` detects `need_preprocess=true`, this function runs clang's
preprocessor to evaluate conditions and extract the actual module name.
It stops lexing as soon as the module declaration is found, making it
much cheaper than `scan_precise()`.
- Integrate the fallback into `scan_dependency_graph()` for wave 0
source files, so conditional module declarations (e.g. `#ifdef
USE_MODULES / export module M; / #endif`) are correctly registered in
the dependency graph.
- Add comprehensive test cases covering all C++20 module declaration
forms from cppreference, including `scan_module_decl()` tests for
conditional resolution and `scan_precise()` tests for module import
semantics.

## Test plan

- [x] All 310 unit tests pass (0 failures, 9 skipped)
- [x] `scan()` tests cover: primary interface, implementation, dotted
names, partitions, GMF, conditional module declarations, private module
fragment
- [x] `scan_module_decl()` tests cover: basic, conditional with `-D`,
conditional with `#if` expression, GMF with conditional, implementation
unit, dotted name, partition, no-module file
- [x] `scan_precise()` tests cover: named import, multiple imports,
dotted import, partition import, export-import, export-import partition,
implementation import, GMF with import, mixed includes/imports,
no-module file

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Improved detection of module declarations hidden by conditional
compilation via a lightweight fallback scan. Resolved module vs.
interface classification is cached to avoid repeated work and is used
consistently in dependency mapping.
* Better handling and classification of module imports, partitions, and
global-fragment includes when building module relationships.

* **Tests**
* Added comprehensive unit tests covering module declaration extraction,
fallback resolution under preprocessor guards, imports, partitions,
includes, and macro-driven cases.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 22:27:49 +08:00
ykiko
f8a39147a7 feat: add include resolver, dependency graph, BFS scanner (#368)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 17:40:29 +08:00
ykiko
f7a8d104ce refactor: move command files to src/command/, remove scan_fuzzy (#366)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 23:54:32 +08:00
ykiko
020c2cb3cc feat: implement multi-process LSP server architecture (#364)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 23:37:08 +08:00
ykiko
73afcfbb58 refactor: introduce syntax/scan module with DependencyDirectivesGetter (#357)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 21:45:31 +08:00
ykiko
ce2f355988 refactor: introduce eventide and rewrite server architecture (#355) 2026-03-01 18:17:02 +08:00