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.cx.add_window(|cx| {
32 Workspace::new(
33 Default::default(),
34 project.clone(),
35 |_, _| unimplemented!(),
36 cx,
37 )
38 });
39
40 (project, workspace)
41 }
42
43 ///Creates a worktree with 1 folder: /root{suffix}/
44 pub async fn create_folder_wt(
45 &mut self,
46 project: ModelHandle<Project>,
47 path: impl AsRef<Path>,
48 ) -> (ModelHandle<Worktree>, Entry) {
49 self.create_wt(project, true, path).await
50 }
51
52 ///Creates a worktree with 1 file: /root{suffix}.txt
53 pub async fn create_file_wt(
54 &mut self,
55 project: ModelHandle<Project>,
56 path: impl AsRef<Path>,
57 ) -> (ModelHandle<Worktree>, Entry) {
58 self.create_wt(project, false, path).await
59 }
60
61 async fn create_wt(
62 &mut self,
63 project: ModelHandle<Project>,
64 is_dir: bool,
65 path: impl AsRef<Path>,
66 ) -> (ModelHandle<Worktree>, Entry) {
67 let (wt, _) = project
68 .update(self.cx, |project, cx| {
69 project.find_or_create_local_worktree(path, true, cx)
70 })
71 .await
72 .unwrap();
73
74 let entry = self
75 .cx
76 .update(|cx| {
77 wt.update(cx, |wt, cx| {
78 wt.as_local()
79 .unwrap()
80 .create_entry(Path::new(""), is_dir, cx)
81 })
82 })
83 .await
84 .unwrap();
85
86 (wt, entry)
87 }
88
89 pub fn insert_active_entry_for(
90 &mut self,
91 wt: ModelHandle<Worktree>,
92 entry: Entry,
93 project: ModelHandle<Project>,
94 ) {
95 self.cx.update(|cx| {
96 let p = ProjectPath {
97 worktree_id: wt.read(cx).id(),
98 path: entry.path,
99 };
100 project.update(cx, |project, cx| project.set_active_path(Some(p), cx));
101 });
102 }
103
104 pub fn create_terminal_content(
105 size: TerminalSize,
106 rng: &mut ThreadRng,
107 ) -> (TerminalContent, Vec<Vec<char>>) {
108 let mut ic = Vec::new();
109 let mut cells = Vec::new();
110
111 for row in 0..((size.height() / size.line_height()) as usize) {
112 let mut row_vec = Vec::new();
113 for col in 0..((size.width() / size.cell_width()) as usize) {
114 let cell_char = rng.gen();
115 ic.push(IndexedCell {
116 point: Point::new(Line(row as i32), Column(col)),
117 cell: Cell {
118 c: cell_char,
119 ..Default::default()
120 },
121 });
122 row_vec.push(cell_char)
123 }
124 cells.push(row_vec)
125 }
126
127 (
128 TerminalContent {
129 cells: ic,
130 size,
131 ..Default::default()
132 },
133 cells,
134 )
135 }
136}
137
138impl<'a> Drop for TerminalTestContext<'a> {
139 fn drop(&mut self) {
140 self.cx.set_condition_duration(None);
141 }
142}