aboutsummaryrefslogtreecommitdiff
path: root/lib/typst/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/typst/src')
-rw-r--r--lib/typst/src/lib.rs52
-rw-r--r--lib/typst/src/world.rs88
2 files changed, 140 insertions, 0 deletions
diff --git a/lib/typst/src/lib.rs b/lib/typst/src/lib.rs
new file mode 100644
index 0000000..5c2ee0d
--- /dev/null
+++ b/lib/typst/src/lib.rs
@@ -0,0 +1,52 @@
+//! Based on https://github.com/zeon256/minimal-typst-svg-renderer
+use std::ffi::{CStr, CString};
+use std::os::raw::c_char;
+
+use typst::layout::PagedDocument;
+use typst_svg::svg_frame;
+
+use crate::world::MinimalWorld;
+
+mod world;
+
+pub fn compile(content: &str) -> String {
+ let world = MinimalWorld::new(content);
+
+ let res = typst::compile::<PagedDocument>(&world);
+
+ if !res.warnings.is_empty() {
+ eprintln!("Warnings: {:?}", res.warnings);
+ }
+
+ let doc = res.output.expect("Error compiling typst");
+
+ svg_frame(&doc.pages[0].frame)
+}
+
+pub fn escape_math(content: &str) -> String {
+ content.replace("$", r"\$").replace("\n", r"\ ")
+}
+
+unsafe fn convert_call(source: *const c_char, f: fn(&str) -> String) -> *const c_char {
+ unsafe {
+ let res = f(CStr::from_ptr(source).to_str().unwrap());
+ CString::new(res).unwrap().into_raw()
+ }
+}
+
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn typst_generateSVG(source: *const c_char) -> *const c_char {
+ unsafe { convert_call(source, compile) }
+}
+
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn typst_freeString(res: *mut c_char) {
+ unsafe {
+ drop(CString::from_raw(res));
+ }
+}
+
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn typst_escapeMath(source: *const c_char) -> *const c_char {
+ unsafe { convert_call(source, escape_math) }
+}
diff --git a/lib/typst/src/world.rs b/lib/typst/src/world.rs
new file mode 100644
index 0000000..c2fe7c7
--- /dev/null
+++ b/lib/typst/src/world.rs
@@ -0,0 +1,88 @@
+//! Based on https://github.com/zeon256/minimal-typst-svg-renderer
+
+use std::path::PathBuf;
+
+use typst::Library;
+use typst::LibraryExt;
+use typst::World;
+use typst::diag::{FileError, FileResult};
+use typst::foundations::{Bytes, Datetime};
+use typst::syntax::{FileId, Source};
+use typst::text::{Font, FontBook};
+use typst::utils::LazyHash;
+use typst_kit::fonts::{FontSlot, Fonts};
+
+/// Main interface that determines the environment for Typst.
+pub struct MinimalWorld {
+ /// The content of a source.
+ source: Source,
+
+ /// The standard library.
+ library: LazyHash<Library>,
+
+ /// Metadata about all known fonts.
+ book: LazyHash<FontBook>,
+
+ /// Metadata about all known fonts.
+ fonts: Vec<FontSlot>,
+}
+
+impl MinimalWorld {
+ pub fn new(source: impl Into<String>) -> Self {
+ let mut searcher = Fonts::searcher();
+ searcher.include_system_fonts(true);
+ #[cfg(feature = "embed-fonts")]
+ searcher.include_embedded_fonts(true);
+ let fonts = searcher.search();
+
+ Self {
+ library: LazyHash::new(Library::default()),
+ book: LazyHash::new(fonts.book),
+ fonts: fonts.fonts,
+ source: Source::detached(source),
+ }
+ }
+}
+
+impl World for MinimalWorld {
+ /// Standard library.
+ fn library(&self) -> &LazyHash<Library> {
+ &self.library
+ }
+
+ /// Metadata about all known Books.
+ fn book(&self) -> &LazyHash<FontBook> {
+ &self.book
+ }
+
+ /// Accessing the main source file.
+ fn main(&self) -> FileId {
+ self.source.id()
+ }
+
+ /// Accessing a specified source file (based on `FileId`).
+ fn source(&self, id: FileId) -> FileResult<Source> {
+ if id == self.source.id() {
+ Ok(self.source.clone())
+ } else {
+ Err(FileError::NotFound(PathBuf::new()))
+ }
+ }
+
+ /// Accessing a specified file (non-file).
+ fn file(&self, _id: FileId) -> FileResult<Bytes> {
+ Err(FileError::NotFound(PathBuf::new()))
+ }
+
+ /// Accessing a specified font per index of font book.
+ fn font(&self, id: usize) -> Option<Font> {
+ self.fonts.get(id)?.get()
+ }
+
+ /// Get the current date.
+ ///
+ /// Optionally, an offset in hours is given.
+ fn today(&self, _offset: Option<i64>) -> Option<Datetime> {
+ None
+ }
+}