use brink_syntax::ast::{self, AstNode};
use crate::Block;
use super::super::backbone::{BranchChild, classify_branch_child};
use super::super::choice::LowerChoice;
use super::super::content::{ContentAccumulator, HandleResult};
use super::super::context::{LowerScope, LowerSink, Lowered};
use super::LowerBlock;
use super::weave::WeaveBackend;
impl LowerBlock for ast::MultilineBranchBody {
fn lower_block(&self, scope: &LowerScope, sink: &mut impl LowerSink) -> Lowered<Block> {
Ok(lower_branch_body_from_syntax(self.syntax(), scope, sink))
}
}
pub fn lower_branch_body(
body: &brink_syntax::SyntaxNode,
scope: &LowerScope,
sink: &mut impl LowerSink,
) -> Block {
lower_branch_body_from_syntax(body, scope, sink)
}
fn lower_branch_body_from_syntax(
body: &brink_syntax::SyntaxNode,
scope: &LowerScope,
sink: &mut impl LowerSink,
) -> Block {
let mut acc = ContentAccumulator::new(WeaveBackend::new());
let mut pending_ws: Option<String> = None;
let mut seen_content = false;
let mut after_content_block = false;
for child in body.children_with_tokens() {
match classify_branch_child(&child) {
BranchChild::ContentLine(cl) => {
pending_ws = None;
acc.handle(&cl, scope, sink);
}
BranchChild::LogicLine(ll) => {
pending_ws = None;
acc.handle(&ll, scope, sink);
}
BranchChild::TagLine(tl) => {
pending_ws = None;
acc.handle(&tl, scope, sink);
}
BranchChild::DivertNode(dn) => {
pending_ws = None;
acc.handle(&dn, scope, sink);
}
BranchChild::InlineLogic(il) => match acc.handle(&il, scope, sink) {
HandleResult::Block => {
pending_ws = None;
after_content_block = true;
}
HandleResult::Inline => {
if let Some(ws) = pending_ws.take() {
acc.push_text(ws);
}
seen_content = true;
}
},
BranchChild::Text(t) => {
if let Some(ws) = pending_ws.take() {
acc.push_text(ws);
}
seen_content = true;
acc.push_text(t);
}
BranchChild::Glue => {
if let Some(ws) = pending_ws.take() {
acc.push_text(ws);
}
seen_content = true;
acc.push_glue();
}
BranchChild::Escape(t) => {
if let Some(ws) = pending_ws.take() {
acc.push_text(ws);
}
seen_content = true;
acc.push_escape(&t);
}
BranchChild::Choice(c) => {
pending_ws = None;
acc.flush();
let depth = c.bullets().map_or(1, |b| b.depth());
if let Ok(choice) = c.lower_choice(scope, sink) {
acc.backend_mut().push_choice(choice, depth);
}
}
BranchChild::Trivia => {}
BranchChild::Stop => break,
BranchChild::Newline => {
if acc.has_buffered_parts() {
let ends_glue = acc.ends_with_glue();
acc.flush();
if !ends_glue {
acc.push_eol();
}
} else if after_content_block {
acc.push_eol();
}
seen_content = false;
pending_ws = None;
after_content_block = false;
}
BranchChild::Whitespace(ws) => {
if seen_content {
if let Some(ref mut existing) = pending_ws {
existing.push_str(&ws);
} else {
pending_ws = Some(ws);
}
}
}
}
}
if acc.has_buffered_parts() {
let ends_glue = acc.ends_with_glue();
acc.flush();
if !ends_glue {
acc.push_eol();
}
}
acc.finish()
}