Skip to content

Commit 32b263a

Browse files
echobtfactorydroid
andauthored
feat(cortex-tui-capture): add comprehensive TUI screenshot generator (#222)
Add a new screenshot generator tool that creates visual snapshots of ALL possible TUI states for debugging and documentation purposes. Features: - Generate 64+ scenarios across 14 categories (views, autocomplete, modals, streaming, tools, approval, permissions, messages, errors, sidebar, questions, input, scroll, animations) - Support for mocked data to simulate all UI states - Markdown export with ASCII art captures - Auto-generated index file with links to all screenshots - Configurable output directory and terminal size - Category filtering for selective generation Usage: cargo run --bin generate_tui_screenshots cargo run --bin generate_tui_screenshots -- --output ./docs/screenshots cargo run --bin generate_tui_screenshots -- --list-categories This tool is invaluable for: - Visual regression testing - AI agent TUI understanding - Documentation generation - Debugging rendering issues Co-authored-by: Droid Agent <droid@factory.ai>
1 parent d30ef64 commit 32b263a

4 files changed

Lines changed: 2655 additions & 0 deletions

File tree

cortex-tui-capture/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ description = "TUI capture and snapshot testing framework for Cortex CLI debuggi
1010
[lib]
1111
doctest = false
1212

13+
[[bin]]
14+
name = "generate_tui_screenshots"
15+
path = "src/bin/generate_tui_screenshots.rs"
16+
1317
[dependencies]
1418
# TUI dependencies
1519
ratatui = { workspace = true }
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
//! TUI Screenshot Generator Binary
2+
//!
3+
//! Generates comprehensive screenshots of ALL possible TUI states for debugging.
4+
//!
5+
//! ## Usage
6+
//!
7+
//! ```bash
8+
//! # Generate all screenshots to ./tui-screenshots
9+
//! cargo run --bin generate_tui_screenshots
10+
//!
11+
//! # Generate to custom directory
12+
//! cargo run --bin generate_tui_screenshots -- --output ./my-screenshots
13+
//!
14+
//! # Generate only specific categories
15+
//! cargo run --bin generate_tui_screenshots -- --categories views,modals
16+
//!
17+
//! # Specify terminal size
18+
//! cargo run --bin generate_tui_screenshots -- --width 100 --height 30
19+
//! ```
20+
21+
use cortex_tui_capture::screenshot_generator::{GeneratorConfig, ScreenshotGenerator};
22+
use std::env;
23+
use std::path::PathBuf;
24+
25+
fn print_help() {
26+
println!(
27+
r#"
28+
TUI Screenshot Generator - Generate comprehensive TUI state screenshots
29+
30+
USAGE:
31+
generate_tui_screenshots [OPTIONS]
32+
33+
OPTIONS:
34+
-o, --output <DIR> Output directory (default: ./tui-screenshots)
35+
-w, --width <WIDTH> Terminal width (default: 120)
36+
-h, --height <HEIGHT> Terminal height (default: 40)
37+
-c, --categories <LIST> Comma-separated list of categories to generate
38+
--no-index Don't generate index file
39+
--list-categories List all available categories
40+
--list-scenarios List all available scenarios
41+
--help Show this help message
42+
43+
EXAMPLES:
44+
# Generate all screenshots
45+
generate_tui_screenshots
46+
47+
# Generate to specific directory
48+
generate_tui_screenshots --output ./docs/screenshots
49+
50+
# Generate only autocomplete and modal screenshots
51+
generate_tui_screenshots --categories autocomplete,modals
52+
53+
# List available categories
54+
generate_tui_screenshots --list-categories
55+
"#
56+
);
57+
}
58+
59+
fn parse_args() -> Result<GeneratorConfig, String> {
60+
let args: Vec<String> = env::args().collect();
61+
let mut config = GeneratorConfig::default();
62+
63+
let mut i = 1;
64+
while i < args.len() {
65+
match args[i].as_str() {
66+
"--help" => {
67+
print_help();
68+
std::process::exit(0);
69+
}
70+
"--list-categories" => {
71+
let generator = ScreenshotGenerator::new();
72+
println!("Available categories:");
73+
for cat in generator.categories() {
74+
let count = generator.scenarios_by_category(&cat).len();
75+
println!(" {} ({} scenarios)", cat, count);
76+
}
77+
std::process::exit(0);
78+
}
79+
"--list-scenarios" => {
80+
let generator = ScreenshotGenerator::new();
81+
println!("Available scenarios:\n");
82+
for cat in generator.categories() {
83+
println!("== {} ==", cat.to_uppercase());
84+
for scenario in generator.scenarios_by_category(&cat) {
85+
println!(" {} - {}", scenario.id, scenario.description);
86+
}
87+
println!();
88+
}
89+
std::process::exit(0);
90+
}
91+
"-o" | "--output" => {
92+
i += 1;
93+
if i >= args.len() {
94+
return Err("Missing value for --output".to_string());
95+
}
96+
config.output_dir = PathBuf::from(&args[i]);
97+
}
98+
"-w" | "--width" => {
99+
i += 1;
100+
if i >= args.len() {
101+
return Err("Missing value for --width".to_string());
102+
}
103+
config.width = args[i]
104+
.parse()
105+
.map_err(|_| "Invalid width value".to_string())?;
106+
}
107+
"-h" | "--height" => {
108+
i += 1;
109+
if i >= args.len() {
110+
return Err("Missing value for --height".to_string());
111+
}
112+
config.height = args[i]
113+
.parse()
114+
.map_err(|_| "Invalid height value".to_string())?;
115+
}
116+
"-c" | "--categories" => {
117+
i += 1;
118+
if i >= args.len() {
119+
return Err("Missing value for --categories".to_string());
120+
}
121+
config.categories = args[i].split(',').map(|s| s.trim().to_string()).collect();
122+
}
123+
"--no-index" => {
124+
config.generate_index = false;
125+
}
126+
arg => {
127+
return Err(format!("Unknown argument: {}", arg));
128+
}
129+
}
130+
i += 1;
131+
}
132+
133+
Ok(config)
134+
}
135+
136+
#[tokio::main]
137+
async fn main() {
138+
// Parse command line arguments
139+
let config = match parse_args() {
140+
Ok(c) => c,
141+
Err(e) => {
142+
eprintln!("Error: {}", e);
143+
eprintln!("\nRun with --help for usage information.");
144+
std::process::exit(1);
145+
}
146+
};
147+
148+
println!("╭─────────────────────────────────────────────────────────────╮");
149+
println!("│ TUI Screenshot Generator │");
150+
println!("╰─────────────────────────────────────────────────────────────╯");
151+
println!();
152+
println!("Configuration:");
153+
println!(" Output: {:?}", config.output_dir);
154+
println!(" Size: {}x{}", config.width, config.height);
155+
if !config.categories.is_empty() {
156+
println!(" Categories: {}", config.categories.join(", "));
157+
} else {
158+
println!(" Categories: all");
159+
}
160+
println!();
161+
162+
// Create generator
163+
let generator = ScreenshotGenerator::with_config(config);
164+
165+
println!(
166+
"Registered {} scenarios across {} categories",
167+
generator.scenarios().len(),
168+
generator.categories().len()
169+
);
170+
println!();
171+
println!("Generating screenshots...");
172+
println!();
173+
174+
// Generate all screenshots
175+
match generator.generate_all().await {
176+
Ok(result) => {
177+
println!();
178+
println!("╭─────────────────────────────────────────────────────────────╮");
179+
println!("│ Generation Complete! │");
180+
println!("╰─────────────────────────────────────────────────────────────╯");
181+
println!();
182+
println!(" ✓ Generated {} screenshots", result.success);
183+
184+
if !result.failed.is_empty() {
185+
println!(" ✗ Failed: {}", result.failed.len());
186+
for (id, error) in &result.failed {
187+
println!(" - {}: {}", id, error);
188+
}
189+
}
190+
191+
println!();
192+
println!(" Output directory: {:?}", result.output_dir);
193+
println!();
194+
println!("Categories generated:");
195+
196+
// Count files per category
197+
let mut cat_counts: std::collections::HashMap<String, usize> =
198+
std::collections::HashMap::new();
199+
for path in &result.files {
200+
if let Some(parent) = path.parent() {
201+
if let Some(cat_name) = parent.file_name() {
202+
*cat_counts
203+
.entry(cat_name.to_string_lossy().to_string())
204+
.or_insert(0) += 1;
205+
}
206+
}
207+
}
208+
209+
for (cat, count) in &cat_counts {
210+
println!(" - {}: {} files", cat, count);
211+
}
212+
213+
println!();
214+
println!(
215+
"View the index at: {:?}",
216+
result.output_dir.join("README.md")
217+
);
218+
}
219+
Err(e) => {
220+
eprintln!("Error generating screenshots: {:?}", e);
221+
std::process::exit(1);
222+
}
223+
}
224+
}

cortex-tui-capture/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ mod exporter;
8585
pub mod integration;
8686
mod mock_terminal;
8787
mod recorder;
88+
pub mod screenshot_generator;
8889
mod types;
8990

9091
pub use capture::{BufferSnapshot, FrameCapture, SnapshotCell};
@@ -93,6 +94,10 @@ pub use exporter::{MarkdownExporter, ReportSection};
9394
pub use integration::{CaptureManager, ExportResult, QuickCapture};
9495
pub use mock_terminal::{MockBackend, MockTerminal};
9596
pub use recorder::{SessionRecorder, SessionReport, SessionStats};
97+
pub use screenshot_generator::{
98+
GeneratorConfig, GeneratorResult, ScreenshotGenerator, ScreenshotScenario,
99+
generate_all_screenshots, generate_screenshots_to,
100+
};
96101
pub use types::{ActionType, CaptureError, CaptureResult, CapturedFrame, TuiAction, TuiEvent};
97102

98103
/// Cortex TUI Capture version

0 commit comments

Comments
 (0)