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}