summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/make4ht/filters/make4ht-mjcli.lua
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2021-03-20 22:20:13 +0000
committerKarl Berry <karl@freefriends.org>2021-03-20 22:20:13 +0000
commitc401f68497eea2603e3c5a8742b032335fc6dfce (patch)
tree4a20a407fd27e90ebb9ea2493a89539344d2910a /Master/texmf-dist/scripts/make4ht/filters/make4ht-mjcli.lua
parent18d932604c99399d6fd9d26967b6e9bd2553898b (diff)
make4ht (20mar21)
git-svn-id: svn://tug.org/texlive/trunk@58563 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts/make4ht/filters/make4ht-mjcli.lua')
-rw-r--r--Master/texmf-dist/scripts/make4ht/filters/make4ht-mjcli.lua183
1 files changed, 183 insertions, 0 deletions
diff --git a/Master/texmf-dist/scripts/make4ht/filters/make4ht-mjcli.lua b/Master/texmf-dist/scripts/make4ht/filters/make4ht-mjcli.lua
new file mode 100644
index 00000000000..c7b3c46507a
--- /dev/null
+++ b/Master/texmf-dist/scripts/make4ht/filters/make4ht-mjcli.lua
@@ -0,0 +1,183 @@
+local mkutils = require "mkutils"
+local log = logging.new("mjcli")
+-- other possible value is page2svg
+local mathnodepath = "mjcli"
+-- options for MathJax command
+local options = ""
+-- math fonts position
+-- don't alter fonts if not set
+local fontdir = nil
+-- if we copy fonts
+local fontdest = nil
+local fontformat = "woff"
+local cssfilename = "mathjax-chtml.css"
+
+local function compile(filename, options)
+ -- local tmpfile = os.tmpname()
+ log:info("Compile using MathJax")
+ local command = mathnodepath .. " ".. options .. " " .. filename
+ log:info(command)
+ local commandhandle, msg = io.popen(command,"r")
+ if not commandhandle then return nil, msg end
+ local content = commandhandle:read("*all")
+ commandhandle:close()
+ return content
+end
+
+local saved_styles = {}
+local used_styles = {}
+
+local function make_css(saved_styles)
+ -- this buffer contains lines of the new CSS file
+ local buffer = {}
+ -- process table with saved CSS rules and make CSS file again
+ for _, rule in ipairs(saved_styles) do
+ buffer[#buffer+1] = rule.selector .. " {"
+ -- save CSS properties
+ for _, line in ipairs(rule.content) do
+ buffer[#buffer+1] = line
+ end
+ buffer[#buffer+1] = "}"
+ buffer[#buffer+1] = "" -- add blank line
+ end
+ return table.concat(buffer, "\n")
+end
+
+-- MathJax generated CSS contains reusable declarations but also
+-- declarations of fixes for elements in the current file
+-- the idea is to reuse the common declarations and to save each
+-- fix.
+local function parse_css(css, file_class)
+ local status = "init"
+ local current = {}
+ local current_selector
+ for line in css:gmatch("([^\n]+)") do
+ if status == "init" then
+ local selector, rest = line:match("%s*(.-)%s*{(.-)")
+ if selector then
+ current_selector = selector
+ -- if the current selector contains class, we must prepend the current file class
+ -- as the joined CSS file could contain multiple rules with the same class otherwise
+ if current_selector:match("%.") then current_selector = "." .. file_class .. " " .. current_selector end
+ status = "record"
+ end
+ elseif status == "record" then
+ if line:match("%}") then
+ status = "init"
+ if not used_styles[current_selector] then
+ table.insert(saved_styles, {selector = current_selector, content = current})
+ end
+ current = {}
+ used_styles[current_selector] = true
+ else
+ table.insert(current, line)
+ end
+ end
+
+ end
+ -- save combined CSS for all files
+ return make_css(saved_styles)
+end
+
+local function make_file_class(name)
+ -- clean the filename to make it safe as a class name
+ return name:gsub("[%s%p%s]", "_")
+end
+
+-- set class attribute in the body element of the current file
+-- this is necessary for the updated CSS file
+local function set_body_class(content, file_class)
+ content = content:gsub("<body(.-)>", function(body)
+ if body:match("class") then
+ -- add new class if there already is one
+ body = body:gsub("(class.-[\"'])", "%1" .. file_class .. " ")
+ else
+ body = body .. ' class="' .. file_class .. '"'
+ end
+ return "<body" ..body ..">"
+ end)
+ return content
+end
+
+
+-- save the css code from the html page generated by MathJax
+local function extract_css(contents, currentfilename)
+ local css
+ local filename = cssfilename
+ local file_class = make_file_class(currentfilename)
+ -- detect all <style> tags
+ contents = contents:gsub('<style [^>]+>(.-)</style>', function(style)
+ -- replace only the style for mathjax
+ if style:match "mjx%-container" then
+ css = parse_css(style, file_class)
+ return '<link rel="stylesheet" type="text/css" href="'..filename ..'" />'
+ end
+ end)
+ contents = set_body_class(contents, file_class)
+ return filename, contents, css
+end
+
+-- Update the paths to fonts to use the local versions
+local function use_fonts(css)
+ local family_pattern = "font%-family:%s*(.-);.-%/([^%/]+)%.".. fontformat
+ local family_build = "@font-face {font-family: %s; src: url('%s/%s.%s') format('%s')}"
+ local fontdir = fontdir:gsub("/$","")
+ css = css:gsub("(@font%-face%s*{.-})", function(face)
+ if not face:match("url%(") then return face end
+ -- print(face)
+ local family, filename = face:match(family_pattern)
+ log:info("use font: ",family, filename)
+ local newfile = string.format("%s/%s.%s", fontdir, filename, fontformat)
+ Make:add_file(newfile)
+ return family_build:format(family, fontdir, filename, fontformat, fontformat)
+ -- return face
+ end)
+ return css
+end
+
+
+local function save_css(filename, css)
+ local f = io.open(filename, "w")
+ f:write(css)
+ f:close()
+end
+
+return function(text, arguments)
+ -- if arguments.prg then mathnodepath = arguments.prg end
+ local extoptions = mkutils.get_filter_settings "mjcli" or {}
+ local arguments = arguments or {}
+ mathnodepath = arguments.prg or extoptions.prg or mathnodepath
+ local options = arguments.options or extoptions.options or options
+ fontdir = arguments.fontdir or extoptions.fontdir or fontdir
+ -- the following ne is unused ATM
+ fontdest = arguments.fontdest or extoptions.fontdest or fontdest
+ fontformat = arguments.fontformat or extoptions.fontformat or fontformat
+ cssfilename = arguments.cssfilename or extoptions.cssfilename or arguments.input .. "-mathjax.css"
+ local is_latex = arguments.latex or extoptions.latex or false
+ local filename = arguments.filename
+
+ -- modify options to use LaTeX syntax by MathJax
+ if is_latex then
+ options = options .. " -l"
+ end
+
+ -- compile current html file with mathjax
+ local newtext, msg = compile(filename, options)
+ if not newtext then
+ log:error(msg)
+ return text
+ end
+ -- save CSS to a standalone file
+ local cssfile, newtext, css = extract_css(newtext, filename)
+ -- use local font files if fontdir is present
+ if fontdir then
+ css = use_fonts(css)
+ end
+ if css then
+ save_css(cssfile, css)
+ Make:add_file(cssfile)
+ -- print(css)
+ log:info("CSS file: " .. cssfile)
+ end
+ return newtext
+end