pub struct Rendered {
pub lines: Vec<Line>,
}Expand description
A fully laid-out block of styled lines, ready to print or compose.
Fields§
§lines: Vec<Line>The styled lines, top to bottom.
Implementations§
Source§impl Rendered
impl Rendered
Sourcepub fn new(lines: Vec<Line>) -> Self
pub fn new(lines: Vec<Line>) -> Self
Creates a rendered block from lines.
Examples found in repository?
examples/output-readme.rs (line 25)
24fn blank() -> Rendered {
25 Rendered::new(vec![Line::default()])
26}
27
28/// The top hero panel with styled, centered text.
29fn hero() -> Result<()> {
30 let cyan = Style::new().fg(Color::Cyan).bold();
31 let on_magenta = Style::new().fg(Color::Black).bg(Color::Magenta).bold();
32 let yellow = Style::new().fg(Color::Yellow).bold();
33 let body = Text::new(vec![
34 Line::new(vec![
35 Span::raw("A native Rust library for "),
36 Span::styled("styled terminal output", cyan),
37 Span::raw(" and "),
38 Span::styled("input", on_magenta),
39 Span::raw(" - panels, tables, trees, lists,"),
40 ]),
41 Line::new(vec![
42 Span::raw("key-value pairs, badges, rules, "),
43 Span::styled("columns", cyan),
44 Span::raw(" and progress bars, with Rich-compatible "),
45 Span::styled("[markup]", yellow),
46 Span::raw("."),
47 ]),
48 ]);
49 Panel::new(body)
50 .border(BorderType::Rounded)
51 .border_style(Style::new().fg(Color::Cyan))
52 .title(
53 Title::new(" sparcli ")
54 .align(Align::Center)
55 .style(Style::new().fg(Color::Cyan).bold()),
56 )
57 .content_align(Align::Center)
58 .width(96)
59 .print()
60}
61
62/// The three-column dashboard row.
63fn dashboard() -> Result<()> {
64 Columns::new()
65 .add_rendered(overview_table())
66 .add_rendered(middle_column())
67 .add_rendered(right_column())
68 .gap(3)
69 .separator(BorderType::Single)
70 .print()
71}
72
73/// Left column: the striped, row-separated "Overview" table.
74fn overview_table() -> Rendered {
75 let status = |text: &str, color: Color| {
76 Cell::new(Text::styled(text, Style::new().fg(color).bold()))
77 };
78 Table::new()
79 .title("Overview")
80 .title_style(Style::new().fg(Color::Magenta).bold())
81 .border(BorderType::Rounded)
82 .border_style(Style::new().fg(Color::Magenta))
83 .header_style(Style::new().fg(Color::Cyan).bold())
84 .striped(true)
85 .stripe_style(Style::new().bg(Color::Rgb(40, 40, 60)))
86 .row_separators(true)
87 .columns([
88 Column::new("Service"),
89 Column::new("Status").align(Align::Center),
90 Column::new("Uptime").align(Align::Right),
91 ])
92 .row([
93 Cell::new("api-gateway"),
94 status("● OK", Color::Green),
95 Cell::new("99.98%"),
96 ])
97 .row([
98 Cell::new("auth"),
99 status("● OK", Color::Green),
100 Cell::new("99.91%"),
101 ])
102 .row([
103 Cell::new("billing"),
104 status("● WARN", Color::Yellow),
105 Cell::new("97.40%"),
106 ])
107 .row([
108 Cell::new("scheduler"),
109 status("● FAIL", Color::Red),
110 Cell::new("82.10%"),
111 ])
112 .render(40)
113}
114
115/// Middle column: a numbered list above a tree beside titled rules.
116fn middle_column() -> Rendered {
117 let list = List::ordered(Marker::Number)
118 .marker_style(Style::new().fg(Color::Yellow).bold())
119 .item("Compose widgets side by side")
120 .item("Capture, pad, and align them")
121 .item("Style with Rich-style markup")
122 .item("Render to any UTF-8 terminal")
123 .render(36);
124
125 let tree = Tree::new()
126 .dashes(2)
127 .connector_style(Style::new().fg(Color::Cyan))
128 .node(
129 TreeNode::new("project/")
130 .child(
131 TreeNode::new("api/")
132 .child(TreeNode::new("routes.c"))
133 .child(TreeNode::new("auth.c")),
134 )
135 .child(TreeNode::new("worker.c"))
136 .child(TreeNode::new("store.c")),
137 )
138 .render(18);
139
140 let rules = vstack(
141 &[
142 rule("Pipeline", BorderType::Single, Color::Magenta),
143 blank(),
144 rule("Workers", BorderType::Double, Color::Green),
145 blank(),
146 rule("Storage", BorderType::Thick, Color::Yellow),
147 blank(),
148 ],
149 0,
150 );
151
152 let tree_and_rules = Columns::new()
153 .add_rendered(tree)
154 .add_rendered(rules)
155 .gap(2)
156 .render(40);
157
158 vstack(&[list, blank(), tree_and_rules], 0)
159}
160
161/// One titled rule with a colored title and line.
162fn rule(title: &str, border: BorderType, color: Color) -> Rendered {
163 Rule::with_title(Text::styled(title, Style::new().fg(color).bold()))
164 .border(border)
165 .style(Style::new().fg(color))
166 .width(20)
167 .render(20)
168}
169
170/// Right column: key-value pairs, badges and a staggered columns demo.
171fn right_column() -> Rendered {
172 let kv = KeyValue::new()
173 .key_style(Style::new().fg(Color::Cyan).bold())
174 .value_style(Style::new())
175 .add("host", "localhost")
176 .add("port", "8080")
177 .add("scheme", "https")
178 .add("timeout", "30s")
179 .render(24);
180
181 let badge = |text: &str, color: Color| {
182 Badge::new(text)
183 .pad(1)
184 .style(Style::new().fg(Color::Black).bg(color).bold())
185 .span()
186 };
187 let badges = Rendered::new(vec![
188 Line::new(vec![
189 badge("DONE", Color::Green),
190 Span::raw(" "),
191 badge("INFO", Color::LightBlue),
192 ]),
193 Line::default(),
194 Line::new(vec![
195 badge("WARN", Color::Yellow),
196 Span::raw(" "),
197 badge("FAIL", Color::Red),
198 ]),
199 ]);
200
201 let label = |text: &str| {
202 Rendered::new(vec![Line::styled(
203 text,
204 Style::new().fg(Color::Cyan).bold(),
205 )])
206 };
207 let staggered = Columns::new()
208 .add_rendered(label("Col 1"))
209 .add_rendered(vstack(&[blank(), label("Col 2")], 0))
210 .add_rendered(vstack(&[blank(), blank(), label("Col 3")], 0))
211 .gap(2)
212 .separator(BorderType::Single)
213 .render(40);
214
215 vstack(&[kv, blank(), badges, blank(), staggered], 0)
216}More examples
examples/prompt-readme.rs (line 29)
28fn blank() -> Rendered {
29 Rendered::new(vec![Line::default()])
30}
31
32/// The top hero panel, sized to match the dashboard width.
33fn hero(width: u16) -> Result<()> {
34 let theme = theme();
35 let body = Text::new(vec![
36 Line::raw("Interactive prompts - confirm · select · text · password ·"),
37 Line::raw("number · textarea · fuzzy · date."),
38 ]);
39 Panel::new(body)
40 .border(BorderType::Rounded)
41 .border_style(Style::new().fg(theme.accent))
42 .title(
43 Title::new(" sparcli · input widgets ")
44 .align(Align::Center)
45 .style(theme.title),
46 )
47 .content_align(Align::Center)
48 .width(width)
49 .print()
50}
51
52/// The balanced three-column dashboard of prompt frames.
53fn dashboard() -> Rendered {
54 Columns::new()
55 .add_rendered(left_column())
56 .add_rendered(middle_column())
57 .add_rendered(calendar_column())
58 .gap(3)
59 .separator(BorderType::Single)
60 .render(0)
61}
62
63/// Left column: the confirm prompt with the input fields stacked beneath it,
64/// then the notes textarea.
65fn left_column() -> Rendered {
66 vstack(
67 &[
68 Confirm::new("Deploy to production?").default_yes().frame(),
69 blank(),
70 TextInput::new("Service").initial("api-gateway").frame(),
71 PasswordInput::new("Password").initial("hunter2").frame(),
72 NumberInput::new("Replicas")
73 .initial(3.0)
74 .range(1.0, 10.0)
75 .frame(),
76 TextInput::new("Email")
77 .placeholder("you@example.com")
78 .frame(),
79 TextInput::new("Region")
80 .initial("eu-")
81 .suggestions(["eu-central-1"])
82 .frame(),
83 blank(),
84 Textarea::new("Notes")
85 .initial("first line\nsecond line\nthird line")
86 .frame(),
87 ],
88 0,
89 )
90}
91
92/// Middle column: the single- and multi-select prompts.
93fn middle_column() -> Rendered {
94 vstack(
95 &[
96 Select::new("Environment")
97 .options(["staging", "production", "local"])
98 .cursor(1)
99 .frame(),
100 blank(),
101 Select::new("Targets")
102 .multi()
103 .options(["web", "api", "worker", "db"])
104 .checked([0, 2])
105 .frame(),
106 ],
107 0,
108 )
109}
110
111/// Right column: the date picker with the fuzzy finder beneath it.
112fn calendar_column() -> Rendered {
113 let date = DatePicker::new("Release date")
114 .initial(Date::new(2026, 5, 15))
115 .frame();
116 vstack(&[date, blank(), fuzzy_block()], 0)
117}
118
119/// A composed snapshot of an inline fuzzy finder (no `fuzzy` feature needed
120/// for this static screenshot).
121fn fuzzy_block() -> Rendered {
122 let theme = theme();
123 Rendered::new(vec![
124 Line::new(vec![
125 Span::styled("Language ".to_string(), theme.title),
126 Span::raw("ru"),
127 Span::styled(" ".to_string(), theme.cursor),
128 ]),
129 Line::new(vec![
130 Span::styled("‣ ".to_string(), theme.selection),
131 Span::styled("Rust".to_string(), theme.selection),
132 ]),
133 ])
134}examples/output_gallery.rs (lines 44-52)
41fn styled_text() -> Result<()> {
42 Rule::with_title("sparcli output gallery").print()?;
43 println!();
44 Rendered::new(vec![Line::new(vec![
45 Span::styled("bold ", Style::new().bold()),
46 Span::styled("dim ", Style::new().dim()),
47 Span::styled("italic ", Style::new().italic()),
48 Span::styled("red ", Style::new().fg(Color::Red)),
49 Span::styled("on-blue ", Style::new().bg(Color::Blue)),
50 Span::raw("link: "),
51 Span::raw("sparcli").link("https://example.com/sparcli"),
52 ])])
53 .print()?;
54
55 #[cfg(feature = "markup")]
56 markup_println("[bold green]markup[/]: [#ff8800]orange[/] and `code`")?;
57 Ok(())
58}
59
60/// Rules in all three alignments.
61fn sections() -> Result<()> {
62 section("Rules")?;
63 Rule::with_title("left")
64 .align(Align::Left)
65 .border(BorderType::Single)
66 .print()?;
67 Rule::with_title("center").align(Align::Center).print()?;
68 Rule::with_title("right")
69 .align(Align::Right)
70 .border(BorderType::Thick)
71 .print()?;
72 Ok(())
73}
74
75/// All five alert kinds.
76fn alerts() -> Result<()> {
77 section("Alerts")?;
78 Alert::info("Informational message.").print()?;
79 Alert::debug("Diagnostic detail.").print()?;
80 Alert::success("Everything compiled.").print()?;
81 Alert::warning("Low on disk space.").print()?;
82 Alert::error("Connection refused.").print()?;
83 Ok(())
84}
85
86/// Panels: borders, title/subtitle, fill and centered content.
87fn panels() -> Result<()> {
88 section("Panels")?;
89 Panel::new("Rounded border (default).").print()?;
90 Panel::new("Double border.")
91 .border(BorderType::Double)
92 .print()?;
93 Panel::new("Centered, filled, fixed width.")
94 .border(BorderType::Thick)
95 .title(Title::new("Title"))
96 .subtitle(Title::new("subtitle"))
97 .content_align(Align::Center)
98 .fill(Style::new().bg(Color::Indexed(236)))
99 .width(40)
100 .print()?;
101 Ok(())
102}
103
104/// Tables: colspan + striping, and footer + a wrapping column.
105fn tables() -> Result<()> {
106 section("Tables")?;
107 Table::new()
108 .title("Servers")
109 .columns(["Name", "Region", "Status"])
110 .row(["web-1", "eu-west", "online"])
111 .row(["db-1", "eu-west", "online"])
112 .row([Cell::new("maintenance window")
113 .colspan(3)
114 .align(Align::Center)])
115 .striped(true)
116 .print()?;
117 println!();
118 Table::new()
119 .columns([
120 Column::new("Item").align(Align::Left),
121 Column::new("Note").wrap().max_width(24),
122 ])
123 .row([
124 "alpha",
125 "a long note that wraps across several lines nicely",
126 ])
127 .row(["beta", "short note"])
128 .footer_row([Cell::new("2 items").colspan(2).align(Align::Right)])
129 .border(BorderType::Ascii)
130 .print()?;
131 Ok(())
132}
133
134/// Lists in several marker styles, plus a tree.
135fn lists_and_trees() -> Result<()> {
136 section("Lists & trees")?;
137 List::ordered(Marker::Number)
138 .item("First step")
139 .item_with("Second step", List::new().item("detail a").item("detail b"))
140 .item("Third step")
141 .print()?;
142 println!();
143 List::ordered(Marker::AlphaLower)
144 .item("alpha")
145 .item("beta")
146 .print()?;
147 List::ordered(Marker::RomanUpper)
148 .item("one")
149 .item("two")
150 .print()?;
151 println!();
152 Tree::new()
153 .node(
154 TreeNode::new("project")
155 .child(TreeNode::new("src").child(TreeNode::new("main.rs")))
156 .child(TreeNode::new("Cargo.toml")),
157 )
158 .print()?;
159 Ok(())
160}
161
162/// Key-value list and inline badges.
163fn key_values_and_badges() -> Result<()> {
164 section("Key-value & badges")?;
165 KeyValue::new()
166 .add("Version", "0.1.0")
167 .add("License", "MIT")
168 .print()?;
169 println!();
170 Rendered::new(vec![Line::new(vec![
171 Badge::new("PASS")
172 .style(Style::new().fg(Color::Green).bold())
173 .span(),
174 Span::raw(" "),
175 Badge::new("WARN")
176 .style(Style::new().fg(Color::Yellow).bold())
177 .span(),
178 Span::raw(" "),
179 Badge::new("v0.1").caps("(", ")").span(),
180 ])])
181 .print()?;
182 Ok(())
183}
184
185/// Progress bars in every style, a threshold bar, and a static spinner frame.
186fn progress_and_spinner() -> Result<()> {
187 section("Progress & spinner")?;
188 let styles = [
189 ("block", ProgressStyle::Block),
190 ("ascii", ProgressStyle::Ascii),
191 ("line", ProgressStyle::Line),
192 ("shaded", ProgressStyle::Shaded),
193 ];
194 for (label, style) in styles {
195 ProgressBar::new()
196 .style(style)
197 .label(label)
198 .width(20)
199 .bar(6.0, 10.0)
200 .print()?;
201 }
202 let thresholds = Thresholds {
203 mid: 0.5,
204 high: 0.8,
205 low_color: Color::Green,
206 mid_color: Color::Yellow,
207 high_color: Color::Red,
208 };
209 ProgressBar::new()
210 .thresholds(thresholds)
211 .label("load")
212 .width(20)
213 .bar(9.0, 10.0)
214 .print()?;
215 Spinner::new("spinner (static frame)").frame().print()?;
216 Ok(())
217}
218
219/// A colored diff and a two-column layout.
220fn diff_and_columns() -> Result<()> {
221 section("Diff & columns")?;
222 Diff::new(
223 "line one\nline two\nline three",
224 "line one\nline 2\nline three",
225 )
226 .print()?;
227 println!();
228 let left = Panel::new("left").render(20);
229 let right = Panel::new("right").render(20);
230 Columns::new()
231 .add_rendered(left)
232 .add_rendered(right)
233 .gap(3)
234 .separator(BorderType::Single)
235 .print()?;
236 Ok(())
237}
238
239/// Composition helpers: align, pad and vstack.
240fn composition() -> Result<()> {
241 section("Composition (align / pad / vstack)")?;
242 let block = Rendered::new(vec![Line::raw("aligned right")]);
243 align(&block, 30, Align::Right).print()?;
244 println!();
245 pad(&Rendered::new(vec![Line::raw("padded")]), Edges::all(1)).print()?;
246 println!();
247 let a = Rendered::new(vec![Line::raw("first block")]);
248 let b = Rendered::new(vec![Line::raw("second block")]);
249 vstack(&[a, b], 1).print()?;
250 Ok(())
251}Trait Implementations§
impl Eq for Rendered
Source§impl Renderable for Rendered
impl Renderable for Rendered
impl StructuralPartialEq for Rendered
Auto Trait Implementations§
impl Freeze for Rendered
impl RefUnwindSafe for Rendered
impl Send for Rendered
impl Sync for Rendered
impl Unpin for Rendered
impl UnsafeUnpin for Rendered
impl UnwindSafe for Rendered
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more