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
1 change: 1 addition & 0 deletions en/clice/cli/query.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- `documentSymbols --path <file>` is the file's outline.
- `compileCommand --path <file>` is the command the editor would compile the file with, and where it came from: the file's own database entry, a host source for a header, a rule's default command, a command borrowed from a nearby unit — for a provisional member (`provisional`) or a file outside the build (`inferred`) — or the fallback. The command is the one the compiler resolves it to, with its target and system include directories; when asking the compiler failed, `toolchainError` says why and the command stays the unresolved driver command.
- `projectFiles [--filter all|source|header|module]` lists the build's files; `fileDeps --path <file> [--direction includes|includers|both] [--depth <n>]` and `impactAnalysis --path <file>` follow the include graph.
- `counterparts --path <file>` lists the files the file pairs with — a header's sources, a source's headers, a module's interface and implementation units — best first, each with its reasons, and names the one an editor would open without asking as `preferred` (see [Switch Source/Header](../features/navigation.md#switch-source-header)).

Paths are workspace-relative or absolute in questions, absolute in answers; lines are 1-based.

Expand Down
105 changes: 100 additions & 5 deletions en/clice/features/navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -1693,17 +1693,112 @@ tests/snap/document_highlight/document_highlight/11_highlight_module_unit/main.c

## Switch Source/Header

Open the file the current one pairs with: a header's source, a source's header, a module interface's implementation units, an implementation unit's interface. VS Code runs it as **Clice: Switch Source/Header** (`Alt+O`), Neovim as `:LspCliceSwitchSourceHeader`, and `clice query --method counterparts --path <file>` answers the same on the command line. Zed lets no extension add a command, and its own _switch source header_ works with clangd only.

The candidates come from what the build and the index already know, so nothing is compiled for the answer: the files of the same name on the other side — in the file's own directory, or elsewhere in the workspace when one includes the other —, the declarations one holds that the other defines, and module declarations. Each candidate carries its reasons. The editor opens the best one directly when it is the only candidate or beats every other: it has each of the other's reasons among shared declarations and the same name, at least as many shared declarations, and either a reason more, twice the shared declarations when both share some, or — neither sharing any — a module pairing the other lacks. Otherwise it lists the candidates to pick from.

<!-- BEGIN GENERATED ITEMS: switch_source_header -->

<!-- BEGIN CAPABILITY: unsupported -->
<!-- BEGIN CAPABILITY: supported -->

**Header and its source**

A header and the source of the same name that defines what it declares switch to each other directly

```snap
tests/snap/switch_source_header/switch_source_header/01_header_source/main.cpp
```

<!-- END CAPABILITY -->

<!-- BEGIN CAPABILITY: supported -->

**Headers apart from sources**

A header under `include/` finds its source under `src/`, ahead of another file of the same name that defines none of its declarations

Away from the header's own directory, a file of the same name counts
only when one of the two includes the other — `tools/shape.cpp` includes
nothing and is no counterpart — and of those only the nearest:
`src/legacy/shape.cpp` lies a directory deeper than `src/shape.cpp`.

```snap
tests/snap/switch_source_header/switch_source_header/02_split_layout/main.cpp
```

<!-- END CAPABILITY -->

<!-- BEGIN CAPABILITY: supported -->

**Definitions across several sources**

When several sources define a header's declarations, the one defining clearly the most is taken directly and the others stay listed

```snap
tests/snap/switch_source_header/switch_source_header/03_scattered_definitions/main.cpp
```

<!-- END CAPABILITY -->

<!-- BEGIN CAPABILITY: supported -->

**No clear counterpart**

When no candidate clearly outweighs the others, the editor lists them with their reasons to pick from

```snap
tests/snap/switch_source_header/switch_source_header/04_split_evenly/main.cpp
```

<!-- END CAPABILITY -->

<!-- BEGIN CAPABILITY: supported -->

**Module interface and implementations**

A module interface unit pairs with the units implementing its module, and each of them with the interface

```snap
tests/snap/switch_source_header/switch_source_header/05_module_units/main.cpp
```

<!-- END CAPABILITY -->

<!-- BEGIN CAPABILITY: supported -->

**Partition beside its implementation**

An internal partition and the implementation unit of the same name defining its declarations switch to each other directly

The implementation unit also lists the primary interface of its module,
after the partition.

```snap
tests/snap/switch_source_header/switch_source_header/06_module_partition/main.cpp
```

<!-- END CAPABILITY -->

<!-- BEGIN CAPABILITY: supported -->

**Files without a counterpart**

A header that defines everything it declares, and a `.def` fragment, have no counterpart

```snap
tests/snap/switch_source_header/switch_source_header/07_no_counterpart/main.cpp
```

<!-- END CAPABILITY -->

<!-- BEGIN CAPABILITY: supported -->

**Source-header switching**
**Template definitions apart**

Source/header switching is not implemented, so users cannot jump directly
between paired files
A header and the `.tpp` file it includes for its template definitions switch to each other

```snap
tests/snap/navigation/switch_source_header/01_switch_source_header.cpp
tests/snap/switch_source_header/switch_source_header/08_template_definitions/main.cpp
```

<!-- END CAPABILITY -->
Expand Down
2 changes: 1 addition & 1 deletion en/clice/features/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Language Server Protocol features available when using clice as an editor backen
| [Code Completion](./completion.md) | 57 supported |
| [Hover](./hover.md) | 38 supported · 19 partial · 10 unsupported |
| [Signature Help](./signature-help.md) | 14 supported |
| [Code Navigation](./navigation.md) | 71 supported · 12 partial · 26 unsupported |
| [Code Navigation](./navigation.md) | 79 supported · 12 partial · 25 unsupported |
| [Document Links](./document-links.md) | 7 supported · 1 partial · 1 unsupported |
| [Semantic Tokens](./semantic-tokens.md) | 56 supported · 2 partial · 10 unsupported |
| [Inlay Hints](./inlay-hints.md) | 34 supported · 6 partial · 4 unsupported |
Expand Down

This file was deleted.

4 changes: 4 additions & 0 deletions sources/clice/tests/snap/switch_source_header/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# The fixtures' doc headers and code feed the docs as written, so
# formatting is disabled for this directory.
DisableFormat: true
SortIncludes: false
4 changes: 4 additions & 0 deletions sources/clice/tests/snap/switch_source_header/corpus.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"notes": "Freestanding, -undef and -nostdinc keep host headers out of the build, so the files a reply names are the fixture's own on every host. Fixtures declare the files to ask about as `// switch:` comment lines in the entry source.",
"flags": ["-std=c++23", "-ffreestanding", "-undef", "-nostdinc"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// # Header and its source
///
/// - status: supported
/// - verify: server
/// - indexing: true
///
/// A header and the source of the same name that defines what it declares switch to each other directly

// switch: widget.h
// switch: widget.cpp

#include "widget.h"

int render(Widget& widget) {
widget.draw();
return widget.area();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
created_at: 2026-10-09
input_file: switch_source_header/01_header_source/main.cpp
---
"widget.h":
preferred: "${WS}/switch_source_header/01_header_source/widget.cpp"
candidates:
- { file: "${WS}/switch_source_header/01_header_source/widget.cpp", reasons: ["defines 2 of 2 declarations", "same name"] }

"widget.cpp":
preferred: "${WS}/switch_source_header/01_header_source/widget.h"
candidates:
- { file: "${WS}/switch_source_header/01_header_source/widget.h", reasons: ["declares 2 of 2 definitions", "same name"] }
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include "widget.h"

void Widget::draw() {}

int Widget::area() const {
return width * height;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

class Widget {
public:
void draw();
int area() const;

private:
int width = 0;
int height = 0;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once

int shape_area(int width, int height);
int shape_perimeter(int width, int height);
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/// # Headers apart from sources
///
/// - status: supported
/// - verify: server
/// - indexing: true
///
/// A header under `include/` finds its source under `src/`, ahead of another file of the same name that defines none of its declarations
///
/// Away from the header's own directory, a file of the same name counts
/// only when one of the two includes the other — `tools/shape.cpp` includes
/// nothing and is no counterpart — and of those only the nearest:
/// `src/legacy/shape.cpp` lies a directory deeper than `src/shape.cpp`.

// switch: include/geometry/shape.h
// switch: src/shape.cpp

#include "include/geometry/shape.h"

int total(int width, int height) {
return shape_area(width, height) + shape_perimeter(width, height);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
created_at: 2026-10-09
input_file: switch_source_header/02_split_layout/main.cpp
---
"include/geometry/shape.h":
preferred: "${WS}/switch_source_header/02_split_layout/src/shape.cpp"
candidates:
- { file: "${WS}/switch_source_header/02_split_layout/src/shape.cpp", reasons: ["defines 2 of 2 declarations", "same name"] }
- { file: "${WS}/switch_source_header/02_split_layout/tests/shape.cpp", reasons: ["same name"] }

"src/shape.cpp":
preferred: "${WS}/switch_source_header/02_split_layout/include/geometry/shape.h"
candidates:
- { file: "${WS}/switch_source_header/02_split_layout/include/geometry/shape.h", reasons: ["declares 2 of 2 definitions", "same name"] }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include "../../include/geometry/shape.h"

int legacy_area(int width, int height) {
return shape_area(height, width);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include "../include/geometry/shape.h"

int shape_area(int width, int height) {
return width * height;
}

int shape_perimeter(int width, int height) {
return 2 * (width + height);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include "../include/geometry/shape.h"

int check_shape() {
return shape_area(2, 3) == 6 ? 0 : 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
int draw_shape(int sides) {
return sides * 2;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/// # Definitions across several sources
///
/// - status: supported
/// - verify: server
/// - indexing: true
///
/// When several sources define a header's declarations, the one defining clearly the most is taken directly and the others stay listed

// switch: text.h
// switch: text_case.cpp

#include "text.h"

int process(char* text) {
return trim(text) + split(text) + join(text) + upper(text);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
created_at: 2026-10-09
input_file: switch_source_header/03_scattered_definitions/main.cpp
---
"text.h":
preferred: "${WS}/switch_source_header/03_scattered_definitions/text_ops.cpp"
candidates:
- { file: "${WS}/switch_source_header/03_scattered_definitions/text_ops.cpp", reasons: ["defines 3 of 4 declarations"] }
- { file: "${WS}/switch_source_header/03_scattered_definitions/text_case.cpp", reasons: ["defines 1 of 4 declarations"] }

"text_case.cpp":
preferred: "${WS}/switch_source_header/03_scattered_definitions/text.h"
candidates:
- { file: "${WS}/switch_source_header/03_scattered_definitions/text.h", reasons: ["declares 1 of 1 definition"] }
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

int trim(char* text);
int split(char* text);
int join(char* text);
int upper(char* text);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include "text.h"

int upper(char* text) {
return text[0] - 32;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "text.h"

int trim(char* text) {
return text[0];
}

int split(char* text) {
return text[1];
}

int join(char* text) {
return text[2];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once

int encode(int value);
int decode(int value);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include "codec.h"

int decode(int value) {
return value ^ 0x5a;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include "codec.h"

int encode(int value) {
return value ^ 0x5a;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/// # No clear counterpart
///
/// - status: supported
/// - verify: server
/// - indexing: true
///
/// When no candidate clearly outweighs the others, the editor lists them with their reasons to pick from

// switch: codec.h

#include "codec.h"

int round_trip(int value) {
return decode(encode(value));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
created_at: 2026-10-09
input_file: switch_source_header/04_split_evenly/main.cpp
---
"codec.h":
candidates:
- { file: "${WS}/switch_source_header/04_split_evenly/decode.cpp", reasons: ["defines 1 of 2 declarations"] }
- { file: "${WS}/switch_source_header/04_split_evenly/encode.cpp", reasons: ["defines 1 of 2 declarations"] }
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/// # Module interface and implementations
///
/// - status: supported
/// - verify: server
/// - indexing: true
///
/// A module interface unit pairs with the units implementing its module, and each of them with the interface

// switch: shapes.cppm
// switch: shapes_debug.cpp

import shapes;

int total(int width, int height) {
return area(width, height) + perimeter(width, height);
}
Loading
Loading