stylic 0.3.1

A simple, fast library for styling text with ANSI escape codes
Documentation
//! A simple, fast library for styling text with ANSI escape codes.
//!
//! # Features
//!
//! - Simple, intuitive API
//! - Fast, no allocations
//! - No dependencies
//! - `#![no_std]` out of the box
//! - Hyperlink support
//!
//! # Basic Usage
//!
//! Import the [`Styleable`](crate::Styleable) trait for an easy way to create
//! styled values. Then use the methods from [`Styled`](crate::Styled) to style the value.
//!
//! ```
//! use stylic::Styleable;
//!
//! println!("{}", "Hello, World!".styled().green().italic());
//! ```
//!
//! You can also create a style and apply it later. [`Style`](struct@crate::Style) has the same
//! styling options as [`Styled`](crate::Styled). Styling methods (on both types) are `const`,
//! so you can create constant styles.
//!
//! ```
//! use stylic::{Style, Styleable};
//!
//! const EMPHASIS: Style = Style::new().bold().italic();
//! println!("To be or not to be, {} is the question.", "that".styled_with(EMPHASIS));
//! ```
//!
//! # Styling
//!
//! Both [`Style`](struct@crate::Style) and [`Styled`](crate::Styled) have methods for setting
//! the foreground color, background color, underline color, and attributes of the text
//! (such as bold, italic, etc).
//!
//! Available attributes are:
//!
//! - `bold`
//! - `dim`
//! - `italic`
//! - `underlined`
//! - `blink`
//! - `inverted`
//! - `hidden`
//! - `strikethrough`
//!
//! Available colors include basic ANSI colors, the extended 256-color palette, and RGB colors.
//!
//! The ANSI colors are:
//!
//! - `black`
//! - `red`
//! - `green`
//! - `yellow`
//! - `blue`
//! - `magenta`
//! - `cyan`
//! - `white`
//!
//! Plus bright variants.
//!
//! There are methods for setting the foreground color, background color and underline color
//! to basic ANSI colors:
//!
//! ```rust
//! use stylic::Styleable;
//!
//! println!("{}", "Hello, World!".styled().black().on_blue());
//! ```
//!
//! There are also [`fg`](fn@crate::Style::fg), [`bg`](fn@crate::Style::bg)
//! and [`underline_colored`](fn@crate::Style::underline_colored) methods that take a `Color`,
//! allowing the use of colors from the extended 256-color palette and RGB colors:
//!
//! ```
//! use stylic::{Styleable, BasicColor, Color};
//!
//! // Setting the foreground color to red.
//! println!("{}", "Hello, World!".styled().fg(Color::Basic(BasicColor::Red)));
//! println!("{}", "Hello, World!".styled().fg(BasicColor::Red.into()));
//!
//! // Setting the background color to a color from the 256-color palette.
//! println!("{}", "Hello, World!".styled().bg(Color::Extended(58)));
//! println!("{}", "Hello, World!".styled().bg(58.into()));
//!
//! // Setting the underline color to a RGB color.
//! println!("{}", "Hello, World!".styled().underline_colored(Color::Rgb(255, 0, 255)));
//! println!("{}", "Hello, World!".styled().underline_colored((255, 0, 255).into()));
//! ```
//!
//! You can also create attributes separately and apply them later:
//!
//! ```
//! use stylic::{Styleable, Attributes};
//!
//! let my_attrs = Attributes::ITALIC | Attributes::STRIKETHROUGH;
//! println!("My homework was {}", "redacted".styled().attributes(my_attrs));
//! ```
//!
//! Attributes have methods for performing bitwise operations in a `const` environment:
//!
//! ```
//! use stylic::{Styleable, Attributes};
//!
//! const MY_ATTRS: Attributes = Attributes::ITALIC.or(Attributes::BLINK);
//! println!("Did you hear about the {}?", "thing".styled().attributes(MY_ATTRS));
//! ```
//!
//! # Hyperlinks
//!
//! You can add a hyperlink to a styled value using the [`Styled::link`](fn@crate::Styled::link) method:
//!
//! ```
//! use stylic::Styleable;
//!
//! println!("{}", "Example!".styled().link("https://example.com"));
//! ```

#![no_std]
#![forbid(unsafe_code)]
#![warn(missing_docs)]
#![allow(rustdoc::redundant_explicit_links)] // These are used for `cargo-rdme`.

mod builder;
mod display;
mod style;

#[doc(hidden)]
pub mod macros;

use builder::builder_methods;
pub use style::{Attributes, BasicColor, Color, Style};

/// A trait for making types styleable with ANSI colors and attributes.
///
/// This trait is implemented for all ([`Sized`](core::marker::Sized)) types and allows easily creating
/// a [`Styled`](crate::Styled) value from any type using the `.styled()` or `.styled_with(style)` method.
pub trait Styleable: Sized {
    /// Create a new [`Styled`](crate::Styled) value from this value.
    ///
    /// # Examples
    ///
    /// ```
    /// use stylic::Styleable;
    ///
    /// println!("{}", "Hello, world!".styled().red());
    /// ```
    fn styled(self) -> Styled<Self> {
        Styled {
            value: self,
            link: WithoutLink,
            style: Style::new(),
        }
    }

    /// Create a new [`Styled`](crate::Styled) value from this value, with an existing style.
    ///
    /// # Examples
    ///
    /// ```
    /// use stylic::{Style, Styleable};
    ///
    /// let style = Style::new().red();
    /// println!("{}", "Hello, world!".styled_with(style));
    /// ```
    #[inline]
    fn styled_with(self, style: Style) -> Styled<Self> {
        let mut styled = self.styled();
        styled.style = style;
        styled
    }
}

impl<T> Styleable for T {}

/// Type parameter for [`Styled`](crate::Styled) value with no associated link.
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WithoutLink;

/// Type parameter for [`Styled`](crate::Styled) value with an associated link.
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WithLink<Uri>(Uri);

/// A styled value.
///
/// Has builder methods for building a style. See crate level docs for examples
/// of these.
///
/// Supports hyperlinks via the [`link`](`crate::Styled::link`) method.
///
/// This type can be created using [`Styleable::styled`](crate::Styleable::styled)
/// or [`Styleable::styled_with`](crate::Styleable::styled_with).
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(missing_docs)]
pub struct Styled<T, Link = WithoutLink> {
    pub value: T,
    pub style: Style,
    link: Link,
}

impl<T, Link> Styled<T, Link> {
    builder_methods! { s => s.style }

    /// Set a link associated with this value.
    ///
    /// This will create a clickable link in terminal emulators that support it.
    ///
    /// Note that this method produces a different type to a styled value without
    /// a link - `Styled<T, WithLink<Uri>` as opposed to the default
    /// `Styled<T, Link = WithoutLink>`.
    ///
    /// # Examples
    ///
    /// ```
    /// use stylic::Styleable;
    ///
    /// println!("{}", "Click me!".styled().link("https://example.com"));
    /// ```
    #[inline]
    pub fn link<Uri>(self, uri: Uri) -> Styled<T, WithLink<Uri>>
    where
        Uri: core::fmt::Display,
    {
        Styled {
            value: self.value,
            style: self.style,
            link: WithLink(uri),
        }
    }
}

impl<T> Styled<T, WithoutLink> {
    /// Create a new styled value.
    ///
    /// This is not the recommended way of doing this (see
    /// [`Styleable::styled`](crate::Styleable::styled) for a more
    /// convenient way), but could be useful in a `const` environment.
    pub const fn new(value: T, style: Style) -> Self {
        Self {
            value,
            style,
            link: WithoutLink,
        }
    }
}

impl<T, Uri> Styled<T, WithLink<Uri>> {
    /// Access the link associated with this styled value.
    ///
    /// # Examples
    ///
    /// ```
    /// use stylic::Styleable;
    ///
    /// let my_linked_value = "Example link"
    ///     .styled()
    ///     .link("https://example.com");
    ///
    /// println!("Link: {}", my_linked_value.get_link());
    /// ```
    pub fn get_link(&self) -> &Uri {
        &self.link.0
    }
}