diff options
Diffstat (limited to 'Master/texmf-dist/scripts/make4ht/filters/make4ht-mjcli.lua')
-rw-r--r-- | Master/texmf-dist/scripts/make4ht/filters/make4ht-mjcli.lua | 183 |
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 |