-
Notifications
You must be signed in to change notification settings - Fork 4
/
liquid_latex.rb
161 lines (146 loc) · 5.93 KB
/
liquid_latex.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
require "digest"
require "fileutils"
module Jekyll
module Tags
class LatexBlock < Liquid::Block
include Liquid::StandardFilters
@@globals = {
"debug" => false,
"density" => "300",
"usepackages" => "",
"latex_cmd" => "latex -interaction=nonstopmode $texfile &> /dev/null",
"dvips_cmd" => "dvips -E $dvifile -o $epsfile &> /dev/null",
"convert_cmd" => "convert -density $density $epsfile $pngfile &> /dev/null",
"temp_filename" => "latex_temp",
"output_directory" => "/latex",
"src_dir" => "",
"dst_dir" => ""
}
@@generated_files = [ ]
def self.generated_files
@@generated_files
end
def self.latex_output_directory
@@globals["output_directory"]
end
def initialize(tag_name, text, tokens)
super
# We now can adquire the options for this liquid tag
@p = { "usepackages" => "" }
text.gsub(" ", " ").split(" ").each do |part|
if part.split("=").count != 2
raise SyntaxError.new("Syntax Error in tag 'latex'")
end
var,val = part.split("=")
@p[var] = val
end
end
def self.read_config(name, site)
cfg = site.config["liquid_latex"]
return if cfg.nil?
value = cfg[name]
@@globals[name] = value if !value.nil?
end
def self.init_globals(site)
# Get all the variables from the config and remember them for future use.
if !defined?(@@first_time)
@@first_time = true
@@globals.keys.each do |k|
read_config(k, site)
end
@@globals["src_dir"] = File.join(site.config["source"], @@globals["output_directory"])
@@globals["dst_dir"] = File.join(site.config["destination"], @@globals["output_directory"])
# Verify and prepare the output folder if it doesn't exist
FileUtils.mkdir_p(@@globals["src_dir"]) unless File.exists?(@@globals["src_dir"])
end
end
def execute_cmd(cmd)
cmd = cmd.gsub("\$density", @p["density"].to_s)
cmd = cmd.gsub("\$texfile", @p["tex_fn"])
cmd = cmd.gsub("\$dvifile", @p["dvi_fn"])
cmd = cmd.gsub("\$epsfile", @p["eps_fn"])
cmd = cmd.gsub("\$pngfile", @p["png_fn"])
puts cmd if @@globals["debug"]
system(cmd)
return ($?.exitstatus == 0)
end
def render(context)
latex_source = super
# fix initial configurations
site = context.registers[:site]
Tags::LatexBlock::init_globals(site)
# prepare density and usepackages
@p["density"] = @@globals["density"] unless @p.key?("density")
@p["usepackages"] = (@@globals["usepackages"].split(",") + @p["usepackages"].split(",")).join(",")
# if this LaTeX code is already compiled, skip its compilation
hash_txt = @p["density"].to_s + @p["usepackages"].to_s + latex_source
filename = "latex-" + Digest::MD5.hexdigest(hash_txt) + ".png"
@p["png_fn"] = File.join(@@globals["src_dir"], filename)
ok = true
if !File.exists?(@p["png_fn"])
puts "Compiling with LaTeX..." if @@globals["debug"]
@p["tex_fn"] = @@globals["temp_filename"] + ".tex"
@p["dvi_fn"] = @@globals["temp_filename"] + ".dvi"
@p["eps_fn"] = @@globals["temp_filename"] + ".eps"
# Put the LaTeX source code to file
latex_tex = "\\documentclass[letterpaper,dvips]{article}\n"
@p["usepackages"].gsub(" ","").split(",").each do |packagename|
latex_tex << "\\usepackage\{#{packagename}\}\n"
end
latex_tex << "\\begin{document}\n\\pagestyle{empty}\n"
latex_tex << latex_source
latex_tex << "\\end{document}"
tex_file = File.new(@p["tex_fn"], "w")
tex_file.puts(latex_tex)
tex_file.close
# Compile the document to PNG
ok = execute_cmd(@@globals["latex_cmd"])
execute_cmd(@@globals["dvips_cmd"]) if ok
execute_cmd(@@globals["convert_cmd"]) if ok
# Delete temporary files
Dir.glob(@@globals["temp_filename"] + ".*").each do |f|
File.delete(f)
end
end
if ok
# Add the file to the list of static files for the final copy once generated
st_file = Jekyll::StaticFile.new(site, site.source, @@globals["output_directory"], filename)
@@generated_files << st_file
site.static_files << st_file
# Build the <img> tag to be returned to the renderer
png_path = File.join(@@globals["output_directory"], filename)
return "<img src=\"" + png_path + "\" />"
else
# Generate a block of text in the post with the original source
resp = "Failed to render the following block of LaTeX:<br/>\n"
resp << "<pre><code>" + latex_tex + "</code></pre>"
return resp
end
end
end
end
class Site
# Alias for the parent Site::write method (ingenious static override)
alias :super_latex_write :write
def write
super_latex_write # call the super method
Tags::LatexBlock::init_globals(self)
dest_folder = File.join(dest, Tags::LatexBlock::latex_output_directory)
FileUtils.mkdir_p(dest_folder) unless File.exists?(dest_folder)
# clean all previously rendered files not rendered in the actual build
src_files = []
Tags::LatexBlock::generated_files.each do |f|
src_files << f.path
end
pre_files = Dir.glob(File.join(source, Tags::LatexBlock::latex_output_directory, "latex-*.png"))
to_remove = pre_files - src_files
to_remove.each do |f|
File.unlink f if File.exists?(f)
d, fn = File.split(f)
df = File.join(dest, Tags::LatexBlock::latex_output_directory, fn)
File.unlink df if File.exists?(df)
end
end
end
end
Liquid::Template.register_tag('latex', Jekyll::Tags::LatexBlock)