first commit
This commit is contained in:
45
cracked_md/src/parser/block.rs
Normal file
45
cracked_md/src/parser/block.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use crate::ast::Block;
|
||||
|
||||
use super::inline::parse_inlines;
|
||||
|
||||
pub fn parse_blocks(input: &str) -> Vec<Block> {
|
||||
let mut blocks = Vec::new();
|
||||
|
||||
let mut lines = input.lines().peekable();
|
||||
|
||||
while let Some(line) = lines.next() {
|
||||
if line.starts_with("#") {
|
||||
let level = line.chars().take_while(|&c| c == '#').count() as u8;
|
||||
let text = line[level as usize..].trim();
|
||||
blocks.push(Block::Heading {
|
||||
level,
|
||||
content: parse_inlines(text),
|
||||
});
|
||||
} else if let Some(quote_body) = line.strip_prefix(">") {
|
||||
let quote_blocks = parse_blocks(quote_body);
|
||||
blocks.push(Block::Quote(quote_blocks));
|
||||
} else if line.starts_with("```") {
|
||||
let lang_line = line.strip_prefix("```").unwrap().to_string();
|
||||
let lang = if lang_line.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(lang_line)
|
||||
};
|
||||
let mut code = String::new();
|
||||
while lines.peek().is_some() && !lines.peek().unwrap().starts_with("```") {
|
||||
code.push_str(&format!("{}\n", lines.next().unwrap()));
|
||||
}
|
||||
lines.next();
|
||||
blocks.push(Block::Code {
|
||||
language: lang,
|
||||
content: code,
|
||||
});
|
||||
} else if line.trim().is_empty() {
|
||||
continue;
|
||||
} else {
|
||||
blocks.push(Block::Paragraph(parse_inlines(line)));
|
||||
}
|
||||
}
|
||||
|
||||
blocks
|
||||
}
|
||||
61
cracked_md/src/parser/inline.rs
Normal file
61
cracked_md/src/parser/inline.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
use crate::ast::Inline;
|
||||
|
||||
pub fn parse_inlines(input: &str) -> Vec<Inline> {
|
||||
let mut inlines = Vec::new();
|
||||
let mut chars = input.chars().peekable();
|
||||
|
||||
while let Some(c) = chars.next() {
|
||||
match c {
|
||||
'*' => {
|
||||
let inner = collect_until(&mut chars, '*');
|
||||
inlines.push(Inline::Bold(parse_inlines(&inner)));
|
||||
}
|
||||
'_' => {
|
||||
let inner = collect_until(&mut chars, '_');
|
||||
inlines.push(Inline::Italic(parse_inlines(&inner)));
|
||||
}
|
||||
'`' => {
|
||||
let code = collect_until(&mut chars, '`');
|
||||
inlines.push(Inline::Code(code));
|
||||
}
|
||||
'[' => {
|
||||
let text = collect_until(&mut chars, ']');
|
||||
if chars.next() == Some('(') {
|
||||
let href = collect_until(&mut chars, ')');
|
||||
inlines.push(Inline::Link {
|
||||
text: parse_inlines(&text),
|
||||
href,
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let mut text = String::new();
|
||||
text.push(c);
|
||||
while let Some(&nc) = chars.peek() {
|
||||
if matches!(nc, '*' | '_' | '`' | '[') {
|
||||
break;
|
||||
}
|
||||
text.push(chars.next().unwrap());
|
||||
}
|
||||
inlines.push(Inline::Text(text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inlines
|
||||
}
|
||||
|
||||
fn collect_until<I: Iterator<Item = char>>(
|
||||
chars: &mut std::iter::Peekable<I>,
|
||||
end: char,
|
||||
) -> String {
|
||||
let mut s = String::new();
|
||||
while let Some(&c) = chars.peek() {
|
||||
if c == end {
|
||||
chars.next();
|
||||
break;
|
||||
}
|
||||
s.push(chars.next().unwrap());
|
||||
}
|
||||
s
|
||||
}
|
||||
Reference in New Issue
Block a user