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<String>,
text: AnsiString<'static>,
#[allow(clippy::box_vec)]
matching_ranges: Option<Box<Vec<(usize, usize)>>>,
}
impl<'a> DefaultSkimItem {
pub fn new(
orig_text: String,
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), transformed)
} else if using_transform_fields {
let transformed = parse_transform_fields(delimiter, &orig_text, trans_fields).into();
(Some(orig_text), transformed)
} else if ansi_enabled {
(None, ansi_parser.parse_ansi(&orig_text))
} else {
(None, orig_text.into())
};
let matching_ranges = if !matching_fields.is_empty() {
Some(Box::new(parse_matching_fields(
delimiter,
text.stripped(),
matching_fields,
)))
} 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> {
if self.orig_text.is_some() {
if self.text.has_attrs() {
let mut ansi_parser: ANSIParser = Default::default();
let text = ansi_parser.parse_ansi(self.orig_text.as_ref().unwrap());
text.into_inner()
} else {
Cow::Borrowed(self.orig_text.as_ref().unwrap())
}
} else {
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<'a>(&'a self, context: DisplayContext<'a>) -> AnsiString<'a> {
let new_fragments: Vec<(Attr, (u32, u32))> = match context.matches {
Matches::CharIndices(indices) => indices
.iter()
.map(|&idx| (context.highlight_attr, (idx as u32, idx as u32 + 1)))
.collect(),
Matches::CharRange(start, end) => vec![(context.highlight_attr, (start as u32, end as u32))],
Matches::ByteRange(start, end) => {
let ch_start = context.text[..start].chars().count();
let ch_end = ch_start + context.text[start..end].chars().count();
vec![(context.highlight_attr, (ch_start as u32, ch_end as u32))]
}
Matches::None => vec![],
};
let mut ret = self.text.clone();
ret.override_attrs(new_fragments);
ret
}
}