theater_cli/output/
formatters.rs1use crate::error::CliResult;
2use crate::output::{OutputFormat, OutputManager};
3
4#[derive(Debug, serde::Serialize)]
6pub struct BuildResult {
7 pub success: bool,
8 pub project_dir: std::path::PathBuf,
9 pub wasm_path: Option<std::path::PathBuf>,
10 pub manifest_exists: bool,
11 pub manifest_path: Option<std::path::PathBuf>,
12 pub build_type: String,
13 pub package_name: String,
14 pub stdout: String,
15 pub stderr: String,
16}
17
18impl OutputFormat for BuildResult {
19 fn format_compact(&self, output: &OutputManager) -> CliResult<()> {
20 if self.success {
21 output.success("Build completed successfully")?;
22 if let Some(wasm_path) = &self.wasm_path {
23 println!(
24 " Package: {}",
25 output.theme().accent().apply_to(wasm_path.display())
26 );
27 }
28 } else {
29 output.error("Build failed")?;
30 if !self.stderr.is_empty() {
31 println!("{}", output.theme().muted().apply_to(&self.stderr));
32 }
33 }
34 Ok(())
35 }
36
37 fn format_pretty(&self, output: &OutputManager) -> CliResult<()> {
38 if self.success {
39 println!(
40 "{} {}",
41 output.theme().success_icon(),
42 output.theme().highlight().apply_to("Build Successful")
43 );
44 println!();
45 println!(
46 "Package: {}",
47 output.theme().accent().apply_to(&self.package_name)
48 );
49 println!(
50 "Build Type: {}",
51 output.theme().muted().apply_to(&self.build_type)
52 );
53
54 if let Some(wasm_path) = &self.wasm_path {
55 println!(
56 "WASM: {}",
57 output.theme().accent().apply_to(wasm_path.display())
58 );
59 }
60
61 if self.manifest_exists {
62 if let Some(manifest_path) = &self.manifest_path {
63 println!("\nTo run your actor:");
64 println!(
65 " theater spawn {}",
66 output.theme().muted().apply_to(manifest_path.display())
67 );
68 }
69 } else {
70 println!(
71 "\n{} No manifest.toml found.",
72 output.theme().warning_icon()
73 );
74 }
75
76 if !self.stdout.is_empty() {
77 println!("\nBuild Output:");
78 println!("{}", output.theme().muted().apply_to(&self.stdout));
79 }
80 } else {
81 println!(
82 "{} {}",
83 output.theme().error_icon(),
84 output.theme().error().apply_to("Build Failed")
85 );
86
87 if !self.stderr.is_empty() {
88 println!("\nError Output:");
89 println!("{}", self.stderr);
90 }
91 if !self.stdout.is_empty() {
92 println!("\nBuild Output:");
93 println!("{}", self.stdout);
94 }
95 }
96 Ok(())
97 }
98
99 fn format_table(&self, output: &OutputManager) -> CliResult<()> {
100 let headers = vec!["Property", "Value"];
101 let mut rows = vec![vec![
102 "Status".to_string(),
103 if self.success {
104 "Success".to_string()
105 } else {
106 "Failed".to_string()
107 },
108 ]];
109
110 rows.push(vec!["Package".to_string(), self.package_name.clone()]);
111 rows.push(vec!["Build Type".to_string(), self.build_type.clone()]);
112 rows.push(vec![
113 "Project Dir".to_string(),
114 self.project_dir.display().to_string(),
115 ]);
116
117 if let Some(wasm_path) = &self.wasm_path {
118 rows.push(vec!["WASM".to_string(), wasm_path.display().to_string()]);
119 }
120
121 rows.push(vec![
122 "Manifest Exists".to_string(),
123 self.manifest_exists.to_string(),
124 ]);
125
126 if let Some(manifest_path) = &self.manifest_path {
127 rows.push(vec![
128 "Manifest Path".to_string(),
129 manifest_path.display().to_string(),
130 ]);
131 }
132
133 output.table(&headers, &rows)?;
134 Ok(())
135 }
136
137 fn format_detailed(&self, _output: &OutputManager) -> CliResult<()> {
138 todo!()
139 }
140}
141
142#[derive(Debug, serde::Serialize)]
144pub struct ProjectCreated {
145 pub name: String,
146 pub template: String,
147 pub path: std::path::PathBuf,
148 pub build_instructions: Vec<String>,
149}
150
151impl OutputFormat for ProjectCreated {
152 fn format_compact(&self, output: &OutputManager) -> CliResult<()> {
153 println!(
154 "{} Created project: {}",
155 output.theme().success().apply_to("✓"),
156 output.theme().accent().apply_to(&self.name)
157 );
158 println!(
159 "Path: {}",
160 output.theme().muted().apply_to(self.path.display())
161 );
162 Ok(())
163 }
164
165 fn format_pretty(&self, output: &OutputManager) -> CliResult<()> {
166 println!(
167 "{} {}",
168 output.theme().success().apply_to("✓"),
169 output
170 .theme()
171 .highlight()
172 .apply_to(&format!("Created new actor project: {}", self.name))
173 );
174 println!();
175 println!(
176 "Template: {}",
177 output.theme().accent().apply_to(&self.template)
178 );
179 println!(
180 "Location: {}",
181 output.theme().muted().apply_to(self.path.display())
182 );
183 println!();
184 println!("{}", output.theme().highlight().apply_to("Next steps:"));
185 for (i, instruction) in self.build_instructions.iter().enumerate() {
186 println!(
187 " {}. {}",
188 i + 1,
189 output.theme().muted().apply_to(instruction)
190 );
191 }
192 Ok(())
193 }
194
195 fn format_table(&self, output: &OutputManager) -> CliResult<()> {
196 let headers = vec!["Property", "Value"];
197 let rows = vec![
198 vec!["Name".to_string(), self.name.clone()],
199 vec!["Template".to_string(), self.template.clone()],
200 vec!["Path".to_string(), self.path.display().to_string()],
201 ];
202 output.table(&headers, &rows)?;
203
204 println!();
205 println!(
206 "{}",
207 output.theme().highlight().apply_to("Build Instructions:")
208 );
209 for (i, instruction) in self.build_instructions.iter().enumerate() {
210 println!(" {}. {}", i + 1, instruction);
211 }
212 Ok(())
213 }
214
215 fn format_detailed(&self, _output: &OutputManager) -> CliResult<()> {
216 todo!()
217 }
218}