2 releases

0.1.1 Jan 15, 2019
0.1.0 Aug 8, 2018

#653 in Command-line interface

Download history 1280/week @ 2024-03-13 697/week @ 2024-03-20 610/week @ 2024-03-27 611/week @ 2024-04-03 497/week @ 2024-04-10 271/week @ 2024-04-17 160/week @ 2024-04-24 251/week @ 2024-05-01 262/week @ 2024-05-08 203/week @ 2024-05-15 182/week @ 2024-05-22 245/week @ 2024-05-29 531/week @ 2024-06-05 391/week @ 2024-06-12 113/week @ 2024-06-19 193/week @ 2024-06-26

1,272 downloads per month
Used in 21 crates (2 directly)

ISC license

105KB
2.5K SLoC

This module defines a tree structure that you can use to build documents to render with color.

There are three kinds of nodes in the Render Tree:

  • Lines, which represent content followed by a newline
  • Sections, which represent named content that can be targeted by style rules.
  • Components, which are parameterized chunks of the Render Tree

The easiest way to build a render tree is using the tree! macro:

#[macro_use]
extern crate render_tree;
extern crate termcolor;
use render_tree::{Document, Line, RenderComponent};
use termcolor::StandardStream;

fn main() -> std::io::Result<()> {
    let world = "world";

    let document = tree! {
        <Line as {
            "Hello" {world}
        }>

        <Line as {
            "Goodbye" {world}
        }>
    };

    document.write()
}

This will print out:

Hello world
Goodbye world

You can use sections and stylesheets to colorize the output:

#[macro_use]
extern crate render_tree;
extern crate termcolor;
use render_tree::{Document, Line, RenderComponent, Section, Stylesheet};
use render_tree::prelude::*;
use termcolor::StandardStream;

fn main() -> std::io::Result<()> {
    let world = "world";

    let document = tree! {
        <Line as {
            <Section name="hello" as { "Hello" }>
            {world}
        }>

        <Line as {
            <Section name="goodbye" as { "Goodbye"}>
            {world}
        }>
    };

    let stylesheet = Stylesheet::new()
        .add("hello", "fg: blue")
        .add("goodbye", "fg: red");

    document.write_styled(&stylesheet)
}

This will print out:

Hello world
Goodbye world

with the word "Hello" colored blue and "Goodbye" colored red.

You can nest sections, which can be targeted by style paths:

#[macro_use]
extern crate render_tree;
extern crate termcolor;
use render_tree::{Document, Line, RenderComponent, Section, Stylesheet};
use render_tree::prelude::*;
use termcolor::StandardStream;

fn main() -> std::io::Result<()> {
    let world = "world";

    let document = tree! {
        <Line as {
            <Section name="hello-world" as {
                <Section name="greeting" as { "Hello" }>
                {world}
            }>
        }>

        <Line as {
            "Some content in the middle here"
        }>

        <Line as {
            <Section name="goodbye-world" as {
                <Section name="greeting" as { "Goodbye" }>
                {world}
            }>
        }>
    };

    let stylesheet = Stylesheet::new()
        .add("** greeting", "weight: bold")
        .add("hello-world greeting", "fg: red")
        .add("goodbye-world greeting", "fg: blue");

    document.write_styled(&stylesheet)
}

This will print out:

Hello world
Some content in the middle here
Goodbye world

with the "Hello world" and "Goodbye world" bolded, the word "Hello" colored red (and bolded, of course), and the word "Goodbye" colored red (and bolded).

Globs (**) in a rule are superseded by stars (*), which are supersede by literal names. Globs match zero or more section names and stars match exactly one section name.

Using without the tree! macro

It's also easy to build a Render Tree without the macro. Repeating the previous example without the macro and without the string DSL for the stylesheet:

#[macro_use]
extern crate render_tree;
extern crate termcolor;
use render_tree::{
    Color,
    Document,
    Line,
    Render,
    RenderComponent,
    Section,
    Selector,
    Segment,
    Style,
    Stylesheet
};
use termcolor::StandardStream;

fn main() -> std::io::Result<()> {
    let world = "world";
    
    let document = Document::with(
        Line(
            Section("hello-world", |doc|
                doc.add(
                    Section("greeting", |doc| doc.add("Hello").add(world))
                )
            )
        )
    ).add(
        Line(
            "Some content in the middle here"
        )
    ).add(
        Line(
            Section("goodbye-world", |doc|
                doc.add(
                    Section("greeting", |doc| doc.add("Goodbye").add(world))
                )
            )
        )
    );

    let stylesheet = Stylesheet::new()
        .add(Selector::glob().add("greeting"), Style::new().bold())
        .add(Selector::name("hello-world").add("greeting"), Style::new().fg(Color::Red))
        .add(Selector::name("goodbye-world").add("greeting"), Style::new().fg(Color::Blue));

    document.write_styled(&stylesheet)
}

Dependencies

~0.6–7.5MB
~51K SLoC