jekyll-t4j 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +4 -1
- data/lib/jekyll-t4j/engine/katex.rb +22 -9
- data/lib/jekyll-t4j/engine.rb +71 -89
- data/lib/jekyll-t4j/merger.rb +2 -2
- data/lib/jekyll-t4j/renderer.rb +3 -3
- data/lib/jekyll-t4j/snippet.rb +42 -0
- data/lib/jekyll-t4j/version.rb +1 -1
- data/lib/jekyll-t4j.rb +3 -0
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '08b199ca229a735a5862598c3833f1ca8c4643db6458fb24e1575604df8196aa'
|
4
|
+
data.tar.gz: aeb6470ab96afd7e12008946f568804c36fb44d42350cec3d5d3f20728b86401
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eff915fbdffe8b6942226ef1dcfc39068fd89d5fd6fc51469844b7793af7804304f41249a5f02e11d2427fc8b9d5fc44c51bd6641ec449f112daaeb0e3e15a18
|
7
|
+
data.tar.gz: 5e6f3859887cca6604359dcc8341279f18b50d877815f87d7dc14e0310219c70a9b51d572c2ce1df1dc7b83aaad823a0745400859520e9e7ceeb9593d26fda4e
|
data/README.md
CHANGED
@@ -3,13 +3,16 @@
|
|
3
3
|
jekyll-t4j is a Jekyll plugin providing (nearly) full support of LaTeX.
|
4
4
|
|
5
5
|
- **Comprehensive**: support almost all packages, including tikz, chemfig, etc.
|
6
|
-
- **
|
6
|
+
- **Highly optimized**: employ KaTeX to boost speed. Use cache, precompiled preamble, bulk rendering.
|
7
7
|
- **Server side rendering**: all stuffs are done in server.
|
8
8
|
|
9
9
|
T4J integrates Jekyll with your local TeX distribution, so you need to have either [MikTeX](https://miktex.org/) or [TeX Live](https://tug.org/texlive/) installed.
|
10
10
|
|
11
11
|
Feel free to write any LaTeX! 🎉
|
12
12
|
|
13
|
+
> **Warning**
|
14
|
+
> T4J now is in rapid development, it's pretty unstable. So don't forget to check and update frequently.
|
15
|
+
|
13
16
|
## Getting Started
|
14
17
|
|
15
18
|
Let's start by a simple instance, write a post `2023-02-04-hello-latex.md` and fill it with:
|
@@ -1,28 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "duktape"
|
4
4
|
|
5
5
|
module Jekyll::T4J
|
6
6
|
module Engine
|
7
7
|
KATEX_VERSION = "0.16.4"
|
8
8
|
|
9
|
-
@@
|
9
|
+
@@_katex_ctx_ = nil
|
10
10
|
|
11
11
|
def self.setup_katex
|
12
|
-
if not @@
|
12
|
+
if not @@_katex_ctx_ then
|
13
13
|
src = File.read(File.join(__dir__, "katex.js"))
|
14
14
|
src << File.read(File.join(__dir__, "katex.mhchem.js")) if Jekyll::T4J.cfg_pkgs.include?("mhchem")
|
15
15
|
|
16
|
-
@@
|
16
|
+
@@_katex_ctx_ = Duktape::Context.new
|
17
|
+
@@_katex_ctx_.exec_string(src)
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
20
|
-
def self.katex_raw(snippet
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
def self.katex_raw(snippet)
|
22
|
+
begin
|
23
|
+
@@_katex_ctx_.call_prop(["katex", "renderToString"], snippet.code_in,
|
24
|
+
{
|
25
|
+
displayMode: snippet.display_mode?,
|
26
|
+
output: "mathml",
|
27
|
+
strict: true
|
28
|
+
}
|
29
|
+
)[20..-8]
|
30
|
+
rescue
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
24
34
|
|
25
|
-
|
35
|
+
def self.katex_raw_bulk(snippets)
|
36
|
+
snippets.map do |snippet|
|
37
|
+
katex_raw(snippet) # TODO: parallel
|
38
|
+
end
|
26
39
|
end
|
27
40
|
end
|
28
41
|
end
|
data/lib/jekyll-t4j/engine.rb
CHANGED
@@ -7,35 +7,30 @@ unless system("latex -version", [:out, :err] => File::NULL)
|
|
7
7
|
end
|
8
8
|
|
9
9
|
require "open3"
|
10
|
-
require "jekyll/cache"
|
11
10
|
|
12
|
-
require "jekyll-t4j/engine/dvisvgm"
|
13
11
|
require "jekyll-t4j/engine/katex"
|
12
|
+
require "jekyll-t4j/engine/dvisvgm"
|
14
13
|
|
15
14
|
module Jekyll::T4J
|
16
15
|
module Engine
|
17
|
-
@@cache_katex = Jekyll::Cache.new "Jekyll
|
18
|
-
@@cache_dvisvgm = Jekyll::Cache.new "Jekyll
|
19
|
-
|
20
|
-
@@header = <<~HD
|
21
|
-
<link rel=\"stylesheet\" href=\"https://unpkg.com/katex@#{KATEX_VERSION}/dist/katex.min.css\">
|
22
|
-
<style>
|
23
|
-
.katex-ext-d {
|
24
|
-
border-radius: 0px;
|
25
|
-
display: block;
|
26
|
-
margin: 5px auto;
|
27
|
-
}
|
28
|
-
.katex-ext-i {
|
29
|
-
border-radius: 0px;
|
30
|
-
display: inline;
|
31
|
-
vertical-align: middle;
|
32
|
-
}
|
33
|
-
</style>
|
34
|
-
HD
|
35
|
-
@@header.freeze
|
16
|
+
@@cache_katex = Jekyll::Cache.new "Jekyll-T4J::Katex"
|
17
|
+
@@cache_dvisvgm = Jekyll::Cache.new "Jekyll-T4J::Dvisvgm"
|
36
18
|
|
37
19
|
def self.header
|
38
|
-
|
20
|
+
<<~HD
|
21
|
+
<script>
|
22
|
+
document.addEventListener("DOMContentLoaded", () => {
|
23
|
+
let z = document.body.getElementsByTagName("include")
|
24
|
+
for (let i = 0; i < z.length; ++i) {
|
25
|
+
let elmnt = z[i]
|
26
|
+
let xhttp = new XMLHttpRequest()
|
27
|
+
xhttp.onreadystatechange = function() { elmnt.innerHTML = this.responseText }
|
28
|
+
xhttp.open("GET", elmnt.getAttribute("src"), true)
|
29
|
+
xhttp.send()
|
30
|
+
}
|
31
|
+
})
|
32
|
+
</script>
|
33
|
+
HD
|
39
34
|
end
|
40
35
|
|
41
36
|
def self.setup
|
@@ -44,95 +39,82 @@ module Jekyll::T4J
|
|
44
39
|
end
|
45
40
|
|
46
41
|
def self.render(snippets, merger)
|
47
|
-
|
48
|
-
"<
|
49
|
-
|
50
|
-
}
|
51
|
-
|
52
|
-
}
|
42
|
+
gen_svg = ->(svg, displayMode) {
|
43
|
+
"<embed src=\"#{merger.(svg, ".svg")}\" style=\"height:#{
|
44
|
+
(svg[/height='(\S+?)pt'/, 1].to_f * 0.1).round(4)
|
45
|
+
}em;#{
|
46
|
+
displayMode ? "display:block;margin:auto" : "display:inline;vertical-align:middle"
|
47
|
+
}\">"
|
53
48
|
}
|
54
|
-
|
55
|
-
|
56
|
-
snippets.map! {|snippet|
|
57
|
-
if not snippet.start_with?("\\") then
|
58
|
-
s = split_snippet(snippet)
|
59
|
-
snippet = s[1] ? "\\[#{s[0]}\\]" : "\\(#{s[0]}\\)"
|
60
|
-
end
|
61
|
-
|
62
|
-
snippet
|
49
|
+
gen_mathml = ->(mathml) {
|
50
|
+
"<include src=\"#{merger.(mathml, ".xml")}\"></include>"
|
63
51
|
}
|
64
52
|
|
65
|
-
#
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
s = snippets[i]
|
70
|
-
r = @@cache_katex.getset(s) {
|
71
|
-
begin
|
72
|
-
katex_raw(s, {strict: true})
|
73
|
-
rescue
|
74
|
-
"NIL"
|
75
|
-
end
|
76
|
-
}
|
53
|
+
# 'snippets' << caches
|
54
|
+
uncached = {} #act as hash set
|
55
|
+
snippets.each_with_index do |s, i|
|
56
|
+
r = nil
|
77
57
|
|
78
|
-
|
58
|
+
begin
|
59
|
+
r = gen_mathml.(@@cache_katex[s.source])
|
60
|
+
rescue
|
79
61
|
begin
|
80
|
-
r =
|
62
|
+
r = gen_svg.(@@cache_dvisvgm[Jekyll::T4J.cfg_pkgs + s.source], s.display_mode?)
|
81
63
|
rescue
|
82
64
|
uncached[s] = nil
|
83
|
-
unset << i
|
84
|
-
r = s
|
85
65
|
end
|
86
66
|
end
|
87
67
|
|
88
|
-
snippets[i] = r
|
89
|
-
|
68
|
+
snippets[i] = r if r
|
69
|
+
end
|
70
|
+
|
71
|
+
# finish if no 'uncached' found
|
72
|
+
return if uncached.empty?
|
73
|
+
uncached = uncached.keys
|
74
|
+
|
75
|
+
# otherwise render 'uncached' with katex and cache them
|
76
|
+
katex_raw_bulk(uncached).each_with_index do |result, i|
|
77
|
+
@@cache_katex[uncached[i].source] = result if result
|
78
|
+
end
|
79
|
+
|
80
|
+
# 'snippets' << rendering results
|
81
|
+
uncached = {} #act as hash set again
|
82
|
+
snippets.each_with_index do |s, i|
|
83
|
+
next if !s.is_a?(Snippet)
|
90
84
|
|
91
|
-
# render 'uncached'
|
92
|
-
if not uncached.empty? then
|
93
|
-
# bulk render 'uncached'
|
94
85
|
begin
|
95
|
-
|
96
|
-
|
97
|
-
|
86
|
+
snippets[i] = gen_mathml.(@@cache_katex[s.source])
|
87
|
+
rescue
|
88
|
+
uncached[s] = nil
|
98
89
|
end
|
90
|
+
end
|
99
91
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
r = uncached[s]
|
92
|
+
# finish if no 'uncached' found
|
93
|
+
return if uncached.empty?
|
94
|
+
uncached = uncached.keys
|
104
95
|
|
105
|
-
|
106
|
-
|
107
|
-
|
96
|
+
# otherwise render 'uncached' with dvisvgm and cache them
|
97
|
+
dvisvgm_raw_bulk(uncached).each_with_index do |result, i|
|
98
|
+
@@cache_dvisvgm[Jekyll::T4J.cfg_pkgs + uncached[i].source] = result
|
108
99
|
end
|
109
|
-
end
|
110
100
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
times -= 1
|
101
|
+
# 'snippets' << rendering results
|
102
|
+
snippets.each_with_index do |s, i|
|
103
|
+
next if !s.is_a?(Snippet)
|
115
104
|
|
116
|
-
|
117
|
-
|
105
|
+
begin
|
106
|
+
snippets[i] = gen_svg.(@@cache_dvisvgm[Jekyll::T4J.cfg_pkgs + s.source], s.display_mode?)
|
107
|
+
rescue
|
108
|
+
# impossible!
|
109
|
+
end
|
118
110
|
end
|
119
111
|
end
|
120
112
|
|
121
|
-
def self.
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
def self.split_snippet(snippet)
|
126
|
-
displayMode = false
|
127
|
-
range = 2..-3
|
128
|
-
|
129
|
-
if snippet.start_with?("\\[") or snippet.start_with?("$$") then
|
130
|
-
displayMode = true
|
131
|
-
elsif snippet.start_with?("$") then
|
132
|
-
range = 1..-2
|
113
|
+
def self.shell(cmd, pwd, n = 1)
|
114
|
+
n.times do
|
115
|
+
log, s = Open3.capture2e(cmd, :chdir => pwd) # TODO: even the quickest 'dvisvgm' cost at least 0.3s in my laptop
|
116
|
+
raise log if not s.success?
|
133
117
|
end
|
134
|
-
|
135
|
-
[snippet[range], displayMode]
|
136
118
|
end
|
137
119
|
end
|
138
120
|
end
|
data/lib/jekyll-t4j/merger.rb
CHANGED
@@ -20,10 +20,10 @@ module Jekyll::T4J
|
|
20
20
|
|
21
21
|
# write external files and clean up
|
22
22
|
Jekyll::Hooks.register :site, :post_write, priority: Jekyll::Hooks::PRIORITY_MAP[:low] do |site|
|
23
|
-
@@table.each
|
23
|
+
@@table.each do |filedata, request|
|
24
24
|
basename = request[0]
|
25
25
|
request[1].each {|extname| File.write(File.join(site.dest, basename + extname), filedata)}
|
26
|
-
|
26
|
+
end
|
27
27
|
|
28
28
|
@@table.clear
|
29
29
|
end
|
data/lib/jekyll-t4j/renderer.rb
CHANGED
@@ -82,16 +82,16 @@ module Jekyll::T4J
|
|
82
82
|
docs = []
|
83
83
|
|
84
84
|
# collect tex snippets
|
85
|
-
site.each_site_file
|
85
|
+
site.each_site_file do |f|
|
86
86
|
next if f.is_a?(Jekyll::StaticFile)
|
87
87
|
next if f.is_a?(Jekyll::Page) and not f.html?
|
88
88
|
|
89
89
|
parts = extract(f.output)
|
90
90
|
if parts.size > 1 then #'f' has tex snippet(s)
|
91
|
-
parts.each {|part| snippets << CGI::unescapeHTML
|
91
|
+
parts.each {|part| snippets << Jekyll::T4J::Snippet.new(CGI::unescapeHTML part[0]) if part[1]}
|
92
92
|
docs << [f, parts]
|
93
93
|
end
|
94
|
-
|
94
|
+
end
|
95
95
|
|
96
96
|
# render 'snippets'
|
97
97
|
Jekyll::T4J::Engine.render(snippets, ->(data, extname) {Jekyll::T4J::Merger.ask_for_merge(data, extname)})
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll::T4J
|
4
|
+
class Snippet
|
5
|
+
@is_display_mode
|
6
|
+
@source
|
7
|
+
@code_in
|
8
|
+
|
9
|
+
attr_reader :source, :code_in
|
10
|
+
|
11
|
+
def initialize(raw)
|
12
|
+
@is_display_mode = raw.start_with?("\\[") or raw.start_with?("$$")
|
13
|
+
|
14
|
+
# extract the code inside and minimize it
|
15
|
+
@code_in = raw[(display_mode? or raw.start_with?("\\")) ? (2..-3) : (1..-2)]
|
16
|
+
@code_in.strip! # TODO: minimize code
|
17
|
+
@code_in.freeze
|
18
|
+
|
19
|
+
# create minimized source
|
20
|
+
@source = display_mode? ? "\\[#{code_in}\\]" : "\\(#{code_in}\\)"
|
21
|
+
@source.freeze
|
22
|
+
|
23
|
+
# we are immutable
|
24
|
+
freeze
|
25
|
+
end
|
26
|
+
|
27
|
+
def display_mode?
|
28
|
+
@is_display_mode
|
29
|
+
end
|
30
|
+
|
31
|
+
def hash
|
32
|
+
source.hash
|
33
|
+
end
|
34
|
+
|
35
|
+
def ==(other)
|
36
|
+
self.class === other and source == other.source
|
37
|
+
end
|
38
|
+
|
39
|
+
alias to_s source
|
40
|
+
alias eql? ==
|
41
|
+
end
|
42
|
+
end
|
data/lib/jekyll-t4j/version.rb
CHANGED
data/lib/jekyll-t4j.rb
CHANGED
@@ -14,6 +14,7 @@ module Jekyll::T4J
|
|
14
14
|
# initialize plugin
|
15
15
|
Jekyll::Hooks.register :site, :after_init do |site|
|
16
16
|
Jekyll.logger.info "Initializing T4J..."
|
17
|
+
t0 = Time.now
|
17
18
|
|
18
19
|
cfg = site.config["t4j"]
|
19
20
|
if cfg and (cfg = cfg["packages"]) then
|
@@ -30,9 +31,11 @@ module Jekyll::T4J
|
|
30
31
|
end
|
31
32
|
|
32
33
|
Jekyll::T4J::Engine.setup
|
34
|
+
Jekyll.logger.info "", "done in #{(Time.now - t0).round(3)} seconds."
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
38
|
+
require "jekyll-t4j/snippet"
|
36
39
|
require "jekyll-t4j/merger"
|
37
40
|
require "jekyll-t4j/engine"
|
38
41
|
require "jekyll-t4j/renderer"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll-t4j
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- crow02531
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-02-
|
11
|
+
date: 2023-02-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jekyll
|
@@ -25,20 +25,21 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '4.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: duktape
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '2.
|
33
|
+
version: '2.7'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '2.
|
41
|
-
description: "
|
40
|
+
version: '2.7'
|
41
|
+
description: " An optimized Jekyll plugin providing (nearly) full support of
|
42
|
+
LaTeX.\n"
|
42
43
|
email: crow02531@outlook.com
|
43
44
|
executables: []
|
44
45
|
extensions: []
|
@@ -55,6 +56,7 @@ files:
|
|
55
56
|
- lib/jekyll-t4j/engine/katex.rb
|
56
57
|
- lib/jekyll-t4j/merger.rb
|
57
58
|
- lib/jekyll-t4j/renderer.rb
|
59
|
+
- lib/jekyll-t4j/snippet.rb
|
58
60
|
- lib/jekyll-t4j/version.rb
|
59
61
|
homepage: https://github.com/crow02531/jekyll-t4j
|
60
62
|
licenses:
|
@@ -76,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
78
|
version: '0'
|
77
79
|
requirements:
|
78
80
|
- A TeX distribution
|
79
|
-
rubygems_version: 3.3.
|
81
|
+
rubygems_version: 3.3.26
|
80
82
|
signing_key:
|
81
83
|
specification_version: 4
|
82
84
|
summary: LaTeX support for Jekyll.
|