#![warn(missing_docs, rust_2018_idioms)]
#[cfg(feature = "ansi_term")]
pub mod ansi_term;
#[cfg(feature = "crossterm")]
pub mod crossterm;
#[cfg(feature = "cursive")]
pub mod cursive;
#[cfg(feature = "genpdf")]
pub mod genpdf;
#[cfg(feature = "syntect")]
pub mod syntect;
#[cfg(feature = "termion")]
pub mod termion;
#[derive(Clone, Debug, PartialEq)]
pub struct StyledStr<'a> {
pub s: &'a str,
pub style: Option<Style>,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct StyledString {
pub s: String,
pub style: Option<Style>,
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Style {
pub fg: Option<Color>,
pub bg: Option<Color>,
pub effects: Effects,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Effect {
Bold,
Italic,
Underline,
Strikethrough,
}
pub const EFFECTS: &[Effect] = &[
Effect::Bold,
Effect::Italic,
Effect::Underline,
Effect::Strikethrough,
];
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Effects {
pub is_bold: bool,
pub is_italic: bool,
pub is_underline: bool,
pub is_strikethrough: bool,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct EffectsIter {
effects: Effects,
i: usize,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Color {
Ansi {
color: AnsiColor,
mode: AnsiMode,
},
Rgb {
r: u8,
g: u8,
b: u8,
},
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum AnsiColor {
Black,
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum AnsiMode {
Dark,
Light,
}
impl<'a> StyledStr<'a> {
pub fn new(s: &'a str, style: Option<Style>) -> StyledStr<'a> {
StyledStr { s, style }
}
pub fn styled(s: &'a str, style: Style) -> StyledStr<'a> {
StyledStr::new(s, Some(style))
}
pub fn plain(s: &'a str) -> StyledStr<'a> {
StyledStr::new(s, None)
}
pub fn with(mut self, fg: Color) -> Self {
self.style_mut().fg = Some(fg);
self
}
pub fn on(mut self, bg: Color) -> Self {
self.style_mut().bg = Some(bg);
self
}
pub fn bold(self) -> Self {
self.effect(Effect::Bold)
}
pub fn italic(self) -> Self {
self.effect(Effect::Italic)
}
pub fn underline(self) -> Self {
self.effect(Effect::Underline)
}
pub fn strikethrough(self) -> Self {
self.effect(Effect::Strikethrough)
}
pub fn effect(mut self, effect: Effect) -> Self {
self.style_mut().effects.set(effect, true);
self
}
pub fn style_mut(&mut self) -> &mut Style {
self.style.get_or_insert_with(Default::default)
}
}
impl StyledString {
pub fn new(s: String, style: Option<Style>) -> StyledString {
StyledString { s, style }
}
pub fn styled(s: String, style: Style) -> StyledString {
StyledString::new(s, Some(style))
}
pub fn plain(s: String) -> StyledString {
StyledString::new(s, None)
}
pub fn with(mut self, fg: Color) -> Self {
self.style_mut().fg = Some(fg);
self
}
pub fn on(mut self, bg: Color) -> Self {
self.style_mut().bg = Some(bg);
self
}
pub fn bold(self) -> Self {
self.effect(Effect::Bold)
}
pub fn italic(self) -> Self {
self.effect(Effect::Italic)
}
pub fn underline(self) -> Self {
self.effect(Effect::Underline)
}
pub fn strikethrough(self) -> Self {
self.effect(Effect::Strikethrough)
}
pub fn effect(mut self, effect: Effect) -> Self {
self.style_mut().effects.set(effect, true);
self
}
pub fn style_mut(&mut self) -> &mut Style {
self.style.get_or_insert_with(Default::default)
}
}
impl<'a, 'b> From<&'b StyledStr<'a>> for StyledStr<'a> {
fn from(s: &'b StyledStr<'a>) -> StyledStr<'a> {
StyledStr {
s: &s.s,
style: s.style,
}
}
}
impl<'a> From<&'a StyledString> for StyledStr<'a> {
fn from(s: &'a StyledString) -> StyledStr<'a> {
StyledStr {
s: &s.s,
style: s.style,
}
}
}
impl<'a> From<StyledStr<'a>> for StyledString {
fn from(s: StyledStr<'a>) -> StyledString {
StyledString {
s: s.s.to_owned(),
style: s.style,
}
}
}
impl<'a> From<&'a str> for StyledStr<'a> {
fn from(s: &'a str) -> StyledStr<'a> {
StyledStr::plain(s)
}
}
impl From<String> for StyledString {
fn from(s: String) -> StyledString {
StyledString::plain(s)
}
}
impl Style {
pub fn new(fg: Option<Color>, bg: Option<Color>, effects: Effects) -> Style {
Style { fg, bg, effects }
}
pub fn fg(color: Color) -> Style {
Style::new(Some(color), None, Effects::new())
}
pub fn bg(color: Color) -> Style {
Style::new(None, Some(color), Effects::new())
}
pub fn effect(effect: Effect) -> Style {
Style::new(None, None, Effects::only(effect))
}
pub fn effects(effects: Effects) -> Style {
Style::new(None, None, effects)
}
pub fn and(mut self, style: Style) -> Style {
if let Some(fg) = style.fg {
self.fg = Some(fg);
}
if let Some(bg) = style.bg {
self.bg = Some(bg);
}
self.effects = self.effects.and(style.effects);
self
}
pub fn set_fg(&mut self, color: Color) {
self.fg = Some(color);
}
pub fn set_bg(&mut self, color: Color) {
self.bg = Some(color);
}
pub fn set_bold(&mut self, bold: bool) {
self.effects.is_bold = bold;
}
pub fn set_italic(&mut self, italic: bool) {
self.effects.is_italic = italic;
}
pub fn set_underline(&mut self, underline: bool) {
self.effects.is_underline = underline;
}
pub fn strikethrough(&mut self, strikethrough: bool) {
self.effects.is_strikethrough = strikethrough;
}
pub fn set_effect(&mut self, effect: Effect, set: bool) {
self.effects.set(effect, set);
}
}
impl From<Effect> for Style {
fn from(effect: Effect) -> Style {
Style::effect(effect)
}
}
impl From<Effects> for Style {
fn from(effects: Effects) -> Style {
Style::effects(effects)
}
}
impl Effects {
pub fn new() -> Effects {
Default::default()
}
pub fn empty() -> Effects {
Effects::new()
}
pub fn only(effect: Effect) -> Effects {
Effects::from(effect)
}
pub fn set(&mut self, effect: Effect, set: bool) {
match effect {
Effect::Bold => self.is_bold = set,
Effect::Italic => self.is_italic = set,
Effect::Underline => self.is_underline = set,
Effect::Strikethrough => self.is_strikethrough = set,
}
}
pub fn is_set(&self, effect: Effect) -> bool {
match effect {
Effect::Bold => self.is_bold,
Effect::Italic => self.is_italic,
Effect::Underline => self.is_underline,
Effect::Strikethrough => self.is_strikethrough,
}
}
pub fn and(&self, other: Effects) -> Effects {
Effects {
is_bold: self.is_bold || other.is_bold,
is_italic: self.is_italic || other.is_italic,
is_underline: self.is_underline || other.is_underline,
is_strikethrough: self.is_strikethrough || other.is_strikethrough,
}
}
pub fn is_empty(&self) -> bool {
!self.is_bold && !self.is_italic && !self.is_underline && !self.is_strikethrough
}
}
impl std::iter::FromIterator<Effect> for Effects {
fn from_iter<I: IntoIterator<Item = Effect>>(iter: I) -> Effects {
let mut effects = Effects::new();
for effect in iter {
effects.set(effect, true);
}
effects
}
}
impl IntoIterator for Effects {
type Item = Effect;
type IntoIter = EffectsIter;
fn into_iter(self) -> EffectsIter {
EffectsIter::from(self)
}
}
impl From<Effect> for Effects {
fn from(effect: Effect) -> Effects {
let mut effects = Effects::new();
effects.set(effect, true);
effects
}
}
impl Iterator for EffectsIter {
type Item = Effect;
fn next(&mut self) -> Option<Effect> {
let mut next = None;
while let Some(effect) = EFFECTS.get(self.i) {
self.i += 1;
if self.effects.is_set(*effect) {
next = Some(*effect);
break;
}
}
next
}
}
impl From<Effects> for EffectsIter {
fn from(effects: Effects) -> EffectsIter {
EffectsIter { effects, i: 0 }
}
}
impl AnsiColor {
pub fn dark(self) -> Color {
Color::Ansi {
color: self,
mode: AnsiMode::Dark,
}
}
pub fn light(self) -> Color {
Color::Ansi {
color: self,
mode: AnsiMode::Light,
}
}
}