typst 0.14.2 → 0.14.2.2
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 +4 -4
- data/README.md +34 -24
- data/README.typ +35 -25
- data/Rakefile +3 -7
- data/ext/typst/Cargo.toml +2 -4
- data/ext/typst/src/compiler.rs +0 -1
- data/ext/typst/src/download.rs +1 -1
- data/ext/typst/src/lib.rs +80 -39
- data/ext/typst/src/query.rs +1 -1
- data/ext/typst/src/world.rs +0 -1
- data/lib/base.rb +45 -72
- data/lib/document.rb +15 -7
- data/lib/formats/html_experimental.rb +3 -1
- data/lib/formats/pdf.rb +4 -2
- data/lib/formats/png.rb +4 -2
- data/lib/formats/svg.rb +3 -1
- data/lib/query.rb +6 -3
- data/lib/typst.rb +67 -4
- metadata +32 -7
- data/lib/formats/html.rb +0 -35
- data/lib/typst/typst.bundle +0 -0
- data/lib/typst/typst.so +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0e902865d606a53619b4af115102284997f623a128bc06405f5300c4c2b4c687
|
|
4
|
+
data.tar.gz: a33d506d802a470779eb60c2d075a0c6cf9babf50756b8633d87e297d05cc1fd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: baa7a4a6b87a9ba92b821f061e53dd4a45f014a45d672c68dd9cc6c08c4b1fd90a60c548c5d87a4fa41f1d5c024c5f916691fb122aafa5705259dbdfcc8ee7c2
|
|
7
|
+
data.tar.gz: c208d4cf87db4672ba0e9bfc40f63b1b8152dadb5e42c42f270d57172318a7194189c5c208f2a91b44c3933ec6f15bc84ebf465edcedb7cf8b35f4e33158bec4
|
data/README.md
CHANGED
|
@@ -27,43 +27,40 @@ t = Typst(body: %{hello world})
|
|
|
27
27
|
t = Typst(zip: "test/main.typ.zip")
|
|
28
28
|
|
|
29
29
|
# Compile to PDF
|
|
30
|
-
|
|
30
|
+
doc = t.compile(:pdf)
|
|
31
|
+
|
|
32
|
+
# Compile to PDF selecting the typst supported PdfStandard
|
|
33
|
+
doc = t.compile(:pdf, pdf_standards: ["2.0"])
|
|
31
34
|
|
|
32
35
|
# Compile to SVG
|
|
33
|
-
|
|
36
|
+
doc = t.compile(:svg)
|
|
34
37
|
|
|
35
38
|
# Compile to PNG
|
|
36
|
-
|
|
39
|
+
doc = t.compile(:png)
|
|
37
40
|
|
|
38
|
-
# Compile to
|
|
39
|
-
|
|
40
|
-
f = t.compile(:html, title: "Typst+Ruby")
|
|
41
|
+
# Compile to PNG and set PPI
|
|
42
|
+
doc = t.compile(:png, ppi: 72)
|
|
41
43
|
|
|
42
44
|
# Compile to HTML (using Typst expirmental HTML)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
# Access PDF or HTML output as a string
|
|
46
|
-
# Note: For PDF and PNG this will give data, for SVG and HTML this will give markup
|
|
47
|
-
Typst("readme.typ").compile(:pdf).document
|
|
48
|
-
# => "%PDF-1.7\n%\x80\x80\x80\x80\n\n4 0 obj\n<<\n /Type /Font\n /Subtype ..."
|
|
49
|
-
Typst("readme.typ").compile(:html).document
|
|
50
|
-
# => "\n<!DOCTYPE html>\n<html>\n<head>\n<title>main</title>\n</head>\n<body>\n<svg class=\"typst-doc\" ...
|
|
45
|
+
doc = t.compile(:html_experimental)
|
|
51
46
|
|
|
52
47
|
# Or return content as an array of bytes
|
|
53
48
|
pdf_bytes = Typst("readme.typ").compile(:pdf).bytes
|
|
54
49
|
# => [37, 80, 68, 70, 45, 49, 46, 55, 10, 37, 128 ...]
|
|
55
50
|
|
|
56
51
|
# Write the output to a file
|
|
57
|
-
# Note: for multi-page documents using formats other than PDF, pages write to multiple files, e.g. `readme_0.png`, `readme_1.png`
|
|
58
|
-
|
|
52
|
+
# Note: for multi-page documents using formats other than PDF and HTML, pages write to multiple files, e.g. `readme_0.png`, `readme_1.png`
|
|
53
|
+
doc.write("filename.pdf")
|
|
59
54
|
|
|
60
|
-
# Return SVG,
|
|
55
|
+
# Return PDF, SVG, PNG or HTML content as an array of pages
|
|
56
|
+
Typst("readme.typ").compile(:pdf).pages
|
|
57
|
+
# => ["%PDF-1.7\n%\x80\x80\x80\x80\n\n1 0 obj\n<<\n /Type /Pages\n /Count 3\n /Kids [160 0 R 162 ...
|
|
61
58
|
Typst("readme.typ").compile(:svg).pages
|
|
62
|
-
# => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ...
|
|
63
|
-
Typst("readme.typ").compile(:html).pages
|
|
64
|
-
# => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
|
|
59
|
+
# => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ...
|
|
65
60
|
Typst("readme.typ").compile(:png).pages
|
|
66
61
|
# => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...
|
|
62
|
+
Typst("readme.typ").compile(:html_experimental).pages
|
|
63
|
+
# => ["<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" ...
|
|
67
64
|
|
|
68
65
|
# Pass values into typst using sys_inputs
|
|
69
66
|
sys_inputs_example = %{
|
|
@@ -110,23 +107,36 @@ Typst(body: main, dependencies: { "template.typ" => template, "icon.svg" => icon
|
|
|
110
107
|
# From a zip with a named main typst file
|
|
111
108
|
Typst(zip: "test/main.typ.zip", main_file: "hello.typ").compile(:pdf)
|
|
112
109
|
|
|
113
|
-
Typst
|
|
110
|
+
Typst("readme.typ").query("heading").result
|
|
114
111
|
# =>
|
|
115
112
|
# [{"func" => "heading",
|
|
116
113
|
# "level" => 1,
|
|
117
114
|
# "depth" => 1,
|
|
118
115
|
# ...
|
|
119
116
|
|
|
120
|
-
Typst
|
|
117
|
+
Typst("readme.typ").query("heading", format: "json").result(raw: true)
|
|
121
118
|
# => "[\n {\n \"func\": \"heading\",\n \"level\": 1,\n \"depth\": ..."
|
|
122
119
|
|
|
123
|
-
Typst
|
|
120
|
+
Typst("readme.typ").query("heading", format: "yaml").result(raw: true)
|
|
124
121
|
# => "- func: heading\n level: 1\n depth: 1\n offset: 0\n numbering: ..."
|
|
125
122
|
|
|
123
|
+
# Query results as JSON string
|
|
124
|
+
Typst("test/test.typ").query("heading").to_s
|
|
125
|
+
=> "[\n {\n \"func\": \"heading\",\n \"level\": 1,\n \"depth\": 1,\n \"offset\": 0,\n ...
|
|
126
|
+
|
|
127
|
+
# Query results as YAML string
|
|
128
|
+
Typst("test/test.typ").query("heading", format: "yaml").to_s
|
|
129
|
+
=> "- func: heading\n level: 1\n depth: 1\n offset: 0\n numbering: null\n supplement:\n ...
|
|
130
|
+
|
|
131
|
+
# clear the compilation cache
|
|
132
|
+
# Evict all entries whose age is larger than or equal to `max_age`
|
|
133
|
+
max_age = 10
|
|
134
|
+
Typst::clear_cache(max_age)
|
|
126
135
|
```
|
|
127
136
|
|
|
128
137
|
## Contributors & Acknowledgements
|
|
129
|
-
typst-rb is based on [typst-py](https://github.com/messense/typst-py) by [messense](https://github.com/messense)
|
|
138
|
+
typst-rb is based on [typst-py](https://github.com/messense/typst-py) by [messense](https://github.com/messense)\
|
|
139
|
+
clear_cache was contributed by [NRicciVestmark](https://github.com/NRicciVestmark)
|
|
130
140
|
|
|
131
141
|
## License
|
|
132
142
|
|
data/README.typ
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
#set document(title: [typst.rb README])
|
|
2
2
|
#show link: underline
|
|
3
3
|
#show link: set text(blue)
|
|
4
4
|
|
|
@@ -30,43 +30,40 @@ t = Typst(body: %{hello world})
|
|
|
30
30
|
t = Typst(zip: "test/main.typ.zip")
|
|
31
31
|
|
|
32
32
|
# Compile to PDF
|
|
33
|
-
|
|
33
|
+
doc = t.compile(:pdf)
|
|
34
|
+
|
|
35
|
+
# Compile to PDF selecting the typst supported PdfStandard
|
|
36
|
+
doc = t.compile(:pdf, pdf_standards: ["2.0"])
|
|
34
37
|
|
|
35
38
|
# Compile to SVG
|
|
36
|
-
|
|
39
|
+
doc = t.compile(:svg)
|
|
37
40
|
|
|
38
41
|
# Compile to PNG
|
|
39
|
-
|
|
42
|
+
doc = t.compile(:png)
|
|
40
43
|
|
|
41
|
-
# Compile to
|
|
42
|
-
|
|
43
|
-
f = t.compile(:html, title: "Typst+Ruby")
|
|
44
|
+
# Compile to PNG and set PPI
|
|
45
|
+
doc = t.compile(:png, ppi: 72)
|
|
44
46
|
|
|
45
47
|
# Compile to HTML (using Typst expirmental HTML)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
# Access PDF or HTML output as a string
|
|
49
|
-
# Note: For PDF and PNG this will give data, for SVG and HTML this will give markup
|
|
50
|
-
Typst("readme.typ").compile(:pdf).document
|
|
51
|
-
# => "%PDF-1.7\n%\x80\x80\x80\x80\n\n4 0 obj\n<<\n /Type /Font\n /Subtype ..."
|
|
52
|
-
Typst("readme.typ").compile(:html).document
|
|
53
|
-
# => "\n<!DOCTYPE html>\n<html>\n<head>\n<title>main</title>\n</head>\n<body>\n<svg class=\"typst-doc\" ...
|
|
48
|
+
doc = t.compile(:html_experimental)
|
|
54
49
|
|
|
55
50
|
# Or return content as an array of bytes
|
|
56
51
|
pdf_bytes = Typst("readme.typ").compile(:pdf).bytes
|
|
57
52
|
# => [37, 80, 68, 70, 45, 49, 46, 55, 10, 37, 128 ...]
|
|
58
53
|
|
|
59
54
|
# Write the output to a file
|
|
60
|
-
# Note: for multi-page documents using formats other than PDF, pages write to multiple files, e.g. `readme_0.png`, `readme_1.png`
|
|
61
|
-
|
|
55
|
+
# Note: for multi-page documents using formats other than PDF and HTML, pages write to multiple files, e.g. `readme_0.png`, `readme_1.png`
|
|
56
|
+
doc.write("filename.pdf")
|
|
62
57
|
|
|
63
|
-
# Return SVG,
|
|
58
|
+
# Return PDF, SVG, PNG or HTML content as an array of pages
|
|
59
|
+
Typst("readme.typ").compile(:pdf).pages
|
|
60
|
+
# => ["%PDF-1.7\n%\x80\x80\x80\x80\n\n1 0 obj\n<<\n /Type /Pages\n /Count 3\n /Kids [160 0 R 162 ...
|
|
64
61
|
Typst("readme.typ").compile(:svg).pages
|
|
65
|
-
# => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ...
|
|
66
|
-
Typst("readme.typ").compile(:html).pages
|
|
67
|
-
# => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
|
|
62
|
+
# => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ...
|
|
68
63
|
Typst("readme.typ").compile(:png).pages
|
|
69
64
|
# => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...
|
|
65
|
+
Typst("readme.typ").compile(:html_experimental).pages
|
|
66
|
+
# => ["<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" ...
|
|
70
67
|
|
|
71
68
|
# Pass values into typst using sys_inputs
|
|
72
69
|
sys_inputs_example = %{
|
|
@@ -113,23 +110,36 @@ Typst(body: main, dependencies: { "template.typ" => template, "icon.svg" => icon
|
|
|
113
110
|
# From a zip with a named main typst file
|
|
114
111
|
Typst(zip: "test/main.typ.zip", main_file: "hello.typ").compile(:pdf)
|
|
115
112
|
|
|
116
|
-
Typst
|
|
113
|
+
Typst("readme.typ").query("heading").result
|
|
117
114
|
# =>
|
|
118
115
|
# [{"func" => "heading",
|
|
119
116
|
# "level" => 1,
|
|
120
117
|
# "depth" => 1,
|
|
121
118
|
# ...
|
|
122
119
|
|
|
123
|
-
Typst
|
|
120
|
+
Typst("readme.typ").query("heading", format: "json").result(raw: true)
|
|
124
121
|
# => "[\n {\n \"func\": \"heading\",\n \"level\": 1,\n \"depth\": ..."
|
|
125
122
|
|
|
126
|
-
Typst
|
|
123
|
+
Typst("readme.typ").query("heading", format: "yaml").result(raw: true)
|
|
127
124
|
# => "- func: heading\n level: 1\n depth: 1\n offset: 0\n numbering: ..."
|
|
128
125
|
|
|
126
|
+
# Query results as JSON string
|
|
127
|
+
Typst("test/test.typ").query("heading").to_s
|
|
128
|
+
=> "[\n {\n \"func\": \"heading\",\n \"level\": 1,\n \"depth\": 1,\n \"offset\": 0,\n ...
|
|
129
|
+
|
|
130
|
+
# Query results as YAML string
|
|
131
|
+
Typst("test/test.typ").query("heading", format: "yaml").to_s
|
|
132
|
+
=> "- func: heading\n level: 1\n depth: 1\n offset: 0\n numbering: null\n supplement:\n ...
|
|
133
|
+
|
|
134
|
+
# clear the compilation cache
|
|
135
|
+
# Evict all entries whose age is larger than or equal to `max_age`
|
|
136
|
+
max_age = 10
|
|
137
|
+
Typst::clear_cache(max_age)
|
|
129
138
|
```
|
|
130
139
|
|
|
131
140
|
== Contributors & Acknowledgements
|
|
132
|
-
typst-rb is based on #link("https://github.com/messense/typst-py")[typst-py] by #link("https://github.com/messense")[messense]
|
|
141
|
+
typst-rb is based on #link("https://github.com/messense/typst-py")[typst-py] by #link("https://github.com/messense")[messense]\
|
|
142
|
+
clear_cache was contributed by #link("https://github.com/NRicciVestmark")[NRicciVestmark]
|
|
133
143
|
|
|
134
144
|
== License
|
|
135
145
|
|
data/Rakefile
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
require "bundler/gem_tasks"
|
|
2
|
-
require "
|
|
2
|
+
require "rb_sys/extensiontask"
|
|
3
3
|
require "rake/testtask"
|
|
4
|
-
require 'rake_compiler_dock'
|
|
5
|
-
require "rubygems/package_task"
|
|
6
|
-
require "bundler"
|
|
7
4
|
|
|
8
5
|
CROSS_PLATFORMS = %w[
|
|
9
6
|
aarch64-linux
|
|
7
|
+
aarch64-linux-musl
|
|
10
8
|
arm64-darwin
|
|
11
9
|
x64-mingw-ucrt
|
|
12
10
|
x86_64-darwin
|
|
@@ -18,9 +16,7 @@ spec = Bundler.load_gemspec("typst.gemspec")
|
|
|
18
16
|
|
|
19
17
|
Gem::PackageTask.new(spec).define
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Rake::ExtensionTask.new("typst", spec) do |ext|
|
|
19
|
+
RbSys::ExtensionTask.new("typst", spec) do |ext|
|
|
24
20
|
ext.lib_dir = "lib/typst"
|
|
25
21
|
ext.source_pattern = "*.{rs,toml}"
|
|
26
22
|
ext.cross_compile = true
|
data/ext/typst/Cargo.toml
CHANGED
|
@@ -21,13 +21,11 @@ filetime = "0.2.22" #
|
|
|
21
21
|
flate2 = "1" #
|
|
22
22
|
fontdb = "0.15.0" #
|
|
23
23
|
log = "0.4.20" #
|
|
24
|
-
magnus = { version = "0.
|
|
24
|
+
magnus = { version = "0.8.2" }
|
|
25
25
|
pathdiff = "0.2"
|
|
26
26
|
same-file = "1" #
|
|
27
27
|
siphasher = "1.0" #
|
|
28
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
29
|
serde = { version = "1.0.228", features = ["derive"] }
|
|
32
30
|
serde_json = "1"
|
|
33
31
|
serde_yaml = "0.9"
|
|
@@ -51,4 +49,4 @@ walkdir = "2.4.0"
|
|
|
51
49
|
|
|
52
50
|
# enable rb-sys feature to test against Ruby head. This is only needed if you
|
|
53
51
|
# want to work with the unreleased, in-development, next version of Ruby
|
|
54
|
-
rb-sys = { version = "0.9.
|
|
52
|
+
rb-sys = { version = "0.9.123", default-features = false, features = ["stable-api-compiled-fallback"] }
|
data/ext/typst/src/compiler.rs
CHANGED
|
@@ -6,7 +6,6 @@ use typst::diag::{Severity, SourceDiagnostic, StrResult, Warned};
|
|
|
6
6
|
use typst::foundations::Datetime;
|
|
7
7
|
use typst_html::HtmlDocument;
|
|
8
8
|
use typst::layout::PagedDocument;
|
|
9
|
-
//use typst::syntax::{FileId, Source, Span};
|
|
10
9
|
use typst::syntax::{FileId, Lines, Span};
|
|
11
10
|
use typst::{World, WorldExt};
|
|
12
11
|
|
data/ext/typst/src/download.rs
CHANGED
|
@@ -14,6 +14,6 @@ impl<T: Display> Progress for SlientDownload<T> {
|
|
|
14
14
|
|
|
15
15
|
/// Returns a new downloader.
|
|
16
16
|
pub fn downloader() -> Downloader {
|
|
17
|
-
let user_agent = concat!("typst-
|
|
17
|
+
let user_agent = concat!("typst-rb/", env!("CARGO_PKG_VERSION"));
|
|
18
18
|
Downloader::new(user_agent)
|
|
19
19
|
}
|
data/ext/typst/src/lib.rs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
use std::path::PathBuf;
|
|
2
2
|
|
|
3
|
-
use magnus::{
|
|
4
|
-
use magnus::{prelude::*};
|
|
3
|
+
use magnus::{function, prelude::*, Error, Ruby};
|
|
5
4
|
|
|
6
5
|
use std::collections::HashMap;
|
|
7
6
|
use query::{query as typst_query, QueryCommand, SerializationFormat};
|
|
8
7
|
use typst::foundations::{Dict, Value};
|
|
9
8
|
use typst_library::Feature;
|
|
9
|
+
use typst_pdf::PdfStandard;
|
|
10
10
|
use world::SystemWorld;
|
|
11
11
|
|
|
12
12
|
mod compiler;
|
|
@@ -15,6 +15,7 @@ mod query;
|
|
|
15
15
|
mod world;
|
|
16
16
|
|
|
17
17
|
fn to_html(
|
|
18
|
+
ruby: &Ruby,
|
|
18
19
|
input: PathBuf,
|
|
19
20
|
root: Option<PathBuf>,
|
|
20
21
|
font_paths: Vec<PathBuf>,
|
|
@@ -23,11 +24,11 @@ fn to_html(
|
|
|
23
24
|
sys_inputs: HashMap<String, String>,
|
|
24
25
|
) -> Result<Vec<Vec<u8>>, Error> {
|
|
25
26
|
let input = input.canonicalize()
|
|
26
|
-
.map_err(|err| magnus::Error::new(
|
|
27
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?;
|
|
27
28
|
|
|
28
29
|
let root = if let Some(root) = root {
|
|
29
30
|
root.canonicalize()
|
|
30
|
-
.map_err(|err| magnus::Error::new(
|
|
31
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?
|
|
31
32
|
} else if let Some(dir) = input.parent() {
|
|
32
33
|
dir.into()
|
|
33
34
|
} else {
|
|
@@ -35,12 +36,12 @@ fn to_html(
|
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
let resource_path = resource_path.canonicalize()
|
|
38
|
-
.map_err(|err| magnus::Error::new(
|
|
39
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?;
|
|
39
40
|
|
|
40
41
|
let mut default_fonts = Vec::new();
|
|
41
42
|
for entry in walkdir::WalkDir::new(resource_path.join("fonts")) {
|
|
42
43
|
let path = entry
|
|
43
|
-
.map_err(|err| magnus::Error::new(
|
|
44
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?
|
|
44
45
|
.into_path();
|
|
45
46
|
let Some(extension) = path.extension() else {
|
|
46
47
|
continue;
|
|
@@ -72,16 +73,17 @@ fn to_html(
|
|
|
72
73
|
.font_paths(font_paths)
|
|
73
74
|
.ignore_system_fonts(ignore_system_fonts)
|
|
74
75
|
.build()
|
|
75
|
-
.map_err(|msg| magnus::Error::new(
|
|
76
|
+
.map_err(|msg| magnus::Error::new(ruby.exception_arg_error(), msg.to_string()))?;
|
|
76
77
|
|
|
77
78
|
let bytes = world
|
|
78
79
|
.compile(Some("html"), None, &Vec::new())
|
|
79
|
-
.map_err(|msg| magnus::Error::new(
|
|
80
|
+
.map_err(|msg| magnus::Error::new(ruby.exception_arg_error(), msg.to_string()))?;
|
|
80
81
|
|
|
81
82
|
Ok(bytes)
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
fn to_svg(
|
|
86
|
+
ruby: &Ruby,
|
|
85
87
|
input: PathBuf,
|
|
86
88
|
root: Option<PathBuf>,
|
|
87
89
|
font_paths: Vec<PathBuf>,
|
|
@@ -90,11 +92,11 @@ fn to_svg(
|
|
|
90
92
|
sys_inputs: HashMap<String, String>,
|
|
91
93
|
) -> Result<Vec<Vec<u8>>, Error> {
|
|
92
94
|
let input = input.canonicalize()
|
|
93
|
-
.map_err(|err| magnus::Error::new(
|
|
95
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?;
|
|
94
96
|
|
|
95
97
|
let root = if let Some(root) = root {
|
|
96
98
|
root.canonicalize()
|
|
97
|
-
.map_err(|err| magnus::Error::new(
|
|
99
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?
|
|
98
100
|
} else if let Some(dir) = input.parent() {
|
|
99
101
|
dir.into()
|
|
100
102
|
} else {
|
|
@@ -102,12 +104,12 @@ fn to_svg(
|
|
|
102
104
|
};
|
|
103
105
|
|
|
104
106
|
let resource_path = resource_path.canonicalize()
|
|
105
|
-
.map_err(|err| magnus::Error::new(
|
|
107
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?;
|
|
106
108
|
|
|
107
109
|
let mut default_fonts = Vec::new();
|
|
108
110
|
for entry in walkdir::WalkDir::new(resource_path.join("fonts")) {
|
|
109
111
|
let path = entry
|
|
110
|
-
.map_err(|err| magnus::Error::new(
|
|
112
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?
|
|
111
113
|
.into_path();
|
|
112
114
|
let Some(extension) = path.extension() else {
|
|
113
115
|
continue;
|
|
@@ -126,29 +128,31 @@ fn to_svg(
|
|
|
126
128
|
.font_paths(font_paths)
|
|
127
129
|
.ignore_system_fonts(ignore_system_fonts)
|
|
128
130
|
.build()
|
|
129
|
-
.map_err(|msg| magnus::Error::new(
|
|
131
|
+
.map_err(|msg| magnus::Error::new(ruby.exception_arg_error(), msg.to_string()))?;
|
|
130
132
|
|
|
131
133
|
let svg_bytes = world
|
|
132
134
|
.compile(Some("svg"), None, &Vec::new())
|
|
133
|
-
.map_err(|msg| magnus::Error::new(
|
|
135
|
+
.map_err(|msg| magnus::Error::new(ruby.exception_arg_error(), msg.to_string()))?;
|
|
134
136
|
|
|
135
137
|
Ok(svg_bytes)
|
|
136
138
|
}
|
|
137
139
|
|
|
138
140
|
fn to_png(
|
|
141
|
+
ruby: &Ruby,
|
|
139
142
|
input: PathBuf,
|
|
140
143
|
root: Option<PathBuf>,
|
|
141
144
|
font_paths: Vec<PathBuf>,
|
|
142
145
|
resource_path: PathBuf,
|
|
143
146
|
ignore_system_fonts: bool,
|
|
144
147
|
sys_inputs: HashMap<String, String>,
|
|
148
|
+
ppi: Option<f32>,
|
|
145
149
|
) -> Result<Vec<Vec<u8>>, Error> {
|
|
146
150
|
let input = input.canonicalize()
|
|
147
|
-
.map_err(|err| magnus::Error::new(
|
|
151
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?;
|
|
148
152
|
|
|
149
153
|
let root = if let Some(root) = root {
|
|
150
154
|
root.canonicalize()
|
|
151
|
-
.map_err(|err| magnus::Error::new(
|
|
155
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?
|
|
152
156
|
} else if let Some(dir) = input.parent() {
|
|
153
157
|
dir.into()
|
|
154
158
|
} else {
|
|
@@ -156,12 +160,12 @@ fn to_png(
|
|
|
156
160
|
};
|
|
157
161
|
|
|
158
162
|
let resource_path = resource_path.canonicalize()
|
|
159
|
-
.map_err(|err| magnus::Error::new(
|
|
163
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?;
|
|
160
164
|
|
|
161
165
|
let mut default_fonts = Vec::new();
|
|
162
166
|
for entry in walkdir::WalkDir::new(resource_path.join("fonts")) {
|
|
163
167
|
let path = entry
|
|
164
|
-
.map_err(|err| magnus::Error::new(
|
|
168
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?
|
|
165
169
|
.into_path();
|
|
166
170
|
let Some(extension) = path.extension() else {
|
|
167
171
|
continue;
|
|
@@ -180,29 +184,31 @@ fn to_png(
|
|
|
180
184
|
.font_paths(font_paths)
|
|
181
185
|
.ignore_system_fonts(ignore_system_fonts)
|
|
182
186
|
.build()
|
|
183
|
-
.map_err(|msg| magnus::Error::new(
|
|
187
|
+
.map_err(|msg| magnus::Error::new(ruby.exception_arg_error(), msg.to_string()))?;
|
|
184
188
|
|
|
185
189
|
let bytes = world
|
|
186
|
-
.compile(Some("png"),
|
|
187
|
-
.map_err(|msg| magnus::Error::new(
|
|
190
|
+
.compile(Some("png"), ppi, &Vec::new())
|
|
191
|
+
.map_err(|msg| magnus::Error::new(ruby.exception_arg_error(), msg.to_string()))?;
|
|
188
192
|
|
|
189
193
|
Ok(bytes)
|
|
190
194
|
}
|
|
191
195
|
|
|
192
196
|
fn to_pdf(
|
|
197
|
+
ruby: &Ruby,
|
|
193
198
|
input: PathBuf,
|
|
194
199
|
root: Option<PathBuf>,
|
|
195
200
|
font_paths: Vec<PathBuf>,
|
|
196
201
|
resource_path: PathBuf,
|
|
197
202
|
ignore_system_fonts: bool,
|
|
198
203
|
sys_inputs: HashMap<String, String>,
|
|
204
|
+
pdf_standards: Vec<String>,
|
|
199
205
|
) -> Result<Vec<Vec<u8>>, Error> {
|
|
200
206
|
let input = input.canonicalize()
|
|
201
|
-
.map_err(|err| magnus::Error::new(
|
|
207
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?;
|
|
202
208
|
|
|
203
209
|
let root = if let Some(root) = root {
|
|
204
210
|
root.canonicalize()
|
|
205
|
-
.map_err(|err| magnus::Error::new(
|
|
211
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?
|
|
206
212
|
} else if let Some(dir) = input.parent() {
|
|
207
213
|
dir.into()
|
|
208
214
|
} else {
|
|
@@ -210,12 +216,12 @@ fn to_pdf(
|
|
|
210
216
|
};
|
|
211
217
|
|
|
212
218
|
let resource_path = resource_path.canonicalize()
|
|
213
|
-
.map_err(|err| magnus::Error::new(
|
|
219
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?;
|
|
214
220
|
|
|
215
221
|
let mut default_fonts = Vec::new();
|
|
216
222
|
for entry in walkdir::WalkDir::new(resource_path.join("fonts")) {
|
|
217
223
|
let path = entry
|
|
218
|
-
.map_err(|err| magnus::Error::new(
|
|
224
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?
|
|
219
225
|
.into_path();
|
|
220
226
|
let Some(extension) = path.extension() else {
|
|
221
227
|
continue;
|
|
@@ -234,16 +240,46 @@ fn to_pdf(
|
|
|
234
240
|
.font_paths(font_paths)
|
|
235
241
|
.ignore_system_fonts(ignore_system_fonts)
|
|
236
242
|
.build()
|
|
237
|
-
.map_err(|msg| magnus::Error::new(
|
|
243
|
+
.map_err(|msg| magnus::Error::new(ruby.exception_arg_error(), msg.to_string()))?;
|
|
244
|
+
|
|
245
|
+
let pdf_standards_lookup: HashMap::<&str, PdfStandard> = HashMap::from([
|
|
246
|
+
("1.4", PdfStandard::V_1_4),
|
|
247
|
+
("1.5", PdfStandard::V_1_5),
|
|
248
|
+
("1.6", PdfStandard::V_1_6),
|
|
249
|
+
("1.7", PdfStandard::V_1_7),
|
|
250
|
+
("2.0", PdfStandard::V_2_0),
|
|
251
|
+
("a-1a", PdfStandard::A_1a),
|
|
252
|
+
("a-1b", PdfStandard::A_1b),
|
|
253
|
+
("a-2a", PdfStandard::A_2a),
|
|
254
|
+
("a-2b", PdfStandard::A_2b),
|
|
255
|
+
("a-2u", PdfStandard::A_2u),
|
|
256
|
+
("a-3a", PdfStandard::A_3a),
|
|
257
|
+
("a-3b", PdfStandard::A_3b),
|
|
258
|
+
("a-3u", PdfStandard::A_3u),
|
|
259
|
+
("a-4", PdfStandard::A_4),
|
|
260
|
+
("a-4e", PdfStandard::A_4e),
|
|
261
|
+
("a-4f", PdfStandard::A_4f),
|
|
262
|
+
("ua-1", PdfStandard::Ua_1),
|
|
263
|
+
]);
|
|
264
|
+
|
|
265
|
+
let mut pdf_standards_vec = Vec::<PdfStandard>::new();
|
|
266
|
+
for pdf_standard in pdf_standards.iter() {
|
|
267
|
+
let result = pdf_standards_lookup.get(pdf_standard.as_str());
|
|
268
|
+
match result {
|
|
269
|
+
Some(value) => pdf_standards_vec.push(*value),
|
|
270
|
+
_ => return Err(magnus::Error::new(ruby.exception_arg_error(), "Unknown PdfStandard")),
|
|
271
|
+
}
|
|
272
|
+
}
|
|
238
273
|
|
|
239
274
|
let pdf_bytes = world
|
|
240
|
-
.compile(Some("pdf"), None, &
|
|
241
|
-
.map_err(|msg| magnus::Error::new(
|
|
275
|
+
.compile(Some("pdf"), None, &pdf_standards_vec)
|
|
276
|
+
.map_err(|msg| magnus::Error::new(ruby.exception_arg_error(), msg.to_string()))?;
|
|
242
277
|
|
|
243
278
|
Ok(pdf_bytes)
|
|
244
279
|
}
|
|
245
280
|
|
|
246
281
|
fn query(
|
|
282
|
+
ruby: &Ruby,
|
|
247
283
|
selector: String,
|
|
248
284
|
field: Option<String>,
|
|
249
285
|
one: bool,
|
|
@@ -258,15 +294,15 @@ fn query(
|
|
|
258
294
|
let format = match format.unwrap().to_ascii_lowercase().as_str() {
|
|
259
295
|
"json" => SerializationFormat::Json,
|
|
260
296
|
"yaml" => SerializationFormat::Yaml,
|
|
261
|
-
_ => return Err(magnus::Error::new(
|
|
297
|
+
_ => return Err(magnus::Error::new(ruby.exception_arg_error(), "unsupported serialization format"))?,
|
|
262
298
|
};
|
|
263
299
|
|
|
264
300
|
let input = input.canonicalize()
|
|
265
|
-
.map_err(|err| magnus::Error::new(
|
|
301
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?;
|
|
266
302
|
|
|
267
303
|
let root = if let Some(root) = root {
|
|
268
304
|
root.canonicalize()
|
|
269
|
-
.map_err(|err| magnus::Error::new(
|
|
305
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?
|
|
270
306
|
} else if let Some(dir) = input.parent() {
|
|
271
307
|
dir.into()
|
|
272
308
|
} else {
|
|
@@ -274,12 +310,12 @@ fn query(
|
|
|
274
310
|
};
|
|
275
311
|
|
|
276
312
|
let resource_path = resource_path.canonicalize()
|
|
277
|
-
.map_err(|err| magnus::Error::new(
|
|
313
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?;
|
|
278
314
|
|
|
279
315
|
let mut default_fonts = Vec::new();
|
|
280
316
|
for entry in walkdir::WalkDir::new(resource_path.join("fonts")) {
|
|
281
317
|
let path = entry
|
|
282
|
-
.map_err(|err| magnus::Error::new(
|
|
318
|
+
.map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?
|
|
283
319
|
.into_path();
|
|
284
320
|
let Some(extension) = path.extension() else {
|
|
285
321
|
continue;
|
|
@@ -298,7 +334,7 @@ fn query(
|
|
|
298
334
|
.font_paths(font_paths)
|
|
299
335
|
.ignore_system_fonts(ignore_system_fonts)
|
|
300
336
|
.build()
|
|
301
|
-
.map_err(|msg| magnus::Error::new(
|
|
337
|
+
.map_err(|msg| magnus::Error::new(ruby.exception_arg_error(), msg.to_string()))?;
|
|
302
338
|
|
|
303
339
|
let result = typst_query(
|
|
304
340
|
&mut world,
|
|
@@ -312,19 +348,24 @@ fn query(
|
|
|
312
348
|
|
|
313
349
|
match result {
|
|
314
350
|
Ok(data) => Ok(data),
|
|
315
|
-
Err(msg) => Err(magnus::Error::new(
|
|
351
|
+
Err(msg) => Err(magnus::Error::new(ruby.exception_arg_error(), msg.to_string())),
|
|
316
352
|
}
|
|
317
353
|
}
|
|
318
354
|
|
|
355
|
+
fn clear_cache(_ruby: &Ruby, max_age: usize) {
|
|
356
|
+
comemo::evict(max_age);
|
|
357
|
+
}
|
|
358
|
+
|
|
319
359
|
#[magnus::init]
|
|
320
|
-
fn init() -> Result<(), Error> {
|
|
360
|
+
fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
321
361
|
env_logger::init();
|
|
322
362
|
|
|
323
|
-
let module = define_module("Typst")?;
|
|
324
|
-
module.define_singleton_method("_to_pdf", function!(to_pdf,
|
|
363
|
+
let module = ruby.define_module("Typst")?;
|
|
364
|
+
module.define_singleton_method("_to_pdf", function!(to_pdf, 7))?;
|
|
325
365
|
module.define_singleton_method("_to_svg", function!(to_svg, 6))?;
|
|
326
|
-
module.define_singleton_method("_to_png", function!(to_png,
|
|
366
|
+
module.define_singleton_method("_to_png", function!(to_png, 7))?;
|
|
327
367
|
module.define_singleton_method("_to_html", function!(to_html, 6))?;
|
|
328
368
|
module.define_singleton_method("_query", function!(query, 10))?;
|
|
369
|
+
module.define_singleton_method("_clear_cache", function!(clear_cache, 1))?;
|
|
329
370
|
Ok(())
|
|
330
371
|
}
|
data/ext/typst/src/query.rs
CHANGED
data/ext/typst/src/world.rs
CHANGED
|
@@ -3,7 +3,6 @@ use std::path::{Path, PathBuf};
|
|
|
3
3
|
use std::sync::{Mutex, OnceLock};
|
|
4
4
|
|
|
5
5
|
use chrono::{DateTime, Datelike, Local};
|
|
6
|
-
//use rustc_hash::FxHashMap;
|
|
7
6
|
use ecow::eco_format;
|
|
8
7
|
use typst::diag::{FileError, FileResult, StrResult};
|
|
9
8
|
use typst::foundations::{Bytes, Datetime, Dict};
|
data/lib/base.rb
CHANGED
|
@@ -34,74 +34,44 @@ module Typst
|
|
|
34
34
|
options[:dependencies] ||= {}
|
|
35
35
|
options[:fonts] ||= {}
|
|
36
36
|
options[:sys_inputs] ||= {}
|
|
37
|
+
options[:resource_path] ||= File.dirname(__FILE__)
|
|
38
|
+
options[:ignore_system_fonts] ||= false
|
|
37
39
|
|
|
38
40
|
self.options = options
|
|
39
41
|
end
|
|
40
42
|
|
|
41
43
|
def typst_args
|
|
42
|
-
[options[:file], options[:root], options[:font_paths],
|
|
44
|
+
[options[:file], options[:root], options[:font_paths], options[:resource_path], options[:ignore_system_fonts], options[:sys_inputs].map{ |k,v| [k.to_s,v.to_s] }.to_h]
|
|
43
45
|
end
|
|
44
46
|
|
|
45
|
-
def
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
Dir.mktmpdir do |tmp_dir|
|
|
50
|
-
tmp_main_file = Pathname.new(tmp_dir).join("main.typ")
|
|
51
|
-
File.write(tmp_main_file, main_source)
|
|
52
|
-
|
|
53
|
-
dependencies.each do |dep_name, dep_source|
|
|
54
|
-
tmp_dep_file = Pathname.new(tmp_dir).join(dep_name)
|
|
55
|
-
File.write(tmp_dep_file, dep_source)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
relative_font_path = Pathname.new(tmp_dir).join("fonts")
|
|
59
|
-
fonts.each do |font_name, font_bytes|
|
|
60
|
-
Pathname.new(relative_font_path).mkpath
|
|
61
|
-
tmp_font_file = relative_font_path.join(font_name)
|
|
62
|
-
File.write(tmp_font_file, font_bytes)
|
|
63
|
-
end
|
|
47
|
+
def typst_pdf_args
|
|
48
|
+
options[:pdf_standards] ||= []
|
|
49
|
+
[*typst_args, options[:pdf_standards]]
|
|
50
|
+
end
|
|
64
51
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
52
|
+
def typst_png_args
|
|
53
|
+
[*typst_args, options[:ppi]]
|
|
54
|
+
end
|
|
68
55
|
|
|
69
|
-
|
|
70
|
-
|
|
56
|
+
def self.from_s(main_source, **options)
|
|
57
|
+
Typst::build_world_from_s(main_source, **options) do |opts|
|
|
58
|
+
from_options = options.merge(opts)
|
|
59
|
+
if from_options[:format]
|
|
60
|
+
Typst::formats[from_options[:format]].new(**from_options)
|
|
71
61
|
else
|
|
72
|
-
new(**
|
|
62
|
+
new(**from_options)
|
|
73
63
|
end
|
|
74
64
|
end
|
|
75
65
|
end
|
|
76
66
|
|
|
77
|
-
def self.from_zip(zip_file_path, main_file =
|
|
78
|
-
options
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
when file_names.include?(main_file) then tmp_main_file = main_file
|
|
85
|
-
when file_names.include?("main.typ") then tmp_main_file = "main.typ"
|
|
86
|
-
when file_names.size == 1 then tmp_main_file = file_names.first
|
|
87
|
-
else raise "no main file found"
|
|
88
|
-
end
|
|
89
|
-
main_source = zipfile.file.read(tmp_main_file)
|
|
90
|
-
file_names.delete(tmp_main_file)
|
|
91
|
-
file_names.delete("fonts/")
|
|
92
|
-
|
|
93
|
-
file_names.each do |dep_name|
|
|
94
|
-
options[:dependencies][dep_name] = zipfile.file.read(dep_name)
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
font_file_names = zipfile.dir.glob("fonts/*").collect{ |f| f.name }
|
|
98
|
-
font_file_names.each do |font_name|
|
|
99
|
-
options[:fonts][Pathname.new(font_name).basename.to_s] = zipfile.file.read(font_name)
|
|
67
|
+
def self.from_zip(zip_file_path, main_file = "main.typ", **options)
|
|
68
|
+
Typst::build_world_from_zip(zip_file_path, main_file, **options) do |opts|
|
|
69
|
+
from_options = options.merge(opts)
|
|
70
|
+
if from_options[:format]
|
|
71
|
+
Typst::formats[from_options[:format]].new(**from_options)
|
|
72
|
+
else
|
|
73
|
+
new(**from_options)
|
|
100
74
|
end
|
|
101
|
-
|
|
102
|
-
options[:main_file] = tmp_main_file
|
|
103
|
-
|
|
104
|
-
from_s(main_source, **options)
|
|
105
75
|
end
|
|
106
76
|
end
|
|
107
77
|
|
|
@@ -138,32 +108,35 @@ module Typst
|
|
|
138
108
|
if options.has_key?(:file)
|
|
139
109
|
Typst::formats[format].new(**options).compiled
|
|
140
110
|
elsif options.has_key?(:body)
|
|
141
|
-
Typst::
|
|
111
|
+
Typst::build_world_from_s(self.options[:body], **options) do |opts|
|
|
112
|
+
Typst::formats[format].new(**options.merge(opts)).compiled
|
|
113
|
+
end
|
|
142
114
|
elsif options.has_key?(:zip)
|
|
143
|
-
|
|
115
|
+
main_file = options[:main_file]
|
|
116
|
+
Typst::build_world_from_zip(options[:zip], main_file, **options) do |opts|
|
|
117
|
+
Typst::formats[format].new(**options.merge(opts)).compiled
|
|
118
|
+
end
|
|
144
119
|
else
|
|
145
120
|
raise "No input given"
|
|
146
121
|
end
|
|
147
122
|
end
|
|
148
123
|
|
|
149
|
-
def
|
|
150
|
-
|
|
151
|
-
compiled.write(output)
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
def document
|
|
155
|
-
STDERR.puts "DEPRECATION WARNING: this method will go away in a future version"
|
|
156
|
-
compiled.document
|
|
157
|
-
end
|
|
124
|
+
def query(selector, field: nil, one: false, format: "json")
|
|
125
|
+
query_options = { field: field, one: one, format: format }
|
|
158
126
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
127
|
+
if self.options.has_key?(:file)
|
|
128
|
+
Typst::Query.new(selector, self.options[:file], **query_options.merge(self.options.slice(:root, :font_paths, :resource_path, :ignore_system_fonts, :sys_inputs)))
|
|
129
|
+
elsif self.options.has_key?(:body)
|
|
130
|
+
Typst::build_world_from_s(self.options[:body], **self.options) do |opts|
|
|
131
|
+
Typst::Query.new(selector, opts[:file], **query_options.merge(opts.slice(:root, :font_paths, :resource_path, :ignore_system_fonts, :sys_inputs)))
|
|
132
|
+
end
|
|
133
|
+
elsif self.options.has_key?(:zip)
|
|
134
|
+
Typst::build_world_from_zip(self.options[:zip], **self.options) do |opts|
|
|
135
|
+
Typst::Query.new(selector, opts[:file], **query_options.merge(opts.slice(:root, :font_paths, :resource_path, :ignore_system_fonts, :sys_inputs)))
|
|
136
|
+
end
|
|
137
|
+
else
|
|
138
|
+
raise "No input given"
|
|
139
|
+
end
|
|
167
140
|
end
|
|
168
141
|
end
|
|
169
142
|
end
|
data/lib/document.rb
CHANGED
|
@@ -6,15 +6,23 @@ module Typst
|
|
|
6
6
|
@bytes = bytes
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def
|
|
9
|
+
def write_some(filename)
|
|
10
10
|
if pages.size == 1
|
|
11
|
-
|
|
11
|
+
write_one(filename)
|
|
12
12
|
else
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
write_paged(filename)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def write_one(filename)
|
|
18
|
+
File.write(filename, pages.first, mode: "wb")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def write_paged(base_filename)
|
|
22
|
+
pages.each_with_index do |page, i|
|
|
23
|
+
paged_filename = File.basename(base_filename, ".*") + "_{{n}}" + File.extname(base_filename) unless base_filename.include?("{{n}}")
|
|
24
|
+
paged_filename = paged_filename.gsub("{{n}}", (i+1).to_s)
|
|
25
|
+
File.write(paged_filename, page, mode: "wb")
|
|
18
26
|
end
|
|
19
27
|
end
|
|
20
28
|
|
|
@@ -5,7 +5,9 @@ module Typst
|
|
|
5
5
|
@compiled = HtmlExperimentalDocument.new(Typst::_to_html(*self.typst_args))
|
|
6
6
|
end
|
|
7
7
|
end
|
|
8
|
-
class HtmlExperimentalDocument < Document
|
|
8
|
+
class HtmlExperimentalDocument < Document
|
|
9
|
+
alias_method :write, :write_one
|
|
10
|
+
end
|
|
9
11
|
|
|
10
12
|
register_format(html_experimental: HtmlExperimental)
|
|
11
13
|
end
|
data/lib/formats/pdf.rb
CHANGED
|
@@ -2,10 +2,12 @@ module Typst
|
|
|
2
2
|
class Pdf < Base
|
|
3
3
|
def initialize(*options)
|
|
4
4
|
super(*options)
|
|
5
|
-
@compiled = PdfDocument.new(Typst::_to_pdf(*self.
|
|
5
|
+
@compiled = PdfDocument.new(Typst::_to_pdf(*self.typst_pdf_args))
|
|
6
6
|
end
|
|
7
7
|
end
|
|
8
|
-
class PdfDocument < Document
|
|
8
|
+
class PdfDocument < Document
|
|
9
|
+
alias_method :write, :write_one
|
|
10
|
+
end
|
|
9
11
|
|
|
10
12
|
register_format(pdf: Pdf)
|
|
11
13
|
end
|
data/lib/formats/png.rb
CHANGED
|
@@ -2,10 +2,12 @@ module Typst
|
|
|
2
2
|
class Png < Base
|
|
3
3
|
def initialize(*options)
|
|
4
4
|
super(*options)
|
|
5
|
-
@compiled = PngDocument.new(Typst::_to_png(*self.
|
|
5
|
+
@compiled = PngDocument.new(Typst::_to_png(*self.typst_png_args))
|
|
6
6
|
end
|
|
7
7
|
end
|
|
8
|
-
class PngDocument < Document
|
|
8
|
+
class PngDocument < Document
|
|
9
|
+
alias_method :write, :write_some
|
|
10
|
+
end
|
|
9
11
|
|
|
10
12
|
register_format(png: Png)
|
|
11
13
|
end
|
data/lib/formats/svg.rb
CHANGED
data/lib/query.rb
CHANGED
|
@@ -2,10 +2,9 @@ module Typst
|
|
|
2
2
|
class Query < Base
|
|
3
3
|
attr_accessor :format
|
|
4
4
|
|
|
5
|
-
def initialize(selector, input, field: nil, one: false, format: "json", root: ".", font_paths: [], sys_inputs: {})
|
|
6
|
-
super(input, root: root, font_paths: font_paths, sys_inputs: sys_inputs)
|
|
5
|
+
def initialize(selector, input, field: nil, one: false, format: "json", root: ".", font_paths: [], resource_path: ".", ignore_system_fonts: false, sys_inputs: {})
|
|
7
6
|
self.format = format
|
|
8
|
-
@result = Typst::_query(selector, field, one, format, input, root, font_paths,
|
|
7
|
+
@result = Typst::_query(selector, field, one, format, input, root, font_paths, resource_path, ignore_system_fonts, sys_inputs)
|
|
9
8
|
end
|
|
10
9
|
|
|
11
10
|
def result(raw: false)
|
|
@@ -15,5 +14,9 @@ module Typst
|
|
|
15
14
|
else @result
|
|
16
15
|
end
|
|
17
16
|
end
|
|
17
|
+
|
|
18
|
+
def to_s
|
|
19
|
+
@result
|
|
20
|
+
end
|
|
18
21
|
end
|
|
19
22
|
end
|
data/lib/typst.rb
CHANGED
|
@@ -12,19 +12,83 @@ module Typst
|
|
|
12
12
|
def self.formats
|
|
13
13
|
@@formats
|
|
14
14
|
end
|
|
15
|
-
end
|
|
16
15
|
|
|
16
|
+
def self.clear_cache(max_age = 0)
|
|
17
|
+
Typst::_clear_cache(max_age)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.build_world_from_s(main_source, **options, &blk)
|
|
21
|
+
dependencies = options[:dependencies] ||= {}
|
|
22
|
+
fonts = options[:fonts] ||= {}
|
|
23
|
+
|
|
24
|
+
Dir.mktmpdir do |tmp_dir|
|
|
25
|
+
tmp_main_file = Pathname.new(tmp_dir).join("main.typ")
|
|
26
|
+
File.write(tmp_main_file, main_source)
|
|
27
|
+
|
|
28
|
+
dependencies.each do |dep_name, dep_source|
|
|
29
|
+
tmp_dep_file = Pathname.new(tmp_dir).join(dep_name)
|
|
30
|
+
File.write(tmp_dep_file, dep_source)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
relative_font_path = Pathname.new(tmp_dir).join("fonts")
|
|
34
|
+
relative_font_path.mkpath
|
|
35
|
+
fonts.each do |font_name, font_bytes|
|
|
36
|
+
tmp_font_file = relative_font_path.join(font_name)
|
|
37
|
+
File.write(tmp_font_file, font_bytes)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
options[:file] = tmp_main_file
|
|
41
|
+
options[:root] = tmp_dir
|
|
42
|
+
options[:font_paths] = [relative_font_path]
|
|
43
|
+
|
|
44
|
+
blk.call(options)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.build_world_from_zip(zip_file_path, main_file = "main.typ", **options, &blk)
|
|
49
|
+
options[:dependencies] ||= {}
|
|
50
|
+
options[:fonts] ||= {}
|
|
51
|
+
|
|
52
|
+
Zip::File.open(zip_file_path) do |zipfile|
|
|
53
|
+
file_names = zipfile.dir.glob("*").collect{ |f| f.name }
|
|
54
|
+
case
|
|
55
|
+
when file_names.include?(main_file) then tmp_main_file = main_file
|
|
56
|
+
when file_names.include?("main.typ") then tmp_main_file = "main.typ"
|
|
57
|
+
when file_names.size == 1 then tmp_main_file = file_names.first
|
|
58
|
+
else raise "no main file found"
|
|
59
|
+
end
|
|
60
|
+
main_source = zipfile.file.read(tmp_main_file)
|
|
61
|
+
file_names.delete(tmp_main_file)
|
|
62
|
+
file_names.delete("fonts/")
|
|
63
|
+
|
|
64
|
+
file_names.each do |dep_name|
|
|
65
|
+
options[:dependencies][dep_name] = zipfile.file.read(dep_name)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
font_file_names = zipfile.dir.glob("fonts/*").collect{ |f| f.name }
|
|
69
|
+
font_file_names.each do |font_name|
|
|
70
|
+
options[:fonts][Pathname.new(font_name).basename.to_s] = zipfile.file.read(font_name)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
options[:main_file] = tmp_main_file
|
|
74
|
+
|
|
75
|
+
build_world_from_s(main_source, **options, &blk)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
17
79
|
|
|
18
|
-
require "cgi"
|
|
80
|
+
require "cgi/escape"
|
|
19
81
|
require "pathname"
|
|
20
82
|
require "tmpdir"
|
|
21
83
|
require "zip/filesystem"
|
|
84
|
+
require "json"
|
|
85
|
+
require "yaml"
|
|
22
86
|
|
|
23
87
|
begin
|
|
24
88
|
# native precompiled gems package shared libraries in <gem_dir>/lib/typst/<ruby_version>
|
|
25
89
|
RUBY_VERSION =~ /(\d+\.\d+)/
|
|
26
90
|
require_relative "typst/#{Regexp.last_match(1)}/typst"
|
|
27
|
-
rescue LoadError
|
|
91
|
+
rescue LoadError
|
|
28
92
|
require_relative "typst/typst"
|
|
29
93
|
end
|
|
30
94
|
|
|
@@ -34,5 +98,4 @@ require_relative "document"
|
|
|
34
98
|
require_relative "formats/pdf"
|
|
35
99
|
require_relative "formats/svg"
|
|
36
100
|
require_relative "formats/png"
|
|
37
|
-
require_relative "formats/html"
|
|
38
101
|
require_relative "formats/html_experimental"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: typst
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.14.2
|
|
4
|
+
version: 0.14.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Flinn
|
|
@@ -18,7 +18,7 @@ dependencies:
|
|
|
18
18
|
version: '0.9'
|
|
19
19
|
- - ">="
|
|
20
20
|
- !ruby/object:Gem::Version
|
|
21
|
-
version: 0.9.
|
|
21
|
+
version: 0.9.124
|
|
22
22
|
type: :runtime
|
|
23
23
|
prerelease: false
|
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -28,7 +28,7 @@ dependencies:
|
|
|
28
28
|
version: '0.9'
|
|
29
29
|
- - ">="
|
|
30
30
|
- !ruby/object:Gem::Version
|
|
31
|
-
version: 0.9.
|
|
31
|
+
version: 0.9.124
|
|
32
32
|
- !ruby/object:Gem::Dependency
|
|
33
33
|
name: rubyzip
|
|
34
34
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -71,6 +71,34 @@ dependencies:
|
|
|
71
71
|
- - "~>"
|
|
72
72
|
- !ruby/object:Gem::Version
|
|
73
73
|
version: '3.6'
|
|
74
|
+
- !ruby/object:Gem::Dependency
|
|
75
|
+
name: os
|
|
76
|
+
requirement: !ruby/object:Gem::Requirement
|
|
77
|
+
requirements:
|
|
78
|
+
- - "~>"
|
|
79
|
+
- !ruby/object:Gem::Version
|
|
80
|
+
version: '1.1'
|
|
81
|
+
type: :development
|
|
82
|
+
prerelease: false
|
|
83
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
84
|
+
requirements:
|
|
85
|
+
- - "~>"
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
version: '1.1'
|
|
88
|
+
- !ruby/object:Gem::Dependency
|
|
89
|
+
name: pngcheck
|
|
90
|
+
requirement: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - "~>"
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: '0.3'
|
|
95
|
+
type: :development
|
|
96
|
+
prerelease: false
|
|
97
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
98
|
+
requirements:
|
|
99
|
+
- - "~>"
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '0.3'
|
|
74
102
|
email: flinn@actsasflinn.com
|
|
75
103
|
executables: []
|
|
76
104
|
extensions:
|
|
@@ -106,15 +134,12 @@ files:
|
|
|
106
134
|
- lib/fonts/NewCM10-Regular.otf
|
|
107
135
|
- lib/fonts/NewCMMath-Book.otf
|
|
108
136
|
- lib/fonts/NewCMMath-Regular.otf
|
|
109
|
-
- lib/formats/html.rb
|
|
110
137
|
- lib/formats/html_experimental.rb
|
|
111
138
|
- lib/formats/pdf.rb
|
|
112
139
|
- lib/formats/png.rb
|
|
113
140
|
- lib/formats/svg.rb
|
|
114
141
|
- lib/query.rb
|
|
115
142
|
- lib/typst.rb
|
|
116
|
-
- lib/typst/typst.bundle
|
|
117
|
-
- lib/typst/typst.so
|
|
118
143
|
homepage: https://github.com/actsasflinn/typst-rb
|
|
119
144
|
licenses:
|
|
120
145
|
- Apache-2.0
|
|
@@ -133,7 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
133
158
|
- !ruby/object:Gem::Version
|
|
134
159
|
version: '0'
|
|
135
160
|
requirements: []
|
|
136
|
-
rubygems_version:
|
|
161
|
+
rubygems_version: 4.0.3
|
|
137
162
|
specification_version: 4
|
|
138
163
|
summary: Ruby binding to typst, a new markup-based typesetting system that is powerful
|
|
139
164
|
and easy to learn.
|
data/lib/formats/html.rb
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
module Typst
|
|
2
|
-
class Html < Base
|
|
3
|
-
def initialize(*options)
|
|
4
|
-
super(*options)
|
|
5
|
-
title = CGI::escapeHTML(@options[:title] || File.basename(@options[:file], ".*"))
|
|
6
|
-
@compiled = HtmlDocument.new(Typst::_to_svg(*self.typst_args), title)
|
|
7
|
-
end
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
class HtmlDocument < Document
|
|
11
|
-
attr_accessor :title
|
|
12
|
-
|
|
13
|
-
def initialize(bytes, title)
|
|
14
|
-
super(bytes)
|
|
15
|
-
self.title = title
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def markup
|
|
19
|
-
%{
|
|
20
|
-
<!DOCTYPE html>
|
|
21
|
-
<html>
|
|
22
|
-
<head>
|
|
23
|
-
<title>#{title}</title>
|
|
24
|
-
</head>
|
|
25
|
-
<body>
|
|
26
|
-
#{pages.join("<br />")}
|
|
27
|
-
</body>
|
|
28
|
-
</html>
|
|
29
|
-
}
|
|
30
|
-
end
|
|
31
|
-
alias_method :document, :markup
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
register_format(html: Html)
|
|
35
|
-
end
|
data/lib/typst/typst.bundle
DELETED
|
Binary file
|
data/lib/typst/typst.so
DELETED
|
Binary file
|