mirror of
https://github.com/typst/typst
synced 2025-07-11 22:52:53 +08:00
176 lines
5.7 KiB
Rust
176 lines
5.7 KiB
Rust
use std::fmt::{self, Debug, Formatter};
|
|
use std::hash::{Hash, Hasher};
|
|
|
|
use comemo::{Tracked, TrackedMut};
|
|
use typst_syntax::{Span, SyntaxMode};
|
|
use typst_utils::LazyHash;
|
|
|
|
use crate::diag::SourceResult;
|
|
use crate::engine::{Engine, Route, Sink, Traced};
|
|
use crate::foundations::{
|
|
Args, Closure, Content, Context, Func, Module, NativeRuleMap, Scope, StyleChain,
|
|
Styles, Value,
|
|
};
|
|
use crate::introspection::{Introspector, Locator, SplitLocator};
|
|
use crate::layout::{Frame, Region};
|
|
use crate::model::DocumentInfo;
|
|
use crate::World;
|
|
|
|
/// Defines the `Routines` struct.
|
|
macro_rules! routines {
|
|
($(
|
|
$(#[$attr:meta])*
|
|
fn $name:ident $(<$($time:lifetime),*>)? ($($args:tt)*) -> $ret:ty
|
|
)*) => {
|
|
/// Defines implementation of various Typst compiler routines as a table
|
|
/// of function pointers.
|
|
///
|
|
/// This is essentially dynamic linking and done to allow for crate
|
|
/// splitting.
|
|
pub struct Routines {
|
|
/// Native show rules.
|
|
pub rules: NativeRuleMap,
|
|
$(
|
|
$(#[$attr])*
|
|
pub $name: $(for<$($time),*>)? fn ($($args)*) -> $ret
|
|
),*
|
|
}
|
|
|
|
impl Hash for Routines {
|
|
fn hash<H: Hasher>(&self, _: &mut H) {}
|
|
}
|
|
|
|
impl Debug for Routines {
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
f.pad("Routines(..)")
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
routines! {
|
|
/// Evaluates a string as code and return the resulting value.
|
|
fn eval_string(
|
|
routines: &Routines,
|
|
world: Tracked<dyn World + '_>,
|
|
sink: TrackedMut<Sink>,
|
|
string: &str,
|
|
span: Span,
|
|
mode: SyntaxMode,
|
|
scope: Scope,
|
|
) -> SourceResult<Value>
|
|
|
|
/// Call the closure in the context with the arguments.
|
|
fn eval_closure(
|
|
func: &Func,
|
|
closure: &LazyHash<Closure>,
|
|
routines: &Routines,
|
|
world: Tracked<dyn World + '_>,
|
|
introspector: Tracked<Introspector>,
|
|
traced: Tracked<Traced>,
|
|
sink: TrackedMut<Sink>,
|
|
route: Tracked<Route>,
|
|
context: Tracked<Context>,
|
|
args: Args,
|
|
) -> SourceResult<Value>
|
|
|
|
/// Realizes content into a flat list of well-known, styled items.
|
|
fn realize<'a>(
|
|
kind: RealizationKind,
|
|
engine: &mut Engine,
|
|
locator: &mut SplitLocator,
|
|
arenas: &'a Arenas,
|
|
content: &'a Content,
|
|
styles: StyleChain<'a>,
|
|
) -> SourceResult<Vec<Pair<'a>>>
|
|
|
|
/// Lays out content into a single region, producing a single frame.
|
|
fn layout_frame(
|
|
engine: &mut Engine,
|
|
content: &Content,
|
|
locator: Locator,
|
|
styles: StyleChain,
|
|
region: Region,
|
|
) -> SourceResult<Frame>
|
|
|
|
/// Constructs the `html` module.
|
|
fn html_module() -> Module
|
|
}
|
|
|
|
/// Defines what kind of realization we are performing.
|
|
pub enum RealizationKind<'a> {
|
|
/// This the root realization for layout. Requires a mutable reference
|
|
/// to document metadata that will be filled from `set document` rules.
|
|
LayoutDocument(&'a mut DocumentInfo),
|
|
/// A nested realization in a container (e.g. a `block`). Requires a mutable
|
|
/// reference to an enum that will be set to `FragmentKind::Inline` if the
|
|
/// fragment's content was fully inline.
|
|
LayoutFragment(&'a mut FragmentKind),
|
|
/// A nested realization in a paragraph (i.e. a `par`)
|
|
LayoutPar,
|
|
/// This the root realization for HTML. Requires a mutable reference
|
|
/// to document metadata that will be filled from `set document` rules.
|
|
HtmlDocument(&'a mut DocumentInfo),
|
|
/// A nested realization in a container (e.g. a `block`). Requires a mutable
|
|
/// reference to an enum that will be set to `FragmentKind::Inline` if the
|
|
/// fragment's content was fully inline.
|
|
HtmlFragment(&'a mut FragmentKind),
|
|
/// A realization within math.
|
|
Math,
|
|
}
|
|
|
|
impl RealizationKind<'_> {
|
|
/// It this a realization for HTML export?
|
|
pub fn is_html(&self) -> bool {
|
|
matches!(self, Self::HtmlDocument(_) | Self::HtmlFragment(_))
|
|
}
|
|
|
|
/// It this a realization for a container?
|
|
pub fn is_fragment(&self) -> bool {
|
|
matches!(self, Self::LayoutFragment(_) | Self::HtmlFragment(_))
|
|
}
|
|
|
|
/// If this is a document-level realization, accesses the document info.
|
|
pub fn as_document_mut(&mut self) -> Option<&mut DocumentInfo> {
|
|
match self {
|
|
Self::LayoutDocument(info) | Self::HtmlDocument(info) => Some(*info),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
/// If this is a container-level realization, accesses the fragment kind.
|
|
pub fn as_fragment_mut(&mut self) -> Option<&mut FragmentKind> {
|
|
match self {
|
|
Self::LayoutFragment(kind) | Self::HtmlFragment(kind) => Some(*kind),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The kind of fragment output that realization produced.
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
|
pub enum FragmentKind {
|
|
/// The fragment's contents were fully inline, and as a result, the output
|
|
/// elements are too.
|
|
Inline,
|
|
/// The fragment contained non-inline content, so inline content was forced
|
|
/// into paragraphs, and as a result, the output elements are not inline.
|
|
Block,
|
|
}
|
|
|
|
/// Temporary storage arenas for lifetime extension during realization.
|
|
///
|
|
/// Must be kept live while the content returned from realization is processed.
|
|
#[derive(Default)]
|
|
pub struct Arenas {
|
|
/// A typed arena for owned content.
|
|
pub content: typed_arena::Arena<Content>,
|
|
/// A typed arena for owned styles.
|
|
pub styles: typed_arena::Arena<Styles>,
|
|
/// An untyped arena for everything that is `Copy`.
|
|
pub bump: bumpalo::Bump,
|
|
}
|
|
|
|
/// A pair of content and a style chain that applies to it.
|
|
pub type Pair<'a> = (&'a Content, StyleChain<'a>);
|