tasks.rs

 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}