mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Fix pagebreak-in-box bug ✔
This commit is contained in:
parent
c3acb491e3
commit
1584b09708
@ -23,7 +23,7 @@ pub struct ExecContext<'a> {
|
|||||||
/// The tree of finished page runs.
|
/// The tree of finished page runs.
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
/// Metrics of the active page.
|
/// Metrics of the active page.
|
||||||
page: PageData,
|
page: Option<PageInfo>,
|
||||||
/// The content of the active stack. This may be the top-level stack for the
|
/// The content of the active stack. This may be the top-level stack for the
|
||||||
/// page or a lower one created by [`exec`](Self::exec).
|
/// page or a lower one created by [`exec`](Self::exec).
|
||||||
stack: NodeStack,
|
stack: NodeStack,
|
||||||
@ -38,7 +38,7 @@ impl<'a> ExecContext<'a> {
|
|||||||
env,
|
env,
|
||||||
diags: DiagSet::new(),
|
diags: DiagSet::new(),
|
||||||
tree: Tree { runs: vec![] },
|
tree: Tree { runs: vec![] },
|
||||||
page: PageData::new(&state, Softness::Hard),
|
page: Some(PageInfo::new(&state, Softness::Hard)),
|
||||||
stack: NodeStack::new(&state),
|
stack: NodeStack::new(&state),
|
||||||
par: NodePar::new(&state),
|
par: NodePar::new(&state),
|
||||||
state,
|
state,
|
||||||
@ -130,16 +130,18 @@ impl<'a> ExecContext<'a> {
|
|||||||
|
|
||||||
/// Execute a template and return the result as a stack node.
|
/// Execute a template and return the result as a stack node.
|
||||||
pub fn exec(&mut self, template: &ValueTemplate) -> NodeStack {
|
pub fn exec(&mut self, template: &ValueTemplate) -> NodeStack {
|
||||||
let prev_par = mem::replace(&mut self.par, NodePar::new(&self.state));
|
let page = self.page.take();
|
||||||
let prev_stack = mem::replace(&mut self.stack, NodeStack::new(&self.state));
|
let stack = mem::replace(&mut self.stack, NodeStack::new(&self.state));
|
||||||
|
let par = mem::replace(&mut self.par, NodePar::new(&self.state));
|
||||||
|
|
||||||
template.exec(self);
|
template.exec(self);
|
||||||
let stack = self.finish_stack();
|
let result = self.finish_stack();
|
||||||
|
|
||||||
self.par = prev_par;
|
self.page = page;
|
||||||
self.stack = prev_stack;
|
self.stack = stack;
|
||||||
|
self.par = par;
|
||||||
|
|
||||||
stack
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a text node from the given string based on the active text
|
/// Construct a text node from the given string based on the active text
|
||||||
@ -190,24 +192,30 @@ impl<'a> ExecContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Finish the active page.
|
/// Finish the active page.
|
||||||
pub fn finish_page(&mut self, keep: bool, new_softnes: Softness) {
|
pub fn finish_page(&mut self, keep: bool, new_softness: Softness, source: Span) {
|
||||||
let stack = self.finish_stack();
|
if let Some(info) = &mut self.page {
|
||||||
let data = mem::replace(&mut self.page, PageData::new(&self.state, new_softnes));
|
let info = mem::replace(info, PageInfo::new(&self.state, new_softness));
|
||||||
if !stack.children.is_empty() || (keep && data.softness == Softness::Hard) {
|
let stack = self.finish_stack();
|
||||||
self.tree.runs.push(NodePages {
|
|
||||||
size: data.size,
|
if !stack.children.is_empty() || (keep && info.softness == Softness::Hard) {
|
||||||
child: NodePad {
|
self.tree.runs.push(NodePages {
|
||||||
padding: data.padding,
|
size: info.size,
|
||||||
child: stack.into(),
|
child: NodePad {
|
||||||
}
|
padding: info.padding,
|
||||||
.into(),
|
child: stack.into(),
|
||||||
});
|
}
|
||||||
|
.into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.diag(error!(source, "cannot modify page from here"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish execution and return the created layout tree.
|
/// Finish execution and return the created layout tree.
|
||||||
pub fn finish(mut self) -> Pass<Tree> {
|
pub fn finish(mut self) -> Pass<Tree> {
|
||||||
self.finish_page(true, Softness::Soft);
|
assert!(self.page.is_some());
|
||||||
|
self.finish_page(true, Softness::Soft, Span::default());
|
||||||
Pass::new(self.tree, self.diags)
|
Pass::new(self.tree, self.diags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,13 +249,13 @@ fn trim(nodes: &mut Vec<Node>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct PageData {
|
struct PageInfo {
|
||||||
size: Size,
|
size: Size,
|
||||||
padding: Sides<Linear>,
|
padding: Sides<Linear>,
|
||||||
softness: Softness,
|
softness: Softness,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageData {
|
impl PageInfo {
|
||||||
fn new(state: &State, softness: Softness) -> Self {
|
fn new(state: &State, softness: Softness) -> Self {
|
||||||
Self {
|
Self {
|
||||||
size: state.page.size,
|
size: state.page.size,
|
||||||
|
@ -38,6 +38,7 @@ pub fn page(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
|||||||
let main = args.get(ctx, "main-dir");
|
let main = args.get(ctx, "main-dir");
|
||||||
let cross = args.get(ctx, "cross-dir");
|
let cross = args.get(ctx, "cross-dir");
|
||||||
let body = args.find::<ValueTemplate>(ctx);
|
let body = args.find::<ValueTemplate>(ctx);
|
||||||
|
let span = args.span;
|
||||||
|
|
||||||
Value::template("page", move |ctx| {
|
Value::template("page", move |ctx| {
|
||||||
let snapshot = ctx.state.clone();
|
let snapshot = ctx.state.clone();
|
||||||
@ -83,20 +84,21 @@ pub fn page(ctx: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.set_dirs(Gen::new(main, cross));
|
ctx.set_dirs(Gen::new(main, cross));
|
||||||
ctx.finish_page(false, Softness::Hard);
|
ctx.finish_page(false, Softness::Hard, span);
|
||||||
|
|
||||||
if let Some(body) = &body {
|
if let Some(body) = &body {
|
||||||
// TODO: Restrict body to a single page?
|
// TODO: Restrict body to a single page?
|
||||||
body.exec(ctx);
|
body.exec(ctx);
|
||||||
ctx.state = snapshot;
|
ctx.state = snapshot;
|
||||||
ctx.finish_page(true, Softness::Soft);
|
ctx.finish_page(true, Softness::Soft, span);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `pagebreak`: Start a new page.
|
/// `pagebreak`: Start a new page.
|
||||||
pub fn pagebreak(_: &mut EvalContext, _: &mut ValueArgs) -> Value {
|
pub fn pagebreak(_: &mut EvalContext, args: &mut ValueArgs) -> Value {
|
||||||
|
let span = args.span;
|
||||||
Value::template("pagebreak", move |ctx| {
|
Value::template("pagebreak", move |ctx| {
|
||||||
ctx.finish_page(true, Softness::Hard);
|
ctx.finish_page(true, Softness::Hard, span);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 3.2 KiB |
@ -21,3 +21,20 @@ Sometimes there is no box.
|
|||||||
#box(width: 0.5in, height: 10pt, color: #D6CD67)
|
#box(width: 0.5in, height: 10pt, color: #D6CD67)
|
||||||
#box(width: 0.5in, height: 10pt, color: #EDD466)
|
#box(width: 0.5in, height: 10pt, color: #EDD466)
|
||||||
#box(width: 0.5in, height: 10pt, color: #E3BE62)
|
#box(width: 0.5in, height: 10pt, color: #E3BE62)
|
||||||
|
|
||||||
|
---
|
||||||
|
// Make sure that you can't do page related stuff in a box.
|
||||||
|
A
|
||||||
|
#box[
|
||||||
|
B
|
||||||
|
// Error: 16 cannot modify page from here
|
||||||
|
#pagebreak()
|
||||||
|
|
||||||
|
// Error: 11-15 cannot modify page from here
|
||||||
|
#page("a4")
|
||||||
|
]
|
||||||
|
C
|
||||||
|
|
||||||
|
// No consequences from the page("A4") call here.
|
||||||
|
#pagebreak()
|
||||||
|
D
|
||||||
|
Loading…
x
Reference in New Issue
Block a user