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