mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Split up styled and sequence template
This commit is contained in:
parent
a7b403fd74
commit
d3ccd55d4b
@ -183,17 +183,18 @@ fn eval_markup(
|
|||||||
nodes: &mut impl Iterator<Item = MarkupNode>,
|
nodes: &mut impl Iterator<Item = MarkupNode>,
|
||||||
) -> TypResult<Template> {
|
) -> TypResult<Template> {
|
||||||
let mut seq = Vec::with_capacity(nodes.size_hint().1.unwrap_or_default());
|
let mut seq = Vec::with_capacity(nodes.size_hint().1.unwrap_or_default());
|
||||||
let mut styles = StyleMap::new();
|
|
||||||
|
|
||||||
while let Some(node) = nodes.next() {
|
while let Some(node) = nodes.next() {
|
||||||
let template = match node {
|
seq.push(match node {
|
||||||
MarkupNode::Expr(Expr::Set(set)) => {
|
MarkupNode::Expr(Expr::Set(set)) => {
|
||||||
let class = set.class();
|
let class = set.class();
|
||||||
let class = class.eval(ctx)?.cast::<Class>().at(class.span())?;
|
let class = class.eval(ctx)?.cast::<Class>().at(class.span())?;
|
||||||
let mut args = set.args().eval(ctx)?;
|
let mut args = set.args().eval(ctx)?;
|
||||||
|
let mut styles = StyleMap::new();
|
||||||
class.set(&mut args, &mut styles)?;
|
class.set(&mut args, &mut styles)?;
|
||||||
args.finish()?;
|
args.finish()?;
|
||||||
continue;
|
let tail = eval_markup(ctx, nodes)?;
|
||||||
|
tail.styled_with_map(styles)
|
||||||
}
|
}
|
||||||
MarkupNode::Expr(Expr::Show(show)) => {
|
MarkupNode::Expr(Expr::Show(show)) => {
|
||||||
return Err("show rules are not yet implemented").at(show.span());
|
return Err("show rules are not yet implemented").at(show.span());
|
||||||
@ -204,12 +205,14 @@ fn eval_markup(
|
|||||||
wrap.body().eval(ctx)?.show()
|
wrap.body().eval(ctx)?.show()
|
||||||
}
|
}
|
||||||
_ => node.eval(ctx)?,
|
_ => node.eval(ctx)?,
|
||||||
};
|
});
|
||||||
|
|
||||||
seq.push(Styled::new(template, styles.clone()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Template::Sequence(seq))
|
if seq.len() == 1 {
|
||||||
|
Ok(seq.into_iter().next().unwrap())
|
||||||
|
} else {
|
||||||
|
Ok(Template::Sequence(seq))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for MarkupNode {
|
impl Eval for MarkupNode {
|
||||||
@ -265,7 +268,7 @@ impl Eval for RawNode {
|
|||||||
impl RawNode {
|
impl RawNode {
|
||||||
/// Styled template for a code block, with optional syntax highlighting.
|
/// Styled template for a code block, with optional syntax highlighting.
|
||||||
pub fn highlighted(&self) -> Template {
|
pub fn highlighted(&self) -> Template {
|
||||||
let mut seq: Vec<Styled<Template>> = vec![];
|
let mut seq: Vec<Template> = vec![];
|
||||||
|
|
||||||
let syntax = if let Some(syntax) = self
|
let syntax = if let Some(syntax) = self
|
||||||
.lang
|
.lang
|
||||||
@ -294,7 +297,7 @@ impl RawNode {
|
|||||||
let mut highlighter = HighlightLines::new(syntax, &THEME);
|
let mut highlighter = HighlightLines::new(syntax, &THEME);
|
||||||
for (i, line) in self.text.lines().enumerate() {
|
for (i, line) in self.text.lines().enumerate() {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
seq.push(Styled::bare(Template::Linebreak));
|
seq.push(Template::Linebreak);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (style, piece) in highlighter.highlight(line, &SYNTAXES) {
|
for (style, piece) in highlighter.highlight(line, &SYNTAXES) {
|
||||||
@ -322,7 +325,7 @@ impl RawNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Style a piece of text with a syntect style.
|
/// Style a piece of text with a syntect style.
|
||||||
fn style_piece(piece: &str, foreground: Paint, style: SynStyle) -> Styled<Template> {
|
fn style_piece(piece: &str, foreground: Paint, style: SynStyle) -> Template {
|
||||||
let mut styles = StyleMap::new();
|
let mut styles = StyleMap::new();
|
||||||
|
|
||||||
let paint = style.foreground.into();
|
let paint = style.foreground.into();
|
||||||
@ -342,7 +345,7 @@ fn style_piece(piece: &str, foreground: Paint, style: SynStyle) -> Styled<Templa
|
|||||||
styles.set(TextNode::LINES, vec![DecoLine::Underline.into()]);
|
styles.set(TextNode::LINES, vec![DecoLine::Underline.into()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Styled::new(Template::Text(piece.into()), styles)
|
Template::Text(piece.into()).styled_with_map(styles)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval for MathNode {
|
impl Eval for MathNode {
|
||||||
|
@ -20,9 +20,25 @@ use crate::util::EcoString;
|
|||||||
/// - anything written between square brackets in Typst
|
/// - anything written between square brackets in Typst
|
||||||
/// - any class constructor
|
/// - any class constructor
|
||||||
///
|
///
|
||||||
/// When you write `[Hi] + [you]` in Typst, this type's [`Add`] implementation
|
/// This enum has two notable variants:
|
||||||
/// is invoked. There, multiple templates are combined into a single
|
///
|
||||||
/// [`Sequence`](Self::Sequence) template.
|
/// 1. A `Styled` template attaches a style map to a template. This map affects
|
||||||
|
/// the whole subtemplate. For example, a single bold word could be
|
||||||
|
/// represented as a `Styled(Text("Hello"), [TextNode::STRONG: true])`
|
||||||
|
/// template.
|
||||||
|
///
|
||||||
|
/// 2. A `Sequence` template simply combines multiple templates and will be
|
||||||
|
/// layouted as a [flow](FlowNode). So, when you write `[Hi] + [you]` in
|
||||||
|
/// Typst, this type's [`Add`] implementation is invoked and the two
|
||||||
|
/// templates are combined into a single [`Sequence`](Self::Sequence)
|
||||||
|
/// template.
|
||||||
|
///
|
||||||
|
/// A sequence may contain nested sequences (meaning this variant effectively
|
||||||
|
/// allows nodes to form trees). All nested sequences can equivalently be
|
||||||
|
/// represented as a single flat sequence, but allowing nesting doesn't hurt
|
||||||
|
/// since we can just recurse into the nested sequences during packing. Also,
|
||||||
|
/// in theory, this allows better complexity when adding (large) sequence
|
||||||
|
/// nodes (just like for a text rope).
|
||||||
#[derive(Debug, PartialEq, Clone, Hash)]
|
#[derive(Debug, PartialEq, Clone, Hash)]
|
||||||
pub enum Template {
|
pub enum Template {
|
||||||
/// A word space.
|
/// A word space.
|
||||||
@ -45,21 +61,10 @@ pub enum Template {
|
|||||||
Block(PackedNode),
|
Block(PackedNode),
|
||||||
/// A page node.
|
/// A page node.
|
||||||
Page(PageNode),
|
Page(PageNode),
|
||||||
/// Multiple nodes with attached styles.
|
/// A template with attached styles.
|
||||||
///
|
Styled(Box<Self>, StyleMap),
|
||||||
/// For example, the Typst template `[Hi *you!*]` would result in the
|
/// A sequence of multiple subtemplates.
|
||||||
/// sequence:
|
Sequence(Vec<Self>),
|
||||||
/// - `Text("Hi")` with empty style map,
|
|
||||||
/// - `Space` with empty style map,
|
|
||||||
/// - `Text("you!")` with `TextNode::STRONG` set to `true`.
|
|
||||||
///
|
|
||||||
/// A sequence may contain nested sequences (meaning this variant
|
|
||||||
/// effectively allows nodes to form trees). All nested sequences can
|
|
||||||
/// equivalently be represented as a single flat sequence, but allowing
|
|
||||||
/// nesting doesn't hurt since we can just recurse into the nested sequences
|
|
||||||
/// during packing. Also, in theory, this allows better complexity when
|
|
||||||
/// adding (large) sequence nodes (just like for a text rope).
|
|
||||||
Sequence(Vec<Styled<Self>>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Template {
|
impl Template {
|
||||||
@ -86,30 +91,24 @@ impl Template {
|
|||||||
|
|
||||||
/// Style this template with a single property.
|
/// Style this template with a single property.
|
||||||
pub fn styled<P: Property>(mut self, key: P, value: P::Value) -> Self {
|
pub fn styled<P: Property>(mut self, key: P, value: P::Value) -> Self {
|
||||||
if let Self::Sequence(vec) = &mut self {
|
if let Self::Styled(_, map) = &mut self {
|
||||||
if let [styled] = vec.as_mut_slice() {
|
map.set(key, value);
|
||||||
styled.map.set(key, value);
|
self
|
||||||
return self;
|
} else {
|
||||||
}
|
self.styled_with_map(StyleMap::with(key, value))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.styled_with_map(StyleMap::with(key, value))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Style this template with a full style map.
|
/// Style this template with a full style map.
|
||||||
pub fn styled_with_map(mut self, styles: StyleMap) -> Self {
|
pub fn styled_with_map(mut self, styles: StyleMap) -> Self {
|
||||||
if styles.is_empty() {
|
if styles.is_empty() {
|
||||||
return self;
|
self
|
||||||
|
} else if let Self::Styled(_, map) = &mut self {
|
||||||
|
map.apply(&styles);
|
||||||
|
self
|
||||||
|
} else {
|
||||||
|
Self::Styled(Box::new(self), styles)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Self::Sequence(vec) = &mut self {
|
|
||||||
if let [styled] = vec.as_mut_slice() {
|
|
||||||
styled.map.apply(&styles);
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Self::Sequence(vec![Styled::new(self, styles)])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Style this template in monospace.
|
/// Style this template in monospace.
|
||||||
@ -140,7 +139,7 @@ impl Template {
|
|||||||
let count = usize::try_from(n)
|
let count = usize::try_from(n)
|
||||||
.map_err(|_| format!("cannot repeat this template {} times", n))?;
|
.map_err(|_| format!("cannot repeat this template {} times", n))?;
|
||||||
|
|
||||||
Ok(Self::Sequence(vec![Styled::bare(self.clone()); count]))
|
Ok(Self::Sequence(vec![self.clone(); count]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,15 +159,15 @@ impl Add for Template {
|
|||||||
left
|
left
|
||||||
}
|
}
|
||||||
(Self::Sequence(mut left), right) => {
|
(Self::Sequence(mut left), right) => {
|
||||||
left.push(Styled::bare(right));
|
left.push(right);
|
||||||
left
|
left
|
||||||
}
|
}
|
||||||
(left, Self::Sequence(mut right)) => {
|
(left, Self::Sequence(mut right)) => {
|
||||||
right.insert(0, Styled::bare(left));
|
right.insert(0, left);
|
||||||
right
|
right
|
||||||
}
|
}
|
||||||
(left, right) => {
|
(left, right) => {
|
||||||
vec![Styled::bare(left), Styled::bare(right)]
|
vec![left, right]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -182,7 +181,7 @@ impl AddAssign for Template {
|
|||||||
|
|
||||||
impl Sum for Template {
|
impl Sum for Template {
|
||||||
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
|
||||||
Self::Sequence(iter.map(|n| Styled::bare(n)).collect())
|
Self::Sequence(iter.collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,12 +288,15 @@ impl Packer {
|
|||||||
self.push_block(Styled::new(page.0, styles));
|
self.push_block(Styled::new(page.0, styles));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Template::Sequence(list) => {
|
Template::Styled(template, mut map) => {
|
||||||
|
map.apply(&styles);
|
||||||
|
self.walk(*template, map);
|
||||||
|
}
|
||||||
|
Template::Sequence(seq) => {
|
||||||
// For a list of templates, we apply the list's styles to each
|
// For a list of templates, we apply the list's styles to each
|
||||||
// templates individually.
|
// templates individually.
|
||||||
for Styled { item, mut map } in list {
|
for item in seq {
|
||||||
map.apply(&styles);
|
self.walk(item, styles.clone());
|
||||||
self.walk(item, map);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,13 +130,13 @@
|
|||||||
#test(test == test, true)
|
#test(test == test, true)
|
||||||
#test((() => {}) == (() => {}), false)
|
#test((() => {}) == (() => {}), false)
|
||||||
|
|
||||||
// Templates compare by shallow equality.
|
// Templates compare by some kind of equality.
|
||||||
#let t = [a]
|
#let t = [a]
|
||||||
#test(t == t, true)
|
#test(t == t, true)
|
||||||
#test([] == [], true)
|
#test([] == [], true)
|
||||||
#test([a] == [a], true)
|
#test([a] == [a], true)
|
||||||
|
#test([[a]] == [a], true)
|
||||||
#test([] == [a], false)
|
#test([] == [a], false)
|
||||||
#test([[a]] == [a], false)
|
|
||||||
#test(box[] == box[], false)
|
#test(box[] == box[], false)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
Loading…
x
Reference in New Issue
Block a user