1use std::{path::Path, time::Duration};
2
3use alacritty_terminal::{
4 index::{Column, Line, Point},
5 term::cell::Cell,
6};
7use gpui::{ModelHandle, TestAppContext, ViewHandle};
8
9use project::{Entry, Project, ProjectPath, Worktree};
10use rand::{rngs::ThreadRng, Rng};
11use workspace::{AppState, Workspace};
12
13use crate::{IndexedCell, TerminalContent, TerminalSize};
14
15pub struct TerminalTestContext<'a> {
16 pub cx: &'a mut TestAppContext,
17}
18
19impl<'a> TerminalTestContext<'a> {
20 pub fn new(cx: &'a mut TestAppContext) -> Self {
21 cx.set_condition_duration(Some(Duration::from_secs(5)));
22
23 TerminalTestContext { cx }
24 }
25
26 ///Creates a worktree with 1 file: /root.txt
27 pub async fn blank_workspace(&mut self) -> (ModelHandle<Project>, ViewHandle<Workspace>) {
28 let params = self.cx.update(AppState::test);
29
30 let project = Project::test(params.fs.clone(), [], self.cx).await;
31 let (_, workspace) = self
32 .cx
33 .add_window(|cx| Workspace::new(project.clone(), |_, _| unimplemented!(), cx));
34
35 (project, workspace)
36 }
37
38 ///Creates a worktree with 1 folder: /root{suffix}/
39 pub async fn create_folder_wt(
40 &mut self,
41 project: ModelHandle<Project>,
42 path: impl AsRef<Path>,
43 ) -> (ModelHandle<Worktree>, Entry) {
44 self.create_wt(project, true, path).await
45 }
46
47 ///Creates a worktree with 1 file: /root{suffix}.txt
48 pub async fn create_file_wt(
49 &mut self,
50 project: ModelHandle<Project>,
51 path: impl AsRef<Path>,
52 ) -> (ModelHandle<Worktree>, Entry) {
53 self.create_wt(project, false, path).await
54 }
55
56 async fn create_wt(
57 &mut self,
58 project: ModelHandle<Project>,
59 is_dir: bool,
60 path: impl AsRef<Path>,
61 ) -> (ModelHandle<Worktree>, Entry) {
62 let (wt, _) = project
63 .update(self.cx, |project, cx| {
64 project.find_or_create_local_worktree(path, true, cx)
65 })
66 .await
67 .unwrap();
68
69 let entry = self
70 .cx
71 .update(|cx| {
72 wt.update(cx, |wt, cx| {
73 wt.as_local()
74 .unwrap()
75 .create_entry(Path::new(""), is_dir, cx)
76 })
77 })
78 .await
79 .unwrap();
80
81 (wt, entry)
82 }
83
84 pub fn insert_active_entry_for(
85 &mut self,
86 wt: ModelHandle<Worktree>,
87 entry: Entry,
88 project: ModelHandle<Project>,
89 ) {
90 self.cx.update(|cx| {
91 let p = ProjectPath {
92 worktree_id: wt.read(cx).id(),
93 path: entry.path,
94 };
95 project.update(cx, |project, cx| project.set_active_path(Some(p), cx));
96 });
97 }
98
99 pub fn create_terminal_content(
100 size: TerminalSize,
101 rng: &mut ThreadRng,
102 ) -> (TerminalContent, Vec<Vec<char>>) {
103 let mut ic = Vec::new();
104 let mut cells = Vec::new();
105
106 for row in 0..((size.height() / size.line_height()) as usize) {
107 let mut row_vec = Vec::new();
108 for col in 0..((size.width() / size.cell_width()) as usize) {
109 let cell_char = rng.gen();
110 ic.push(IndexedCell {
111 point: Point::new(Line(row as i32), Column(col)),
112 cell: Cell {
113 c: cell_char,
114 ..Default::default()
115 },
116 });
117 row_vec.push(cell_char)
118 }
119 cells.push(row_vec)
120 }
121
122 (
123 TerminalContent {
124 cells: ic,
125 size,
126 ..Default::default()
127 },
128 cells,
129 )
130 }
131}
132
133impl<'a> Drop for TerminalTestContext<'a> {
134 fn drop(&mut self) {
135 self.cx.set_condition_duration(None);
136 }
137}