pub struct Output {
pub title: Option<String>,
pub subtitle: Option<String>,
pub blocks: Vec<Block>,
pub data: BTreeMap<String, Value>,
pub plain: Option<Value>,
pub jsonl_records: Vec<Value>,
}Expand description
Structured output container with blocks and metadata.
Build up content using builder methods (.heading(), .paragraph(), etc.), then
render with Ui::render() or Ui::print() in your preferred format.
§Examples
use scriba::{Output, StatusKind};
let output = Output::new()
.title("Report")
.heading(1, "Summary")
.paragraph("All systems operational")
.status(StatusKind::Ok, "Complete");Fields§
§title: Option<String>§subtitle: Option<String>§blocks: Vec<Block>§data: BTreeMap<String, Value>§plain: Option<Value>§jsonl_records: Vec<Value>Implementations§
Source§impl Output
impl Output
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new empty output.
Examples found in repository?
25fn main() -> scriba::Result<()> {
26 let output = Output::new()
27 .title("Pipeline")
28 .data("stage", "build")
29 .data("commit", "a3f9c12")
30 .paragraph("Build succeeded in 42s.");
31
32 let ui = Ui::new()
33 .with_format(Format::Json)
34 .with_envelope(
35 EnvelopeConfig::default()
36 .with_mode(EnvelopeMode::Json)
37 .with_layout(EnvelopeLayout::Nested),
38 );
39
40 println!("=== Nested envelope, no meta ===");
41 ui.print(&output)?;
42
43 println!("\n=== Nested envelope, with meta merged in ===");
44 let meta = Meta::default()
45 .with_dry_run(true)
46 .with_command("ci run".into())
47 .with_timestamp("2026-04-13T09:30:00Z".into())
48 .with_scope("ci".into())
49 .with_version("0.3.0".into());
50 ui.print_with_meta(&output, Some(&meta), true)?;
51
52 Ok(())
53}More examples
16fn main() -> scriba::Result<()> {
17 let output = Output::new()
18 .title("Deployment")
19 .data("environment", "production")
20 .data("version", "1.4.2")
21 .paragraph("All services healthy.");
22
23 let ui = Ui::new()
24 .with_format(Format::Json)
25 .with_envelope(
26 EnvelopeConfig::default()
27 .with_mode(EnvelopeMode::Json)
28 .with_layout(EnvelopeLayout::Flat),
29 );
30
31 println!("=== Flat envelope, no meta ===");
32 ui.print(&output)?;
33
34 println!("\n=== Flat envelope, with meta ===");
35 let meta = Meta::default()
36 .with_dry_run(false)
37 .with_command("deploy".into())
38 .with_duration_ms(312)
39 .with_timestamp("2026-04-13T15:00:00Z".into());
40 ui.print_with_meta(&output, Some(&meta), true)?;
41
42 println!("\n=== Flat envelope, ok: false (error case) ===");
43 let error_output = Output::new()
44 .title("Deployment")
45 .paragraph("Health check failed on eu-west-1.");
46 ui.print_with_meta(&error_output, None, false)?;
47
48 Ok(())
49}17fn main() -> scriba::Result<()> {
18 let output = Output::new()
19 .title("Release")
20 .data("tag", "v0.3.0")
21 .paragraph("Release pipeline completed.");
22
23 let meta = Meta::default()
24 .with_dry_run(false)
25 .with_command("release publish".into())
26 .with_duration_ms(4821)
27 .with_timestamp("2026-04-13T18:00:00Z".into())
28 .with_scope("production".into())
29 .with_version("0.3.0".into())
30 // Arbitrary extra fields — any serialisable value
31 .with_extra("region", "eu-west-1")
32 .with_extra("actor", "github-actions")
33 .with_extra("run_id", 9_981_234_u64);
34
35 println!("=== Full meta — flat layout ===");
36 let flat_ui = Ui::new()
37 .with_format(Format::Json)
38 .with_envelope(
39 EnvelopeConfig::default()
40 .with_mode(EnvelopeMode::Json)
41 .with_layout(EnvelopeLayout::Flat),
42 );
43 flat_ui.print_with_meta(&output, Some(&meta), true)?;
44
45 println!("\n=== Full meta — nested layout (all fields merged under meta) ===");
46 let nested_ui = Ui::new()
47 .with_format(Format::Json)
48 .with_envelope(
49 EnvelopeConfig::default()
50 .with_mode(EnvelopeMode::Json)
51 .with_layout(EnvelopeLayout::Nested),
52 );
53 nested_ui.print_with_meta(&output, Some(&meta), true)?;
54
55 println!("\n=== Meta with non-JSON output format (text rendered inside envelope) ===");
56 let text_ui = Ui::new()
57 .with_format(Format::Text)
58 .with_envelope(
59 EnvelopeConfig::default()
60 .with_mode(EnvelopeMode::Json)
61 .with_layout(EnvelopeLayout::Flat),
62 );
63 text_ui.print_with_meta(&output, Some(&meta), true)?;
64
65 Ok(())
66}13fn main() -> scriba::Result<()> {
14 // Example unified diff content
15 let patch = r#"--- a/src/main.rs
16+++ b/src/main.rs
17@@ -1,5 +1,6 @@
18 fn main() {
19- println!("Hello, world!");
20+ println!("Hello, Scriba!");
21+ println!("Diff viewer is great!");
22
23 let x = 42;
24- println!("x = {}", x);
25+ println!("x = {}", x * 2);
26"#;
27
28 println!("=== TEXT FORMAT (default) ===\n");
29 let ui_text = Ui::new().with_format(Format::Text);
30 ui_text.show_diff("src/main.rs", patch)?;
31
32 println!("\n=== MARKDOWN FORMAT ===\n");
33 let ui_markdown = Ui::new().with_format(Format::Markdown);
34 ui_markdown.show_diff("src/main.rs", patch)?;
35
36 println!("\n=== COLORED DIFF (for terminal output) ===\n");
37 let ui_colored = Ui::new().with_format(Format::Text);
38 ui_colored.show_diff_colored("src/main.rs", patch, true)?;
39
40 println!("\n=== JSON FORMAT ===\n");
41 let ui_json = Ui::new().with_format(Format::Json);
42 ui_json.show_diff("src/main.rs", patch)?;
43
44 // Example: Working with parsed diff lines
45 println!("\n=== PARSED DIFF LINES ===\n");
46 let diff_lines = scriba::parse_diff(patch);
47 let mut output = Output::new()
48 .title("Parsed Diff Analysis")
49 .subtitle("Breaking down the diff into structured lines");
50
51 let mut stats = String::new();
52 stats.push_str(&format!(
53 "Total lines: {}\n",
54 diff_lines.len()
55 ));
56
57 let added = diff_lines
58 .iter()
59 .filter(|l| l.kind == scriba::DiffLineKind::Added)
60 .count();
61 let removed = diff_lines
62 .iter()
63 .filter(|l| l.kind == scriba::DiffLineKind::Removed)
64 .count();
65 let context = diff_lines
66 .iter()
67 .filter(|l| l.kind == scriba::DiffLineKind::Context)
68 .count();
69
70 stats.push_str(&format!("Added: {}\n", added));
71 stats.push_str(&format!("Removed: {}\n", removed));
72 stats.push_str(&format!("Context: {}", context));
73
74 output = output.section("Statistics", stats, "text".to_string());
75
76 let ui_stats = Ui::new().with_format(Format::Markdown);
77 ui_stats.print(&output)?;
78
79 Ok(())
80}17fn main() -> scriba::Result<()> {
18 let output = Output::new()
19 .title("Users")
20 .data("count", 42u64)
21 .paragraph("Query executed successfully.");
22
23 // --- Custom flat field names ---
24 let flat_ui = Ui::new()
25 .with_format(Format::Json)
26 .with_envelope(
27 EnvelopeConfig::default()
28 .with_mode(EnvelopeMode::Json)
29 .with_layout(EnvelopeLayout::Flat)
30 .with_fields(EnvelopeFields {
31 ok_field: "success".into(),
32 format_field: "type".into(),
33 content_field: "result".into(),
34 meta_field: "context".into(),
35 }),
36 );
37
38 println!("=== Custom field names, flat ===");
39 println!(r#" fields: success / type / result / context"#);
40 flat_ui.print(&output)?;
41
42 // --- Custom nested field names ---
43 let nested_ui = Ui::new()
44 .with_format(Format::Json)
45 .with_envelope(
46 EnvelopeConfig::default()
47 .with_mode(EnvelopeMode::Json)
48 .with_layout(EnvelopeLayout::Nested)
49 .with_fields(EnvelopeFields {
50 ok_field: "success".into(),
51 format_field: "type".into(),
52 content_field: "data".into(),
53 meta_field: "header".into(),
54 }),
55 );
56
57 let meta = Meta::default()
58 .with_command("users list".into())
59 .with_extra("region", "eu-west-1");
60
61 println!("\n=== Custom field names, nested ===");
62 println!(r#" fields: success / type / data / header"#);
63 nested_ui.print_with_meta(&output, Some(&meta), true)?;
64
65 // --- Omit ok and format fields entirely ---
66 let minimal_ui = Ui::new()
67 .with_format(Format::Json)
68 .with_envelope(
69 EnvelopeConfig::default()
70 .with_mode(EnvelopeMode::Json)
71 .with_show_ok(false)
72 .with_show_format(false),
73 );
74
75 println!("\n=== Envelope without ok or format fields ===");
76 minimal_ui.print(&output)?;
77
78 Ok(())
79}13fn main() -> scriba::Result<()> {
14 // Text format — ANSI escape codes applied
15 println!("=== TEXT FORMAT (ANSI codes) ===\n");
16
17 let ui_text = Ui::new().with_format(Format::Text);
18
19 let output_text = Output::new()
20 .heading(1, "Text Styling Examples")
21 .styled_paragraph(Styled::new("This is bold text", TextStyle::Bold))
22 .styled_paragraph(Styled::new("This is italic text", TextStyle::Italic))
23 .styled_paragraph(Styled::new("This is bold and italic", TextStyle::BoldItalic))
24 .styled_paragraph(Styled::new("This is underlined", TextStyle::Underline))
25 .styled_paragraph(Styled::new("This is strikethrough", TextStyle::Strikethrough))
26 .styled_paragraph(Styled::new("This is dimmed/faded", TextStyle::Dim));
27
28 ui_text.print(&output_text)?;
29
30 // Markdown format — Markdown syntax applied
31 println!("\n=== MARKDOWN FORMAT ===\n");
32
33 let ui_md = Ui::new().with_format(Format::Markdown);
34
35 let output_md = Output::new()
36 .heading(1, "Text Styling in Markdown")
37 .styled_paragraph(Styled::new("This is bold", TextStyle::Bold))
38 .styled_paragraph(Styled::new("This is italic", TextStyle::Italic))
39 .styled_paragraph(Styled::new("This is bold italic", TextStyle::BoldItalic))
40 .styled_paragraph(Styled::new("This has strikethrough", TextStyle::Strikethrough))
41 .styled_paragraph(Styled::new("This is underlined", TextStyle::Underline));
42
43 ui_md.print(&output_md)?;
44
45 // Direct use of Styled API
46 println!("\n=== DIRECT API ===\n");
47
48 let bold_styled = Styled::new("Warning: check your config", TextStyle::Bold);
49 let italic_styled = Styled::new("Optional: skip if unneeded", TextStyle::Italic);
50 let dim_styled = Styled::new("Hint: use --verbose for more detail", TextStyle::Dim);
51
52 println!("ANSI:");
53 println!(" {}", bold_styled.render_ansi());
54 println!(" {}", italic_styled.render_ansi());
55 println!(" {}", dim_styled.render_ansi());
56
57 println!("\nMarkdown:");
58 println!(" {}", bold_styled.render_markdown());
59 println!(" {}", italic_styled.render_markdown());
60 println!(" {}", dim_styled.render_markdown());
61
62 Ok(())
63}Sourcepub fn title(self, value: impl Into<String>) -> Self
pub fn title(self, value: impl Into<String>) -> Self
Set the title (rendered as # in Markdown, underlined in Text).
Examples found in repository?
25fn main() -> scriba::Result<()> {
26 let output = Output::new()
27 .title("Pipeline")
28 .data("stage", "build")
29 .data("commit", "a3f9c12")
30 .paragraph("Build succeeded in 42s.");
31
32 let ui = Ui::new()
33 .with_format(Format::Json)
34 .with_envelope(
35 EnvelopeConfig::default()
36 .with_mode(EnvelopeMode::Json)
37 .with_layout(EnvelopeLayout::Nested),
38 );
39
40 println!("=== Nested envelope, no meta ===");
41 ui.print(&output)?;
42
43 println!("\n=== Nested envelope, with meta merged in ===");
44 let meta = Meta::default()
45 .with_dry_run(true)
46 .with_command("ci run".into())
47 .with_timestamp("2026-04-13T09:30:00Z".into())
48 .with_scope("ci".into())
49 .with_version("0.3.0".into());
50 ui.print_with_meta(&output, Some(&meta), true)?;
51
52 Ok(())
53}More examples
16fn main() -> scriba::Result<()> {
17 let output = Output::new()
18 .title("Deployment")
19 .data("environment", "production")
20 .data("version", "1.4.2")
21 .paragraph("All services healthy.");
22
23 let ui = Ui::new()
24 .with_format(Format::Json)
25 .with_envelope(
26 EnvelopeConfig::default()
27 .with_mode(EnvelopeMode::Json)
28 .with_layout(EnvelopeLayout::Flat),
29 );
30
31 println!("=== Flat envelope, no meta ===");
32 ui.print(&output)?;
33
34 println!("\n=== Flat envelope, with meta ===");
35 let meta = Meta::default()
36 .with_dry_run(false)
37 .with_command("deploy".into())
38 .with_duration_ms(312)
39 .with_timestamp("2026-04-13T15:00:00Z".into());
40 ui.print_with_meta(&output, Some(&meta), true)?;
41
42 println!("\n=== Flat envelope, ok: false (error case) ===");
43 let error_output = Output::new()
44 .title("Deployment")
45 .paragraph("Health check failed on eu-west-1.");
46 ui.print_with_meta(&error_output, None, false)?;
47
48 Ok(())
49}17fn main() -> scriba::Result<()> {
18 let output = Output::new()
19 .title("Release")
20 .data("tag", "v0.3.0")
21 .paragraph("Release pipeline completed.");
22
23 let meta = Meta::default()
24 .with_dry_run(false)
25 .with_command("release publish".into())
26 .with_duration_ms(4821)
27 .with_timestamp("2026-04-13T18:00:00Z".into())
28 .with_scope("production".into())
29 .with_version("0.3.0".into())
30 // Arbitrary extra fields — any serialisable value
31 .with_extra("region", "eu-west-1")
32 .with_extra("actor", "github-actions")
33 .with_extra("run_id", 9_981_234_u64);
34
35 println!("=== Full meta — flat layout ===");
36 let flat_ui = Ui::new()
37 .with_format(Format::Json)
38 .with_envelope(
39 EnvelopeConfig::default()
40 .with_mode(EnvelopeMode::Json)
41 .with_layout(EnvelopeLayout::Flat),
42 );
43 flat_ui.print_with_meta(&output, Some(&meta), true)?;
44
45 println!("\n=== Full meta — nested layout (all fields merged under meta) ===");
46 let nested_ui = Ui::new()
47 .with_format(Format::Json)
48 .with_envelope(
49 EnvelopeConfig::default()
50 .with_mode(EnvelopeMode::Json)
51 .with_layout(EnvelopeLayout::Nested),
52 );
53 nested_ui.print_with_meta(&output, Some(&meta), true)?;
54
55 println!("\n=== Meta with non-JSON output format (text rendered inside envelope) ===");
56 let text_ui = Ui::new()
57 .with_format(Format::Text)
58 .with_envelope(
59 EnvelopeConfig::default()
60 .with_mode(EnvelopeMode::Json)
61 .with_layout(EnvelopeLayout::Flat),
62 );
63 text_ui.print_with_meta(&output, Some(&meta), true)?;
64
65 Ok(())
66}13fn main() -> scriba::Result<()> {
14 // Example unified diff content
15 let patch = r#"--- a/src/main.rs
16+++ b/src/main.rs
17@@ -1,5 +1,6 @@
18 fn main() {
19- println!("Hello, world!");
20+ println!("Hello, Scriba!");
21+ println!("Diff viewer is great!");
22
23 let x = 42;
24- println!("x = {}", x);
25+ println!("x = {}", x * 2);
26"#;
27
28 println!("=== TEXT FORMAT (default) ===\n");
29 let ui_text = Ui::new().with_format(Format::Text);
30 ui_text.show_diff("src/main.rs", patch)?;
31
32 println!("\n=== MARKDOWN FORMAT ===\n");
33 let ui_markdown = Ui::new().with_format(Format::Markdown);
34 ui_markdown.show_diff("src/main.rs", patch)?;
35
36 println!("\n=== COLORED DIFF (for terminal output) ===\n");
37 let ui_colored = Ui::new().with_format(Format::Text);
38 ui_colored.show_diff_colored("src/main.rs", patch, true)?;
39
40 println!("\n=== JSON FORMAT ===\n");
41 let ui_json = Ui::new().with_format(Format::Json);
42 ui_json.show_diff("src/main.rs", patch)?;
43
44 // Example: Working with parsed diff lines
45 println!("\n=== PARSED DIFF LINES ===\n");
46 let diff_lines = scriba::parse_diff(patch);
47 let mut output = Output::new()
48 .title("Parsed Diff Analysis")
49 .subtitle("Breaking down the diff into structured lines");
50
51 let mut stats = String::new();
52 stats.push_str(&format!(
53 "Total lines: {}\n",
54 diff_lines.len()
55 ));
56
57 let added = diff_lines
58 .iter()
59 .filter(|l| l.kind == scriba::DiffLineKind::Added)
60 .count();
61 let removed = diff_lines
62 .iter()
63 .filter(|l| l.kind == scriba::DiffLineKind::Removed)
64 .count();
65 let context = diff_lines
66 .iter()
67 .filter(|l| l.kind == scriba::DiffLineKind::Context)
68 .count();
69
70 stats.push_str(&format!("Added: {}\n", added));
71 stats.push_str(&format!("Removed: {}\n", removed));
72 stats.push_str(&format!("Context: {}", context));
73
74 output = output.section("Statistics", stats, "text".to_string());
75
76 let ui_stats = Ui::new().with_format(Format::Markdown);
77 ui_stats.print(&output)?;
78
79 Ok(())
80}17fn main() -> scriba::Result<()> {
18 let output = Output::new()
19 .title("Users")
20 .data("count", 42u64)
21 .paragraph("Query executed successfully.");
22
23 // --- Custom flat field names ---
24 let flat_ui = Ui::new()
25 .with_format(Format::Json)
26 .with_envelope(
27 EnvelopeConfig::default()
28 .with_mode(EnvelopeMode::Json)
29 .with_layout(EnvelopeLayout::Flat)
30 .with_fields(EnvelopeFields {
31 ok_field: "success".into(),
32 format_field: "type".into(),
33 content_field: "result".into(),
34 meta_field: "context".into(),
35 }),
36 );
37
38 println!("=== Custom field names, flat ===");
39 println!(r#" fields: success / type / result / context"#);
40 flat_ui.print(&output)?;
41
42 // --- Custom nested field names ---
43 let nested_ui = Ui::new()
44 .with_format(Format::Json)
45 .with_envelope(
46 EnvelopeConfig::default()
47 .with_mode(EnvelopeMode::Json)
48 .with_layout(EnvelopeLayout::Nested)
49 .with_fields(EnvelopeFields {
50 ok_field: "success".into(),
51 format_field: "type".into(),
52 content_field: "data".into(),
53 meta_field: "header".into(),
54 }),
55 );
56
57 let meta = Meta::default()
58 .with_command("users list".into())
59 .with_extra("region", "eu-west-1");
60
61 println!("\n=== Custom field names, nested ===");
62 println!(r#" fields: success / type / data / header"#);
63 nested_ui.print_with_meta(&output, Some(&meta), true)?;
64
65 // --- Omit ok and format fields entirely ---
66 let minimal_ui = Ui::new()
67 .with_format(Format::Json)
68 .with_envelope(
69 EnvelopeConfig::default()
70 .with_mode(EnvelopeMode::Json)
71 .with_show_ok(false)
72 .with_show_format(false),
73 );
74
75 println!("\n=== Envelope without ok or format fields ===");
76 minimal_ui.print(&output)?;
77
78 Ok(())
79}13fn main() -> scriba::Result<()> {
14 // Simulated git diff output
15 let git_diff = r#"--- a/src/lib.rs
16+++ b/src/lib.rs
17@@ -10,8 +10,9 @@ pub struct Config {
18 pub format: String,
19 }
20
21-impl Config {
22+impl Config {
23 pub fn new() -> Self {
24+ // Initialize with defaults
25 Self::default()
26 }
27 }
28@@ -45,10 +46,12 @@ pub fn render() {
29 println!("Rendering...");
30 }
31
32-pub fn cleanup() {
33+pub fn cleanup() -> Result<()> {
34 // Clean up resources
35+ println!("Cleanup complete");
36+ Ok(())
37 }
38"#;
39
40 println!("=== BASIC USAGE ===\n");
41 println!("Simple way to show a diff:\n");
42
43 let ui = Ui::new().with_format(Format::Text);
44 ui.show_diff("src/lib.rs", git_diff)?;
45
46 println!("\n\n=== WITH METADATA ===\n");
47 println!("Include diff in structured output with metadata:\n");
48
49 let output = scriba::Output::new()
50 .title("File Changes")
51 .subtitle("Reviewing unstaged modifications")
52 .data("file", "src/lib.rs")
53 .data("status", "modified")
54 .code(Some("diff".to_string()), git_diff.trim());
55
56 ui.print(&output)?;
57
58 println!("\n\n=== COLORED OUTPUT ===\n");
59 println!("Terminal-friendly colored diff (for stderr fallback):\n");
60
61 ui.show_diff_colored("src/lib.rs", git_diff, true)?;
62
63 println!("\n\n=== MARKDOWN FORMAT ===\n");
64 println!("Perfect for documentation or markdown reports:\n");
65
66 let ui_md = Ui::new().with_format(Format::Markdown);
67 ui_md.show_diff("src/lib.rs", git_diff)?;
68
69 println!("\n\n=== PARSED DIFF ANALYSIS ===\n");
70 println!("Work with structured diff data:\n");
71
72 let diff_lines = scriba::parse_diff(git_diff);
73 let mut analysis = scriba::Output::new()
74 .title("Diff Analysis")
75 .data("total_lines", diff_lines.len().to_string());
76
77 let added = diff_lines.iter().filter(|l| l.kind == scriba::DiffLineKind::Added).count();
78 let removed = diff_lines.iter().filter(|l| l.kind == scriba::DiffLineKind::Removed).count();
79
80 analysis = analysis
81 .data("lines_added", added.to_string())
82 .data("lines_removed", removed.to_string())
83 .data("net_change", format!("{:+}", added as i32 - removed as i32));
84
85 ui.print(&analysis)?;
86
87 Ok(())
88}Sourcepub fn subtitle(self, value: impl Into<String>) -> Self
pub fn subtitle(self, value: impl Into<String>) -> Self
Set the subtitle (rendered as italics in Markdown).
Examples found in repository?
13fn main() -> scriba::Result<()> {
14 // Example unified diff content
15 let patch = r#"--- a/src/main.rs
16+++ b/src/main.rs
17@@ -1,5 +1,6 @@
18 fn main() {
19- println!("Hello, world!");
20+ println!("Hello, Scriba!");
21+ println!("Diff viewer is great!");
22
23 let x = 42;
24- println!("x = {}", x);
25+ println!("x = {}", x * 2);
26"#;
27
28 println!("=== TEXT FORMAT (default) ===\n");
29 let ui_text = Ui::new().with_format(Format::Text);
30 ui_text.show_diff("src/main.rs", patch)?;
31
32 println!("\n=== MARKDOWN FORMAT ===\n");
33 let ui_markdown = Ui::new().with_format(Format::Markdown);
34 ui_markdown.show_diff("src/main.rs", patch)?;
35
36 println!("\n=== COLORED DIFF (for terminal output) ===\n");
37 let ui_colored = Ui::new().with_format(Format::Text);
38 ui_colored.show_diff_colored("src/main.rs", patch, true)?;
39
40 println!("\n=== JSON FORMAT ===\n");
41 let ui_json = Ui::new().with_format(Format::Json);
42 ui_json.show_diff("src/main.rs", patch)?;
43
44 // Example: Working with parsed diff lines
45 println!("\n=== PARSED DIFF LINES ===\n");
46 let diff_lines = scriba::parse_diff(patch);
47 let mut output = Output::new()
48 .title("Parsed Diff Analysis")
49 .subtitle("Breaking down the diff into structured lines");
50
51 let mut stats = String::new();
52 stats.push_str(&format!(
53 "Total lines: {}\n",
54 diff_lines.len()
55 ));
56
57 let added = diff_lines
58 .iter()
59 .filter(|l| l.kind == scriba::DiffLineKind::Added)
60 .count();
61 let removed = diff_lines
62 .iter()
63 .filter(|l| l.kind == scriba::DiffLineKind::Removed)
64 .count();
65 let context = diff_lines
66 .iter()
67 .filter(|l| l.kind == scriba::DiffLineKind::Context)
68 .count();
69
70 stats.push_str(&format!("Added: {}\n", added));
71 stats.push_str(&format!("Removed: {}\n", removed));
72 stats.push_str(&format!("Context: {}", context));
73
74 output = output.section("Statistics", stats, "text".to_string());
75
76 let ui_stats = Ui::new().with_format(Format::Markdown);
77 ui_stats.print(&output)?;
78
79 Ok(())
80}More examples
13fn main() -> scriba::Result<()> {
14 // Simulated git diff output
15 let git_diff = r#"--- a/src/lib.rs
16+++ b/src/lib.rs
17@@ -10,8 +10,9 @@ pub struct Config {
18 pub format: String,
19 }
20
21-impl Config {
22+impl Config {
23 pub fn new() -> Self {
24+ // Initialize with defaults
25 Self::default()
26 }
27 }
28@@ -45,10 +46,12 @@ pub fn render() {
29 println!("Rendering...");
30 }
31
32-pub fn cleanup() {
33+pub fn cleanup() -> Result<()> {
34 // Clean up resources
35+ println!("Cleanup complete");
36+ Ok(())
37 }
38"#;
39
40 println!("=== BASIC USAGE ===\n");
41 println!("Simple way to show a diff:\n");
42
43 let ui = Ui::new().with_format(Format::Text);
44 ui.show_diff("src/lib.rs", git_diff)?;
45
46 println!("\n\n=== WITH METADATA ===\n");
47 println!("Include diff in structured output with metadata:\n");
48
49 let output = scriba::Output::new()
50 .title("File Changes")
51 .subtitle("Reviewing unstaged modifications")
52 .data("file", "src/lib.rs")
53 .data("status", "modified")
54 .code(Some("diff".to_string()), git_diff.trim());
55
56 ui.print(&output)?;
57
58 println!("\n\n=== COLORED OUTPUT ===\n");
59 println!("Terminal-friendly colored diff (for stderr fallback):\n");
60
61 ui.show_diff_colored("src/lib.rs", git_diff, true)?;
62
63 println!("\n\n=== MARKDOWN FORMAT ===\n");
64 println!("Perfect for documentation or markdown reports:\n");
65
66 let ui_md = Ui::new().with_format(Format::Markdown);
67 ui_md.show_diff("src/lib.rs", git_diff)?;
68
69 println!("\n\n=== PARSED DIFF ANALYSIS ===\n");
70 println!("Work with structured diff data:\n");
71
72 let diff_lines = scriba::parse_diff(git_diff);
73 let mut analysis = scriba::Output::new()
74 .title("Diff Analysis")
75 .data("total_lines", diff_lines.len().to_string());
76
77 let added = diff_lines.iter().filter(|l| l.kind == scriba::DiffLineKind::Added).count();
78 let removed = diff_lines.iter().filter(|l| l.kind == scriba::DiffLineKind::Removed).count();
79
80 analysis = analysis
81 .data("lines_added", added.to_string())
82 .data("lines_removed", removed.to_string())
83 .data("net_change", format!("{:+}", added as i32 - removed as i32));
84
85 ui.print(&analysis)?;
86
87 Ok(())
88}Sourcepub fn data(self, key: impl Into<String>, value: impl Serialize) -> Self
pub fn data(self, key: impl Into<String>, value: impl Serialize) -> Self
Add structured data (key-value pair).
Data is serialized and included in JSON/JSONL formats.
Examples found in repository?
25fn main() -> scriba::Result<()> {
26 let output = Output::new()
27 .title("Pipeline")
28 .data("stage", "build")
29 .data("commit", "a3f9c12")
30 .paragraph("Build succeeded in 42s.");
31
32 let ui = Ui::new()
33 .with_format(Format::Json)
34 .with_envelope(
35 EnvelopeConfig::default()
36 .with_mode(EnvelopeMode::Json)
37 .with_layout(EnvelopeLayout::Nested),
38 );
39
40 println!("=== Nested envelope, no meta ===");
41 ui.print(&output)?;
42
43 println!("\n=== Nested envelope, with meta merged in ===");
44 let meta = Meta::default()
45 .with_dry_run(true)
46 .with_command("ci run".into())
47 .with_timestamp("2026-04-13T09:30:00Z".into())
48 .with_scope("ci".into())
49 .with_version("0.3.0".into());
50 ui.print_with_meta(&output, Some(&meta), true)?;
51
52 Ok(())
53}More examples
16fn main() -> scriba::Result<()> {
17 let output = Output::new()
18 .title("Deployment")
19 .data("environment", "production")
20 .data("version", "1.4.2")
21 .paragraph("All services healthy.");
22
23 let ui = Ui::new()
24 .with_format(Format::Json)
25 .with_envelope(
26 EnvelopeConfig::default()
27 .with_mode(EnvelopeMode::Json)
28 .with_layout(EnvelopeLayout::Flat),
29 );
30
31 println!("=== Flat envelope, no meta ===");
32 ui.print(&output)?;
33
34 println!("\n=== Flat envelope, with meta ===");
35 let meta = Meta::default()
36 .with_dry_run(false)
37 .with_command("deploy".into())
38 .with_duration_ms(312)
39 .with_timestamp("2026-04-13T15:00:00Z".into());
40 ui.print_with_meta(&output, Some(&meta), true)?;
41
42 println!("\n=== Flat envelope, ok: false (error case) ===");
43 let error_output = Output::new()
44 .title("Deployment")
45 .paragraph("Health check failed on eu-west-1.");
46 ui.print_with_meta(&error_output, None, false)?;
47
48 Ok(())
49}17fn main() -> scriba::Result<()> {
18 let output = Output::new()
19 .title("Release")
20 .data("tag", "v0.3.0")
21 .paragraph("Release pipeline completed.");
22
23 let meta = Meta::default()
24 .with_dry_run(false)
25 .with_command("release publish".into())
26 .with_duration_ms(4821)
27 .with_timestamp("2026-04-13T18:00:00Z".into())
28 .with_scope("production".into())
29 .with_version("0.3.0".into())
30 // Arbitrary extra fields — any serialisable value
31 .with_extra("region", "eu-west-1")
32 .with_extra("actor", "github-actions")
33 .with_extra("run_id", 9_981_234_u64);
34
35 println!("=== Full meta — flat layout ===");
36 let flat_ui = Ui::new()
37 .with_format(Format::Json)
38 .with_envelope(
39 EnvelopeConfig::default()
40 .with_mode(EnvelopeMode::Json)
41 .with_layout(EnvelopeLayout::Flat),
42 );
43 flat_ui.print_with_meta(&output, Some(&meta), true)?;
44
45 println!("\n=== Full meta — nested layout (all fields merged under meta) ===");
46 let nested_ui = Ui::new()
47 .with_format(Format::Json)
48 .with_envelope(
49 EnvelopeConfig::default()
50 .with_mode(EnvelopeMode::Json)
51 .with_layout(EnvelopeLayout::Nested),
52 );
53 nested_ui.print_with_meta(&output, Some(&meta), true)?;
54
55 println!("\n=== Meta with non-JSON output format (text rendered inside envelope) ===");
56 let text_ui = Ui::new()
57 .with_format(Format::Text)
58 .with_envelope(
59 EnvelopeConfig::default()
60 .with_mode(EnvelopeMode::Json)
61 .with_layout(EnvelopeLayout::Flat),
62 );
63 text_ui.print_with_meta(&output, Some(&meta), true)?;
64
65 Ok(())
66}17fn main() -> scriba::Result<()> {
18 let output = Output::new()
19 .title("Users")
20 .data("count", 42u64)
21 .paragraph("Query executed successfully.");
22
23 // --- Custom flat field names ---
24 let flat_ui = Ui::new()
25 .with_format(Format::Json)
26 .with_envelope(
27 EnvelopeConfig::default()
28 .with_mode(EnvelopeMode::Json)
29 .with_layout(EnvelopeLayout::Flat)
30 .with_fields(EnvelopeFields {
31 ok_field: "success".into(),
32 format_field: "type".into(),
33 content_field: "result".into(),
34 meta_field: "context".into(),
35 }),
36 );
37
38 println!("=== Custom field names, flat ===");
39 println!(r#" fields: success / type / result / context"#);
40 flat_ui.print(&output)?;
41
42 // --- Custom nested field names ---
43 let nested_ui = Ui::new()
44 .with_format(Format::Json)
45 .with_envelope(
46 EnvelopeConfig::default()
47 .with_mode(EnvelopeMode::Json)
48 .with_layout(EnvelopeLayout::Nested)
49 .with_fields(EnvelopeFields {
50 ok_field: "success".into(),
51 format_field: "type".into(),
52 content_field: "data".into(),
53 meta_field: "header".into(),
54 }),
55 );
56
57 let meta = Meta::default()
58 .with_command("users list".into())
59 .with_extra("region", "eu-west-1");
60
61 println!("\n=== Custom field names, nested ===");
62 println!(r#" fields: success / type / data / header"#);
63 nested_ui.print_with_meta(&output, Some(&meta), true)?;
64
65 // --- Omit ok and format fields entirely ---
66 let minimal_ui = Ui::new()
67 .with_format(Format::Json)
68 .with_envelope(
69 EnvelopeConfig::default()
70 .with_mode(EnvelopeMode::Json)
71 .with_show_ok(false)
72 .with_show_format(false),
73 );
74
75 println!("\n=== Envelope without ok or format fields ===");
76 minimal_ui.print(&output)?;
77
78 Ok(())
79}13fn main() -> scriba::Result<()> {
14 // Simulated git diff output
15 let git_diff = r#"--- a/src/lib.rs
16+++ b/src/lib.rs
17@@ -10,8 +10,9 @@ pub struct Config {
18 pub format: String,
19 }
20
21-impl Config {
22+impl Config {
23 pub fn new() -> Self {
24+ // Initialize with defaults
25 Self::default()
26 }
27 }
28@@ -45,10 +46,12 @@ pub fn render() {
29 println!("Rendering...");
30 }
31
32-pub fn cleanup() {
33+pub fn cleanup() -> Result<()> {
34 // Clean up resources
35+ println!("Cleanup complete");
36+ Ok(())
37 }
38"#;
39
40 println!("=== BASIC USAGE ===\n");
41 println!("Simple way to show a diff:\n");
42
43 let ui = Ui::new().with_format(Format::Text);
44 ui.show_diff("src/lib.rs", git_diff)?;
45
46 println!("\n\n=== WITH METADATA ===\n");
47 println!("Include diff in structured output with metadata:\n");
48
49 let output = scriba::Output::new()
50 .title("File Changes")
51 .subtitle("Reviewing unstaged modifications")
52 .data("file", "src/lib.rs")
53 .data("status", "modified")
54 .code(Some("diff".to_string()), git_diff.trim());
55
56 ui.print(&output)?;
57
58 println!("\n\n=== COLORED OUTPUT ===\n");
59 println!("Terminal-friendly colored diff (for stderr fallback):\n");
60
61 ui.show_diff_colored("src/lib.rs", git_diff, true)?;
62
63 println!("\n\n=== MARKDOWN FORMAT ===\n");
64 println!("Perfect for documentation or markdown reports:\n");
65
66 let ui_md = Ui::new().with_format(Format::Markdown);
67 ui_md.show_diff("src/lib.rs", git_diff)?;
68
69 println!("\n\n=== PARSED DIFF ANALYSIS ===\n");
70 println!("Work with structured diff data:\n");
71
72 let diff_lines = scriba::parse_diff(git_diff);
73 let mut analysis = scriba::Output::new()
74 .title("Diff Analysis")
75 .data("total_lines", diff_lines.len().to_string());
76
77 let added = diff_lines.iter().filter(|l| l.kind == scriba::DiffLineKind::Added).count();
78 let removed = diff_lines.iter().filter(|l| l.kind == scriba::DiffLineKind::Removed).count();
79
80 analysis = analysis
81 .data("lines_added", added.to_string())
82 .data("lines_removed", removed.to_string())
83 .data("net_change", format!("{:+}", added as i32 - removed as i32));
84
85 ui.print(&analysis)?;
86
87 Ok(())
88}Sourcepub fn plain(self, value: impl Serialize) -> Self
pub fn plain(self, value: impl Serialize) -> Self
Set a plain scalar value for rendering.
Used with Format::Plain for simple output (string, number, boolean).
Sourcepub fn jsonl_record(self, value: impl Serialize) -> Self
pub fn jsonl_record(self, value: impl Serialize) -> Self
Add a JSONL record.
Multiple records are rendered as newline-delimited JSON when using Format::Jsonl.
Sourcepub fn heading(self, level: u8, text: impl Into<String>) -> Self
pub fn heading(self, level: u8, text: impl Into<String>) -> Self
Add a heading block.
level: 1-6 (levels 1-2 typically shown in most formats)text: Heading content
Examples found in repository?
13fn main() -> scriba::Result<()> {
14 // Text format — ANSI escape codes applied
15 println!("=== TEXT FORMAT (ANSI codes) ===\n");
16
17 let ui_text = Ui::new().with_format(Format::Text);
18
19 let output_text = Output::new()
20 .heading(1, "Text Styling Examples")
21 .styled_paragraph(Styled::new("This is bold text", TextStyle::Bold))
22 .styled_paragraph(Styled::new("This is italic text", TextStyle::Italic))
23 .styled_paragraph(Styled::new("This is bold and italic", TextStyle::BoldItalic))
24 .styled_paragraph(Styled::new("This is underlined", TextStyle::Underline))
25 .styled_paragraph(Styled::new("This is strikethrough", TextStyle::Strikethrough))
26 .styled_paragraph(Styled::new("This is dimmed/faded", TextStyle::Dim));
27
28 ui_text.print(&output_text)?;
29
30 // Markdown format — Markdown syntax applied
31 println!("\n=== MARKDOWN FORMAT ===\n");
32
33 let ui_md = Ui::new().with_format(Format::Markdown);
34
35 let output_md = Output::new()
36 .heading(1, "Text Styling in Markdown")
37 .styled_paragraph(Styled::new("This is bold", TextStyle::Bold))
38 .styled_paragraph(Styled::new("This is italic", TextStyle::Italic))
39 .styled_paragraph(Styled::new("This is bold italic", TextStyle::BoldItalic))
40 .styled_paragraph(Styled::new("This has strikethrough", TextStyle::Strikethrough))
41 .styled_paragraph(Styled::new("This is underlined", TextStyle::Underline));
42
43 ui_md.print(&output_md)?;
44
45 // Direct use of Styled API
46 println!("\n=== DIRECT API ===\n");
47
48 let bold_styled = Styled::new("Warning: check your config", TextStyle::Bold);
49 let italic_styled = Styled::new("Optional: skip if unneeded", TextStyle::Italic);
50 let dim_styled = Styled::new("Hint: use --verbose for more detail", TextStyle::Dim);
51
52 println!("ANSI:");
53 println!(" {}", bold_styled.render_ansi());
54 println!(" {}", italic_styled.render_ansi());
55 println!(" {}", dim_styled.render_ansi());
56
57 println!("\nMarkdown:");
58 println!(" {}", bold_styled.render_markdown());
59 println!(" {}", italic_styled.render_markdown());
60 println!(" {}", dim_styled.render_markdown());
61
62 Ok(())
63}More examples
14fn main() -> scriba::Result<()> {
15 let headers = vec!["Product".into(), "Price".into(), "Stock".into()];
16 let rows = vec![
17 vec!["Widget A".into(), "$9.99".into(), "42".into()],
18 vec!["Widget B".into(), "$14.50".into(), "18".into()],
19 vec!["Widget C".into(), "$24.99".into(), "0".into()],
20 ];
21
22 let ui = Ui::new().with_format(Format::Text);
23
24 // Full layout (default) — bordered, full width
25 println!("=== FULL LAYOUT ===");
26 println!("(Bordered, full width — best for normal terminals)\n");
27
28 let table_full = Table::new(headers.clone(), rows.clone()).with_layout_full();
29 let output_full = Output::new()
30 .heading(2, "Inventory")
31 .table(None, table_full);
32
33 ui.print(&output_full)?;
34
35 // Compact layout — minimal spacing, no borders
36 println!("\n=== COMPACT LAYOUT ===");
37 println!("(Minimal spacing, no borders — dense display)\n");
38
39 let table_compact = Table::new(headers.clone(), rows.clone()).with_layout_compact();
40 let output_compact = Output::new()
41 .heading(2, "Inventory")
42 .table(None, table_compact);
43
44 ui.print(&output_compact)?;
45
46 // Stacked layout — key-value per row
47 println!("\n=== STACKED LAYOUT ===");
48 println!("(Key-value per row — great for narrow terminals)\n");
49
50 let table_stacked = Table::new(headers.clone(), rows.clone()).with_layout_stacked();
51 let output_stacked = Output::new()
52 .heading(2, "Inventory")
53 .table(None, table_stacked);
54
55 ui.print(&output_stacked)?;
56
57 // Stacked with index
58 println!("\n=== STACKED LAYOUT WITH INDEX ===");
59 println!("(Row numbers for reference)\n");
60
61 let table_stacked_idx = Table::new(headers.clone(), rows.clone())
62 .with_index()
63 .with_layout_stacked();
64 let output_idx = Output::new()
65 .heading(2, "Inventory")
66 .table(None, table_stacked_idx);
67
68 ui.print(&output_idx)?;
69
70 // Compact with index
71 println!("\n=== COMPACT LAYOUT WITH INDEX ===");
72 println!("(Minimal display with row numbers)\n");
73
74 let table_compact_idx = Table::new(headers.clone(), rows.clone())
75 .with_index()
76 .with_layout_compact();
77 let output_compact_idx = Output::new()
78 .heading(2, "Inventory")
79 .table(None, table_compact_idx);
80
81 ui.print(&output_compact_idx)?;
82
83 Ok(())
84}Sourcepub fn paragraph(self, text: impl Into<String>) -> Self
pub fn paragraph(self, text: impl Into<String>) -> Self
Add a paragraph block.
Examples found in repository?
25fn main() -> scriba::Result<()> {
26 let output = Output::new()
27 .title("Pipeline")
28 .data("stage", "build")
29 .data("commit", "a3f9c12")
30 .paragraph("Build succeeded in 42s.");
31
32 let ui = Ui::new()
33 .with_format(Format::Json)
34 .with_envelope(
35 EnvelopeConfig::default()
36 .with_mode(EnvelopeMode::Json)
37 .with_layout(EnvelopeLayout::Nested),
38 );
39
40 println!("=== Nested envelope, no meta ===");
41 ui.print(&output)?;
42
43 println!("\n=== Nested envelope, with meta merged in ===");
44 let meta = Meta::default()
45 .with_dry_run(true)
46 .with_command("ci run".into())
47 .with_timestamp("2026-04-13T09:30:00Z".into())
48 .with_scope("ci".into())
49 .with_version("0.3.0".into());
50 ui.print_with_meta(&output, Some(&meta), true)?;
51
52 Ok(())
53}More examples
16fn main() -> scriba::Result<()> {
17 let output = Output::new()
18 .title("Deployment")
19 .data("environment", "production")
20 .data("version", "1.4.2")
21 .paragraph("All services healthy.");
22
23 let ui = Ui::new()
24 .with_format(Format::Json)
25 .with_envelope(
26 EnvelopeConfig::default()
27 .with_mode(EnvelopeMode::Json)
28 .with_layout(EnvelopeLayout::Flat),
29 );
30
31 println!("=== Flat envelope, no meta ===");
32 ui.print(&output)?;
33
34 println!("\n=== Flat envelope, with meta ===");
35 let meta = Meta::default()
36 .with_dry_run(false)
37 .with_command("deploy".into())
38 .with_duration_ms(312)
39 .with_timestamp("2026-04-13T15:00:00Z".into());
40 ui.print_with_meta(&output, Some(&meta), true)?;
41
42 println!("\n=== Flat envelope, ok: false (error case) ===");
43 let error_output = Output::new()
44 .title("Deployment")
45 .paragraph("Health check failed on eu-west-1.");
46 ui.print_with_meta(&error_output, None, false)?;
47
48 Ok(())
49}17fn main() -> scriba::Result<()> {
18 let output = Output::new()
19 .title("Release")
20 .data("tag", "v0.3.0")
21 .paragraph("Release pipeline completed.");
22
23 let meta = Meta::default()
24 .with_dry_run(false)
25 .with_command("release publish".into())
26 .with_duration_ms(4821)
27 .with_timestamp("2026-04-13T18:00:00Z".into())
28 .with_scope("production".into())
29 .with_version("0.3.0".into())
30 // Arbitrary extra fields — any serialisable value
31 .with_extra("region", "eu-west-1")
32 .with_extra("actor", "github-actions")
33 .with_extra("run_id", 9_981_234_u64);
34
35 println!("=== Full meta — flat layout ===");
36 let flat_ui = Ui::new()
37 .with_format(Format::Json)
38 .with_envelope(
39 EnvelopeConfig::default()
40 .with_mode(EnvelopeMode::Json)
41 .with_layout(EnvelopeLayout::Flat),
42 );
43 flat_ui.print_with_meta(&output, Some(&meta), true)?;
44
45 println!("\n=== Full meta — nested layout (all fields merged under meta) ===");
46 let nested_ui = Ui::new()
47 .with_format(Format::Json)
48 .with_envelope(
49 EnvelopeConfig::default()
50 .with_mode(EnvelopeMode::Json)
51 .with_layout(EnvelopeLayout::Nested),
52 );
53 nested_ui.print_with_meta(&output, Some(&meta), true)?;
54
55 println!("\n=== Meta with non-JSON output format (text rendered inside envelope) ===");
56 let text_ui = Ui::new()
57 .with_format(Format::Text)
58 .with_envelope(
59 EnvelopeConfig::default()
60 .with_mode(EnvelopeMode::Json)
61 .with_layout(EnvelopeLayout::Flat),
62 );
63 text_ui.print_with_meta(&output, Some(&meta), true)?;
64
65 Ok(())
66}17fn main() -> scriba::Result<()> {
18 let output = Output::new()
19 .title("Users")
20 .data("count", 42u64)
21 .paragraph("Query executed successfully.");
22
23 // --- Custom flat field names ---
24 let flat_ui = Ui::new()
25 .with_format(Format::Json)
26 .with_envelope(
27 EnvelopeConfig::default()
28 .with_mode(EnvelopeMode::Json)
29 .with_layout(EnvelopeLayout::Flat)
30 .with_fields(EnvelopeFields {
31 ok_field: "success".into(),
32 format_field: "type".into(),
33 content_field: "result".into(),
34 meta_field: "context".into(),
35 }),
36 );
37
38 println!("=== Custom field names, flat ===");
39 println!(r#" fields: success / type / result / context"#);
40 flat_ui.print(&output)?;
41
42 // --- Custom nested field names ---
43 let nested_ui = Ui::new()
44 .with_format(Format::Json)
45 .with_envelope(
46 EnvelopeConfig::default()
47 .with_mode(EnvelopeMode::Json)
48 .with_layout(EnvelopeLayout::Nested)
49 .with_fields(EnvelopeFields {
50 ok_field: "success".into(),
51 format_field: "type".into(),
52 content_field: "data".into(),
53 meta_field: "header".into(),
54 }),
55 );
56
57 let meta = Meta::default()
58 .with_command("users list".into())
59 .with_extra("region", "eu-west-1");
60
61 println!("\n=== Custom field names, nested ===");
62 println!(r#" fields: success / type / data / header"#);
63 nested_ui.print_with_meta(&output, Some(&meta), true)?;
64
65 // --- Omit ok and format fields entirely ---
66 let minimal_ui = Ui::new()
67 .with_format(Format::Json)
68 .with_envelope(
69 EnvelopeConfig::default()
70 .with_mode(EnvelopeMode::Json)
71 .with_show_ok(false)
72 .with_show_format(false),
73 );
74
75 println!("\n=== Envelope without ok or format fields ===");
76 minimal_ui.print(&output)?;
77
78 Ok(())
79}Sourcepub fn list(self, ordered: bool, items: Vec<String>) -> Self
pub fn list(self, ordered: bool, items: Vec<String>) -> Self
Add a list (ordered or unordered).
ordered:truefor numbered list,falsefor bullet points
Sourcepub fn code(self, language: Option<String>, code: impl Into<String>) -> Self
pub fn code(self, language: Option<String>, code: impl Into<String>) -> Self
Add a code block.
language: Optional language hint for syntax highlighting (e.g., “rust”, “bash”)code: Source code content
Examples found in repository?
13fn main() -> scriba::Result<()> {
14 // Simulated git diff output
15 let git_diff = r#"--- a/src/lib.rs
16+++ b/src/lib.rs
17@@ -10,8 +10,9 @@ pub struct Config {
18 pub format: String,
19 }
20
21-impl Config {
22+impl Config {
23 pub fn new() -> Self {
24+ // Initialize with defaults
25 Self::default()
26 }
27 }
28@@ -45,10 +46,12 @@ pub fn render() {
29 println!("Rendering...");
30 }
31
32-pub fn cleanup() {
33+pub fn cleanup() -> Result<()> {
34 // Clean up resources
35+ println!("Cleanup complete");
36+ Ok(())
37 }
38"#;
39
40 println!("=== BASIC USAGE ===\n");
41 println!("Simple way to show a diff:\n");
42
43 let ui = Ui::new().with_format(Format::Text);
44 ui.show_diff("src/lib.rs", git_diff)?;
45
46 println!("\n\n=== WITH METADATA ===\n");
47 println!("Include diff in structured output with metadata:\n");
48
49 let output = scriba::Output::new()
50 .title("File Changes")
51 .subtitle("Reviewing unstaged modifications")
52 .data("file", "src/lib.rs")
53 .data("status", "modified")
54 .code(Some("diff".to_string()), git_diff.trim());
55
56 ui.print(&output)?;
57
58 println!("\n\n=== COLORED OUTPUT ===\n");
59 println!("Terminal-friendly colored diff (for stderr fallback):\n");
60
61 ui.show_diff_colored("src/lib.rs", git_diff, true)?;
62
63 println!("\n\n=== MARKDOWN FORMAT ===\n");
64 println!("Perfect for documentation or markdown reports:\n");
65
66 let ui_md = Ui::new().with_format(Format::Markdown);
67 ui_md.show_diff("src/lib.rs", git_diff)?;
68
69 println!("\n\n=== PARSED DIFF ANALYSIS ===\n");
70 println!("Work with structured diff data:\n");
71
72 let diff_lines = scriba::parse_diff(git_diff);
73 let mut analysis = scriba::Output::new()
74 .title("Diff Analysis")
75 .data("total_lines", diff_lines.len().to_string());
76
77 let added = diff_lines.iter().filter(|l| l.kind == scriba::DiffLineKind::Added).count();
78 let removed = diff_lines.iter().filter(|l| l.kind == scriba::DiffLineKind::Removed).count();
79
80 analysis = analysis
81 .data("lines_added", added.to_string())
82 .data("lines_removed", removed.to_string())
83 .data("net_change", format!("{:+}", added as i32 - removed as i32));
84
85 ui.print(&analysis)?;
86
87 Ok(())
88}Sourcepub fn table(self, title: Option<String>, table: Table) -> Self
pub fn table(self, title: Option<String>, table: Table) -> Self
Add a data table.
Examples found in repository?
14fn main() -> scriba::Result<()> {
15 let headers = vec!["Product".into(), "Price".into(), "Stock".into()];
16 let rows = vec![
17 vec!["Widget A".into(), "$9.99".into(), "42".into()],
18 vec!["Widget B".into(), "$14.50".into(), "18".into()],
19 vec!["Widget C".into(), "$24.99".into(), "0".into()],
20 ];
21
22 let ui = Ui::new().with_format(Format::Text);
23
24 // Full layout (default) — bordered, full width
25 println!("=== FULL LAYOUT ===");
26 println!("(Bordered, full width — best for normal terminals)\n");
27
28 let table_full = Table::new(headers.clone(), rows.clone()).with_layout_full();
29 let output_full = Output::new()
30 .heading(2, "Inventory")
31 .table(None, table_full);
32
33 ui.print(&output_full)?;
34
35 // Compact layout — minimal spacing, no borders
36 println!("\n=== COMPACT LAYOUT ===");
37 println!("(Minimal spacing, no borders — dense display)\n");
38
39 let table_compact = Table::new(headers.clone(), rows.clone()).with_layout_compact();
40 let output_compact = Output::new()
41 .heading(2, "Inventory")
42 .table(None, table_compact);
43
44 ui.print(&output_compact)?;
45
46 // Stacked layout — key-value per row
47 println!("\n=== STACKED LAYOUT ===");
48 println!("(Key-value per row — great for narrow terminals)\n");
49
50 let table_stacked = Table::new(headers.clone(), rows.clone()).with_layout_stacked();
51 let output_stacked = Output::new()
52 .heading(2, "Inventory")
53 .table(None, table_stacked);
54
55 ui.print(&output_stacked)?;
56
57 // Stacked with index
58 println!("\n=== STACKED LAYOUT WITH INDEX ===");
59 println!("(Row numbers for reference)\n");
60
61 let table_stacked_idx = Table::new(headers.clone(), rows.clone())
62 .with_index()
63 .with_layout_stacked();
64 let output_idx = Output::new()
65 .heading(2, "Inventory")
66 .table(None, table_stacked_idx);
67
68 ui.print(&output_idx)?;
69
70 // Compact with index
71 println!("\n=== COMPACT LAYOUT WITH INDEX ===");
72 println!("(Minimal display with row numbers)\n");
73
74 let table_compact_idx = Table::new(headers.clone(), rows.clone())
75 .with_index()
76 .with_layout_compact();
77 let output_compact_idx = Output::new()
78 .heading(2, "Inventory")
79 .table(None, table_compact_idx);
80
81 ui.print(&output_compact_idx)?;
82
83 Ok(())
84}Sourcepub fn key_value(self, key: impl Into<String>, value: impl ToString) -> Self
pub fn key_value(self, key: impl Into<String>, value: impl ToString) -> Self
Add or append a key-value pair.
Consecutive calls group into a single block.
Sourcepub fn definition(
self,
term: impl Into<String>,
description: impl Into<String>,
) -> Self
pub fn definition( self, term: impl Into<String>, description: impl Into<String>, ) -> Self
Add or append a definition (term/description pair).
Consecutive calls group into a single definition list.
Sourcepub fn status(self, kind: StatusKind, text: impl Into<String>) -> Self
pub fn status(self, kind: StatusKind, text: impl Into<String>) -> Self
Add a status block (for success, warning, error messages).
Sourcepub fn section(
self,
title: impl Into<String>,
content: impl Into<String>,
language: impl Into<Option<String>>,
) -> Self
pub fn section( self, title: impl Into<String>, content: impl Into<String>, language: impl Into<Option<String>>, ) -> Self
Add a section with a heading and code block.
Convenience method that adds both a level-2 heading and code block.
Examples found in repository?
13fn main() -> scriba::Result<()> {
14 // Example unified diff content
15 let patch = r#"--- a/src/main.rs
16+++ b/src/main.rs
17@@ -1,5 +1,6 @@
18 fn main() {
19- println!("Hello, world!");
20+ println!("Hello, Scriba!");
21+ println!("Diff viewer is great!");
22
23 let x = 42;
24- println!("x = {}", x);
25+ println!("x = {}", x * 2);
26"#;
27
28 println!("=== TEXT FORMAT (default) ===\n");
29 let ui_text = Ui::new().with_format(Format::Text);
30 ui_text.show_diff("src/main.rs", patch)?;
31
32 println!("\n=== MARKDOWN FORMAT ===\n");
33 let ui_markdown = Ui::new().with_format(Format::Markdown);
34 ui_markdown.show_diff("src/main.rs", patch)?;
35
36 println!("\n=== COLORED DIFF (for terminal output) ===\n");
37 let ui_colored = Ui::new().with_format(Format::Text);
38 ui_colored.show_diff_colored("src/main.rs", patch, true)?;
39
40 println!("\n=== JSON FORMAT ===\n");
41 let ui_json = Ui::new().with_format(Format::Json);
42 ui_json.show_diff("src/main.rs", patch)?;
43
44 // Example: Working with parsed diff lines
45 println!("\n=== PARSED DIFF LINES ===\n");
46 let diff_lines = scriba::parse_diff(patch);
47 let mut output = Output::new()
48 .title("Parsed Diff Analysis")
49 .subtitle("Breaking down the diff into structured lines");
50
51 let mut stats = String::new();
52 stats.push_str(&format!(
53 "Total lines: {}\n",
54 diff_lines.len()
55 ));
56
57 let added = diff_lines
58 .iter()
59 .filter(|l| l.kind == scriba::DiffLineKind::Added)
60 .count();
61 let removed = diff_lines
62 .iter()
63 .filter(|l| l.kind == scriba::DiffLineKind::Removed)
64 .count();
65 let context = diff_lines
66 .iter()
67 .filter(|l| l.kind == scriba::DiffLineKind::Context)
68 .count();
69
70 stats.push_str(&format!("Added: {}\n", added));
71 stats.push_str(&format!("Removed: {}\n", removed));
72 stats.push_str(&format!("Context: {}", context));
73
74 output = output.section("Statistics", stats, "text".to_string());
75
76 let ui_stats = Ui::new().with_format(Format::Markdown);
77 ui_stats.print(&output)?;
78
79 Ok(())
80}Sourcepub fn styled_paragraph(self, styled: Styled) -> Self
pub fn styled_paragraph(self, styled: Styled) -> Self
Add a styled text block (with bold, italic, underline, etc.).
Renders with ANSI codes in Text format and Markdown syntax in Markdown format.
Examples found in repository?
13fn main() -> scriba::Result<()> {
14 // Text format — ANSI escape codes applied
15 println!("=== TEXT FORMAT (ANSI codes) ===\n");
16
17 let ui_text = Ui::new().with_format(Format::Text);
18
19 let output_text = Output::new()
20 .heading(1, "Text Styling Examples")
21 .styled_paragraph(Styled::new("This is bold text", TextStyle::Bold))
22 .styled_paragraph(Styled::new("This is italic text", TextStyle::Italic))
23 .styled_paragraph(Styled::new("This is bold and italic", TextStyle::BoldItalic))
24 .styled_paragraph(Styled::new("This is underlined", TextStyle::Underline))
25 .styled_paragraph(Styled::new("This is strikethrough", TextStyle::Strikethrough))
26 .styled_paragraph(Styled::new("This is dimmed/faded", TextStyle::Dim));
27
28 ui_text.print(&output_text)?;
29
30 // Markdown format — Markdown syntax applied
31 println!("\n=== MARKDOWN FORMAT ===\n");
32
33 let ui_md = Ui::new().with_format(Format::Markdown);
34
35 let output_md = Output::new()
36 .heading(1, "Text Styling in Markdown")
37 .styled_paragraph(Styled::new("This is bold", TextStyle::Bold))
38 .styled_paragraph(Styled::new("This is italic", TextStyle::Italic))
39 .styled_paragraph(Styled::new("This is bold italic", TextStyle::BoldItalic))
40 .styled_paragraph(Styled::new("This has strikethrough", TextStyle::Strikethrough))
41 .styled_paragraph(Styled::new("This is underlined", TextStyle::Underline));
42
43 ui_md.print(&output_md)?;
44
45 // Direct use of Styled API
46 println!("\n=== DIRECT API ===\n");
47
48 let bold_styled = Styled::new("Warning: check your config", TextStyle::Bold);
49 let italic_styled = Styled::new("Optional: skip if unneeded", TextStyle::Italic);
50 let dim_styled = Styled::new("Hint: use --verbose for more detail", TextStyle::Dim);
51
52 println!("ANSI:");
53 println!(" {}", bold_styled.render_ansi());
54 println!(" {}", italic_styled.render_ansi());
55 println!(" {}", dim_styled.render_ansi());
56
57 println!("\nMarkdown:");
58 println!(" {}", bold_styled.render_markdown());
59 println!(" {}", italic_styled.render_markdown());
60 println!(" {}", dim_styled.render_markdown());
61
62 Ok(())
63}Sourcepub fn styled_heading(self, level: u8, styled: Styled) -> Self
pub fn styled_heading(self, level: u8, styled: Styled) -> Self
Add a styled heading (with bold, italic, underline, etc.).
The heading level is rendered normally; style is applied to the heading text.
Sourcepub fn from_serializable(value: impl Serialize) -> Self
pub fn from_serializable(value: impl Serialize) -> Self
Create output from a serializable value.
Converts objects to key-value data; other values are stored as data[“value”].