mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Re-enable *, _ and `.
This commit is contained in:
parent
7b84f3b553
commit
bd384a2a63
@ -101,7 +101,7 @@ pub enum Command<'a> {
|
|||||||
|
|
||||||
Add(Layout),
|
Add(Layout),
|
||||||
AddMultiple(MultiLayout),
|
AddMultiple(MultiLayout),
|
||||||
AddSpacing(Size, SpacingKind, GenericAxis),
|
SpacingFunc(Size, SpacingKind, GenericAxis),
|
||||||
|
|
||||||
FinishLine,
|
FinishLine,
|
||||||
FinishSpace,
|
FinishSpace,
|
||||||
|
@ -44,9 +44,19 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
|
|||||||
Node::Space => self.layout_space(),
|
Node::Space => self.layout_space(),
|
||||||
Node::Newline => self.layout_paragraph()?,
|
Node::Newline => self.layout_paragraph()?,
|
||||||
|
|
||||||
Node::ToggleItalics => {},
|
Node::ToggleItalics => self.style.text.variant.style.toggle(),
|
||||||
Node::ToggleBold => {},
|
Node::ToggleBolder => {
|
||||||
Node::ToggleMonospace => {},
|
self.style.text.variant.weight.0 += 300 *
|
||||||
|
if self.style.text.bolder { -1 } else { 1 };
|
||||||
|
self.style.text.bolder = !self.style.text.bolder;
|
||||||
|
}
|
||||||
|
Node::ToggleMonospace => {
|
||||||
|
let list = &mut self.style.text.fallback.list;
|
||||||
|
match list.get(0).map(|s| s.as_str()) {
|
||||||
|
Some("monospace") => { list.remove(0); },
|
||||||
|
_ => list.insert(0, "monospace".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Node::Func(func) => self.layout_func(func)?,
|
Node::Func(func) => self.layout_func(func)?,
|
||||||
}
|
}
|
||||||
@ -98,7 +108,7 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
|
|||||||
|
|
||||||
Add(layout) => self.layouter.add(layout)?,
|
Add(layout) => self.layouter.add(layout)?,
|
||||||
AddMultiple(layouts) => self.layouter.add_multiple(layouts)?,
|
AddMultiple(layouts) => self.layouter.add_multiple(layouts)?,
|
||||||
AddSpacing(space, kind, axis) => match axis {
|
SpacingFunc(space, kind, axis) => match axis {
|
||||||
Primary => self.layouter.add_primary_spacing(space, kind),
|
Primary => self.layouter.add_primary_spacing(space, kind),
|
||||||
Secondary => self.layouter.add_secondary_spacing(space, kind)?,
|
Secondary => self.layouter.add_secondary_spacing(space, kind)?,
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
use crate::func::prelude::*;
|
use crate::func::prelude::*;
|
||||||
use super::maps::{PosAxisMap, AlignmentKey};
|
use super::maps::{PosAxisMap, AlignmentKey};
|
||||||
|
|
||||||
|
|
||||||
function! {
|
function! {
|
||||||
/// `align`: Aligns content along the layouting axes.
|
/// `align`: Aligns content along the layouting axes.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Align {
|
pub struct AlignFunc {
|
||||||
body: Option<SyntaxTree>,
|
body: Option<SyntaxTree>,
|
||||||
map: PosAxisMap<AlignmentKey>,
|
map: PosAxisMap<AlignmentKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
parse(args, body, ctx) {
|
parse(args, body, ctx) {
|
||||||
Align {
|
AlignFunc {
|
||||||
body: parse!(optional: body, ctx),
|
body: parse!(optional: body, ctx),
|
||||||
map: PosAxisMap::new(&mut args)?,
|
map: PosAxisMap::new(&mut args)?,
|
||||||
}
|
}
|
||||||
@ -28,7 +29,7 @@ function! {
|
|||||||
|
|
||||||
match &self.body {
|
match &self.body {
|
||||||
Some(body) => vec![AddMultiple(layout(&body, ctx)?)],
|
Some(body) => vec![AddMultiple(layout(&body, ctx)?)],
|
||||||
None => vec![Command::SetAlignment(ctx.alignment)],
|
None => vec![SetAlignment(ctx.alignment)],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,18 @@ use smallvec::smallvec;
|
|||||||
use crate::func::prelude::*;
|
use crate::func::prelude::*;
|
||||||
use super::maps::ExtentMap;
|
use super::maps::ExtentMap;
|
||||||
|
|
||||||
|
|
||||||
function! {
|
function! {
|
||||||
/// `box`: Layouts content into a box.
|
/// `box`: Layouts content into a box.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Boxed {
|
pub struct BoxFunc {
|
||||||
body: SyntaxTree,
|
body: SyntaxTree,
|
||||||
map: ExtentMap<PSize>,
|
map: ExtentMap<PSize>,
|
||||||
debug: Option<bool>,
|
debug: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
parse(args, body, ctx) {
|
parse(args, body, ctx) {
|
||||||
Boxed {
|
BoxFunc {
|
||||||
body: parse!(optional: body, ctx).unwrap_or(SyntaxTree::new()),
|
body: parse!(optional: body, ctx).unwrap_or(SyntaxTree::new()),
|
||||||
map: ExtentMap::new(&mut args, false)?,
|
map: ExtentMap::new(&mut args, false)?,
|
||||||
debug: args.get_key_opt::<bool>("debug")?,
|
debug: args.get_key_opt::<bool>("debug")?,
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
use crate::func::prelude::*;
|
use crate::func::prelude::*;
|
||||||
use super::maps::PosAxisMap;
|
use super::maps::PosAxisMap;
|
||||||
|
|
||||||
|
|
||||||
function! {
|
function! {
|
||||||
/// `direction`: Sets the directions of the layouting axes.
|
/// `direction`: Sets the directions of the layouting axes.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct DirectionChange {
|
pub struct DirectionFunc {
|
||||||
body: Option<SyntaxTree>,
|
body: Option<SyntaxTree>,
|
||||||
map: PosAxisMap<Direction>,
|
map: PosAxisMap<Direction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
parse(args, body, ctx) {
|
parse(args, body, ctx) {
|
||||||
DirectionChange {
|
DirectionFunc {
|
||||||
body: parse!(optional: body, ctx),
|
body: parse!(optional: body, ctx),
|
||||||
map: PosAxisMap::new(&mut args)?,
|
map: PosAxisMap::new(&mut args)?,
|
||||||
}
|
}
|
||||||
|
@ -12,73 +12,168 @@ pub_use_mod!(align);
|
|||||||
pub_use_mod!(boxed);
|
pub_use_mod!(boxed);
|
||||||
pub_use_mod!(direction);
|
pub_use_mod!(direction);
|
||||||
|
|
||||||
|
|
||||||
/// Create a scope with all standard functions.
|
/// Create a scope with all standard functions.
|
||||||
pub fn std() -> Scope {
|
pub fn std() -> Scope {
|
||||||
let mut std = Scope::new();
|
let mut std = Scope::new();
|
||||||
|
|
||||||
std.add::<Align>("align");
|
// Font setup
|
||||||
std.add::<Boxed>("box");
|
std.add::<FontFamilyFunc>("font.family");
|
||||||
std.add::<DirectionChange>("direction");
|
std.add::<FontStyleFunc>("font.style");
|
||||||
|
std.add::<FontWeightFunc>("font.weight");
|
||||||
|
std.add::<FontSizeFunc>("font.size");
|
||||||
|
|
||||||
std.add::<LineBreak>("n");
|
// Layout
|
||||||
std.add::<LineBreak>("line.break");
|
std.add::<AlignFunc>("align");
|
||||||
std.add::<ParBreak>("par.break");
|
std.add::<DirectionFunc>("direction");
|
||||||
std.add::<PageBreak>("page.break");
|
std.add_with_metadata::<ContentSpacingFunc>("par.spacing", ContentKind::Paragraph);
|
||||||
|
std.add_with_metadata::<ContentSpacingFunc>("word.spacing", ContentKind::Word);
|
||||||
|
std.add_with_metadata::<ContentSpacingFunc>("line.spacing", ContentKind::Line);
|
||||||
|
std.add::<BoxFunc>("box");
|
||||||
|
|
||||||
std.add_with_metadata::<ContentSpacing>("word.spacing", ContentKind::Word);
|
// Spacing
|
||||||
std.add_with_metadata::<ContentSpacing>("line.spacing", ContentKind::Line);
|
std.add::<LineBreakFunc>("n");
|
||||||
std.add_with_metadata::<ContentSpacing>("par.spacing", ContentKind::Paragraph);
|
std.add::<LineBreakFunc>("line.break");
|
||||||
|
std.add::<ParBreakFunc>("par.break");
|
||||||
|
std.add::<PageBreakFunc>("page.break");
|
||||||
|
std.add_with_metadata::<SpacingFunc>("spacing", None);
|
||||||
|
std.add_with_metadata::<SpacingFunc>("h", Some(Horizontal));
|
||||||
|
std.add_with_metadata::<SpacingFunc>("v", Some(Vertical));
|
||||||
|
|
||||||
std.add::<PageSize>("page.size");
|
// Page setup
|
||||||
std.add::<PageMargins>("page.margins");
|
std.add::<PageSizeFunc>("page.size");
|
||||||
|
std.add::<PageMarginsFunc>("page.margins");
|
||||||
std.add_with_metadata::<Spacing>("spacing", None);
|
|
||||||
std.add_with_metadata::<Spacing>("h", Some(Horizontal));
|
|
||||||
std.add_with_metadata::<Spacing>("v", Some(Vertical));
|
|
||||||
|
|
||||||
std.add_with_metadata::<FontFamily>("font.family", None);
|
|
||||||
std.add_with_metadata::<FontFamily>("mono", Some("monospace".to_string()));
|
|
||||||
std.add::<SetFontStyle>("font.style");
|
|
||||||
std.add::<SetFontWeight>("font.weight");
|
|
||||||
std.add::<FontSize>("font.size");
|
|
||||||
|
|
||||||
std
|
std
|
||||||
}
|
}
|
||||||
|
|
||||||
function! {
|
// -------------------------------------------------------------------------- //
|
||||||
/// `line.break`, `n`: Ends the current line.
|
// Font setup
|
||||||
#[derive(Debug, Default, PartialEq)]
|
|
||||||
pub struct LineBreak;
|
|
||||||
|
|
||||||
parse(default)
|
function! {
|
||||||
layout() { vec![FinishLine] }
|
/// `font.family`: Set the font family.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct FontFamilyFunc {
|
||||||
|
body: Option<SyntaxTree>,
|
||||||
|
family: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
parse(args, body, ctx, meta) {
|
||||||
|
FontFamilyFunc {
|
||||||
|
body: parse!(optional: body, ctx),
|
||||||
|
family: args.get_pos::<String>()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout(self, ctx) {
|
||||||
|
let mut style = ctx.style.text.clone();
|
||||||
|
style.fallback.list = vec![self.family.clone()];
|
||||||
|
styled(&self.body, &ctx, style)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function! {
|
function! {
|
||||||
/// `par.break`: Ends the current paragraph.
|
/// `font.style`: Set the font style (normal / italic).
|
||||||
///
|
#[derive(Debug, PartialEq)]
|
||||||
/// self has the same effect as two subsequent newlines.
|
pub struct FontStyleFunc {
|
||||||
#[derive(Debug, Default, PartialEq)]
|
body: Option<SyntaxTree>,
|
||||||
pub struct ParBreak;
|
style: FontStyle,
|
||||||
|
}
|
||||||
|
|
||||||
parse(default)
|
parse(args, body, ctx) {
|
||||||
layout() { vec![BreakParagraph] }
|
FontStyleFunc {
|
||||||
|
body: parse!(optional: body, ctx),
|
||||||
|
style: {
|
||||||
|
let s = args.get_pos::<String>()?;
|
||||||
|
match FontStyle::from_str(&s) {
|
||||||
|
Some(style) => style,
|
||||||
|
None => error!("invalid font style: `{}`", s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout(self, ctx) {
|
||||||
|
let mut style = ctx.style.text.clone();
|
||||||
|
style.variant.style = self.style;
|
||||||
|
styled(&self.body, &ctx, style)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function! {
|
function! {
|
||||||
/// `page.break`: Ends the current page.
|
/// `font.weight`: Set text with a given weight.
|
||||||
#[derive(Debug, Default, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct PageBreak;
|
pub struct FontWeightFunc {
|
||||||
|
body: Option<SyntaxTree>,
|
||||||
parse(default)
|
weight: FontWeight,
|
||||||
layout() { vec![BreakPage] }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parse(args, body, ctx, meta) {
|
||||||
|
FontWeightFunc {
|
||||||
|
body: parse!(optional: body, ctx),
|
||||||
|
weight: match args.get_pos::<Expression>()? {
|
||||||
|
Expression::Num(weight) => {
|
||||||
|
let weight = weight.round() as i16;
|
||||||
|
FontWeight(
|
||||||
|
if weight < 100 { 100 }
|
||||||
|
else if weight <= 900 { weight }
|
||||||
|
else { 900 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Expression::Ident(Ident(s)) => {
|
||||||
|
match FontWeight::from_str(&s) {
|
||||||
|
Some(weight) => weight,
|
||||||
|
None => error!("invalid font weight: `{}`", s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => error!("expected identifier or number"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout(self, ctx) {
|
||||||
|
let mut style = ctx.style.text.clone();
|
||||||
|
style.variant.style.toggle();
|
||||||
|
styled(&self.body, &ctx, style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function! {
|
||||||
|
/// `font.size`: Sets the font size.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct FontSizeFunc {
|
||||||
|
body: Option<SyntaxTree>,
|
||||||
|
size: ScaleSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
parse(args, body, ctx) {
|
||||||
|
FontSizeFunc {
|
||||||
|
body: parse!(optional: body, ctx),
|
||||||
|
size: args.get_pos::<ScaleSize>()?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout(self, ctx) {
|
||||||
|
let mut style = ctx.style.text.clone();
|
||||||
|
match self.size {
|
||||||
|
ScaleSize::Absolute(size) => {
|
||||||
|
style.base_font_size = size;
|
||||||
|
style.font_scale = 1.0;
|
||||||
|
}
|
||||||
|
ScaleSize::Scaled(scale) => style.font_scale = scale,
|
||||||
|
}
|
||||||
|
styled(&self.body, &ctx, style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------- //
|
||||||
|
// Layout
|
||||||
|
|
||||||
function! {
|
function! {
|
||||||
/// `word.spacing`, `line.spacing`, `par.spacing`: The spacing between
|
/// `word.spacing`, `line.spacing`, `par.spacing`: The spacing between
|
||||||
/// words, lines or paragraphs as a multiple of the font size.
|
/// words, lines or paragraphs as a multiple of the font size.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct ContentSpacing {
|
pub struct ContentSpacingFunc {
|
||||||
body: Option<SyntaxTree>,
|
body: Option<SyntaxTree>,
|
||||||
content: ContentKind,
|
content: ContentKind,
|
||||||
spacing: f32,
|
spacing: f32,
|
||||||
@ -87,7 +182,7 @@ function! {
|
|||||||
type Meta = ContentKind;
|
type Meta = ContentKind;
|
||||||
|
|
||||||
parse(args, body, ctx, meta) {
|
parse(args, body, ctx, meta) {
|
||||||
ContentSpacing {
|
ContentSpacingFunc {
|
||||||
body: parse!(optional: body, ctx),
|
body: parse!(optional: body, ctx),
|
||||||
content: meta,
|
content: meta,
|
||||||
spacing: args.get_pos::<f64>()? as f32,
|
spacing: args.get_pos::<f64>()? as f32,
|
||||||
@ -113,10 +208,81 @@ pub enum ContentKind {
|
|||||||
Paragraph,
|
Paragraph,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------- //
|
||||||
|
// Spacing
|
||||||
|
|
||||||
|
function! {
|
||||||
|
/// `line.break`, `n`: Ends the current line.
|
||||||
|
#[derive(Debug, Default, PartialEq)]
|
||||||
|
pub struct LineBreakFunc;
|
||||||
|
|
||||||
|
parse(default)
|
||||||
|
layout() { vec![FinishLine] }
|
||||||
|
}
|
||||||
|
|
||||||
|
function! {
|
||||||
|
/// `par.break`: Ends the current paragraph.
|
||||||
|
///
|
||||||
|
/// self has the same effect as two subsequent newlines.
|
||||||
|
#[derive(Debug, Default, PartialEq)]
|
||||||
|
pub struct ParBreakFunc;
|
||||||
|
|
||||||
|
parse(default)
|
||||||
|
layout() { vec![BreakParagraph] }
|
||||||
|
}
|
||||||
|
|
||||||
|
function! {
|
||||||
|
/// `page.break`: Ends the current page.
|
||||||
|
#[derive(Debug, Default, PartialEq)]
|
||||||
|
pub struct PageBreakFunc;
|
||||||
|
|
||||||
|
parse(default)
|
||||||
|
layout() { vec![BreakPage] }
|
||||||
|
}
|
||||||
|
|
||||||
|
function! {
|
||||||
|
/// `spacing`, `h`, `v`: Adds spacing along an axis.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct SpacingFunc {
|
||||||
|
axis: AxisKey,
|
||||||
|
spacing: FSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Meta = Option<SpecificAxis>;
|
||||||
|
|
||||||
|
parse(args, body, _, meta) {
|
||||||
|
parse!(forbidden: body);
|
||||||
|
|
||||||
|
if let Some(axis) = meta {
|
||||||
|
SpacingFunc {
|
||||||
|
axis: AxisKey::Specific(axis),
|
||||||
|
spacing: FSize::from_expr(args.get_pos::<Spanned<Expression>>()?)?,
|
||||||
|
}
|
||||||
|
} else if let Some(arg) = args.get_key_next() {
|
||||||
|
let axis = AxisKey::from_ident(&arg.v.key)
|
||||||
|
.map_err(|_| error!(@unexpected_argument))?;
|
||||||
|
|
||||||
|
let spacing = FSize::from_expr(arg.v.value)?;
|
||||||
|
SpacingFunc { axis, spacing }
|
||||||
|
} else {
|
||||||
|
error!("expected axis and spacing")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout(self, ctx) {
|
||||||
|
let axis = self.axis.to_generic(ctx.axes);
|
||||||
|
let spacing = self.spacing.scaled(ctx.style.text.font_size());
|
||||||
|
vec![SpacingFunc(spacing, SpacingKind::Hard, axis)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------- //
|
||||||
|
// Page setup
|
||||||
|
|
||||||
function! {
|
function! {
|
||||||
/// `page.size`: Set the size of pages.
|
/// `page.size`: Set the size of pages.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum PageSize {
|
pub enum PageSizeFunc {
|
||||||
Paper(Paper, bool),
|
Paper(Paper, bool),
|
||||||
Custom(ExtentMap<PSize>),
|
Custom(ExtentMap<PSize>),
|
||||||
}
|
}
|
||||||
@ -125,11 +291,11 @@ function! {
|
|||||||
parse!(forbidden: body);
|
parse!(forbidden: body);
|
||||||
|
|
||||||
if let Some(name) = args.get_pos_opt::<Ident>()? {
|
if let Some(name) = args.get_pos_opt::<Ident>()? {
|
||||||
let landscape = args.get_key_opt::<bool>("landscape")?
|
let flip = args.get_key_opt::<bool>("flip")?
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
PageSize::Paper(Paper::from_name(name.as_str())?, landscape)
|
PageSizeFunc::Paper(Paper::from_name(name.as_str())?, flip)
|
||||||
} else {
|
} else {
|
||||||
PageSize::Custom(ExtentMap::new(&mut args, true)?)
|
PageSizeFunc::Custom(ExtentMap::new(&mut args, true)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,15 +303,15 @@ function! {
|
|||||||
let mut style = ctx.style.page;
|
let mut style = ctx.style.page;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
PageSize::Paper(paper, landscape) => {
|
PageSizeFunc::Paper(paper, flip) => {
|
||||||
style.class = paper.class;
|
style.class = paper.class;
|
||||||
style.dimensions = paper.dimensions;
|
style.dimensions = paper.dimensions;
|
||||||
if *landscape {
|
if *flip {
|
||||||
style.dimensions.swap();
|
style.dimensions.swap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PageSize::Custom(map) => {
|
PageSizeFunc::Custom(map) => {
|
||||||
style.class = PaperClass::Custom;
|
style.class = PaperClass::Custom;
|
||||||
|
|
||||||
let map = map.dedup(ctx.axes)?;
|
let map = map.dedup(ctx.axes)?;
|
||||||
@ -162,13 +328,13 @@ function! {
|
|||||||
function! {
|
function! {
|
||||||
/// `page.margins`: Sets the page margins.
|
/// `page.margins`: Sets the page margins.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct PageMargins {
|
pub struct PageMarginsFunc {
|
||||||
map: PaddingMap,
|
map: PaddingMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
parse(args, body) {
|
parse(args, body) {
|
||||||
parse!(forbidden: body);
|
parse!(forbidden: body);
|
||||||
PageMargins {
|
PageMarginsFunc {
|
||||||
map: PaddingMap::new(&mut args)?,
|
map: PaddingMap::new(&mut args)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,162 +346,8 @@ function! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function! {
|
// -------------------------------------------------------------------------- //
|
||||||
/// `spacing`, `h`, `v`: Adds spacing along an axis.
|
// Helpers
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub struct Spacing {
|
|
||||||
axis: AxisKey,
|
|
||||||
spacing: FSize,
|
|
||||||
}
|
|
||||||
|
|
||||||
type Meta = Option<SpecificAxis>;
|
|
||||||
|
|
||||||
parse(args, body, _, meta) {
|
|
||||||
parse!(forbidden: body);
|
|
||||||
|
|
||||||
if let Some(axis) = meta {
|
|
||||||
Spacing {
|
|
||||||
axis: AxisKey::Specific(axis),
|
|
||||||
spacing: FSize::from_expr(args.get_pos::<Spanned<Expression>>()?)?,
|
|
||||||
}
|
|
||||||
} else if let Some(arg) = args.get_key_next() {
|
|
||||||
let axis = AxisKey::from_ident(&arg.v.key)
|
|
||||||
.map_err(|_| error!(@unexpected_argument))?;
|
|
||||||
|
|
||||||
let spacing = FSize::from_expr(arg.v.value)?;
|
|
||||||
Spacing { axis, spacing }
|
|
||||||
} else {
|
|
||||||
error!("expected axis and spacing")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
layout(self, ctx) {
|
|
||||||
let axis = self.axis.to_generic(ctx.axes);
|
|
||||||
let spacing = self.spacing.scaled(ctx.style.text.font_size());
|
|
||||||
vec![AddSpacing(spacing, SpacingKind::Hard, axis)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function! {
|
|
||||||
/// `font.weight`, `bold`: Set text with a given weight.
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub struct SetFontWeight {
|
|
||||||
body: Option<SyntaxTree>,
|
|
||||||
weight: FontWeight,
|
|
||||||
}
|
|
||||||
|
|
||||||
parse(args, body, ctx, meta) {
|
|
||||||
SetFontWeight {
|
|
||||||
body: parse!(optional: body, ctx),
|
|
||||||
weight: match args.get_pos::<Expression>()? {
|
|
||||||
Expression::Num(weight) => FontWeight(if weight < 0.0 {
|
|
||||||
0
|
|
||||||
} else if weight < 1000.0 {
|
|
||||||
weight.round() as u16
|
|
||||||
} else {
|
|
||||||
1000
|
|
||||||
}),
|
|
||||||
Expression::Ident(Ident(s)) => {
|
|
||||||
match FontWeight::from_str(&s) {
|
|
||||||
Some(weight) => weight,
|
|
||||||
None => error!("invalid font weight: `{}`", s),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => error!("expected identifier or number"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
layout(self, ctx) {
|
|
||||||
let mut style = ctx.style.text.clone();
|
|
||||||
style.variant.style.toggle();
|
|
||||||
styled(&self.body, &ctx, style)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function! {
|
|
||||||
/// `font.style`: Set the font style (normal / italic).
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub struct SetFontStyle {
|
|
||||||
body: Option<SyntaxTree>,
|
|
||||||
style: FontStyle,
|
|
||||||
}
|
|
||||||
|
|
||||||
parse(args, body, ctx) {
|
|
||||||
SetFontStyle {
|
|
||||||
body: parse!(optional: body, ctx),
|
|
||||||
style: {
|
|
||||||
let s = args.get_pos::<String>()?;
|
|
||||||
match FontStyle::from_str(&s) {
|
|
||||||
Some(style) => style,
|
|
||||||
None => error!("invalid font style: `{}`", s),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
layout(self, ctx) {
|
|
||||||
let mut style = ctx.style.text.clone();
|
|
||||||
style.variant.style = self.style;
|
|
||||||
styled(&self.body, &ctx, style)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function! {
|
|
||||||
/// `font.family`: Set the font family.
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub struct FontFamily {
|
|
||||||
body: Option<SyntaxTree>,
|
|
||||||
family: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
type Meta = Option<String>;
|
|
||||||
|
|
||||||
parse(args, body, ctx, meta) {
|
|
||||||
FontFamily {
|
|
||||||
body: parse!(optional: body, ctx),
|
|
||||||
family: if let Some(family) = meta {
|
|
||||||
family
|
|
||||||
} else {
|
|
||||||
args.get_pos::<String>()?
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
layout(self, ctx) {
|
|
||||||
let mut style = ctx.style.text.clone();
|
|
||||||
style.fallback.list = vec![self.family.clone()];
|
|
||||||
styled(&self.body, &ctx, style)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function! {
|
|
||||||
/// `font.size`: Sets the font size.
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub struct FontSize {
|
|
||||||
body: Option<SyntaxTree>,
|
|
||||||
size: ScaleSize,
|
|
||||||
}
|
|
||||||
|
|
||||||
parse(args, body, ctx) {
|
|
||||||
FontSize {
|
|
||||||
body: parse!(optional: body, ctx),
|
|
||||||
size: args.get_pos::<ScaleSize>()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
layout(self, ctx) {
|
|
||||||
let mut style = ctx.style.text.clone();
|
|
||||||
match self.size {
|
|
||||||
ScaleSize::Absolute(size) => {
|
|
||||||
style.base_font_size = size;
|
|
||||||
style.font_scale = 1.0;
|
|
||||||
}
|
|
||||||
ScaleSize::Scaled(scale) => style.font_scale = scale,
|
|
||||||
}
|
|
||||||
styled(&self.body, &ctx, style)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Layout the body with the style or update the style if there is no body.
|
/// Layout the body with the style or update the style if there is no body.
|
||||||
fn styled<'a>(
|
fn styled<'a>(
|
||||||
|
@ -20,6 +20,9 @@ pub struct TextStyle {
|
|||||||
pub fallback: FontFallbackTree,
|
pub fallback: FontFallbackTree,
|
||||||
/// The selected font variant.
|
/// The selected font variant.
|
||||||
pub variant: FontVariant,
|
pub variant: FontVariant,
|
||||||
|
/// Whether the bolder toggle is active or inactive. This determines
|
||||||
|
/// whether the next `*` adds or removes font weight.
|
||||||
|
pub bolder: bool,
|
||||||
/// The base font size.
|
/// The base font size.
|
||||||
pub base_font_size: Size,
|
pub base_font_size: Size,
|
||||||
/// The font scale to apply on the base font size.
|
/// The font scale to apply on the base font size.
|
||||||
@ -80,6 +83,7 @@ impl Default for TextStyle {
|
|||||||
style: FontStyle::Normal,
|
style: FontStyle::Normal,
|
||||||
weight: FontWeight(400),
|
weight: FontWeight(400),
|
||||||
},
|
},
|
||||||
|
bolder: false,
|
||||||
base_font_size: Size::pt(11.0),
|
base_font_size: Size::pt(11.0),
|
||||||
font_scale: 1.0,
|
font_scale: 1.0,
|
||||||
word_spacing_scale: 0.25,
|
word_spacing_scale: 0.25,
|
||||||
|
@ -72,11 +72,11 @@ pub enum Node {
|
|||||||
Space,
|
Space,
|
||||||
/// A line feed.
|
/// A line feed.
|
||||||
Newline,
|
Newline,
|
||||||
/// Indicates that italics were enabled / disabled.
|
/// Indicates that italics were toggled.
|
||||||
ToggleItalics,
|
ToggleItalics,
|
||||||
/// Indicates that boldface was enabled / disabled.
|
/// Indicates that bolder text was toggled.
|
||||||
ToggleBold,
|
ToggleBolder,
|
||||||
/// Indicates that monospace was enabled / disabled.
|
/// Indicates that monospace was toggled.
|
||||||
ToggleMonospace,
|
ToggleMonospace,
|
||||||
/// Literal text.
|
/// Literal text.
|
||||||
Text(String),
|
Text(String),
|
||||||
|
@ -73,7 +73,7 @@ impl<'s> Parser<'s> {
|
|||||||
|
|
||||||
// Modifiers.
|
// Modifiers.
|
||||||
Underscore => self.append_consumed(Node::ToggleItalics, token.span),
|
Underscore => self.append_consumed(Node::ToggleItalics, token.span),
|
||||||
Star => self.append_consumed(Node::ToggleBold, token.span),
|
Star => self.append_consumed(Node::ToggleBolder, token.span),
|
||||||
Backtick => self.append_consumed(Node::ToggleMonospace, token.span),
|
Backtick => self.append_consumed(Node::ToggleMonospace, token.span),
|
||||||
|
|
||||||
// Normal text.
|
// Normal text.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user