use bitflags::bitflags;
use std::collections::HashMap;
use crate::{
core::{Action, game_state::InternalKey},
utils::linguate,
};
#[derive(Debug, Clone, Default)]
pub struct Span {
pub action: Option<Action>,
pub content: String,
pub variant: SpanVariant,
pub modifiers: Modifier,
pub style: HashMap<String, String>,
pub classes: Vec<String>,
pub no_sim: bool,
}
#[derive(Debug, Default, Clone)]
pub enum SpanVariant {
#[default]
None,
Link,
Muted,
Secondary,
}
impl Span {
pub fn new(s: String) -> Self {
Self {
action: None,
content: s,
variant: SpanVariant::None,
modifiers: Modifier::empty(),
style: HashMap::new(),
classes: Vec::new(),
no_sim: false,
}
}
pub fn from_lingual(v: impl Into<Self>) -> Self {
v.into().lingual()
}
pub fn as_variant(mut self, variant: SpanVariant) -> Self {
self.variant = variant;
self
}
pub fn as_link(mut self) -> Self {
self.variant = SpanVariant::Link;
self
}
pub fn with_action(mut self, action: impl Into<Action>) -> Self {
self.action = Some(action.into());
self
}
pub fn lingual(mut self) -> Self {
self.content = linguate(&self.content);
self
}
pub fn with_text(mut self, text: String) -> Self {
self.content = text;
self
}
pub fn no_sim(mut self) -> Self {
self.no_sim = true;
self
}
pub fn sim(mut self) -> Self {
self.no_sim = false;
self
}
}
#[derive(Debug, Clone)]
pub struct Line {
pub spans: Vec<Span>,
}
impl Line {
pub fn new() -> Self {
Self { spans: Vec::new() }
}
pub fn content(&self) -> String {
let mut s = String::new();
for span in &self.spans {
s.push_str(&span.content)
}
s
}
pub fn from_lingual(v: impl Into<Self>) -> Self {
let mut ret = v.into();
for s in ret.spans.iter_mut() {
s.content = linguate(&s.content)
}
ret
}
pub fn from_iter<I: IntoIterator<Item = impl Into<Span>>>(iter: I) -> Self {
Self {
spans: iter.into_iter().map(|x| x.into()).collect(),
}
}
pub fn from_spans(spans: Vec<Span>) -> Self {
Self { spans }
}
pub fn from_interleaved_actions<const MASK: bool>(
key: InternalKey,
parts: Vec<String>,
) -> Self {
let mut spans = Vec::new();
for (i, part) in parts.into_iter().enumerate() {
if i % 2 == 1 {
if MASK {
spans.push(
Span::from_lingual(part)
.as_link()
.with_action(Action::SetBit(key.clone(), i as u8 / 2)),
);
} else {
let h: u64;
#[cfg(feature = "rand")]
{
h = const_fnv1a_hash::fnv1a_hash_str_64(&part);
}
#[cfg(not(feature = "rand"))]
{
h = (i / 2) as u64;
}
spans.push(
Span::from_lingual(part)
.as_link()
.with_action(Action::Set(key.clone(), h)),
);
}
} else {
spans.push(Span::from_lingual(part));
}
}
Line { spans }
}
}
bitflags! {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
pub struct Modifier: u16 {
const BOLD = 0b0000_0000_0001;
const DIM = 0b0000_0000_0010;
const ITALIC = 0b0000_0000_0100;
const UNDERLINE = 0b0000_0000_1000;
const SUPER_SCRIPT = 0b0000_0001_0000;
const SUBSCRIPT = 0b0000_0010_0000;
const REVERSED = 0b0000_0100_0000;
const HIDDEN = 0b0000_1000_0000;
const STRIKETHROUGH = 0b0001_0000_0000;
}
}
impl<'a> IntoIterator for &'a Line {
type Item = &'a Span;
type IntoIter = std::slice::Iter<'a, Span>;
fn into_iter(self) -> Self::IntoIter {
self.spans.iter()
}
}
impl<T: ToString> From<T> for Span {
fn from(s: T) -> Self {
Self::new(s.to_string())
}
}
impl From<&str> for Line {
fn from(item: &str) -> Self {
Line::from_iter(std::iter::once(item))
}
}
impl From<String> for Line {
fn from(item: String) -> Self {
Line::from_iter(std::iter::once(item))
}
}
impl From<Span> for Line {
fn from(item: Span) -> Self {
Line::from_iter(std::iter::once(item))
}
}
impl From<Vec<&str>> for Line {
fn from(items: Vec<&str>) -> Self {
Line::from_iter(items)
}
}
impl From<Vec<String>> for Line {
fn from(items: Vec<String>) -> Self {
Line::from_iter(items)
}
}
impl From<&[&str]> for Line {
fn from(items: &[&str]) -> Self {
Line::from_iter(items.iter().copied())
}
}
impl From<&[String]> for Line {
fn from(items: &[String]) -> Self {
Line::from_iter(items.iter().cloned())
}
}
impl<const N: usize> From<[&str; N]> for Line {
fn from(items: [&str; N]) -> Self {
Line::from_iter(items)
}
}
impl<const N: usize> From<[String; N]> for Line {
fn from(items: [String; N]) -> Self {
Line::from_iter(items)
}
}
impl<const N: usize> From<[Span; N]> for Line {
fn from(items: [Span; N]) -> Self {
Line::from_iter(items)
}
}