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 Dock {
23 // TODO: Make this a hashset or something
24 modals: HashMap<usize, AnyModelHandle>,
25}
26
27impl Dock {
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::<Dock, _, _>(|pm, _| pm.insert_or_replace_internal::<T>(window, program))
34 }
35
36 pub fn remove<T: Entity, V: View>(
37 window: usize,
38 cx: &mut ViewContext<V>,
39 ) -> Option<ModelHandle<T>> {
40 cx.update_global::<Dock, _, _>(|pm, _| pm.remove_internal::<T>(window))
41 }
42
43 pub fn new() -> Self {
44 Self {
45 modals: Default::default(),
46 }
47 }
48
49 /// Inserts or replaces the model at the given location.
50 fn insert_or_replace_internal<T: Entity>(
51 &mut self,
52 window: usize,
53 program: ModelHandle<T>,
54 ) -> Option<AnyModelHandle> {
55 self.modals.insert(window, AnyModelHandle::from(program))
56 }
57
58 /// Remove the program associated with this window, if it's of the given type
59 fn remove_internal<T: Entity>(&mut self, window: usize) -> Option<ModelHandle<T>> {
60 let program = self.modals.remove(&window);
61 if let Some(program) = program {
62 if program.is::<T>() {
63 // Guaranteed to be some, but leave it in the option
64 // anyway for the API
65 program.downcast()
66 } else {
67 // Model is of the incorrect type, put it back
68 self.modals.insert(window, program);
69 None
70 }
71 } else {
72 None
73 }
74 }
75}