#color #display #representation #format #interface #life #data-structures

color-your-life

一个具有 Display 类似接口的数据表示着色库

10 个版本 (破坏性更新)

0.8.0 2024 年 4 月 27 日
0.7.1 2024 年 4 月 19 日
0.6.0 2024 年 3 月 26 日
0.5.0 2024 年 3 月 26 日
0.1.1 2024 年 3 月 25 日

#298 in 文本处理

MIT/Apache

41KB
1K SLoC

Color Your Life

Rust

概述

这个 Rust 包提供了一种基于特质的、类似于 std::fmt::Display 的架构,让您可以着色并格式化打印数据结构。

用法

将此 crate 添加到项目 Cargo.toml 的依赖中

[dependencies]
color-your-life = "0.8.0"

现在我们可以打印,例如字符串

use color_your_life::{Color, ColorDisplay, str::StrFormat};

// A piece of text to format and color.
let text = "Alice and Bob have a drink.";

// The sink can be any type `T: std::fmt::Write`, including e.g.
// `std::fmt::Formatter<'_>` used in the `std::fmt::Display` and
// `std::fmt::Debug` traits.  Here, using a `String` is convenient.
let mut sink = String::with_capacity(1024);

// The trait `ColorDisplay<StrFormat>` is implemented for `&str`, so we can
// now call `text.color_fmt()`.
// The `text` is written to the `sink`, where the `&StrFormat` value provides
// a description of *how* to format the text, and in particular the `style_desc`
// field describes the color and style to be used.
text.color_fmt(&mut sink, &StrFormat {
    indent: 0,
    delimiter: "",
    prefix: "",
    style_desc: Some(StyleDesc {
        color: Color::Red,
        bold: true,
        italic: false,
        underline: true,
        dimmed: false,
    }),
})?;

let expected = format!("{}", Color::Red.bold().underline().paint(text));
assert_eq!(sink, expected);

编写用户自定义的 impl ColorDisplay<F> for T

编写一个类型的 ColorDisplay<F> 实现,与为该类型编写 std::fmt::Displaystd::fmt::Debug 实现非常相似,这不是巧合。它的目的是与它们非常相似,同时使实现例如 std::fmt::Display 之类的功能变得容易,使用 ColorDisplay<F>

新功能主要涉及数据值的样式和着色

use color_your_life::{Color, ColorDisplay, Format, StrFormat, StyleDesc};

/// A simple 2-line string. Indentation is managed for both lines at once.
struct TwoLineString {
    line0: String,
    line1: String,
}

impl ColorDisplay<TwoLineStringFormat> for TwoLineString {
    fn color_fmt(
        &self,
        sink: &mut impl Write,
        format: &TwoLineStringFormat,
    ) -> std::fmt::Result {

        self.line0.as_str().color_fmt(sink, &StrFormat {
            indent: format.indent, // override
            ..format.line0_format
        })?;
        for _ in 0..format.vertical_spacing {
            writeln!(sink)?;
        }
        self.line1.as_str().color_fmt(sink, &StrFormat {
            indent: format.indent, // override
            ..format.line1_format
        })?;
        Ok(())

    }
}

// This types allows a user to describe how to style,
// color and format values of type `TwoLineString`:
struct TwoLineStringFormat {
    /// The indentation of `self` as a whole.  Overrides
    /// `self::line0_format.indent` and `self::line1_format.indent`.
    pub indent: u16,
    /// The number of newlines to write between the 2 lines.
    /// A value of:
    ///   - 0 means the lines will be concatenated
    ///   - 1 truly separates the 2 lines
    ///   - 2 writes 1 empty line between the 2 lines,
    ///   - etc
    pub vertical_spacing: u8,
    /// Describes how to format the first line
    pub line0_format: StrFormat,
    /// Describes how to format the second line
    pub line1_format: StrFormat,
}

// The `Format` trait gives a user a standard way of creating
// colored as well as monochrome values of type `TwoLineString`.
impl Format for TwoLineStringFormat {
    fn colored(indent: u16) -> Self {
        Self {
            indent,
            vertical_spacing: 1,
            line0_format: StrFormat::colored(indent),
            line1_format: StrFormat::colored(indent),
        }
    }

    fn monochrome(indent: u16) -> Self {
        Self {
            indent,
            vertical_spacing: 1,
            line0_format: StrFormat::monochrome(indent),
            line1_format: StrFormat::monochrome(indent),
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn two_line_string() -> std::fmt::Result {
        let tls = TwoLineString {
            line0: "hello".to_string(),
            line1: "world".to_string(),
        };

        // Perform a write to the sink of a colored representation
        // of `tls` and one newline to separate the 2 lines
        let mut sink = String::with_capacity(1024);
        tls.color_fmt(&mut sink, &&TwoLineStringFormat {
            indent: 0,
            vertical_spacing: 1,
            line0_format: StrFormat::colored(0/*doesn't matter*/),
            line1_format: StrFormat::colored(0/*doesn't matter*/),
        })?;
        let expected = format!(
            "{}\n{}",
            Color::Green.paint("hello"),
            Color::Green.paint("world"),
        );
        assert_eq!(sink, expected);

        // Perform a write to the sink of a partially monochrome representation
        // of `tls` and 2 newlines (i.e. 1 blank line) to separate the 2 lines,
        // as well as 1 horizontal indentation for both lines
        let mut sink = String::with_capacity(1024);
        tls.color_fmt(&mut sink, &&TwoLineStringFormat {
            indent: 1,
            vertical_spacing: 2,
            line0_format: StrFormat::monochrome(0/*doesn't matter*/),
            line1_format: StrFormat::colored(0/*doesn't matter*/),
        })?;
        let expected = format!(
            "    {}\n\n    {}",
            "hello",
            Color::Green.paint("world"),
        );
        assert_eq!(sink, expected);

        Ok(())
    }
}

依赖项

~245KB