mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Prune derives
This commit is contained in:
parent
f38eb10c2b
commit
0dd4ae0a7a
42
src/color.rs
42
src/color.rs
@ -12,14 +12,6 @@ pub enum Color {
|
|||||||
Rgba(RgbaColor),
|
Rgba(RgbaColor),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Color {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Rgba(c) => Display::fmt(c, f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for Color {
|
impl Debug for Color {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@ -28,6 +20,14 @@ impl Debug for Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Color {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Rgba(c) => Display::fmt(c, f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An 8-bit RGBA color.
|
/// An 8-bit RGBA color.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||||
pub struct RgbaColor {
|
pub struct RgbaColor {
|
||||||
@ -97,16 +97,6 @@ impl FromStr for RgbaColor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for RgbaColor {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
write!(f, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b)?;
|
|
||||||
if self.a != 255 {
|
|
||||||
write!(f, "{:02x}", self.a)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for RgbaColor {
|
impl Debug for RgbaColor {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
@ -121,18 +111,28 @@ impl Debug for RgbaColor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for RgbaColor {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
write!(f, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b)?;
|
||||||
|
if self.a != 255 {
|
||||||
|
write!(f, "{:02x}", self.a)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The error when parsing an [`RgbaColor`] from a string fails.
|
/// The error when parsing an [`RgbaColor`] from a string fails.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub struct ParseRgbaError;
|
pub struct ParseRgbaError;
|
||||||
|
|
||||||
impl std::error::Error for ParseRgbaError {}
|
impl Display for ParseRgbaError {
|
||||||
|
|
||||||
impl fmt::Display for ParseRgbaError {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
f.pad("invalid color")
|
f.pad("invalid color")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for ParseRgbaError {}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -22,7 +22,7 @@ pub type TypResult<T> = Result<T, Box<Vec<Error>>>;
|
|||||||
pub type StrResult<T> = Result<T, String>;
|
pub type StrResult<T> = Result<T, String>;
|
||||||
|
|
||||||
/// An error in a source file.
|
/// An error in a source file.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
/// The erroneous location in the source code.
|
/// The erroneous location in the source code.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
@ -137,18 +137,18 @@ impl AddAssign for Array {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromIterator<Value> for Array {
|
|
||||||
fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
|
|
||||||
Self(Rc::new(iter.into_iter().collect()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Extend<Value> for Array {
|
impl Extend<Value> for Array {
|
||||||
fn extend<T: IntoIterator<Item = Value>>(&mut self, iter: T) {
|
fn extend<T: IntoIterator<Item = Value>>(&mut self, iter: T) {
|
||||||
Rc::make_mut(&mut self.0).extend(iter);
|
Rc::make_mut(&mut self.0).extend(iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromIterator<Value> for Array {
|
||||||
|
fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
|
||||||
|
Self(Rc::new(iter.into_iter().collect()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl IntoIterator for Array {
|
impl IntoIterator for Array {
|
||||||
type Item = Value;
|
type Item = Value;
|
||||||
type IntoIter = std::vec::IntoIter<Value>;
|
type IntoIter = std::vec::IntoIter<Value>;
|
||||||
|
@ -5,7 +5,6 @@ use crate::syntax::visit::{immutable::visit_expr, Visit};
|
|||||||
use crate::syntax::{Expr, Ident};
|
use crate::syntax::{Expr, Ident};
|
||||||
|
|
||||||
/// A visitor that captures variable slots.
|
/// A visitor that captures variable slots.
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct CapturesVisitor<'a> {
|
pub struct CapturesVisitor<'a> {
|
||||||
external: &'a Scopes<'a>,
|
external: &'a Scopes<'a>,
|
||||||
internal: Scopes<'a>,
|
internal: Scopes<'a>,
|
||||||
|
@ -82,6 +82,12 @@ fn missing_key(key: &Str) -> String {
|
|||||||
format!("dictionary does not contain key: {}", key)
|
format!("dictionary does not contain key: {}", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for Dict {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
f.debug_map().entries(self.0.iter()).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Dict {
|
impl Display for Dict {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
f.write_char('(')?;
|
f.write_char('(')?;
|
||||||
@ -100,12 +106,6 @@ impl Display for Dict {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Dict {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
f.debug_map().entries(self.0.iter()).finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add for Dict {
|
impl Add for Dict {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
@ -124,18 +124,18 @@ impl AddAssign for Dict {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromIterator<(Str, Value)> for Dict {
|
|
||||||
fn from_iter<T: IntoIterator<Item = (Str, Value)>>(iter: T) -> Self {
|
|
||||||
Self(Rc::new(iter.into_iter().collect()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Extend<(Str, Value)> for Dict {
|
impl Extend<(Str, Value)> for Dict {
|
||||||
fn extend<T: IntoIterator<Item = (Str, Value)>>(&mut self, iter: T) {
|
fn extend<T: IntoIterator<Item = (Str, Value)>>(&mut self, iter: T) {
|
||||||
Rc::make_mut(&mut self.0).extend(iter);
|
Rc::make_mut(&mut self.0).extend(iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromIterator<(Str, Value)> for Dict {
|
||||||
|
fn from_iter<T: IntoIterator<Item = (Str, Value)>>(iter: T) -> Self {
|
||||||
|
Self(Rc::new(iter.into_iter().collect()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl IntoIterator for Dict {
|
impl IntoIterator for Dict {
|
||||||
type Item = (Str, Value);
|
type Item = (Str, Value);
|
||||||
type IntoIter = std::collections::btree_map::IntoIter<Str, Value>;
|
type IntoIter = std::collections::btree_map::IntoIter<Str, Value>;
|
||||||
|
@ -38,6 +38,12 @@ impl Function {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for Function {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
f.debug_struct("Function").field("name", &self.0.name).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Function {
|
impl Display for Function {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
f.write_str("<function")?;
|
f.write_str("<function")?;
|
||||||
@ -49,12 +55,6 @@ impl Display for Function {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Function {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("Function").field("name", &self.0.name).finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Function {
|
impl PartialEq for Function {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
// We cast to thin pointers for comparison.
|
// We cast to thin pointers for comparison.
|
||||||
|
135
src/eval/mod.rs
135
src/eval/mod.rs
@ -13,6 +13,7 @@ mod scope;
|
|||||||
mod state;
|
mod state;
|
||||||
mod str;
|
mod str;
|
||||||
mod template;
|
mod template;
|
||||||
|
mod walk;
|
||||||
|
|
||||||
pub use self::str::*;
|
pub use self::str::*;
|
||||||
pub use array::*;
|
pub use array::*;
|
||||||
@ -23,25 +24,24 @@ pub use scope::*;
|
|||||||
pub use state::*;
|
pub use state::*;
|
||||||
pub use template::*;
|
pub use template::*;
|
||||||
pub use value::*;
|
pub use value::*;
|
||||||
|
pub use walk::*;
|
||||||
|
|
||||||
use std::cell::RefMut;
|
use std::cell::RefMut;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Write;
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::diag::{At, Error, StrResult, Trace, Tracepoint, TypResult};
|
use crate::diag::{At, Error, StrResult, Trace, Tracepoint, TypResult};
|
||||||
use crate::geom::{Angle, Fractional, Gen, Length, Relative};
|
use crate::geom::{Angle, Fractional, Length, Relative};
|
||||||
use crate::image::ImageStore;
|
use crate::image::ImageStore;
|
||||||
use crate::layout::{ParChild, ParNode, StackChild, StackNode};
|
|
||||||
use crate::loading::Loader;
|
use crate::loading::Loader;
|
||||||
use crate::parse::parse;
|
use crate::parse::parse;
|
||||||
use crate::source::{SourceId, SourceStore};
|
use crate::source::{SourceId, SourceStore};
|
||||||
use crate::syntax::visit::Visit;
|
use crate::syntax::visit::Visit;
|
||||||
use crate::syntax::*;
|
use crate::syntax::*;
|
||||||
use crate::util::{EcoString, RefMutExt};
|
use crate::util::RefMutExt;
|
||||||
use crate::Context;
|
use crate::Context;
|
||||||
|
|
||||||
/// Evaluate a parsed source file into a module.
|
/// Evaluate a parsed source file into a module.
|
||||||
@ -52,7 +52,7 @@ pub fn eval(ctx: &mut Context, source: SourceId, ast: &SyntaxTree) -> TypResult<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An evaluated module, ready for importing or instantiation.
|
/// An evaluated module, ready for importing or instantiation.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
/// The top-level definitions that were bound in this module.
|
/// The top-level definitions that were bound in this module.
|
||||||
pub scope: Scope,
|
pub scope: Scope,
|
||||||
@ -717,128 +717,3 @@ impl Access for CallExpr {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Walk a syntax node and fill the currently built template.
|
|
||||||
pub trait Walk {
|
|
||||||
/// Walk the node.
|
|
||||||
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Walk for SyntaxTree {
|
|
||||||
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> {
|
|
||||||
for node in self.iter() {
|
|
||||||
node.walk(ctx)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Walk for SyntaxNode {
|
|
||||||
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> {
|
|
||||||
match self {
|
|
||||||
Self::Space => ctx.template.space(),
|
|
||||||
Self::Linebreak(_) => ctx.template.linebreak(),
|
|
||||||
Self::Parbreak(_) => ctx.template.parbreak(),
|
|
||||||
Self::Strong(_) => {
|
|
||||||
ctx.template.modify(|state| state.font_mut().strong ^= true);
|
|
||||||
}
|
|
||||||
Self::Emph(_) => {
|
|
||||||
ctx.template.modify(|state| state.font_mut().emph ^= true);
|
|
||||||
}
|
|
||||||
Self::Text(text) => ctx.template.text(text),
|
|
||||||
Self::Raw(raw) => raw.walk(ctx)?,
|
|
||||||
Self::Heading(heading) => heading.walk(ctx)?,
|
|
||||||
Self::List(list) => list.walk(ctx)?,
|
|
||||||
Self::Enum(enum_) => enum_.walk(ctx)?,
|
|
||||||
Self::Expr(expr) => match expr.eval(ctx)? {
|
|
||||||
Value::None => {}
|
|
||||||
Value::Int(v) => ctx.template.text(v.to_string()),
|
|
||||||
Value::Float(v) => ctx.template.text(v.to_string()),
|
|
||||||
Value::Str(v) => ctx.template.text(v),
|
|
||||||
Value::Template(v) => ctx.template += v,
|
|
||||||
// For values which can't be shown "naturally", we print the
|
|
||||||
// representation in monospace.
|
|
||||||
other => ctx.template.monospace(other.to_string()),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Walk for RawNode {
|
|
||||||
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> {
|
|
||||||
if self.block {
|
|
||||||
ctx.template.parbreak();
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.template.monospace(&self.text);
|
|
||||||
|
|
||||||
if self.block {
|
|
||||||
ctx.template.parbreak();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Walk for HeadingNode {
|
|
||||||
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> {
|
|
||||||
let level = self.level;
|
|
||||||
let body = self.body.eval(ctx)?;
|
|
||||||
|
|
||||||
ctx.template.parbreak();
|
|
||||||
ctx.template.save();
|
|
||||||
ctx.template.modify(move |state| {
|
|
||||||
let font = state.font_mut();
|
|
||||||
let upscale = 1.6 - 0.1 * level as f64;
|
|
||||||
font.size *= upscale;
|
|
||||||
font.strong = true;
|
|
||||||
});
|
|
||||||
ctx.template += body;
|
|
||||||
ctx.template.restore();
|
|
||||||
ctx.template.parbreak();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Walk for ListItem {
|
|
||||||
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> {
|
|
||||||
let body = self.body.eval(ctx)?;
|
|
||||||
walk_item(ctx, '•'.into(), body);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Walk for EnumItem {
|
|
||||||
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> {
|
|
||||||
let body = self.body.eval(ctx)?;
|
|
||||||
let mut label = EcoString::new();
|
|
||||||
write!(&mut label, "{}.", self.number.unwrap_or(1)).unwrap();
|
|
||||||
walk_item(ctx, label, body);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Walk a list or enum item, converting it into a stack.
|
|
||||||
fn walk_item(ctx: &mut EvalContext, label: EcoString, body: Template) {
|
|
||||||
ctx.template += Template::from_block(move |state| {
|
|
||||||
let label = ParNode {
|
|
||||||
dir: state.dirs.cross,
|
|
||||||
line_spacing: state.line_spacing(),
|
|
||||||
children: vec![ParChild::Text(
|
|
||||||
label.clone(),
|
|
||||||
state.aligns.cross,
|
|
||||||
Rc::clone(&state.font),
|
|
||||||
)],
|
|
||||||
};
|
|
||||||
StackNode {
|
|
||||||
dirs: Gen::new(state.dirs.main, state.dirs.cross),
|
|
||||||
children: vec![
|
|
||||||
StackChild::Any(label.into(), Gen::default()),
|
|
||||||
StackChild::Spacing((state.font.size / 2.0).into()),
|
|
||||||
StackChild::Any(body.to_stack(&state).into(), Gen::default()),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
@ -12,7 +12,7 @@ use crate::util::EcoString;
|
|||||||
pub type Slot = Rc<RefCell<Value>>;
|
pub type Slot = Rc<RefCell<Value>>;
|
||||||
|
|
||||||
/// A stack of scopes.
|
/// A stack of scopes.
|
||||||
#[derive(Debug, Default, Clone, PartialEq)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct Scopes<'a> {
|
pub struct Scopes<'a> {
|
||||||
/// The active scope.
|
/// The active scope.
|
||||||
pub top: Scope,
|
pub top: Scope,
|
||||||
@ -65,7 +65,7 @@ impl<'a> Scopes<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A map from variable names to variable slots.
|
/// A map from variable names to variable slots.
|
||||||
#[derive(Default, Clone, PartialEq)]
|
#[derive(Default, Clone)]
|
||||||
pub struct Scope {
|
pub struct Scope {
|
||||||
/// The mapping from names to slots.
|
/// The mapping from names to slots.
|
||||||
values: HashMap<EcoString, Slot>,
|
values: HashMap<EcoString, Slot>,
|
||||||
|
@ -63,7 +63,7 @@ impl Default for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Defines page properties.
|
/// Defines page properties.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct PageState {
|
pub struct PageState {
|
||||||
/// The class of this page.
|
/// The class of this page.
|
||||||
pub class: PaperClass,
|
pub class: PaperClass,
|
||||||
@ -220,7 +220,7 @@ impl Default for FontState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Font family definitions.
|
/// Font family definitions.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct FamilyState {
|
pub struct FamilyState {
|
||||||
/// The user-defined list of font families.
|
/// The user-defined list of font families.
|
||||||
pub list: Rc<Vec<FontFamily>>,
|
pub list: Rc<Vec<FontFamily>>,
|
||||||
@ -250,7 +250,7 @@ impl Default for FamilyState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct LineState {
|
pub struct LineState {
|
||||||
/// Stroke color of the line, defaults to the text color if `None`.
|
/// Stroke color of the line, defaults to the text color if `None`.
|
||||||
pub stroke: Option<Paint>,
|
pub stroke: Option<Paint>,
|
||||||
|
@ -6,7 +6,7 @@ use crate::diag::StrResult;
|
|||||||
use crate::util::EcoString;
|
use crate::util::EcoString;
|
||||||
|
|
||||||
/// A string value with inline storage and clone-on-write semantics.
|
/// A string value with inline storage and clone-on-write semantics.
|
||||||
#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
pub struct Str(EcoString);
|
pub struct Str(EcoString);
|
||||||
|
|
||||||
impl Str {
|
impl Str {
|
||||||
@ -46,6 +46,20 @@ impl Str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Deref for Str {
|
||||||
|
type Target = str;
|
||||||
|
|
||||||
|
fn deref(&self) -> &str {
|
||||||
|
self.0.deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Str {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
Debug::fmt(&self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Str {
|
impl Display for Str {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
f.write_char('"')?;
|
f.write_char('"')?;
|
||||||
@ -63,20 +77,6 @@ impl Display for Str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Str {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
Debug::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Str {
|
|
||||||
type Target = str;
|
|
||||||
|
|
||||||
fn deref(&self) -> &str {
|
|
||||||
self.0.deref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add for Str {
|
impl Add for Str {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
|
@ -160,18 +160,18 @@ impl Template {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Template {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
f.pad("<template>")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for Template {
|
impl Debug for Template {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
f.pad("Template { .. }")
|
f.pad("Template { .. }")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Template {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
f.pad("<template>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for Template {
|
impl PartialEq for Template {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
Rc::ptr_eq(&self.0, &other.0)
|
Rc::ptr_eq(&self.0, &other.0)
|
||||||
@ -465,11 +465,11 @@ impl ParBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn push_inner(&mut self, child: ParChild) {
|
fn push_inner(&mut self, child: ParChild) {
|
||||||
if let ParChild::Text(curr_text, curr_props, curr_align) = &child {
|
if let ParChild::Text(curr_text, curr_align, curr_props) = &child {
|
||||||
if let Some(ParChild::Text(prev_text, prev_props, prev_align)) =
|
if let Some(ParChild::Text(prev_text, prev_align, prev_props)) =
|
||||||
self.children.last_mut()
|
self.children.last_mut()
|
||||||
{
|
{
|
||||||
if prev_align == curr_align && prev_props == curr_props {
|
if prev_align == curr_align && Rc::ptr_eq(prev_props, curr_props) {
|
||||||
prev_text.push_str(&curr_text);
|
prev_text.push_str(&curr_text);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -144,6 +144,12 @@ impl From<usize> for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<RgbaColor> for Value {
|
||||||
|
fn from(v: RgbaColor) -> Self {
|
||||||
|
Self::Color(Color::Rgba(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<&str> for Value {
|
impl From<&str> for Value {
|
||||||
fn from(v: &str) -> Self {
|
fn from(v: &str) -> Self {
|
||||||
Self::Str(v.into())
|
Self::Str(v.into())
|
||||||
@ -162,12 +168,6 @@ impl From<EcoString> for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<RgbaColor> for Value {
|
|
||||||
fn from(v: RgbaColor) -> Self {
|
|
||||||
Self::Color(Color::Rgba(v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Dynamic> for Value {
|
impl From<Dynamic> for Value {
|
||||||
fn from(v: Dynamic) -> Self {
|
fn from(v: Dynamic) -> Self {
|
||||||
Self::Dyn(v)
|
Self::Dyn(v)
|
||||||
@ -181,7 +181,7 @@ impl Dynamic {
|
|||||||
/// Create a new instance from any value that satisifies the required bounds.
|
/// Create a new instance from any value that satisifies the required bounds.
|
||||||
pub fn new<T>(any: T) -> Self
|
pub fn new<T>(any: T) -> Self
|
||||||
where
|
where
|
||||||
T: Type + Debug + Display + Clone + PartialEq + 'static,
|
T: Type + Debug + Display + PartialEq + 'static,
|
||||||
{
|
{
|
||||||
Self(Rc::new(any))
|
Self(Rc::new(any))
|
||||||
}
|
}
|
||||||
@ -202,18 +202,18 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Dynamic {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
Display::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for Dynamic {
|
impl Debug for Dynamic {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
Debug::fmt(&self.0, f)
|
Debug::fmt(&self.0, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Dynamic {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
Display::fmt(&self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for Dynamic {
|
impl PartialEq for Dynamic {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.0.dyn_eq(other)
|
self.0.dyn_eq(other)
|
||||||
@ -228,7 +228,7 @@ trait Bounds: Debug + Display + 'static {
|
|||||||
|
|
||||||
impl<T> Bounds for T
|
impl<T> Bounds for T
|
||||||
where
|
where
|
||||||
T: Type + Debug + Display + Clone + PartialEq + 'static,
|
T: Type + Debug + Display + PartialEq + 'static,
|
||||||
{
|
{
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
@ -309,12 +309,6 @@ macro_rules! primitive {
|
|||||||
const TYPE_NAME: &'static str = $name;
|
const TYPE_NAME: &'static str = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<$type> for Value {
|
|
||||||
fn from(v: $type) -> Self {
|
|
||||||
Value::$variant(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Cast<Value> for $type {
|
impl Cast<Value> for $type {
|
||||||
fn is(value: &Value) -> bool {
|
fn is(value: &Value) -> bool {
|
||||||
matches!(value, Value::$variant(_) $(| Value::$other(_))*)
|
matches!(value, Value::$variant(_) $(| Value::$other(_))*)
|
||||||
@ -332,6 +326,12 @@ macro_rules! primitive {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<$type> for Value {
|
||||||
|
fn from(v: $type) -> Self {
|
||||||
|
Value::$variant(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,17 +342,17 @@ macro_rules! dynamic {
|
|||||||
const TYPE_NAME: &'static str = $name;
|
const TYPE_NAME: &'static str = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<$type> for $crate::eval::Value {
|
|
||||||
fn from(v: $type) -> Self {
|
|
||||||
$crate::eval::Value::Dyn($crate::eval::Dynamic::new(v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
castable! {
|
castable! {
|
||||||
$type: <Self as $crate::eval::Type>::TYPE_NAME,
|
$type: <Self as $crate::eval::Type>::TYPE_NAME,
|
||||||
$($tts)*
|
$($tts)*
|
||||||
@this: Self => this.clone(),
|
@this: Self => this.clone(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<$type> for $crate::eval::Value {
|
||||||
|
fn from(v: $type) -> Self {
|
||||||
|
$crate::eval::Value::Dyn($crate::eval::Dynamic::new(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
129
src/eval/walk.rs
Normal file
129
src/eval/walk.rs
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
use std::fmt::Write;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use super::{Eval, EvalContext, Template, Value};
|
||||||
|
use crate::diag::TypResult;
|
||||||
|
use crate::geom::Gen;
|
||||||
|
use crate::layout::{ParChild, ParNode, StackChild, StackNode};
|
||||||
|
use crate::syntax::*;
|
||||||
|
use crate::util::EcoString;
|
||||||
|
|
||||||
|
/// Walk a syntax node and fill the currently built template.
|
||||||
|
pub trait Walk {
|
||||||
|
/// Walk the node.
|
||||||
|
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Walk for SyntaxTree {
|
||||||
|
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> {
|
||||||
|
for node in self.iter() {
|
||||||
|
node.walk(ctx)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Walk for SyntaxNode {
|
||||||
|
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> {
|
||||||
|
match self {
|
||||||
|
Self::Space => ctx.template.space(),
|
||||||
|
Self::Linebreak(_) => ctx.template.linebreak(),
|
||||||
|
Self::Parbreak(_) => ctx.template.parbreak(),
|
||||||
|
Self::Strong(_) => ctx.template.modify(|s| s.font_mut().strong ^= true),
|
||||||
|
Self::Emph(_) => ctx.template.modify(|s| s.font_mut().emph ^= true),
|
||||||
|
Self::Text(text) => ctx.template.text(text),
|
||||||
|
Self::Raw(raw) => raw.walk(ctx)?,
|
||||||
|
Self::Heading(heading) => heading.walk(ctx)?,
|
||||||
|
Self::List(list) => list.walk(ctx)?,
|
||||||
|
Self::Enum(enum_) => enum_.walk(ctx)?,
|
||||||
|
Self::Expr(expr) => match expr.eval(ctx)? {
|
||||||
|
Value::None => {}
|
||||||
|
Value::Int(v) => ctx.template.text(v.to_string()),
|
||||||
|
Value::Float(v) => ctx.template.text(v.to_string()),
|
||||||
|
Value::Str(v) => ctx.template.text(v),
|
||||||
|
Value::Template(v) => ctx.template += v,
|
||||||
|
// For values which can't be shown "naturally", we print the
|
||||||
|
// representation in monospace.
|
||||||
|
other => ctx.template.monospace(other.to_string()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Walk for RawNode {
|
||||||
|
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> {
|
||||||
|
if self.block {
|
||||||
|
ctx.template.parbreak();
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.template.monospace(&self.text);
|
||||||
|
|
||||||
|
if self.block {
|
||||||
|
ctx.template.parbreak();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Walk for HeadingNode {
|
||||||
|
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> {
|
||||||
|
let level = self.level;
|
||||||
|
let body = self.body.eval(ctx)?;
|
||||||
|
|
||||||
|
ctx.template.parbreak();
|
||||||
|
ctx.template.save();
|
||||||
|
ctx.template.modify(move |state| {
|
||||||
|
let font = state.font_mut();
|
||||||
|
let upscale = 1.6 - 0.1 * level as f64;
|
||||||
|
font.size *= upscale;
|
||||||
|
font.strong = true;
|
||||||
|
});
|
||||||
|
ctx.template += body;
|
||||||
|
ctx.template.restore();
|
||||||
|
ctx.template.parbreak();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Walk for ListNode {
|
||||||
|
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> {
|
||||||
|
let body = self.body.eval(ctx)?;
|
||||||
|
walk_item(ctx, '•'.into(), body);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Walk for EnumNode {
|
||||||
|
fn walk(&self, ctx: &mut EvalContext) -> TypResult<()> {
|
||||||
|
let body = self.body.eval(ctx)?;
|
||||||
|
let mut label = EcoString::new();
|
||||||
|
write!(&mut label, "{}.", self.number.unwrap_or(1)).unwrap();
|
||||||
|
walk_item(ctx, label, body);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk_item(ctx: &mut EvalContext, label: EcoString, body: Template) {
|
||||||
|
ctx.template += Template::from_block(move |state| {
|
||||||
|
let label = ParNode {
|
||||||
|
dir: state.dirs.cross,
|
||||||
|
line_spacing: state.line_spacing(),
|
||||||
|
children: vec![ParChild::Text(
|
||||||
|
label.clone(),
|
||||||
|
state.aligns.cross,
|
||||||
|
Rc::clone(&state.font),
|
||||||
|
)],
|
||||||
|
};
|
||||||
|
StackNode {
|
||||||
|
dirs: Gen::new(state.dirs.main, state.dirs.cross),
|
||||||
|
children: vec![
|
||||||
|
StackChild::Any(label.into(), Gen::default()),
|
||||||
|
StackChild::Spacing((state.font.size / 2.0).into()),
|
||||||
|
StackChild::Any(body.to_stack(&state).into(), Gen::default()),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
47
src/font.rs
47
src/font.rs
@ -14,8 +14,7 @@ use crate::geom::Length;
|
|||||||
use crate::loading::{FileHash, Loader};
|
use crate::loading::{FileHash, Loader};
|
||||||
|
|
||||||
/// A unique identifier for a loaded font face.
|
/// A unique identifier for a loaded font face.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct FaceId(u32);
|
pub struct FaceId(u32);
|
||||||
|
|
||||||
impl FaceId {
|
impl FaceId {
|
||||||
@ -271,7 +270,7 @@ impl Face {
|
|||||||
/// A length in em units.
|
/// A length in em units.
|
||||||
///
|
///
|
||||||
/// `1em` is the same as the font size.
|
/// `1em` is the same as the font size.
|
||||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, PartialOrd)]
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
pub struct Em(N64);
|
pub struct Em(N64);
|
||||||
|
|
||||||
impl Em {
|
impl Em {
|
||||||
@ -343,11 +342,15 @@ impl Display for VerticalFontMetric {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A generic or named font family.
|
/// A generic or named font family.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum FontFamily {
|
pub enum FontFamily {
|
||||||
|
/// A family that has "serifs", small strokes attached to letters.
|
||||||
Serif,
|
Serif,
|
||||||
|
/// A family in which glyphs do not have "serifs", small attached strokes.
|
||||||
SansSerif,
|
SansSerif,
|
||||||
|
/// A family in which (almost) all glyphs are of equal width.
|
||||||
Monospace,
|
Monospace,
|
||||||
|
/// A specific family with a name.
|
||||||
Named(String),
|
Named(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,15 +578,6 @@ impl Default for FontWeight {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for FontWeight {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
match self.to_str() {
|
|
||||||
Some(name) => f.pad(name),
|
|
||||||
None => write!(f, "{}", self.0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for FontWeight {
|
impl Debug for FontWeight {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
f.pad(match *self {
|
f.pad(match *self {
|
||||||
@ -601,6 +595,15 @@ impl Debug for FontWeight {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for FontWeight {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
match self.to_str() {
|
||||||
|
Some(name) => f.pad(name),
|
||||||
|
None => write!(f, "{}", self.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The width of a font face.
|
/// The width of a font face.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@ -707,15 +710,6 @@ impl Default for FontStretch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for FontStretch {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
match self.to_str() {
|
|
||||||
Some(name) => f.pad(name),
|
|
||||||
None => write!(f, "{}", self.to_ratio()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for FontStretch {
|
impl Debug for FontStretch {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
f.pad(match *self {
|
f.pad(match *self {
|
||||||
@ -733,6 +727,15 @@ impl Debug for FontStretch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for FontStretch {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
match self.to_str() {
|
||||||
|
Some(name) => f.pad(name),
|
||||||
|
None => write!(f, "{}", self.to_ratio()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
use super::*;
|
|
||||||
use decorum::N64;
|
use decorum::N64;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
/// An angle.
|
/// An angle.
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Angle(N64);
|
pub struct Angle(N64);
|
||||||
|
|
||||||
impl Angle {
|
impl Angle {
|
||||||
@ -52,6 +55,13 @@ impl Angle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for Angle {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
let unit = AngularUnit::Deg;
|
||||||
|
write!(f, "{}{}", self.to_unit(unit), unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Angle {
|
impl Display for Angle {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
// Format with the unit that yields the shortest output, preferring
|
// Format with the unit that yields the shortest output, preferring
|
||||||
@ -66,13 +76,6 @@ impl Display for Angle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Angle {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
let unit = AngularUnit::Deg;
|
|
||||||
write!(f, "{}{}", self.to_unit(unit), unit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Neg for Angle {
|
impl Neg for Angle {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
@ -134,7 +137,7 @@ impl Sum for Angle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Different units of angular measurement.
|
/// Different units of angular measurement.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub enum AngularUnit {
|
pub enum AngularUnit {
|
||||||
/// Radians.
|
/// Radians.
|
||||||
Rad,
|
Rad,
|
||||||
|
@ -33,18 +33,18 @@ impl Fractional {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Fractional {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}fr", self.get())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for Fractional {
|
impl Debug for Fractional {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
Display::fmt(self, f)
|
Display::fmt(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Fractional {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}fr", self.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Neg for Fractional {
|
impl Neg for Fractional {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
|
@ -126,6 +126,13 @@ impl Length {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for Length {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
let unit = LengthUnit::Pt;
|
||||||
|
write!(f, "{}{}", self.to_unit(unit), unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Length {
|
impl Display for Length {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
use LengthUnit::*;
|
use LengthUnit::*;
|
||||||
@ -142,13 +149,6 @@ impl Display for Length {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Length {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
let unit = LengthUnit::Pt;
|
|
||||||
write!(f, "{}{}", self.to_unit(unit), unit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Neg for Length {
|
impl Neg for Length {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
@ -217,7 +217,7 @@ impl<'a> Sum<&'a Length> for Length {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Different units of length measurement.
|
/// Different units of length measurement.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub enum LengthUnit {
|
pub enum LengthUnit {
|
||||||
/// Points.
|
/// Points.
|
||||||
Pt,
|
Pt,
|
||||||
|
@ -47,18 +47,18 @@ impl Linear {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Linear {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{} + {}", self.rel, self.abs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for Linear {
|
impl Debug for Linear {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
write!(f, "{:?} + {:?}", self.rel, self.abs)
|
write!(f, "{:?} + {:?}", self.rel, self.abs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Linear {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{} + {}", self.rel, self.abs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Length> for Linear {
|
impl From<Length> for Linear {
|
||||||
fn from(abs: Length) -> Self {
|
fn from(abs: Length) -> Self {
|
||||||
Self { rel: Relative::zero(), abs }
|
Self { rel: Relative::zero(), abs }
|
||||||
|
@ -46,18 +46,18 @@ impl Relative {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Relative {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}%", 100.0 * self.get())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for Relative {
|
impl Debug for Relative {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
Display::fmt(self, f)
|
Display::fmt(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Relative {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}%", 100.0 * self.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Neg for Relative {
|
impl Neg for Relative {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
|
@ -33,6 +33,14 @@ impl<T> Sides<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Sides<Length> {
|
||||||
|
/// A size with `left` and `right` summed into `width`, and `top` and
|
||||||
|
/// `bottom` summed into `height`.
|
||||||
|
pub fn size(self) -> Size {
|
||||||
|
Size::new(self.left + self.right, self.top + self.bottom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Sides<Linear> {
|
impl Sides<Linear> {
|
||||||
/// Resolve the linear sides relative to the given `size`.
|
/// Resolve the linear sides relative to the given `size`.
|
||||||
pub fn resolve(self, size: Size) -> Sides<Length> {
|
pub fn resolve(self, size: Size) -> Sides<Length> {
|
||||||
@ -45,14 +53,6 @@ impl Sides<Linear> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sides<Length> {
|
|
||||||
/// A size with `left` and `right` summed into `width`, and `top` and
|
|
||||||
/// `bottom` summed into `height`.
|
|
||||||
pub fn size(self) -> Size {
|
|
||||||
Size::new(self.left + self.right, self.top + self.bottom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Get<Side> for Sides<T> {
|
impl<T> Get<Side> for Sides<T> {
|
||||||
type Component = T;
|
type Component = T;
|
||||||
|
|
||||||
|
@ -13,8 +13,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::loading::{FileHash, Loader};
|
use crate::loading::{FileHash, Loader};
|
||||||
|
|
||||||
/// A unique identifier for a loaded image.
|
/// A unique identifier for a loaded image.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct ImageId(u32);
|
pub struct ImageId(u32);
|
||||||
|
|
||||||
impl ImageId {
|
impl ImageId {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A node that places a rectangular filled background behind its child.
|
/// A node that places a rectangular filled background behind its child.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||||
pub struct BackgroundNode {
|
pub struct BackgroundNode {
|
||||||
/// The kind of shape to use as a background.
|
/// The kind of shape to use as a background.
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Carries an item that is only valid in certain regions and the constraints
|
/// Carries an item that is only valid in certain regions and the constraints
|
||||||
@ -12,14 +10,6 @@ pub struct Constrained<T> {
|
|||||||
pub constraints: Constraints,
|
pub constraints: Constraints,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Deref for Constrained<T> {
|
|
||||||
type Target = T;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Describe regions that match them.
|
/// Describe regions that match them.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub struct Constraints {
|
pub struct Constraints {
|
||||||
|
@ -3,7 +3,6 @@ use decorum::N64;
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A node that can fix its child's width and height.
|
/// A node that can fix its child's width and height.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||||
pub struct FixedNode {
|
pub struct FixedNode {
|
||||||
/// The fixed width, if any.
|
/// The fixed width, if any.
|
||||||
@ -78,7 +77,7 @@ impl Layout for FixedNode {
|
|||||||
// relayout with expansion.
|
// relayout with expansion.
|
||||||
if let Some(aspect) = aspect {
|
if let Some(aspect) = aspect {
|
||||||
if width.is_none() && height.is_none() {
|
if width.is_none() && height.is_none() {
|
||||||
let needed = frames[0].size.cap(size);
|
let needed = frames[0].item.size.cap(size);
|
||||||
let width = needed.width.max(aspect * needed.height);
|
let width = needed.width.max(aspect * needed.height);
|
||||||
regions.current = Size::new(width, width / aspect);
|
regions.current = Size::new(width, width / aspect);
|
||||||
regions.expand = Spec::splat(true);
|
regions.expand = Spec::splat(true);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A node that arranges its children in a grid.
|
/// A node that arranges its children in a grid.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||||
pub struct GridNode {
|
pub struct GridNode {
|
||||||
/// The `main` and `cross` directions of this grid.
|
/// The `main` and `cross` directions of this grid.
|
||||||
@ -256,7 +255,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
for node in (0 .. self.rows.len()).filter_map(|y| self.cell(x, y)) {
|
for node in (0 .. self.rows.len()).filter_map(|y| self.cell(x, y)) {
|
||||||
let size = Gen::new(available, Length::inf()).to_size(self.main);
|
let size = Gen::new(available, Length::inf()).to_size(self.main);
|
||||||
let regions = Regions::one(size, size, Spec::splat(false));
|
let regions = Regions::one(size, size, Spec::splat(false));
|
||||||
let frame = node.layout(ctx, ®ions).remove(0);
|
let frame = node.layout(ctx, ®ions).remove(0).item;
|
||||||
resolved.set_max(frame.size.get(self.cross));
|
resolved.set_max(frame.size.get(self.cross));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,7 +352,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
let mut sizes = node
|
let mut sizes = node
|
||||||
.layout(ctx, &self.regions)
|
.layout(ctx, &self.regions)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|frame| frame.size.get(self.main));
|
.map(|frame| frame.item.size.get(self.main));
|
||||||
|
|
||||||
if let Some(size) = sizes.next() {
|
if let Some(size) = sizes.next() {
|
||||||
first.set_max(size);
|
first.set_max(size);
|
||||||
|
@ -4,7 +4,6 @@ use crate::image::ImageId;
|
|||||||
use ::image::GenericImageView;
|
use ::image::GenericImageView;
|
||||||
|
|
||||||
/// An image node.
|
/// An image node.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||||
pub struct ImageNode {
|
pub struct ImageNode {
|
||||||
/// The id of the image file.
|
/// The id of the image file.
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A node that adds padding to its child.
|
/// A node that adds padding to its child.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||||
pub struct PadNode {
|
pub struct PadNode {
|
||||||
/// The amount of padding.
|
/// The amount of padding.
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use std::fmt::{self, Debug, Formatter};
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use unicode_bidi::{BidiInfo, Level};
|
use unicode_bidi::{BidiInfo, Level};
|
||||||
@ -11,7 +10,6 @@ use crate::util::{EcoString, RangeExt, SliceExt};
|
|||||||
type Range = std::ops::Range<usize>;
|
type Range = std::ops::Range<usize>;
|
||||||
|
|
||||||
/// A node that arranges its children into a paragraph.
|
/// A node that arranges its children into a paragraph.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||||
pub struct ParNode {
|
pub struct ParNode {
|
||||||
/// The inline direction of this paragraph.
|
/// The inline direction of this paragraph.
|
||||||
@ -23,7 +21,6 @@ pub struct ParNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A child of a paragraph node.
|
/// A child of a paragraph node.
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||||
pub enum ParChild {
|
pub enum ParChild {
|
||||||
/// Spacing between other nodes.
|
/// Spacing between other nodes.
|
||||||
@ -94,18 +91,6 @@ impl From<ParNode> for LayoutNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for ParChild {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Spacing(amount) => write!(f, "Spacing({:?})", amount),
|
|
||||||
Self::Text(text, align, _) => write!(f, "Text({:?}, {:?})", text, align),
|
|
||||||
Self::Any(any, align) => {
|
|
||||||
f.debug_tuple("Any").field(any).field(align).finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A paragraph representation in which children are already layouted and text
|
/// A paragraph representation in which children are already layouted and text
|
||||||
/// is separated into shapable runs.
|
/// is separated into shapable runs.
|
||||||
struct ParLayouter<'a> {
|
struct ParLayouter<'a> {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use rustybuzz::UnicodeBuffer;
|
use rustybuzz::UnicodeBuffer;
|
||||||
@ -11,12 +10,45 @@ use crate::geom::{Dir, Length, Point, Size};
|
|||||||
use crate::layout::Geometry;
|
use crate::layout::Geometry;
|
||||||
use crate::util::SliceExt;
|
use crate::util::SliceExt;
|
||||||
|
|
||||||
|
/// Shape text into [`ShapedText`].
|
||||||
|
pub fn shape<'a>(
|
||||||
|
ctx: &mut LayoutContext,
|
||||||
|
text: &'a str,
|
||||||
|
dir: Dir,
|
||||||
|
state: &'a FontState,
|
||||||
|
) -> ShapedText<'a> {
|
||||||
|
let mut glyphs = vec![];
|
||||||
|
if !text.is_empty() {
|
||||||
|
shape_segment(
|
||||||
|
ctx,
|
||||||
|
&mut glyphs,
|
||||||
|
0,
|
||||||
|
text,
|
||||||
|
dir,
|
||||||
|
state.size,
|
||||||
|
state.variant(),
|
||||||
|
state.families(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (size, baseline) = measure(ctx, &glyphs, state);
|
||||||
|
|
||||||
|
ShapedText {
|
||||||
|
text,
|
||||||
|
dir,
|
||||||
|
state,
|
||||||
|
size,
|
||||||
|
baseline,
|
||||||
|
glyphs: Cow::Owned(glyphs),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The result of shaping text.
|
/// The result of shaping text.
|
||||||
///
|
///
|
||||||
/// This type contains owned or borrowed shaped text runs, which can be
|
/// This type contains owned or borrowed shaped text runs, which can be
|
||||||
/// measured, used to reshape substrings more quickly and converted into a
|
/// measured, used to reshape substrings more quickly and converted into a
|
||||||
/// frame.
|
/// frame.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ShapedText<'a> {
|
pub struct ShapedText<'a> {
|
||||||
/// The text that was shaped.
|
/// The text that was shaped.
|
||||||
pub text: &'a str,
|
pub text: &'a str,
|
||||||
@ -33,7 +65,7 @@ pub struct ShapedText<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A single glyph resulting from shaping.
|
/// A single glyph resulting from shaping.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct ShapedGlyph {
|
pub struct ShapedGlyph {
|
||||||
/// The font face the glyph is contained in.
|
/// The font face the glyph is contained in.
|
||||||
pub face_id: FaceId,
|
pub face_id: FaceId,
|
||||||
@ -51,13 +83,6 @@ pub struct ShapedGlyph {
|
|||||||
pub safe_to_break: bool,
|
pub safe_to_break: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A visual side.
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
|
||||||
enum Side {
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ShapedText<'a> {
|
impl<'a> ShapedText<'a> {
|
||||||
/// Build the shaped text's frame.
|
/// Build the shaped text's frame.
|
||||||
pub fn build(&self, ctx: &LayoutContext) -> Frame {
|
pub fn build(&self, ctx: &LayoutContext) -> Frame {
|
||||||
@ -174,44 +199,10 @@ impl<'a> ShapedText<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for ShapedText<'_> {
|
/// A visual side.
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
enum Side {
|
||||||
write!(f, "Shaped({:?})", self.text)
|
Left,
|
||||||
}
|
Right,
|
||||||
}
|
|
||||||
|
|
||||||
/// Shape text into [`ShapedText`].
|
|
||||||
pub fn shape<'a>(
|
|
||||||
ctx: &mut LayoutContext,
|
|
||||||
text: &'a str,
|
|
||||||
dir: Dir,
|
|
||||||
state: &'a FontState,
|
|
||||||
) -> ShapedText<'a> {
|
|
||||||
let mut glyphs = vec![];
|
|
||||||
if !text.is_empty() {
|
|
||||||
shape_segment(
|
|
||||||
ctx,
|
|
||||||
&mut glyphs,
|
|
||||||
0,
|
|
||||||
text,
|
|
||||||
dir,
|
|
||||||
state.size,
|
|
||||||
state.variant(),
|
|
||||||
state.families(),
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (size, baseline) = measure(ctx, &glyphs, state);
|
|
||||||
|
|
||||||
ShapedText {
|
|
||||||
text,
|
|
||||||
dir,
|
|
||||||
state,
|
|
||||||
size,
|
|
||||||
baseline,
|
|
||||||
glyphs: Cow::Owned(glyphs),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shape text with font fallback using the `families` iterator.
|
/// Shape text with font fallback using the `families` iterator.
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A node that stacks its children.
|
/// A node that stacks its children.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||||
pub struct StackNode {
|
pub struct StackNode {
|
||||||
/// The `main` and `cross` directions of this stack.
|
/// The `main` and `cross` directions of this stack.
|
||||||
@ -14,7 +13,6 @@ pub struct StackNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A child of a stack node.
|
/// A child of a stack node.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||||
pub enum StackChild {
|
pub enum StackChild {
|
||||||
/// Spacing between other nodes.
|
/// Spacing between other nodes.
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
|
||||||
|
|
||||||
#[cfg(feature = "layout-cache")]
|
#[cfg(feature = "layout-cache")]
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
@ -10,7 +9,6 @@ use std::hash::{Hash, Hasher};
|
|||||||
use fxhash::FxHasher64;
|
use fxhash::FxHasher64;
|
||||||
|
|
||||||
/// A tree of layout nodes.
|
/// A tree of layout nodes.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub struct LayoutTree {
|
pub struct LayoutTree {
|
||||||
/// Runs of pages with the same properties.
|
/// Runs of pages with the same properties.
|
||||||
pub runs: Vec<PageRun>,
|
pub runs: Vec<PageRun>,
|
||||||
@ -24,7 +22,6 @@ impl LayoutTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A run of pages that all have the same properties.
|
/// A run of pages that all have the same properties.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub struct PageRun {
|
pub struct PageRun {
|
||||||
/// The size of each page.
|
/// The size of each page.
|
||||||
pub size: Size,
|
pub size: Size,
|
||||||
@ -47,7 +44,7 @@ impl PageRun {
|
|||||||
|
|
||||||
/// A dynamic layouting node.
|
/// A dynamic layouting node.
|
||||||
pub struct LayoutNode {
|
pub struct LayoutNode {
|
||||||
node: Box<dyn Bounds>,
|
node: Box<dyn Layout>,
|
||||||
#[cfg(feature = "layout-cache")]
|
#[cfg(feature = "layout-cache")]
|
||||||
hash: u64,
|
hash: u64,
|
||||||
}
|
}
|
||||||
@ -57,7 +54,7 @@ impl LayoutNode {
|
|||||||
#[cfg(not(feature = "layout-cache"))]
|
#[cfg(not(feature = "layout-cache"))]
|
||||||
pub fn new<T>(node: T) -> Self
|
pub fn new<T>(node: T) -> Self
|
||||||
where
|
where
|
||||||
T: Layout + Debug + Clone + Eq + PartialEq + 'static,
|
T: Layout + 'static,
|
||||||
{
|
{
|
||||||
Self { node: Box::new(node) }
|
Self { node: Box::new(node) }
|
||||||
}
|
}
|
||||||
@ -66,7 +63,7 @@ impl LayoutNode {
|
|||||||
#[cfg(feature = "layout-cache")]
|
#[cfg(feature = "layout-cache")]
|
||||||
pub fn new<T>(node: T) -> Self
|
pub fn new<T>(node: T) -> Self
|
||||||
where
|
where
|
||||||
T: Layout + Debug + Clone + Eq + PartialEq + Hash + 'static,
|
T: Layout + Hash + 'static,
|
||||||
{
|
{
|
||||||
let hash = {
|
let hash = {
|
||||||
let mut state = FxHasher64::default();
|
let mut state = FxHasher64::default();
|
||||||
@ -99,60 +96,9 @@ impl Layout for LayoutNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for LayoutNode {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
self.node.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for LayoutNode {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
node: self.node.dyn_clone(),
|
|
||||||
#[cfg(feature = "layout-cache")]
|
|
||||||
hash: self.hash,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for LayoutNode {}
|
|
||||||
|
|
||||||
impl PartialEq for LayoutNode {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.node.dyn_eq(other.node.as_ref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "layout-cache")]
|
#[cfg(feature = "layout-cache")]
|
||||||
impl Hash for LayoutNode {
|
impl Hash for LayoutNode {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
state.write_u64(self.hash);
|
state.write_u64(self.hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Bounds: Layout + Debug + 'static {
|
|
||||||
fn as_any(&self) -> &dyn Any;
|
|
||||||
fn dyn_eq(&self, other: &dyn Bounds) -> bool;
|
|
||||||
fn dyn_clone(&self) -> Box<dyn Bounds>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Bounds for T
|
|
||||||
where
|
|
||||||
T: Layout + Debug + Eq + PartialEq + Clone + 'static,
|
|
||||||
{
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dyn_eq(&self, other: &dyn Bounds) -> bool {
|
|
||||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
|
||||||
self == other
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dyn_clone(&self) -> Box<dyn Bounds> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -13,7 +13,7 @@ use crate::font::FaceInfo;
|
|||||||
/// Loads fonts and files from the local file system.
|
/// Loads fonts and files from the local file system.
|
||||||
///
|
///
|
||||||
/// _This is only available when the `fs` feature is enabled._
|
/// _This is only available when the `fs` feature is enabled._
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Default)]
|
||||||
pub struct FsLoader {
|
pub struct FsLoader {
|
||||||
faces: Vec<FaceInfo>,
|
faces: Vec<FaceInfo>,
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ use crate::font::FaceInfo;
|
|||||||
use crate::util::PathExt;
|
use crate::util::PathExt;
|
||||||
|
|
||||||
/// Loads fonts and files from an in-memory storage.
|
/// Loads fonts and files from an in-memory storage.
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Default)]
|
||||||
pub struct MemLoader {
|
pub struct MemLoader {
|
||||||
faces: Vec<FaceInfo>,
|
faces: Vec<FaceInfo>,
|
||||||
files: HashMap<PathBuf, Cow<'static, [u8]>>,
|
files: HashMap<PathBuf, Cow<'static, [u8]>>,
|
||||||
|
@ -11,15 +11,12 @@ pub use mem::*;
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::font::FaceInfo;
|
use crate::font::FaceInfo;
|
||||||
|
|
||||||
/// A hash that identifies a file.
|
/// A hash that identifies a file.
|
||||||
///
|
///
|
||||||
/// Such a hash can be [resolved](Loader::resolve) from a path.
|
/// Such a hash can be [resolved](Loader::resolve) from a path.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct FileHash(pub u64);
|
pub struct FileHash(pub u64);
|
||||||
|
|
||||||
/// Loads resources from a local or remote source.
|
/// Loads resources from a local or remote source.
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use crate::geom::{Length, Linear, Relative, Sides, Size};
|
use crate::geom::{Length, Linear, Relative, Sides, Size};
|
||||||
|
|
||||||
/// Specification of a paper.
|
/// Specification of a paper.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct Paper {
|
pub struct Paper {
|
||||||
/// The broad class this paper belongs to.
|
/// The broad class this paper belongs to.
|
||||||
class: PaperClass,
|
class: PaperClass,
|
||||||
|
@ -201,7 +201,7 @@ fn list_item(p: &mut Parser) -> SyntaxNode {
|
|||||||
let column = p.column(start);
|
let column = p.column(start);
|
||||||
p.eat_assert(Token::Hyph);
|
p.eat_assert(Token::Hyph);
|
||||||
let body = tree_indented(p, column);
|
let body = tree_indented(p, column);
|
||||||
SyntaxNode::List(Box::new(ListItem { span: p.span_from(start), body }))
|
SyntaxNode::List(Box::new(ListNode { span: p.span_from(start), body }))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a single enum item.
|
/// Parse a single enum item.
|
||||||
@ -210,7 +210,7 @@ fn enum_item(p: &mut Parser, number: Option<usize>) -> SyntaxNode {
|
|||||||
let column = p.column(start);
|
let column = p.column(start);
|
||||||
p.eat_assert(Token::Numbering(number));
|
p.eat_assert(Token::Numbering(number));
|
||||||
let body = tree_indented(p, column);
|
let body = tree_indented(p, column);
|
||||||
SyntaxNode::Enum(Box::new(EnumItem {
|
SyntaxNode::Enum(Box::new(EnumNode {
|
||||||
span: p.span_from(start),
|
span: p.span_from(start),
|
||||||
number,
|
number,
|
||||||
body,
|
body,
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use std::fmt::{self, Debug, Formatter};
|
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use super::{TokenMode, Tokens};
|
use super::{TokenMode, Tokens};
|
||||||
@ -28,7 +27,6 @@ pub struct Parser<'s> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A logical group of tokens, e.g. `[...]`.
|
/// A logical group of tokens, e.g. `[...]`.
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
struct GroupEntry {
|
struct GroupEntry {
|
||||||
/// The start index of the group. Used by `Parser::end_group` to return the
|
/// The start index of the group. Used by `Parser::end_group` to return the
|
||||||
/// group's full span.
|
/// group's full span.
|
||||||
@ -391,11 +389,3 @@ impl<'s> Parser<'s> {
|
|||||||
self.groups.iter().any(|g| g.kind == kind)
|
self.groups.iter().any(|g| g.kind == kind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Parser<'_> {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
let mut s = self.tokens.scanner();
|
|
||||||
s.jump(self.next_start());
|
|
||||||
write!(f, "Parser({}|{})", s.eaten(), s.rest())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use std::fmt::{self, Debug, Formatter};
|
|
||||||
use std::slice::SliceIndex;
|
use std::slice::SliceIndex;
|
||||||
|
|
||||||
/// A featureful char-based scanner.
|
/// A featureful char-based scanner.
|
||||||
@ -153,12 +152,6 @@ impl<'s> Scanner<'s> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Scanner<'_> {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
write!(f, "Scanner({}|{})", self.eaten(), self.rest())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether this character denotes a newline.
|
/// Whether this character denotes a newline.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_newline(character: char) -> bool {
|
pub fn is_newline(character: char) -> bool {
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
use std::fmt::{self, Debug, Formatter};
|
|
||||||
|
|
||||||
use super::{is_newline, Scanner};
|
use super::{is_newline, Scanner};
|
||||||
use crate::geom::{AngularUnit, LengthUnit};
|
use crate::geom::{AngularUnit, LengthUnit};
|
||||||
use crate::syntax::*;
|
use crate::syntax::*;
|
||||||
|
|
||||||
/// An iterator over the tokens of a string of source code.
|
/// An iterator over the tokens of a string of source code.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Tokens<'s> {
|
pub struct Tokens<'s> {
|
||||||
s: Scanner<'s>,
|
s: Scanner<'s>,
|
||||||
mode: TokenMode,
|
mode: TokenMode,
|
||||||
@ -481,12 +478,6 @@ impl<'s> Tokens<'s> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Tokens<'_> {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
write!(f, "Tokens({}|{})", self.s.eaten(), self.s.rest())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn keyword(ident: &str) -> Option<Token<'static>> {
|
fn keyword(ident: &str) -> Option<Token<'static>> {
|
||||||
Some(match ident {
|
Some(match ident {
|
||||||
"not" => Token::Not,
|
"not" => Token::Not,
|
||||||
@ -512,6 +503,8 @@ fn keyword(ident: &str) -> Option<Token<'static>> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use Option::None;
|
use Option::None;
|
||||||
|
@ -15,8 +15,7 @@ use crate::parse::{is_newline, Scanner};
|
|||||||
use crate::util::PathExt;
|
use crate::util::PathExt;
|
||||||
|
|
||||||
/// A unique identifier for a loaded source file.
|
/// A unique identifier for a loaded source file.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct SourceId(u32);
|
pub struct SourceId(u32);
|
||||||
|
|
||||||
impl SourceId {
|
impl SourceId {
|
||||||
@ -252,12 +251,6 @@ impl SourceFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<str> for SourceFile {
|
|
||||||
fn as_ref(&self) -> &str {
|
|
||||||
&self.src
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The indices at which lines start (right behind newlines).
|
/// The indices at which lines start (right behind newlines).
|
||||||
///
|
///
|
||||||
/// The beginning of the string (index 0) is not returned.
|
/// The beginning of the string (index 0) is not returned.
|
||||||
@ -276,6 +269,12 @@ fn newlines(string: &str) -> impl Iterator<Item = usize> + '_ {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsRef<str> for SourceFile {
|
||||||
|
fn as_ref(&self) -> &str {
|
||||||
|
&self.src
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "codespan-reporting")]
|
#[cfg(feature = "codespan-reporting")]
|
||||||
impl<'a> Files<'a> for SourceStore {
|
impl<'a> Files<'a> for SourceStore {
|
||||||
type FileId = SourceId;
|
type FileId = SourceId;
|
||||||
|
@ -12,7 +12,7 @@ use crate::util::EcoString;
|
|||||||
/// - `_` and `-` as continuing characters.
|
/// - `_` and `-` as continuing characters.
|
||||||
///
|
///
|
||||||
/// [uax31]: http://www.unicode.org/reports/tr31/
|
/// [uax31]: http://www.unicode.org/reports/tr31/
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Ident {
|
pub struct Ident {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
@ -20,9 +20,9 @@ pub enum SyntaxNode {
|
|||||||
/// A section heading: `= Introduction`.
|
/// A section heading: `= Introduction`.
|
||||||
Heading(Box<HeadingNode>),
|
Heading(Box<HeadingNode>),
|
||||||
/// An item in an unordered list: `- ...`.
|
/// An item in an unordered list: `- ...`.
|
||||||
List(Box<ListItem>),
|
List(Box<ListNode>),
|
||||||
/// An item in an enumeration (ordered list): `1. ...`.
|
/// An item in an enumeration (ordered list): `1. ...`.
|
||||||
Enum(Box<EnumItem>),
|
Enum(Box<EnumNode>),
|
||||||
/// An expression.
|
/// An expression.
|
||||||
Expr(Expr),
|
Expr(Expr),
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@ pub struct HeadingNode {
|
|||||||
|
|
||||||
/// An item in an unordered list: `- ...`.
|
/// An item in an unordered list: `- ...`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ListItem {
|
pub struct ListNode {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The contents of the list item.
|
/// The contents of the list item.
|
||||||
@ -64,7 +64,7 @@ pub struct ListItem {
|
|||||||
|
|
||||||
/// An item in an enumeration (ordered list): `1. ...`.
|
/// An item in an enumeration (ordered list): `1. ...`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct EnumItem {
|
pub struct EnumNode {
|
||||||
/// The source code location.
|
/// The source code location.
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
/// The number, if any.
|
/// The number, if any.
|
||||||
|
@ -94,14 +94,14 @@ impl Pretty for SyntaxNode {
|
|||||||
Self::Emph(_) => p.push('_'),
|
Self::Emph(_) => p.push('_'),
|
||||||
Self::Text(text) => p.push_str(text),
|
Self::Text(text) => p.push_str(text),
|
||||||
Self::Raw(raw) => raw.pretty(p),
|
Self::Raw(raw) => raw.pretty(p),
|
||||||
Self::Heading(n) => n.pretty(p),
|
Self::Heading(heading) => heading.pretty(p),
|
||||||
Self::List(n) => n.pretty(p),
|
Self::List(list) => list.pretty(p),
|
||||||
Self::Enum(n) => n.pretty(p),
|
Self::Enum(enum_) => enum_.pretty(p),
|
||||||
Self::Expr(n) => {
|
Self::Expr(expr) => {
|
||||||
if n.has_short_form() {
|
if expr.has_short_form() {
|
||||||
p.push('#');
|
p.push('#');
|
||||||
}
|
}
|
||||||
n.pretty(p);
|
expr.pretty(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,14 +173,14 @@ impl Pretty for HeadingNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for ListItem {
|
impl Pretty for ListNode {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
p.push_str("- ");
|
p.push_str("- ");
|
||||||
self.body.pretty(p);
|
self.body.pretty(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pretty for EnumItem {
|
impl Pretty for EnumNode {
|
||||||
fn pretty(&self, p: &mut Printer) {
|
fn pretty(&self, p: &mut Printer) {
|
||||||
if let Some(number) = self.number {
|
if let Some(number) = self.number {
|
||||||
write!(p, "{}", number).unwrap();
|
write!(p, "{}", number).unwrap();
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use std::cmp::Ordering;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::ops::{Add, Range};
|
use std::ops::{Add, Range};
|
||||||
|
|
||||||
@ -6,8 +7,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::source::SourceId;
|
use crate::source::SourceId;
|
||||||
|
|
||||||
/// A value with the span it corresponds to in the source code.
|
/// A value with the span it corresponds to in the source code.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct Spanned<T> {
|
pub struct Spanned<T> {
|
||||||
/// The spanned value.
|
/// The spanned value.
|
||||||
pub v: T,
|
pub v: T,
|
||||||
@ -48,8 +48,7 @@ impl<T: Debug> Debug for Spanned<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Bounds of a slice of source code.
|
/// Bounds of a slice of source code.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct Span {
|
pub struct Span {
|
||||||
/// The id of the source file.
|
/// The id of the source file.
|
||||||
pub source: SourceId,
|
pub source: SourceId,
|
||||||
@ -127,9 +126,18 @@ impl Debug for Span {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for Span {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
if self.source == other.source {
|
||||||
|
Some(self.start.cmp(&other.start).then(self.end.cmp(&other.end)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A byte position in source code.
|
/// A byte position in source code.
|
||||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct Pos(pub u32);
|
pub struct Pos(pub u32);
|
||||||
|
|
||||||
impl Pos {
|
impl Pos {
|
||||||
@ -148,17 +156,6 @@ impl Debug for Pos {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Add<T> for Pos
|
|
||||||
where
|
|
||||||
T: Into<Pos>,
|
|
||||||
{
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn add(self, rhs: T) -> Self {
|
|
||||||
Pos(self.0 + rhs.into().0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u32> for Pos {
|
impl From<u32> for Pos {
|
||||||
fn from(index: u32) -> Self {
|
fn from(index: u32) -> Self {
|
||||||
Self(index)
|
Self(index)
|
||||||
@ -171,6 +168,17 @@ impl From<usize> for Pos {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Add<T> for Pos
|
||||||
|
where
|
||||||
|
T: Into<Pos>,
|
||||||
|
{
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: T) -> Self {
|
||||||
|
Pos(self.0 + rhs.into().0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert a position or range into a span.
|
/// Convert a position or range into a span.
|
||||||
pub trait IntoSpan {
|
pub trait IntoSpan {
|
||||||
/// Convert into a span by providing the source id.
|
/// Convert into a span by providing the source id.
|
||||||
|
@ -157,7 +157,7 @@ pub enum Token<'s> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A quoted string token: `"..."`.
|
/// A quoted string token: `"..."`.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct StrToken<'s> {
|
pub struct StrToken<'s> {
|
||||||
/// The string inside the quotes.
|
/// The string inside the quotes.
|
||||||
///
|
///
|
||||||
@ -170,7 +170,7 @@ pub struct StrToken<'s> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A raw block token: `` `...` ``.
|
/// A raw block token: `` `...` ``.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct RawToken<'s> {
|
pub struct RawToken<'s> {
|
||||||
/// The raw text between the backticks.
|
/// The raw text between the backticks.
|
||||||
pub text: &'s str,
|
pub text: &'s str,
|
||||||
@ -181,7 +181,7 @@ pub struct RawToken<'s> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A math formula token: `$2pi + x$` or `$[f'(x) = x^2]$`.
|
/// A math formula token: `$2pi + x$` or `$[f'(x) = x^2]$`.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct MathToken<'s> {
|
pub struct MathToken<'s> {
|
||||||
/// The formula between the dollars.
|
/// The formula between the dollars.
|
||||||
pub formula: &'s str,
|
pub formula: &'s str,
|
||||||
@ -193,7 +193,7 @@ pub struct MathToken<'s> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A unicode escape sequence token: `\u{1F5FA}`.
|
/// A unicode escape sequence token: `\u{1F5FA}`.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct UnicodeEscapeToken<'s> {
|
pub struct UnicodeEscapeToken<'s> {
|
||||||
/// The escape sequence between the braces.
|
/// The escape sequence between the braces.
|
||||||
pub sequence: &'s str,
|
pub sequence: &'s str,
|
||||||
|
@ -104,12 +104,12 @@ impl_visitors! {
|
|||||||
v.visit_tree(r!(heading.body));
|
v.visit_tree(r!(heading.body));
|
||||||
}
|
}
|
||||||
|
|
||||||
visit_list(v, item: ListItem) {
|
visit_list(v, list: ListNode) {
|
||||||
v.visit_tree(r!(item.body));
|
v.visit_tree(r!(list.body));
|
||||||
}
|
}
|
||||||
|
|
||||||
visit_enum(v, item: EnumItem) {
|
visit_enum(v, enum_: EnumNode) {
|
||||||
v.visit_tree(r!(item.body));
|
v.visit_tree(r!(enum_.body));
|
||||||
}
|
}
|
||||||
|
|
||||||
visit_expr(v, expr: Expr) {
|
visit_expr(v, expr: Expr) {
|
||||||
|
@ -163,24 +163,6 @@ impl EcoString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for EcoString {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for EcoString {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
Display::fmt(self.as_str(), f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for EcoString {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
Debug::fmt(self.as_str(), f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for EcoString {
|
impl Deref for EcoString {
|
||||||
type Target = str;
|
type Target = str;
|
||||||
|
|
||||||
@ -201,6 +183,24 @@ impl Deref for EcoString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for EcoString {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for EcoString {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
Debug::fmt(self.as_str(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for EcoString {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
Display::fmt(self.as_str(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Eq for EcoString {}
|
impl Eq for EcoString {}
|
||||||
|
|
||||||
impl PartialEq for EcoString {
|
impl PartialEq for EcoString {
|
||||||
|
@ -248,8 +248,9 @@ fn test_part(
|
|||||||
error.trace.clear();
|
error.trace.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
ref_errors.sort();
|
// The comparison never fails since all spans are from the same source file.
|
||||||
errors.sort();
|
ref_errors.sort_by(|a, b| a.span.partial_cmp(&b.span).unwrap());
|
||||||
|
errors.sort_by(|a, b| a.span.partial_cmp(&b.span).unwrap());
|
||||||
|
|
||||||
if errors != ref_errors {
|
if errors != ref_errors {
|
||||||
println!(" Subtest {} does not match expected errors. ❌", i);
|
println!(" Subtest {} does not match expected errors. ❌", i);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user