modal.rs

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