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