use crate::console::{Console, ConsoleOptions};
use crate::markup;
use crate::segment::Segment;
use crate::text::Text;
pub trait Renderable {
fn render<'a>(&'a self, console: &Console, options: &ConsoleOptions) -> Vec<Segment<'a>>;
}
pub mod align;
pub mod columns;
pub mod constrain;
pub mod control;
pub mod emoji;
pub mod group;
pub mod layout;
pub mod padding;
pub mod panel;
pub mod pretty;
pub mod progress;
pub mod rule;
pub mod table;
pub mod traceback;
pub mod tree;
pub use align::{Align, AlignLines, AlignMethod, VerticalAlignMethod, align_text};
pub use columns::Columns;
pub use constrain::Constrain;
pub use control::Control;
pub use emoji::{Emoji, NoEmoji};
pub use group::{Group, group};
pub use layout::{Layout, LayoutSplitter, Region};
pub use padding::{Padding, PaddingDimensions};
pub use panel::Panel;
pub use pretty::{Inspect, InspectOptions, Pretty, PrettyOptions, inspect};
pub use progress::{
BarStyle, DownloadColumn, FileSizeColumn, ProgressBar, Spinner, TotalFileSizeColumn,
TransferSpeedColumn,
};
pub use rule::Rule;
pub use table::{Cell, Column, Row, Table, VerticalAlign};
pub use traceback::{Traceback, TracebackFrame, print_exception};
pub use tree::{Tree, TreeGuides, TreeNode};
impl Renderable for str {
fn render<'a>(&'a self, console: &Console, options: &ConsoleOptions) -> Vec<Segment<'a>> {
let content = if console.emoji() {
crate::emoji::replace(self, None)
} else {
std::borrow::Cow::Borrowed(self)
};
let mut text = if options.markup.unwrap_or(true) {
markup::render_or_plain_with_style_resolver(content.as_ref(), |definition| {
console.get_style(definition)
})
} else {
Text::new(content.as_ref())
};
console.apply_highlighter_to_text(options, &mut text);
text.render("")
.into_iter()
.map(Segment::into_owned)
.collect()
}
}
impl Renderable for String {
fn render<'a>(&'a self, console: &Console, options: &ConsoleOptions) -> Vec<Segment<'a>> {
self.as_str().render(console, options)
}
}
impl<T: Renderable + ?Sized> Renderable for &T {
fn render<'a>(&'a self, console: &Console, options: &ConsoleOptions) -> Vec<Segment<'a>> {
(*self).render(console, options)
}
}
#[cfg(feature = "syntax")]
pub mod syntax;
#[cfg(feature = "syntax")]
pub use syntax::{Syntax, SyntaxError};
#[cfg(feature = "syntax")]
impl Renderable for Syntax {
fn render<'a>(&'a self, _console: &Console, options: &ConsoleOptions) -> Vec<Segment<'a>> {
self.render(Some(options.max_width))
.unwrap_or_default()
.into_iter()
.map(Segment::into_owned) .collect()
}
}
#[cfg(feature = "markdown")]
pub mod markdown;
#[cfg(feature = "markdown")]
pub use markdown::Markdown;
#[cfg(feature = "markdown")]
impl Renderable for Markdown {
fn render<'a>(&'a self, _console: &Console, options: &ConsoleOptions) -> Vec<Segment<'a>> {
self.render(options.max_width).into_iter().collect()
}
}
#[cfg(feature = "json")]
pub mod json;
#[cfg(feature = "json")]
pub use json::{Json, JsonError, JsonTheme};
#[cfg(feature = "json")]
impl Renderable for Json {
fn render<'a>(&'a self, console: &Console, options: &ConsoleOptions) -> Vec<Segment<'a>> {
let width = options.max_width;
let segments = self.render_with_tab_size(console.tab_size());
let mut text = Text::new("");
text.tab_size = console.tab_size();
for segment in &segments {
if segment.is_control() {
continue;
}
if let Some(style) = segment.style.as_ref() {
text.append_styled(segment.text.as_ref(), style.clone());
} else {
text.append(segment.text.as_ref());
}
}
let lines = text.wrap(width);
let mut wrapped: Vec<Segment<'static>> = Vec::new();
for (idx, line) in lines.iter().enumerate() {
wrapped.extend(line.render("").into_iter().map(Segment::into_owned));
if idx + 1 < lines.len() {
wrapped.push(Segment::new("\n", None));
}
}
wrapped.into_iter().map(Segment::into_owned).collect()
}
}
#[cfg(test)]
mod tests {
use crate::color::ColorSystem;
use crate::console::Console;
use crate::renderables::Renderable;
#[test]
fn str_renderable_applies_console_highlighter_when_enabled() {
let console = Console::builder()
.force_terminal(true)
.color_system(ColorSystem::TrueColor)
.highlight(true)
.build();
let options = console.options();
let segments = "True".render(&console, &options);
assert!(segments.iter().any(|segment| segment.style.is_some()));
let mut buf = Vec::new();
console
.print_segments_to(&mut buf, &segments)
.expect("print_segments_to failed");
let ansi = String::from_utf8(buf).expect("utf8");
assert!(ansi.contains("\x1b["));
}
}