typst 0.13.2 → 0.13.3
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 +57 -55
- data/README.typ +57 -45
- data/lib/base.rb +169 -0
- data/lib/document.rb +29 -0
- data/lib/formats/html.rb +35 -0
- data/lib/formats/html_experimental.rb +11 -0
- data/lib/formats/pdf.rb +11 -0
- data/lib/formats/png.rb +11 -0
- data/lib/formats/svg.rb +11 -0
- data/lib/query.rb +19 -0
- data/lib/typst.rb +22 -194
- metadata +9 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: efba2668a9abea7b8c3679ce34f67d35c29737f1c2c3afd88c8542b7609ec4e8
|
4
|
+
data.tar.gz: 285d1408b40eafc2237089c7b5bfcd32196f832ce4b1e05e5175a2cde5558ae8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c15d656ce6673c9e1c8d67f5743c8c13a1ea3e8a960d93271f27ec8a4e41144f505593f37ec81bf97a7f608b123a7fa57fbac4aada94a5bdc2b06369eb09f607
|
7
|
+
data.tar.gz: 9c080fa1092d04481e1a78c99e871d53af7138025a0586d2993bb9d8f43167f7eee2c742d266478011172d4a62150e6589723c191080bdc2daedfec20be1dd70
|
data/README.md
CHANGED
@@ -14,59 +14,75 @@ gem install typst
|
|
14
14
|
```ruby
|
15
15
|
require "typst"
|
16
16
|
|
17
|
-
# Compile
|
18
|
-
Typst
|
17
|
+
# Compile a typst file and write the output to a PDF file
|
18
|
+
Typst("readme.typ").compile(:pdf).write("readme.pdf")
|
19
19
|
|
20
|
-
#
|
21
|
-
|
22
|
-
# => [37, 80, 68, 70, 45, 49, 46, 55, 10, 37, 128 ...]
|
20
|
+
# Use a typst file `readme.typ`
|
21
|
+
t = Typst("readme.typ")
|
23
22
|
|
24
|
-
#
|
25
|
-
|
26
|
-
# => "%PDF-1.7\n%\x80\x80\x80\x80\n\n4 0 obj\n<<\n /Type /Font\n /Subtype ..."
|
23
|
+
# Use a typst string
|
24
|
+
t = Typst(body: %{hello world})
|
27
25
|
|
28
|
-
#
|
29
|
-
Typst
|
26
|
+
# Use a typst file in a zip file
|
27
|
+
t = Typst(zip: "test/main.typ.zip")
|
30
28
|
|
31
|
-
#
|
32
|
-
|
33
|
-
# => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
|
29
|
+
# Compile to PDF
|
30
|
+
f = t.compile(:pdf)
|
34
31
|
|
35
|
-
# Compile
|
36
|
-
|
32
|
+
# Compile to SVG
|
33
|
+
f = t.compile(:svg)
|
37
34
|
|
38
|
-
#
|
39
|
-
|
40
|
-
# => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...
|
35
|
+
# Compile to PNG
|
36
|
+
f = t.compile(:png)
|
41
37
|
|
42
|
-
# Compile
|
43
|
-
|
38
|
+
# Compile to SVGs enveloped in HTML
|
39
|
+
# Depracation warning: this feature will go away once Typst HTML moves out of experimental
|
40
|
+
f = t.compile(:html, title: "Typst+Ruby")
|
44
41
|
|
45
|
-
#
|
46
|
-
|
47
|
-
# => "\n<!DOCTYPE html>\n<html>\n<head>\n<title>README</title>\n</head>\n<bo..."
|
42
|
+
# Compile to HTML (using Typst expirmental HTML)
|
43
|
+
f = t.compile(:html_experimental)
|
48
44
|
|
49
|
-
#
|
50
|
-
|
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\" ...
|
51
|
+
|
52
|
+
# Or return content as an array of bytes
|
53
|
+
pdf_bytes = Typst("readme.typ").compile(:pdf).bytes
|
54
|
+
# => [37, 80, 68, 70, 45, 49, 46, 55, 10, 37, 128 ...]
|
51
55
|
|
52
|
-
#
|
53
|
-
|
54
|
-
|
56
|
+
# 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
|
+
f.write("filename.pdf")
|
55
59
|
|
56
|
-
#
|
57
|
-
|
60
|
+
# Return SVG, HTML or PNG content as an array of pages
|
61
|
+
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\" ..."
|
65
|
+
Typst("readme.typ").compile(:png).pages
|
66
|
+
# => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...
|
58
67
|
|
59
|
-
#
|
60
|
-
|
68
|
+
# Pass values into typst using sys_inputs
|
69
|
+
sys_inputs_example = %{
|
70
|
+
#let persons = json(bytes(sys.inputs.persons))
|
61
71
|
|
62
|
-
#
|
63
|
-
|
72
|
+
#for person in persons [
|
73
|
+
#person.name is #person.age years old.\\
|
74
|
+
]
|
75
|
+
}
|
76
|
+
people = [{"name" => "John", "age" => 35}, {"name" => "Xoliswa", "age" => 45}]
|
77
|
+
data = { "persons" => people.to_json }
|
78
|
+
Typst(body: sys_inputs_example, sys_inputs: data).compile(:pdf).write("sys_inputs_example.pdf")
|
64
79
|
|
65
|
-
#
|
66
|
-
t = Typst::Html.from_s(%{hello world})
|
80
|
+
# Apply inputs to typst to product multiple PDFs
|
67
81
|
|
68
|
-
|
69
|
-
|
82
|
+
t = Typst(body: sys_inputs_example)
|
83
|
+
people.each do |person|
|
84
|
+
t.with_inputs({ "persons" => [person].to_json }).compile(:pdf).write("#{person['name']}.pdf")
|
85
|
+
end
|
70
86
|
|
71
87
|
# A more complex example of compiling from string
|
72
88
|
main = %{
|
@@ -89,24 +105,10 @@ template = %{
|
|
89
105
|
icon = File.read("icon.svg")
|
90
106
|
font_bytes = File.read("Example.ttf")
|
91
107
|
|
92
|
-
|
93
|
-
|
94
|
-
# Pass values into a typst template using sys_inputs
|
95
|
-
sys_inputs_example = %{
|
96
|
-
#let persons = json(bytes(sys.inputs.persons))
|
97
|
-
|
98
|
-
#for person in persons [
|
99
|
-
#person.name is #person.age years old.\\
|
100
|
-
]
|
101
|
-
}
|
102
|
-
Typst::Pdf.from_s(sys_inputs_example, sys_inputs: { "persons" => [{"name": "John", "age": 35}, {"name": "Xoliswa", "age": 45}].to_json }).write("sys_inputs_example.pdf")
|
103
|
-
|
104
|
-
# From a zip file that includes a main.typ
|
105
|
-
# zip file include flat dependencies included and a fonts directory
|
106
|
-
Typst::Pdf::from_zip("working_directory.zip")
|
107
|
-
|
108
|
+
Typst(body: main, dependencies: { "template.typ" => template, "icon.svg" => icon }, fonts: { "Example.ttf" => font_bytes }).compile(:pdf)
|
109
|
+
|
108
110
|
# From a zip with a named main typst file
|
109
|
-
Typst
|
111
|
+
Typst(zip: "test/main.typ.zip", main_file: "hello.typ").compile(:pdf)
|
110
112
|
|
111
113
|
Typst::Query.new("heading", "readme.typ").result
|
112
114
|
# =>
|
data/README.typ
CHANGED
@@ -17,59 +17,75 @@ gem install typst
|
|
17
17
|
```ruby
|
18
18
|
require "typst"
|
19
19
|
|
20
|
-
# Compile
|
21
|
-
Typst
|
20
|
+
# Compile a typst file and write the output to a PDF file
|
21
|
+
Typst("readme.typ").compile(:pdf).write("readme.pdf")
|
22
22
|
|
23
|
-
#
|
24
|
-
|
25
|
-
# => [37, 80, 68, 70, 45, 49, 46, 55, 10, 37, 128 ...]
|
23
|
+
# Use a typst file `readme.typ`
|
24
|
+
t = Typst("readme.typ")
|
26
25
|
|
27
|
-
#
|
28
|
-
|
29
|
-
# => "%PDF-1.7\n%\x80\x80\x80\x80\n\n4 0 obj\n<<\n /Type /Font\n /Subtype ..."
|
26
|
+
# Use a typst string
|
27
|
+
t = Typst(body: %{hello world})
|
30
28
|
|
31
|
-
#
|
32
|
-
Typst
|
29
|
+
# Use a typst file in a zip file
|
30
|
+
t = Typst(zip: "test/main.typ.zip")
|
33
31
|
|
34
|
-
#
|
35
|
-
|
36
|
-
# => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
|
32
|
+
# Compile to PDF
|
33
|
+
f = t.compile(:pdf)
|
37
34
|
|
38
|
-
# Compile
|
39
|
-
|
35
|
+
# Compile to SVG
|
36
|
+
f = t.compile(:svg)
|
40
37
|
|
41
|
-
#
|
42
|
-
|
43
|
-
# => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...
|
38
|
+
# Compile to PNG
|
39
|
+
f = t.compile(:png)
|
44
40
|
|
45
|
-
# Compile
|
46
|
-
|
41
|
+
# Compile to SVGs enveloped in HTML
|
42
|
+
# Depracation warning: this feature will go away once Typst HTML moves out of experimental
|
43
|
+
f = t.compile(:html, title: "Typst+Ruby")
|
47
44
|
|
48
|
-
#
|
49
|
-
|
50
|
-
# => "\n<!DOCTYPE html>\n<html>\n<head>\n<title>README</title>\n</head>\n<bo..."
|
45
|
+
# Compile to HTML (using Typst expirmental HTML)
|
46
|
+
f = t.compile(:html_experimental)
|
51
47
|
|
52
|
-
#
|
53
|
-
|
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\" ...
|
54
54
|
|
55
|
-
# Or return
|
56
|
-
|
57
|
-
# =>
|
55
|
+
# Or return content as an array of bytes
|
56
|
+
pdf_bytes = Typst("readme.typ").compile(:pdf).bytes
|
57
|
+
# => [37, 80, 68, 70, 45, 49, 46, 55, 10, 37, 128 ...]
|
58
58
|
|
59
|
-
#
|
60
|
-
|
59
|
+
# 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
|
+
f.write("filename.pdf")
|
61
62
|
|
62
|
-
#
|
63
|
-
|
63
|
+
# Return SVG, HTML or PNG content as an array of pages
|
64
|
+
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\" ..."
|
68
|
+
Typst("readme.typ").compile(:png).pages
|
69
|
+
# => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...
|
70
|
+
|
71
|
+
# Pass values into typst using sys_inputs
|
72
|
+
sys_inputs_example = %{
|
73
|
+
#let persons = json(bytes(sys.inputs.persons))
|
64
74
|
|
65
|
-
#
|
66
|
-
|
75
|
+
#for person in persons [
|
76
|
+
#person.name is #person.age years old.\\
|
77
|
+
]
|
78
|
+
}
|
79
|
+
people = [{"name" => "John", "age" => 35}, {"name" => "Xoliswa", "age" => 45}]
|
80
|
+
data = { "persons" => people.to_json }
|
81
|
+
Typst(body: sys_inputs_example, sys_inputs: data).compile(:pdf).write("sys_inputs_example.pdf")
|
67
82
|
|
68
|
-
#
|
69
|
-
t = Typst::Html.from_s(%{hello world})
|
83
|
+
# Apply inputs to typst to product multiple PDFs
|
70
84
|
|
71
|
-
|
72
|
-
|
85
|
+
t = Typst(body: sys_inputs_example)
|
86
|
+
people.each do |person|
|
87
|
+
t.with_inputs({ "persons" => [person].to_json }).compile(:pdf).write("#{person['name']}.pdf")
|
88
|
+
end
|
73
89
|
|
74
90
|
# A more complex example of compiling from string
|
75
91
|
main = %{
|
@@ -92,14 +108,10 @@ template = %{
|
|
92
108
|
icon = File.read("icon.svg")
|
93
109
|
font_bytes = File.read("Example.ttf")
|
94
110
|
|
95
|
-
|
96
|
-
|
97
|
-
# From a zip file that includes a main.typ
|
98
|
-
# zip file include flat dependencies included and a fonts directory
|
99
|
-
Typst::Pdf::from_zip("working_directory.zip")
|
100
|
-
|
111
|
+
Typst(body: main, dependencies: { "template.typ" => template, "icon.svg" => icon }, fonts: { "Example.ttf" => font_bytes }).compile(:pdf)
|
112
|
+
|
101
113
|
# From a zip with a named main typst file
|
102
|
-
Typst
|
114
|
+
Typst(zip: "test/main.typ.zip", main_file: "hello.typ").compile(:pdf)
|
103
115
|
|
104
116
|
Typst::Query.new("heading", "readme.typ").result
|
105
117
|
# =>
|
data/lib/base.rb
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
module Typst
|
2
|
+
class Base
|
3
|
+
attr_accessor :options
|
4
|
+
attr_accessor :compiled
|
5
|
+
|
6
|
+
def initialize(*options)
|
7
|
+
if options.size.zero?
|
8
|
+
raise "No options given"
|
9
|
+
elsif options.first.is_a?(String)
|
10
|
+
file, options = options
|
11
|
+
options ||= {}
|
12
|
+
options[:file] = file
|
13
|
+
elsif options.first.is_a?(Hash)
|
14
|
+
options = options.first
|
15
|
+
end
|
16
|
+
|
17
|
+
if options.has_key?(:file)
|
18
|
+
raise "Can't find file" unless File.exist?(options[:file])
|
19
|
+
elsif options.has_key?(:body)
|
20
|
+
raise "Empty body" if options[:body].to_s.empty?
|
21
|
+
elsif options.has_key?(:zip)
|
22
|
+
raise "Can't find zip" unless File.exist?(options[:zip])
|
23
|
+
else
|
24
|
+
raise "No input given"
|
25
|
+
end
|
26
|
+
|
27
|
+
root = Pathname.new(options[:root] || ".").expand_path
|
28
|
+
raise "Invalid path for root" unless root.exist?
|
29
|
+
options[:root] = root.to_s
|
30
|
+
|
31
|
+
font_paths = (options[:font_paths] || []).collect{ |fp| Pathname.new(fp).expand_path }
|
32
|
+
options[:font_paths] = font_paths.collect(&:to_s)
|
33
|
+
|
34
|
+
options[:dependencies] ||= {}
|
35
|
+
options[:fonts] ||= {}
|
36
|
+
options[:sys_inputs] ||= {}
|
37
|
+
|
38
|
+
self.options = options
|
39
|
+
end
|
40
|
+
|
41
|
+
def typst_args
|
42
|
+
[options[:file], options[:root], options[:font_paths], File.dirname(__FILE__), false, options[:sys_inputs].map{ |k,v| [k.to_s,v.to_s] }.to_h]
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.from_s(main_source, **options)
|
46
|
+
dependencies = options[:dependencies] ||= {}
|
47
|
+
fonts = options[:fonts] ||= {}
|
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
|
64
|
+
|
65
|
+
options[:file] = tmp_main_file
|
66
|
+
options[:root] = tmp_dir
|
67
|
+
options[:font_paths] = [relative_font_path]
|
68
|
+
|
69
|
+
if options[:format]
|
70
|
+
Typst::formats[options[:format]].new(**options)
|
71
|
+
else
|
72
|
+
new(**options)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.from_zip(zip_file_path, main_file = nil, **options)
|
78
|
+
options[:dependencies] ||= {}
|
79
|
+
options[:fonts] ||= {}
|
80
|
+
|
81
|
+
Zip::File.open(zip_file_path) do |zipfile|
|
82
|
+
file_names = zipfile.dir.glob("*").collect{ |f| f.name }
|
83
|
+
case
|
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)
|
100
|
+
end
|
101
|
+
|
102
|
+
options[:main_file] = tmp_main_file
|
103
|
+
|
104
|
+
from_s(main_source, **options)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def with_dependencies(dependencies)
|
109
|
+
self.options[:dependencies] = self.options[:dependencies].merge(dependencies)
|
110
|
+
self
|
111
|
+
end
|
112
|
+
|
113
|
+
def with_fonts(fonts)
|
114
|
+
self.options[:fonts] = self.options[:fonts].merge(fonts)
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
def with_inputs(inputs)
|
119
|
+
self.options[:sys_inputs] = self.options[:sys_inputs].merge(inputs)
|
120
|
+
self
|
121
|
+
end
|
122
|
+
|
123
|
+
def with_font_paths(font_paths)
|
124
|
+
self.options[:font_paths] = self.options[:font_paths] + font_paths
|
125
|
+
self
|
126
|
+
end
|
127
|
+
|
128
|
+
def with_root(root)
|
129
|
+
self.options[:root] = root
|
130
|
+
self
|
131
|
+
end
|
132
|
+
|
133
|
+
def compile(format, **options)
|
134
|
+
raise "Invalid format" if Typst::formats[format].nil?
|
135
|
+
|
136
|
+
options = self.options.merge(options)
|
137
|
+
|
138
|
+
if options.has_key?(:file)
|
139
|
+
Typst::formats[format].new(**options).compiled
|
140
|
+
elsif options.has_key?(:body)
|
141
|
+
Typst::formats[format].from_s(options[:body], **options).compiled
|
142
|
+
elsif options.has_key?(:zip)
|
143
|
+
Typst::formats[format].from_zip(options[:zip], options[:main_file], **options).compiled
|
144
|
+
else
|
145
|
+
raise "No input given"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def write(output)
|
150
|
+
STDERR.puts "DEPRECATION WARNING: this method will go away in a future version"
|
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
|
158
|
+
|
159
|
+
def bytes
|
160
|
+
STDERR.puts "DEPRECATION WARNING: this method will go away in a future version"
|
161
|
+
compiled.bytes
|
162
|
+
end
|
163
|
+
|
164
|
+
def pages
|
165
|
+
STDERR.puts "DEPRECATION WARNING: this method will go away in a future version"
|
166
|
+
compiled.pages
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
data/lib/document.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Typst
|
2
|
+
class Document
|
3
|
+
attr_accessor :bytes
|
4
|
+
|
5
|
+
def initialize(bytes)
|
6
|
+
@bytes = bytes
|
7
|
+
end
|
8
|
+
|
9
|
+
def write(out)
|
10
|
+
if pages.size == 1
|
11
|
+
File.write(out, pages.first, mode: "wb")
|
12
|
+
else
|
13
|
+
pages.each_with_index do |page, i|
|
14
|
+
fn = File.basename(out, ".*") + "_{{n}}" + File.extname(out) unless out.include?("{{n}}")
|
15
|
+
fn = fn.gsub("{{n}}", (i+1).to_s)
|
16
|
+
File.write(fn, page, mode: "wb")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def pages
|
22
|
+
bytes.collect{ |page| page.pack("C*").to_s }
|
23
|
+
end
|
24
|
+
|
25
|
+
def document
|
26
|
+
pages.size == 1 ? pages.first : pages
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/formats/html.rb
ADDED
@@ -0,0 +1,35 @@
|
|
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
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Typst
|
2
|
+
class HtmlExperimental < Base
|
3
|
+
def initialize(*options)
|
4
|
+
super(*options)
|
5
|
+
@compiled = HtmlExperimentalDocument.new(Typst::_to_html(*self.typst_args))
|
6
|
+
end
|
7
|
+
end
|
8
|
+
class HtmlExperimentalDocument < Document; end
|
9
|
+
|
10
|
+
register_format(html_experimental: HtmlExperimental)
|
11
|
+
end
|
data/lib/formats/pdf.rb
ADDED
data/lib/formats/png.rb
ADDED
data/lib/formats/svg.rb
ADDED
data/lib/query.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Typst
|
2
|
+
class Query < Base
|
3
|
+
attr_accessor :format
|
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)
|
7
|
+
self.format = format
|
8
|
+
@result = Typst::_query(selector, field, one, format, input, root, font_paths, File.dirname(__FILE__), false, sys_inputs)
|
9
|
+
end
|
10
|
+
|
11
|
+
def result(raw: false)
|
12
|
+
case raw || format
|
13
|
+
when "json" then JSON(@result)
|
14
|
+
when "yaml" then YAML::safe_load(@result)
|
15
|
+
else @result
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/typst.rb
CHANGED
@@ -1,203 +1,31 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require "tmpdir"
|
5
|
-
require "zip/filesystem"
|
1
|
+
def Typst(*options)
|
2
|
+
Typst::Base.new(*options)
|
3
|
+
end
|
6
4
|
|
7
5
|
module Typst
|
8
|
-
|
9
|
-
attr_accessor :input
|
10
|
-
attr_accessor :root
|
11
|
-
attr_accessor :font_paths
|
12
|
-
attr_accessor :sys_inputs
|
13
|
-
|
14
|
-
def initialize(input, root: ".", font_paths: [], sys_inputs: {})
|
15
|
-
self.input = input
|
16
|
-
self.root = Pathname.new(root).expand_path.to_s
|
17
|
-
self.font_paths = font_paths.collect{ |fp| Pathname.new(fp).expand_path.to_s }
|
18
|
-
self.sys_inputs = sys_inputs
|
19
|
-
end
|
20
|
-
|
21
|
-
def write(output)
|
22
|
-
File.open(output, "wb"){ |f| f.write(document) }
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.from_s(main_source, dependencies: {}, fonts: {}, sys_inputs: {})
|
26
|
-
dependencies = {} if dependencies.nil?
|
27
|
-
fonts = {} if fonts.nil?
|
28
|
-
Dir.mktmpdir do |tmp_dir|
|
29
|
-
tmp_main_file = Pathname.new(tmp_dir).join("main.typ")
|
30
|
-
File.write(tmp_main_file, main_source)
|
31
|
-
|
32
|
-
dependencies.each do |dep_name, dep_source|
|
33
|
-
tmp_dep_file = Pathname.new(tmp_dir).join(dep_name)
|
34
|
-
File.write(tmp_dep_file, dep_source)
|
35
|
-
end
|
36
|
-
|
37
|
-
relative_font_path = Pathname.new(tmp_dir).join("fonts")
|
38
|
-
fonts.each do |font_name, font_bytes|
|
39
|
-
Pathname.new(relative_font_path).mkpath
|
40
|
-
tmp_font_file = relative_font_path.join(font_name)
|
41
|
-
File.write(tmp_font_file, font_bytes)
|
42
|
-
end
|
43
|
-
|
44
|
-
new(tmp_main_file, root: tmp_dir, font_paths: [relative_font_path], sys_inputs: sys_inputs)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.from_zip(zip_file_path, main_file = nil, sys_inputs: {})
|
49
|
-
dependencies = {}
|
50
|
-
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
|
-
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
|
-
fonts[Pathname.new(font_name).basename.to_s] = zipfile.file.read(font_name)
|
71
|
-
end
|
72
|
-
|
73
|
-
from_s(main_source, dependencies: dependencies, fonts: fonts, sys_inputs: sys_inputs)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
class Pdf < Base
|
79
|
-
attr_accessor :bytes
|
80
|
-
|
81
|
-
def initialize(input, root: ".", font_paths: [], sys_inputs: {})
|
82
|
-
super(input, root: root, font_paths: font_paths, sys_inputs: sys_inputs)
|
83
|
-
@bytes = Typst::_to_pdf(self.input, self.root, self.font_paths, File.dirname(__FILE__), false, sys_inputs)[0]
|
84
|
-
end
|
85
|
-
|
86
|
-
def document
|
87
|
-
bytes.pack("C*").to_s
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
class Svg < Base
|
92
|
-
attr_accessor :pages
|
93
|
-
|
94
|
-
def initialize(input, root: ".", font_paths: [], sys_inputs: {})
|
95
|
-
super(input, root: root, font_paths: font_paths, sys_inputs: sys_inputs)
|
96
|
-
@pages = Typst::_to_svg(self.input, self.root, self.font_paths, File.dirname(__FILE__), false, sys_inputs).collect{ |page| page.pack("C*").to_s }
|
97
|
-
end
|
98
|
-
|
99
|
-
def write(output)
|
100
|
-
if pages.size > 1
|
101
|
-
pages.each_with_index do |page, i|
|
102
|
-
if output.include?("{{n}}")
|
103
|
-
file_name = output.gsub("{{n}}", (i+1).to_s)
|
104
|
-
else
|
105
|
-
file_name = File.basename(output, File.extname(output)) + "_" + i.to_s
|
106
|
-
file_name = file_name + File.extname(output)
|
107
|
-
end
|
108
|
-
File.open(file_name, "w"){ |f| f.write(page) }
|
109
|
-
end
|
110
|
-
elsif pages.size == 1
|
111
|
-
File.open(output, "w"){ |f| f.write(pages[0]) }
|
112
|
-
else
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
class Png < Base
|
118
|
-
attr_accessor :pages
|
6
|
+
@@formats = {}
|
119
7
|
|
120
|
-
|
121
|
-
|
122
|
-
@pages = Typst::_to_png(self.input, self.root, self.font_paths, File.dirname(__FILE__), false, sys_inputs).collect{ |page| page.pack("C*").to_s }
|
123
|
-
end
|
124
|
-
|
125
|
-
def write(output)
|
126
|
-
if pages.size > 1
|
127
|
-
pages.each_with_index do |page, i|
|
128
|
-
if output.include?("{{n}}")
|
129
|
-
file_name = output.gsub("{{n}}", (i+1).to_s)
|
130
|
-
else
|
131
|
-
file_name = File.basename(output, File.extname(output)) + "_" + i.to_s
|
132
|
-
file_name = file_name + File.extname(output)
|
133
|
-
end
|
134
|
-
File.open(file_name, "w"){ |f| f.write(page) }
|
135
|
-
end
|
136
|
-
elsif pages.size == 1
|
137
|
-
File.open(output, "w"){ |f| f.write(pages[0]) }
|
138
|
-
else
|
139
|
-
end
|
140
|
-
end
|
8
|
+
def self.register_format(**format)
|
9
|
+
@@formats.merge!(format)
|
141
10
|
end
|
142
|
-
|
143
|
-
class Html < Base
|
144
|
-
attr_accessor :title
|
145
|
-
attr_accessor :svg
|
146
|
-
attr_accessor :html
|
147
|
-
|
148
|
-
def initialize(input, title: nil, root: ".", font_paths: [], sys_inputs: {})
|
149
|
-
super(input, root: root, font_paths: font_paths, sys_inputs: sys_inputs)
|
150
|
-
title = title || File.basename(input, File.extname(input))
|
151
|
-
self.title = CGI::escapeHTML(title)
|
152
|
-
self.svg = Svg.new(self.input, root: self.root, font_paths: self.font_paths, sys_inputs: sys_inputs)
|
153
|
-
end
|
154
11
|
|
155
|
-
|
156
|
-
|
157
|
-
<!DOCTYPE html>
|
158
|
-
<html>
|
159
|
-
<head>
|
160
|
-
<title>#{title}</title>
|
161
|
-
</head>
|
162
|
-
<body>
|
163
|
-
#{svg.pages.join("<br />")}
|
164
|
-
</body>
|
165
|
-
</html>
|
166
|
-
}
|
167
|
-
end
|
168
|
-
alias_method :document, :markup
|
169
|
-
end
|
170
|
-
|
171
|
-
class HtmlExperimental < Base
|
172
|
-
attr_accessor :bytes
|
173
|
-
|
174
|
-
def initialize(input, root: ".", font_paths: [], sys_inputs: {})
|
175
|
-
super(input, root: root, font_paths: font_paths, sys_inputs: sys_inputs)
|
176
|
-
@bytes = Typst::_to_html(self.input, self.root, self.font_paths, File.dirname(__FILE__), false, sys_inputs)[0]
|
177
|
-
end
|
178
|
-
|
179
|
-
def document
|
180
|
-
bytes.pack("C*").to_s
|
181
|
-
end
|
182
|
-
alias_method :markup, :document
|
12
|
+
def self.formats
|
13
|
+
@@formats
|
183
14
|
end
|
15
|
+
end
|
184
16
|
|
185
|
-
class Query < Base
|
186
|
-
attr_accessor :format
|
187
|
-
attr_accessor :result
|
188
17
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
end
|
18
|
+
require "cgi"
|
19
|
+
require "pathname"
|
20
|
+
require "tmpdir"
|
21
|
+
require "zip/filesystem"
|
194
22
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
23
|
+
require_relative "typst/typst"
|
24
|
+
require_relative "base"
|
25
|
+
require_relative "query"
|
26
|
+
require_relative "document"
|
27
|
+
require_relative "formats/pdf"
|
28
|
+
require_relative "formats/svg"
|
29
|
+
require_relative "formats/png"
|
30
|
+
require_relative "formats/html"
|
31
|
+
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.13.
|
4
|
+
version: 0.13.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Flinn
|
@@ -71,6 +71,8 @@ files:
|
|
71
71
|
- ext/typst/src/package.rs
|
72
72
|
- ext/typst/src/query.rs
|
73
73
|
- ext/typst/src/world.rs
|
74
|
+
- lib/base.rb
|
75
|
+
- lib/document.rb
|
74
76
|
- lib/fonts/DejaVuSansMono-Bold.ttf
|
75
77
|
- lib/fonts/DejaVuSansMono-BoldOblique.ttf
|
76
78
|
- lib/fonts/DejaVuSansMono-Oblique.ttf
|
@@ -85,6 +87,12 @@ files:
|
|
85
87
|
- lib/fonts/NewCM10-Regular.otf
|
86
88
|
- lib/fonts/NewCMMath-Book.otf
|
87
89
|
- lib/fonts/NewCMMath-Regular.otf
|
90
|
+
- lib/formats/html.rb
|
91
|
+
- lib/formats/html_experimental.rb
|
92
|
+
- lib/formats/pdf.rb
|
93
|
+
- lib/formats/png.rb
|
94
|
+
- lib/formats/svg.rb
|
95
|
+
- lib/query.rb
|
88
96
|
- lib/typst.rb
|
89
97
|
homepage: https://github.com/actsasflinn/typst-rb
|
90
98
|
licenses:
|