mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Refactor building
This commit is contained in:
parent
321121c6c3
commit
f69c3fb1e5
@ -28,7 +28,7 @@ pub enum Behaviour {
|
|||||||
Supportive,
|
Supportive,
|
||||||
/// A node that destroys adjacent weak nodes.
|
/// A node that destroys adjacent weak nodes.
|
||||||
Destructive,
|
Destructive,
|
||||||
/// A node that does not interact at all with other node, having the
|
/// A node that does not interact at all with other nodes, having the
|
||||||
/// same effect as if it didn't exist.
|
/// same effect as if it didn't exist.
|
||||||
Ignorant,
|
Ignorant,
|
||||||
}
|
}
|
||||||
|
@ -322,8 +322,7 @@ impl<'a> Builder<'a> {
|
|||||||
|
|
||||||
if let Some(realized) = styles.show(self.world, content)? {
|
if let Some(realized) = styles.show(self.world, content)? {
|
||||||
let stored = self.scratch.content.alloc(realized);
|
let stored = self.scratch.content.alloc(realized);
|
||||||
self.accept(stored, styles)?;
|
return self.accept(stored, styles);
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.list.accept(content, styles) {
|
if self.list.accept(content, styles) {
|
||||||
@ -353,7 +352,9 @@ impl<'a> Builder<'a> {
|
|||||||
self.interrupt(Interruption::Page, styles, keep)?;
|
self.interrupt(Interruption::Page, styles, keep)?;
|
||||||
|
|
||||||
if let Some(doc) = &mut self.doc {
|
if let Some(doc) = &mut self.doc {
|
||||||
doc.accept(content, styles);
|
if doc.accept(content, styles) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We might want to issue a warning or error for content that wasn't
|
// We might want to issue a warning or error for content that wasn't
|
||||||
@ -402,20 +403,32 @@ impl<'a> Builder<'a> {
|
|||||||
styles: StyleChain<'a>,
|
styles: StyleChain<'a>,
|
||||||
keep: bool,
|
keep: bool,
|
||||||
) -> SourceResult<()> {
|
) -> SourceResult<()> {
|
||||||
if intr >= Interruption::List && !self.list.is_empty() {
|
if intr >= Interruption::List && !self.list.items.is_empty() {
|
||||||
mem::take(&mut self.list).finish(self)?;
|
let staged = mem::take(&mut self.list.staged);
|
||||||
|
let (list, styles) = mem::take(&mut self.list).finish();
|
||||||
|
let stored = self.scratch.content.alloc(list);
|
||||||
|
self.accept(stored, styles)?;
|
||||||
|
for (content, styles) in staged {
|
||||||
|
self.accept(content, styles)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if intr >= Interruption::Par && !self.par.is_empty() {
|
if intr >= Interruption::Par && !self.par.0.is_empty() {
|
||||||
mem::take(&mut self.par).finish(self);
|
let (par, styles) = mem::take(&mut self.par).finish();
|
||||||
|
let stored = self.scratch.content.alloc(par);
|
||||||
|
self.accept(stored, styles)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if intr >= Interruption::Page {
|
if let Some(doc) = &mut self.doc {
|
||||||
if let Some(doc) = &mut self.doc {
|
if intr >= Interruption::Page
|
||||||
if !self.flow.is_empty() || (doc.keep_next && keep) {
|
&& (!self.flow.0.is_empty() || (doc.keep_next && keep))
|
||||||
mem::take(&mut self.flow).finish(doc, styles);
|
{
|
||||||
}
|
let (flow, shared) = mem::take(&mut self.flow).finish();
|
||||||
doc.keep_next = !keep;
|
let styles =
|
||||||
|
if shared == StyleChain::default() { styles } else { shared };
|
||||||
|
let page = PageNode(flow).pack();
|
||||||
|
let stored = self.scratch.content.alloc(page);
|
||||||
|
self.accept(stored, styles)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,15 +456,19 @@ struct DocBuilder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DocBuilder<'a> {
|
impl<'a> DocBuilder<'a> {
|
||||||
fn accept(&mut self, content: &Content, styles: StyleChain<'a>) {
|
fn accept(&mut self, content: &Content, styles: StyleChain<'a>) -> bool {
|
||||||
if let Some(pagebreak) = content.downcast::<PagebreakNode>() {
|
if let Some(pagebreak) = content.downcast::<PagebreakNode>() {
|
||||||
self.keep_next = !pagebreak.weak;
|
self.keep_next = !pagebreak.weak;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(page) = content.downcast::<PageNode>() {
|
if let Some(page) = content.downcast::<PageNode>() {
|
||||||
self.pages.push(page.clone(), styles);
|
self.pages.push(page.clone(), styles);
|
||||||
self.keep_next = false;
|
self.keep_next = false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,32 +483,35 @@ impl Default for DocBuilder<'_> {
|
|||||||
struct FlowBuilder<'a>(BehavedBuilder<'a>, bool);
|
struct FlowBuilder<'a>(BehavedBuilder<'a>, bool);
|
||||||
|
|
||||||
impl<'a> FlowBuilder<'a> {
|
impl<'a> FlowBuilder<'a> {
|
||||||
fn accept(&mut self, content: &Content, styles: StyleChain<'a>) -> bool {
|
fn accept(&mut self, content: &'a Content, styles: StyleChain<'a>) -> bool {
|
||||||
let last_was_parbreak = std::mem::replace(&mut self.1, false);
|
|
||||||
|
|
||||||
if content.is::<ParbreakNode>() {
|
if content.is::<ParbreakNode>() {
|
||||||
self.1 = true;
|
self.1 = true;
|
||||||
return true;
|
return true;
|
||||||
} else if content.is::<VNode>() || content.is::<ColbreakNode>() {
|
}
|
||||||
|
|
||||||
|
let last_was_parbreak = self.1;
|
||||||
|
self.1 = false;
|
||||||
|
|
||||||
|
if content.is::<VNode>() || content.is::<ColbreakNode>() {
|
||||||
self.0.push(content.clone(), styles);
|
self.0.push(content.clone(), styles);
|
||||||
return true;
|
return true;
|
||||||
} else if content.has::<dyn LayoutBlock>() {
|
}
|
||||||
if !last_was_parbreak {
|
|
||||||
let tight = if let Some(node) = content.downcast::<ListNode>() {
|
|
||||||
node.tight
|
|
||||||
} else if let Some(node) = content.downcast::<EnumNode>() {
|
|
||||||
node.tight
|
|
||||||
} else if let Some(node) = content.downcast::<DescNode>() {
|
|
||||||
node.tight
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
if tight {
|
if content.has::<dyn LayoutBlock>() {
|
||||||
let leading = styles.get(ParNode::LEADING);
|
let is_tight_list = if let Some(node) = content.downcast::<ListNode>() {
|
||||||
let spacing = VNode::list_attach(leading.into());
|
node.tight
|
||||||
self.0.push(spacing.pack(), styles);
|
} else if let Some(node) = content.downcast::<EnumNode>() {
|
||||||
}
|
node.tight
|
||||||
|
} else if let Some(node) = content.downcast::<DescNode>() {
|
||||||
|
node.tight
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if !last_was_parbreak && is_tight_list {
|
||||||
|
let leading = styles.get(ParNode::LEADING);
|
||||||
|
let spacing = VNode::list_attach(leading.into());
|
||||||
|
self.0.push(spacing.pack(), styles);
|
||||||
}
|
}
|
||||||
|
|
||||||
let above = styles.get(BlockNode::ABOVE);
|
let above = styles.get(BlockNode::ABOVE);
|
||||||
@ -505,15 +525,9 @@ impl<'a> FlowBuilder<'a> {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(self, doc: &mut DocBuilder<'a>, styles: StyleChain<'a>) {
|
fn finish(self) -> (Content, StyleChain<'a>) {
|
||||||
let (flow, shared) = self.0.finish();
|
let (flow, shared) = self.0.finish();
|
||||||
let styles = if flow.is_empty() { styles } else { shared };
|
(FlowNode(flow).pack(), shared)
|
||||||
let node = PageNode(FlowNode(flow).pack());
|
|
||||||
doc.pages.push(node, styles);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.0.is_empty()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -522,7 +536,7 @@ impl<'a> FlowBuilder<'a> {
|
|||||||
struct ParBuilder<'a>(BehavedBuilder<'a>);
|
struct ParBuilder<'a>(BehavedBuilder<'a>);
|
||||||
|
|
||||||
impl<'a> ParBuilder<'a> {
|
impl<'a> ParBuilder<'a> {
|
||||||
fn accept(&mut self, content: &Content, styles: StyleChain<'a>) -> bool {
|
fn accept(&mut self, content: &'a Content, styles: StyleChain<'a>) -> bool {
|
||||||
if content.is::<SpaceNode>()
|
if content.is::<SpaceNode>()
|
||||||
|| content.is::<LinebreakNode>()
|
|| content.is::<LinebreakNode>()
|
||||||
|| content.is::<HNode>()
|
|| content.is::<HNode>()
|
||||||
@ -537,15 +551,9 @@ impl<'a> ParBuilder<'a> {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(self, parent: &mut Builder<'a>) {
|
fn finish(self) -> (Content, StyleChain<'a>) {
|
||||||
let (children, shared) = self.0.finish();
|
let (children, shared) = self.0.finish();
|
||||||
if !children.is_empty() {
|
(ParNode(children).pack(), shared)
|
||||||
parent.flow.accept(&ParNode(children).pack(), shared);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.0.is_empty()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,50 +573,34 @@ impl<'a> ListBuilder<'a> {
|
|||||||
&& (content.is::<SpaceNode>() || content.is::<ParbreakNode>())
|
&& (content.is::<SpaceNode>() || content.is::<ParbreakNode>())
|
||||||
{
|
{
|
||||||
self.staged.push((content, styles));
|
self.staged.push((content, styles));
|
||||||
} else if let Some(item) = content.downcast::<ListItem>() {
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(item) = content.downcast::<ListItem>() {
|
||||||
if self
|
if self
|
||||||
.items
|
.items
|
||||||
.items()
|
.items()
|
||||||
.next()
|
.next()
|
||||||
.map_or(false, |first| item.kind() != first.kind())
|
.map_or(true, |first| item.kind() == first.kind())
|
||||||
{
|
{
|
||||||
return false;
|
self.items.push(item.clone(), styles);
|
||||||
|
self.tight &= self.staged.drain(..).all(|(t, _)| !t.is::<ParbreakNode>());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.items.push(item.clone(), styles);
|
|
||||||
self.tight &= self.staged.drain(..).all(|(t, _)| !t.is::<ParbreakNode>());
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(self, parent: &mut Builder<'a>) -> SourceResult<()> {
|
fn finish(self) -> (Content, StyleChain<'a>) {
|
||||||
let (items, shared) = self.items.finish();
|
let (items, shared) = self.items.finish();
|
||||||
if let Some(item) = items.items().next() {
|
let item = items.items().next().unwrap();
|
||||||
let tight = self.tight;
|
let output = match item.kind() {
|
||||||
let content = match item.kind() {
|
LIST => ListNode::<LIST> { tight: self.tight, items }.pack(),
|
||||||
LIST => ListNode::<LIST> { tight, items }.pack(),
|
ENUM => ListNode::<ENUM> { tight: self.tight, items }.pack(),
|
||||||
ENUM => ListNode::<ENUM> { tight, items }.pack(),
|
DESC | _ => ListNode::<DESC> { tight: self.tight, items }.pack(),
|
||||||
DESC | _ => ListNode::<DESC> { tight, items }.pack(),
|
};
|
||||||
};
|
(output, shared)
|
||||||
|
|
||||||
let stored = parent.scratch.content.alloc(content);
|
|
||||||
parent.accept(stored, shared)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (content, styles) in self.staged {
|
|
||||||
parent.accept(content, styles)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.list.tight = true;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.items.is_empty()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user