use super::build_regex;
use memchr::memchr;
use regex::Regex;
use crate::core::config::KeyValueConfig;
use super::super::palette::{Palette, StyleId};
use super::super::span::{Collector, Finder};
#[derive(Debug, Clone)]
pub(crate) struct KeyValueFinder {
regex: Regex,
key: StyleId,
separator: StyleId,
}
impl KeyValueFinder {
pub fn new(config: KeyValueConfig, palette: &mut Palette) -> Self {
let pattern = r"(?:^|\s)\w+\b=";
let regex = build_regex(pattern);
Self {
regex,
key: palette.intern(config.key),
separator: palette.intern(config.separator),
}
}
}
impl Finder for KeyValueFinder {
fn find_spans(&self, input: &str, collector: &mut Collector) {
if memchr(b'=', input.as_bytes()).is_none() {
return;
}
for m in self.regex.find_iter(input) {
let bytes = m.as_str().as_bytes();
let skip = usize::from(bytes[0].is_ascii_whitespace());
let s = m.start() + skip;
collector.push(s, m.end() - 1, self.key);
collector.push(m.end() - 1, m.end(), self.separator);
}
}
}
#[cfg(test)]
mod tests {
use super::super::span_texts;
use super::*;
use crate::style::{Color, Style};
fn make_finder() -> KeyValueFinder {
KeyValueFinder::new(
KeyValueConfig {
key: Style::new().fg(Color::Red),
separator: Style::new().fg(Color::Yellow),
},
&mut Palette::new(),
)
}
#[test]
fn basic_key_value() {
let texts = span_texts("Entry key=value", &make_finder());
assert_eq!(texts, ["key", "="]);
}
#[test]
fn multiple_key_values() {
let texts = span_texts("host=localhost port=8080", &make_finder());
assert_eq!(texts, ["host", "=", "port", "="]);
}
#[test]
fn key_value_at_start_of_line() {
let texts = span_texts("key=value", &make_finder());
assert_eq!(texts, ["key", "="]);
}
#[test]
fn no_key_value_no_match() {
assert!(span_texts("No numbers here!", &make_finder()).is_empty());
}
}