Skip to main content

panache_parser/parser/blocks/
blockquotes.rs

1//! Blockquote parsing utilities.
2//!
3//! Re-exports marker parsing functions from marker_utils for backward compatibility.
4
5use crate::syntax::SyntaxKind;
6use rowan::GreenNodeBuilder;
7
8use crate::parser::utils::container_stack::{Container, ContainerStack};
9
10pub(crate) use crate::parser::utils::marker_utils::{
11    count_blockquote_markers, try_parse_blockquote_marker,
12};
13
14/// Check if we need a blank line before starting a new blockquote.
15/// Returns true if a blockquote can start here.
16pub(in crate::parser) fn can_start_blockquote(pos: usize, lines: &[&str]) -> bool {
17    // At start of document, no blank line needed
18    if pos == 0 {
19        return true;
20    }
21    // After a blank line, can start blockquote
22    if pos > 0 && lines[pos - 1].trim().is_empty() {
23        return true;
24    }
25    // If we're already in a blockquote, nested blockquotes need blank line too
26    // (blank_before_blockquote extension)
27    false
28}
29
30/// Get the current blockquote depth from the container stack.
31pub(in crate::parser) fn current_blockquote_depth(containers: &ContainerStack) -> usize {
32    containers
33        .stack
34        .iter()
35        .filter(|c| matches!(c, Container::BlockQuote { .. }))
36        .count()
37}
38
39/// Strip exactly n blockquote markers from a line, returning the rest.
40pub(in crate::parser) fn strip_n_blockquote_markers(line: &str, n: usize) -> &str {
41    let mut remaining = line;
42    for _ in 0..n {
43        if let Some((_, content_start)) = try_parse_blockquote_marker(remaining) {
44            remaining = &remaining[content_start..];
45        } else {
46            break;
47        }
48    }
49    remaining
50}
51
52/// Emit one blockquote marker with its whitespace.
53pub(in crate::parser) fn emit_one_blockquote_marker(
54    builder: &mut GreenNodeBuilder<'static>,
55    leading_spaces: usize,
56    has_trailing_space: bool,
57) {
58    if leading_spaces > 0 {
59        builder.token(SyntaxKind::WHITESPACE.into(), &" ".repeat(leading_spaces));
60    }
61    builder.token(SyntaxKind::BLOCK_QUOTE_MARKER.into(), ">");
62    if has_trailing_space {
63        builder.token(SyntaxKind::WHITESPACE.into(), " ");
64    }
65}