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