task_context.rs

  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}