1use gpui::{ModelHandle, ViewContext};
2use settings::{Settings, WorkingDirectory};
3use workspace::Workspace;
4
5use crate::{
6 get_working_directory, model::Terminal, DeployModal, Event, TerminalContent, TerminalView,
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 wd_strategy = cx
32 .global::<Settings>()
33 .terminal_overrides
34 .working_directory
35 .clone()
36 .unwrap_or(WorkingDirectory::CurrentProjectDirectory);
37
38 let working_directory = get_working_directory(workspace, cx, wd_strategy);
39
40 let this = cx.add_view(|cx| TerminalView::new(working_directory, true, cx));
41
42 if let TerminalContent::Connected(connected) = &this.read(cx).content {
43 let terminal_handle = connected.read(cx).handle();
44 cx.subscribe(&terminal_handle, on_event).detach();
45 // Set the global immediately if terminal construction was successful,
46 // in case the user opens the command palette
47 cx.set_global::<Option<StoredTerminal>>(Some(StoredTerminal(
48 terminal_handle.clone(),
49 )));
50 }
51
52 this
53 }) {
54 // Terminal modal was dismissed. Store terminal if the terminal view is connected
55 if let TerminalContent::Connected(connected) = &closed_terminal_handle.read(cx).content
56 {
57 let terminal_handle = connected.read(cx).handle();
58 // Set the global immediately if terminal construction was successful,
59 // in case the user opens the command palette
60 cx.set_global::<Option<StoredTerminal>>(Some(StoredTerminal(
61 terminal_handle.clone(),
62 )));
63 }
64 }
65 }
66}
67
68pub fn on_event(
69 workspace: &mut Workspace,
70 _: ModelHandle<Terminal>,
71 event: &Event,
72 cx: &mut ViewContext<Workspace>,
73) {
74 // Dismiss the modal if the terminal quit
75 if let Event::CloseTerminal = event {
76 cx.set_global::<Option<StoredTerminal>>(None);
77 if workspace.modal::<TerminalView>().is_some() {
78 workspace.dismiss_modal(cx)
79 }
80 }
81}