diff options
author | Karl Berry <karl@freefriends.org> | 2017-04-27 16:43:40 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2017-04-27 16:43:40 +0000 |
commit | a2a03aa6230e0fdc8d5a7922f2c0c23c05915fe1 (patch) | |
tree | 4e8dc79aacfc86534f6feb0f55794d16556ba61c | |
parent | b22ccce5b0f563434ae23f9f1f9481829739aa89 (diff) |
make4ht (27apr17)
git-svn-id: svn://tug.org/texlive/trunk@44079 c570f23f-e606-0410-a88d-b1316a301751
-rwxr-xr-x | Build/source/texk/texlive/linked_scripts/make4ht/make4ht | 5 | ||||
-rwxr-xr-x | Build/source/texk/texlive/linked_scripts/texlive/tlmgr.pl | 11 | ||||
-rwxr-xr-x | Build/source/texk/texlive/linked_scripts/texlive/updmap.pl | 13 | ||||
-rw-r--r-- | Master/texmf-dist/doc/support/make4ht/README | 55 | ||||
-rw-r--r-- | Master/texmf-dist/doc/support/make4ht/changelog.tex | 55 | ||||
-rw-r--r-- | Master/texmf-dist/doc/support/make4ht/make4ht-doc.pdf | bin | 62872 -> 66961 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/support/make4ht/make4ht-doc.tex | 3 | ||||
-rw-r--r-- | Master/texmf-dist/doc/support/make4ht/readme.tex | 51 | ||||
-rw-r--r-- | Master/texmf-dist/scripts/make4ht/filters/make4ht-fix-links.lua | 19 | ||||
-rwxr-xr-x | Master/texmf-dist/scripts/make4ht/make4ht | 5 | ||||
-rwxr-xr-x | Master/texmf-dist/scripts/make4ht/make4ht-dom.lua | 448 | ||||
-rwxr-xr-x | Master/texmf-dist/scripts/make4ht/make4ht-lib.lua | 30 | ||||
-rwxr-xr-x | Master/texmf-dist/scripts/make4ht/mathnode.lua | 87 | ||||
-rwxr-xr-x | Master/texmf-dist/scripts/make4ht/mkparams.lua | 19 | ||||
-rwxr-xr-x | Master/texmf-dist/scripts/make4ht/mkutils.lua | 13 |
15 files changed, 764 insertions, 50 deletions
diff --git a/Build/source/texk/texlive/linked_scripts/make4ht/make4ht b/Build/source/texk/texlive/linked_scripts/make4ht/make4ht index 49b1d0159a5..15bda54aca8 100755 --- a/Build/source/texk/texlive/linked_scripts/make4ht/make4ht +++ b/Build/source/texk/texlive/linked_scripts/make4ht/make4ht @@ -24,6 +24,11 @@ make4ht [options] filename ["tex4ht.sty op." "tex4ht op." "t4ht op" "latex op"] <filename> (string) Input file name ]] +-- set version number. the template should be replaced by the +-- actual version number by the build script +local version = "v0.1c" +mkparams.version_number = version + local args = mkparams.get_args() local parameters = mkparams.process_args(args) diff --git a/Build/source/texk/texlive/linked_scripts/texlive/tlmgr.pl b/Build/source/texk/texlive/linked_scripts/texlive/tlmgr.pl index a0a0d79733e..d365acb2dd0 100755 --- a/Build/source/texk/texlive/linked_scripts/texlive/tlmgr.pl +++ b/Build/source/texk/texlive/linked_scripts/texlive/tlmgr.pl @@ -1,13 +1,13 @@ #!/usr/bin/env perl -# $Id: tlmgr.pl 43940 2017-04-20 14:47:49Z preining $ +# $Id: tlmgr.pl 43990 2017-04-23 13:21:28Z preining $ # # Copyright 2008-2017 Norbert Preining # This file is licensed under the GNU General Public License version 2 # or any later version. # -my $svnrev = '$Revision: 43940 $'; -my $datrev = '$Date: 2017-04-20 16:47:49 +0200 (Thu, 20 Apr 2017) $'; +my $svnrev = '$Revision: 43990 $'; +my $datrev = '$Date: 2017-04-23 15:21:28 +0200 (Sun, 23 Apr 2017) $'; my $tlmgrrevision; my $prg; if ($svnrev =~ m/: ([0-9]+) /) { @@ -6689,6 +6689,11 @@ sub action_shell { } else { print "OK\n"; } + # make sure that we restart after having called update --self! + if (($cmd eq 'update') && $opts{'self'}) { + print "tlmgr has been updated, restarting!\n"; + exec("tlmgr", @::SAVEDARGV); + } %opts = %savedopts; } else { print "ERROR unknown command\n"; diff --git a/Build/source/texk/texlive/linked_scripts/texlive/updmap.pl b/Build/source/texk/texlive/linked_scripts/texlive/updmap.pl index e7cadcfc0d4..a8d9ff67293 100755 --- a/Build/source/texk/texlive/linked_scripts/texlive/updmap.pl +++ b/Build/source/texk/texlive/linked_scripts/texlive/updmap.pl @@ -1,5 +1,5 @@ #!/usr/bin/env perl -# $Id: updmap.pl 43794 2017-04-15 00:12:54Z preining $ +# $Id: updmap.pl 44056 2017-04-26 08:14:28Z preining $ # updmap - maintain map files for outline fonts. # (Maintained in TeX Live:Master/texmf-dist/scripts/texlive.) # @@ -14,7 +14,7 @@ # the original versions were licensed under the following agreement: # Anyone may freely use, modify, and/or distribute this file, without -my $svnid = '$Id: updmap.pl 43794 2017-04-15 00:12:54Z preining $'; +my $svnid = '$Id: updmap.pl 44056 2017-04-26 08:14:28Z preining $'; my $TEXMFROOT; BEGIN { @@ -27,10 +27,10 @@ BEGIN { unshift(@INC, "$TEXMFROOT/tlpkg"); } -my $lastchdate = '$Date: 2017-04-15 02:12:54 +0200 (Sat, 15 Apr 2017) $'; +my $lastchdate = '$Date: 2017-04-26 10:14:28 +0200 (Wed, 26 Apr 2017) $'; $lastchdate =~ s/^\$Date:\s*//; $lastchdate =~ s/ \(.*$//; -my $svnrev = '$Revision: 43794 $'; +my $svnrev = '$Revision: 44056 $'; $svnrev =~ s/^\$Revision:\s*//; $svnrev =~ s/\s*\$$//; my $version = "r$svnrev ($lastchdate)"; @@ -1476,6 +1476,11 @@ sub enable_disable_maps { if ($w =~ m/=/) { # this is --enable MapType=MapName my ($type, $map) = split ('=', $w); + # allow for all lowercase map types (map/mixedmap/kanjimap) + $type =~ s/map$/Map/; + $type = ucfirst($type); + # don't allow for map names containing / + die "$prg: map files cannot be relative/absolute paths: $map\n" if ($map =~ m{/}) enable_map($tc, $type, $map); } else { # this is --disable MapName diff --git a/Master/texmf-dist/doc/support/make4ht/README b/Master/texmf-dist/doc/support/make4ht/README index c3c689c87ae..9d7c10c75b4 100644 --- a/Master/texmf-dist/doc/support/make4ht/README +++ b/Master/texmf-dist/doc/support/make4ht/README @@ -60,9 +60,12 @@ Sample: Make:htlatex() Make:match("html$", "tidy -m -xml -utf8 -q -i ${filename}") - `Make:htlatex()` is preconfigured command for calling LaTeX with `tex4ht` loaded on the input file. In this case it will be called one time. After compilation, `tidy` command is executed on the output `html` file. +`Make:htlatex()` is preconfigured command for calling LaTeX with `tex4ht` +loaded on the input file. In this case it will be called one time. After +compilation, `tidy` command is executed on the output `html` file. -Note that you don't have to call `tex4ht` and `t4ht` commands explicitly in the build file, they are called automatically. +Note that you don't have to call `tex4ht` and `t4ht` commands explicitly in the +build file, they are called automatically. You can add more commands like `Make:htlatex` with @@ -76,7 +79,11 @@ it can be called with `command` can be text template, or function: Make:add("text", "hello, input file: ${input}") - Make:add("function", function(params) for k, v in pairs(params) do print(k..": "..v) end) + Make:add("function", function(params) + for k, v in pairs(params) do + print(k..": "..v) + end + ) `parameters` is a table or `nil` value. @@ -101,7 +108,7 @@ latex_par packages : insert additionl LaTeX code which is inserted before `\documentclass`. - useful for passing options to packages or additional packages loading + Useful for passing options to packages or additional packages loading tex4ht_sty_par @@ -125,7 +132,8 @@ repetition correct_exit -: expected `exit code` from the command. +: expected `exit code` from the command. The compilation will be terminted + when the command `exit code` is different. You may add your own parameters, they will be accessible in templates and @@ -138,9 +146,9 @@ multiple times if you include them in the build file, because they would be called also by `make4ht`. With `repetition`, second execution is blocked. You can set expected exit code from a command with `correct_exit`. Compilation -is stopped when command returns different exit code. Situation is little bit -difficult with LaTeX (all engines and formats in fact), because it doesn't -differentiate between fatal and non fatal errors and returns same exit code +is stopped when command returns different exit code. The situation is +different for LaTeX (for all TeX engines and formats, in fact), because it doesn't +differentiate between fatal and non fatal errors, and it returns the same exit code in all cases. Log parsing is used because of that, error code `1` is returned in the case of fatal error, `0` is used otherwise. @@ -193,10 +201,18 @@ hruletohr : `\hrule` commands are translated to series of underscore characters by `tex4ht`, this filter translate these underscores to `<hr>` elements + entites -: convert prohibited named entities to numeric entities (currently, only ` `, as it causes validation errors, and `tex4ht` is producing it sometimes +: convert prohibited named entities to numeric entities (currently, only + ` `, as it causes validation errors, and `tex4ht` is producing it + sometimes + +fix-links +: replace colons in local links and `id` attributes with underscores. Some + cross-reference commands may produce colons in internal links, which results in + validation error. Function `filter` accepts also function arguments, in this case this function takes file contents as parameter and modified contents are returned. @@ -222,7 +238,7 @@ These pictures are stored in special `dvi` file, on which `dvi to image` commands are called. This conversion is normally configured in the `env file`, -which is system dependent and which has a little bit unintuitive syntax. +which is system dependent and which has a bit unintuitive syntax. This configuration is processed by `t4ht` application and conversion commands are called for all pictures. @@ -243,9 +259,9 @@ There are three parameters: - source - `dvi` file with the pictures - page - page number of the converted image -## `mode` variable +## The `mode` variable -Variable `mode` contains contents of `-mode` command line option. +The `mode` variable contains contents of `--mode` command line option. It can be used to run some commands conditionally. For example: if mode == "draft" then @@ -256,11 +272,22 @@ It can be used to run some commands conditionally. For example: Make:htlatex{} end -In this example (which is default configuration used by `make4ht`), -LaTeX is called only once when `make4ht` is called with +In this example (which is the default configuration used by `make4ht`), +LaTeX is called only once when `make4ht` is called with `draft` mode: make4ht -m draft filename +## The `settings` table + +You may want to access to the parameters also outside commands, file matches +and image conversion functions. For example, if you want to convert your file to +the `OpenDocument Format`, you can use the following settings, based on `oolatex` +command: + + settings.tex4ht_sty_par = settings.tex4ht_sty_par ..",ooffice" + settings.tex4ht_par = settings.tex4ht_par .. " ooffice/! -cmozhtf" + settings.t4ht_par = settings.t4ht_par .. " -cooxtpipes -coo " + # Command line options diff --git a/Master/texmf-dist/doc/support/make4ht/changelog.tex b/Master/texmf-dist/doc/support/make4ht/changelog.tex index b69cd5d7829..752787d1594 100644 --- a/Master/texmf-dist/doc/support/make4ht/changelog.tex +++ b/Master/texmf-dist/doc/support/make4ht/changelog.tex @@ -2,6 +2,61 @@ \begin{itemize} \item + 2017/04/26 + + \begin{itemize} + \itemsep1pt\parskip0pt\parsep0pt + \item + Released version \texttt{v0.1c} + \end{itemize} +\item + 2017/03/16 + + \begin{itemize} + \itemsep1pt\parskip0pt\parsep0pt + \item + check for \texttt{TeX capacity exceeded} error in the \LaTeX~run. + \end{itemize} +\item + 2016/12/19 + + \begin{itemize} + \itemsep1pt\parskip0pt\parsep0pt + \item + use full input name in \texttt{tex\_file} variable. This should + enable use of files without \texttt{.tex} extension. + \end{itemize} +\item + 2016/10/22 + + \begin{itemize} + \itemsep1pt\parskip0pt\parsep0pt + \item + new command available in the build file: + \texttt{Make:add\_file(filename)}. This enables filters and commands + to register files to the output. + \item + use ipairs instead of pairs for traversing files and executing + filters. This should ensure correct order of executions. + \end{itemize} +\item + 2016/10/18 + + \begin{itemize} + \itemsep1pt\parskip0pt\parsep0pt + \item + new filter: replace colons in \texttt{id} and \texttt{href} + attributes with underscores + \end{itemize} +\item + 2016/01/11 + + \begin{itemize} + \itemsep1pt\parskip0pt\parsep0pt + \item + fixed bug in loading documents with full path specified + \end{itemize} +\item 2015/12/06 version 0.1b \begin{itemize} 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 91bd73fe761..2867bf29dc0 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/make4ht-doc.tex b/Master/texmf-dist/doc/support/make4ht/make4ht-doc.tex index 9c9a5eeddf8..973a349c6ce 100644 --- a/Master/texmf-dist/doc/support/make4ht/make4ht-doc.tex +++ b/Master/texmf-dist/doc/support/make4ht/make4ht-doc.tex @@ -11,10 +11,11 @@ \setmainfont{TeX Gyre Schola} \fi \usepackage{microtype} +\providecommand\tightlist{\relax} \title{The \texttt{make4ht} build system} \author{Michal Hoftich\footnote{\url{michal.h21@gmail.com}}} -\date{Version 0.1b\\12/11/2015} +\date{Version \version\\\gitdate} \begin{document} \maketitle \tableofcontents diff --git a/Master/texmf-dist/doc/support/make4ht/readme.tex b/Master/texmf-dist/doc/support/make4ht/readme.tex index 83244743deb..77e1ecdc6b1 100644 --- a/Master/texmf-dist/doc/support/make4ht/readme.tex +++ b/Master/texmf-dist/doc/support/make4ht/readme.tex @@ -93,7 +93,11 @@ Make:name() \begin{verbatim} Make:add("text", "hello, input file: ${input}") -Make:add("function", function(params) for k, v in pairs(params) do print(k..": "..v) end) +Make:add("function", function(params) + for k, v in pairs(params) do + print(k..": "..v) + end +) \end{verbatim} \texttt{parameters} is a table or \texttt{nil} value. @@ -111,7 +115,7 @@ input TeX file parameters to \texttt{latex} \item[packages] insert additionl LaTeX code which is inserted before -\texttt{\textbackslash{}documentclass}. useful for passing options to +\texttt{\textbackslash{}documentclass}. Useful for passing options to packages or additional packages loading \item[tex4ht\_sty\_par] parameters to \texttt{tex4ht.sty} @@ -124,7 +128,8 @@ output directory \item[repetition] limit number of command execution. \item[correct\_exit] -expected \texttt{exit code} from the command. +expected \texttt{exit code} from the command. The compilation will be +terminted when the command \texttt{exit code} is different. \end{description} You may add your own parameters, they will be accessible in templates @@ -139,11 +144,11 @@ in the build file, because they would be called also by You can set expected exit code from a command with \texttt{correct\_exit}. Compilation is stopped when command returns -different exit code. Situation is little bit difficult with LaTeX (all -engines and formats in fact), because it doesn't differentiate between -fatal and non fatal errors and returns same exit code in all cases. Log -parsing is used because of that, error code \texttt{1} is returned in -the case of fatal error, \texttt{0} is used otherwise. +different exit code. The situation is different for LaTeX (for all TeX +engines and formats, in fact), because it doesn't differentiate between +fatal and non fatal errors, and it returns the same exit code in all +cases. Log parsing is used because of that, error code \texttt{1} is +returned in the case of fatal error, \texttt{0} is used otherwise. \subsection{File matches}\label{file-matches} @@ -197,6 +202,10 @@ underscores to \texttt{\textless{}hr\textgreater{}} elements convert prohibited named entities to numeric entities (currently, only \texttt{\ }, as it causes validation errors, and \texttt{tex4ht} is producing it sometimes +\item[fix-links] +replace colons in local links and \texttt{id} attributes with +underscores. Some cross-reference commands may produce colons in +internal links, which results in validation error. \end{description} Function \texttt{filter} accepts also function arguments, in this case @@ -226,7 +235,7 @@ These pictures are stored in special \texttt{dvi} file, on which \texttt{dvi to image} commands are called. This conversion is normally configured in the \texttt{env file}, which -is system dependent and which has a little bit unintuitive syntax. This +is system dependent and which has a bit unintuitive syntax. This configuration is processed by \texttt{t4ht} application and conversion commands are called for all pictures. @@ -254,10 +263,11 @@ There are three parameters: page - page number of the converted image \end{itemize} -\subsection{\texttt{mode} variable}\label{mode-variable} +\subsection{The \texttt{mode} variable}\label{the-mode-variable} -Variable \texttt{mode} contains contents of \texttt{-mode} command line -option. It can be used to run some commands conditionally. For example: +The \texttt{mode} variable contains contents of \texttt{-{}-mode} +command line option. It can be used to run some commands conditionally. +For example: \begin{verbatim} if mode == "draft" then @@ -269,14 +279,27 @@ option. It can be used to run some commands conditionally. For example: end \end{verbatim} -In this example (which is default configuration used by +In this example (which is the default configuration used by \texttt{make4ht}), LaTeX is called only once when \texttt{make4ht} is -called with +called with \texttt{draft} mode: \begin{verbatim} make4ht -m draft filename \end{verbatim} +\subsection{The \texttt{settings} table}\label{the-settings-table} + +You may want to access to the parameters also outside commands, file +matches and image conversion functions. For example, if you want to +convert your file to the \texttt{OpenDocument Format}, you can use the +following settings, based on \texttt{oolatex} command: + +\begin{verbatim} +settings.tex4ht_sty_par = settings.tex4ht_sty_par ..",ooffice" +settings.tex4ht_par = settings.tex4ht_par .. " ooffice/! -cmozhtf" +settings.t4ht_par = settings.t4ht_par .. " -cooxtpipes -coo " +\end{verbatim} + \section{Command line options}\label{command-line-options} \begin{verbatim} diff --git a/Master/texmf-dist/scripts/make4ht/filters/make4ht-fix-links.lua b/Master/texmf-dist/scripts/make4ht/filters/make4ht-fix-links.lua new file mode 100644 index 00000000000..4dbc26824f3 --- /dev/null +++ b/Master/texmf-dist/scripts/make4ht/filters/make4ht-fix-links.lua @@ -0,0 +1,19 @@ +-- replace colons in `id` or `href` attributes for local links with underscores +-- + +local function fix_href_colons(s) + return s:gsub('(href=".-")', function(a) + if a:match("[a-z]%://") then return a end + return a:gsub(":","_") + end) +end + +local function fix_id_colons(s) + return s:gsub('(id=".-")', function(a) + return a:gsub(":", "_") + end) +end + +return function(s) + return fix_id_colons(fix_href_colons(s)) +end diff --git a/Master/texmf-dist/scripts/make4ht/make4ht b/Master/texmf-dist/scripts/make4ht/make4ht index 49b1d0159a5..15bda54aca8 100755 --- a/Master/texmf-dist/scripts/make4ht/make4ht +++ b/Master/texmf-dist/scripts/make4ht/make4ht @@ -24,6 +24,11 @@ make4ht [options] filename ["tex4ht.sty op." "tex4ht op." "t4ht op" "latex op"] <filename> (string) Input file name ]] +-- set version number. the template should be replaced by the +-- actual version number by the build script +local version = "v0.1c" +mkparams.version_number = version + local args = mkparams.get_args() local parameters = mkparams.process_args(args) diff --git a/Master/texmf-dist/scripts/make4ht/make4ht-dom.lua b/Master/texmf-dist/scripts/make4ht/make4ht-dom.lua new file mode 100755 index 00000000000..fc90bf67e7c --- /dev/null +++ b/Master/texmf-dist/scripts/make4ht/make4ht-dom.lua @@ -0,0 +1,448 @@ +--- DOM module for LuaXML +-- @module make4ht-dom +local dom = {} +local xml = require("luaxml-mod-xml") +local handler = require("luaxml-mod-handler") +local query = require("make4ht-parse-query") + + +local void = {area = true, base = true, br = true, col = true, hr = true, img = true, input = true, link = true, meta = true, param = true} + +local actions = { + TEXT = {text = "%s"}, + COMMENT = {start = "<!-- ", text = "%s", stop = " -->"}, + ELEMENT = {start = "<%s%s>", stop = "</%s>", void = "<%s%s />"}, + DECL = {start = "<?%s %s?>"}, + DTD = {start = "<!DOCTYPE ", text = "%s" , stop=">"} +} + +--- It serializes the DOM object back to XML +-- @function serialize_dom +-- @param parser DOM object +-- @param current +-- @param level +-- @param output +-- @return table +function serialize_dom(parser, current,level, output) + local output = output or {} + local function get_action(typ, action) + local ac = actions[typ] or {} + local format = ac[action] or "" + return format + end + local function insert(format, ...) + table.insert(output, string.format(format, ...)) + end + local function prepare_attributes(attr) + local t = {} + local attr = attr or {} + for k, v in pairs(attr) do + t[#t+1] = string.format("%s='%s'", k, v) + end + if #t == 0 then return "" end + -- add space before attributes + return " " .. table.concat(t, " ") + end + local function start(typ, el, attr) + local format = get_action(typ, "start") + insert(format, el, prepare_attributes(attr)) + end + local function text(typ, text) + local format = get_action(typ, "text") + insert(format, text) + end + local function stop(typ, el) + local format = get_action(typ, "stop") + insert(format,el) + end + local level = level or 0 + local spaces = string.rep(" ",level) + local root= current or parser._handler.root + local name = root._name or "unnamed" + local xtype = root._type or "untyped" + local text_content = root._text or "" + local attributes = root._attr or {} + -- if xtype == "TEXT" then + -- print(spaces .."TEXT : " .. root._text) + -- elseif xtype == "COMMENT" then + -- print(spaces .. "Comment : ".. root._text) + -- else + -- print(spaces .. xtype .. " : " .. name) + -- end + -- for k, v in pairs(attributes) do + -- print(spaces .. " ".. k.."="..v) + -- end + if xtype == "DTD" then + text_content = string.format('%s %s "%s" "%s"', name, attributes["_type"], attributes._name, attributes._uri ) + attributes = {} + elseif xtype == "ELEMENT" and void[name] then + local format = get_action(xtype, "void") + insert(format, name, prepare_attributes(attributes)) + return output + end + + start(xtype, name, attributes) + text(xtype,text_content) + local children = root._children or {} + for _, child in ipairs(children) do + output = serialize_dom(parser,child, level + 1, output) + end + stop(xtype, name) + return output +end + +local parse = function(x) + local domHandler = handler.domHandler() + local Parser = xml.xmlParser(domHandler) + -- preserve whitespace + Parser.options.stripWS = nil + Parser:parse(x) + Parser.current = Parser._handler.root + Parser.__index = Parser + + local function save_methods(element) + setmetatable(element,Parser) + local children = element._children or {} + for _, x in ipairs(children) do + save_methods(x) + end + end + local parser = setmetatable({}, Parser) + + --- @class Parser + function Parser.root_node(self) + return self._handler.root + end + + + function Parser.get_element_type(self, el) + local el = el or self + return el._type + end + function Parser.is_element(self, el) + local el = el or self + return self:get_element_type(el) == "ELEMENT" + end + + function Parser.is_text(self, el) + local el = el or self + return self:get_element_type(el) == "TEXT" + end + + local lower = string.lower + + function Parser.get_element_name(self, el) + local el = el or self + return el._name or "unnamed" + end + + function Parser.get_attribute(self, name) + local el = self + if self:is_element(el) then + local attr = el._attr or {} + return attr[name] + end + end + + function Parser.set_attribute(self, name, value) + local el = self + if self:is_element(el) then + el._attr[name] = value + return true + end + end + + + function Parser.serialize(self, current) + local current = current + -- if no current element is added and self is not plain parser object + -- (_type is then nil), use the current object as serialized root + if not current and self._type then + current = self + end + return table.concat(serialize_dom(self, current)) + end + + function Parser.get_path(self,path, current) + local function traverse_path(path_elements, current, t) + local t = t or {} + if #path_elements == 0 then + -- for _, x in ipairs(current._children or {}) do + -- table.insert(t,x) + -- end + table.insert(t,current) + return t + end + local current_path = table.remove(path_elements, 1) + for _, x in ipairs(self:get_children(current)) do + if self:is_element(x) then + local name = string.lower(self:get_element_name(x)) + if name == current_path then + t = traverse_path(path_elements, x, t) + end + end + end + return t + end + local current = current or self:root_node() -- self._handler.root + local path_elements = {} + local path = string.lower(path) + for el in path:gmatch("([^%s]+)") do table.insert(path_elements, el) end + return traverse_path(path_elements, current) + end + + function Parser.calculate_specificity(self, query) + local query = query or {} + local specificity = 0 + for _, item in ipairs(query.query or {}) do + for key, value in pairs(item) do + if key == "id" then + specificity = specificity + 100 + elseif key == "tag" then + specificity = specificity + 1 + else + specificity = specificity + 10 + end + end + end + return specificity + end + + function Parser.match_querylist(self, querylist) + local matches = {} + local querylist = querylist + + local function test_part(key, value, el) + -- print("testing", key, value, el:get_element_name()) + if key == "tag" then + return el:get_element_name() == value + elseif key == "id" then + local id = el:get_attribute "id" + return id and id == value + elseif key == "class" then + local class = el:get_attribute "class" + if not class then return false end + local c = {} + for part in class:gmatch "([^%s]+)" do + c[part] = true + end + return c[value] == true + end + -- TODO: Add more cases + -- just return true for not supported selectors + return true + end + + local function test_object(query, el) + -- test one object in CSS selector + local matched = {} + for key, value in pairs(query) do + matched[#matched+1] = test_part(key, value, el) + end + if #matched == 0 then return false end + for k, v in ipairs(matched) do + if v ~= true then return false end + end + return true + end + + local function match_query(query, el) + local query = query or {} + local object = table.remove(query) -- get current object from the query stack + if not object then return true end -- if the query stack is empty, then we can be sure that it matched previous items + if not el:is_element() then return false end -- if there is object to test, but current node isn't element, test failed + local result = test_object(object, el) + if result then + return match_query(query, el:get_parent()) + end + return false + end + for _,element in ipairs(querylist) do + local query = {} + for k,v in ipairs(element.query) do query[k] = v end + if #query > 0 then -- don't try to match empty query + local result = match_query(query, self) + if result then matches[#matches+1] = element end + end + end + return matches + end + + function Parser.get_selector_path(self, selectorlist) + local nodelist = {} + self:traverse_elements(function(el) + local matches = el:match_querylist(selectorlist) + print("Matching", el:get_element_name(), #matches) + if #matches > 0 then nodelist[#nodelist+1] = el + end + end) + return nodelist + end + + --- Parse CSS selector to match table + function Parser.prepare_selector(self, selector) + local querylist = {} + local function parse_selector(item) + local query = {} + -- for i = #item, 1, -1 do + -- local part = item[i] + for _, part in ipairs(item) do + local t = {} + for _, atom in ipairs(part) do + local key = atom[1] + local value = atom[2] + t[key] = value + end + query[#query + 1] = t + end + return query + end + -- for item in selector:gmatch("([^%s]+)") do + -- elements[#elements+1] = parse_selector(item) + -- end + local parts = query.parse_query(selector) or {} + -- several selectors may be separated using ",", we must process them separately + for _, part in ipairs(parts) do + querylist[#querylist+1] = {query = parse_selector(part)} + end + return querylist + end + + function Parser.get_children(self, el) + local el = el or self + local children = el._children or {} + return children + end + + function Parser.get_parent(self, el) + local el = el or self + return el._parent + end + + function Parser.traverse_elements(self, fn, current) + local current = current or self:root_node() + local status = true + if self:is_element(current) or self:get_element_type(current) == "ROOT"then + local status = fn(current) + -- don't traverse child nodes when the user function return false + if status ~= false then + for _, child in ipairs(self:get_children(current)) do + self:traverse_elements(fn, child) + end + end + end + end + + function Parser.traverse_node_list(self, nodelist, fn) + local nodelist = nodelist or {} + for _, node in ipairs(nodelist) do + for _, element in ipairs(node._children) do + fn(element) + end + end + end + + function Parser.replace_node(self, new) + local old = self + local parent = self:get_parent(old) + local id,msg = self:find_element_pos( old) + if id then + parent._children[id] = new + return true + end + return false, msg + end + + function Parser.add_child_node(self, child) + local parent = self + child._parent = parent + table.insert(parent._children, child) + end + + + function Parser.copy_node(self, element) + local element = element or self + local t = {} + for k, v in pairs(element) do + if type(v) == "table" and k~="_parent" then + t[k] = self:copy_node(v) + else + t[k] = v + end + end + save_methods(t) + return t + end + + function Parser.create_element(self, name, attributes, parent) + local parent = parent or self + local new = {} + new._type = "ELEMENT" + new._name = name + new._attr = attributes or {} + new._children = {} + new._parent = parent + save_methods(new) + return new + end + + function Parser.remove_node(self, element) + local element = element or self + local parent = self:get_parent(element) + local pos = self:find_element_pos(element) + -- if pos then table.remove(parent._children, pos) end + if pos then + -- table.remove(parent._children, pos) + parent._children[pos] = setmetatable({_type = "removed"}, Parser) + end + end + + function Parser.find_element_pos(self, el) + local el = el or self + local parent = self:get_parent(el) + if not self:is_element(parent) and self:get_element_type(parent) ~= "ROOT" then return nil, "The parent isn't element" end + for i, x in ipairs(parent._children) do + if x == el then return i end + end + return false, "Cannot find element" + end + + function Parser.get_siblibgs(self, el) + local el = el or self + local parent = el:get_parent() + if parent:is_element() then + return parent:get_children() + end + end + + function Parser.get_sibling_node(self, change) + local el = self + local pos = el:find_element_pos() + local siblings = el:get_siblibgs() + if pos and siblings then + return siblings[pos + change] + end + end + + function Parser.get_next_node(self, el) + local el = el or self + return el:get_sibling_node(1) + end + + function Parser.get_prev_node(self, el) + local el = el or self + return el:get_sibling_node(-1) + end + + + -- include the methods to all xml nodes + save_methods(parser._handler.root) + -- parser: + return parser +end + + +local M = {} +M.parse = parse +M.serialize= serialize_dom +return M diff --git a/Master/texmf-dist/scripts/make4ht/make4ht-lib.lua b/Master/texmf-dist/scripts/make4ht/make4ht-lib.lua index 3b550b9995c..918343f20ca 100755 --- a/Master/texmf-dist/scripts/make4ht/make4ht-lib.lua +++ b/Master/texmf-dist/scripts/make4ht/make4ht-lib.lua @@ -116,9 +116,9 @@ Make.file_matches = function(self, files) self.matches[k].params = v end -- Loop over files, run command on matched - for _, file in pairs(files)do + for _, file in ipairs(files)do statuses[file] = {} - for _, s in pairs(self.matches) do + for _, s in ipairs(self.matches) do local pattern= s.pattern if file:match(pattern) then local status, msg = self:run_command(file,s) @@ -134,6 +134,27 @@ Make.file_matches = function(self, files) return statuses end +-- add files from the mk4 file +-- we must add them to the table generated from the lg file, so they can be processed later +-- +Make.add_file = function(self, filename) + -- self.lgfile should be present, as it is created once the lg_file was parsed for the first time + local lg = self.lgfile or {} + local files = lg.files or {} + -- run filters on the file + local filtertable = {filename} + -- should we care about return status? + self:file_matches(filtertable) + -- break if the file is present already + -- start at the end, it it was added by a build file, the file will be likely at the end + for i = #files,1,-1 do + if files[i] == filename then return false, "File was already added" end + end + -- save the added file to the lg_file + table.insert(lg.files, filename) + self.lg = lg +end + Make.run = function(self) local return_codes = {} local params = self.params or {} @@ -174,12 +195,13 @@ Make.run = function(self) end local lgfile = params.input and params.input .. ".lg" or nil if lgfile then - local lg = mkutils.parse_lg(lgfile) + self.lgfile = self.lgfile or mkutils.parse_lg(lgfile) + local lg = self.lgfile -- First convert images from lg files self:image_convert(lg["images"]) -- Then run file matchers on lg files and converted images local files = lg["files"] - for _,v in pairs(lg["images"]) do + for _,v in ipairs(lg["images"]) do local v = v.output -- print(v) table.insert(files,v) diff --git a/Master/texmf-dist/scripts/make4ht/mathnode.lua b/Master/texmf-dist/scripts/make4ht/mathnode.lua new file mode 100755 index 00000000000..6d054ad7b85 --- /dev/null +++ b/Master/texmf-dist/scripts/make4ht/mathnode.lua @@ -0,0 +1,87 @@ +-- local mathnodepath = os.getenv "mathjaxnodepath" +-- +-- print("mathnode", mathnodepath) +local mkutils = require "mkutils" +-- other possible value is page2svg +local mathnodepath = "page2html" +-- options for MathJax command +local options = "--format MathML" +-- math fonts position +-- don't alter fonts if not set +local fontdir = nil +-- if we copy fonts +local fontdest = nil +local fontformat = "otf" + +local function compile(src) + local tmpfile = os.tmpname() + local filename = src + print("Compile using MathJax") + local command = mathnodepath .. " ".. options .. " < " .. filename .. " > " .. tmpfile + print(command) + local status = os.execute(command) + print("Result written to: ".. tmpfile) + mkutils.cp(tmpfile, src) + os.remove(tmpfile) +end + +local function extract_css(file) + local f = io.open(file, "r") + local contents = f:read("*all") + f:close() + local css = "" + local filename = "" + contents = contents:gsub('<style id="(MathJax.-)">(.+)</style>', function(name, style) + css = style + filename = (name or "") .. ".css" + return '<link rel="stylesheet" type="text/css" href="'..filename ..'" />' + end) + local x = assert(io.open(file, "w")) + x:write(contents) + x:close() + return filename, css +end + +-- +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 + if not face:match("url%(") then return "" end + -- print(face) + local family, filename = face:match(family_pattern) + print(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 + mathnodepath = arguments.prg or mathnodepath + options = arguments.options or options + fontdir = arguments.fontdir or fontdir + fontdest = arguments.fontdest or fontdest + fontformat = arguments.fontformat or fontformat + compile(text) + filename, css = extract_css(text) + if fontdir then + css = use_fonts(css) + end + save_css(filename, css) + Make:add_file(filename) + -- print(css) + print(filename) +end diff --git a/Master/texmf-dist/scripts/make4ht/mkparams.lua b/Master/texmf-dist/scripts/make4ht/mkparams.lua index 0dc74a0ce16..61c522a2406 100755 --- a/Master/texmf-dist/scripts/make4ht/mkparams.lua +++ b/Master/texmf-dist/scripts/make4ht/mkparams.lua @@ -2,6 +2,12 @@ local lapp = require "lapp-mk4" local mkutils = require "mkutils" local m = {} -- use ugly module system for new lua versions support +-- these two variables will be used in the version number +-- progname will be set in get_args +m.progname = "make4ht" +-- set the version number before call to process_args() +m.version_number = "v0.1" + m.optiontext = [[ ${progname} - build system for tex4ht Usage: @@ -43,7 +49,7 @@ local function process_args(args) end if args.version ==true then - print "make4ht version 0.1b" + print(string.format("%s version %s", m.progname, m.version_number)) os.exit() end @@ -66,14 +72,15 @@ local function process_args(args) local compiler = args.lua and "dvilualatex" or args.xetex and "xelatex --no-pdf" or "latex" + local tex_file = args.filename local input = mkutils.remove_extension(args.filename) - local latex_params = {} - local tex_file = input local insert_latex = get_inserter(args,latex_params) insert_latex("shell-escape","-shell-escape") local latex_cli_params = args[4] or "" if not latex_cli_params:match("%-jobname") then + -- we must strip out directories from jobname when full path to document is given + input = input:match("([^%/]+)$") table.insert(latex_params,"-jobname="..input) else -- when user specifies -jobname, we must change name of the input file, @@ -117,12 +124,13 @@ local function process_args(args) --end local tex4ht = "" + local dvi= args.xetex and "xdv" or "dvi" if args[2] and args[2] ~="" then tex4ht = args[2] else tex4ht = args.utf8 and " -cmozhtf -utf8" or "" - local xdv = args.xetex and " -.xdv" or "" - tex4ht = tex4ht .. xdv + if args.xetex then tex4ht = tex4ht .. " -.xdv" end + -- tex4ht = tex4ht .. xdv end local t4ht = args[3] or "" @@ -146,6 +154,7 @@ local function process_args(args) ,tex4ht_par=tex4ht ,t4ht_par=t4ht ,mode = mode + ,dvi = dvi ,build_file = build_file --,t4ht_dir_format=t4ht_dir_format } diff --git a/Master/texmf-dist/scripts/make4ht/mkutils.lua b/Master/texmf-dist/scripts/make4ht/mkutils.lua index e550ead9801..56c413ffb43 100755 --- a/Master/texmf-dist/scripts/make4ht/mkutils.lua +++ b/Master/texmf-dist/scripts/make4ht/mkutils.lua @@ -92,9 +92,13 @@ function parse_lg(filename) end +-- local cp_func = os.type == "unix" and "cp" or "copy" +-- maybe it would be better to actually move the files +-- in reality it isn't. +-- local cp_func = os.type == "unix" and "mv" or "move" function cp(src,dest) - local command = string.format('%s %s %s', cp_func, src, dest) + local command = string.format('%s "%s" "%s"', cp_func, src, dest) if cp_func == "copy" then command = command:gsub("/",'\\') end print("Copy: "..command) os.execute(command) @@ -262,15 +266,14 @@ env.Make:add("htlatex",function(par) return 1 end local len = f:seek("end") - - f:seek("set", len - 256) + f:seek("set", len - 1256) local text = f:read("*a") f:close() - if text:match("No pages of output") then return 1 end + if text:match("No pages of output") or text:match("TeX capacity exceeded, sorry") then return 1 end return 0 end ,{correct_exit=0}) -env.Make:add("tex4ht","tex4ht ${tex4ht_par} \"${input}\"", nil, 1) +env.Make:add("tex4ht","tex4ht ${tex4ht_par} \"${input}.${dvi}\"", nil, 1) env.Make:add("t4ht","t4ht ${t4ht_par} \"${input}.${ext}\"",{ext="dvi"},1) function load_config(settings, config_name) |