Separate typesetting and compilation

This commit is contained in:
Laurenz 2022-11-24 17:51:07 +01:00
parent 8d3c68a1de
commit 96f72eee6c
6 changed files with 49 additions and 24 deletions

@ -30,12 +30,12 @@ type CodespanError = codespan_reporting::files::Error;
/// What to do.
enum Command {
Typeset(TypesetCommand),
Compile(CompileCommand),
Fonts(FontsCommand),
}
/// Typeset a .typ file into a PDF file.
struct TypesetCommand {
/// Compile a .typ file into a PDF file.
struct CompileCommand {
input: PathBuf,
output: PathBuf,
root: Option<PathBuf>,
@ -110,7 +110,7 @@ fn parse_args() -> StrResult<Command> {
let root = args.opt_value_from_str("--root").map_err(|_| "missing root path")?;
let watch = args.contains(["-w", "--watch"]);
let (input, output) = parse_input_output(&mut args, "pdf")?;
Command::Typeset(TypesetCommand { input, output, watch, root })
Command::Compile(CompileCommand { input, output, watch, root })
};
// Don't allow excess arguments.
@ -164,13 +164,13 @@ fn print_error(msg: &str) -> io::Result<()> {
/// Dispatch a command.
fn dispatch(command: Command) -> StrResult<()> {
match command {
Command::Typeset(command) => typeset(command),
Command::Compile(command) => compile(command),
Command::Fonts(command) => fonts(command),
}
}
/// Execute a typesetting command.
fn typeset(command: TypesetCommand) -> StrResult<()> {
/// Execute a compilation command.
fn compile(command: CompileCommand) -> StrResult<()> {
let root = if let Some(root) = &command.root {
root.clone()
} else if let Some(dir) = command.input.parent() {
@ -182,8 +182,8 @@ fn typeset(command: TypesetCommand) -> StrResult<()> {
// Create the world that serves sources, fonts and files.
let mut world = SystemWorld::new(root);
// Typeset.
typeset_once(&mut world, &command)?;
// Perform initial compilation.
compile_once(&mut world, &command)?;
if !command.watch {
return Ok(());
@ -221,20 +221,20 @@ fn typeset(command: TypesetCommand) -> StrResult<()> {
}
if recompile {
typeset_once(&mut world, &command)?;
compile_once(&mut world, &command)?;
}
}
}
/// Typeset a single time.
fn typeset_once(world: &mut SystemWorld, command: &TypesetCommand) -> StrResult<()> {
/// Compile a single time.
fn compile_once(world: &mut SystemWorld, command: &CompileCommand) -> StrResult<()> {
status(command, Status::Compiling).unwrap();
world.reset();
let main = world.resolve(&command.input).map_err(|err| err.to_string())?;
let source = world.source(main);
match typst::typeset(world, source) {
match typst::compile(world, source) {
// Export the PDF.
Ok(frames) => {
let buffer = typst::export::pdf(&frames);
@ -254,7 +254,7 @@ fn typeset_once(world: &mut SystemWorld, command: &TypesetCommand) -> StrResult<
}
/// Clear the terminal and render the status message.
fn status(command: &TypesetCommand, status: Status) -> io::Result<()> {
fn status(command: &CompileCommand, status: Status) -> io::Result<()> {
if !command.watch {
return Ok(());
}

@ -49,16 +49,16 @@ use comemo::{Prehashed, Track};
use crate::diag::{FileResult, SourceResult};
use crate::font::{Font, FontBook};
use crate::frame::Frame;
use crate::model::{Library, Route, StyleChain};
use crate::model::{Library, Route};
use crate::syntax::{Source, SourceId};
use crate::util::Buffer;
/// Typeset a source file into a collection of layouted frames.
/// Compile a source file into a collection of layouted frames.
///
/// Returns either a vector of frames representing individual pages or
/// diagnostics in the form of a vector of error message with file and span
/// information.
pub fn typeset(
pub fn compile(
world: &(dyn World + 'static),
source: &Source,
) -> SourceResult<Vec<Frame>> {
@ -66,10 +66,8 @@ pub fn typeset(
let route = Route::default();
let module = model::eval(world.track(), route.track(), source)?;
// Layout the module's contents.
let library = world.library();
let styles = StyleChain::with_root(&library.styles);
(library.items.layout)(&module.content, world.track(), styles)
// Typeset the module's contents.
model::typeset(world.track(), &module.content)
}
/// The environment in which typesetting occurs.

@ -21,6 +21,7 @@ mod func;
mod methods;
mod ops;
mod scope;
mod typeset;
mod vm;
#[doc(hidden)]
@ -38,5 +39,6 @@ pub use self::library::*;
pub use self::scope::*;
pub use self::str::*;
pub use self::styles::*;
pub use self::typeset::*;
pub use self::value::*;
pub use self::vm::*;

17
src/model/typeset.rs Normal file

@ -0,0 +1,17 @@
use comemo::Tracked;
use super::{Content, StyleChain};
use crate::diag::SourceResult;
use crate::frame::Frame;
use crate::World;
/// Typeset content into a collection of layouted frames.
///
/// Returns either a vector of frames representing individual pages or
/// diagnostics in the form of a vector of error message with file and span
/// information.
pub fn typeset(world: Tracked<dyn World>, content: &Content) -> SourceResult<Vec<Frame>> {
let library = world.library();
let styles = StyleChain::with_root(&library.styles);
(library.items.layout)(content, world, styles)
}

@ -21,6 +21,7 @@ main!(
bench_edit,
bench_eval,
bench_typeset,
bench_compile,
bench_highlight,
bench_render,
);
@ -81,12 +82,19 @@ fn bench_eval(iai: &mut Iai) {
fn bench_typeset(iai: &mut Iai) {
let world = BenchWorld::new();
iai.run(|| typst::typeset(&world, &world.source));
let route = typst::model::Route::default();
let module = typst::model::eval(world.track(), route.track(), &world.source).unwrap();
iai.run(|| typst::model::typeset(world.track(), &module.content));
}
fn bench_compile(iai: &mut Iai) {
let world = BenchWorld::new();
iai.run(|| typst::compile(&world, &world.source));
}
fn bench_render(iai: &mut Iai) {
let world = BenchWorld::new();
let frames = typst::typeset(&world, &world.source).unwrap();
let frames = typst::compile(&world, &world.source).unwrap();
iai.run(|| typst::export::render(&frames[0], 1.0))
}

@ -424,7 +424,7 @@ fn test_part(
println!("Model:\n{:#?}\n", module.content);
}
let (mut frames, errors) = match typst::typeset(world, source) {
let (mut frames, errors) = match typst::compile(world, source) {
Ok(frames) => (frames, vec![]),
Err(errors) => (vec![], *errors),
};