10 releases

0.1.1 Aug 9, 2023
0.1.0 Aug 8, 2023
0.0.8 Jul 26, 2023

#304 in Command-line interface

MIT license

56KB
836 lines

easy-sgr

Build status Crates.io docs.rs License Code Coverage

An easy-to-use library for adding graphical ANSI codes or SGR escape sequences to your project. Its main strengths are the multitude of methods that are provided, and the lack of dependencies; compile times should be pretty good.

This library does not support the usage of non-SGR ANSI escape sequences

Installation

Add this to your Cargo.toml:

[dependencies]
easy-sgr="0.1.1"

Usage

Macros

The method I would recommend when regarding ease-of-use is to use the macros provided, through this library or the macro library itself.

This can be done without importing any other features of the library as such:

[dependencies]
easy-sgr = { version = "0.1.1", features = ["macro-only"] }

Or if you want to still use the other features, replace "macro-only" with "macros".

And its usage is very simple:

use easy_sgr::println;

println!("{[italic red]}This should be italic & red!{[]}");

{[]} is interpreted as a reset here.

All the other fmt functions are also implemented, see easy-sgr-macros for more.

Color and Style enums

The simplest runtime way to color text, using these two enums allows you to work inline of a string literal when using a macro such as println!, writeln! or format!:

use easy_sgr::{Color::*, Style::*};

println!("{Italic}{RedFg}This should be italic & red!{Reset}");

Color and Style are both enums that implement Display: when they are printed a matching SGR code is written.

This method is the best when it comes to simplicity, but has drawbacks; using it rewrites the sequence escape \x1b[ and the sequence end m repeatedly. In this example this is what would be written:

\x1b[3m\x1b[31mThis should be italic & red!\x1b[0m

This would not be much of an issue for the vast majority of use cases.

EasySGR trait

This is similar to the method above but uses the EasySGR trait. This trait is implemented by anything that implements Into<AnsiString> including Style and Color. Its main purpose is to provide functions for chaining SGR codes.

The example above can be achieved using it as such:

use easy_sgr::{ Color::*, EasySGR, Style::*};

let sgr = Italic.color(RedFg);

println!("{sgr}This should be italic & red!{Reset}");

Now the output would look something like this:

\x1b[31;3mThis should be italic & red!\x1b[0m

Instead of a rewriting the entire sequence, the separator character ; is used instead.

Doing this avoids the issue of rewriting the Escape and End sequences, though is more expensive to use as it allocates an SGRString.

SGRString struct

SGRString is the type returned by all EasySGR functions, it encapsulates all possible SGR sequences. You can use it to reproduce the previous examples as such:

use easy_sgr::{Color::*, EasySGR, Style::*};

let text = "This should be italic & red!"
    .to_sgr()
    .style(Italic)
    .color(RedFg);
println!("{text}");

You can forgo .to_sgr() as .style(..), .color(..) and all other EasySGR functions can be directly called on the string literal and other types that implement it.

The method above still uses the EasySGR trait, you can go without it like here:

use easy_sgr::{ColorKind, SGRString, StyleKind};

let mut text = SGRString::from("This should be italic & red!");
text.italic = StyleKind::Place;
text.foreground = ColorKind::Red;

println!("{text}")

SGRWriter struct

The writer can also be used directly, instead of using the above methods:

use std::io::{stdout, Write};
use easy_sgr::{Color::*, EasySGR, SGRWriter, Style::*};

let mut writer = SGRWriter::from(stdout());
writer.sgr(&Italic.color(RedFg)).unwrap();
writer.write_inner("This should be italic & red!").unwrap();
writer.sgr(&Reset).unwrap();

or, when writing to a String

use easy_sgr::{Color::*, EasySGR, SGRWriter, Style::*};

let stylized_string = {
    let mut writer = SGRWriter::from(String::new());
    writer.sgr(&Italic.color(RedFg)).unwrap();
    writer.write_inner("This should be italic & red!").unwrap();
    writer.sgr(&Reset).unwrap();
    writer.internal()
};

Features

partial

This feature changes the way that the discrete module works, enabling it causes it's types to not write the sequence escape and end.

This means to achieve the same affect as above you must do this:

use easy_sgr::{Color::*, Seq::*, Style::*};

println!("{Esc}{Italic};{RedFg}{End}This should be italic & red!{Esc}{Reset}{End}");

resulting in the string:

\x1b[3;31mThis should be italic & red!\x1b[0m

This feature exchanges ease of use for verbosity, resulting in more control.

Structure

easy-sgr is split into three modules:

  • discrete
    • Contains types that can be used inline of a string literal
    • The types, Seq, Color & Style are all able to function independently
    • They all implement the DiscreteSGR type to aid in this
    • The DiscreteSGR types can all work with an SGRString
  • graphics
    • Centerpiece is SGRString & EasySGR
    • SGRString is a String with the ability to write SGR codes
    • EasySGR is a trait for chaining SGR codes to create a SGRString
    • EasySGR is blanket implemented by everything that implements Into<SGRString>
    • This includes:
      • SGRString
      • Color
      • Style
      • &str
      • String
      • &String
  • writing
    • Implements SGRWriter & SGRBuilder
    • Used by other modules to do writing

Though no modules really will be seen in usage, as all the types they contain are reexported.

TODO for 1.0.0 release

  • Add examples to docs
    • discrete
    • graphics
    • writing
  • Macros (east-sgr-macros) (0.1.0)
  • Add parser?
    • Add parsing from ansi codes
    • Add parsing for SGRString
  • EasySGR implementation that doesn't allocate an SGRString

Dependencies