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),
|
||||
}
|
||||
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
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.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
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.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct ParseRgbaError;
|
||||
|
||||
impl std::error::Error for ParseRgbaError {}
|
||||
|
||||
impl fmt::Display for ParseRgbaError {
|
||||
impl Display for ParseRgbaError {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
f.pad("invalid color")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ParseRgbaError {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -22,7 +22,7 @@ pub type TypResult<T> = Result<T, Box<Vec<Error>>>;
|
||||
pub type StrResult<T> = Result<T, String>;
|
||||
|
||||
/// 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 {
|
||||
/// The erroneous location in the source code.
|
||||
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 {
|
||||
fn extend<T: IntoIterator<Item = Value>>(&mut self, iter: T) {
|
||||
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 {
|
||||
type Item = Value;
|
||||
type IntoIter = std::vec::IntoIter<Value>;
|
||||
|
@ -5,7 +5,6 @@ use crate::syntax::visit::{immutable::visit_expr, Visit};
|
||||
use crate::syntax::{Expr, Ident};
|
||||
|
||||
/// A visitor that captures variable slots.
|
||||
#[derive(Debug)]
|
||||
pub struct CapturesVisitor<'a> {
|
||||
external: &'a Scopes<'a>,
|
||||
internal: Scopes<'a>,
|
||||
|
@ -82,6 +82,12 @@ fn missing_key(key: &Str) -> String {
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
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 {
|
||||
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 {
|
||||
fn extend<T: IntoIterator<Item = (Str, Value)>>(&mut self, iter: T) {
|
||||
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 {
|
||||
type Item = (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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
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 {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
// 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 str;
|
||||
mod template;
|
||||
mod walk;
|
||||
|
||||
pub use self::str::*;
|
||||
pub use array::*;
|
||||
@ -23,25 +24,24 @@ pub use scope::*;
|
||||
pub use state::*;
|
||||
pub use template::*;
|
||||
pub use value::*;
|
||||
pub use walk::*;
|
||||
|
||||
use std::cell::RefMut;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
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::layout::{ParChild, ParNode, StackChild, StackNode};
|
||||
use crate::loading::Loader;
|
||||
use crate::parse::parse;
|
||||
use crate::source::{SourceId, SourceStore};
|
||||
use crate::syntax::visit::Visit;
|
||||
use crate::syntax::*;
|
||||
use crate::util::{EcoString, RefMutExt};
|
||||
use crate::util::RefMutExt;
|
||||
use crate::Context;
|
||||
|
||||
/// 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.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Module {
|
||||
/// The top-level definitions that were bound in this module.
|
||||
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>>;
|
||||
|
||||
/// A stack of scopes.
|
||||
#[derive(Debug, Default, Clone, PartialEq)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Scopes<'a> {
|
||||
/// The active scope.
|
||||
pub top: Scope,
|
||||
@ -65,7 +65,7 @@ impl<'a> Scopes<'a> {
|
||||
}
|
||||
|
||||
/// A map from variable names to variable slots.
|
||||
#[derive(Default, Clone, PartialEq)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Scope {
|
||||
/// The mapping from names to slots.
|
||||
values: HashMap<EcoString, Slot>,
|
||||
|
@ -63,7 +63,7 @@ impl Default for State {
|
||||
}
|
||||
|
||||
/// Defines page properties.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct PageState {
|
||||
/// The class of this page.
|
||||
pub class: PaperClass,
|
||||
@ -220,7 +220,7 @@ impl Default for FontState {
|
||||
}
|
||||
|
||||
/// Font family definitions.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct FamilyState {
|
||||
/// The user-defined list of font families.
|
||||
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.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct LineState {
|
||||
/// Stroke color of the line, defaults to the text color if `None`.
|
||||
pub stroke: Option<Paint>,
|
||||
|
@ -6,7 +6,7 @@ use crate::diag::StrResult;
|
||||
use crate::util::EcoString;
|
||||
|
||||
/// 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);
|
||||
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
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 {
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
f.pad("Template { .. }")
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Template {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
f.pad("<template>")
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Template {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Rc::ptr_eq(&self.0, &other.0)
|
||||
@ -465,11 +465,11 @@ impl ParBuilder {
|
||||
}
|
||||
|
||||
fn push_inner(&mut self, child: ParChild) {
|
||||
if let ParChild::Text(curr_text, curr_props, curr_align) = &child {
|
||||
if let Some(ParChild::Text(prev_text, prev_props, prev_align)) =
|
||||
if let ParChild::Text(curr_text, curr_align, curr_props) = &child {
|
||||
if let Some(ParChild::Text(prev_text, prev_align, prev_props)) =
|
||||
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);
|
||||
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 {
|
||||
fn from(v: &str) -> Self {
|
||||
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 {
|
||||
fn from(v: Dynamic) -> Self {
|
||||
Self::Dyn(v)
|
||||
@ -181,7 +181,7 @@ impl Dynamic {
|
||||
/// Create a new instance from any value that satisifies the required bounds.
|
||||
pub fn new<T>(any: T) -> Self
|
||||
where
|
||||
T: Type + Debug + Display + Clone + PartialEq + 'static,
|
||||
T: Type + Debug + Display + PartialEq + 'static,
|
||||
{
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
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 {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.dyn_eq(other)
|
||||
@ -228,7 +228,7 @@ trait Bounds: Debug + Display + 'static {
|
||||
|
||||
impl<T> Bounds for T
|
||||
where
|
||||
T: Type + Debug + Display + Clone + PartialEq + 'static,
|
||||
T: Type + Debug + Display + PartialEq + 'static,
|
||||
{
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
@ -309,12 +309,6 @@ macro_rules! primitive {
|
||||
const TYPE_NAME: &'static str = $name;
|
||||
}
|
||||
|
||||
impl From<$type> for Value {
|
||||
fn from(v: $type) -> Self {
|
||||
Value::$variant(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl Cast<Value> for $type {
|
||||
fn is(value: &Value) -> bool {
|
||||
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;
|
||||
}
|
||||
|
||||
impl From<$type> for $crate::eval::Value {
|
||||
fn from(v: $type) -> Self {
|
||||
$crate::eval::Value::Dyn($crate::eval::Dynamic::new(v))
|
||||
}
|
||||
}
|
||||
|
||||
castable! {
|
||||
$type: <Self as $crate::eval::Type>::TYPE_NAME,
|
||||
$($tts)*
|
||||
@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};
|
||||
|
||||
/// A unique identifier for a loaded font face.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
pub struct FaceId(u32);
|
||||
|
||||
impl FaceId {
|
||||
@ -271,7 +270,7 @@ impl Face {
|
||||
/// A length in em units.
|
||||
///
|
||||
/// `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);
|
||||
|
||||
impl Em {
|
||||
@ -343,11 +342,15 @@ impl Display for VerticalFontMetric {
|
||||
}
|
||||
|
||||
/// A generic or named font family.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum FontFamily {
|
||||
/// A family that has "serifs", small strokes attached to letters.
|
||||
Serif,
|
||||
/// A family in which glyphs do not have "serifs", small attached strokes.
|
||||
SansSerif,
|
||||
/// A family in which (almost) all glyphs are of equal width.
|
||||
Monospace,
|
||||
/// A specific family with a name.
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
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.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -1,8 +1,11 @@
|
||||
use super::*;
|
||||
use decorum::N64;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::*;
|
||||
|
||||
/// An angle.
|
||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Angle(N64);
|
||||
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
// 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 {
|
||||
type Output = Self;
|
||||
|
||||
@ -134,7 +137,7 @@ impl Sum for Angle {
|
||||
}
|
||||
}
|
||||
/// Different units of angular measurement.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum AngularUnit {
|
||||
/// Radians.
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
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 {
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
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 {
|
||||
type Output = Self;
|
||||
|
||||
@ -217,7 +217,7 @@ impl<'a> Sum<&'a Length> for Length {
|
||||
}
|
||||
|
||||
/// Different units of length measurement.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum LengthUnit {
|
||||
/// Points.
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
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 {
|
||||
fn from(abs: Length) -> Self {
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
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 {
|
||||
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> {
|
||||
/// Resolve the linear sides relative to the given `size`.
|
||||
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> {
|
||||
type Component = T;
|
||||
|
||||
|
@ -13,8 +13,7 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::loading::{FileHash, Loader};
|
||||
|
||||
/// A unique identifier for a loaded image.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
pub struct ImageId(u32);
|
||||
|
||||
impl ImageId {
|
||||
|
@ -1,7 +1,6 @@
|
||||
use super::*;
|
||||
|
||||
/// A node that places a rectangular filled background behind its child.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub struct BackgroundNode {
|
||||
/// The kind of shape to use as a background.
|
||||
|
@ -1,5 +1,3 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Carries an item that is only valid in certain regions and the constraints
|
||||
@ -12,14 +10,6 @@ pub struct Constrained<T> {
|
||||
pub constraints: Constraints,
|
||||
}
|
||||
|
||||
impl<T> Deref for Constrained<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.item
|
||||
}
|
||||
}
|
||||
|
||||
/// Describe regions that match them.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct Constraints {
|
||||
|
@ -3,7 +3,6 @@ use decorum::N64;
|
||||
use super::*;
|
||||
|
||||
/// A node that can fix its child's width and height.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub struct FixedNode {
|
||||
/// The fixed width, if any.
|
||||
@ -78,7 +77,7 @@ impl Layout for FixedNode {
|
||||
// relayout with expansion.
|
||||
if let Some(aspect) = aspect {
|
||||
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);
|
||||
regions.current = Size::new(width, width / aspect);
|
||||
regions.expand = Spec::splat(true);
|
||||
|
@ -1,7 +1,6 @@
|
||||
use super::*;
|
||||
|
||||
/// A node that arranges its children in a grid.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub struct GridNode {
|
||||
/// 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)) {
|
||||
let size = Gen::new(available, Length::inf()).to_size(self.main);
|
||||
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));
|
||||
}
|
||||
|
||||
@ -353,7 +352,7 @@ impl<'a> GridLayouter<'a> {
|
||||
let mut sizes = node
|
||||
.layout(ctx, &self.regions)
|
||||
.into_iter()
|
||||
.map(|frame| frame.size.get(self.main));
|
||||
.map(|frame| frame.item.size.get(self.main));
|
||||
|
||||
if let Some(size) = sizes.next() {
|
||||
first.set_max(size);
|
||||
|
@ -4,7 +4,6 @@ use crate::image::ImageId;
|
||||
use ::image::GenericImageView;
|
||||
|
||||
/// An image node.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub struct ImageNode {
|
||||
/// The id of the image file.
|
||||
|
@ -1,7 +1,6 @@
|
||||
use super::*;
|
||||
|
||||
/// A node that adds padding to its child.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub struct PadNode {
|
||||
/// The amount of padding.
|
||||
|
@ -1,4 +1,3 @@
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::rc::Rc;
|
||||
|
||||
use unicode_bidi::{BidiInfo, Level};
|
||||
@ -11,7 +10,6 @@ use crate::util::{EcoString, RangeExt, SliceExt};
|
||||
type Range = std::ops::Range<usize>;
|
||||
|
||||
/// A node that arranges its children into a paragraph.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub struct ParNode {
|
||||
/// The inline direction of this paragraph.
|
||||
@ -23,7 +21,6 @@ pub struct ParNode {
|
||||
}
|
||||
|
||||
/// A child of a paragraph node.
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub enum ParChild {
|
||||
/// 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
|
||||
/// is separated into shapable runs.
|
||||
struct ParLayouter<'a> {
|
||||
|
@ -1,5 +1,4 @@
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::ops::Range;
|
||||
|
||||
use rustybuzz::UnicodeBuffer;
|
||||
@ -11,12 +10,45 @@ use crate::geom::{Dir, Length, Point, Size};
|
||||
use crate::layout::Geometry;
|
||||
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.
|
||||
///
|
||||
/// This type contains owned or borrowed shaped text runs, which can be
|
||||
/// measured, used to reshape substrings more quickly and converted into a
|
||||
/// frame.
|
||||
#[derive(Clone)]
|
||||
pub struct ShapedText<'a> {
|
||||
/// The text that was shaped.
|
||||
pub text: &'a str,
|
||||
@ -33,7 +65,7 @@ pub struct ShapedText<'a> {
|
||||
}
|
||||
|
||||
/// A single glyph resulting from shaping.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ShapedGlyph {
|
||||
/// The font face the glyph is contained in.
|
||||
pub face_id: FaceId,
|
||||
@ -51,13 +83,6 @@ pub struct ShapedGlyph {
|
||||
pub safe_to_break: bool,
|
||||
}
|
||||
|
||||
/// A visual side.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
enum Side {
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
impl<'a> ShapedText<'a> {
|
||||
/// Build the shaped text's frame.
|
||||
pub fn build(&self, ctx: &LayoutContext) -> Frame {
|
||||
@ -174,44 +199,10 @@ impl<'a> ShapedText<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for ShapedText<'_> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "Shaped({:?})", self.text)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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),
|
||||
}
|
||||
/// A visual side.
|
||||
enum Side {
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
/// Shape text with font fallback using the `families` iterator.
|
||||
|
@ -1,7 +1,6 @@
|
||||
use super::*;
|
||||
|
||||
/// A node that stacks its children.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub struct StackNode {
|
||||
/// The `main` and `cross` directions of this stack.
|
||||
@ -14,7 +13,6 @@ pub struct StackNode {
|
||||
}
|
||||
|
||||
/// A child of a stack node.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub enum StackChild {
|
||||
/// Spacing between other nodes.
|
||||
|
@ -1,7 +1,6 @@
|
||||
use super::*;
|
||||
|
||||
use std::any::Any;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
#[cfg(feature = "layout-cache")]
|
||||
use std::hash::{Hash, Hasher};
|
||||
@ -10,7 +9,6 @@ use std::hash::{Hash, Hasher};
|
||||
use fxhash::FxHasher64;
|
||||
|
||||
/// A tree of layout nodes.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct LayoutTree {
|
||||
/// Runs of pages with the same properties.
|
||||
pub runs: Vec<PageRun>,
|
||||
@ -24,7 +22,6 @@ impl LayoutTree {
|
||||
}
|
||||
|
||||
/// A run of pages that all have the same properties.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct PageRun {
|
||||
/// The size of each page.
|
||||
pub size: Size,
|
||||
@ -47,7 +44,7 @@ impl PageRun {
|
||||
|
||||
/// A dynamic layouting node.
|
||||
pub struct LayoutNode {
|
||||
node: Box<dyn Bounds>,
|
||||
node: Box<dyn Layout>,
|
||||
#[cfg(feature = "layout-cache")]
|
||||
hash: u64,
|
||||
}
|
||||
@ -57,7 +54,7 @@ impl LayoutNode {
|
||||
#[cfg(not(feature = "layout-cache"))]
|
||||
pub fn new<T>(node: T) -> Self
|
||||
where
|
||||
T: Layout + Debug + Clone + Eq + PartialEq + 'static,
|
||||
T: Layout + 'static,
|
||||
{
|
||||
Self { node: Box::new(node) }
|
||||
}
|
||||
@ -66,7 +63,7 @@ impl LayoutNode {
|
||||
#[cfg(feature = "layout-cache")]
|
||||
pub fn new<T>(node: T) -> Self
|
||||
where
|
||||
T: Layout + Debug + Clone + Eq + PartialEq + Hash + 'static,
|
||||
T: Layout + Hash + 'static,
|
||||
{
|
||||
let hash = {
|
||||
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")]
|
||||
impl Hash for LayoutNode {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
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.
|
||||
///
|
||||
/// _This is only available when the `fs` feature is enabled._
|
||||
#[derive(Debug, Default, Clone)]
|
||||
#[derive(Default)]
|
||||
pub struct FsLoader {
|
||||
faces: Vec<FaceInfo>,
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use crate::font::FaceInfo;
|
||||
use crate::util::PathExt;
|
||||
|
||||
/// Loads fonts and files from an in-memory storage.
|
||||
#[derive(Debug, Default, Clone)]
|
||||
#[derive(Default)]
|
||||
pub struct MemLoader {
|
||||
faces: Vec<FaceInfo>,
|
||||
files: HashMap<PathBuf, Cow<'static, [u8]>>,
|
||||
|
@ -11,15 +11,12 @@ pub use mem::*;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::font::FaceInfo;
|
||||
|
||||
/// A hash that identifies a file.
|
||||
///
|
||||
/// Such a hash can be [resolved](Loader::resolve) from a path.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct FileHash(pub u64);
|
||||
|
||||
/// Loads resources from a local or remote source.
|
||||
|
@ -3,7 +3,7 @@
|
||||
use crate::geom::{Length, Linear, Relative, Sides, Size};
|
||||
|
||||
/// Specification of a paper.
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Paper {
|
||||
/// The broad class this paper belongs to.
|
||||
class: PaperClass,
|
||||
|
@ -201,7 +201,7 @@ fn list_item(p: &mut Parser) -> SyntaxNode {
|
||||
let column = p.column(start);
|
||||
p.eat_assert(Token::Hyph);
|
||||
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.
|
||||
@ -210,7 +210,7 @@ fn enum_item(p: &mut Parser, number: Option<usize>) -> SyntaxNode {
|
||||
let column = p.column(start);
|
||||
p.eat_assert(Token::Numbering(number));
|
||||
let body = tree_indented(p, column);
|
||||
SyntaxNode::Enum(Box::new(EnumItem {
|
||||
SyntaxNode::Enum(Box::new(EnumNode {
|
||||
span: p.span_from(start),
|
||||
number,
|
||||
body,
|
||||
|
@ -1,4 +1,3 @@
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::ops::Range;
|
||||
|
||||
use super::{TokenMode, Tokens};
|
||||
@ -28,7 +27,6 @@ pub struct Parser<'s> {
|
||||
}
|
||||
|
||||
/// A logical group of tokens, e.g. `[...]`.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct GroupEntry {
|
||||
/// The start index of the group. Used by `Parser::end_group` to return the
|
||||
/// group's full span.
|
||||
@ -391,11 +389,3 @@ impl<'s> Parser<'s> {
|
||||
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;
|
||||
|
||||
/// 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.
|
||||
#[inline]
|
||||
pub fn is_newline(character: char) -> bool {
|
||||
|
@ -1,11 +1,8 @@
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
use super::{is_newline, Scanner};
|
||||
use crate::geom::{AngularUnit, LengthUnit};
|
||||
use crate::syntax::*;
|
||||
|
||||
/// An iterator over the tokens of a string of source code.
|
||||
#[derive(Clone)]
|
||||
pub struct Tokens<'s> {
|
||||
s: Scanner<'s>,
|
||||
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>> {
|
||||
Some(match ident {
|
||||
"not" => Token::Not,
|
||||
@ -512,6 +503,8 @@ fn keyword(ident: &str) -> Option<Token<'static>> {
|
||||
#[cfg(test)]
|
||||
#[allow(non_snake_case)]
|
||||
mod tests {
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::*;
|
||||
|
||||
use Option::None;
|
||||
|
@ -15,8 +15,7 @@ use crate::parse::{is_newline, Scanner};
|
||||
use crate::util::PathExt;
|
||||
|
||||
/// A unique identifier for a loaded source file.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
pub struct SourceId(u32);
|
||||
|
||||
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 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")]
|
||||
impl<'a> Files<'a> for SourceStore {
|
||||
type FileId = SourceId;
|
||||
|
@ -12,7 +12,7 @@ use crate::util::EcoString;
|
||||
/// - `_` and `-` as continuing characters.
|
||||
///
|
||||
/// [uax31]: http://www.unicode.org/reports/tr31/
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Ident {
|
||||
/// The source code location.
|
||||
pub span: Span,
|
||||
|
@ -20,9 +20,9 @@ pub enum SyntaxNode {
|
||||
/// A section heading: `= Introduction`.
|
||||
Heading(Box<HeadingNode>),
|
||||
/// An item in an unordered list: `- ...`.
|
||||
List(Box<ListItem>),
|
||||
List(Box<ListNode>),
|
||||
/// An item in an enumeration (ordered list): `1. ...`.
|
||||
Enum(Box<EnumItem>),
|
||||
Enum(Box<EnumNode>),
|
||||
/// An expression.
|
||||
Expr(Expr),
|
||||
}
|
||||
@ -55,7 +55,7 @@ pub struct HeadingNode {
|
||||
|
||||
/// An item in an unordered list: `- ...`.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ListItem {
|
||||
pub struct ListNode {
|
||||
/// The source code location.
|
||||
pub span: Span,
|
||||
/// The contents of the list item.
|
||||
@ -64,7 +64,7 @@ pub struct ListItem {
|
||||
|
||||
/// An item in an enumeration (ordered list): `1. ...`.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct EnumItem {
|
||||
pub struct EnumNode {
|
||||
/// The source code location.
|
||||
pub span: Span,
|
||||
/// The number, if any.
|
||||
|
@ -94,14 +94,14 @@ impl Pretty for SyntaxNode {
|
||||
Self::Emph(_) => p.push('_'),
|
||||
Self::Text(text) => p.push_str(text),
|
||||
Self::Raw(raw) => raw.pretty(p),
|
||||
Self::Heading(n) => n.pretty(p),
|
||||
Self::List(n) => n.pretty(p),
|
||||
Self::Enum(n) => n.pretty(p),
|
||||
Self::Expr(n) => {
|
||||
if n.has_short_form() {
|
||||
Self::Heading(heading) => heading.pretty(p),
|
||||
Self::List(list) => list.pretty(p),
|
||||
Self::Enum(enum_) => enum_.pretty(p),
|
||||
Self::Expr(expr) => {
|
||||
if expr.has_short_form() {
|
||||
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) {
|
||||
p.push_str("- ");
|
||||
self.body.pretty(p);
|
||||
}
|
||||
}
|
||||
|
||||
impl Pretty for EnumItem {
|
||||
impl Pretty for EnumNode {
|
||||
fn pretty(&self, p: &mut Printer) {
|
||||
if let Some(number) = self.number {
|
||||
write!(p, "{}", number).unwrap();
|
||||
|
@ -1,3 +1,4 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::ops::{Add, Range};
|
||||
|
||||
@ -6,8 +7,7 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::source::SourceId;
|
||||
|
||||
/// A value with the span it corresponds to in the source code.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Spanned<T> {
|
||||
/// The spanned value.
|
||||
pub v: T,
|
||||
@ -48,8 +48,7 @@ impl<T: Debug> Debug for Spanned<T> {
|
||||
}
|
||||
|
||||
/// Bounds of a slice of source code.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Span {
|
||||
/// The id of the source file.
|
||||
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.
|
||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
|
||||
pub struct Pos(pub u32);
|
||||
|
||||
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 {
|
||||
fn from(index: u32) -> Self {
|
||||
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.
|
||||
pub trait IntoSpan {
|
||||
/// Convert into a span by providing the source id.
|
||||
|
@ -157,7 +157,7 @@ pub enum Token<'s> {
|
||||
}
|
||||
|
||||
/// A quoted string token: `"..."`.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub struct StrToken<'s> {
|
||||
/// The string inside the quotes.
|
||||
///
|
||||
@ -170,7 +170,7 @@ pub struct StrToken<'s> {
|
||||
}
|
||||
|
||||
/// A raw block token: `` `...` ``.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub struct RawToken<'s> {
|
||||
/// The raw text between the backticks.
|
||||
pub text: &'s str,
|
||||
@ -181,7 +181,7 @@ pub struct RawToken<'s> {
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
/// The formula between the dollars.
|
||||
pub formula: &'s str,
|
||||
@ -193,7 +193,7 @@ pub struct MathToken<'s> {
|
||||
}
|
||||
|
||||
/// A unicode escape sequence token: `\u{1F5FA}`.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub struct UnicodeEscapeToken<'s> {
|
||||
/// The escape sequence between the braces.
|
||||
pub sequence: &'s str,
|
||||
|
@ -104,12 +104,12 @@ impl_visitors! {
|
||||
v.visit_tree(r!(heading.body));
|
||||
}
|
||||
|
||||
visit_list(v, item: ListItem) {
|
||||
v.visit_tree(r!(item.body));
|
||||
visit_list(v, list: ListNode) {
|
||||
v.visit_tree(r!(list.body));
|
||||
}
|
||||
|
||||
visit_enum(v, item: EnumItem) {
|
||||
v.visit_tree(r!(item.body));
|
||||
visit_enum(v, enum_: EnumNode) {
|
||||
v.visit_tree(r!(enum_.body));
|
||||
}
|
||||
|
||||
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 {
|
||||
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 PartialEq for EcoString {
|
||||
|
@ -248,8 +248,9 @@ fn test_part(
|
||||
error.trace.clear();
|
||||
}
|
||||
|
||||
ref_errors.sort();
|
||||
errors.sort();
|
||||
// The comparison never fails since all spans are from the same source file.
|
||||
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 {
|
||||
println!(" Subtest {} does not match expected errors. ❌", i);
|
||||
|
Loading…
x
Reference in New Issue
Block a user