diff options
17 files changed, 896 insertions, 149 deletions
diff --git a/Build/source/texk/texlive/linked_scripts/make4ht/make4ht b/Build/source/texk/texlive/linked_scripts/make4ht/make4ht index 7d579fafeaa..f6358956774 100755 --- a/Build/source/texk/texlive/linked_scripts/make4ht/make4ht +++ b/Build/source/texk/texlive/linked_scripts/make4ht/make4ht @@ -29,7 +29,7 @@ make4ht [options] filename ["tex4ht.sty op." "tex4ht op." "t4ht op" "latex op"] -- set version number. the template should be replaced by the -- actual version number by the build script -local version = "v0.3l" +local version = "v0.3m" mkparams.version_number = version local args = mkparams.get_args() @@ -120,7 +120,13 @@ make:match("tmp$", function(filename,params) make:match(".*",function(filename,par) local outdir = '' --par["outdir"] and par["outdir"] .."/" or '' - if par['outdir'] ~= "" then outdir = par['outdir'] .. '/' end + if par['outdir'] ~= "" then + outdir = par['outdir'] .. '/' + else + -- don't run unnecessary copy without output dir + log:info("No output directory") + return true + end log:info("outdir: "..outdir) local outfilename = outdir .. filename mkutils.copy(filename,outfilename) diff --git a/Master/texmf-dist/doc/support/make4ht/README b/Master/texmf-dist/doc/support/make4ht/README index bdb5e173c3d..0675e1d0ce1 100644 --- a/Master/texmf-dist/doc/support/make4ht/README +++ b/Master/texmf-dist/doc/support/make4ht/README @@ -278,9 +278,13 @@ dvisvgm\_hashes : efficient generation of SVG pictures using Dvisvgm. It can utilize multiple processor cores and generates only changed images. +inlinecss + +: load the `inlinecss` DOM filter. + join\_colors -: load the `joincolors` domfilter for all HTML files. +: load the `joincolors` DOM filter for all HTML files. latexmk\_build @@ -646,6 +650,11 @@ idcolons : replace the colon (`:`) character in internal links and `id` attributes. They cause validation issues. +inlinecss + +: remove CSS rules that target elements with unique attributes, such as color boxes, table rules, or inline math pictures, + and insert their properties as a inline `style` attribute in the HTML document. + joincharacters : join consecutive `<span>` or `<mn>` elements. This DOM filter supersedes the `cleanspan` filter. @@ -655,7 +664,8 @@ joincolors : many `<span>` elements with unique `id` attributes are created when \LaTeX\ colors are being used in the document. A CSS rule is added for each of these elements, which may result in substantial growth of the CSS file. This filter replaces these rules with a - common one for elements with the same color value. + common one for elements with the same color value. See also the `inlinecss` DOM filter and extension, which provides an + alternative using inline styles. odtfonts diff --git a/Master/texmf-dist/doc/support/make4ht/changelog.tex b/Master/texmf-dist/doc/support/make4ht/changelog.tex index 1d579d45149..4516805f3ad 100644 --- a/Master/texmf-dist/doc/support/make4ht/changelog.tex +++ b/Master/texmf-dist/doc/support/make4ht/changelog.tex @@ -3,7 +3,182 @@ \begin{itemize} \item - 2022/02/22 + 2023/02/24 + + \begin{itemize} + \tightlist + \item + version \texttt{0.3k} released. + \end{itemize} +\item + 2023/01/09 + + \begin{itemize} + \tightlist + \item + fixed detection of image file names in \texttt{mkutils.parse\_lg()} + \end{itemize} +\item + 2022/11/25 + + \begin{itemize} + \tightlist + \item + reverted change of index page numbers, it was buggy + \item + test if the \texttt{.idx} file exists. + \end{itemize} +\item + 2022/11/24 + + \begin{itemize} + \tightlist + \item + \texttt{make4ht-indexing}: fixed handling of numbers in index + entries text. + \end{itemize} +\item + 2022/11/01 + + \begin{itemize} + \tightlist + \item + remove empty last rows in MathML tables. + \end{itemize} +\item + 2022/10/21 + + \begin{itemize} + \tightlist + \item + added the \texttt{inlinecss} DOM filter and extension with the same + name. + \end{itemize} +\item + 2022/09/29 + + \begin{itemize} + \tightlist + \item + the \texttt{join\_characters} DOM filter now shouldn't produce extra + \texttt{\textless{}span\textgreater{}} elements after white space. + \end{itemize} +\item + 2022/09/16 + + \begin{itemize} + \tightlist + \item + use the \texttt{no\^{}} option to compile the \texttt{make4ht} HTML + docs, to prevent clash with the Doc package. + \end{itemize} +\item + 2022/07/22 + + \begin{itemize} + \tightlist + \item + \texttt{mathmlfixes} DOM filter: + + \begin{itemize} + \tightlist + \item + don't change \texttt{\textless{}mo\textgreater{}} to + \texttt{\textless{}mtext\textgreater{}} if the element contain the + \texttt{stretchy} attribute. + \item + add \texttt{\textless{}mtext\textgreater{}} to + \texttt{\textless{}mstyle\textgreater{}} if it contains only plain + text + \end{itemize} + \end{itemize} +\item + 2022/07/08 + + \begin{itemize} + \tightlist + \item + configure elements used in \texttt{join\_characters} DOM filter. + \item + added support for the \texttt{mml:} prefix in \texttt{mathml\_fixes} + DOM filter. + \end{itemize} +\item + 2022/06/28 + + \begin{itemize} + \tightlist + \item + handle \texttt{\textbackslash{}maketitle} in JATS. + \end{itemize} +\item + 2022/06/24 + + \begin{itemize} + \tightlist + \item + handle internal and external links in the JATS output. + \item + better detection of empty paragraphs. + \end{itemize} +\item + 2022/06/16 + + \begin{itemize} + \tightlist + \item + use DOM filters to fix JATS output. + \end{itemize} +\item + 2022/04/22 + + \begin{itemize} + \tightlist + \item + use more explicit options for \texttt{latexmk}. + \end{itemize} +\item + 2022/04/19 + + \begin{itemize} + \tightlist + \item + remove all \texttt{htlatex} calls from the build sequence when the + \texttt{latexmk\_build} extension is used. + \item + fixed other issues that caused spurious executions of + \texttt{latexmk}. + \end{itemize} +\item + 2022/04/01 + + \begin{itemize} + \tightlist + \item + don't copy files to the output dir if it wasn't requested + \item + fixed copying of the ODT file to the output dir. + \end{itemize} +\item + 2022/03/29 + + \begin{itemize} + \tightlist + \item + check if tidy return non-empty string in the \texttt{tidy} + extension. + \end{itemize} +\item + 2022/03/24 + + \begin{itemize} + \tightlist + \item + don't use totally random names in the \texttt{preprocess\_input} + extension, in order to support images correctly. + \end{itemize} +\item + 2022/03/22 \begin{itemize} \tightlist diff --git a/Master/texmf-dist/doc/support/make4ht/make4ht-doc.pdf b/Master/texmf-dist/doc/support/make4ht/make4ht-doc.pdf Binary files differindex bf3b9a47952..207f7135a83 100644 --- a/Master/texmf-dist/doc/support/make4ht/make4ht-doc.pdf +++ b/Master/texmf-dist/doc/support/make4ht/make4ht-doc.pdf diff --git a/Master/texmf-dist/doc/support/make4ht/readme.tex b/Master/texmf-dist/doc/support/make4ht/readme.tex index db45e582d56..98a07128999 100644 --- a/Master/texmf-dist/doc/support/make4ht/readme.tex +++ b/Master/texmf-dist/doc/support/make4ht/readme.tex @@ -358,8 +358,10 @@ It supports also Plain \TeX, use for example \texttt{tex} or \item[dvisvgm\_hashes] efficient generation of SVG pictures using Dvisvgm. It can utilize multiple processor cores and generates only changed images. +\item[inlinecss] +load the \texttt{inlinecss} DOM filter. \item[join\_colors] -load the \texttt{joincolors} domfilter for all HTML files. +load the \texttt{joincolors} DOM filter for all HTML files. \item[latexmk\_build] use \href{https://ctan.org/pkg/latexmk?lang=en}{Latexmk} for the \LaTeX~compilation. @@ -724,6 +726,10 @@ put all inline elements which are direct children of the \item[idcolons] replace the colon (\texttt{:}) character in internal links and \texttt{id} attributes. They cause validation issues. +\item[inlinecss] +remove CSS rules that target elements with unique attributes, such as +color boxes, table rules, or inline math pictures, and insert their +properties as a inline \texttt{style} attribute in the HTML document. \item[joincharacters] join consecutive \texttt{\textless{}span\textgreater{}} or \texttt{\textless{}mn\textgreater{}} elements. This DOM filter @@ -733,7 +739,9 @@ many \texttt{\textless{}span\textgreater{}} elements with unique \texttt{id} attributes are created when \LaTeX~colors are being used in the document. A CSS rule is added for each of these elements, which may result in substantial growth of the CSS file. This filter replaces these -rules with a common one for elements with the same color value. +rules with a common one for elements with the same color value. See also +the \texttt{inlinecss} DOM filter and extension, which provides an +alternative using inline styles. \item[odtfonts] fix styles for fonts that were wrongly converted by \texttt{Xtpipes} in the ODT format. diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-inlinecss.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-inlinecss.lua new file mode 100644 index 00000000000..b086a2fc423 --- /dev/null +++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-inlinecss.lua @@ -0,0 +1,83 @@ +local cssquery = require "luaxml-cssquery" + +local log = logging.new("inlinecss") + +local cssrules = {} +local cssobj = cssquery() + +local function parse_rule(line) + -- parse CSS selector and attributes + -- they are always on one line in the CSS file produced by TeX4ht + local selector, values = line:match("%s*(.-)%s*(%b{})") + if values then + values = values:sub(2,-2) + end + return selector, values +end + +local function join_values(old, new) + -- correctly joins two attribute lists, depending on the ending + local separator = ";" + if not old then return new end + -- if old already ends with ;, then don't use semicolon as a separator + if old:match(";%s*$") then separator = "" end + return old .. separator .. new +end + +local function parse_css(filename) + local css_file = io.open(filename, "r") + if not css_file then return nil, "cannot load css file: " .. (filename or "") end + local newlines = {} + for line in css_file:lines() do + -- match lines that contain # or =, as these can be id or attribute selectors + if line:match("[%#%=].-{") then + -- update attributes for the current selector + local selector, value = parse_rule(line) + local oldvalue = cssrules[selector] + cssrules[selector] = join_values(oldvalue, value) + else + newlines[#newlines+1] = line + end + end + -- we need to add css rules + for selector, value in pairs(cssrules) do + cssobj:add_selector(selector, function(dom) end, {value=value}) + end + css_file:close() + -- write new version of the CSS file, without rules for ids and attributes + local css_file = io.open(filename, "w") + css_file:write(table.concat(newlines, "\n")) + css_file:close() + return true +end + +local processed = false + +-- process the HTML file and insert inline CSS for id and attribute selectors +return function(dom, par) + if not processed then + -- process the CSS file before everything else, but only once + processed = true + local css_file = par.input .. ".css" + local status, msg = parse_css(css_file) + if not status then log:warning(msg) end + end + -- loop over all elements in the current page + dom:traverse_elements(function(curr) + -- use CSS object to match if the current element + -- is matched by id attribute selector + local matched = cssobj:match_querylist(curr) + if #matched > 0 then + -- join possible already existing style attribute with values from the CSS file + local values = curr:get_attribute("style") + -- join values of all matched rules + for _,rule in ipairs(matched) do + values = join_values(values, rule.params.value) + end + curr:set_attribute("style", values) + end + + end) + return dom +end + diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincharacters.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincharacters.lua index 34737f921aa..7f70cca3db4 100644 --- a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincharacters.lua +++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincharacters.lua @@ -107,7 +107,7 @@ local function join_characters(obj,par) -- we must create a new node el:add_child_node(el:create_text_node(s)) next_el:remove_node() - real_next = nil + -- real_next = nil else real_next = nil end diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-mathmlfixes.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-mathmlfixes.lua index 12754bedb97..7fa74f4632d 100644 --- a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-mathmlfixes.lua +++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-mathmlfixes.lua @@ -5,17 +5,53 @@ local token = {"mi", "mn", "mo", "mtext", "mspace", "ms"} local token_elements = {} for _, tok in ipairs(token) do token_elements[tok] = true end +-- helper functions to support MathML elements with prefixes (<mml:mi> etc). +-- +local function get_element_name(el) + -- return element name and xmlns prefix + local name = el:get_element_name() + if name:match(":") then + local prefix, real_name = name:match("([^%:]+):?(.+)") + return real_name, prefix + else + return name + end +end + +local function get_attribute(el, attr_name) + -- attributes can have the prefix, but sometimes they don't have it + -- so we need to catch both cases + local _, prefix = get_element_name(el) + prefix = prefix or "" + return el:get_attribute(attr_name) or el:get_attribute(prefix .. ":" .. attr_name) +end + +local function get_new_element_name(name, prefix) + return prefix and prefix .. ":" .. name or name +end + +local function update_element_name(el, name, prefix) + local newname = get_new_element_name(name, prefix) + el._name = newname +end + +local function create_element(el, name, prefix) + return el:create_element(newname) +end + local function is_token_element(el) - return token_elements[el:get_element_name()] + local name, prefix = get_element_name(el) + return token_elements[name], prefix end local function fix_token_elements(el) -- find token elements that are children of other token elements if is_token_element(el) then local parent = el:get_parent() - if is_token_element(parent) then + local is_parent_token, prefix = is_token_element(parent) + if is_parent_token then -- change top element in nested token elements to mstyle - parent._name = "mstyle" + update_element_name(parent, "mstyle", prefix) end end end @@ -23,7 +59,8 @@ end local function fix_nested_mstyle(el) -- the <mstyle> element can be child of token elements -- we must exterminate it - if el:get_element_name() == "mstyle" then + local el_name = get_element_name(el) + if el_name == "mstyle" then local parent = el:get_parent() if is_token_element(parent) then -- if parent doesn't have the mathvariant attribute copy it from <mstyle> @@ -44,13 +81,13 @@ local function fix_mathvariant(el) -- find if element has <mstyle> parent, and its value of mathvariant if not x:is_element() then return nil - elseif x:get_element_name() == "mstyle" then + elseif get_element_name(x) == "mstyle" then return x:get_attribute("mathvariant") else return find_mstyle(x:get_parent()) end end - if el:get_element_name() == "mi" then + if get_element_name(el) == "mi" then -- process only <mi> that have mathvariant set local oldmathvariant = el:get_attribute("mathvariant") if oldmathvariant then @@ -62,6 +99,74 @@ local function fix_mathvariant(el) end end +local function contains_only_text(el) + -- detect if element contains only text + local elements = 0 + local text = 0 + local children = el:get_children() or {} + for _ , child in ipairs(children) do + if child:is_text() then text = text + 1 + elseif child:is_element() then elements = elements + 1 + end + end + return text > 0 and elements == 0 +end + +-- check if <mstyle> element contains direct text. in that case, add +-- <mtext> +local function fix_missing_mtext(el) + if el:get_element_name() == "mstyle" and contains_only_text(el) then + -- add child <mtext> + log:debug("mstyle contains only text: " .. el:get_text()) + -- copy the current mode, change it's element name to mtext and add it as a child of <mstyle> + local copy = el:copy_node() + copy._name = "mtext" + copy._parent = el + el._children = {copy} + end +end + +local function is_radical(el) + local radicals = {msup=true, msub=true, msubsup=true} + return radicals[el:get_element_name()] +end + +local function get_mrow_child(el) + local get_first = function(x) + local children = x:get_children() + return children[1] + end + local first = get_first(el) + -- either return first child, and if the child is <mrow>, return it's first child + if first and first:is_element() then + if first:get_element_name() == "mrow" then + return get_first(first), first + else + return first + end + end +end + +local function fix_radicals(el) + if is_radical(el) then + local first_child, mrow = get_mrow_child(el) + -- if the first child is only one character long, it is possible that there is a problem + if first_child and string.len(first_child:get_text()) == 1 then + local name = first_child:get_element_name() + local siblings = el:get_siblings() + local pos = el:find_element_pos() + -- it doesn't make sense to do any further processing if the element is at the beginning + if pos == 1 then return end + if name == "mo" then + for i = pos, 1,-1 do + end + + end + end + + end +end + -- put <mrow> as child of <math> if it already isn't here local allowed_top_mrow = { math=true @@ -73,24 +178,25 @@ local function top_mrow(math) -- don't process elements that already are mrow local parent = math:get_parent() local parent_name - if parent then parent_name = parent:get_element_name() end - local current_name = math:get_element_name() + if parent then parent_name = get_element_name(parent) end + local current_name, prefix = get_element_name(math) if #children < 2 or not allowed_top_mrow[current_name] or current_name == "mrow" or parent_name == "mrow" then return nil end local mrow_count = 0 for _,v in ipairs(children) do if v:is_element() and is_token_element(v) then put_mrow = true -- break - elseif v:is_element() and v:get_element_name() == "mrow" then + elseif v:is_element() and get_element_name(v) == "mrow" then mrow_count = mrow_count + 1 end end - if not put_mrow and math:get_element_name() == "math" and mrow_count == 0 then + if not put_mrow and get_element_name(math) == "math" and mrow_count == 0 then -- put at least one <mrow> to each <math> put_mrow = true end if put_mrow then - local mrow = math:create_element("mrow") + local newname = get_new_element_name("mrow", prefix) + local mrow = math:create_element(newname) for _, el in ipairs(children) do mrow:add_child_node(el) end @@ -106,7 +212,9 @@ local function get_fence(el, attr, form) local char = el:get_attribute(attr) local mo if char then - mo = el:create_element("mo", {fence="true", form = form}) + local name, prefix = get_element_name(el) + local newname = get_new_element_name("mo", prefix) + mo = el:create_element(newname, {fence="true", form = form}) mo:add_child_node(mo:create_text_node(char)) end return mo @@ -116,13 +224,15 @@ end local function fix_mfenced(el) -- TeX4ht uses in some cases <mfenced> element which is deprecated in MathML. -- Firefox doesn't support it already. - if el:get_element_name() == "mfenced" then + local name, prefix = get_element_name(el) + if name == "mfenced" then -- we must replace it by <mrow><mo>start</mo><mfenced children...><mo>end</mo></mrow> local open = get_fence(el, "open", "prefix") local close = get_fence(el, "close", "postfix") -- there can be also separator attribute, but it is not used in TeX4ht -- change <mfenced> to <mrow> and remove all attributes - el._name = "mrow" + local newname = get_new_element_name("mrow", prefix) + el._name = newname el._attr = {} -- open must be first child, close needs to be last if open then el:add_child_node(open, 1) end @@ -131,7 +241,7 @@ local function fix_mfenced(el) end local function is_fence(el) - return el:get_element_name() == "mo" and el:get_attribute("fence") == "true" + return get_element_name(el) == "mo" and el:get_attribute("fence") == "true" end local function fix_mo_to_mfenced(el) @@ -155,25 +265,27 @@ local function fix_mo_to_mfenced(el) end end -- convert parent <mrow> to <mfenced> - parent._name = "mfenced" + local _, prefix = get_element_name(parent) + local newname = get_new_element_name("mfenced", prefix) + parent._name = newname parent._attr = {open = open, close = close} end end local function fix_numbers(el) -- convert <mn>1</mn><mo>.</mo><mn>3</mn> to <mn>1.3</mn> - if el:get_element_name() == "mn" then + if get_element_name(el) == "mn" then local n = el:get_sibling_node(1) -- test if next element is <mo class="MathClass-punc">.</mo> if n and n:is_element() - and n:get_element_name() == "mo" - and n:get_attribute("class") == "MathClass-punc" + and get_element_name(n) == "mo" + and get_attribute(n, "class") == "MathClass-punc" and n:get_text() == "." then -- get next element and test if it is <mn> local x = el:get_sibling_node(2) if x and x:is_element() - and x:get_element_name() == "mn" + and get_element_name(x) == "mn" then -- join numbers and set it as text content of the current element local newnumber = el:get_text() .. "." .. x:get_text() @@ -194,7 +306,7 @@ local function just_operators(list) -- count <mo> and return true if list contains just them local mo = 0 for _, x in ipairs(list) do - if x:get_element_name() == "mo" then mo = mo + 1 end + if get_element_name(x) == "mo" then mo = mo + 1 end end return mo end @@ -205,18 +317,22 @@ local function fix_operators(x) -- this fixes issues in LibreOffice with a^{*} -- I hope it doesn't introduce different issues -- process only <mo> - if x:get_element_name() ~= "mo" then return nil end + local el_name, prefix = get_element_name(x) + if el_name ~= "mo" then return nil end local siblings = x:get_siblings() -- test if current element list contains only <mo> if just_operators(siblings) == #siblings then if #siblings == 1 then - -- one <mo> translates to <mtext> - x._name = "mtext" - log:debug("changing one <mo> to <mtext>: " .. x:get_text()) - -- I think we should use <mi>, but LO incorrectly renders it in <msubsup>, - -- even if we use the mathvariant="normal" attribute. <mtext> works, so - -- we use that instead. - -- x:set_attribute("mathvariant", "normal") + if not x:get_attribute("stretchy") then + -- one <mo> translates to <mtext> + local newname = get_new_element_name("mtext", prefix) + x._name = newname + log:debug("changing one <mo> to <mtext>: " .. x:get_text()) + -- I think we should use <mi>, but LO incorrectly renders it in <msubsup>, + -- even if we use the mathvariant="normal" attribute. <mtext> works, so + -- we use that instead. + -- x:set_attribute("mathvariant", "normal") + end else -- multiple <mo> translate to <mtext> local text = {} @@ -231,7 +347,8 @@ local function fix_operators(x) log:debug("changing <mo> to <mtext>: " .. newtext) x:add_child_node(text_el) -- change <mo> to <mtext> - x._name = "mtext" + local newname = get_new_element_name("mtext", prefix) + x._name = newname -- remove subsequent <mo> for i = 2, #siblings do siblings[i]:remove_node() @@ -240,6 +357,47 @@ local function fix_operators(x) end end +local function is_last_element(el) + local siblings = el:get_siblings() + -- return true only if the current element is the last in the parent's children + for i = #siblings, 1, -1 do + local curr = siblings[i] + if curr == el then + return true + elseif curr:is_element() then + return false + end + end + return false +end + +local function is_empty_row(el) + -- empty row should contain only one <mtd> + local count = 0 + if el:get_text():match("^%s*$") then + for _, child in ipairs(el:get_children()) do + if child:is_element() then count = count + 1 end + end + end + -- if there is one or zero childrens, then it is empty row + return count < 2 +end + + +local function delete_last_empty_mtr(el) + -- arrays sometimes contain last empty row, which causes rendering issues, + -- so we should remove them + local el_name, prefix = get_element_name(el) + if el_name == "mtr" + and get_attribute(el, "class") == "array-row" + and is_last_element(el) + and is_empty_row(el) + then + el:remove_node() + end + +end + return function(dom) dom:traverse_elements(function(el) if settings.output_format ~= "odt" then @@ -248,12 +406,15 @@ return function(dom) else fix_mo_to_mfenced(el) end + fix_radicals(el) fix_token_elements(el) fix_nested_mstyle(el) + fix_missing_mtext(el) fix_numbers(el) fix_operators(el) fix_mathvariant(el) top_mrow(el) + delete_last_empty_mtr(el) end) return dom end diff --git a/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-inlinecss.lua b/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-inlinecss.lua new file mode 100644 index 00000000000..105c29d3c30 --- /dev/null +++ b/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-inlinecss.lua @@ -0,0 +1,16 @@ +local M = {} + +local filter = require "make4ht-domfilter" + +-- filters support only html formats +function M.test(format) + if format:match("html") then return true end + return false +end + +function M.modify_build(make) + local process = filter({"inlinecss"}, "inlinecss") + make:match("html?$", process) + return make +end +return M diff --git a/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-latexmk_build.lua b/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-latexmk_build.lua index bf4dcdde5a4..b9ed94b0dc7 100644 --- a/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-latexmk_build.lua +++ b/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-latexmk_build.lua @@ -12,8 +12,31 @@ function M.modify_build(make) first = pos end end + -- we need to save contents of the .tmp file, to prevent extra executions from latexmk + -- tex4ht command overwrites content that was set by LaTeX with it's own stuff + local tmp_file + make:add("save_tmp", function(par) + local f = io.open(par.input .. ".tmp", "r") + if f then + tmp_file = f:read("*all") + f:close() + end + return 0 + end) + make:add("load_tmp", function(par) + if tmp_file then + local f = io.open(par.input .. ".tmp", "w") + if f then + f:write(tmp_file) + end + end + return 0 + end) -- if htlatex was found if first then + -- handle tmp file + make:load_tmp {} + make:save_tmp {} -- add dummy latexmk call to the build sequence make:latexmk {} -- replace name, command and type in the first htlatex @@ -26,6 +49,21 @@ function M.modify_build(make) -- remove the dummy latexmk table.remove(build_seq) end + -- remove htlatex calls from the build sequence, they are unnecessary + local new_build_seq = {} + for pos, v in ipairs(build_seq) do + if v.name ~= "htlatex" and v.name ~= "tex4ht" then + table.insert(new_build_seq, v) + elseif v.name == "tex4ht" then + -- insert save_tmp before tex4ht + table.insert(new_build_seq, build_seq[#build_seq]) + -- remove save_tmp from the end + table.remove(build_seq) + -- and now insert tex4ht + table.insert(new_build_seq, v) + end + end + make.build_seq = new_build_seq return make end return M diff --git a/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-preprocess_input.lua b/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-preprocess_input.lua index 306c7bf7728..763c25ea7e5 100644 --- a/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-preprocess_input.lua +++ b/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-preprocess_input.lua @@ -6,7 +6,7 @@ local mkutils = require "mkutils" local commands = { knitr = { command = 'Rscript -e "library(knitr); knit(\'${tex_file}\', output=\'${tmp_file}\')"'}, pandoc = { command = 'pandoc -f ${input_format} -s -o \'${tmp_file}\' -t latex \'${tex_file}\''}, - render = { command = 'Rscript -e "library(rmarkdown); render(\'${tex_file}\', output_file=\'${tmp_file}\')"'} + render = { command = 'Rscript -e "library(rmarkdown); render(\'${tex_file}\', output_file=\'${tmp_file}\',output_format = \'latex_document\')"'} } local filetypes = { rnw = {sequence = {"knitr"} }, @@ -17,6 +17,21 @@ local filetypes = { rst = {sequence = {"pandoc"}, options = {input_format = "rst"}}, } +local function get_temp_name(arg,curr, length) + -- we don't want to use the temp dir, because graphics would be then generated outside of + -- the directory of the source document. so we will make + local tmp_name = os.tmpname() + if pos == sequence then + -- base tmp_name on the input name in the last step of sequence + -- so the generated images won't have random names + tmp_name = arg.input .. "-preprocess_input" + else + tmp_name = tmp_name:match("([^/\\]+)$") + end + return tmp_name +end + + local function execute_sequence(sequence, arg, make) -- keep track of all generated tmp files @@ -25,8 +40,8 @@ local function execute_sequence(sequence, arg, make) -- should become the tex_file for the next one. It doesn't -- matter that it isn't TeX file in some cases local previous_temp - for _, cmd_name in ipairs(sequence) do - local tmp_name = os.tmpname() + for pos, cmd_name in ipairs(sequence) do + local tmp_name = get_temp_name(arg,pos, #sequence) temp_files[#temp_files+1] = tmp_name -- make the temp file name accessible to the executed commands arg.tmp_file = tmp_name diff --git a/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-tidy.lua b/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-tidy.lua index 8318a8b8949..4bb0976b0d9 100644 --- a/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-tidy.lua +++ b/Master/texmf-dist/scripts/make4ht/extensions/make4ht-ext-tidy.lua @@ -44,9 +44,13 @@ function M.modify_build(make) local command = "tidy ${options} ${filename}" % par log:info("running tidy: ".. command) -- os.execute(command) - local run = io.popen(command, "r") + local run, msg = io.popen(command, "r") local result = run:read("*all") run:close() + if not result or result == "" then + log:warning("Cannot execute Tidy command") + return nil + end result = close_tags(result) local f = io.open(filename, "w") f:write(result) diff --git a/Master/texmf-dist/scripts/make4ht/formats/make4ht-jats.lua b/Master/texmf-dist/scripts/make4ht/formats/make4ht-jats.lua index 13bcd86d41e..41eabf87449 100644 --- a/Master/texmf-dist/scripts/make4ht/formats/make4ht-jats.lua +++ b/Master/texmf-dist/scripts/make4ht/formats/make4ht-jats.lua @@ -1,5 +1,168 @@ local M = {} local xtpipeslib = require "make4ht-xtpipes" +local domfilter = require "make4ht-domfilter" + + +-- some elements need to be moved from the document flow to the document meta +local article_meta +local elements_to_move_to_meta = {} +local function move_to_meta(el) + -- we don't move elements immediatelly, because it would prevent them from further + -- processing in the filter. so we save them in an array, and move them once + -- the full DOM was processed + table.insert(elements_to_move_to_meta, el) +end + +local elements_to_move_to_title = {} +local function move_to_title_group(el) + -- there can be only one title and subtitle + local name = el:get_element_name() + if not elements_to_move_to_title[name] then + elements_to_move_to_title[name] = el + end +end + +local elements_to_move_to_contribs = {} +local function move_to_contribs(el) + table.insert(elements_to_move_to_contribs, el) +end + + + +local function process_moves() + if article_meta then + if elements_to_move_to_title["article-title"] + and #article_meta:query_selector("title_group") == 0 then -- don't move anything if user added title_group from a config file + local title_group = article_meta:create_element("title_group") + for _, name in ipairs{ "article-title", "subtitle" } do + local v = elements_to_move_to_title[name] + if v then + title_group:add_child_node(v:copy_node()) + v:remove_node() + end + end + article_meta:add_child_node(title_group) + end + if #elements_to_move_to_contribs > 0 then + local contrib_group = article_meta:create_element("contrib-group") + for _, el in ipairs(elements_to_move_to_contribs) do + contrib_group:add_child_node(el:copy_node()) + el:remove_node() + end + article_meta:add_child_node(contrib_group) + end + for _, el in ipairs(elements_to_move_to_meta) do + -- move elemnt's copy, and remove the original + article_meta:add_child_node(el:copy_node()) + el:remove_node() + end + end +end + +local function has_no_text(el) + -- detect if element contains only whitespace + if el:get_text():match("^%s*$") then + --- if it contains any elements, it has text + for _, child in ipairs(el:get_children()) do + if child:is_element() then return false end + end + return true + end + return false +end + +local function is_xref_id(el) + return el:get_element_name() == "xref" and el:get_attribute("id") and el:get_attribute("rid") == nil and has_no_text(el) +end +-- set id to parent element for <xref> that contain only id +local function xref_to_id(el) + local parent = el:get_parent() + -- set id only if it doesn't exist yet + if parent:get_attribute("id") == nil then + parent:set_attribute("id", el:get_attribute("id")) + el:remove_node() + end +end + +local function make_text(el) + local text = el:get_text():gsub("^%s*", ""):gsub("%s*$", "") + local text_el = el:create_text_node(text) + el._children = {text_el} +end + +local function is_empty_par(el) + return el:get_element_name() == "p" and has_no_text(el) +end + +local function handle_links(el, params) + -- we must distinguish between internal links in the document, and external links + -- to websites etc. these needs to be changed to the <ext-link> element. + local link = el:get_attribute("rid") + if link then + -- try to remove \jobname.xml from the beginning of the link + -- if the rest starts with #, then it is an internal link + local local_link = link:gsub("^" .. params.input .. ".xml", "") + if local_link:match("^%#") then + el:set_attribute("rid", local_link) + else + -- change element to ext-link for extenal links + el._name = "ext-link" + el:set_attribute("rid", nil) + el:set_attribute("xlink:href", link) + end + end +end + +local function handle_maketitle(el) + -- <maketitle> is special element produced by TeX4ht from LaTeX's \maketitle + -- we need to pick interesting info from there, and move it to the header + local function is_empty(selector) + return #article_meta:query_selector(selector) == 0 + end + -- move <aff> to <contrib> + local affiliations = {} + for _, aff in ipairs(el:query_selector("aff")) do + local id = aff:get_attribute("id") + if id then + for _,mark in ipairs(aff:query_selector("affmark")) do mark:remove_node() end + affiliations[id] = aff:copy_node() + end + end + if is_empty("contrib") then + for _, contrib in ipairs(el:query_selector("contrib")) do + for _, affref in ipairs(contrib:query_selector("affref")) do + local id = affref:get_attribute("rid") or "" + -- we no longer need this node + affref:remove_node() + local linked_affiliation = affiliations[id] + if linked_affiliation then + contrib:add_child_node(linked_affiliation) + end + end + for _, string_name in ipairs(contrib:query_selector("string-name")) do + make_text(string_name) + end + move_to_contribs(contrib:copy_node()) + -- we need to remove it from here, even though we remove <maketitle> later + -- we got doubgle contributors without that + contrib:remove_node() + end + end + if is_empty("pub-date") then + for _, date in ipairs(el:query_selector("date")) do + date._name = "pub-date" + for _, s in ipairs(date:query_selector("string-date")) do + make_text(s) + end + move_to_meta(date:copy_node()) + end + end + el:remove_node() +end + + + + function M.prepare_parameters(settings, extensions) settings.tex4ht_sty_par = settings.tex4ht_sty_par ..",jats" @@ -11,4 +174,49 @@ function M.prepare_extensions(extensions) return extensions end +function M.modify_build(make) + filter_settings("joincharacters", {charclasses = {italic=true, bold=true}}) + + local process = domfilter { + function(dom, params) + dom:traverse_elements(function(el) + -- some elements need special treatment + local el_name = el:get_element_name() + if is_xref_id(el) then + xref_to_id(el) + elseif el_name == "article-meta" then + -- save article-meta element for further processig + article_meta = el + elseif el_name == "article-title" then + move_to_title_group(el) + elseif el_name == "subtitle" then + move_to_title_group(el) + elseif el_name == "abstract" then + move_to_meta(el) + elseif el_name == "string-name" then + make_text(el) + elseif el_name == "contrib" then + move_to_contribs(el) + elseif is_empty_par(el) then + -- remove empty paragraphs + el:remove_node() + elseif el_name == "xref" then + handle_links(el, params) + elseif el_name == "maketitle" then + handle_maketitle(el) + elseif el_name == "div" and el:get_attribute("class") == "maketitle" then + el:remove_node() + end + + end) + -- move elements that are marked for move + process_moves() + return dom + end, "joincharacters","mathmlfixes", "tablerows","booktabs" + } + local charclasses = {["mml:mi"] = true, ["mml:mn"] = true , italic = true, bold=true, roman = true, ["mml:mtext"] = true, mi=true, mn=true} + make:match("xml$", process, {charclasses = charclasses}) + return make +end + return M diff --git a/Master/texmf-dist/scripts/make4ht/formats/make4ht-odt.lua b/Master/texmf-dist/scripts/make4ht/formats/make4ht-odt.lua index 3f0ee3aaa89..7511ed481d0 100644 --- a/Master/texmf-dist/scripts/make4ht/formats/make4ht-odt.lua +++ b/Master/texmf-dist/scripts/make4ht/formats/make4ht-odt.lua @@ -291,6 +291,9 @@ function M.modify_build(make) local fixentities = filter {"entities-to-unicode", remove_xtpipes} make:match("4oo", fixentities) make:match("4om", fixentities) + -- we must handle outdir. make4ht copies the ODT file before it was packed, so + -- we will copy it again after packing later in this format file + local outdir = make.params["outdir"] -- build the ODT file. This match must be executed as a last one -- this will be executed as a first match, just to find the last filename @@ -305,7 +308,7 @@ function M.modify_build(make) local lastfile = escape_file(lgfiles[#lgfiles]) .."$" -- make match for the last file -- odt packing will be done here - make:match(lastfile, function() + make:match(lastfile, function(filename, par) local groups = prepare_output_files(make.lgfile.files) local basename = groups.odt[1] local odtname = basename .. ".odt" @@ -367,6 +370,12 @@ function M.modify_build(make) end) odt:pack() + if outdir and outdir ~= "" then + local filename = odt.name + local outfilename = outdir .. "/" .. filename + log:info("Copying ODT file to the output dir: " .. outfilename) + mkutils.copy(filename,outfilename) + end end) end executed = true diff --git a/Master/texmf-dist/scripts/make4ht/make4ht b/Master/texmf-dist/scripts/make4ht/make4ht index 7d579fafeaa..f6358956774 100755 --- a/Master/texmf-dist/scripts/make4ht/make4ht +++ b/Master/texmf-dist/scripts/make4ht/make4ht @@ -29,7 +29,7 @@ make4ht [options] filename ["tex4ht.sty op." "tex4ht op." "t4ht op" "latex op"] -- set version number. the template should be replaced by the -- actual version number by the build script -local version = "v0.3l" +local version = "v0.3m" mkparams.version_number = version local args = mkparams.get_args() @@ -120,7 +120,13 @@ make:match("tmp$", function(filename,params) make:match(".*",function(filename,par) local outdir = '' --par["outdir"] and par["outdir"] .."/" or '' - if par['outdir'] ~= "" then outdir = par['outdir'] .. '/' end + if par['outdir'] ~= "" then + outdir = par['outdir'] .. '/' + else + -- don't run unnecessary copy without output dir + log:info("No output directory") + return true + end log:info("outdir: "..outdir) local outfilename = outdir .. filename mkutils.copy(filename,outfilename) diff --git a/Master/texmf-dist/scripts/make4ht/make4ht-indexing.lua b/Master/texmf-dist/scripts/make4ht/make4ht-indexing.lua index eb9c9b50172..746c062cb31 100755 --- a/Master/texmf-dist/scripts/make4ht/make4ht-indexing.lua +++ b/Master/texmf-dist/scripts/make4ht/make4ht-indexing.lua @@ -80,7 +80,7 @@ local parse_idx = function(content) elseif line:match("^\\indexentry") then -- replace the page number with the current -- index entry number - local result = line:gsub("{[0-9]+}", "{"..current_entry .."}") + local result = line:gsub("{[0-9]+}$", "{"..current_entry .."}") buffer[#buffer+1] = get_utf8(result) else buffer[#buffer+1] = line @@ -96,11 +96,14 @@ local fix_idx_pages = function(content, idxobj) local entries = idxobj.map for line in content:gmatch("([^\n]+)") do local line = line:gsub("(%s*\\%a+.-%,)(.+)$", function(start,rest) + -- there is a problem when index term itself contains numbers, like Bible verses (1:2), + -- because they will be detected as page numbers too. I cannot find a good solution + -- that wouldn't break something else. return start .. rest:gsub("(%d+)", function(page) local entry = entries[tonumber(page)] if entry then -- construct link to the index entry - return "\\Link[" .. entry.file .."]{".. entry.dest .."}{}" .. page .."\\EndLink{}" + return "\\Link[" .. entry.file .."]{".. entry.dest .."}{}" .. page .."\\EndLink{}" else return page end @@ -148,6 +151,7 @@ end local prepare_tmp_idx = function(par) par.idxfile = get_idxname(par) + if not par.idxfile or not mkutils.file_exists(par.idxfile) then return nil, "Cannot load idx file " .. (par.idxfile or "''") end -- construct the .ind name, based on the .idx name par.indfile = par.indfile or par.idxfile:gsub("idx$", "ind") load_enc() @@ -166,6 +170,7 @@ local splitindex = function(par) local idxfiles = {} local buffer local idxfile = get_idxname(par) + if not idxfile or not mkutils.file_exists(idxfile) then return nil, "Cannot load idx file " .. (idxfile or "''") end for line in io.lines(idxfile) do local file = line:match("indexentry%[(.-)%]") if file then @@ -198,7 +203,7 @@ local function run_indexing_command (command, par) local cmd_name = command:match("^[%a]+") or "indexing" local xindylog = logging.new(cmd_name) -- support split index - local subindexes = splitindex(par) + local subindexes = splitindex(par) or {} if #subindexes > 0 then -- call the command again on all files produced by splitindex for _, subindex in ipairs(subindexes) do diff --git a/Master/texmf-dist/scripts/make4ht/mkutils.lua b/Master/texmf-dist/scripts/make4ht/mkutils.lua index 6bcc4787c39..f7636b9d2a6 100755 --- a/Master/texmf-dist/scripts/make4ht/mkutils.lua +++ b/Master/texmf-dist/scripts/make4ht/mkutils.lua @@ -7,17 +7,17 @@ local mkparams = require("mkparams") local indexing = require("make4ht-indexing") --template engine function interp(s, tab) - local tab = tab or {} - return (s:gsub('($%b{})', function(w) return tab[w:sub(3, -2)] or w end)) + local tab = tab or {} + return (s:gsub('($%b{})', function(w) return tab[w:sub(3, -2)] or w end)) end --print( interp("${name} is ${value}", {name = "foo", value = "bar"}) ) function addProperty(s,prop) - if prop ~=nil then - return s .." "..prop - else - return s - end + if prop ~=nil then + return s .." "..prop + else + return s + end end getmetatable("").__mod = interp getmetatable("").__add = addProperty @@ -39,27 +39,27 @@ function merge(t1, t2) end function string:split(sep) - local sep, fields = sep or ":", {} - local pattern = string.format("([^%s]+)", sep) - self:gsub(pattern, function(c) fields[#fields+1] = c end) - return fields + local sep, fields = sep or ":", {} + local pattern = string.format("([^%s]+)", sep) + self:gsub(pattern, function(c) fields[#fields+1] = c end) + return fields end function remove_extension(path) - local found, len, remainder = string.find(path, "^(.*)%.[^%.]*$") - if found then - return remainder - else - return path - end + local found, len, remainder = string.find(path, "^(.*)%.[^%.]*$") + if found then + return remainder + else + return path + end end -- -- check if file exists function file_exists(file) - local f = io.open(file, "rb") - if f then f:close() end - return f ~= nil + local f = io.open(file, "rb") + if f then f:close() end + return f ~= nil end -- check if Lua module exists @@ -90,18 +90,18 @@ function parse_lg(filename) else local usedfiles={} for line in io.lines(filename) do - --- needs --- pokus.idv[1] ==> pokus0x.png --- + --- needs --- pokus.idv[1] ==> pokus0x.png --- -- line:gsub("needs --- (.+?)[([0-9]+) ==> ([%a%d%p%.%-%_]*)",function(name,page,k) table.insert(outputimages,k)end) - line:gsub("needs %-%-%- (.+)%[([0-9]+)%] ==> ([%a%d%p%.%-%_]*)", - function(file,page,output) - local rec = { - source = file, - page=page, - output = output - } - table.insert(outputimages,rec) - end - ) + line:gsub("needs %-%-%- (.+)%[([0-9]+)%] ==> (.*) %-%-%-", + function(file,page,output) + local rec = { + source = file, + page=page, + output = output + } + table.insert(outputimages,rec) + end + ) line:gsub("File: (.*)", function(k) if not usedfiles[k] then table.insert(outputfiles,k) @@ -137,20 +137,20 @@ function cp(src,dest) -- try to find file using kpse library if it cannot be found src = kpse.find_file(src) or src end - local command = string.format('%s "%s" "%s"', cp_func, src, dest) - if cp_func == "copy" then command = command:gsub("/",'\\') end - log:info("Copy: "..command) + local command = string.format('%s "%s" "%s"', cp_func, src, dest) + if cp_func == "copy" then command = command:gsub("/",'\\') end + log:info("Copy: "..command) if not file_exists(src) then log:error("File " .. src .. " doesn't exist") end - os.execute(command) + os.execute(command) end function mv(src, dest) local mv_func = os.type == "unix" and "mv " or "move " - local command = string.format('%s "%s" "%s"', mv_func, src, dest) + local command = string.format('%s "%s" "%s"', mv_func, src, dest) -- fix windows paths - if mv_func == "move" then command = command:gsub("/",'\\') end + if mv_func == "move" then command = command:gsub("/",'\\') end log:info("Move: ".. command) os.execute(command) end @@ -163,61 +163,61 @@ end local used_dir = {} function prepare_path(path) - --local dirs = path:split("/") - local dirs = {} - if path:match("^/") then dirs = {""} - elseif path:match("^~") then - local home = os.getenv "HOME" - dirs = home:split "/" - path = path:gsub("^~/","") - table.insert(dirs,1,"") - end - if path:match("/$")then path = path .. " " end - for _,d in pairs(path:split "/") do - table.insert(dirs,d) - end - table.remove(dirs,#dirs) - return dirs,table.concat(dirs,"/") + --local dirs = path:split("/") + local dirs = {} + if path:match("^/") then dirs = {""} + elseif path:match("^~") then + local home = os.getenv "HOME" + dirs = home:split "/" + path = path:gsub("^~/","") + table.insert(dirs,1,"") + end + if path:match("/$")then path = path .. " " end + for _,d in pairs(path:split "/") do + table.insert(dirs,d) + end + table.remove(dirs,#dirs) + return dirs,table.concat(dirs,"/") end -- Find which part of path already exists -- and which directories have to be created function find_directories(dirs, pos) - local pos = pos or #dirs - -- we tried whole path and no dir exist - if pos < 1 then return dirs end - local path = "" - -- in the case of unix absolute path, empty string is inserted in dirs - if pos == 1 and dirs[pos] == "" then - path = "/" - else - path = table.concat(dirs,"/", 1,pos) .. "/" - end - if not lfs.chdir(path) then -- recursion until we succesfully changed dir - -- or there are no elements in the dir table - return find_directories(dirs,pos - 1) + local pos = pos or #dirs + -- we tried whole path and no dir exist + if pos < 1 then return dirs end + local path = "" + -- in the case of unix absolute path, empty string is inserted in dirs + if pos == 1 and dirs[pos] == "" then + path = "/" + else + path = table.concat(dirs,"/", 1,pos) .. "/" + end + if not lfs.chdir(path) then -- recursion until we succesfully changed dir + -- or there are no elements in the dir table + return find_directories(dirs,pos - 1) elseif pos ~= #dirs then -- if we succesfully changed dir - -- and we have dirs to create - local p = {} - for i = pos+1, #dirs do - table.insert(p, dirs[i]) - end - return p + -- and we have dirs to create + local p = {} + for i = pos+1, #dirs do + table.insert(p, dirs[i]) + end + return p else -- whole path exists - return {} + return {} end end function mkdirectories(dirs) - if type(dirs) ~="table" then - return false, "mkdirectories: dirs is not table" - end - for _,d in ipairs(dirs) do - local stat,msg = lfs.mkdir(d) - if not stat then return false, "makedirectories error: "..msg end - lfs.chdir(d) - end - return true + if type(dirs) ~="table" then + return false, "mkdirectories: dirs is not table" + end + for _,d in ipairs(dirs) do + local stat,msg = lfs.mkdir(d) + if not stat then return false, "makedirectories error: "..msg end + lfs.chdir(d) + end + return true end function copy_filter(src,dest, filter) @@ -233,22 +233,22 @@ end function copy(filename,outfilename) - local currdir = lfs.currentdir() - if filename == outfilename then return true end - local parts, path = prepare_path(outfilename) - if not used_dir[path] then - local to_create, msg = find_directories(parts) - if not to_create then - log:warning(msg) - return false - end - used_dir[path] = true - local stat, msg = mkdirectories(to_create) - if not stat then log:warning(msg) end - end - lfs.chdir(currdir) - cp(filename, path) - return true + local currdir = lfs.currentdir() + if filename == outfilename then return true end + local parts, path = prepare_path(outfilename) + if not used_dir[path] then + local to_create, msg = find_directories(parts) + if not to_create then + log:warning(msg) + return false + end + used_dir[path] = true + local stat, msg = mkdirectories(to_create) + if not stat then log:warning(msg) end + end + lfs.chdir(currdir) + cp(filename, path) + return true end function execute(command) @@ -373,11 +373,14 @@ env.Make:add("httex", htlatex.httex, { env.Make:add("latexmk", function(par) local settings = get_filter_settings "htlatex" or {} par.interaction = par.interaction or settings.interaction or "batchmode" - local command = Make.latex_command + local command = Make.latex_command + -- add " %O " after the engine name. it should be filled by latexmk + command = command:gsub("%s", " %%O ", 1) par.expanded = command % par -- quotes in latex_command must be escaped, they cause Latexmk error par.expanded = par.expanded:gsub('"', '\\"') - local newcommand = 'latexmk -latex="${expanded}" -dvi ${tex_file}' % par + local newcommand = 'latexmk -pdf- -ps- -auxdir=. -outdir=. -latex="${expanded}" -dvi -jobname=${input} ${tex_file}' % par + log:info("LaTeX call: " .. newcommand) os.execute(newcommand) return Make.testlogfile(par) end, {correct_exit= 0}) @@ -406,7 +409,7 @@ env.Make:add("tex4ht",function(par) log:info("executing: " .. command) return execute(command) end - , nil, 1) +, nil, 1) env.Make:add("t4ht","t4ht ${t4ht_par} \"${input}.${ext}\"",{ext="dvi"},1) env.Make:add("clean", function(par) @@ -439,7 +442,7 @@ env.Make:add("clean", function(par) end Make:match("tmp$", function() -- remove temporary and auxilary files - for _,ext in ipairs {"aux", "xref", "tmp", "4tc", "4ct", "idv", "lg","dvi", "log"} do + for _,ext in ipairs {"aux", "xref", "tmp", "4tc", "4ct", "idv", "lg","dvi", "log", "ncx"} do remove_file(main_name .. "." .. ext) end end) |