bitflags::bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SgrFlags: u16 {
const UNDERLINE = 1 << 0;
const STRIKETHROUGH = 1 << 1;
const OVERLINE = 1 << 2;
const BOLD = 1 << 3;
const ITALIC = 1 << 4;
const FAINT = 1 << 5;
const INVERSE = 1 << 6;
const INVISIBLE = 1 << 7;
const BLINK = 1 << 8;
const BLINK_RAPID = 1 << 9;
const RESET = 1 << 10;
}
}
impl SgrFlags {
pub const DEFAULT: Self = Self::empty();
#[inline]
pub const fn decorations(self) -> StyleFlags {
StyleFlags::from_bits_truncate(self.bits() as u8)
}
}
impl From<i32> for SgrFlags {
fn from(code: i32) -> Self {
match code {
1 => Self::BOLD,
2 => Self::FAINT,
3 => Self::ITALIC,
4 | 21 => Self::UNDERLINE,
5 => Self::BLINK,
6 => Self::BLINK_RAPID,
7 => Self::INVERSE,
8 => Self::INVISIBLE,
9 => Self::STRIKETHROUGH,
53 => Self::OVERLINE,
22 => Self::BOLD | Self::FAINT | Self::RESET,
23 => Self::ITALIC | Self::RESET,
24 => Self::UNDERLINE | Self::RESET,
25 => Self::BLINK | Self::BLINK_RAPID | Self::RESET,
27 => Self::INVERSE | Self::RESET,
28 => Self::INVISIBLE | Self::RESET,
29 => Self::STRIKETHROUGH | Self::RESET,
55 => Self::OVERLINE | Self::RESET,
_ => Self::DEFAULT,
}
}
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct StyleFlags: u8 {
const UNDERLINE = 1 << 0;
const STRIKETHROUGH = 1 << 1;
const OVERLINE = 1 << 2;
const BOLD = 1 << 3;
const ITALIC = 1 << 4;
}
}
impl StyleFlags {}
const _: () = {
assert!(
StyleFlags::UNDERLINE.bits() == SgrFlags::UNDERLINE.bits() as u8,
"StyleFlags::UNDERLINE must mirror SgrFlags::UNDERLINE"
);
assert!(
StyleFlags::STRIKETHROUGH.bits() == SgrFlags::STRIKETHROUGH.bits() as u8,
"StyleFlags::STRIKETHROUGH must mirror SgrFlags::STRIKETHROUGH"
);
assert!(
StyleFlags::OVERLINE.bits() == SgrFlags::OVERLINE.bits() as u8,
"StyleFlags::OVERLINE must mirror SgrFlags::OVERLINE"
);
assert!(
StyleFlags::BOLD.bits() == SgrFlags::BOLD.bits() as u8,
"StyleFlags::BOLD must mirror SgrFlags::BOLD"
);
assert!(
StyleFlags::ITALIC.bits() == SgrFlags::ITALIC.bits() as u8,
"StyleFlags::ITALIC must mirror SgrFlags::ITALIC"
);
};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum UnderlineStyle {
#[default]
None = 0,
Single = 1,
Double = 2,
Curly = 3,
Dotted = 4,
Dashed = 5,
}
impl UnderlineStyle {
#[inline]
pub const fn from_u8(v: u8) -> Self {
match v {
0 => Self::None,
2 => Self::Double,
3 => Self::Curly,
4 => Self::Dotted,
5 => Self::Dashed,
_ => Self::Single,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
#[repr(u8)]
#[non_exhaustive]
pub enum CursorStyle {
#[default]
None = 0,
Block = 1,
Bar = 2,
Underline = 3,
}
impl CursorStyle {
pub fn parse(name: &str) -> Self {
match name.trim().to_ascii_lowercase().as_str() {
"block" => Self::Block,
"bar" | "beam" | "vertical" => Self::Bar,
"underline" | "underscore" => Self::Underline,
"none" | "off" | "hidden" => Self::None,
_ => Self::Bar,
}
}
#[inline]
pub const fn from_decscusr(param: i32) -> Self {
match param {
0..=2 => Self::Block,
3 | 4 => Self::Underline,
5 | 6 => Self::Bar,
_ => Self::None,
}
}
#[inline]
pub const fn from_osc(param: i32) -> Self {
match param {
0 => Self::Block,
1 => Self::Bar,
2 => Self::Underline,
_ => Self::None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cursor_style_from_decscusr() {
assert_eq!(CursorStyle::from_decscusr(0), CursorStyle::Block);
assert_eq!(CursorStyle::from_decscusr(2), CursorStyle::Block);
assert_eq!(CursorStyle::from_decscusr(3), CursorStyle::Underline);
assert_eq!(CursorStyle::from_decscusr(4), CursorStyle::Underline);
assert_eq!(CursorStyle::from_decscusr(5), CursorStyle::Bar);
assert_eq!(CursorStyle::from_decscusr(6), CursorStyle::Bar);
assert_eq!(CursorStyle::from_decscusr(7), CursorStyle::None);
}
#[test]
fn cursor_style_parse() {
assert_eq!(CursorStyle::parse("block"), CursorStyle::Block);
assert_eq!(CursorStyle::parse("BAR"), CursorStyle::Bar);
assert_eq!(CursorStyle::parse("beam"), CursorStyle::Bar);
assert_eq!(CursorStyle::parse("underline"), CursorStyle::Underline);
assert_eq!(CursorStyle::parse("none"), CursorStyle::None);
assert_eq!(CursorStyle::parse("hidden"), CursorStyle::None);
assert_eq!(CursorStyle::parse("garbage"), CursorStyle::Bar);
}
}