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.write_to_pty(command);
44 connection.write_to_pty("\r".to_string());
45 });
46
47 self.connection
48 .condition(self.cx, |conn, cx| {
49 let content = Self::grid_as_str(conn);
50 f(content, cx)
51 })
52 .await;
53
54 self.cx
55 .read_model_with(&self.connection, &mut |conn, _: &AppContext| {
56 Self::grid_as_str(conn)
57 })
58 }
59
60 fn grid_as_str(connection: &TerminalConnection) -> String {
61 let term = connection.term.lock();
62 let grid_iterator = term.renderable_content().display_iter;
63 let lines = grid_iterator.group_by(|i| i.point.line.0);
64 lines
65 .into_iter()
66 .map(|(_, line)| line.map(|i| i.c).collect::<String>())
67 .collect::<Vec<String>>()
68 .join("\n")
69 }
70}
71
72impl<'a> Drop for TerminalTestContext<'a> {
73 fn drop(&mut self) {
74 self.cx.set_condition_duration(None);
75 }
76}