use crate::color_utils;
use crate::model::parser::{SyntaxType, tokenize_smart_input};
use iced::advanced::text::highlighter::{self, Highlighter};
use iced::{Color, Font};
use std::ops::Range;
pub struct SmartInputHighlighter {
is_dark: bool,
is_search: bool,
}
impl Default for SmartInputHighlighter {
fn default() -> Self {
Self {
is_dark: true,
is_search: false,
} }
}
impl Highlighter for SmartInputHighlighter {
type Settings = (bool, bool); type Highlight = highlighter::Format<Font>;
type Iterator<'a> = std::vec::IntoIter<(Range<usize>, Self::Highlight)>;
fn new(settings: &Self::Settings) -> Self {
Self {
is_dark: settings.0,
is_search: settings.1,
}
}
fn update(&mut self, settings: &Self::Settings) {
self.is_dark = settings.0;
self.is_search = settings.1;
}
fn highlight_line(&mut self, line: &str) -> Self::Iterator<'_> {
let tokens = tokenize_smart_input(line, self.is_search);
let spans: Vec<(Range<usize>, Self::Highlight)> = tokens
.into_iter()
.map(|t| {
let format = match t.kind {
SyntaxType::Priority => {
let text = &line[t.start..t.end];
let p = text.trim_start_matches('!').parse::<u8>().unwrap_or(0);
let (r, g, b) = color_utils::get_priority_rgb(p, self.is_dark);
highlighter::Format {
color: Some(Color::from_rgb(r, g, b)),
font: Some(Font {
weight: iced::font::Weight::Bold,
..Default::default()
}),
}
}
SyntaxType::DueDate => highlighter::Format {
color: Some(Color::from_rgb(0.2, 0.6, 1.0)),
font: None,
},
SyntaxType::StartDate => highlighter::Format {
color: Some(Color::from_rgb(0.4, 0.8, 0.4)),
font: None,
},
SyntaxType::Recurrence => highlighter::Format {
color: Some(Color::from_rgb(0.8, 0.4, 0.8)),
font: None,
},
SyntaxType::Duration => highlighter::Format {
color: Some(Color::from_rgb(0.6, 0.6, 0.6)),
font: None,
},
SyntaxType::Tag => {
let text = &line[t.start..t.end];
let tag_name = text.trim_start_matches('#');
let (r, g, b) = color_utils::generate_color(tag_name);
highlighter::Format {
color: Some(Color::from_rgb(r, g, b)),
font: Some(Font {
weight: iced::font::Weight::Bold,
..Default::default()
}),
}
}
SyntaxType::Text => highlighter::Format {
color: None,
font: None,
},
SyntaxType::Location => highlighter::Format {
color: Some(Color::from_rgb(0.8, 0.5, 0.0)),
font: None,
},
SyntaxType::Url => highlighter::Format {
color: Some(Color::from_rgb(0.2, 0.2, 0.8)),
font: None,
},
SyntaxType::Geo => highlighter::Format {
color: Some(Color::from_rgb(0.5, 0.5, 0.5)),
font: None,
},
SyntaxType::Description => highlighter::Format {
color: Some(Color::from_rgb(0.6, 0.0, 0.6)),
font: None,
},
SyntaxType::Reminder => highlighter::Format {
color: Some(Color::from_rgb(1.0, 0.4, 0.0)),
font: Some(Font {
weight: iced::font::Weight::Bold,
..Default::default()
}),
},
SyntaxType::Filter => highlighter::Format {
color: Some(Color::from_rgb(0.0, 0.8, 0.8)), font: None,
},
SyntaxType::Operator => highlighter::Format {
color: Some(Color::from_rgb(1.0, 0.0, 1.0)), font: Some(Font {
weight: iced::font::Weight::Bold,
..Default::default()
}),
},
SyntaxType::Calendar => highlighter::Format {
color: Some(Color::from_rgb(0.91, 0.11, 0.38)), font: Some(Font {
weight: iced::font::Weight::Bold,
..Default::default()
}),
},
};
(t.start..t.end, format)
})
.collect();
spans.into_iter()
}
fn change_line(&mut self, _line: usize) {}
fn current_line(&self) -> usize {
0
}
}
pub struct SessionHighlighter {
is_dark: bool,
}
impl Default for SessionHighlighter {
fn default() -> Self {
Self { is_dark: true }
}
}
impl Highlighter for SessionHighlighter {
type Settings = bool;
type Highlight = highlighter::Format<Font>;
type Iterator<'a> = std::vec::IntoIter<(Range<usize>, Self::Highlight)>;
fn new(settings: &Self::Settings) -> Self {
Self { is_dark: *settings }
}
fn update(&mut self, settings: &Self::Settings) {
self.is_dark = *settings;
}
fn change_line(&mut self, _line: usize) {}
fn current_line(&self) -> usize {
0
}
fn highlight_line(&mut self, line: &str) -> Self::Iterator<'_> {
let mut spans = Vec::new();
let mut cursor = 0;
for word in line.split_whitespace() {
let start = line[cursor..].find(word).unwrap() + cursor;
let end = start + word.len();
if start > cursor {
spans.push((
cursor..start,
highlighter::Format {
color: None,
font: None,
},
));
}
let lower = word.to_lowercase();
let format = if crate::model::parser::parse_duration(&lower).is_some() {
highlighter::Format {
color: Some(Color::from_rgb(0.6, 0.6, 0.6)),
font: None,
}
} else if lower == "today"
|| lower == "yesterday"
|| chrono::NaiveDate::parse_from_str(&lower, "%Y-%m-%d").is_ok()
{
highlighter::Format {
color: Some(Color::from_rgb(0.2, 0.6, 1.0)),
font: None,
}
} else if lower.contains(':') && (lower.contains('-') || lower.len() <= 5) {
highlighter::Format {
color: Some(Color::from_rgb(0.4, 0.8, 0.4)),
font: None,
}
} else {
highlighter::Format {
color: None,
font: None,
}
};
spans.push((start..end, format));
cursor = end;
}
if cursor < line.len() {
spans.push((
cursor..line.len(),
highlighter::Format {
color: None,
font: None,
},
));
}
spans.into_iter()
}
}