use super::text_format::TextFormat;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum BlockType {
#[default]
Paragraph,
Heading1,
Heading2,
Heading3,
Heading4,
Heading5,
Heading6,
Quote,
CodeBlock,
BulletList,
NumberedList,
HorizontalRule,
}
impl BlockType {
pub fn markdown_prefix(&self) -> &'static str {
match self {
BlockType::Paragraph => "",
BlockType::Heading1 => "# ",
BlockType::Heading2 => "## ",
BlockType::Heading3 => "### ",
BlockType::Heading4 => "#### ",
BlockType::Heading5 => "##### ",
BlockType::Heading6 => "###### ",
BlockType::Quote => "> ",
BlockType::CodeBlock => "```\n",
BlockType::BulletList => "- ",
BlockType::NumberedList => "1. ",
BlockType::HorizontalRule => "---",
}
}
}
#[derive(Clone, Debug)]
pub struct FormattedSpan {
pub text: String,
pub format: TextFormat,
}
impl FormattedSpan {
pub fn new(text: impl Into<String>) -> Self {
Self {
text: text.into(),
format: TextFormat::default(),
}
}
pub fn with_format(mut self, format: TextFormat) -> Self {
self.format = format;
self
}
}
#[derive(Clone, Debug)]
pub struct Block {
pub block_type: BlockType,
pub spans: Vec<FormattedSpan>,
pub language: Option<String>,
}
impl Block {
pub fn paragraph(text: impl Into<String>) -> Self {
Self {
block_type: BlockType::Paragraph,
spans: vec![FormattedSpan::new(text)],
language: None,
}
}
pub fn new(block_type: BlockType) -> Self {
Self {
block_type,
spans: vec![FormattedSpan::new("")],
language: None,
}
}
pub fn text(&self) -> String {
self.spans.iter().map(|s| s.text.as_str()).collect()
}
pub fn set_text(&mut self, text: impl Into<String>) {
self.spans = vec![FormattedSpan::new(text)];
}
pub fn len(&self) -> usize {
self.spans.iter().map(|s| s.text.len()).sum()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn to_markdown(&self) -> String {
let prefix = self.block_type.markdown_prefix();
let text = self.spans_to_markdown();
match self.block_type {
BlockType::CodeBlock => {
let lang = self.language.as_deref().unwrap_or("");
format!("```{}\n{}\n```", lang, text)
}
BlockType::HorizontalRule => "---".to_string(),
_ => format!("{}{}", prefix, text),
}
}
fn spans_to_markdown(&self) -> String {
self.spans
.iter()
.map(|span| {
let mut text = span.text.clone();
if span.format.code {
text = format!("`{}`", text);
}
if span.format.bold {
text = format!("**{}**", text);
}
if span.format.italic {
text = format!("*{}*", text);
}
if span.format.strikethrough {
text = format!("~~{}~~", text);
}
text
})
.collect()
}
}