use crate::ansi::ANSIParser;
use crate::field::{parse_matching_fields, parse_transform_fields, FieldRange};
use crate::{AnsiString, DisplayContext, Matches, SkimItem};
use regex::Regex;
use std::borrow::Cow;
use tuikit::prelude::Attr;
#[derive(Debug)]
pub struct DefaultSkimItem {
orig_text: Option<Box<str>>,
text: AnsiString,
matching_ranges: Option<Box<[(usize, usize)]>>,
}
impl DefaultSkimItem {
pub fn new(
orig_text: &str,
ansi_enabled: bool,
trans_fields: &[FieldRange],
matching_fields: &[FieldRange],
delimiter: &Regex,
) -> Self {
let using_transform_fields = !trans_fields.is_empty();
let mut ansi_parser: ANSIParser = Default::default();
let (orig_text, text) = if using_transform_fields && ansi_enabled {
let transformed = ansi_parser.parse_ansi(&parse_transform_fields(delimiter, orig_text, trans_fields));
(Some(orig_text.into()), transformed)
} else if using_transform_fields {
let transformed = parse_transform_fields(delimiter, orig_text, trans_fields).into();
(Some(orig_text.into()), transformed)
} else {
(None, ansi_parser.parse_ansi(orig_text))
};
let matching_ranges = if !matching_fields.is_empty() {
Some(
parse_matching_fields(delimiter, text.stripped(), matching_fields)
.as_slice()
.into(),
)
} else {
None
};
DefaultSkimItem {
orig_text,
text,
matching_ranges,
}
}
}
impl SkimItem for DefaultSkimItem {
#[inline]
fn text(&self) -> Cow<str> {
Cow::Borrowed(self.text.stripped())
}
fn output(&self) -> Cow<str> {
match &self.orig_text {
Some(orig_text) if self.text.has_attrs() => {
let mut ansi_parser: ANSIParser = Default::default();
let text = ansi_parser.parse_ansi(orig_text);
Cow::Owned(text.into_inner().to_string())
}
Some(orig_text) => Cow::Borrowed(orig_text),
None => Cow::Borrowed(self.text.stripped()),
}
}
fn get_matching_ranges(&self) -> Option<&[(usize, usize)]> {
self.matching_ranges.as_ref().map(|vec| vec as &[(usize, usize)])
}
fn display(&self, context: DisplayContext) -> AnsiString {
let new_fragments: Vec<(Attr, (u32, u32))> = match context.matches {
Some(Matches::CharIndices(indices)) => indices
.iter()
.map(|&idx| (context.highlight_attr, (idx as u32, idx as u32 + 1)))
.collect(),
Some(Matches::CharRange(start, end)) => vec![(context.highlight_attr, (start as u32, end as u32))],
Some(Matches::ByteRange(start, end)) => {
let ch_start = context.text[..start].len();
let ch_end = ch_start + context.text[start..end].len();
vec![(context.highlight_attr, (ch_start as u32, ch_end as u32))]
}
None => vec![],
};
let mut ret = self.text.clone();
ret.override_attrs(new_fragments);
ret
}
}