From 12f9a0714ff454931f64d663cdecc3f08f031bb9 Mon Sep 17 00:00:00 2001 From: Jack <34489450+fenjalien@users.noreply.github.com> Date: Wed, 23 Aug 2023 02:19:25 +0100 Subject: [PATCH] change file hashmap handling add better error reporting --- compiler/Cargo.lock | 24 ++++++++- compiler/Cargo.toml | 3 +- compiler/src/file_entry.rs | 30 +++++++++++ compiler/src/lib.rs | 102 ++++++++++++++---------------------- compiler/src/render.rs | 52 ++++++++++++++++-- src/compiler.worker.ts | 3 +- src/typst-canvas-element.ts | 5 +- 7 files changed, 148 insertions(+), 71 deletions(-) create mode 100644 compiler/src/file_entry.rs diff --git a/compiler/Cargo.lock b/compiler/Cargo.lock index 2fb6360..805f12b 100644 --- a/compiler/Cargo.lock +++ b/compiler/Cargo.lock @@ -23,6 +23,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" +[[package]] +name = "ariadne" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72fe02fc62033df9ba41cba57ee19acf5e742511a140c7dbc3a873e19a19a1bd" +dependencies = [ + "unicode-width", + "yansi", +] + [[package]] name = "arrayref" version = "0.3.7" @@ -931,13 +941,13 @@ checksum = "e25be21376a772d15f97ae789845340a9651d3c4246ff5ebb6a2b35f9c37bd31" name = "obsidian-typst" version = "0.5.1" dependencies = [ + "ariadne", "comemo", "console_error_panic_hook", "fast_image_resize", "js-sys", "serde", "serde-wasm-bindgen", - "siphasher", "typst", "typst-library", "wasm-bindgen", @@ -1926,6 +1936,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + [[package]] name = "unicode-xid" version = "0.2.4" @@ -2192,6 +2208,12 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + [[package]] name = "yoke" version = "0.7.1" diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index e102766..4097695 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -15,7 +15,6 @@ crate-type = ["cdylib"] typst = { git = "https://github.com/typst/typst.git", tag = "v0.7.0" } typst-library = { git = "https://github.com/typst/typst.git", tag = "v0.7.0" } comemo = "0.3" -siphasher = "0.3.10" # Everything to do with wasm @@ -35,3 +34,5 @@ console_error_panic_hook = "0.1.7" # Image handling fast_image_resize = "2.7.3" + +ariadne = "0.3.0" diff --git a/compiler/src/file_entry.rs b/compiler/src/file_entry.rs new file mode 100644 index 0000000..89a28f5 --- /dev/null +++ b/compiler/src/file_entry.rs @@ -0,0 +1,30 @@ +use std::cell::OnceCell; + +use typst::{ + eval::Bytes, + syntax::{FileId, Source}, +}; + +pub struct FileEntry { + bytes: OnceCell, + source: Source, +} + +impl FileEntry { + pub fn new(id: FileId, text: String) -> Self { + Self { + bytes: OnceCell::new(), + source: Source::new(id, text), + } + } + + pub fn source(&self) -> Source { + self.source.clone() + } + + pub fn bytes(&self) -> Bytes { + self.bytes + .get_or_init(|| Bytes::from(self.source.text().as_bytes())) + .clone() + } +} diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index e68273d..3a2000b 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -1,5 +1,6 @@ use comemo::Prehashed; use fast_image_resize as fr; +use render::format_diagnostic; use std::{ cell::{OnceCell, RefCell, RefMut}, collections::HashMap, @@ -17,10 +18,10 @@ use typst::{ use wasm_bindgen::prelude::*; use web_sys::ImageData; -mod paths; +mod file_entry; mod render; -use crate::paths::{PathHash, PathSlot}; +use crate::file_entry::FileEntry; /// A world that provides access to the operating system. #[wasm_bindgen] @@ -35,12 +36,8 @@ pub struct SystemWorld { book: Prehashed, /// Storage of fonts fonts: Vec, - /// Maps package-path combinations to canonical hashes. All package-path - /// combinations that point to thes same file are mapped to the same hash. To - /// be used in conjunction with `paths`. - hashes: RefCell>>, - /// Maps canonical path hashes to source files and buffers. - paths: RefCell>, + + files: RefCell>, /// The current date if requested. This is stored here to ensure it is /// always the same within one compilation. Reset between compilations. today: OnceCell>, @@ -66,8 +63,7 @@ impl SystemWorld { library: Prehashed::new(typst_library::build()), book: Prehashed::new(book), fonts, - hashes: RefCell::default(), - paths: RefCell::default(), + files: RefCell::default(), today: OnceCell::new(), packages: RefCell::default(), resizer: fr::Resizer::default(), @@ -77,6 +73,7 @@ impl SystemWorld { pub fn compile( &mut self, + // command: CompileCommand, text: String, path: String, pixel_per_pt: f32, @@ -86,33 +83,24 @@ impl SystemWorld { ) -> Result { self.reset(); - // Insert the main path slot - let system_path = PathBuf::from(path); - let hash = PathHash::new(&text); - self.main = FileId::new(None, &system_path); - self.hashes.borrow_mut().insert(self.main, Ok(hash)); - self.paths.borrow_mut().insert( - hash, - PathSlot { - id: self.main, - system_path, - buffer: OnceCell::new(), - source: Ok(Source::new(self.main, text)), - }, + self.main = FileId::new(None, &PathBuf::from(&path)); + self.files.borrow_mut().insert( + self.main, + FileEntry::new(self.main, text), // bytes: OnceCell::new(), + // source: Source::new(self.main, text), + // }, ); let mut tracer = Tracer::default(); match typst::compile(self, &mut tracer) { - Ok(document) => { - render::to_image(&mut self.resizer, document, size, display, fill, pixel_per_pt) - } - Err(errors) => Err(format!( - "{:?}", - errors - .into_iter() - .map(|e| e.message) - .collect::>() - ) - .into()), + Ok(document) => render::to_image( + &mut self.resizer, + document, + fill, + pixel_per_pt, + size, + display, + ), + Err(errors) => Err(format_diagnostic(self.files.borrow(), &errors).into()), } } @@ -147,11 +135,11 @@ impl World for SystemWorld { } fn source(&self, id: FileId) -> FileResult { - self.slot(id)?.source() + Ok(self.file_entry(id)?.source()) } fn file(&self, id: FileId) -> FileResult { - self.slot(id)?.file() + Ok(self.file_entry(id)?.bytes()) } fn font(&self, index: usize) -> Option { @@ -165,8 +153,7 @@ impl World for SystemWorld { impl SystemWorld { fn reset(&mut self) { - self.hashes.borrow_mut().clear(); - self.paths.borrow_mut().clear(); + self.files.borrow_mut().clear(); self.today.take(); } @@ -207,33 +194,20 @@ impl SystemWorld { .clone() } - fn slot(&self, id: FileId) -> FileResult> { - let mut system_path = PathBuf::new(); - let mut text = String::new(); - let hash = self - .hashes - .borrow_mut() - .entry(id) - .or_insert_with(|| { - let root = match id.package() { - Some(spec) => self.prepare_package(spec)?, - None => self.root.clone(), - }; + fn file_entry(&self, id: FileId) -> FileResult> { + if let Ok(file) = RefMut::filter_map(self.files.borrow_mut(), |files| files.get_mut(&id)) { + return Ok(file); + } - system_path = root.join_rooted(id.path()).ok_or(FileError::AccessDenied)?; - text = self.read_file(&system_path)?; - - Ok(PathHash::new(&text)) - }) - .clone()?; - - Ok(RefMut::map(self.paths.borrow_mut(), |paths| { - paths.entry(hash).or_insert_with(|| PathSlot { - id, - source: Ok(Source::new(id, text)), - buffer: OnceCell::new(), - system_path, - }) + let path = match id.package() { + Some(spec) => self.prepare_package(spec)?, + None => self.root.clone(), + } + .join_rooted(id.path()) + .ok_or(FileError::AccessDenied)?; + let text = self.read_file(&path)?; + Ok(RefMut::map(self.files.borrow_mut(), |files| { + return files.entry(id).or_insert(FileEntry::new(id, text)); })) } diff --git a/compiler/src/render.rs b/compiler/src/render.rs index fc8f047..23217e3 100644 --- a/compiler/src/render.rs +++ b/compiler/src/render.rs @@ -1,21 +1,27 @@ -use std::{num::NonZeroU32, str::FromStr}; +use std::{collections::HashMap, num::NonZeroU32, str::FromStr, cell::Ref}; +use ariadne::{Config, FnCache, Label, Report, ReportKind, Source, Span}; +// use ariadne::{Report, ReportKind}; use fast_image_resize as fr; use fr::Resizer; use typst::{ + diag::{Severity, SourceDiagnostic}, doc::Document, geom::{Color, RgbaColor}, + syntax::FileId, }; use wasm_bindgen::Clamped; use web_sys::ImageData; +use crate::file_entry::FileEntry; + pub fn to_image( resizer: &mut Resizer, document: Document, - size: u32, - display: bool, fill: String, pixel_per_pt: f32, + size: u32, + display: bool, ) -> Result { let mut pixmap = typst::export::render( &document.pages[0], @@ -69,3 +75,43 @@ pub fn to_image( dst_height.get(), ); } + +// impl Into<()> for FileId { + +// } + +pub fn format_diagnostic( + sources: Ref>, + diagnostics: &[SourceDiagnostic], +) -> String { + let mut bytes = Vec::new(); + + let cache = FnCache::new(|id| { + return sources.get(&id); + }); + + for diagnostic in diagnostics { + let id = diagnostic.span.id(); + let source = sources.get(&id).unwrap().source(); + let range = source.range(diagnostic.span); + let report = Report::build( + match diagnostic.severity { + Severity::Error => ReportKind::Error, + Severity::Warning => ReportKind::Warning, + }, + "arst", + // id.path().to_str().unwrap(), + range.start, + ) + .with_config(Config::default().with_color(false).with_tab_width(2)) + .with_message(&diagnostic.message) + .with_label(Label::new(range)) + .finish(); + report + .write(Source::from(source.text()), &mut bytes) + .unwrap(); + bytes.push(b'\n'); + } + + return String::from_utf8(bytes).unwrap(); +} diff --git a/src/compiler.worker.ts b/src/compiler.worker.ts index 85dc438..8b4ad44 100644 --- a/src/compiler.worker.ts +++ b/src/compiler.worker.ts @@ -2,7 +2,8 @@ import wasmBin from '../pkg/obsidian_typst_bg.wasm' import * as typst from '../pkg' -import { CompileCommand, WorkerRequest } from "src/types"; + +import { CompileCommand } from "src/types"; typst.initSync(wasmBin); diff --git a/src/typst-canvas-element.ts b/src/typst-canvas-element.ts index 290508c..6349a14 100644 --- a/src/typst-canvas-element.ts +++ b/src/typst-canvas-element.ts @@ -65,7 +65,10 @@ export default class TypstCanvasElement extends HTMLCanvasElement { await TypstCanvasElement.compile(this.path, this.source, this.size, this.display, fontSize) } catch (error) { console.error(error); - this.outerText = error + let pre = createEl("pre")//"
 
" + pre.textContent = error + this.outerHTML = pre.outerHTML + // this.innerText = error return }