diff --git a/Cargo.lock b/Cargo.lock index aaa8cbb669b2cf716184692ecdd4765ccfa244da..81510a6ad30e11f0185d0f20a7cc3cc59521c36a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7695,6 +7695,7 @@ dependencies = [ "lsp", "node_runtime", "parking_lot", + "pathdiff", "postage", "prettier", "pretty_assertions", diff --git a/Cargo.toml b/Cargo.toml index 993c66e563fb6b9f7660ebe020f0a6d109cefe3b..b174f80fbb5b450cc50e0abea48a5a91ae6a7c0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -305,6 +305,7 @@ once_cell = "1.19.0" ordered-float = "2.1.1" palette = { version = "0.7.5", default-features = false, features = ["std"] } parking_lot = "0.12.1" +pathdiff = "0.2" profiling = "1" postage = { version = "0.5", features = ["futures-traits"] } pretty_assertions = "1.3.0" diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index ae5c510f35234a5e29e8285d8f12e7f8793b6a8a..a35d2f73c4047fa9d0a38d738098a79825789596 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -44,6 +44,7 @@ log.workspace = true lsp.workspace = true node_runtime.workspace = true parking_lot.workspace = true +pathdiff.workspace = true postage.workspace = true prettier.workspace = true worktree.workspace = true diff --git a/crates/project/src/task_inventory.rs b/crates/project/src/task_inventory.rs index fbed35e3828525701f23bd3f5e3bef5e0f90df1c..bc5d9fdfab21ab58f99d198a9bfa3ac89a14b9c1 100644 --- a/crates/project/src/task_inventory.rs +++ b/crates/project/src/task_inventory.rs @@ -549,20 +549,6 @@ impl ContextProvider for BasicContextProvider { if !selected_text.trim().is_empty() { task_variables.insert(VariableName::SelectedText, selected_text); } - if let Some(path) = current_file { - task_variables.insert(VariableName::File, path.clone()); - - let path = Path::new(&path); - - if let Some(filename) = path.file_name().and_then(|f| f.to_str()) { - task_variables.insert(VariableName::Filename, String::from(filename)); - } - - if let Some(stem) = path.file_stem().and_then(|s| s.to_str()) { - task_variables.insert(VariableName::Stem, String::from(stem)); - } - } - let worktree_abs_path = buffer .file() .map(|file| WorktreeId::from_usize(file.worktree_id())) @@ -577,6 +563,32 @@ impl ContextProvider for BasicContextProvider { VariableName::WorktreeRoot, worktree_path.to_string_lossy().to_string(), ); + if let Some(full_path) = current_file.as_ref() { + let relative_path = pathdiff::diff_paths(full_path, worktree_path); + if let Some(relative_path) = relative_path { + task_variables.insert( + VariableName::RelativeFile, + relative_path.to_string_lossy().into_owned(), + ); + } + } + } + + if let Some(path_as_string) = current_file { + let path = Path::new(&path_as_string); + if let Some(filename) = path.file_name().and_then(|f| f.to_str()) { + task_variables.insert(VariableName::Filename, String::from(filename)); + } + + if let Some(stem) = path.file_stem().and_then(|s| s.to_str()) { + task_variables.insert(VariableName::Stem, stem.into()); + } + + if let Some(dirname) = path.parent().and_then(|s| s.to_str()) { + task_variables.insert(VariableName::Dirname, dirname.into()); + } + + task_variables.insert(VariableName::File, path_as_string); } Ok(task_variables) diff --git a/crates/task/src/lib.rs b/crates/task/src/lib.rs index 3d7a4e3a5b4083da4ffef0cf2f05f3c6770ca822..91f3cdb1f95be9d2b8bd94f754db383164f872a8 100644 --- a/crates/task/src/lib.rs +++ b/crates/task/src/lib.rs @@ -124,9 +124,13 @@ impl ResolvedTask { pub enum VariableName { /// An absolute path of the currently opened file. File, - /// the currently opened filename. + /// A path of the currently opened file (relative to worktree root). + RelativeFile, + /// The currently opened filename. Filename, - /// stem (filename without extension) of the currently opened file. + /// The path to a parent directory of a currently opened file. + Dirname, + /// Stem (filename without extension) of the currently opened file. Stem, /// An absolute path of the currently opened worktree, that contains the file. WorktreeRoot, @@ -165,6 +169,8 @@ impl std::fmt::Display for VariableName { match self { Self::File => write!(f, "{ZED_VARIABLE_NAME_PREFIX}FILE"), Self::Filename => write!(f, "{ZED_VARIABLE_NAME_PREFIX}FILENAME"), + Self::RelativeFile => write!(f, "{ZED_VARIABLE_NAME_PREFIX}RELATIVE_FILE"), + Self::Dirname => write!(f, "{ZED_VARIABLE_NAME_PREFIX}DIRNAME"), Self::Stem => write!(f, "{ZED_VARIABLE_NAME_PREFIX}STEM"), Self::WorktreeRoot => write!(f, "{ZED_VARIABLE_NAME_PREFIX}WORKTREE_ROOT"), Self::Symbol => write!(f, "{ZED_VARIABLE_NAME_PREFIX}SYMBOL"), diff --git a/crates/tasks_ui/src/lib.rs b/crates/tasks_ui/src/lib.rs index bbc3161cd7c73bd5253c776704f92002c29214ff..051a59b46b896afdf6c0588cc56a001a4dc609a6 100644 --- a/crates/tasks_ui/src/lib.rs +++ b/crates/tasks_ui/src/lib.rs @@ -261,6 +261,8 @@ mod tests { task_variables: TaskVariables::from_iter([ (VariableName::File, "/dir/rust/b.rs".into()), (VariableName::Filename, "b.rs".into()), + (VariableName::RelativeFile, "rust/b.rs".into()), + (VariableName::Dirname, "/dir/rust".into()), (VariableName::Stem, "b".into()), (VariableName::WorktreeRoot, "/dir".into()), (VariableName::Row, "1".into()), @@ -279,6 +281,8 @@ mod tests { task_variables: TaskVariables::from_iter([ (VariableName::File, "/dir/rust/b.rs".into()), (VariableName::Filename, "b.rs".into()), + (VariableName::RelativeFile, "rust/b.rs".into()), + (VariableName::Dirname, "/dir/rust".into()), (VariableName::Stem, "b".into()), (VariableName::WorktreeRoot, "/dir".into()), (VariableName::Row, "1".into()), @@ -298,6 +302,8 @@ mod tests { task_variables: TaskVariables::from_iter([ (VariableName::File, "/dir/a.ts".into()), (VariableName::Filename, "a.ts".into()), + (VariableName::RelativeFile, "a.ts".into()), + (VariableName::Dirname, "/dir".into()), (VariableName::Stem, "a".into()), (VariableName::WorktreeRoot, "/dir".into()), (VariableName::Row, "1".into()), diff --git a/docs/src/tasks.md b/docs/src/tasks.md index a89f5e9436dfb557fd36c064f47725453d9fda22..06687acf5adb870e23ce344a8b832eed47c3d8e5 100644 --- a/docs/src/tasks.md +++ b/docs/src/tasks.md @@ -45,6 +45,8 @@ These variables allow you to pull information from the current editor and use it - `ZED_ROW`: current line row - `ZED_FILE`: absolute path of the currently opened file (e.g. `/Users/my-user/path/to/project/src/main.rs`) - `ZED_FILENAME`: filename of the currently opened file (e.g. `main.rs`) +- `ZED_DIRNAME`: absolute path of the currently opened file with file name stripped (e.g. `/Users/my-user/path/to/project/src`) +- `ZED_RELATIVE_FILE`: path of the currently opened file, relative to `ZED_WORKTREE_ROOT` (e.g. `src/main.rs`) - `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