1//! Project-wide storage of the runnables available, capable of updating itself from the sources set.
2
3use std::{path::Path, sync::Arc};
4
5use gpui::{AppContext, Context, Model, ModelContext, Subscription};
6use runnable::{Runnable, RunnableId, Source};
7
8/// Inventory tracks available runnables for a given project.
9pub struct Inventory {
10 sources: Vec<SourceInInventory>,
11 pub last_scheduled_runnable: Option<RunnableId>,
12}
13
14struct SourceInInventory {
15 source: Model<Box<dyn Source>>,
16 _subscription: Subscription,
17}
18
19impl Inventory {
20 pub(crate) fn new(cx: &mut AppContext) -> Model<Self> {
21 cx.new_model(|_| Self {
22 sources: Vec::new(),
23 last_scheduled_runnable: None,
24 })
25 }
26
27 /// Registers a new runnables source, that would be fetched for available runnables.
28 pub fn add_source(&mut self, source: Model<Box<dyn Source>>, cx: &mut ModelContext<Self>) {
29 let _subscription = cx.observe(&source, |_, _, cx| {
30 cx.notify();
31 });
32 let source = SourceInInventory {
33 source,
34 _subscription,
35 };
36 self.sources.push(source);
37 cx.notify();
38 }
39
40 /// Pulls its sources to list runanbles for the path given (up to the source to decide what to return for no path).
41 pub fn list_runnables(
42 &self,
43 path: Option<&Path>,
44 cx: &mut AppContext,
45 ) -> Vec<Arc<dyn Runnable>> {
46 let mut runnables = Vec::new();
47 for source in &self.sources {
48 runnables.extend(
49 source
50 .source
51 .update(cx, |source, cx| source.runnables_for_path(path, cx)),
52 );
53 }
54 runnables
55 }
56
57 /// Returns the last scheduled runnable, if any of the sources contains one with the matching id.
58 pub fn last_scheduled_runnable(&self, cx: &mut AppContext) -> Option<Arc<dyn Runnable>> {
59 self.last_scheduled_runnable.as_ref().and_then(|id| {
60 // TODO straighten the `Path` story to understand what has to be passed here: or it will break in the future.
61 self.list_runnables(None, cx)
62 .into_iter()
63 .find(|runnable| runnable.id() == id)
64 })
65 }
66}