From 83adaa52b3ebf5db595c29ec7c978342a96c6120 Mon Sep 17 00:00:00 2001 From: Matt Van Horn Date: Tue, 17 Mar 2026 09:04:04 -0700 Subject: [PATCH] task: Expose current buffer language as $ZED_LANGUAGE variable (#51614) Closes #12628 Adds a `$ZED_LANGUAGE` task variable that resolves to the language name of the active buffer (e.g., "Rust", "Python", "Shell Script"). This lets tasks adapt behavior based on language without parsing file extensions. Use cases from the issue: - Pass syntax highlighting language to external tools (e.g., `rg --type $ZED_LANGUAGE`) - Adjust comment wrapping width per language - Handle extensionless files and untitled buffers that have a language assigned VS Code provides equivalent functionality via `${command:activeEditorLanguageId}`. Neovim exposes it as `&filetype`. ## Changes - Added `Language` variant to `VariableName` in `crates/task/src/task.rs` - Populated from `buffer.language().name()` in `BasicContextProvider::build_context` (`crates/project/src/task_inventory.rs`), following the same pattern as `File` and `Stem` - Updated test fixtures in `crates/tasks_ui/src/tasks_ui.rs` to include the new variable - Added `ZED_LANGUAGE` to the variable list in `docs/src/tasks.md` ## Testing Updated the existing `test_task_variables` test in `tasks_ui` to verify `ZED_LANGUAGE` resolves to "Rust" and "TypeScript" for the respective test buffers. This contribution was developed with AI assistance (Claude Code). Release Notes: - Added `$ZED_LANGUAGE` task variable that exposes the current buffer's language name --------- Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Co-authored-by: Kirill Bulatov --- crates/project/src/task_inventory.rs | 4 ++++ crates/task/src/task.rs | 4 ++++ crates/tasks_ui/src/tasks_ui.rs | 13 +++++++++++-- docs/src/tasks.md | 1 + 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/crates/project/src/task_inventory.rs b/crates/project/src/task_inventory.rs index 205232b523cf3773d895368ba0b1b7d2d32a7afe..cbe4a73a654472550673fe54b60974c57e08991d 100644 --- a/crates/project/src/task_inventory.rs +++ b/crates/project/src/task_inventory.rs @@ -985,6 +985,10 @@ impl ContextProvider for BasicContextProvider { task_variables.insert(VariableName::File, path.to_string_lossy().into_owned()); } + if let Some(language) = buffer.language() { + task_variables.insert(VariableName::Language, language.name().to_string()); + } + Task::ready(Ok(task_variables)) } } diff --git a/crates/task/src/task.rs b/crates/task/src/task.rs index a8eccc9af1d7f8b00fb8557bb02c05281c5bb2e6..e91a0bfb3b54b8780f139a63b342cd58755e6355 100644 --- a/crates/task/src/task.rs +++ b/crates/task/src/task.rs @@ -172,6 +172,8 @@ pub enum VariableName { Column, /// Text from the latest selection. SelectedText, + /// The language of the currently opened buffer (e.g., "Rust", "Python"). + Language, /// The symbol selected by the symbol tagging system, specifically the @run capture in a runnables.scm RunnableSymbol, /// Open a Picker to select a process ID to use in place @@ -209,6 +211,7 @@ impl FromStr for VariableName { "SYMBOL" => Self::Symbol, "RUNNABLE_SYMBOL" => Self::RunnableSymbol, "SELECTED_TEXT" => Self::SelectedText, + "LANGUAGE" => Self::Language, "ROW" => Self::Row, "COLUMN" => Self::Column, _ => { @@ -243,6 +246,7 @@ impl std::fmt::Display for VariableName { Self::Row => write!(f, "{ZED_VARIABLE_NAME_PREFIX}ROW"), Self::Column => write!(f, "{ZED_VARIABLE_NAME_PREFIX}COLUMN"), Self::SelectedText => write!(f, "{ZED_VARIABLE_NAME_PREFIX}SELECTED_TEXT"), + Self::Language => write!(f, "{ZED_VARIABLE_NAME_PREFIX}LANGUAGE"), Self::RunnableSymbol => write!(f, "{ZED_VARIABLE_NAME_PREFIX}RUNNABLE_SYMBOL"), Self::PickProcessId => write!(f, "{ZED_VARIABLE_NAME_PREFIX}PICK_PID"), Self::Custom(s) => write!( diff --git a/crates/tasks_ui/src/tasks_ui.rs b/crates/tasks_ui/src/tasks_ui.rs index fdacef3b193beb8a656916edb61fbff1a200385b..3da0c78f8070e874187c39fcbd073994028d146a 100644 --- a/crates/tasks_ui/src/tasks_ui.rs +++ b/crates/tasks_ui/src/tasks_ui.rs @@ -439,7 +439,10 @@ mod tests { let worktree_store = project.read_with(cx, |project, _| project.worktree_store()); let rust_language = Arc::new( Language::new( - LanguageConfig::default(), + LanguageConfig { + name: "Rust".into(), + ..Default::default() + }, Some(tree_sitter_rust::LANGUAGE.into()), ) .with_outline_query( @@ -455,7 +458,10 @@ mod tests { let typescript_language = Arc::new( Language::new( - LanguageConfig::default(), + LanguageConfig { + name: "TypeScript".into(), + ..Default::default() + }, Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()), ) .with_outline_query( @@ -534,6 +540,7 @@ mod tests { (VariableName::WorktreeRoot, path!("/dir").into()), (VariableName::Row, "1".into()), (VariableName::Column, "1".into()), + (VariableName::Language, "Rust".into()), ]), project_env: HashMap::default(), } @@ -568,6 +575,7 @@ mod tests { (VariableName::Column, "15".into()), (VariableName::SelectedText, "is_i".into()), (VariableName::Symbol, "this_is_a_rust_file".into()), + (VariableName::Language, "Rust".into()), ]), project_env: HashMap::default(), } @@ -596,6 +604,7 @@ mod tests { (VariableName::Row, "1".into()), (VariableName::Column, "1".into()), (VariableName::Symbol, "this_is_a_test".into()), + (VariableName::Language, "TypeScript".into()), ]), project_env: HashMap::default(), } diff --git a/docs/src/tasks.md b/docs/src/tasks.md index 482ca7b4d5779a4861756332ce2c0f25eaad4ad4..52598e11ad40ecfc125ba6d03860809452ae8e43 100644 --- a/docs/src/tasks.md +++ b/docs/src/tasks.md @@ -89,6 +89,7 @@ These variables allow you to pull information from the current editor and use it - `ZED_STEM`: stem (filename without extension) of the currently opened file (e.g. `main`) - `ZED_SYMBOL`: currently selected symbol; should match the last symbol shown in a symbol breadcrumb (e.g. `mod tests > fn test_task_contexts`) - `ZED_SELECTED_TEXT`: currently selected text +- `ZED_LANGUAGE`: language of the currently opened buffer (e.g. `Rust`, `Python`, `Shell Script`) - `ZED_WORKTREE_ROOT`: absolute path to the root of the current worktree. (e.g. `/Users/my-user/path/to/project`) - `ZED_CUSTOM_RUST_PACKAGE`: (Rust-specific) name of the parent package of $ZED_FILE source file.