Skip to main content

Output

Struct Output 

Source
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

Source

pub fn new() -> Self

Create a new empty output.

Examples found in repository?
examples/envelope_nested.rs (line 26)
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
Hide additional examples
examples/envelope_flat.rs (line 17)
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}
examples/envelope_meta.rs (line 18)
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}
examples/diff_viewer.rs (line 47)
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}
examples/envelope_custom_fields.rs (line 18)
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}
examples/styling.rs (line 19)
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}
Source

pub fn title(self, value: impl Into<String>) -> Self

Set the title (rendered as # in Markdown, underlined in Text).

Examples found in repository?
examples/envelope_nested.rs (line 27)
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
Hide additional examples
examples/envelope_flat.rs (line 18)
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}
examples/envelope_meta.rs (line 19)
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}
examples/diff_viewer.rs (line 48)
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}
examples/envelope_custom_fields.rs (line 19)
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}
examples/staged_diff_integration.rs (line 50)
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}
Source

pub fn subtitle(self, value: impl Into<String>) -> Self

Set the subtitle (rendered as italics in Markdown).

Examples found in repository?
examples/diff_viewer.rs (line 49)
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
Hide additional examples
examples/staged_diff_integration.rs (line 51)
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}
Source

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?
examples/envelope_nested.rs (line 28)
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
Hide additional examples
examples/envelope_flat.rs (line 19)
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}
examples/envelope_meta.rs (line 20)
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}
examples/envelope_custom_fields.rs (line 20)
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}
examples/staged_diff_integration.rs (line 52)
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}
Source

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).

Source

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.

Source

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?
examples/styling.rs (line 20)
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
Hide additional examples
examples/table_layouts.rs (line 30)
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}
Source

pub fn paragraph(self, text: impl Into<String>) -> Self

Add a paragraph block.

Examples found in repository?
examples/envelope_nested.rs (line 30)
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
Hide additional examples
examples/envelope_flat.rs (line 21)
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}
examples/envelope_meta.rs (line 21)
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}
examples/envelope_custom_fields.rs (line 21)
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}
Source

pub fn line(self, text: impl Into<String>) -> Self

Add a single line of text.

Source

pub fn separator(self) -> Self

Add a visual separator.

Source

pub fn list(self, ordered: bool, items: Vec<String>) -> Self

Add a list (ordered or unordered).

  • ordered: true for numbered list, false for bullet points
Source

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?
examples/staged_diff_integration.rs (line 54)
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}
Source

pub fn table(self, title: Option<String>, table: Table) -> Self

Add a data table.

Examples found in repository?
examples/table_layouts.rs (line 31)
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}
Source

pub fn json(self, value: impl Serialize) -> Self

Add a JSON data block.

Source

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.

Source

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.

Source

pub fn status(self, kind: StatusKind, text: impl Into<String>) -> Self

Add a status block (for success, warning, error messages).

Source

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?
examples/diff_viewer.rs (line 74)
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}
Source

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?
examples/styling.rs (line 21)
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}
Source

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.

Source

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”].

Trait Implementations§

Source§

impl Clone for Output

Source§

fn clone(&self) -> Output

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Output

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Output

Source§

fn default() -> Output

Returns the “default value” for a type. Read more
Source§

impl Serialize for Output

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.