use crate::options::ParserOptions;
use crate::syntax::SyntaxKind;
use rowan::GreenNodeBuilder;
use crate::parser::utils::helpers::strip_newline;
use crate::parser::utils::inline_emission;
pub fn try_parse_line_block_start(line: &str) -> Option<()> {
let trimmed = line.trim_start();
if trimmed.starts_with("| ") || trimmed == "|" {
Some(())
} else {
None
}
}
pub fn parse_line_block(
lines: &[&str],
start_pos: usize,
builder: &mut GreenNodeBuilder<'static>,
config: &ParserOptions,
) -> usize {
log::debug!("Parsing line block at line {}", start_pos + 1);
builder.start_node(SyntaxKind::LINE_BLOCK.into());
let mut pos = start_pos;
while pos < lines.len() {
let line = lines[pos];
if let Some(content_start) = parse_line_block_line_marker(line) {
builder.start_node(SyntaxKind::LINE_BLOCK_LINE.into());
builder.token(SyntaxKind::LINE_BLOCK_MARKER.into(), &line[..content_start]);
let content = &line[content_start..];
let (content_without_newline, newline_str) = strip_newline(content);
if !content_without_newline.is_empty() {
inline_emission::emit_inlines(builder, content_without_newline, config);
}
if !newline_str.is_empty() {
builder.token(SyntaxKind::NEWLINE.into(), newline_str);
}
builder.finish_node(); pos += 1;
while pos < lines.len() {
let next_line = lines[pos];
if next_line.starts_with(' ') && !next_line.trim_start().starts_with("| ") {
builder.start_node(SyntaxKind::LINE_BLOCK_LINE.into());
let (line_without_newline, newline_str) = strip_newline(next_line);
if !line_without_newline.is_empty() {
inline_emission::emit_inlines(builder, line_without_newline, config);
}
if !newline_str.is_empty() {
builder.token(SyntaxKind::NEWLINE.into(), newline_str);
}
builder.finish_node(); pos += 1;
} else {
break;
}
}
} else {
break;
}
}
builder.finish_node();
log::debug!("Parsed line block: lines {}-{}", start_pos + 1, pos);
pos
}
fn parse_line_block_line_marker(line: &str) -> Option<usize> {
let trimmed_start = line.len() - line.trim_start().len();
let after_indent = &line[trimmed_start..];
if after_indent.starts_with("| ") {
Some(trimmed_start + 2) } else if after_indent == "|" || after_indent == "|\n" {
Some(trimmed_start + 1) } else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_try_parse_line_block_start() {
assert!(try_parse_line_block_start("| Some text").is_some());
assert!(try_parse_line_block_start("| ").is_some());
assert!(try_parse_line_block_start("|").is_some()); assert!(try_parse_line_block_start(" | Some text").is_some());
assert!(try_parse_line_block_start("|No space").is_none());
assert!(try_parse_line_block_start("Regular text").is_none());
assert!(try_parse_line_block_start("").is_none());
}
#[test]
fn test_parse_line_block_marker() {
assert_eq!(parse_line_block_line_marker("| Some text"), Some(2));
assert_eq!(parse_line_block_line_marker("| "), Some(2));
assert_eq!(parse_line_block_line_marker("|"), Some(1)); assert_eq!(parse_line_block_line_marker(" | Indented"), Some(4));
assert_eq!(parse_line_block_line_marker("|No space"), None);
assert_eq!(parse_line_block_line_marker("Regular"), None);
}
#[test]
fn test_simple_line_block() {
let input = vec!["| Line one", "| Line two", "| Line three"];
let mut builder = GreenNodeBuilder::new();
let new_pos = parse_line_block(&input, 0, &mut builder, &ParserOptions::default());
assert_eq!(new_pos, 3);
}
#[test]
fn test_line_block_with_continuation() {
let input = vec![
"| This is a long line",
" that continues here",
"| Second line",
];
let mut builder = GreenNodeBuilder::new();
let new_pos = parse_line_block(&input, 0, &mut builder, &ParserOptions::default());
assert_eq!(new_pos, 3);
}
#[test]
fn test_line_block_with_indentation() {
let input = vec!["| First line", "| Indented line", "| Back to normal"];
let mut builder = GreenNodeBuilder::new();
let new_pos = parse_line_block(&input, 0, &mut builder, &ParserOptions::default());
assert_eq!(new_pos, 3);
}
#[test]
fn test_line_block_stops_at_non_line_block() {
let input = vec!["| Line one", "| Line two", "Regular paragraph"];
let mut builder = GreenNodeBuilder::new();
let new_pos = parse_line_block(&input, 0, &mut builder, &ParserOptions::default());
assert_eq!(new_pos, 2); }
}