programs.rs

 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}