tasks.rs

  1use crate::Editor;
  2
  3use anyhow::Context;
  4use gpui::{Model, WindowContext};
  5use language::ContextProvider;
  6use project::{BasicContextProvider, Location, Project};
  7use task::{TaskContext, TaskVariables, VariableName};
  8use text::Point;
  9use util::ResultExt;
 10use workspace::Workspace;
 11
 12pub(crate) fn task_context_for_location(
 13    captured_variables: TaskVariables,
 14    workspace: &Workspace,
 15    location: Location,
 16    cx: &mut WindowContext<'_>,
 17) -> Option<TaskContext> {
 18    let cwd = workspace::tasks::task_cwd(workspace, cx)
 19        .log_err()
 20        .flatten();
 21
 22    let mut task_variables = combine_task_variables(
 23        captured_variables,
 24        location,
 25        workspace.project().clone(),
 26        cx,
 27    )
 28    .log_err()?;
 29    // Remove all custom entries starting with _, as they're not intended for use by the end user.
 30    task_variables.sweep();
 31
 32    Some(TaskContext {
 33        cwd,
 34        task_variables,
 35    })
 36}
 37
 38fn task_context_with_editor(
 39    workspace: &Workspace,
 40    editor: &mut Editor,
 41    cx: &mut WindowContext<'_>,
 42) -> Option<TaskContext> {
 43    let (selection, buffer, editor_snapshot) = {
 44        let mut selection = editor.selections.newest::<Point>(cx);
 45        if editor.selections.line_mode {
 46            selection.start = Point::new(selection.start.row, 0);
 47            selection.end = Point::new(selection.end.row + 1, 0);
 48        }
 49        let (buffer, _, _) = editor
 50            .buffer()
 51            .read(cx)
 52            .point_to_buffer_offset(selection.start, cx)?;
 53        let snapshot = editor.snapshot(cx);
 54        Some((selection, buffer, snapshot))
 55    }?;
 56    let selection_range = selection.range();
 57    let start = editor_snapshot
 58        .display_snapshot
 59        .buffer_snapshot
 60        .anchor_after(selection_range.start)
 61        .text_anchor;
 62    let end = editor_snapshot
 63        .display_snapshot
 64        .buffer_snapshot
 65        .anchor_after(selection_range.end)
 66        .text_anchor;
 67    let location = Location {
 68        buffer,
 69        range: start..end,
 70    };
 71    let captured_variables = {
 72        let mut variables = TaskVariables::default();
 73        for range in location
 74            .buffer
 75            .read(cx)
 76            .snapshot()
 77            .runnable_ranges(location.range.clone())
 78        {
 79            for (capture_name, value) in range.extra_captures {
 80                variables.insert(VariableName::Custom(capture_name.into()), value);
 81            }
 82        }
 83        variables
 84    };
 85    task_context_for_location(captured_variables, workspace, location.clone(), cx)
 86}
 87
 88pub fn task_context(workspace: &Workspace, cx: &mut WindowContext<'_>) -> TaskContext {
 89    let Some(editor) = workspace
 90        .active_item(cx)
 91        .and_then(|item| item.act_as::<Editor>(cx))
 92    else {
 93        return Default::default();
 94    };
 95    editor.update(cx, |editor, cx| {
 96        task_context_with_editor(workspace, editor, cx).unwrap_or_default()
 97    })
 98}
 99
100fn combine_task_variables(
101    mut captured_variables: TaskVariables,
102    location: Location,
103    project: Model<Project>,
104    cx: &mut WindowContext<'_>,
105) -> anyhow::Result<TaskVariables> {
106    let language_context_provider = location
107        .buffer
108        .read(cx)
109        .language()
110        .and_then(|language| language.context_provider());
111    let baseline = BasicContextProvider::new(project)
112        .build_context(&captured_variables, &location, cx)
113        .context("building basic default context")?;
114    captured_variables.extend(baseline);
115    if let Some(provider) = language_context_provider {
116        captured_variables.extend(
117            provider
118                .build_context(&captured_variables, &location, cx)
119                .context("building provider context ")?,
120        );
121    }
122    Ok(captured_variables)
123}