tasks.rs

  1use crate::Editor;
  2
  3use std::{path::Path, sync::Arc};
  4
  5use anyhow::Context;
  6use gpui::WindowContext;
  7use language::{BasicContextProvider, ContextProvider};
  8use project::{Location, WorktreeId};
  9use task::{TaskContext, TaskVariables};
 10use util::ResultExt;
 11use workspace::Workspace;
 12
 13pub(crate) fn task_context_for_location(
 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 buffer = location.buffer.clone();
 23    let language_context_provider = buffer
 24        .read(cx)
 25        .language()
 26        .and_then(|language| language.context_provider())
 27        .unwrap_or_else(|| Arc::new(BasicContextProvider));
 28
 29    let worktree_abs_path = buffer
 30        .read(cx)
 31        .file()
 32        .map(|file| WorktreeId::from_usize(file.worktree_id()))
 33        .and_then(|worktree_id| {
 34            workspace
 35                .project()
 36                .read(cx)
 37                .worktree_for_id(worktree_id, cx)
 38                .map(|worktree| worktree.read(cx).abs_path())
 39        });
 40    let task_variables = combine_task_variables(
 41        worktree_abs_path.as_deref(),
 42        location,
 43        language_context_provider.as_ref(),
 44        cx,
 45    )
 46    .log_err()?;
 47    Some(TaskContext {
 48        cwd,
 49        task_variables,
 50    })
 51}
 52
 53pub(crate) fn task_context_with_editor(
 54    workspace: &Workspace,
 55    editor: &mut Editor,
 56    cx: &mut WindowContext<'_>,
 57) -> Option<TaskContext> {
 58    let (selection, buffer, editor_snapshot) = {
 59        let selection = editor.selections.newest::<usize>(cx);
 60        let (buffer, _, _) = editor
 61            .buffer()
 62            .read(cx)
 63            .point_to_buffer_offset(selection.start, cx)?;
 64        let snapshot = editor.snapshot(cx);
 65        Some((selection, buffer, snapshot))
 66    }?;
 67    let selection_range = selection.range();
 68    let start = editor_snapshot
 69        .display_snapshot
 70        .buffer_snapshot
 71        .anchor_after(selection_range.start)
 72        .text_anchor;
 73    let end = editor_snapshot
 74        .display_snapshot
 75        .buffer_snapshot
 76        .anchor_after(selection_range.end)
 77        .text_anchor;
 78    let location = Location {
 79        buffer,
 80        range: start..end,
 81    };
 82    task_context_for_location(workspace, location, cx)
 83}
 84
 85pub fn task_context(workspace: &Workspace, cx: &mut WindowContext<'_>) -> TaskContext {
 86    let Some(editor) = workspace
 87        .active_item(cx)
 88        .and_then(|item| item.act_as::<Editor>(cx))
 89    else {
 90        return Default::default();
 91    };
 92    editor.update(cx, |editor, cx| {
 93        task_context_with_editor(workspace, editor, cx).unwrap_or_default()
 94    })
 95}
 96
 97fn combine_task_variables(
 98    worktree_abs_path: Option<&Path>,
 99    location: Location,
100    context_provider: &dyn ContextProvider,
101    cx: &mut WindowContext<'_>,
102) -> anyhow::Result<TaskVariables> {
103    if context_provider.is_basic() {
104        context_provider
105            .build_context(worktree_abs_path, &location, cx)
106            .context("building basic provider context")
107    } else {
108        let mut basic_context = BasicContextProvider
109            .build_context(worktree_abs_path, &location, cx)
110            .context("building basic default context")?;
111        basic_context.extend(
112            context_provider
113                .build_context(worktree_abs_path, &location, cx)
114                .context("building provider context ")?,
115        );
116        Ok(basic_context)
117    }
118}