1use std::path::PathBuf;
2
3use gpui::{ModelContext, ModelHandle, WeakModelHandle};
4use settings::Settings;
5use terminal::{Terminal, TerminalBuilder};
6
7use crate::Project;
8
9pub struct Terminals {
10 pub(crate) local_handles: Vec<WeakModelHandle<terminal::Terminal>>,
11}
12
13impl Project {
14 pub fn create_terminal(
15 &mut self,
16 working_directory: Option<PathBuf>,
17 window_id: usize,
18 cx: &mut ModelContext<Self>,
19 ) -> anyhow::Result<ModelHandle<Terminal>> {
20 if self.is_remote() {
21 return Err(anyhow::anyhow!(
22 "creating terminals as a guest is not supported yet"
23 ));
24 } else {
25 let settings = cx.global::<Settings>();
26 let shell = settings.terminal_shell();
27 let envs = settings.terminal_env();
28 let scroll = settings.terminal_scroll();
29
30 let terminal = TerminalBuilder::new(
31 working_directory.clone(),
32 shell,
33 envs,
34 settings.terminal_overrides.blinking.clone(),
35 scroll,
36 window_id,
37 )
38 .map(|builder| {
39 let terminal_handle = cx.add_model(|cx| builder.subscribe(cx));
40
41 self.terminals
42 .local_handles
43 .push(terminal_handle.downgrade());
44
45 let id = terminal_handle.id();
46 cx.observe_release(&terminal_handle, move |project, _terminal, cx| {
47 let handles = &mut project.terminals.local_handles;
48
49 if let Some(index) = handles.iter().position(|terminal| terminal.id() == id) {
50 handles.remove(index);
51 cx.notify();
52 }
53 })
54 .detach();
55
56 terminal_handle
57 });
58
59 terminal
60 }
61 }
62
63 pub fn local_terminal_handles(&self) -> &Vec<WeakModelHandle<terminal::Terminal>> {
64 &self.terminals.local_handles
65 }
66}
67
68// TODO: Add a few tests for adding and removing terminal tabs