Skip to content
Merged
24 changes: 24 additions & 0 deletions crates/typst-cnd/examples/inline_boxes_and_floats.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Paragraphs that only exist because a fragment body was realized, and the
// three ways that can go wrong: an inline `box` duplicating its enclosing
// paragraph, a deferred float being mistaken for one, and page furniture or
// a rendered pool entry becoming prose.
#set document(title: "Inline boxes and floats", author: "typst-cnd")
#set page(
width: 280pt,
height: 120pt,
margin: 20pt,
foreground: rotate(45deg, text(fill: luma(210), size: 24pt)[DRAFT STAMP]),
)
#set heading(numbering: "1.")

= Target section <sec>

A sentence with #box[see @sec], with #box[@smith2024], and with
#box[boxed#footnote[Note written inside a box.] tail] in it.
#place(bottom, float: true)[FLOATED BODY TEXT]
Filler prose after the float, long enough to push the float onto a page of
its own and to keep the two paragraphs apart.

= References

#bibliography("refs.yml", title: none)
47 changes: 47 additions & 0 deletions crates/typst-cnd/examples/layout_containers.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Text carried by layout-only containers: a `block`, a grid cell, a `place`,
// an inline `box`, and content produced by a user function. None of these
// wrappers is emitted as a node, so the paragraphs inside them are the only
// carrier of that text.

#set document(title: "Layout containers", author: "typst-cnd")

#set page(
paper: "a5",
margin: 1.5cm,
footer: context [RUNNING FOOTER · #counter(page).display()],
)

#let section(kicker, title) = {
block(spacing: 0.9em)[#text(weight: "bold")[#upper(kicker)]]
block(below: 1.1em)[#text(size: 18pt)[#title]]
}

#let card(title, items) = {
block(fill: luma(240), inset: 8pt, width: 100%)[
#text(weight: "bold")[#upper(title)]
#v(0.6em)
#for it in items {
block(spacing: 0.6em)[#it]
}
]
}

#let chip(body) = box(inset: (x: 6pt, y: 3pt), stroke: 0.5pt)[#body]

= Layout containers

#section("Kicker line", "Title inside a block")

A paragraph with #chip[FIRST CHIP] and #chip[SECOND CHIP] inline.

A paragraph where #chip[idem] repeats a word the sentence itself uses: idem.

#grid(
columns: (1fr, 1fr),
card("Left card", ("Left item one", "Left item two")),
card("Right card", ("Right item one", "Right item two")),
)

#place(bottom + left, block(width: 100%)[Placed punch line at the bottom.])

Hard break here: first line \ second line.
17 changes: 4 additions & 13 deletions crates/typst-cnd/src/bin/typst-cnd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,7 @@ fn run() -> SourceResult<()> {

fn compile_file(input: &std::path::Path, output: &std::path::Path) -> SourceResult<()> {
let world = world::CndWorld::new(input).map_err(|err| {
eco_vec![error!(
Span::detached(),
"failed to initialize world: {err}"
)]
eco_vec![error!(Span::detached(), "failed to initialize world: {err}")]
})?;

let warned = compile::<CndDocument>(&world);
Expand All @@ -60,17 +57,11 @@ fn compile_file(input: &std::path::Path, output: &std::path::Path) -> SourceResu
}

let document = warned.output?;
let cnd = cnd_from_document(
&document,
world::source_info(&world),
world::built_at_now(),
);
let cnd =
cnd_from_document(&document, world::source_info(&world), world::built_at_now());
let json = cnd_to_json(&cnd)?;
std::fs::write(output, json).map_err(|err| {
eco_vec![error!(
Span::detached(),
"failed to write output file: {err}"
)]
eco_vec![error!(Span::detached(), "failed to write output file: {err}")]
})?;

Ok(())
Expand Down
7 changes: 5 additions & 2 deletions crates/typst-cnd/src/cnd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
use typst_library::Category;
use typst_library::diag::SourceResult;
use typst_library::engine::Engine;
use typst_library::foundations::{Args, Construct, Content, Dict, Module, NativeFunc, Scope, Str, Value};
use typst_library::foundations::{
Args, Construct, Content, Dict, Module, NativeFunc, Scope, Str, Value,
};
use typst_library::introspection::{State, StateUpdate};
use typst_library::model::TableElem;

Expand Down Expand Up @@ -86,7 +88,8 @@ fn cnd_table(engine: &mut Engine, args: &mut Args) -> SourceResult<Content> {
};

let state = metadata_state();
let set_fn = cnd_set_content_kind::func().with(&mut Args::new(span, [Value::Str(kind)]));
let set_fn =
cnd_set_content_kind::func().with(&mut Args::new(span, [Value::Str(kind)]));
let unset_fn = cnd_unset_content_kind::func();

let before = state.clone().update(span, StateUpdate::Func(set_fn));
Expand Down
26 changes: 14 additions & 12 deletions crates/typst-cnd/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ use typst_library::introspection::Introspector;
use typst_library::model::{Document, DocumentInfo};
use typst_syntax::Span;

use crate::emit::ancestry::Ancestry;
use crate::emit::convert::{self, ConvertContext};
use crate::emit::{pools, refs};
use crate::location::LocationAssigner;
use crate::model::{BibEntry, CND_VERSION, Cnd, DocDate, DocMetadata, Footnote, SourceInfo};
use crate::model::{
BibEntry, CND_VERSION, Cnd, DocDate, DocMetadata, Footnote, SourceInfo,
};

/// A compiled CND document before JSON serialization.
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -68,12 +71,18 @@ impl Output for CndDocument {
let introspector = paged.introspector().clone();
let info = paged.info().clone();

// Containment is read off the laid-out frames: `Introspector::query`
// returns a flat list, but the emit pipeline must know which located
// elements sit inside a paragraph or inside page furniture.
let ancestry = Ancestry::from_document(&paged, engine);

let mut ctx = realize_and_convert(
engine,
introspector.as_ref(),
content,
styles,
&info,
&ancestry,
)?;
refs::rebuild_label_index(&mut ctx, introspector.as_ref());
convert::apply_metadata(&mut ctx);
Expand All @@ -96,13 +105,7 @@ impl Output for CndDocument {
let mut assigner = LocationAssigner::new(introspector.clone(), ctx.records);
assigner.assign_all(&mut nodes);

Ok(Self {
info,
nodes,
bibliography,
footnotes,
introspector,
})
Ok(Self { info, nodes, bibliography, footnotes, introspector })
}

fn introspector(&self) -> &dyn Introspector {
Expand All @@ -116,13 +119,15 @@ fn realize_and_convert(
_content: &Content,
styles: StyleChain,
info: &DocumentInfo,
ancestry: &Ancestry,
) -> SourceResult<ConvertContext> {
let mut ctx = ConvertContext::default();
crate::emit::convert::convert_from_introspector(
engine,
introspector,
styles,
doc_lang_from_info(info),
ancestry,
&mut ctx,
)?;
Ok(ctx)
Expand Down Expand Up @@ -201,9 +206,6 @@ fn datetime_to_doc_date(dt: Datetime) -> DocDate {
/// Serialize a CND to pretty JSON.
pub fn cnd_to_json(cnd: &Cnd) -> SourceResult<String> {
serde_json::to_string_pretty(cnd).map_err(|err| {
eco_vec![error!(
Span::detached(),
"failed to serialize CND: {err}"
)]
eco_vec![error!(Span::detached(), "failed to serialize CND: {err}")]
})
}
Loading
Loading