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 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}