fix(tui): highlight C++ module files (#28554)

## Why

Codex syntax-highlights diffs for conventional C++ extensions such as
`.cpp` and `.cxx`, but C++ module interface files using `.cppm`, `.ixx`,
or `.cxxm` fall back to plain diff coloring. The bundled syntax set
already includes C++, but it does not resolve those module extensions by
itself.

Closes #28223.

## What changed

- map `.cppm`, `.ixx`, and `.cxxm` to the existing `cpp` syntax in
`render/highlight.rs`
- extend alias-resolution coverage for all three module extensions
- verify `.cpp`, `.cppm`, `.ixx`, and `.cxxm` diffs produce
syntax-highlighted RGB spans while unknown extensions retain the plain
fallback
- snapshot the syntax-colored token segmentation for the supported C++
module extensions

## How to Test

1. Ask Codex to create or modify a C++ module interface file using
`.cppm`, `.ixx`, or `.cxxm`.
2. Confirm C++ tokens in the rendered diff receive syntax colors instead
of only the red/green diff treatment.
3. Modify an equivalent `.cpp` file and confirm its existing
highlighting remains unchanged.
4. Modify a file with an unknown extension and confirm it still uses the
plain diff fallback.

Targeted tests:

- `just test -p codex-tui -E
'test(find_syntax_resolves_languages_and_aliases) |
test(cpp_module_extensions_use_cpp_highlighting) |
test(unknown_extension_falls_back_without_syntax_highlighting)'`
This commit is contained in:
Felipe Coury
2026-06-16 13:33:13 -04:00
committed by GitHub
Unverified
parent a376781a3c
commit 3ded846488
3 changed files with 94 additions and 2 deletions
+53
View File
@@ -1307,6 +1307,7 @@ fn style_gutter_dim() -> Style {
#[cfg(test)]
mod tests {
use super::*;
use insta::assert_debug_snapshot;
use insta::assert_snapshot;
use pretty_assertions::assert_eq;
use ratatui::Terminal;
@@ -2200,6 +2201,58 @@ mod tests {
);
}
#[test]
fn cpp_module_extensions_use_cpp_highlighting() {
let highlighted_tokens = ["cpp", "cppm", "CPPM", "cxxm", "CxXm", "ixx", "IXX"]
.into_iter()
.map(|extension| {
let mut changes: HashMap<PathBuf, FileChange> = HashMap::new();
changes.insert(
PathBuf::from(format!("math.{extension}")),
FileChange::Add {
content:
"export module math;\nexport int sum(int a, int b) { return a + b; }\n"
.to_string(),
},
);
let lines =
create_diff_summary(&changes, &PathBuf::from("/"), /*wrap_cols*/ 80);
let rgb_tokens = lines
.iter()
.flat_map(|line| &line.spans)
.filter(|span| matches!(span.style.fg, Some(ratatui::style::Color::Rgb(..))))
.map(|span| span.content.to_string())
.collect::<Vec<_>>();
assert!(
!rgb_tokens.is_empty(),
"add diff for .{extension} file should produce syntax-highlighted (RGB) spans"
);
(extension, rgb_tokens.join("|"))
})
.collect::<Vec<_>>();
assert_debug_snapshot!("cpp_module_extension_highlighting", highlighted_tokens);
}
#[test]
fn unknown_extension_falls_back_without_syntax_highlighting() {
let mut changes: HashMap<PathBuf, FileChange> = HashMap::new();
changes.insert(
PathBuf::from("math.unknown-extension"),
FileChange::Add {
content: "export module math;\nexport int value = 42;\n".to_string(),
},
);
let lines = create_diff_summary(&changes, &PathBuf::from("/"), /*wrap_cols*/ 80);
assert!(lines.iter().all(|line| {
line.spans
.iter()
.all(|span| !matches!(span.style.fg, Some(ratatui::style::Color::Rgb(..))))
}));
}
#[test]
fn delete_diff_uses_path_extension_for_highlighting() {
let mut changes: HashMap<PathBuf, FileChange> = HashMap::new();
+7 -2
View File
@@ -526,8 +526,10 @@ fn find_syntax(lang: &str) -> Option<&'static SyntaxReference> {
let ss = syntax_set();
// Aliases that two-face does not resolve on its own.
let patched = match lang {
let normalized = lang.to_ascii_lowercase();
let patched = match normalized.as_str() {
"csharp" | "c-sharp" => "c#",
"cppm" | "cxxm" | "ixx" => "cpp",
"golang" => "go",
"python3" => "python",
"shell" => "bash",
@@ -1203,7 +1205,10 @@ mod tests {
);
}
// Patched aliases that two-face cannot resolve on its own.
for alias in ["csharp", "c-sharp", "golang", "python3", "shell"] {
for alias in [
"csharp", "c-sharp", "cppm", "CPPM", "cxxm", "CxXm", "ixx", "IXX", "golang", "python3",
"shell",
] {
assert!(
find_syntax(alias).is_some(),
"find_syntax({alias:?}) returned None — patched alias broken"
@@ -0,0 +1,34 @@
---
source: tui/src/diff_render.rs
expression: highlighted_tokens
---
[
(
"cpp",
"export| module math|;|export| |int| |sum|(|int| |a|,| |int| |b|)| |{| |return| a |+| b|;| |}",
),
(
"cppm",
"export| module math|;|export| |int| |sum|(|int| |a|,| |int| |b|)| |{| |return| a |+| b|;| |}",
),
(
"CPPM",
"export| module math|;|export| |int| |sum|(|int| |a|,| |int| |b|)| |{| |return| a |+| b|;| |}",
),
(
"cxxm",
"export| module math|;|export| |int| |sum|(|int| |a|,| |int| |b|)| |{| |return| a |+| b|;| |}",
),
(
"CxXm",
"export| module math|;|export| |int| |sum|(|int| |a|,| |int| |b|)| |{| |return| a |+| b|;| |}",
),
(
"ixx",
"export| module math|;|export| |int| |sum|(|int| |a|,| |int| |b|)| |{| |return| a |+| b|;| |}",
),
(
"IXX",
"export| module math|;|export| |int| |sum|(|int| |a|,| |int| |b|)| |{| |return| a |+| b|;| |}",
),
]