mirror of
https://github.com/mii443/obsidian-typst.git
synced 2025-08-22 16:15:34 +00:00
change file hashmap handling
add better error reporting
This commit is contained in:
24
compiler/Cargo.lock
generated
24
compiler/Cargo.lock
generated
@ -23,6 +23,16 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
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]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
@ -931,13 +941,13 @@ checksum = "e25be21376a772d15f97ae789845340a9651d3c4246ff5ebb6a2b35f9c37bd31"
|
|||||||
name = "obsidian-typst"
|
name = "obsidian-typst"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ariadne",
|
||||||
"comemo",
|
"comemo",
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"fast_image_resize",
|
"fast_image_resize",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"serde",
|
"serde",
|
||||||
"serde-wasm-bindgen",
|
"serde-wasm-bindgen",
|
||||||
"siphasher",
|
|
||||||
"typst",
|
"typst",
|
||||||
"typst-library",
|
"typst-library",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@ -1926,6 +1936,12 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
|
checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
@ -2192,6 +2208,12 @@ dependencies = [
|
|||||||
"linked-hash-map",
|
"linked-hash-map",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yoke"
|
name = "yoke"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -15,7 +15,6 @@ crate-type = ["cdylib"]
|
|||||||
typst = { git = "https://github.com/typst/typst.git", tag = "v0.7.0" }
|
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" }
|
typst-library = { git = "https://github.com/typst/typst.git", tag = "v0.7.0" }
|
||||||
comemo = "0.3"
|
comemo = "0.3"
|
||||||
siphasher = "0.3.10"
|
|
||||||
|
|
||||||
|
|
||||||
# Everything to do with wasm
|
# Everything to do with wasm
|
||||||
@ -35,3 +34,5 @@ console_error_panic_hook = "0.1.7"
|
|||||||
|
|
||||||
# Image handling
|
# Image handling
|
||||||
fast_image_resize = "2.7.3"
|
fast_image_resize = "2.7.3"
|
||||||
|
|
||||||
|
ariadne = "0.3.0"
|
||||||
|
30
compiler/src/file_entry.rs
Normal file
30
compiler/src/file_entry.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use std::cell::OnceCell;
|
||||||
|
|
||||||
|
use typst::{
|
||||||
|
eval::Bytes,
|
||||||
|
syntax::{FileId, Source},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct FileEntry {
|
||||||
|
bytes: OnceCell<Bytes>,
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
use comemo::Prehashed;
|
use comemo::Prehashed;
|
||||||
use fast_image_resize as fr;
|
use fast_image_resize as fr;
|
||||||
|
use render::format_diagnostic;
|
||||||
use std::{
|
use std::{
|
||||||
cell::{OnceCell, RefCell, RefMut},
|
cell::{OnceCell, RefCell, RefMut},
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@ -17,10 +18,10 @@ use typst::{
|
|||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use web_sys::ImageData;
|
use web_sys::ImageData;
|
||||||
|
|
||||||
mod paths;
|
mod file_entry;
|
||||||
mod render;
|
mod render;
|
||||||
|
|
||||||
use crate::paths::{PathHash, PathSlot};
|
use crate::file_entry::FileEntry;
|
||||||
|
|
||||||
/// A world that provides access to the operating system.
|
/// A world that provides access to the operating system.
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
@ -35,12 +36,8 @@ pub struct SystemWorld {
|
|||||||
book: Prehashed<FontBook>,
|
book: Prehashed<FontBook>,
|
||||||
/// Storage of fonts
|
/// Storage of fonts
|
||||||
fonts: Vec<Font>,
|
fonts: Vec<Font>,
|
||||||
/// Maps package-path combinations to canonical hashes. All package-path
|
|
||||||
/// combinations that point to thes same file are mapped to the same hash. To
|
files: RefCell<HashMap<FileId, FileEntry>>,
|
||||||
/// be used in conjunction with `paths`.
|
|
||||||
hashes: RefCell<HashMap<FileId, FileResult<PathHash>>>,
|
|
||||||
/// Maps canonical path hashes to source files and buffers.
|
|
||||||
paths: RefCell<HashMap<PathHash, PathSlot>>,
|
|
||||||
/// The current date if requested. This is stored here to ensure it is
|
/// The current date if requested. This is stored here to ensure it is
|
||||||
/// always the same within one compilation. Reset between compilations.
|
/// always the same within one compilation. Reset between compilations.
|
||||||
today: OnceCell<Option<Datetime>>,
|
today: OnceCell<Option<Datetime>>,
|
||||||
@ -66,8 +63,7 @@ impl SystemWorld {
|
|||||||
library: Prehashed::new(typst_library::build()),
|
library: Prehashed::new(typst_library::build()),
|
||||||
book: Prehashed::new(book),
|
book: Prehashed::new(book),
|
||||||
fonts,
|
fonts,
|
||||||
hashes: RefCell::default(),
|
files: RefCell::default(),
|
||||||
paths: RefCell::default(),
|
|
||||||
today: OnceCell::new(),
|
today: OnceCell::new(),
|
||||||
packages: RefCell::default(),
|
packages: RefCell::default(),
|
||||||
resizer: fr::Resizer::default(),
|
resizer: fr::Resizer::default(),
|
||||||
@ -77,6 +73,7 @@ impl SystemWorld {
|
|||||||
|
|
||||||
pub fn compile(
|
pub fn compile(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
// command: CompileCommand,
|
||||||
text: String,
|
text: String,
|
||||||
path: String,
|
path: String,
|
||||||
pixel_per_pt: f32,
|
pixel_per_pt: f32,
|
||||||
@ -86,33 +83,24 @@ impl SystemWorld {
|
|||||||
) -> Result<ImageData, JsValue> {
|
) -> Result<ImageData, JsValue> {
|
||||||
self.reset();
|
self.reset();
|
||||||
|
|
||||||
// Insert the main path slot
|
self.main = FileId::new(None, &PathBuf::from(&path));
|
||||||
let system_path = PathBuf::from(path);
|
self.files.borrow_mut().insert(
|
||||||
let hash = PathHash::new(&text);
|
self.main,
|
||||||
self.main = FileId::new(None, &system_path);
|
FileEntry::new(self.main, text), // bytes: OnceCell::new(),
|
||||||
self.hashes.borrow_mut().insert(self.main, Ok(hash));
|
// source: Source::new(self.main, text),
|
||||||
self.paths.borrow_mut().insert(
|
// },
|
||||||
hash,
|
|
||||||
PathSlot {
|
|
||||||
id: self.main,
|
|
||||||
system_path,
|
|
||||||
buffer: OnceCell::new(),
|
|
||||||
source: Ok(Source::new(self.main, text)),
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
let mut tracer = Tracer::default();
|
let mut tracer = Tracer::default();
|
||||||
match typst::compile(self, &mut tracer) {
|
match typst::compile(self, &mut tracer) {
|
||||||
Ok(document) => {
|
Ok(document) => render::to_image(
|
||||||
render::to_image(&mut self.resizer, document, size, display, fill, pixel_per_pt)
|
&mut self.resizer,
|
||||||
}
|
document,
|
||||||
Err(errors) => Err(format!(
|
fill,
|
||||||
"{:?}",
|
pixel_per_pt,
|
||||||
errors
|
size,
|
||||||
.into_iter()
|
display,
|
||||||
.map(|e| e.message)
|
),
|
||||||
.collect::<Vec<EcoString>>()
|
Err(errors) => Err(format_diagnostic(self.files.borrow(), &errors).into()),
|
||||||
)
|
|
||||||
.into()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,11 +135,11 @@ impl World for SystemWorld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn source(&self, id: FileId) -> FileResult<Source> {
|
fn source(&self, id: FileId) -> FileResult<Source> {
|
||||||
self.slot(id)?.source()
|
Ok(self.file_entry(id)?.source())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&self, id: FileId) -> FileResult<Bytes> {
|
fn file(&self, id: FileId) -> FileResult<Bytes> {
|
||||||
self.slot(id)?.file()
|
Ok(self.file_entry(id)?.bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn font(&self, index: usize) -> Option<Font> {
|
fn font(&self, index: usize) -> Option<Font> {
|
||||||
@ -165,8 +153,7 @@ impl World for SystemWorld {
|
|||||||
|
|
||||||
impl SystemWorld {
|
impl SystemWorld {
|
||||||
fn reset(&mut self) {
|
fn reset(&mut self) {
|
||||||
self.hashes.borrow_mut().clear();
|
self.files.borrow_mut().clear();
|
||||||
self.paths.borrow_mut().clear();
|
|
||||||
self.today.take();
|
self.today.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,33 +194,20 @@ impl SystemWorld {
|
|||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slot(&self, id: FileId) -> FileResult<RefMut<PathSlot>> {
|
fn file_entry(&self, id: FileId) -> FileResult<RefMut<FileEntry>> {
|
||||||
let mut system_path = PathBuf::new();
|
if let Ok(file) = RefMut::filter_map(self.files.borrow_mut(), |files| files.get_mut(&id)) {
|
||||||
let mut text = String::new();
|
return Ok(file);
|
||||||
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(),
|
|
||||||
};
|
|
||||||
|
|
||||||
system_path = root.join_rooted(id.path()).ok_or(FileError::AccessDenied)?;
|
let path = match id.package() {
|
||||||
text = self.read_file(&system_path)?;
|
Some(spec) => self.prepare_package(spec)?,
|
||||||
|
None => self.root.clone(),
|
||||||
Ok(PathHash::new(&text))
|
}
|
||||||
})
|
.join_rooted(id.path())
|
||||||
.clone()?;
|
.ok_or(FileError::AccessDenied)?;
|
||||||
|
let text = self.read_file(&path)?;
|
||||||
Ok(RefMut::map(self.paths.borrow_mut(), |paths| {
|
Ok(RefMut::map(self.files.borrow_mut(), |files| {
|
||||||
paths.entry(hash).or_insert_with(|| PathSlot {
|
return files.entry(id).or_insert(FileEntry::new(id, text));
|
||||||
id,
|
|
||||||
source: Ok(Source::new(id, text)),
|
|
||||||
buffer: OnceCell::new(),
|
|
||||||
system_path,
|
|
||||||
})
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 fast_image_resize as fr;
|
||||||
use fr::Resizer;
|
use fr::Resizer;
|
||||||
use typst::{
|
use typst::{
|
||||||
|
diag::{Severity, SourceDiagnostic},
|
||||||
doc::Document,
|
doc::Document,
|
||||||
geom::{Color, RgbaColor},
|
geom::{Color, RgbaColor},
|
||||||
|
syntax::FileId,
|
||||||
};
|
};
|
||||||
use wasm_bindgen::Clamped;
|
use wasm_bindgen::Clamped;
|
||||||
use web_sys::ImageData;
|
use web_sys::ImageData;
|
||||||
|
|
||||||
|
use crate::file_entry::FileEntry;
|
||||||
|
|
||||||
pub fn to_image(
|
pub fn to_image(
|
||||||
resizer: &mut Resizer,
|
resizer: &mut Resizer,
|
||||||
document: Document,
|
document: Document,
|
||||||
size: u32,
|
|
||||||
display: bool,
|
|
||||||
fill: String,
|
fill: String,
|
||||||
pixel_per_pt: f32,
|
pixel_per_pt: f32,
|
||||||
|
size: u32,
|
||||||
|
display: bool,
|
||||||
) -> Result<ImageData, wasm_bindgen::JsValue> {
|
) -> Result<ImageData, wasm_bindgen::JsValue> {
|
||||||
let mut pixmap = typst::export::render(
|
let mut pixmap = typst::export::render(
|
||||||
&document.pages[0],
|
&document.pages[0],
|
||||||
@ -69,3 +75,43 @@ pub fn to_image(
|
|||||||
dst_height.get(),
|
dst_height.get(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// impl Into<()> for FileId {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn format_diagnostic(
|
||||||
|
sources: Ref<HashMap<FileId, FileEntry>>,
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
import wasmBin from '../pkg/obsidian_typst_bg.wasm'
|
import wasmBin from '../pkg/obsidian_typst_bg.wasm'
|
||||||
import * as typst from '../pkg'
|
import * as typst from '../pkg'
|
||||||
|
|
||||||
import { CompileCommand, WorkerRequest } from "src/types";
|
|
||||||
|
import { CompileCommand } from "src/types";
|
||||||
|
|
||||||
typst.initSync(wasmBin);
|
typst.initSync(wasmBin);
|
||||||
|
|
||||||
|
@ -65,7 +65,10 @@ export default class TypstCanvasElement extends HTMLCanvasElement {
|
|||||||
await TypstCanvasElement.compile(this.path, this.source, this.size, this.display, fontSize)
|
await TypstCanvasElement.compile(this.path, this.source, this.size, this.display, fontSize)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
this.outerText = error
|
let pre = createEl("pre")//"<pre> </pre>"
|
||||||
|
pre.textContent = error
|
||||||
|
this.outerHTML = pre.outerHTML
|
||||||
|
// this.innerText = error
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user