use pulldown_cmark::{Event, Parser, Tag};
use ratatui::style::Style;
use super::{inline::find_highlight_end, options};
use crate::markdown::StyleSheet;
pub(crate) fn style_overlay(src: &str, sheet: &StyleSheet) -> Vec<Style> {
let offsets: Vec<usize> =
src.char_indices().map(|(byte, _)| byte).collect();
let char_count = offsets.len();
let mut base = Style::default();
if let Some(fg) = sheet.base.fg {
base = base.fg(fg);
}
let mut styles = vec![base; char_count];
if char_count == 0 {
return styles;
}
for (event, range) in
Parser::new_ext(src, options(false)).into_offset_iter()
{
let style = match &event {
Event::Start(Tag::Heading { level, .. }) => {
Some(sheet.heading_char_style(*level))
}
Event::Start(Tag::Strong) => Some(sheet.strong),
Event::Start(Tag::Emphasis) => Some(sheet.emphasis),
Event::Start(Tag::Strikethrough) => Some(sheet.strikethrough),
Event::Start(Tag::Link { .. } | Tag::Image { .. }) => {
Some(sheet.link)
}
Event::Start(Tag::BlockQuote(Some(kind))) => {
Some(sheet.callout.get(*kind).char_style())
}
Event::Start(Tag::BlockQuote(None)) => {
Some(sheet.quote_char_style())
}
Event::Start(Tag::CodeBlock(_)) => {
Some(sheet.code_block.char_style())
}
Event::Code(_) => Some(sheet.inline_code),
_ => None,
};
if let Some(style) = style {
patch_byte_range(&mut styles, &offsets, range, style);
}
}
for (start, end) in highlight_char_ranges(src) {
for cell in &mut styles[start..end.min(char_count)] {
*cell = cell.patch(sheet.highlight);
}
}
styles
}
fn patch_byte_range(
styles: &mut [Style],
offsets: &[usize],
range: std::ops::Range<usize>,
style: Style,
) {
let len = styles.len();
let start = offsets.partition_point(|&byte| byte < range.start);
let end = offsets.partition_point(|&byte| byte < range.end).min(len);
for cell in &mut styles[start..end] {
*cell = cell.patch(style);
}
}
fn highlight_char_ranges(src: &str) -> Vec<(usize, usize)> {
let chars: Vec<char> = src.chars().collect();
let mut out = Vec::new();
let mut i = 0;
while i < chars.len() {
if chars[i] == '='
&& i + 1 < chars.len()
&& chars[i + 1] == '='
&& let Some(end) = find_highlight_end(&chars, i + 2)
{
out.push((i, end + 2));
i = end + 2;
continue;
}
i += 1;
}
out
}