use lex_core::lex::ast::traits::AstNode;
use lex_core::lex::ast::{Annotation, ContentItem, Document};
fn item_key(item: &ContentItem) -> (usize, usize, usize) {
let r = item.range();
(r.start.line, r.start.column, r.span.start)
}
fn child_is_empty(item: &ContentItem) -> bool {
match item {
ContentItem::BlankLineGroup(_) => true,
ContentItem::Paragraph(p) => p.lines.iter().all(|l| match l {
ContentItem::TextLine(tl) => tl.content.as_string().trim().is_empty(),
_ => true,
}),
_ => false,
}
}
fn clean_annotation(ann: &mut Annotation) {
let has_real_body = ann.children.iter().any(|c| !child_is_empty(c));
if has_real_body {
process_stream(ann.children.as_mut_vec());
} else {
ann.children.as_mut_vec().clear();
}
}
pub fn inline_attached_annotations(doc: &mut Document) {
let mut doc_anns = std::mem::take(&mut doc.annotations);
doc_anns.append(&mut doc.root.annotations);
let children = doc.root.children.as_mut_vec();
for ann in doc_anns {
children.push(ContentItem::Annotation(ann));
}
process_stream(children);
}
fn route(
anns: &mut Vec<Annotation>,
lo: usize,
hi: usize,
children: &mut Vec<ContentItem>,
bubble: &mut Vec<Annotation>,
) {
for ann in std::mem::take(anns) {
if (lo..=hi).contains(&ann.location.start.line) {
children.push(ContentItem::Annotation(ann));
} else {
bubble.push(ann);
}
}
}
fn process_stream(items: &mut Vec<ContentItem>) {
let mut bubble: Vec<Annotation> = Vec::new();
for item in items.iter_mut() {
match item {
ContentItem::Session(s) => {
let (lo, hi) = (s.location.start.line, s.location.end.line);
route(
&mut s.annotations,
lo,
hi,
s.children.as_mut_vec(),
&mut bubble,
);
process_stream(s.children.as_mut_vec());
}
ContentItem::Definition(d) => {
let (lo, hi) = (d.location.start.line, d.location.end.line);
route(
&mut d.annotations,
lo,
hi,
d.children.as_mut_vec(),
&mut bubble,
);
process_stream(d.children.as_mut_vec());
}
ContentItem::ListItem(li) => {
let (lo, hi) = (li.location.start.line, li.location.end.line);
route(
&mut li.annotations,
lo,
hi,
li.children.as_mut_vec(),
&mut bubble,
);
process_stream(li.children.as_mut_vec());
}
ContentItem::List(l) => {
let (lo, hi) = (l.location.start.line, l.location.end.line);
route(
&mut l.annotations,
lo,
hi,
l.items.as_mut_vec(),
&mut bubble,
);
process_stream(l.items.as_mut_vec());
}
ContentItem::Paragraph(p) => bubble.append(&mut p.annotations),
ContentItem::VerbatimBlock(v) => bubble.append(&mut v.annotations),
_ => {}
}
}
for ann in bubble {
items.push(ContentItem::Annotation(ann));
}
for item in items.iter_mut() {
if let ContentItem::Annotation(a) = item {
clean_annotation(a);
}
}
let mixed_origin = items
.iter()
.any(|i| i.range().origin_path != items[0].range().origin_path);
if !items.is_empty() && !mixed_origin {
items.sort_by_key(item_key);
}
}