1use std::time::Duration;
2
3use alacritty_terminal::term::SizeInfo;
4use gpui::{AppContext, ModelHandle, ReadModelWith, TestAppContext};
5use itertools::Itertools;
6
7use crate::{
8 connection::TerminalConnection, DEBUG_CELL_WIDTH, DEBUG_LINE_HEIGHT, DEBUG_TERMINAL_HEIGHT,
9 DEBUG_TERMINAL_WIDTH,
10};
11
12pub struct TerminalTestContext<'a> {
13 pub cx: &'a mut TestAppContext,
14 pub connection: ModelHandle<TerminalConnection>,
15}
16
17impl<'a> TerminalTestContext<'a> {
18 pub fn new(cx: &'a mut TestAppContext) -> Self {
19 cx.set_condition_duration(Some(Duration::from_secs(5)));
20
21 let size_info = SizeInfo::new(
22 DEBUG_TERMINAL_WIDTH,
23 DEBUG_TERMINAL_HEIGHT,
24 DEBUG_CELL_WIDTH,
25 DEBUG_LINE_HEIGHT,
26 0.,
27 0.,
28 false,
29 );
30
31 let connection =
32 cx.add_model(|cx| TerminalConnection::new(None, None, None, size_info, cx));
33
34 TerminalTestContext { cx, connection }
35 }
36
37 pub async fn execute_and_wait<F>(&mut self, command: &str, f: F) -> String
38 where
39 F: Fn(String, &AppContext) -> bool,
40 {
41 let command = command.to_string();
42 self.connection.update(self.cx, |connection, _| {
43 connection.get_terminal().unwrap().write_to_pty(command);
44 connection
45 .get_terminal()
46 .unwrap()
47 .write_to_pty("\r".to_string());
48 });
49
50 self.connection
51 .condition(self.cx, |conn, cx| {
52 let content = Self::grid_as_str(conn);
53 f(content, cx)
54 })
55 .await;
56
57 self.cx
58 .read_model_with(&self.connection, &mut |conn, _: &AppContext| {
59 Self::grid_as_str(conn)
60 })
61 }
62
63 fn grid_as_str(connection: &TerminalConnection) -> String {
64 let grid = connection.get_terminal().unwrap().grid();
65 let lines = grid.display_iter().group_by(|i| i.point.line.0);
66 lines
67 .into_iter()
68 .map(|(_, line)| line.map(|i| i.c).collect::<String>())
69 .collect::<Vec<String>>()
70 .join("\n")
71 }
72}
73
74impl<'a> Drop for TerminalTestContext<'a> {
75 fn drop(&mut self) {
76 self.cx.set_condition_duration(None);
77 }
78}