typst 0.0.5 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d143be4c44248f37729e097aab6a1dd66133eacaeb6107ca96311ed1e2e8af9
4
- data.tar.gz: 50ae4baea78d9f8114a0145185f1302d98de695509a89346c2669d34ce154bdf
3
+ metadata.gz: 06f404ad033d71b2031a08e646614ab5340727441aa1da453aa7755ed12ea0a7
4
+ data.tar.gz: 9d7ed83cb3f3e87688b216be9ec111d5948110955ee4d3734281706d63430448
5
5
  SHA512:
6
- metadata.gz: da41e972ffa6c4b19ba00d1cf10d36143595c3e4ff562d4f3d1659fc6d5c28a7b70763055ad5d896183f77153d1bbae06068e8fef4100d19a8f1d6b8ea626869
7
- data.tar.gz: 939294ccb5bf14a0d5bb2e48754c9c1081c7719c184ae77531159b5a03a428dce5f497af8244e0fa36297d3ed6159949018f5183ad41954df020cf3c0845deaa
6
+ metadata.gz: 9e4d70e2585ea792ab65fc440bcd9aaa57b1bfccdfbcddb6f37980b2fa061f9cef92668f7a7ec00c4b5b181bb67e5e9cf960e72421be6448186bc77b1bd68003
7
+ data.tar.gz: e95d548a3a9c11e4d7fb7ca6ec9acd401068c85227ce509cb10c467dbbf668a51069e683372b0525afcb77e08f71d0362b7e8ffdaa8c1b0688cc2dc831609019
data/README.md CHANGED
@@ -25,29 +25,49 @@ pdf_bytes = Typst::Pdf.new("readme.typ").bytes
25
25
  document = Typst::Pdf.new("readme.typ").document
26
26
  # => "%PDF-1.7\n%\x80\x80\x80\x80\n\n4 0 obj\n<<\n /Type /Font\n /Subtype ..."
27
27
 
28
- # Compile `readme.typ` to SVG and save as `readme.svg`
28
+ # Compile `readme.typ` to SVG and save as `readme_0.svg`, `readme_1.svg`
29
29
  Typst::Svg.new("readme.typ").write("readme.svg")
30
30
 
31
31
  # Or return SVG content as an array of pages
32
32
  pages = Typst::Svg.new("readme.typ").pages
33
33
  # => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
34
34
 
35
+ # Compile `readme.typ` to PNG and save as `readme_0.png`, `readme_1.png`
36
+ Typst::Png.new("readme.typ").write("readme.png")
37
+
38
+ # Or return PNG content as an array of pages
39
+ pages = Typst::Png.new("readme.typ").pages
40
+ # => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...
41
+
35
42
  # Compile `readme.typ` to SVG and save as `readme.html`
36
- Typst::Html.new("readme.typ", "README").write("readme.html")
43
+ Typst::Html.new("readme.typ", title: "README").write("readme.html")
37
44
 
38
45
  # Or return HTML content
39
- markup = Typst::Html.new("readme.typ", title: "README").markup
46
+ markup = Typst::Html.new("readme.typ", title: "README").document
40
47
  # => "\n<!DOCTYPE html>\n<html>\n<head>\n<title>README</title>\n</head>\n<bo..."
41
48
 
49
+ # Use native Typst experimental HTML feature to write single frame HTML file
50
+ Typst::HtmlExperimental.new("readme.typ").write("readme.html")
51
+
52
+ # Or return single frame HTML content (using native Typst experimental HTML feature)
53
+ markup = Typst::HtmlExperimental.new("readme.typ").document
54
+ # => "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n..."
55
+
42
56
  # Compile from a string to PDF
43
57
  t = Typst::Pdf.from_s(%{hello world})
44
58
 
45
59
  # Compile from a string to SVG
46
60
  t = Typst::Svg.from_s(%{hello world})
47
61
 
48
- # Compile from a string to PDF
62
+ # Compile from a string to PNG
63
+ t = Typst::Png.from_s(%{hello world})
64
+
65
+ # Compile from a string to SVG multi-frame/pages wrapped in HTML (non-native Typst)
49
66
  t = Typst::Html.from_s(%{hello world})
50
67
 
68
+ # Compile from a string to single frame HTML (native Typst experimental feature)
69
+ t = Typst::HtmlExperimental.from_s(%{hello world})
70
+
51
71
  # A more complex example of compiling from string
52
72
  main = %{
53
73
  #import "template.typ": *
@@ -77,6 +97,20 @@ Typst::Pdf::from_zip("working_directory.zip")
77
97
 
78
98
  # From a zip with a named main typst file
79
99
  Typst::Pdf::from_zip("working_directory.zip", "hello.typ")
100
+
101
+ Typst::Query.new("heading", "readme.typ").result
102
+ # =>
103
+ # [{"func" => "heading",
104
+ # "level" => 1,
105
+ # "depth" => 1,
106
+ # ...
107
+
108
+ Typst::Query.new("heading", "readme.typ", format: "json").result(raw: true)
109
+ # => "[\n {\n \"func\": \"heading\",\n \"level\": 1,\n \"depth\": ..."
110
+
111
+ Typst::Query.new("heading", "readme.typ", format: "yaml").result(raw: true)
112
+ # => "- func: heading\n level: 1\n depth: 1\n offset: 0\n numbering: ..."
113
+
80
114
  ```
81
115
 
82
116
  ## Contributors & Acknowledgements
data/README.typ CHANGED
@@ -28,29 +28,49 @@ pdf_bytes = Typst::Pdf.new("readme.typ").bytes
28
28
  document = Typst::Pdf.new("readme.typ").document
29
29
  # => "%PDF-1.7\n%\x80\x80\x80\x80\n\n4 0 obj\n<<\n /Type /Font\n /Subtype ..."
30
30
 
31
- # Compile `readme.typ` to SVG and save as `readme.svg`
31
+ # Compile `readme.typ` to SVG and save as `readme_0.svg`, `readme_1.svg`
32
32
  Typst::Svg.new("readme.typ").write("readme.svg")
33
33
 
34
34
  # Or return SVG content as an array of pages
35
35
  pages = Typst::Svg.new("readme.typ").pages
36
36
  # => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
37
37
 
38
+ # Compile `readme.typ` to PNG and save as `readme_0.png`, `readme_1.png`
39
+ Typst::Png.new("readme.typ").write("readme.png")
40
+
41
+ # Or return PNG content as an array of pages
42
+ pages = Typst::Png.new("readme.typ").pages
43
+ # => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...
44
+
38
45
  # Compile `readme.typ` to SVG and save as `readme.html`
39
- Typst::Html.new("readme.typ", "README").write("readme.html")
46
+ Typst::Html.new("readme.typ", title: "README").write("readme.html")
40
47
 
41
48
  # Or return HTML content
42
- markup = Typst::Html.new("readme.typ", title: "README").markup
49
+ markup = Typst::Html.new("readme.typ", title: "README").document
43
50
  # => "\n<!DOCTYPE html>\n<html>\n<head>\n<title>README</title>\n</head>\n<bo..."
44
51
 
52
+ # Use native Typst experimental HTML feature to write single frame HTML file
53
+ Typst::HtmlExperimental.new("readme.typ").write("readme.html")
54
+
55
+ # Or return single frame HTML content (using native Typst experimental HTML feature)
56
+ markup = Typst::HtmlExperimental.new("readme.typ").document
57
+ # => "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n..."
58
+
45
59
  # Compile from a string to PDF
46
60
  t = Typst::Pdf.from_s(%{hello world})
47
61
 
48
62
  # Compile from a string to SVG
49
63
  t = Typst::Svg.from_s(%{hello world})
50
64
 
51
- # Compile from a string to PDF
65
+ # Compile from a string to PNG
66
+ t = Typst::Png.from_s(%{hello world})
67
+
68
+ # Compile from a string to SVG multi-frame/pages wrapped in HTML (non-native Typst)
52
69
  t = Typst::Html.from_s(%{hello world})
53
70
 
71
+ # Compile from a string to single frame HTML (native Typst experimental feature)
72
+ t = Typst::HtmlExperimental.from_s(%{hello world})
73
+
54
74
  # A more complex example of compiling from string
55
75
  main = %{
56
76
  #import "template.typ": *
@@ -80,6 +100,20 @@ Typst::Pdf::from_zip("working_directory.zip")
80
100
 
81
101
  # From a zip with a named main typst file
82
102
  Typst::Pdf::from_zip("working_directory.zip", "hello.typ")
103
+
104
+ Typst::Query.new("heading", "readme.typ").result
105
+ # =>
106
+ # [{"func" => "heading",
107
+ # "level" => 1,
108
+ # "depth" => 1,
109
+ # ...
110
+
111
+ Typst::Query.new("heading", "readme.typ", format: "json").result(raw: true)
112
+ # => "[\n {\n \"func\": \"heading\",\n \"level\": 1,\n \"depth\": ..."
113
+
114
+ Typst::Query.new("heading", "readme.typ", format: "yaml").result(raw: true)
115
+ # => "- func: heading\n level: 1\n depth: 1\n offset: 0\n numbering: ..."
116
+
83
117
  ```
84
118
 
85
119
  == Contributors & Acknowledgements
data/ext/typst/Cargo.toml CHANGED
@@ -1,33 +1,48 @@
1
1
  [package]
2
2
  name = "typst"
3
- version = "0.0.1"
3
+ version = "0.13.0"
4
4
  edition = "2021"
5
5
 
6
6
  [lib]
7
7
  crate-type = ["cdylib"]
8
8
 
9
9
  [dependencies]
10
- chrono = { version = "0.4.24", default-features = false, features = [
10
+ chrono = { version = "0.4.38", default-features = false, features = [
11
11
  "clock",
12
12
  "std",
13
13
  ] }
14
14
  codespan-reporting = "0.11"
15
- comemo = "0.3"
16
- dirs = "5"
15
+ comemo = "0.4"
16
+ dirs = "5" #
17
17
  ecow = "0.2"
18
- env_logger = "0.10.1"
19
- env_proxy = "0.4"
20
- filetime = "0.2.22"
21
- flate2 = "1"
22
- fontdb = "0.15.0"
23
- log = "0.4.20"
18
+ env_logger = "0.10.1" #
19
+ env_proxy = "0.4" #
20
+ filetime = "0.2.22" #
21
+ flate2 = "1" #
22
+ fontdb = "0.15.0" #
23
+ log = "0.4.20" #
24
24
  magnus = { version = "0.6" }
25
25
  pathdiff = "0.2"
26
- same-file = "1"
27
- siphasher = "1.0"
28
- tar = "0.4"
29
- typst = { git = "https://github.com/typst/typst.git", tag = "v0.9.0" }
30
- typst-library = { git = "https://github.com/typst/typst.git", tag = "v0.9.0" }
26
+ same-file = "1" #
27
+ siphasher = "1.0" #
28
+ tar = "0.4" #
29
+ #typst = { git = "https://github.com/typst/typst.git", tag = "v0.13.0" }
30
+ #typst-library = { git = "https://github.com/typst/typst.git", tag = "v0.13.0" }
31
+ serde = { version = "1.0.217", features = ["derive"] }
32
+ serde_json = "1"
33
+ serde_yaml = "0.9"
34
+ typst = "0.13.0"
35
+ typst-library = "0.13.0"
36
+ typst-kit = { version = "0.13.0", features = [
37
+ "downloads",
38
+ "embed-fonts",
39
+ "vendor-openssl",
40
+ ] }
41
+ typst-pdf = "0.13.0"
42
+ typst-svg = "0.13.0"
43
+ typst-html = "0.13.0"
44
+ typst-render = "0.13.0"
45
+ typst-eval = "0.13.0"
31
46
  ureq = { version = "2", default-features = false, features = [
32
47
  "gzip",
33
48
  "socks-proxy",
@@ -1,9 +1,11 @@
1
1
  use chrono::{Datelike, Timelike};
2
2
  use codespan_reporting::diagnostic::{Diagnostic, Label};
3
3
  use codespan_reporting::term::{self, termcolor};
4
- use typst::diag::{Severity, SourceDiagnostic, StrResult};
5
- use typst::doc::Document;
6
- use typst::eval::{eco_format, Datetime, Tracer};
4
+ use ecow::{eco_format, EcoString};
5
+ use typst::diag::{Severity, SourceDiagnostic, StrResult, Warned};
6
+ use typst::foundations::Datetime;
7
+ use typst::html::HtmlDocument;
8
+ use typst::layout::PagedDocument;
7
9
  use typst::syntax::{FileId, Source, Span};
8
10
  use typst::{World, WorldExt};
9
11
 
@@ -13,55 +15,86 @@ type CodespanResult<T> = Result<T, CodespanError>;
13
15
  type CodespanError = codespan_reporting::files::Error;
14
16
 
15
17
  impl SystemWorld {
16
- pub fn compile_pdf(&mut self) -> StrResult<Vec<u8>> {
18
+ pub fn compile(
19
+ &mut self,
20
+ format: Option<&str>,
21
+ ppi: Option<f32>,
22
+ pdf_standards: &[typst_pdf::PdfStandard],
23
+ ) -> StrResult<Vec<Vec<u8>>> {
17
24
  // Reset everything and ensure that the main file is present.
18
25
  self.reset();
19
26
  self.source(self.main()).map_err(|err| err.to_string())?;
20
27
 
21
- let mut tracer = Tracer::default();
22
- let result = typst::compile(self, &mut tracer);
23
- let warnings = tracer.warnings();
24
-
25
- match result {
26
- // Export the PDF / PNG.
27
- Ok(document) => Ok(export_pdf(&document, self)?),
28
- Err(errors) => Err(format_diagnostics(self, &errors, &warnings).unwrap().into()),
29
- }
30
- }
31
-
32
- pub fn compile_svg(&mut self) -> StrResult<Vec<String>> {
33
- // Reset everything and ensure that the main file is present.
34
- self.reset();
35
- self.source(self.main()).map_err(|err| err.to_string())?;
36
-
37
- let mut tracer = Tracer::default();
38
- let result = typst::compile(self, &mut tracer);
39
- let warnings = tracer.warnings();
40
-
41
- match result {
42
- // Export the PDF / PNG.
43
- Ok(document) => Ok(export_svg(&document)?),
44
- Err(errors) => Err(format_diagnostics(self, &errors, &warnings).unwrap().into()),
28
+ match format.unwrap_or_else(|| "pdf").to_ascii_lowercase().as_str() {
29
+ "html" => {
30
+ let Warned { output, warnings } = typst::compile::<HtmlDocument>(self);
31
+ match output {
32
+ Ok(document) => {
33
+ Ok(vec![export_html(&document, self)?])
34
+ }
35
+ Err(errors) => Err(format_diagnostics(self, &errors, &warnings).unwrap().into()),
36
+ }
37
+ }
38
+ _ => {
39
+ let Warned { output, warnings } = typst::compile::<PagedDocument>(self);
40
+ match output {
41
+ // Export the PDF / PNG.
42
+ Ok(document) => {
43
+ // Assert format is "pdf" or "png" or "svg"
44
+ match format.unwrap_or("pdf").to_ascii_lowercase().as_str() {
45
+ "pdf" => Ok(vec![export_pdf(
46
+ &document,
47
+ self,
48
+ typst_pdf::PdfStandards::new(pdf_standards)?,
49
+ )?]),
50
+ "png" => Ok(export_image(&document, ImageExportFormat::Png, ppi)?),
51
+ "svg" => Ok(export_image(&document, ImageExportFormat::Svg, ppi)?),
52
+ fmt => Err(eco_format!("unknown format: {fmt}")),
53
+ }
54
+ }
55
+ Err(errors) => Err(format_diagnostics(self, &errors, &warnings).unwrap().into()),
56
+ }
57
+ }
45
58
  }
46
59
  }
47
60
  }
48
61
 
49
62
  /// Export to a PDF.
50
63
  #[inline]
51
- fn export_pdf(document: &Document, world: &SystemWorld) -> StrResult<Vec<u8>> {
52
- let ident = world.input().to_string_lossy();
53
- let buffer = typst::export::pdf(document, Some(&ident), now());
64
+ fn export_html(
65
+ document: &HtmlDocument,
66
+ world: &SystemWorld,
67
+ ) -> StrResult<Vec<u8>> {
68
+ let html = typst_html::html(document)
69
+ .map_err(|e| match format_diagnostics(world, &e, &[]) {
70
+ Ok(e) => EcoString::from(e),
71
+ Err(err) => eco_format!("failed to print diagnostics ({err})"),
72
+ })?;
73
+ let buffer = html.as_bytes().to_vec();
54
74
  Ok(buffer)
55
75
  }
56
76
 
57
- /// Export to one or multiple SVGs.
77
+ /// Export to a PDF.
58
78
  #[inline]
59
- fn export_svg(document: &Document) -> StrResult<Vec<String>> {
60
- let mut buffer: Vec<String> = Vec::new();
61
- for (_i, frame) in document.pages.iter().enumerate() {
62
- let svg = typst::export::svg(frame);
63
- buffer.push(svg.to_string())
64
- }
79
+ fn export_pdf(
80
+ document: &PagedDocument,
81
+ world: &SystemWorld,
82
+ standards: typst_pdf::PdfStandards,
83
+ ) -> StrResult<Vec<u8>> {
84
+ let ident = world.input().to_string_lossy();
85
+ let buffer = typst_pdf::pdf(
86
+ document,
87
+ &typst_pdf::PdfOptions {
88
+ ident: typst::foundations::Smart::Custom(&ident),
89
+ timestamp: now().map(typst_pdf::Timestamp::new_utc),
90
+ standards,
91
+ ..Default::default()
92
+ },
93
+ )
94
+ .map_err(|e| match format_diagnostics(world, &e, &[]) {
95
+ Ok(e) => EcoString::from(e),
96
+ Err(err) => eco_format!("failed to print diagnostics ({err})"),
97
+ })?;
65
98
  Ok(buffer)
66
99
  }
67
100
 
@@ -78,6 +111,34 @@ fn now() -> Option<Datetime> {
78
111
  )
79
112
  }
80
113
 
114
+ /// An image format to export in.
115
+ enum ImageExportFormat {
116
+ Png,
117
+ Svg,
118
+ }
119
+
120
+ /// Export the frames to PNGs or SVGs.
121
+ fn export_image(
122
+ document: &PagedDocument,
123
+ fmt: ImageExportFormat,
124
+ ppi: Option<f32>,
125
+ ) -> StrResult<Vec<Vec<u8>>> {
126
+ let mut buffers = Vec::new();
127
+ for page in &document.pages {
128
+ let buffer = match fmt {
129
+ ImageExportFormat::Png => typst_render::render(page, ppi.unwrap_or(144.0) / 72.0)
130
+ .encode_png()
131
+ .map_err(|err| eco_format!("failed to write PNG file ({err})"))?,
132
+ ImageExportFormat::Svg => {
133
+ let svg = typst_svg::svg(page);
134
+ svg.as_bytes().to_vec()
135
+ }
136
+ };
137
+ buffers.push(buffer);
138
+ }
139
+ Ok(buffers)
140
+ }
141
+
81
142
  /// Format diagnostic messages.\
82
143
  pub fn format_diagnostics(
83
144
  world: &SystemWorld,
@@ -141,7 +202,7 @@ impl<'a> codespan_reporting::files::Files<'a> for SystemWorld {
141
202
  // Try to express the path relative to the working directory.
142
203
  vpath
143
204
  .resolve(self.root())
144
- .and_then(|abs| pathdiff::diff_paths(&abs, self.workdir()))
205
+ .and_then(|abs| pathdiff::diff_paths(abs, self.workdir()))
145
206
  .as_deref()
146
207
  .unwrap_or_else(|| vpath.as_rootless_path())
147
208
  .to_string_lossy()
@@ -1,79 +1,19 @@
1
- use std::io::{self, ErrorKind, Read};
1
+ use std::fmt::Display;
2
2
 
3
- use ureq::Response;
3
+ use typst_kit::download::{DownloadState, Downloader, Progress};
4
4
 
5
- /// Download binary data and display its progress.
6
- #[allow(clippy::result_large_err)]
7
- pub fn download(url: &str) -> Result<Vec<u8>, ureq::Error> {
8
- let mut builder =
9
- ureq::AgentBuilder::new().user_agent(concat!("typst/{}", env!("CARGO_PKG_VERSION")));
5
+ pub struct SlientDownload<T>(pub T);
10
6
 
11
- // Get the network proxy config from the environment.
12
- if let Some(proxy) = env_proxy::for_url_str(url)
13
- .to_url()
14
- .and_then(|url| ureq::Proxy::new(url).ok())
15
- {
16
- builder = builder.proxy(proxy);
17
- }
7
+ impl<T: Display> Progress for SlientDownload<T> {
8
+ fn print_start(&mut self) {}
18
9
 
19
- let agent = builder.build();
20
- let response = agent.get(url).call()?;
21
- Ok(RemoteReader::from_response(response).download()?)
22
- }
10
+ fn print_progress(&mut self, _state: &DownloadState) {}
23
11
 
24
- /// A wrapper around [`ureq::Response`] that reads the response body in chunks
25
- /// over a websocket and displays statistics about its progress.
26
- ///
27
- /// Downloads will _never_ fail due to statistics failing to print, print errors
28
- /// are silently ignored.
29
- struct RemoteReader {
30
- reader: Box<dyn Read + Send + Sync + 'static>,
31
- content_len: Option<usize>,
12
+ fn print_finish(&mut self, _state: &DownloadState) {}
32
13
  }
33
14
 
34
- impl RemoteReader {
35
- /// Wraps a [`ureq::Response`] and prepares it for downloading.
36
- ///
37
- /// The 'Content-Length' header is used as a size hint for read
38
- /// optimization, if present.
39
- pub fn from_response(response: Response) -> Self {
40
- let content_len: Option<usize> = response
41
- .header("Content-Length")
42
- .and_then(|header| header.parse().ok());
43
-
44
- Self {
45
- reader: response.into_reader(),
46
- content_len,
47
- }
48
- }
49
-
50
- /// Download the bodies content as raw bytes while attempting to print
51
- /// download statistics to standard error. Download progress gets displayed
52
- /// and updated every second.
53
- ///
54
- /// These statistics will never prevent a download from completing, errors
55
- /// are silently ignored.
56
- pub fn download(mut self) -> io::Result<Vec<u8>> {
57
- let mut buffer = vec![0; 8192];
58
- let mut data = match self.content_len {
59
- Some(content_len) => Vec::with_capacity(content_len),
60
- None => Vec::with_capacity(8192),
61
- };
62
-
63
- loop {
64
- let read = match self.reader.read(&mut buffer) {
65
- Ok(0) => break,
66
- Ok(n) => n,
67
- // If the data is not yet ready but will be available eventually
68
- // keep trying until we either get an actual error, receive data
69
- // or an Ok(0).
70
- Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
71
- Err(e) => return Err(e),
72
- };
73
-
74
- data.extend(&buffer[..read]);
75
- }
76
-
77
- Ok(data)
78
- }
15
+ /// Returns a new downloader.
16
+ pub fn downloader() -> Downloader {
17
+ let user_agent = concat!("typst-py/", env!("CARGO_PKG_VERSION"));
18
+ Downloader::new(user_agent)
79
19
  }