1use crate::Editor;
2
3use gpui::{Task as AsyncTask, WindowContext};
4use project::Location;
5use task::{TaskContext, TaskVariables, VariableName};
6use text::{Point, ToOffset, ToPoint};
7use workspace::Workspace;
8
9fn task_context_with_editor(
10 editor: &mut Editor,
11 cx: &mut WindowContext<'_>,
12) -> AsyncTask<Option<TaskContext>> {
13 let Some(project) = editor.project.clone() else {
14 return AsyncTask::ready(None);
15 };
16 let (selection, buffer, editor_snapshot) = {
17 let mut selection = editor.selections.newest::<Point>(cx);
18 if editor.selections.line_mode {
19 selection.start = Point::new(selection.start.row, 0);
20 selection.end = Point::new(selection.end.row + 1, 0);
21 }
22 let Some((buffer, _, _)) = editor
23 .buffer()
24 .read(cx)
25 .point_to_buffer_offset(selection.start, cx)
26 else {
27 return AsyncTask::ready(None);
28 };
29 let snapshot = editor.snapshot(cx);
30 (selection, buffer, snapshot)
31 };
32 let selection_range = selection.range();
33 let start = editor_snapshot
34 .display_snapshot
35 .buffer_snapshot
36 .anchor_after(selection_range.start)
37 .text_anchor;
38 let end = editor_snapshot
39 .display_snapshot
40 .buffer_snapshot
41 .anchor_after(selection_range.end)
42 .text_anchor;
43 let location = Location {
44 buffer,
45 range: start..end,
46 };
47 let captured_variables = {
48 let mut variables = TaskVariables::default();
49 let buffer = location.buffer.read(cx);
50 let buffer_id = buffer.remote_id();
51 let snapshot = buffer.snapshot();
52 let starting_point = location.range.start.to_point(&snapshot);
53 let starting_offset = starting_point.to_offset(&snapshot);
54 for (_, tasks) in editor
55 .tasks
56 .range((buffer_id, 0)..(buffer_id, starting_point.row + 1))
57 {
58 if !tasks
59 .context_range
60 .contains(&crate::BufferOffset(starting_offset))
61 {
62 continue;
63 }
64 for (capture_name, value) in tasks.extra_variables.iter() {
65 variables.insert(
66 VariableName::Custom(capture_name.to_owned().into()),
67 value.clone(),
68 );
69 }
70 }
71 variables
72 };
73
74 let context_task = project.update(cx, |project, cx| {
75 project.task_context_for_location(captured_variables, location.clone(), cx)
76 });
77 cx.spawn(|_| context_task)
78}
79
80pub fn task_context(workspace: &Workspace, cx: &mut WindowContext<'_>) -> AsyncTask<TaskContext> {
81 let Some(editor) = workspace
82 .active_item(cx)
83 .and_then(|item| item.act_as::<Editor>(cx))
84 else {
85 return AsyncTask::ready(TaskContext::default());
86 };
87 editor.update(cx, |editor, cx| {
88 let context_task = task_context_with_editor(editor, cx);
89 cx.background_executor()
90 .spawn(async move { context_task.await.unwrap_or_default() })
91 })
92}