1use crate::{LanguageRegistry, Location};
2
3use anyhow::Result;
4use gpui::{AppContext, Context, Model};
5use std::sync::Arc;
6use task::{
7 static_source::{tasks_for, TaskDefinitions},
8 TaskSource, TaskVariables, VariableName,
9};
10
11/// Language Contexts are used by Zed tasks to extract information about source file.
12pub trait ContextProvider: Send + Sync {
13 fn build_context(&self, _: Location, _: &mut AppContext) -> Result<TaskVariables> {
14 Ok(TaskVariables::default())
15 }
16
17 fn associated_tasks(&self) -> Option<TaskDefinitions> {
18 None
19 }
20}
21
22/// A context provider that finds out what symbol is currently focused in the buffer.
23pub struct SymbolContextProvider;
24
25impl ContextProvider for SymbolContextProvider {
26 fn build_context(
27 &self,
28 location: Location,
29 cx: &mut AppContext,
30 ) -> gpui::Result<TaskVariables> {
31 let symbols = location
32 .buffer
33 .read(cx)
34 .snapshot()
35 .symbols_containing(location.range.start, None);
36 let symbol = symbols.unwrap_or_default().last().map(|symbol| {
37 let range = symbol
38 .name_ranges
39 .last()
40 .cloned()
41 .unwrap_or(0..symbol.text.len());
42 symbol.text[range].to_string()
43 });
44 Ok(TaskVariables::from_iter(
45 Some(VariableName::Symbol).zip(symbol),
46 ))
47 }
48}
49
50/// A ContextProvider that doesn't provide any task variables on it's own, though it has some associated tasks.
51pub struct ContextProviderWithTasks {
52 definitions: TaskDefinitions,
53}
54
55impl ContextProviderWithTasks {
56 pub fn new(definitions: TaskDefinitions) -> Self {
57 Self { definitions }
58 }
59}
60
61impl ContextProvider for ContextProviderWithTasks {
62 fn associated_tasks(&self) -> Option<TaskDefinitions> {
63 Some(self.definitions.clone())
64 }
65
66 fn build_context(&self, location: Location, cx: &mut AppContext) -> Result<TaskVariables> {
67 SymbolContextProvider.build_context(location, cx)
68 }
69}
70
71/// A source that pulls in the tasks from language registry.
72pub struct LanguageSource {
73 languages: Arc<LanguageRegistry>,
74}
75
76impl LanguageSource {
77 pub fn new(
78 languages: Arc<LanguageRegistry>,
79 cx: &mut AppContext,
80 ) -> Model<Box<dyn TaskSource>> {
81 cx.new_model(|_| Box::new(Self { languages }) as Box<_>)
82 }
83}
84
85impl TaskSource for LanguageSource {
86 fn as_any(&mut self) -> &mut dyn std::any::Any {
87 self
88 }
89
90 fn tasks_for_path(
91 &mut self,
92 _: Option<&std::path::Path>,
93 _: &mut gpui::ModelContext<Box<dyn TaskSource>>,
94 ) -> Vec<Arc<dyn task::Task>> {
95 self.languages
96 .to_vec()
97 .into_iter()
98 .filter_map(|language| {
99 language
100 .context_provider()?
101 .associated_tasks()
102 .map(|tasks| (tasks, language))
103 })
104 .flat_map(|(tasks, language)| {
105 let language_name = language.name();
106 let id_base = format!("buffer_source_{language_name}");
107 tasks_for(tasks, &id_base)
108 })
109 .collect()
110 }
111}