mirror of
https://github.com/typst/typst
synced 2025-05-15 17:45:27 +08:00
Tidy up styling
This commit is contained in:
parent
5fd9c0b0d7
commit
af014cfe5e
@ -66,7 +66,7 @@ impl Class {
|
|||||||
let mut styles = StyleMap::new();
|
let mut styles = StyleMap::new();
|
||||||
self.set(args, &mut styles)?;
|
self.set(args, &mut styles)?;
|
||||||
let node = (self.construct)(ctx, args)?;
|
let node = (self.construct)(ctx, args)?;
|
||||||
Ok(node.styled(styles))
|
Ok(node.styled_with_map(styles))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute the class's set rule.
|
/// Execute the class's set rule.
|
||||||
|
@ -5,7 +5,7 @@ use std::iter::Sum;
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Add, AddAssign};
|
use std::ops::{Add, AddAssign};
|
||||||
|
|
||||||
use super::{StyleMap, Styled};
|
use super::{Property, StyleMap, Styled};
|
||||||
use crate::diag::StrResult;
|
use crate::diag::StrResult;
|
||||||
use crate::geom::SpecAxis;
|
use crate::geom::SpecAxis;
|
||||||
use crate::layout::{Layout, PackedNode, RootNode};
|
use crate::layout::{Layout, PackedNode, RootNode};
|
||||||
@ -84,14 +84,33 @@ impl Node {
|
|||||||
Self::Block(node.pack())
|
Self::Block(node.pack())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Style this node.
|
/// Style this node with a single property.
|
||||||
pub fn styled(self, styles: StyleMap) -> Self {
|
pub fn styled<P: Property>(mut self, key: P, value: P::Value) -> Self {
|
||||||
|
if let Self::Sequence(vec) = &mut self {
|
||||||
|
if let [styled] = vec.as_mut_slice() {
|
||||||
|
styled.map.set(key, value);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.styled_with_map(StyleMap::with(key, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Style this node with a full style map.
|
||||||
|
pub fn styled_with_map(mut self, styles: StyleMap) -> Self {
|
||||||
|
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)])
|
Self::Sequence(vec![Styled::new(self, styles)])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Style this node in monospace.
|
/// Style this node in monospace.
|
||||||
pub fn monospaced(self) -> Self {
|
pub fn monospaced(self) -> Self {
|
||||||
self.styled(StyleMap::with(TextNode::MONOSPACE, true))
|
self.styled(TextNode::MONOSPACE, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lift to a type-erased block-level node.
|
/// Lift to a type-erased block-level node.
|
||||||
|
@ -106,7 +106,6 @@ impl StyleMap {
|
|||||||
/// `outer`. The ones from `self` take precedence over the ones from
|
/// `outer`. The ones from `self` take precedence over the ones from
|
||||||
/// `outer`. For folded properties `self` contributes the inner value.
|
/// `outer`. For folded properties `self` contributes the inner value.
|
||||||
pub fn chain<'a>(&'a self, outer: &'a StyleChain<'a>) -> StyleChain<'a> {
|
pub fn chain<'a>(&'a self, outer: &'a StyleChain<'a>) -> StyleChain<'a> {
|
||||||
// No need to chain an empty map.
|
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
*outer
|
*outer
|
||||||
} else {
|
} else {
|
||||||
@ -182,7 +181,9 @@ impl PartialEq for StyleMap {
|
|||||||
/// matches further up the chain.
|
/// matches further up the chain.
|
||||||
#[derive(Clone, Copy, Hash)]
|
#[derive(Clone, Copy, Hash)]
|
||||||
pub struct StyleChain<'a> {
|
pub struct StyleChain<'a> {
|
||||||
|
/// The first map in the chain.
|
||||||
inner: &'a StyleMap,
|
inner: &'a StyleMap,
|
||||||
|
/// The remaining maps in the chain.
|
||||||
outer: Option<&'a Self>,
|
outer: Option<&'a Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,14 +239,13 @@ impl<'a> StyleChain<'a> {
|
|||||||
/// entry for it.
|
/// entry for it.
|
||||||
pub fn get_cloned<P: Property>(self, key: P) -> P::Value {
|
pub fn get_cloned<P: Property>(self, key: P) -> P::Value {
|
||||||
if let Some(value) = self.find(key).cloned() {
|
if let Some(value) = self.find(key).cloned() {
|
||||||
if P::FOLDABLE {
|
if !P::FOLDABLE {
|
||||||
if let Some(outer) = self.outer {
|
return value;
|
||||||
P::fold(value, outer.get_cloned(key))
|
|
||||||
} else {
|
|
||||||
P::fold(value, P::default())
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
value
|
match self.outer {
|
||||||
|
Some(outer) => P::fold(value, outer.get_cloned(key)),
|
||||||
|
None => P::fold(value, P::default()),
|
||||||
}
|
}
|
||||||
} else if let Some(outer) = self.outer {
|
} else if let Some(outer) = self.outer {
|
||||||
outer.get_cloned(key)
|
outer.get_cloned(key)
|
||||||
|
@ -15,9 +15,9 @@ pub fn link(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
|||||||
Node::Text(text.into())
|
Node::Text(text.into())
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut passed = StyleMap::new();
|
let mut map = StyleMap::new();
|
||||||
passed.set(TextNode::LINK, Some(url.clone()));
|
map.set(TextNode::LINK, Some(url.clone()));
|
||||||
passed.set(ImageNode::LINK, Some(url.clone()));
|
map.set(ImageNode::LINK, Some(url.clone()));
|
||||||
passed.set(ShapeNode::LINK, Some(url));
|
map.set(ShapeNode::LINK, Some(url));
|
||||||
Ok(Value::Node(body.styled(passed)))
|
Ok(Value::Node(body.styled_with_map(map)))
|
||||||
}
|
}
|
||||||
|
@ -61,8 +61,8 @@ prelude! {
|
|||||||
|
|
||||||
pub use crate::diag::{At, TypResult};
|
pub use crate::diag::{At, TypResult};
|
||||||
pub use crate::eval::{
|
pub use crate::eval::{
|
||||||
Args, Construct, EvalContext, Node, Property, Set, Smart, StyleChain, StyleMap,
|
Args, Construct, EvalContext, Node, Property, Scope, Set, Smart, StyleChain,
|
||||||
Styled, Value,
|
StyleMap, Styled, Value,
|
||||||
};
|
};
|
||||||
pub use crate::frame::*;
|
pub use crate::frame::*;
|
||||||
pub use crate::geom::*;
|
pub use crate::geom::*;
|
||||||
@ -73,53 +73,50 @@ prelude! {
|
|||||||
pub use crate::util::{EcoString, OptionExt};
|
pub use crate::util::{EcoString, OptionExt};
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::eval::Scope;
|
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
/// Construct a scope containing all standard library definitions.
|
/// Construct a scope containing all standard library definitions.
|
||||||
pub fn new() -> Scope {
|
pub fn new() -> Scope {
|
||||||
let mut std = Scope::new();
|
let mut std = Scope::new();
|
||||||
|
|
||||||
// Classes.
|
// Structure and semantics.
|
||||||
std.def_class::<PageNode>("page");
|
std.def_class::<PageNode>("page");
|
||||||
std.def_class::<ParNode>("par");
|
std.def_class::<ParNode>("par");
|
||||||
std.def_class::<TextNode>("text");
|
std.def_class::<TextNode>("text");
|
||||||
std.def_class::<HeadingNode>("heading");
|
|
||||||
std.def_class::<ListNode<Unordered>>("list");
|
|
||||||
std.def_class::<ListNode<Ordered>>("enum");
|
|
||||||
|
|
||||||
// Text functions.
|
|
||||||
std.def_func("underline", underline);
|
std.def_func("underline", underline);
|
||||||
std.def_func("strike", strike);
|
std.def_func("strike", strike);
|
||||||
std.def_func("overline", overline);
|
std.def_func("overline", overline);
|
||||||
std.def_func("link", link);
|
std.def_func("link", link);
|
||||||
|
std.def_class::<HeadingNode>("heading");
|
||||||
// Break and spacing functions.
|
std.def_class::<ListNode<Unordered>>("list");
|
||||||
std.def_func("pagebreak", pagebreak);
|
std.def_class::<ListNode<Ordered>>("enum");
|
||||||
std.def_func("colbreak", colbreak);
|
|
||||||
std.def_func("parbreak", parbreak);
|
|
||||||
std.def_func("linebreak", linebreak);
|
|
||||||
std.def_func("h", h);
|
|
||||||
std.def_func("v", v);
|
|
||||||
|
|
||||||
// Layout functions.
|
|
||||||
std.def_func("box", box_);
|
|
||||||
std.def_func("block", block);
|
|
||||||
std.def_func("stack", stack);
|
|
||||||
std.def_func("grid", grid);
|
|
||||||
std.def_func("pad", pad);
|
|
||||||
std.def_func("columns", columns);
|
|
||||||
std.def_func("align", align);
|
|
||||||
std.def_func("place", place);
|
|
||||||
std.def_func("move", move_);
|
|
||||||
std.def_func("scale", scale);
|
|
||||||
std.def_func("rotate", rotate);
|
|
||||||
std.def_func("image", image);
|
std.def_func("image", image);
|
||||||
std.def_func("rect", rect);
|
std.def_func("rect", rect);
|
||||||
std.def_func("square", square);
|
std.def_func("square", square);
|
||||||
std.def_func("ellipse", ellipse);
|
std.def_func("ellipse", ellipse);
|
||||||
std.def_func("circle", circle);
|
std.def_func("circle", circle);
|
||||||
|
|
||||||
|
// Layout.
|
||||||
|
std.def_func("h", h);
|
||||||
|
std.def_func("v", v);
|
||||||
|
std.def_func("box", box_);
|
||||||
|
std.def_func("block", block);
|
||||||
|
std.def_func("align", align);
|
||||||
|
std.def_func("pad", pad);
|
||||||
|
std.def_func("place", place);
|
||||||
|
std.def_func("move", move_);
|
||||||
|
std.def_func("scale", scale);
|
||||||
|
std.def_func("rotate", rotate);
|
||||||
|
std.def_func("stack", stack);
|
||||||
|
std.def_func("grid", grid);
|
||||||
|
std.def_func("columns", columns);
|
||||||
|
|
||||||
|
// Breaks.
|
||||||
|
std.def_func("pagebreak", pagebreak);
|
||||||
|
std.def_func("colbreak", colbreak);
|
||||||
|
std.def_func("parbreak", parbreak);
|
||||||
|
std.def_func("linebreak", linebreak);
|
||||||
|
|
||||||
// Utility functions.
|
// Utility functions.
|
||||||
std.def_func("assert", assert);
|
std.def_func("assert", assert);
|
||||||
std.def_func("type", type_);
|
std.def_func("type", type_);
|
||||||
|
@ -4,7 +4,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
use super::{ColumnsNode, PadNode};
|
use super::ColumnsNode;
|
||||||
|
|
||||||
/// Layouts its child onto one or multiple pages.
|
/// Layouts its child onto one or multiple pages.
|
||||||
#[derive(Clone, PartialEq, Hash)]
|
#[derive(Clone, PartialEq, Hash)]
|
||||||
@ -111,7 +111,7 @@ impl PageNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Realize margins with padding node.
|
// Realize margins with padding node.
|
||||||
child = PadNode { child, padding }.pack();
|
child = child.padded(padding);
|
||||||
|
|
||||||
// Layout the child.
|
// Layout the child.
|
||||||
let expand = size.map(Length::is_finite);
|
let expand = size.map(Length::is_finite);
|
||||||
|
@ -29,7 +29,10 @@ impl ParNode {
|
|||||||
|
|
||||||
impl Construct for ParNode {
|
impl Construct for ParNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
|
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
|
||||||
// Lift to a block so that it doesn't merge with adjacent stuff.
|
// The paragraph constructor is special: It doesn't create a paragraph
|
||||||
|
// since that happens automatically through markup. Instead, it just
|
||||||
|
// lifts the passed body to the block level so that it won't merge with
|
||||||
|
// adjacent stuff and it styles the contained paragraphs.
|
||||||
Ok(Node::Block(args.expect("body")?))
|
Ok(Node::Block(args.expect("body")?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,10 +96,10 @@ impl TextNode {
|
|||||||
|
|
||||||
impl Construct for TextNode {
|
impl Construct for TextNode {
|
||||||
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
|
fn construct(_: &mut EvalContext, args: &mut Args) -> TypResult<Node> {
|
||||||
// We don't need to do anything more here because the whole point of the
|
// The text constructor is special: It doesn't create a text node.
|
||||||
// text constructor is to apply the styles and that happens
|
// Instead, it leaves the passed argument structurally unchanged, but
|
||||||
// automatically during class construction.
|
// styles all text in it.
|
||||||
args.expect::<Node>("body")
|
args.expect("body")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,9 +404,7 @@ fn line_impl(args: &mut Args, kind: LineKind) -> TypResult<Value> {
|
|||||||
let extent = args.named("extent")?.unwrap_or_default();
|
let extent = args.named("extent")?.unwrap_or_default();
|
||||||
let body: Node = args.expect("body")?;
|
let body: Node = args.expect("body")?;
|
||||||
let deco = LineDecoration { kind, stroke, thickness, offset, extent };
|
let deco = LineDecoration { kind, stroke, thickness, offset, extent };
|
||||||
Ok(Value::Node(
|
Ok(Value::Node(body.styled(TextNode::LINES, vec![deco])))
|
||||||
body.styled(StyleMap::with(TextNode::LINES, vec![deco])),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines a line that is positioned over, under or on top of text.
|
/// Defines a line that is positioned over, under or on top of text.
|
||||||
|
@ -12,8 +12,7 @@ Hello *{x}*
|
|||||||
#let fruit = [
|
#let fruit = [
|
||||||
- Apple
|
- Apple
|
||||||
- Orange
|
- Orange
|
||||||
#set list(body-indent: 10pt)
|
#list(body-indent: 10pt, [Pear])
|
||||||
- Pear
|
|
||||||
]
|
]
|
||||||
|
|
||||||
- Fruit
|
- Fruit
|
||||||
|
Loading…
x
Reference in New Issue
Block a user