use crate::ui::theme;
const FENCE: &str = "```";
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Part {
Prose(String),
Code(String),
}
pub fn parts(words: &str) -> Vec<Part> {
let mut out = Vec::new();
let mut held: Vec<&str> = Vec::new();
let mut fenced = false;
for line in words.lines() {
if line.trim_start().starts_with(FENCE) {
close(&mut out, &mut held, fenced);
fenced = !fenced;
} else {
held.push(line);
}
}
close(&mut out, &mut held, fenced);
out
}
fn close(out: &mut Vec<Part>, held: &mut Vec<&str>, fenced: bool) {
let text = held.join("\n");
held.clear();
if fenced {
out.push(Part::Code(text));
} else if !text.trim().is_empty() {
out.push(Part::Prose(text.trim_matches('\n').to_owned()));
}
}
pub fn paint(ui: &mut egui::Ui, at: usize, words: &str) {
for (n, part) in parts(words).into_iter().enumerate() {
match part {
Part::Prose(text) => {
theme::paint::prose(ui, &text, theme::INK);
}
Part::Code(text) => block(ui, (at, n), &text),
}
}
}
fn block(ui: &mut egui::Ui, salt: (usize, usize), text: &str) {
egui::Frame::none()
.fill(theme::SURFACE)
.rounding(theme::RADIUS)
.inner_margin(theme::space::S)
.show(ui, |ui| {
egui::ScrollArea::horizontal()
.id_salt(("code", salt))
.show(ui, |ui| {
ui.add(
egui::Label::new(egui::RichText::new(text).monospace().color(theme::INK))
.extend(),
);
});
});
}
#[cfg(test)]
mod tests;