Always provide default task context (#10764)

Based on
https://github.com/zed-industries/zed/issues/8324?notification_referrer_id=NT_kwDOACkO1bI5NTk0NjM0NzkyOjI2OTA3NzM&notifications_query=repo%3Azed-industries%2Fzed+is%3Aunread#issuecomment-2065551553

Release Notes:

- Fixed certain files' task modal not showing context-based tasks
This commit is contained in:
Kirill Bulatov 2024-04-19 10:51:50 +03:00 committed by GitHub
parent 9863b920b0
commit 222034cacf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 106 additions and 20 deletions

View file

@ -15,9 +15,9 @@ pub trait ContextProvider: Send + Sync {
/// Builds a specific context to be placed on top of the basic one (replacing all conflicting entries) and to be used for task resolving later.
fn build_context(
&self,
_: Option<&Path>,
_: &Location,
_: &mut AppContext,
_worktree_abs_path: Option<&Path>,
_location: &Location,
_cx: &mut AppContext,
) -> Result<TaskVariables> {
Ok(TaskVariables::default())
}

View file

@ -85,13 +85,7 @@ pub fn init(
config.name.clone(),
config.grammar.clone(),
config.matcher.clone(),
move || {
Ok((
config.clone(),
load_queries($name),
Some(Arc::new(language::BasicContextProvider)),
))
},
move || Ok((config.clone(), load_queries($name), None)),
);
};
($name:literal, $adapters:expr) => {
@ -105,13 +99,7 @@ pub fn init(
config.name.clone(),
config.grammar.clone(),
config.matcher.clone(),
move || {
Ok((
config.clone(),
load_queries($name),
Some(Arc::new(language::BasicContextProvider)),
))
},
move || Ok((config.clone(), load_queries($name), None)),
);
};
($name:literal, $adapters:expr, $context_provider:expr) => {

View file

@ -168,8 +168,8 @@ fn task_context(workspace: &Workspace, cx: &mut WindowContext<'_>) -> TaskContex
let language_context_provider = buffer
.read(cx)
.language()
.and_then(|language| language.context_provider())?;
.and_then(|language| language.context_provider())
.unwrap_or_else(|| Arc::new(BasicContextProvider));
let selection_range = selection.range();
let start = editor_snapshot
.display_snapshot

View file

@ -418,7 +418,11 @@ impl PickerDelegate for TasksModalDelegate {
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use editor::Editor;
use gpui::{TestAppContext, VisualTestContext};
use language::Point;
use project::{FakeFs, Project};
use serde_json::json;
@ -574,6 +578,100 @@ mod tests {
);
}
#[gpui::test]
async fn test_basic_context_for_simple_files(cx: &mut TestAppContext) {
crate::tests::init_test(cx);
let fs = FakeFs::new(cx.executor());
fs.insert_tree(
"/dir",
json!({
".zed": {
"tasks.json": r#"[
{
"label": "hello from $ZED_FILE:$ZED_ROW:$ZED_COLUMN",
"command": "echo",
"args": ["hello", "from", "$ZED_FILE", ":", "$ZED_ROW", ":", "$ZED_COLUMN"]
},
{
"label": "opened now: $ZED_WORKTREE_ROOT",
"command": "echo",
"args": ["opened", "now:", "$ZED_WORKTREE_ROOT"]
}
]"#,
},
"file_without_extension": "aaaaaaaaaaaaaaaaaaaa\naaaaaaaaaaaaaaaaaa",
"file_with.odd_extension": "b",
}),
)
.await;
let project = Project::test(fs, ["/dir".as_ref()], cx).await;
let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
let tasks_picker = open_spawn_tasks(&workspace, cx);
assert_eq!(
task_names(&tasks_picker, cx),
Vec::<String>::new(),
"Should list no file or worktree context-dependent when no file is open"
);
tasks_picker.update(cx, |_, cx| {
cx.emit(DismissEvent);
});
drop(tasks_picker);
cx.executor().run_until_parked();
let _ = workspace
.update(cx, |workspace, cx| {
workspace.open_abs_path(PathBuf::from("/dir/file_with.odd_extension"), true, cx)
})
.await
.unwrap();
cx.executor().run_until_parked();
let tasks_picker = open_spawn_tasks(&workspace, cx);
assert_eq!(
task_names(&tasks_picker, cx),
vec![
"hello from …th.odd_extension:1:1".to_string(),
"opened now: /dir".to_string()
],
"Second opened buffer should fill the context, labels should be trimmed if long enough"
);
tasks_picker.update(cx, |_, cx| {
cx.emit(DismissEvent);
});
drop(tasks_picker);
cx.executor().run_until_parked();
let second_item = workspace
.update(cx, |workspace, cx| {
workspace.open_abs_path(PathBuf::from("/dir/file_without_extension"), true, cx)
})
.await
.unwrap();
let editor = cx.update(|cx| second_item.act_as::<Editor>(cx)).unwrap();
editor.update(cx, |editor, cx| {
editor.change_selections(None, cx, |s| {
s.select_ranges(Some(Point::new(1, 2)..Point::new(1, 5)))
})
});
cx.executor().run_until_parked();
let tasks_picker = open_spawn_tasks(&workspace, cx);
assert_eq!(
task_names(&tasks_picker, cx),
vec![
"hello from …ithout_extension:2:3".to_string(),
"opened now: /dir".to_string()
],
"Opened buffer should fill the context, labels should be trimmed if long enough"
);
tasks_picker.update(cx, |_, cx| {
cx.emit(DismissEvent);
});
drop(tasks_picker);
cx.executor().run_until_parked();
}
fn open_spawn_tasks(
workspace: &View<Workspace>,
cx: &mut VisualTestContext,
@ -582,7 +680,7 @@ mod tests {
workspace.update(cx, |workspace, cx| {
workspace
.active_modal::<TasksModal>(cx)
.unwrap()
.expect("no task modal after `Spawn` action was dispatched")
.read(cx)
.picker
.clone()