1// TODO: Need to put this basic structure in workspace, and make 'program handles'
2// based off of the 'searchable item' pattern except with models. This way, the workspace's clients
3// can register their models as programs with a specific identity and capable of notifying the workspace
4// Programs are:
5// - Kept alive by the program manager, they need to emit an event to get dropped from it
6// - Can be interacted with directly, (closed, activated, etc.) by the program manager, bypassing
7// associated view(s)
8// - Have special rendering methods that the program manager requires them to implement to fill out
9// the status bar
10// - Can emit events for the program manager which:
11// - Add a jewel (notification, change, etc.)
12// - Drop the program
13// - ???
14// - Program Manager is kept in a global, listens for window drop so it can drop all it's program handles
15
16use collections::HashMap;
17use gpui::{AnyModelHandle, Entity, ModelHandle, View, ViewContext};
18
19/// This struct is going to be the starting point for the 'program manager' feature that will
20/// eventually be implemented to provide a collaborative way of engaging with identity-having
21/// features like the terminal.
22pub struct ProgramManager {
23 // TODO: Make this a hashset or something
24 modals: HashMap<usize, AnyModelHandle>,
25}
26
27impl ProgramManager {
28 pub fn insert_or_replace<T: Entity, V: View>(
29 window: usize,
30 program: ModelHandle<T>,
31 cx: &mut ViewContext<V>,
32 ) -> Option<AnyModelHandle> {
33 cx.update_global::<ProgramManager, _, _>(|pm, _| {
34 pm.insert_or_replace_internal::<T>(window, program)
35 })
36 }
37
38 pub fn remove<T: Entity, V: View>(
39 window: usize,
40 cx: &mut ViewContext<V>,
41 ) -> Option<ModelHandle<T>> {
42 cx.update_global::<ProgramManager, _, _>(|pm, _| pm.remove_internal::<T>(window))
43 }
44
45 pub fn new() -> Self {
46 Self {
47 modals: Default::default(),
48 }
49 }
50
51 /// Inserts or replaces the model at the given location.
52 fn insert_or_replace_internal<T: Entity>(
53 &mut self,
54 window: usize,
55 program: ModelHandle<T>,
56 ) -> Option<AnyModelHandle> {
57 self.modals.insert(window, AnyModelHandle::from(program))
58 }
59
60 /// Remove the program associated with this window, if it's of the given type
61 fn remove_internal<T: Entity>(&mut self, window: usize) -> Option<ModelHandle<T>> {
62 let program = self.modals.remove(&window);
63 if let Some(program) = program {
64 if program.is::<T>() {
65 // Guaranteed to be some, but leave it in the option
66 // anyway for the API
67 program.downcast()
68 } else {
69 // Model is of the incorrect type, put it back
70 self.modals.insert(window, program);
71 None
72 }
73 } else {
74 None
75 }
76 }
77}