Began program manager, made terminal modals per-window

This commit is contained in:
Mikayla Maki 2022-09-02 16:45:58 -07:00
parent d189972a0d
commit 1375c5f1a1
3 changed files with 93 additions and 71 deletions

View file

@ -1,11 +1,6 @@
use std::{
any::TypeId,
collections::{HashMap, HashSet},
};
use gpui::{AnyWeakModelHandle, Entity, ModelHandle, ViewContext, WeakModelHandle};
use gpui::{ModelHandle, ViewContext};
use settings::{Settings, WorkingDirectory};
use workspace::Workspace;
use workspace::{programs::ProgramManager, Workspace};
use crate::{
terminal_container_view::{
@ -14,73 +9,20 @@ use crate::{
Event, Terminal,
};
// TODO: Need to put this basic structure in workspace, and make 'program handles'
// based off of the 'searchable item' pattern except with models this way, the workspace's clients
// can register their models as programs.
// Programs are:
// - Kept alive by the program manager, they need to emit an event to get dropped from it
// - Can be interacted with directly, (closed, activated), etc, bypassing associated view(s)
// - Have special rendering methods that the program manager offers to fill out the status bar
// - Can emit events for the program manager which:
// - Add a jewel (notification, change, etc.)
// - Drop the program
// - ???
// - Program Manager is kept in a global, listens for window drop so it can drop all it's program handles
// - Start by making up the infrastructure, then just render the first item as the modal terminal in it's spot
// update),
struct ProgramManager {
window_to_programs: HashMap<usize, HashSet<AnyWeakModelHandle>>,
}
impl ProgramManager {
pub fn add_program<T: Entity>(&mut self, window: usize, program: WeakModelHandle<T>) {
let mut programs = if let Some(programs) = self.window_to_programs.remove(&window) {
programs
} else {
HashSet::default()
};
programs.insert(AnyWeakModelHandle::from(program));
self.window_to_programs.insert(window, programs);
}
pub fn get_programs<T: Entity>(
&self,
window: &usize,
) -> impl Iterator<Item = WeakModelHandle<T>> + '_ {
self.window_to_programs
.get(window)
.into_iter()
.flat_map(|programs| {
programs
.iter()
.filter(|program| program.model_type() != TypeId::of::<T>())
.map(|program| program.downcast().unwrap())
})
}
}
#[derive(Debug)]
struct StoredTerminal(ModelHandle<Terminal>);
pub fn deploy_modal(workspace: &mut Workspace, _: &DeployModal, cx: &mut ViewContext<Workspace>) {
// cx.window_id()
let window = cx.window_id();
// Pull the terminal connection out of the global if it has been stored
let possible_terminal =
cx.update_default_global::<Option<StoredTerminal>, _, _>(|possible_connection, _| {
possible_connection.take()
});
let possible_terminal = ProgramManager::remove::<Terminal, _>(window, cx);
if let Some(StoredTerminal(stored_terminal)) = possible_terminal {
if let Some(terminal_handle) = possible_terminal {
workspace.toggle_modal(cx, |_, cx| {
// Create a view from the stored connection if the terminal modal is not already shown
cx.add_view(|cx| TerminalContainer::from_terminal(stored_terminal.clone(), true, cx))
cx.add_view(|cx| TerminalContainer::from_terminal(terminal_handle.clone(), true, cx))
});
// Toggle Modal will dismiss the terminal modal if it is currently shown, so we must
// store the terminal back in the global
cx.set_global::<Option<StoredTerminal>>(Some(StoredTerminal(stored_terminal.clone())));
ProgramManager::insert_or_replace::<Terminal, _>(window, terminal_handle, cx);
} else {
// No connection was stored, create a new terminal
if let Some(closed_terminal_handle) = workspace.toggle_modal(cx, |workspace, cx| {
@ -101,21 +43,19 @@ pub fn deploy_modal(workspace: &mut Workspace, _: &DeployModal, cx: &mut ViewCon
cx.subscribe(&terminal_handle, on_event).detach();
// Set the global immediately if terminal construction was successful,
// in case the user opens the command palette
cx.set_global::<Option<StoredTerminal>>(Some(StoredTerminal(
terminal_handle.clone(),
)));
ProgramManager::insert_or_replace::<Terminal, _>(window, terminal_handle, cx);
}
this
}) {
// Terminal modal was dismissed. Store terminal if the terminal view is connected
// Terminal modal was dismissed and the terminal view is connected, store the terminal
if let TerminalContainerContent::Connected(connected) =
&closed_terminal_handle.read(cx).content
{
let terminal_handle = connected.read(cx).handle();
// Set the global immediately if terminal construction was successful,
// in case the user opens the command palette
cx.set_global::<Option<StoredTerminal>>(Some(StoredTerminal(terminal_handle)));
ProgramManager::insert_or_replace::<Terminal, _>(window, terminal_handle, cx);
}
}
}
@ -129,7 +69,8 @@ pub fn on_event(
) {
// Dismiss the modal if the terminal quit
if let Event::CloseTerminal = event {
cx.set_global::<Option<StoredTerminal>>(None);
ProgramManager::remove::<Terminal, _>(cx.window_id(), cx);
if workspace.modal::<TerminalContainer>().is_some() {
workspace.dismiss_modal(cx)
}