use nu_ansi_term::{Color, Style};
use reedline::{Highlighter, StyledText};
pub struct KeywordHighlighter {
keywords: Vec<String>,
keyword_style: Style,
neutral_style: Style,
}
impl KeywordHighlighter {
pub fn new(keywords: &[String], foreground: Color) -> Self {
Self {
keywords: keywords.to_vec(),
keyword_style: Style::default().fg(foreground).bold(),
neutral_style: Style::default(),
}
}
fn split_leading_whitespace<'a>(&self, line: &'a str) -> (&'a str, &'a str) {
let trimmed = line.trim_start();
let leading_ws_len = line.len() - trimmed.len();
line.split_at(leading_ws_len)
}
fn first_token<'a>(&self, content: &'a str) -> Option<&'a str> {
content.split_whitespace().next()
}
fn is_keyword(&self, token: &str) -> bool {
self.keywords.contains(&token.to_string())
}
}
impl Highlighter for KeywordHighlighter {
fn highlight(&self, line: &str, _cursor: usize) -> StyledText {
let mut styled = StyledText::new();
let (leading_ws, content) = self.split_leading_whitespace(line);
if let Some(token) = self.first_token(content) {
if self.is_keyword(token) {
let (_, rest) = content.split_at(token.len());
if !leading_ws.is_empty() {
styled.push((self.neutral_style, leading_ws.to_owned()));
}
styled.push((self.keyword_style, token.to_owned()));
if !rest.is_empty() {
styled.push((self.neutral_style, rest.to_owned()));
}
return styled;
}
}
styled.push((self.neutral_style, line.to_owned()));
styled
}
}