mirror of
https://github.com/warpdotdev/warp.git
synced 2026-05-06 23:32:51 +08:00
Enhance programming language support in syntax highlighting by adding aliases and new languages (#9471)
## Description `ProgrammingLanguage::to_extension` in `app/src/ai/agent/mod.rs` is the choke point for syntax highlighting in AI blocks. When the agent emits a markdown code fence, the language token becomes a `ProgrammingLanguage`, and `to_extension()` is called to construct a `snippet.<ext>` path that `set_language_with_path` uses to look up the tree-sitter grammar (see `app/src/ai/blocklist/block.rs:2607-2617`, `block.rs:2675`, and `block/cli.rs:732-740`). If `to_extension` returns `None`, `set_language_with_path` is never called and the block renders as plain text. The function omits a number of languages that the `languages` crate fully supports via `language_by_filename`, so common AI code-fence labels render with no syntax highlighting today: - `jsx`, `tsx` — every React snippet - `vue` — every Vue component snippet - `xml` — every config / Android / .NET snippet - `dockerfile` (and `docker`, `containerfile`) — every container snippet - `starlark`, `objective-c` (and `objc`) This PR adds those arms and folds in the most common markdown-fence aliases (`rs`, `py`, `js`, `ts`, `yml`, `kt`, `rb`, `golang`, `terraform`, `tf`) so coverage matches `language_by_filename`. The TODO comment at the top of the function (`INT-605: Refactor so we don't have to edit this function and the languages crate`) anticipates exactly this kind of sync. The `Self::Shell(Bash | Zsh | Fish)` arms are intentionally left as-is — only PowerShell currently exposes an extension, and extending the other shells looks like a separate behavior change. ## Testing - Added `test_programming_language_to_extension` in `app/src/ai/agent/mod_test.rs` covering 46 cases: every existing arm + every new arm + every alias + a round-trip note that each returned extension is one `language_by_filename` actually accepts. The new arms (`jsx`, `tsx`, `xml`, `vue`, `dockerfile`, `starlark`, `objective-c`, `objc`) and aliases (`rs`, `golang`, `py`, `js`, `ts`, `yml`, `c++`, `rb`, `kt`, `terraform`, `tf`, `docker`, `containerfile`) all fail on master and pass after the change. - `cargo fmt -p warp_terminal -- --check` passes locally. ## Agent Mode - [ ] Warp Agent Mode - This PR was created via Warp's AI Agent Mode ## Changelog Entries for Stable CHANGELOG-BUG-FIX: AI code blocks tagged `vue`, `xml`, `dockerfile`, `jsx`, `tsx`, `objective-c`, or `starlark` now render with syntax highlighting. Common aliases like `rs`, `py`, `js`, `ts`, `yml`, `kt`, `rb`, `golang`, `terraform`, and `docker` are also recognized.
This commit is contained in:
committed by
GitHub
parent
404bfbeb8f
commit
af5eed14fe
@@ -717,13 +717,19 @@ impl ProgrammingLanguage {
|
||||
#[cfg_attr(target_family = "wasm", allow(unused))]
|
||||
pub fn to_extension(&self) -> Option<&str> {
|
||||
match self {
|
||||
// The arms below cover both canonical language names emitted by the agent (e.g.
|
||||
// "rust", "kotlin") and common markdown code-fence aliases (e.g. "rs", "kt") to keep
|
||||
// syntax highlighting working when the model uses either. The set of recognized
|
||||
// languages here is kept in sync with `SUPPORTED_LANGUAGES` in the `languages` crate.
|
||||
Self::Other(language) => match language.to_lowercase().as_str() {
|
||||
"rust" => Some("rs"),
|
||||
"go" => Some("go"),
|
||||
"python" => Some("py"),
|
||||
"javascript" => Some("js"),
|
||||
"typescript" => Some("ts"),
|
||||
"yaml" => Some("yaml"),
|
||||
"rust" | "rs" => Some("rs"),
|
||||
"go" | "golang" => Some("go"),
|
||||
"python" | "py" => Some("py"),
|
||||
"javascript" | "js" => Some("js"),
|
||||
"typescript" | "ts" => Some("ts"),
|
||||
"jsx" => Some("jsx"),
|
||||
"tsx" => Some("tsx"),
|
||||
"yaml" | "yml" => Some("yaml"),
|
||||
"cpp" | "c++" => Some("cpp"),
|
||||
"java" => Some("java"),
|
||||
"groovy" => Some("java"),
|
||||
@@ -733,17 +739,22 @@ impl ProgrammingLanguage {
|
||||
"css" => Some("css"),
|
||||
"c" => Some("c"),
|
||||
"json" => Some("json"),
|
||||
"hcl" => Some("hcl"),
|
||||
"hcl" | "terraform" | "tf" => Some("hcl"),
|
||||
"lua" => Some("lua"),
|
||||
"ruby" => Some("rb"),
|
||||
"ruby" | "rb" => Some("rb"),
|
||||
"php" => Some("php"),
|
||||
"toml" => Some("toml"),
|
||||
"swift" => Some("swift"),
|
||||
"kotlin" => Some("kt"),
|
||||
"kotlin" | "kt" => Some("kt"),
|
||||
"powershell" => Some("ps1"),
|
||||
"elixir" => Some("exs"),
|
||||
"scala" => Some("scala"),
|
||||
"sql" => Some("sql"),
|
||||
"objective-c" | "objc" => Some("m"),
|
||||
"starlark" => Some("bzl"),
|
||||
"xml" => Some("xml"),
|
||||
"vue" => Some("vue"),
|
||||
"dockerfile" | "docker" | "containerfile" => Some("dockerfile"),
|
||||
_ => None,
|
||||
},
|
||||
Self::Shell(ShellType::PowerShell) => Some("ps1"),
|
||||
|
||||
@@ -152,6 +152,86 @@ fn test_programming_language_from_string() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_programming_language_to_extension() {
|
||||
// Each entry is (markdown language token, expected extension). The expected extension
|
||||
// must resolve back to a recognized language via `languages::language_by_filename` so that
|
||||
// syntax highlighting is applied to the AI block.
|
||||
let cases: &[(&str, &str)] = &[
|
||||
// Canonical names.
|
||||
("rust", "rs"),
|
||||
("go", "go"),
|
||||
("python", "py"),
|
||||
("javascript", "js"),
|
||||
("typescript", "ts"),
|
||||
("yaml", "yaml"),
|
||||
("cpp", "cpp"),
|
||||
("java", "java"),
|
||||
("c#", "cs"),
|
||||
("csharp", "cs"),
|
||||
("html", "html"),
|
||||
("css", "css"),
|
||||
("c", "c"),
|
||||
("json", "json"),
|
||||
("hcl", "hcl"),
|
||||
("lua", "lua"),
|
||||
("ruby", "rb"),
|
||||
("php", "php"),
|
||||
("toml", "toml"),
|
||||
("swift", "swift"),
|
||||
("kotlin", "kt"),
|
||||
("powershell", "ps1"),
|
||||
("elixir", "exs"),
|
||||
("scala", "scala"),
|
||||
("sql", "sql"),
|
||||
// Languages newly covered by this fix — previously fell through to None and rendered
|
||||
// without syntax highlighting in AI blocks even though the `languages` crate supports them.
|
||||
("jsx", "jsx"),
|
||||
("tsx", "tsx"),
|
||||
("xml", "xml"),
|
||||
("vue", "vue"),
|
||||
("dockerfile", "dockerfile"),
|
||||
("starlark", "bzl"),
|
||||
("objective-c", "m"),
|
||||
("objc", "m"),
|
||||
// Common markdown code-fence aliases.
|
||||
("rs", "rs"),
|
||||
("golang", "go"),
|
||||
("py", "py"),
|
||||
("js", "js"),
|
||||
("ts", "ts"),
|
||||
("yml", "yaml"),
|
||||
("c++", "cpp"),
|
||||
("rb", "rb"),
|
||||
("kt", "kt"),
|
||||
("terraform", "hcl"),
|
||||
("tf", "hcl"),
|
||||
("docker", "dockerfile"),
|
||||
("containerfile", "dockerfile"),
|
||||
];
|
||||
for (token, expected_extension) in cases {
|
||||
let language = ProgrammingLanguage::from((*token).to_string());
|
||||
assert_eq!(
|
||||
language.to_extension(),
|
||||
Some(*expected_extension),
|
||||
"expected to_extension({token:?}) to be Some({expected_extension:?})",
|
||||
);
|
||||
}
|
||||
|
||||
// PowerShell remains the only Shell variant whose extension is exposed; this preserves
|
||||
// existing behavior for the other Shell variants which are intentionally not extended here.
|
||||
assert_eq!(
|
||||
ProgrammingLanguage::Shell(ShellType::PowerShell).to_extension(),
|
||||
Some("ps1"),
|
||||
);
|
||||
|
||||
// Unrecognized tokens still return None.
|
||||
assert_eq!(
|
||||
ProgrammingLanguage::Other("definitely-not-a-language".to_string()).to_extension(),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_for_copy_preserves_visual_markdown_sections() {
|
||||
let output = AIAgentOutput {
|
||||
|
||||
Reference in New Issue
Block a user