Compare commits

...

1 Commits

Author SHA1 Message Date
Richard Feldman
05660ec626 Have the delete tool use paths, not globs 2025-03-13 10:10:59 -04:00
2 changed files with 16 additions and 83 deletions

View File

@@ -5,12 +5,11 @@ use language_model::LanguageModelRequestMessage;
use project::Project;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::{fs, path::PathBuf, sync::Arc};
use util::paths::PathMatcher;
use std::{fs, sync::Arc};
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct DeletePathToolInput {
/// The glob to match files in the project to delete.
/// The path to the file or directory to delete.
///
/// <example>
/// If the project has the following files:
@@ -19,9 +18,9 @@ pub struct DeletePathToolInput {
/// - directory2/a/things.txt
/// - directory3/a/other.txt
///
/// You can delete the first two files by providing a glob of "*thing*.txt"
/// You can delete the first file by providing the path "directory1/a/something.txt"
/// </example>
pub glob: String,
pub path: String,
}
pub struct DeletePathTool;
@@ -47,47 +46,19 @@ impl Tool for DeletePathTool {
project: Entity<Project>,
cx: &mut App,
) -> Task<Result<String>> {
let glob = match serde_json::from_value::<DeletePathToolInput>(input) {
Ok(input) => input.glob,
let target_path = match serde_json::from_value::<DeletePathToolInput>(input) {
Ok(input) => input.path,
Err(err) => return Task::ready(Err(anyhow!(err))),
};
let path_matcher = match PathMatcher::new(&[glob.clone()]) {
Ok(matcher) => matcher,
Err(err) => return Task::ready(Err(anyhow!("Invalid glob: {}", err))),
};
struct Match {
display_path: String,
path: PathBuf,
}
let mut matches = Vec::new();
let mut deleted_paths = Vec::new();
let mut errors = Vec::new();
// Find the path in any of the worktrees
for worktree_handle in project.read(cx).worktrees(cx) {
let worktree = worktree_handle.read(cx);
let worktree_root = worktree.abs_path().to_path_buf();
// Don't consider ignored entries.
for entry in worktree.entries(false, 0) {
if path_matcher.is_match(&entry.path) {
matches.push(Match {
path: worktree_root.join(&entry.path),
display_path: entry.path.display().to_string(),
});
}
}
}
if matches.is_empty() {
return Task::ready(Ok(format!("No paths in the project matched {glob:?}")));
}
let paths_matched = matches.len();
// Delete the files
for Match { path, display_path } in matches {
let path = worktree.abs_path().join(&target_path);
let display_path = target_path.clone();
match fs::remove_file(&path) {
Ok(()) => {
deleted_paths.push(display_path);
@@ -112,54 +83,16 @@ impl Tool for DeletePathTool {
}
if errors.is_empty() {
// 0 deleted paths should never happen if there were no errors;
// we already returned if matches was empty.
let answer = if deleted_paths.len() == 1 {
format!(
"Deleted {}",
deleted_paths.first().unwrap_or(&String::new())
)
} else {
// Sort to group entries in the same directory together
deleted_paths.sort();
let mut buf = format!("Deleted these {} paths:\n", deleted_paths.len());
for path in deleted_paths.iter() {
buf.push('\n');
buf.push_str(path);
}
buf
};
Task::ready(Ok(answer))
} else {
if deleted_paths.is_empty() {
Task::ready(Err(anyhow!(
"{glob:?} matched {} deleted because of {}:\n{}",
if paths_matched == 1 {
"1 path, but it was not".to_string()
} else {
format!("{} paths, but none were", paths_matched)
},
if errors.len() == 1 {
"this error".to_string()
} else {
format!("{} errors", errors.len())
},
errors.join("\n")
Task::ready(Ok(format!(
"No file or directory found at path: {}",
target_path
)))
} else {
// Sort to group entries in the same directory together
deleted_paths.sort();
Task::ready(Ok(format!(
"Deleted {} paths matching glob {glob:?}:\n{}\n\nErrors:\n{}",
deleted_paths.len(),
deleted_paths.join("\n"),
errors.join("\n")
)))
Task::ready(Ok(format!("Deleted {}", target_path)))
}
} else {
Task::ready(Err(anyhow!(errors.join("\n"))))
}
}
}

View File

@@ -1 +1 @@
Deletes all files and directories in the project which match the given glob, and returns a list of the paths that were deleted.
Deletes a specific file or directory in the project at the given path, and returns confirmation of what was deleted.