modal.rs

 1use gpui::{ModelHandle, ViewContext};
 2use settings::{Settings, WorkingDirectory};
 3use workspace::{programs::ProgramManager, Workspace};
 4
 5use crate::{
 6    terminal_container_view::{
 7        get_working_directory, DeployModal, TerminalContainer, TerminalContainerContent,
 8    },
 9    Event, Terminal,
10};
11
12pub fn deploy_modal(workspace: &mut Workspace, _: &DeployModal, cx: &mut ViewContext<Workspace>) {
13    let window = cx.window_id();
14
15    // Pull the terminal connection out of the global if it has been stored
16    let possible_terminal = ProgramManager::remove::<Terminal, _>(window, cx);
17
18    if let Some(terminal_handle) = possible_terminal {
19        workspace.toggle_modal(cx, |_, cx| {
20            // Create a view from the stored connection if the terminal modal is not already shown
21            cx.add_view(|cx| TerminalContainer::from_terminal(terminal_handle.clone(), true, cx))
22        });
23        // Toggle Modal will dismiss the terminal modal if it is currently shown, so we must
24        // store the terminal back in the global
25        ProgramManager::insert_or_replace::<Terminal, _>(window, terminal_handle, cx);
26    } else {
27        // No connection was stored, create a new terminal
28        if let Some(closed_terminal_handle) = workspace.toggle_modal(cx, |workspace, cx| {
29            // No terminal modal visible, construct a new one.
30            let wd_strategy = cx
31                .global::<Settings>()
32                .terminal_overrides
33                .working_directory
34                .clone()
35                .unwrap_or(WorkingDirectory::CurrentProjectDirectory);
36
37            let working_directory = get_working_directory(workspace, cx, wd_strategy);
38
39            let this = cx.add_view(|cx| TerminalContainer::new(working_directory, true, cx));
40
41            if let TerminalContainerContent::Connected(connected) = &this.read(cx).content {
42                let terminal_handle = connected.read(cx).handle();
43                cx.subscribe(&terminal_handle, on_event).detach();
44                // Set the global immediately if terminal construction was successful,
45                // in case the user opens the command palette
46                ProgramManager::insert_or_replace::<Terminal, _>(window, terminal_handle, cx);
47            }
48
49            this
50        }) {
51            // Terminal modal was dismissed and the terminal view is connected, store the terminal
52            if let TerminalContainerContent::Connected(connected) =
53                &closed_terminal_handle.read(cx).content
54            {
55                let terminal_handle = connected.read(cx).handle();
56                // Set the global immediately if terminal construction was successful,
57                // in case the user opens the command palette
58                ProgramManager::insert_or_replace::<Terminal, _>(window, terminal_handle, cx);
59            }
60        }
61    }
62}
63
64pub fn on_event(
65    workspace: &mut Workspace,
66    _: ModelHandle<Terminal>,
67    event: &Event,
68    cx: &mut ViewContext<Workspace>,
69) {
70    // Dismiss the modal if the terminal quit
71    if let Event::CloseTerminal = event {
72        ProgramManager::remove::<Terminal, _>(cx.window_id(), cx);
73
74        if workspace.modal::<TerminalContainer>().is_some() {
75            workspace.dismiss_modal(cx)
76        }
77    }
78}