typst 0.0.5 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }