task: Make UseSelectedQuery modal action expand to full command (#9947)

Previously it expanded to a label, which was correct for oneshots, but
wrong for everything else.

Release Notes:

- Improved UseSelectedQuery (shift-enter) action for tasks modal by
making it substitute a full command and not the task label.
- Fixed one-shot tasks having duplicates in tasks modal.
This commit is contained in:
Piotr Osiewicz 2024-03-29 11:45:50 +01:00 committed by GitHub
parent c7f04691d9
commit 1360dffead
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 34 additions and 14 deletions

1
Cargo.lock generated
View file

@ -9640,6 +9640,7 @@ dependencies = [
"editor",
"fuzzy",
"gpui",
"itertools 0.11.0",
"language",
"menu",
"picker",

View file

@ -66,9 +66,14 @@ impl OneshotSource {
/// Spawns a certain task based on the user prompt.
pub fn spawn(&mut self, prompt: String) -> Arc<dyn Task> {
let ret = Arc::new(OneshotTask::new(prompt));
self.tasks.push(ret.clone());
ret
if let Some(task) = self.tasks.iter().find(|task| task.id().0 == prompt) {
// If we already have an oneshot task with that command, let's just reuse it.
task.clone()
} else {
let new_oneshot = Arc::new(OneshotTask::new(prompt));
self.tasks.push(new_oneshot.clone());
new_oneshot
}
}
}

View file

@ -22,6 +22,7 @@ ui.workspace = true
util.workspace = true
workspace.workspace = true
language.workspace = true
itertools.workspace = true
[dev-dependencies]
editor = { workspace = true, features = ["test-support"] }

View file

@ -310,7 +310,20 @@ impl PickerDelegate for TasksModalDelegate {
}
fn selected_as_query(&self) -> Option<String> {
Some(self.matches.get(self.selected_index())?.string.clone())
use itertools::intersperse;
let task_index = self.matches.get(self.selected_index())?.candidate_id;
let tasks = self.candidates.as_ref()?;
let (_, task) = tasks.get(task_index)?;
// .exec doesn't actually spawn anything; it merely prepares a spawning command,
// which we can use for substitution.
let mut spawn_prompt = task.exec(self.task_context.clone())?;
if !spawn_prompt.args.is_empty() {
spawn_prompt.command.push(' ');
spawn_prompt
.command
.extend(intersperse(spawn_prompt.args, " ".to_string()));
}
Some(spawn_prompt.command)
}
}
@ -381,15 +394,15 @@ mod tests {
cx.dispatch_action(menu::UseSelectedQuery);
assert_eq!(
query(&tasks_picker, cx),
"example task",
"Query should be set to the selected task's name"
"echo 4",
"Query should be set to the selected task's command"
);
assert_eq!(
task_names(&tasks_picker, cx),
vec!["example task"],
"No other tasks should be listed"
Vec::<String>::new(),
"No task should be listed"
);
cx.dispatch_action(menu::Confirm);
cx.dispatch_action(menu::SecondaryConfirm);
let tasks_picker = open_spawn_tasks(&workspace, cx);
assert_eq!(
@ -399,8 +412,8 @@ mod tests {
);
assert_eq!(
task_names(&tasks_picker, cx),
vec!["example task", "another one"],
"Last recently used task should be listed first"
vec!["echo 4", "another one", "example task"],
"New oneshot task should be listed first"
);
let query_str = "echo 4";
@ -408,8 +421,8 @@ mod tests {
assert_eq!(query(&tasks_picker, cx), query_str);
assert_eq!(
task_names(&tasks_picker, cx),
Vec::<String>::new(),
"No tasks should match custom command query"
vec!["echo 4"],
"New oneshot should match custom command query"
);
cx.dispatch_action(menu::SecondaryConfirm);
@ -421,7 +434,7 @@ mod tests {
);
assert_eq!(
task_names(&tasks_picker, cx),
vec![query_str, "example task", "another one"],
vec![query_str, "another one", "example task"],
"Last recently used one show task should be listed first"
);