summaryrefslogtreecommitdiff
path: root/support
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2021-07-27 03:01:57 +0000
committerNorbert Preining <norbert@preining.info>2021-07-27 03:01:57 +0000
commitcef58753eba8ad7e2071195dbd92454febe82d32 (patch)
treedf909696e42fb25ce108e30258c7f935ded86079 /support
parent84465d50d746dfed1bfbe7bb5065279665fa87de (diff)
CTAN sync 202107270301
Diffstat (limited to 'support')
-rw-r--r--support/make4ht/README77
-rw-r--r--support/make4ht/changelog.tex134
-rw-r--r--support/make4ht/domfilters/make4ht-collapsetoc.lua387
-rw-r--r--support/make4ht/domfilters/make4ht-itemparagraphs.lua26
-rw-r--r--support/make4ht/domfilters/make4ht-joincolors.lua1
-rw-r--r--support/make4ht/domfilters/make4ht-sectionid.lua156
-rw-r--r--support/make4ht/domfilters/make4ht-tablerows.lua7
-rw-r--r--support/make4ht/extensions/make4ht-ext-build_changed.lua68
-rw-r--r--support/make4ht/extensions/make4ht-ext-common_domfilters.lua2
-rw-r--r--support/make4ht/extensions/make4ht-ext-staticsite.lua28
-rwxr-xr-xsupport/make4ht/make4ht13
-rw-r--r--support/make4ht/make4ht-doc.pdfbin137946 -> 144186 bytes
-rw-r--r--support/make4ht/make4ht-odtfilter.lua33
-rw-r--r--support/make4ht/mkutils.lua94
-rw-r--r--support/make4ht/readme.tex78
-rw-r--r--support/tex4ebook/README61
-rw-r--r--support/tex4ebook/changelog.tex55
-rw-r--r--support/tex4ebook/readme.tex74
-rwxr-xr-xsupport/tex4ebook/tex4ebook3
-rw-r--r--support/tex4ebook/tex4ebook-doc.pdfbin79505 -> 83506 bytes
-rw-r--r--support/tex4ebook/tex4ebook-exec_epub.lua8
-rw-r--r--support/tex4ebook/tex4ebook.4ht4
-rw-r--r--support/tex4ebook/tex4ebook.sty182
23 files changed, 1095 insertions, 396 deletions
diff --git a/support/make4ht/README b/support/make4ht/README
index 490b9c4a63..89cfac9141 100644
--- a/support/make4ht/README
+++ b/support/make4ht/README
@@ -175,6 +175,19 @@ cross-references work. It can save quite a lot of the compilation time:
$ make4ht -um draft filename.tex
+Another buil-in mode is `clean`. It executes the `Make:clean()` command to
+remove all generated and temporary files from the current directory.
+No \LaTeX\ compilation happens in this mode.
+
+It should be used in this way:
+
+ # copy generated files to a direcory
+ $ make4ht -d outdir filename.tex
+ # remove all generated files in the current dir
+ # the -a info option will print files that are removed
+ $ make4ht -m clean -a info filename.tex
+
+
More information about the build files can be found in section \ref{sec:buildfiles}.
## Handling of the generated files
@@ -248,7 +261,7 @@ common\_domfilters
: clean the HTML file using DOM filters. It is more powerful than
`common_filters`. Used DOM filters are `fixinlines`, `idcolons`,
-`joincharacters`, and `tablerows`.
+`joincharacters`, `sectionid` and `tablerows`.
detect\_engine
@@ -416,6 +429,12 @@ detect compilation errors in the TeX log file.
: One call to the TeX engine with special configuration for loading of the `tex4ht.sty` package.
+`Make:clean`
+
+: This command removes all generated files, including images, HTML files and
+ various auxilary files, from the current directory. It keeps files whose
+ file names don't match the input file name.
+
`Make:httex`
: Variant of `Make:htlatex` suitable for Plain \TeX.
@@ -653,6 +672,12 @@ mathmlfixes
: fix common issues for MathML.
+sectionid
+
+: create `id` attribute for HTML sectioning elements derived from the section
+ title. It also updates links to these sections. Use the `notoc` command line
+ option to prevent that.
+
t4htlinks
: fix hyperlinks in the ODT format.
@@ -935,7 +960,7 @@ options
`toc_query`
-: CSS selector for selecting the table of contents container.
+: CSS selector for selection of element that contains the table of contents.
`title_query`
@@ -945,12 +970,33 @@ options
: table containing a hierarchy of classes used in TOC
+`max_depth`
+
+: set detph of displayed children TOC levels
+
Default values:
filter_settings "collapsetoc" {
toc_query = ".tableofcontents",
- title_query = ".partHead a, .chapterHead a, .sectionHead a, .subsectionHead a",
- toc_levels = {"partToc", "chapterToc", "sectionToc", "subsectionToc", "subsubsectionToc"}
+ title_query = "h1 a, h2 a, h3 a, h4 a, h5 a, h6 a",
+ max_depth = 1,
+ toc_levels = {
+ tocpart = 1,
+ toclikepart = 1,
+ tocappendix = 1,
+ toclikechapter = 2,
+ tocchapter = 2,
+ tocsection = 3,
+ toclikesection = 3,
+ tocsubsection = 4,
+ toclikesubsection = 4,
+ tocsubsubsection = 5,
+ toclikesubsubsection = 5,
+ tocparagraph = 6,
+ toclikeparagraph = 6,
+ tocsubparagraph = 7,
+ toclikesubparagraph = 7,
+ }
}
## The `fixinlines` dom filter
@@ -1034,15 +1080,22 @@ header
table value is a function, it is executed with current parameters and HTML page
DOM object as arguments.
+remove\_maketitle
+
+: the `staticsite` extension removes text produced by the `\maketitle` command by default. Set this
+option to `false` to disable the removal.
+
Example:
+ -- set the environmental variable 'blog_root' with path to
+ -- the directory that should hold the generated HTML files
local outdir = os.getenv "blog_root"
filter_settings "staticsite" {
site_root = outdir,
map = {
- [".css$"] = "../css/"
+ [".css$"] = "/css/"
},
header = {
layout="post",
@@ -1262,6 +1315,20 @@ Another option is to add a space before the `tex4ht` options:
The former way is preferable, though.
+## Table of Contents points to a wrong destination
+
+The `sectionid` DOM filter creates better link destinations for sectioning commands.
+In some cases, for example if you use Pandoc, the document may already contain the
+link destination with the same name. In such cases the original destination is preserved
+in the file. In this case links to the section will point to that place, instead of
+correct destination in the section. This may happen for example if you use Pandoc for
+the Markdown to \LaTeX\ conversion. It creates `\hypertarget` commands that are placed
+just before section. The links points to that place, instead of the actual section.
+
+In this case you don't want to update links. Use the `notoc` option to prevent that.
+
+
+
## Filenames containing spaces
`tex4ht` command cannot handle filenames containing spaces. to fix this issue, `make4ht`
diff --git a/support/make4ht/changelog.tex b/support/make4ht/changelog.tex
index ead753239a..61dbcdaa3b 100644
--- a/support/make4ht/changelog.tex
+++ b/support/make4ht/changelog.tex
@@ -3,6 +3,140 @@
\begin{itemize}
\item
+ 2021/07/25
+
+ \begin{itemize}
+ \tightlist
+ \item
+ version \texttt{0.3h} released.
+ \end{itemize}
+\item
+ 2021/07/25
+
+ \begin{itemize}
+ \tightlist
+ \item
+ use current directory as default output dir in \texttt{staticsite}
+ extension.
+ \end{itemize}
+\item
+ 2021/07/23
+
+ \begin{itemize}
+ \tightlist
+ \item
+ fixed detection of single paragraphs inside
+ \texttt{\textless{}li\textgreater{}} in the \texttt{itemparagraphs}
+ DOM filter.
+ \end{itemize}
+\item
+ 2021/07/18
+
+ \begin{itemize}
+ \tightlist
+ \item
+ remove elements produced by \texttt{\textbackslash{}maketitle} in
+ the \texttt{staticsite} extension.
+ \end{itemize}
+\item
+ 2021/07/05
+
+ \begin{itemize}
+ \tightlist
+ \item
+ sort colors alphabetically in the \texttt{joincolors} DOM filter to
+ enable reproducible builds.
+ \end{itemize}
+\item
+ 2021/06/26
+
+ \begin{itemize}
+ \tightlist
+ \item
+ rewrote the \texttt{collapsetoc} DOM filter.
+ \end{itemize}
+\item
+ 2021/06/20
+
+ \begin{itemize}
+ \tightlist
+ \item
+ test for the \texttt{svg} picture mode in the \texttt{tex4ht}
+ command. Use the \texttt{-g.svg} option if it is detected. This is
+ necessary for correct support of pictorial characters.
+ \end{itemize}
+\item
+ 2021/06/16
+
+ \begin{itemize}
+ \tightlist
+ \item
+ better handling of duplicate ID attributes in \texttt{sectionid} DOM
+ filter.
+ \item
+ support \texttt{notoc} option in \texttt{sectionid}.
+ \end{itemize}
+\item
+ 2021/06/13
+
+ \begin{itemize}
+ \tightlist
+ \item
+ added \texttt{itemparagraphs} DOM filter. It removes unnecessary
+ paragraphs from \texttt{\textless{}li\textgreater{}} elements.
+ \end{itemize}
+\item
+ 2021/05/06
+
+ \begin{itemize}
+ \tightlist
+ \item
+ remove \texttt{\textless{}hr\textgreater{}} elements in
+ \texttt{.hline} rows in \texttt{tablerows} DOM filter.
+ \end{itemize}
+\item
+ 2021/05/01
+
+ \begin{itemize}
+ \tightlist
+ \item
+ added function \texttt{mkutils.isModuleAvailable}. It checks if Lua
+ library is available.
+ \item
+ check for \texttt{char-def} library in \texttt{sectionid} DOM
+ filter.
+ \end{itemize}
+\item
+ 2021/04/08
+
+ \begin{itemize}
+ \tightlist
+ \item
+ removed \texttt{build\_changed}. New script,
+ \href{https://github.com/michal-h21/siterebuild}{siterebuild},
+ should be used instead.
+ \item
+ new DOM filter, \texttt{sectionid}. It uses sanitized titles instead
+ of automatically generated numbers as section IDs.
+ \item
+ added \texttt{sectionid} to \texttt{common\_domfilters}.
+ \item
+ use \texttt{context} in the Docker file, because it contains the
+ \texttt{char-def.lua} file.
+ \end{itemize}
+\item
+ 2021/03/20
+
+ \begin{itemize}
+ \tightlist
+ \item
+ use \texttt{kpse} library when files are copied to the output
+ directory.
+ \item
+ added \texttt{clean} mode. It removes all generated, temporary and
+ auxilary files.
+ \end{itemize}
+\item
2021/03/19
\begin{itemize}
diff --git a/support/make4ht/domfilters/make4ht-collapsetoc.lua b/support/make4ht/domfilters/make4ht-collapsetoc.lua
index 0b77b9dbbb..ede6e1f908 100644
--- a/support/make4ht/domfilters/make4ht-collapsetoc.lua
+++ b/support/make4ht/domfilters/make4ht-collapsetoc.lua
@@ -1,198 +1,249 @@
+-- mini TOC support for make4ht
local domobject = require "luaxml-domobject"
local filter = require "make4ht-filter"
local log = logging.new "collapsetoc"
-
-
-local toc_levels = {"partToc", "chapterToc", "sectionToc", "subsectionToc", "subsubsectionToc"}
-
-local debug_print = function(...) log:debug(...) end
-
-
--- return toc element type and it's id
-local function get_id(el)
- local name = el:get_attribute "class"
- local id
- local a = el:query_selector "a" or {}
- local first = a[1]
- if first then
- local href = first:get_attribute "href"
- id = href:match("#(.+)$")
+local mktuils = require "mkutils"
+
+
+-- assign levels to entries in the .4tc file
+local toc_levels = {
+ tocpart = 1,
+ toclikepart = 1,
+ tocappendix = 2,
+ toclikechapter = 2,
+ tocchapter = 2,
+ tocsection = 3,
+ toclikesection = 3,
+ tocsubsection = 4,
+ toclikesubsection = 4,
+ tocsubsubsection = 5,
+ toclikesubsubsection = 5,
+ tocparagraph = 6,
+ toclikeparagraph = 6,
+ tocsubparagraph = 7,
+ toclikesubparagraph = 7,
+}
+
+-- number of child levels to be kept
+-- the depth of 1 ensures that only direct children of the current sectioning command
+-- will be kept in TOC
+local max_depth = 1
+
+
+-- debugging function to test correct structure of the TOC tree
+local function print_tree(tree, level)
+ local level = level or 0
+ log:debug(string.rep(" ", level) .. (tree.type or "root"), tree.id)
+ for k, v in pairs(tree.children) do
+ print_tree(v, level + 2)
end
- return name, id
end
-local function remove_sections(part_elements, currentpart)
- -- we need to remove toc entries from the previous part if the
- -- current document isn't part of it
- if currentpart == false then
- for _, part in ipairs(part_elements) do
- part:remove_node()
+-- convert the parsed toc entries to a tree structure
+local function make_toc_tree(tocentries, lowestlevel, position, tree)
+ local position = position or 1
+ local tree = tree or {
+ level = lowestlevel - 1,
+ children = {}
+ }
+ local stack = {tree}
+ if position > #tocentries then return tree, position end
+ -- loop over TOC entries and make a tree
+ for i = 1, #tocentries do
+ -- initialize new child
+ local element = tocentries[i]
+ element.children = element.children or {}
+ local parent = stack[#stack]
+ local level_diff = element.level - parent.level
+ if level_diff == 0 then -- entry is sibling of parent
+ -- current parent is sibling of the current elemetn, true parent is
+ -- sibling's parent
+ parent = parent.parent
+ -- we must replace sibling element with the current element in stact
+ -- so the child elements get correct parent
+ table.remove(stack)
+ table.insert(stack, element)
+ elseif level_diff > 0 then -- entry is child of parent
+ for x = 1, level_diff do
+ table.insert(stack, element)
+ end
+ else
+ -- we must remove levels from the stack to get the correct parent
+ for x =1 , level_diff, -1 do
+ if #stack > 0 then
+ parent = table.remove(stack)
+ end
+ end
+ -- we must reinsert parent back to stack, place the current element to stact too
+ table.insert(stack, parent)
+ table.insert(stack, element)
end
+ table.insert(parent.children, element)
+ element.parent = parent
end
+ print_tree(tree)
+ return tree
end
-local function make_toc_selector(toc_levels)
- local level_classes = {}
- for _, l in ipairs(toc_levels) do
- level_classes[#level_classes+1] = "." .. l
+-- find first sectioning element in the current page
+local function find_headers(dom, header_levels)
+ -- we need to find id attributes in <a> elements that are children of sectioning elements
+ local ids = {}
+ for _, header in ipairs(dom:query_selector(header_levels)) do
+ local id = header:get_attribute "id"
+ if id then ids[#ids+1] = id end
end
- return table.concat(level_classes, ", ")
+ return ids
end
-local function find_toc_levels(toc)
- -- find toc levels used in the document
- -- it ecpects that sectioning levels appears in the TOC in the descending order
- local levels, used = {}, {}
- local level = 1
- -- we still expect the standard class names
- local toc_selector = make_toc_selector(toc_levels)
- for _, el in ipairs(toc:query_selector(toc_selector)) do
- local class = el:get_attribute("class")
- if not used[class] then
- table.insert(levels, class)
- used[class] = level
- level = level + 1
+
+-- process list of ids and find those that should be kept:
+-- siblings, children, parents and top level
+local function find_toc_entries_to_keep(ids, tree)
+ local tree = tree or {}
+ -- all id in TOC tree that we want to kepp are saved in this table
+ local ids_to_keep = {}
+ -- find current id in the TOC tree
+ local function find_id(id, tree)
+ if tree.id == id then return tree end
+ if not tree.children or #tree.children == 0 then return false end
+ for k,v in pairs(tree.children) do
+ local found_id = find_id(id, v)
+ if found_id then return found_id end
end
+ return false
end
- return levels, used
-end
-
-local function remove_levels(toc, matched_ids)
- -- sort the matched sections according to their levels
- local levels, level_numbers = find_toc_levels(toc)
- debug_print("remove levels", #levels)
- -- for _, level in ipairs(levels) do
- -- print(level, level_numbers[level], matched_ids[level])
- -- end
- local keep_branch = false
- local matched_levels = {}
- local toc_selector = make_toc_selector(toc_levels)
- for _, el in ipairs(toc:query_selector(toc_selector)) do
- local name, id = get_id(el)
- -- get the current toc hiearchy level
- local level = level_numbers[name]
- -- get the matched id for the current level
- local level_id = matched_ids[name]
- local matched = level_id == id
- local remove = true
- -- we will use this for toc elements at lower hiearchy than is the top sectioning level on the page
- if matched then keep_branch = true end
- -- find the parent level to the current section level
- local parent_level = toc_levels[level - 1]
- local parent_matched = matched_levels[parent_level]
- if matched then
- debug_print("match",name, id, level_id, level, #levels)
- keep_branch = true
- remove = false
- elseif level==1 then
- -- don't remove the top level
- debug_print("part",name, id, level_id, level)
- remove = false
- matched_levels = {}
- if not matched then keep_branch = false end
- elseif keep_branch then
- -- if level >= (#levels - 1) then
- if level > matched_ids._levels then
- debug_print("level",name, id, level_id, level, parent_level, parent_matched)
- remove = false
- elseif matched_ids.ids[id] then
- debug_print("matched id",name, id, level_id, level, parent_level, parent_matched)
- remove = false
- elseif parent_matched then
- debug_print("parent_matched",name, id, level_id, level, parent_level, parent_matched)
- keep_branch = false
- remove = false
- end
- -- else
- -- print("remove", name, id, level_id, level, #matched_ids)
- -- end
- elseif parent_matched then
- debug_print("parent_matched alternative",name, id, level_id, level, parent_level, parent_matched)
- remove = false
- else
- debug_print("else",name, id, level_id, level, keep_branch)
- keep_branch = false
+ -- always keep top level of the hiearchy
+ local function keep_toplevel(tree)
+ for _, el in ipairs(tree.children) do
+ ids_to_keep[el.id] = true
end
- matched_levels[name] = matched
- if remove then
- el:remove_node()
- --print(name,id, level_id, matched)
+ end
+ -- we want to keep all children in TOC hiearchy
+ local function keep_children(element, depth)
+ local depth = depth or 1
+ local max_depth = max_depth or 1
+ -- stop processing when there are no children
+ for _, el in pairs(element.children or {}) do
+ if el.id then ids_to_keep[el.id] = true end
+ -- by default, we keep just direct children of the current sectioning element
+ if depth < max_depth then
+ keep_children(el, depth + 1)
+ end
end
end
-
+ -- also keep all siblings
+ local function keep_siblings(element)
+ local parent = element.parent
+ for k, v in pairs(parent.children or {}) do
+ ids_to_keep[v.id] = true
+ end
+ end
+ -- and of course, keep all parents
+ local function keep_parents(element)
+ local parent = element.parent
+ if parent and parent.id then
+ ids_to_keep[parent.id] = true
+ -- we should keep siblings of all parents as well
+ keep_siblings(parent)
+ keep_parents(parent)
+ end
+ end
+ -- always keep the top-level TOC hiearchy, even if we cannot find any sectioning element on the page
+ keep_toplevel(tree)
+ for _, id in ipairs(ids) do
+ -- keep the current id
+ ids_to_keep[id] = true
+ local found_element = find_id(id, tree)
+ if found_element then
+ keep_children(found_element)
+ keep_siblings(found_element)
+ keep_parents(found_element)
+ end
+ end
+ return ids_to_keep
end
+-- process the .4tc file and convert entries to a tree structure
+-- based on the sectioning level
+local function parse_4tc(parameters, toc_levels)
+ local tcfilename = parameters.input .. ".4tc"
+ if not mkutils.file_exists(tcfilename) then
+ log:warning("Cannot find TOC: " .. tcfilename)
+ return {}
+ end
+ local tocentries = {}
+ local f = io.open(tcfilename, "r")
+ -- we need to find the lowest level used in the TOC
+ local lowestlevel = 999
+ for line in f:lines() do
+ -- entries looks like: \doTocEntry\tocsubsection{1.2.2}{\csname a:TocLink\endcsname{5}{x5-60001.2.2}{QQ2-5-6}{aaaa}}{7}\relax
+ -- we want do extract tocsubsection and x5-60001.2.2
+ local toctype, id = line:match("\\doTocEntry\\(.-){.-}{.-{.-}{(.-)}")
+ if toctype then
+ local level = toc_levels[toctype]
+ if not level then
+ log:warning("Cannot find TOC level for: " .. toctype)
+ else
+ lowestlevel = level < lowestlevel and level or lowestlevel
+ table.insert(tocentries, {type = toctype, id = id, level = level})
+ end
+ end
+ end
+ f:close()
+ local toc = make_toc_tree(tocentries, lowestlevel)
+ return toc
+end
+local function remove_levels(toc, matched_ids)
+ -- remove links that aren't in the TOC hiearchy that should be kept
+ for _, link in ipairs(toc:query_selector("a")) do
+ local href = link:get_attribute("href")
+ -- find id in the href
+ local id = href:match("#(.+)")
+ if id and not matched_ids[id] then
+ -- toc links are in <span> elements that can contain the section number
+ -- we must remove them too
+ local parent = link:get_parent()
+ if parent:get_element_name() == "span" then
+ parent:remove_node()
+ else
+ -- if the parent node isn't <span>, remove at least the link itself
+ link:remove_node()
+ end
+ end
+ end
+end
-
--- local process = filter{ function(s)
- -- local dom = domobject.parse(s)
-local function collapse_toc(dom, par)
+local function collapsetoc(dom, parameters)
-- set options
+ local par = parameters
local options = get_filter_settings "collapsetoc"
+ -- query to find the TOC element in DOM
local toc_query = par.toc_query or options.toc_query or ".tableofcontents"
- local title_query = par.title_query or options.title_query or ".partHead a, .chapterHead a, .sectionHead a, .subsectionHead a"
- toc_levels = par.toc_levels or options.toc_levels or toc_levels
- -- keep track of current id of each sectioning level
- local current_ids, matched_ids = {}, {_levels = 0, ids = {}}
- -- search sectioning elements
- local titles = dom:query_selector(title_query)
- local section_ids = {}
- for _, x in ipairs(titles) do
- -- get their id attributes and save them in a table
- section_ids[#section_ids+1] = x:get_attribute("id")
- end
-
- -- we need to retrieve the first table of contents
- local toctables = dom:query_selector(toc_query) or {}
- -- process only when we got a TOC
- debug_print("toc query", toc_query, #toctables)
- if #toctables > 0 then
- local tableofcontents = toctables[1]
- -- all toc entries are in span elements
- local toc = tableofcontents:query_selector("span")
- local currentpart = false
- local part_elements = {}
- for _, el in ipairs(toc) do
- -- get sectioning level and id of the current TOC entry
- local name, id = get_id(el)
- -- set the id of the current sectioning level
- current_ids[name] = id
- for _, sectid in ipairs(section_ids) do
- -- detect if the current TOC entry match some sectioning element in the current document
- if id == sectid then
- currentpart = true
- -- save the current id as a matched id
- matched_ids.ids[id] = true
- -- copy the TOC hiearchy for the current toc level
- for i, level in ipairs(toc_levels) do
- -- print("xxx",i, level, current_ids[level])
- matched_ids[level] = current_ids[level]
- -- set the maximum matched level
- if i > matched_ids._levels then matched_ids._levels = i end
- if level == name then break end
- end
- debug_print("match", id)
- end
- end
- end
- remove_levels(tableofcontents, matched_ids)
-
- -- remove sections from the last part
- -- remove_sections(part_elements,currentpart)
- -- remove unneeded br elements
- local br = tableofcontents:query_selector("br")
- for _, el in ipairs(br) do el:remove_node() end
- -- remove unneded whitespace
- for _, el in ipairs(tableofcontents:get_children()) do
- if el:is_text() then el:remove_node() end
- end
+ -- query to select sectioning elements with id's
+ local title_query = par.title_query or options.title_query or "h1 a, h2 a, h3 a, h4 a, h5 a, h6 a"
+ -- level of child levels to be kept in TOC
+ max_depth = par.max_depth or options.max_depth or max_depth
+ -- set level numbers for particular TOC entry types
+ local user_toc_levels = par.toc_levels or options.toc_levels or {}
+ -- join user's levels with default
+ for k,v in pairs(user_toc_levels) do toc_levels[k] = v end
+ -- parse the .4tc file to get TOC tree
+ toc = toc or parse_4tc(parameters, toc_levels)
+ -- find sections in the current html file
+ local ids = find_headers(dom, title_query)
+ log:debug("Ids", table.concat(ids, ","))
+ local ids_to_keep = find_toc_entries_to_keep(ids, toc)
+ local toc_dom = dom:query_selector(toc_query)[1]
+ if toc_dom then
+ remove_levels(toc_dom, ids_to_keep)
+ else
+ log:warning("Cannot find TOC element using query: " .. toc_query)
end
return dom
-end
-
-return collapse_toc
+end
--- Make:match("html$", process)
+return collapsetoc
diff --git a/support/make4ht/domfilters/make4ht-itemparagraphs.lua b/support/make4ht/domfilters/make4ht-itemparagraphs.lua
new file mode 100644
index 0000000000..d8616c564a
--- /dev/null
+++ b/support/make4ht/domfilters/make4ht-itemparagraphs.lua
@@ -0,0 +1,26 @@
+-- TeX4ht puts contents of all \item commands into paragraphs. We are not
+-- able to detect if it contain only one paragraph, or more. If just one,
+-- we can remove the paragraph and put the contents directly to <li> element.
+return function(dom)
+ for _, li in ipairs(dom:query_selector("li")) do
+ local is_single_par = false
+ -- count elements and paragraphs that are direct children of <li>
+ -- remove the paragraph only if it is the only child element
+ local el_count, par_count = 0, 0
+ local par = {}
+ for _, el in ipairs(li._children) do
+ if el:is_element() then
+ el_count = el_count + 1
+ if el:get_element_name() == "p" then
+ par[#par+1] = el
+ end
+ end
+ end
+ if #par == 1 and el_count == 1 then
+ -- place paragraph children as direct children of <li>, this
+ -- efectivelly removes <p>
+ li._children = par[1]._children
+ end
+ end
+ return dom
+end
diff --git a/support/make4ht/domfilters/make4ht-joincolors.lua b/support/make4ht/domfilters/make4ht-joincolors.lua
index 730f66a7a0..1c86481010 100644
--- a/support/make4ht/domfilters/make4ht-joincolors.lua
+++ b/support/make4ht/domfilters/make4ht-joincolors.lua
@@ -25,6 +25,7 @@ local function extract_colors(csscontent)
for class, color in pairs(used_colors) do
t[#t+1] = string.format(".%s{color:%s;}", class, color)
end
+ table.sort(t)
return csscontent .. table.concat(t, "\n")
end
diff --git a/support/make4ht/domfilters/make4ht-sectionid.lua b/support/make4ht/domfilters/make4ht-sectionid.lua
new file mode 100644
index 0000000000..c1629181bb
--- /dev/null
+++ b/support/make4ht/domfilters/make4ht-sectionid.lua
@@ -0,0 +1,156 @@
+local mkutils = require "mkutils"
+local log = logging.new("tocid")
+-- Unicode data distributed with ConTeXt
+-- defines "characters" table
+if not mkutils.isModuleAvailable("char-def") then
+ log:warning("char-def module not found")
+ log:warning("cannot fix section id's")
+ return function(dom) return dom end
+end
+require "char-def"
+local chardata = characters.data or {}
+
+
+local toc = nil
+
+local function is_letter(info)
+ -- test if character is letter
+ local category = info.category or ""
+ return category:match("^l")
+end
+
+local function is_space(info)
+ local category = info.category or ""
+ return category == "zs"
+end
+
+local uchar = utf8.char
+local function normalize_letter(char, result)
+ local info = chardata[char] or {}
+ -- first get lower case of the letter
+ local lowercase = info.lccode or char
+ -- remove accents. the base letter is in the shcode field
+ local lowerinfo = chardata[lowercase] or {}
+ -- when no shcode, use the current lowercase char
+ local shcode = lowerinfo.shcode or lowercase
+ -- shcode can be table if it contains multiple characters
+ -- normaliz it to a table, so we can add all letters to
+ -- the resulting string
+ if type(shcode) ~= "table" then shcode = {shcode} end
+ for _, x in ipairs(shcode) do
+ result[#result+1] = uchar(x)
+ end
+end
+
+local escape_name = function(name)
+ local result = {}
+ for _,char in utf8.codes(name) do
+ local info = chardata[char] or {}
+ if is_space(info) then
+ result[#result+1] = " "
+ elseif is_letter(info) then
+ normalize_letter(char, result)
+ end
+ end
+ --- convert table with normalized characters to string
+ local name = table.concat(result)
+ -- remove spaces
+ return name:gsub("%s+", "-")
+end
+
+local function parse_toc_line(line)
+ -- the section ids and titles are saved in the following format:
+ -- \csname a:TocLink\endcsname{1}{x1-20001}{QQ2-1-2}{Nazdar světe}
+ -- ............................... id ................. title ...
+ local id, name = line:match("a:TocLink.-{.-}{(.-)}{.-}{(.-)}")
+ if id then
+ return id, escape_name(name)
+ end
+end
+
+local used = {}
+
+local function parse_toc(filename)
+ local toc = {}
+ if not mkutils.file_exists(filename) then return nil, "Cannot open TOC file " .. filename end
+ for line in io.lines(filename) do
+ local id, name = parse_toc_line(line)
+ local orig_name = name
+ -- not all lines in the .4tc file contains TOC entries
+ if id then
+ -- test if the same name was used already. user should be notified
+ if used[name] then
+ -- update
+ name = name .. used[name]
+ log:debug("Duplicate id found: ".. orig_name .. ". New id: " .. name)
+ end
+ used[orig_name] = (used[orig_name] or 0) + 1
+ toc[id] = name
+ end
+ end
+ return toc
+end
+
+-- we don't want to change the original id, as there may be links to it from the outside
+-- so we will set it to the parent element (which should be h[1-6])
+local function set_id(el, id)
+ local section = el:get_parent()
+ local section_id = section:get_attribute("id")
+ if section_id and section_id~=id then -- if it already has id, we don't override it, but create dummy child instead
+ local new = section:create_element("span", {id=id})
+ section:add_child_node(new,1)
+ else
+ section:set_attribute("id", id)
+ end
+
+end
+
+
+
+return function(dom, par)
+ local msg
+ toc, msg = toc or parse_toc(par.input .. ".4tc")
+ msg = msg or "Cannot load TOC"
+ -- don't do anyting if toc cannot be found
+ if not toc then
+ log:warning(msg)
+ return dom
+ end
+ -- if user selects the "notoc" option on the command line, we
+ -- will not update href links
+ local notoc = false
+ if par["tex4ht_sty_par"]:match("notoc") then notoc = true end
+ -- the HTML file can already contain ID that we want to assign
+ -- we will not set duplicate id from TOC in that case
+ local toc_ids = {}
+ for _, el in ipairs(dom:query_selector("[id]")) do
+ local id = el:get_attribute("id")
+ toc_ids[id] = true
+ end
+ -- process all elements with id atribute or <a href>
+ for _, el in ipairs(dom:query_selector "[id],a[href]") do
+ local id, href = el:get_attribute("id"), el:get_attribute("href")
+ if id then
+ local name = toc[id]
+ -- replace id with new section id
+ if name and not toc_ids[name] then
+ set_id(el, name)
+ else
+ if name then
+ log:debug("Document already contains id: " .. name)
+ end
+ end
+ end
+ if href and notoc == false then
+ -- replace links to sections with new id
+ local base, anchor = href:match("^(.*)%#(.+)")
+ local name = toc[anchor]
+ if name then
+ el:set_attribute("href", base .. "#" .. name)
+ end
+ end
+ end
+ return dom
+ end
+
+
diff --git a/support/make4ht/domfilters/make4ht-tablerows.lua b/support/make4ht/domfilters/make4ht-tablerows.lua
index 3e3931b368..ef36a85750 100644
--- a/support/make4ht/domfilters/make4ht-tablerows.lua
+++ b/support/make4ht/domfilters/make4ht-tablerows.lua
@@ -40,6 +40,12 @@ return function(dom)
-- that matches this pattern, so we should keep the row if we match them too)
return not css:match(search_term)
end
+ local hline_hr = function(row)
+ -- remove <hr> elements from "hline" rows
+ for _, hr in ipairs(row:query_selector(".hline hr")) do
+ hr:remove_node()
+ end
+ end
local load_css_files = function()
-- the empty rows can be styled using CSS, for example configuration for
-- Booktabs does that. We shouldn't remove such rows.
@@ -62,6 +68,7 @@ return function(dom)
-- find the empty rows
for _, row in ipairs(tbl:query_selector("tr")) do
if is_empty_row(row) and is_not_styled(row, css) then row:remove_node() end
+ hline_hr(row)
end
end
diff --git a/support/make4ht/extensions/make4ht-ext-build_changed.lua b/support/make4ht/extensions/make4ht-ext-build_changed.lua
deleted file mode 100644
index e0fc5ec6eb..0000000000
--- a/support/make4ht/extensions/make4ht-ext-build_changed.lua
+++ /dev/null
@@ -1,68 +0,0 @@
--- this make4ht build file tries to recompile modified blog article sources
---
-
--- disable any compilation
-Make.build_seq = {}
-Make:add("tex4ht", "")
-Make:add("t4ht", "")
-
-local log = logging.new "compile newest"
-
-
-
--- construct the name of the generated HTML file from the .published file
-local function get_generated_html_name(published_file, directory, file_pattern)
- local f = io.open(directory .. "/" .. published_file, "r")
- local content = f:read("*all")
- f:close()
- local timestamp = tonumber(content)
- local basename = mkutils.remove_extension(published_file)
- local tex_file = basename .. ".tex"
- -- expand fillename in the file_pattern
- local expanded = file_pattern % {input = basename}
- -- expand date in the file_pattern
- expanded = os.date(expanded, timestamp)
- log:status("found source files :", directory, basename, expanded)
- return {directory = directory, tex_file = tex_file, generated = expanded .. ".html"}
-end
-
--- process subdirectories of the basedir and look for the filename.published files
-local function find_published(basedir, file_pattern)
- local published = {}
- for f in lfs.dir(basedir) do
- local fullname = basedir .. "/" .. f
- local attributes = lfs.attributes(fullname)
- -- process directories, but ignore . and ..
- if attributes.mode == "directory" and f ~= "." and f~= ".." then
- for name in lfs.dir(fullname) do
- if name:match("published$") then
- published[#published + 1] = get_generated_html_name(name, fullname, file_pattern)
- end
-
- end
- end
- end
- return published
-end
-
--- find tex files that were modified later than the generated HTML files
-local function find_changed(published, site_root)
- local keep = {}
- for _, entry in ipairs(published) do
- local source_attributes = lfs.attributes(entry.directory .. "/" .. entry.tex_file)
- local dest_attributes = lfs.attributes(site_root .. "/" .. entry.generated)
- --
- print(entry.tex_file, entry.generated, source_attributes.change < dest_attributes.change)
- end
-end
-
-
-Make:add("rebuild", function(par)
- local config = get_filter_settings "staticsite"
- -- how the generated HTML files are named
- local file_pattern = config.file_pattern or "%Y-%m-%d-${input}"
- local published = find_published(par.tex_dir, file_pattern)
- local changed = find_changed(published, config.site_root)
-end)
-
-Make:rebuild{tex_dir = "posts"}
diff --git a/support/make4ht/extensions/make4ht-ext-common_domfilters.lua b/support/make4ht/extensions/make4ht-ext-common_domfilters.lua
index 802902d48d..6219c95fbd 100644
--- a/support/make4ht/extensions/make4ht-ext-common_domfilters.lua
+++ b/support/make4ht/extensions/make4ht-ext-common_domfilters.lua
@@ -26,7 +26,7 @@ function M.modify_build(make)
make:match("4om$", process, {charclasses= charclasses})
count = 2
else
- local process = filter {"fixinlines", "idcolons", "joincharacters", "mathmlfixes", "tablerows","booktabs"}
+ local process = filter {"fixinlines", "idcolons", "joincharacters", "mathmlfixes", "tablerows","booktabs", "sectionid", "itemparagraphs"}
make:match("html?$", process)
count = 1
end
diff --git a/support/make4ht/extensions/make4ht-ext-staticsite.lua b/support/make4ht/extensions/make4ht-ext-staticsite.lua
index 5704959970..a9a5bcece7 100644
--- a/support/make4ht/extensions/make4ht-ext-staticsite.lua
+++ b/support/make4ht/extensions/make4ht-ext-staticsite.lua
@@ -16,7 +16,7 @@ local function get_slug(settings)
local f = io.open(published_name, "r")
local readtime = f:read("*line")
time = tonumber(readtime)
- log:info("Already pubslished", slug)
+ log:info("Already pubslished", os.date("%Y-%m-%d %H:%M", time))
f:close()
else
-- escape
@@ -76,6 +76,22 @@ local function insert_filter(make, pattern, fn)
})
end
+local function remove_maketitle(make)
+ -- use DOM filter to remove \maketitle block
+ local domfilter = require "make4ht-domfilter"
+ local process = domfilter {
+ function(dom)
+ local maketitles = dom:query_selector(".maketitle")
+ for _, el in ipairs(maketitles) do
+ log:debug("removing maketitle")
+ el:remove_node()
+ end
+ return dom
+ end
+ }
+ make:match("html$", process)
+end
+
local function copy_files(filename, par)
local function prepare_path(dir, subdir)
@@ -84,7 +100,7 @@ local function copy_files(filename, par)
end
-- get extension settings
local site_settings = get_filter_settings "staticsite"
- local site_root = site_settings.site_root
+ local site_root = site_settings.site_root or "./"
local map = site_settings.map or {}
-- default path without subdir, will be used if the file is not matched
-- by any pattern in the map
@@ -107,6 +123,14 @@ function M.modify_build(make)
local process = filter {
"staticsite"
}
+
+ -- detect if we should remove maketitle
+ local site_settings = get_filter_settings "staticsite"
+ -- \maketitle is removed by default, set `remove_maketitle=false` setting to disable that
+ if site_settings.remove_maketitle ~= false then
+ remove_maketitle(make)
+ end
+
local settings = make.params
-- get the published file name
local slug = get_slug(settings)
diff --git a/support/make4ht/make4ht b/support/make4ht/make4ht
index 3ae56f049a..d2bf27194f 100755
--- a/support/make4ht/make4ht
+++ b/support/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.3g"
+local version = "v0.3h"
mkparams.version_number = version
local args = mkparams.get_args()
@@ -76,6 +76,9 @@ make.params = parameters
if make:length() < 1 then
if mode == "draft" then
make:htlatex()
+ elseif mode == "clean" then
+ make:clean()
+ make.no_dvi_process = true
else
make:htlatex()
make:htlatex()
@@ -84,7 +87,7 @@ if make:length() < 1 then
end
-if not args["no-tex4ht"] then
+if not args["no-tex4ht"] and not make.no_dvi_process then
make:tex4ht()
end
@@ -92,7 +95,11 @@ local ext = args.xetex and "xdv" or "dvi"
if #make.image_patterns > 0 then
make.params.t4ht_par = make.params.t4ht_par .. " -p"
end
-make:t4ht {ext = ext}
+
+if not make.no_dvi_process then
+ make:t4ht {ext = ext}
+end
+
-- run extensions which modify the build sequence
if #extensions > 0 then
make = mkutils.extensions_modify_build(extensions, make)
diff --git a/support/make4ht/make4ht-doc.pdf b/support/make4ht/make4ht-doc.pdf
index 6643f67203..cc0d7d1b50 100644
--- a/support/make4ht/make4ht-doc.pdf
+++ b/support/make4ht/make4ht-doc.pdf
Binary files differ
diff --git a/support/make4ht/make4ht-odtfilter.lua b/support/make4ht/make4ht-odtfilter.lua
deleted file mode 100644
index 97f0b8df67..0000000000
--- a/support/make4ht/make4ht-odtfilter.lua
+++ /dev/null
@@ -1,33 +0,0 @@
-local mkutils = require "mkutils"
-local zip = require "zip"
-
-
--- use function to change contents of the ODT file
-local function update_odt(odtfilename, file_path, fn)
- -- get name of the odt file
- local odtname = mkutils.remove_extension(odtfilename) .. ".odt"
- -- open and read contents of the requested file inside ODT file
- local odtfile = zip.open(odtname)
- local local_file = odtfile:open(file_path)
- local content = local_file:read("*all")
- local_file:close()
- odtfile:close()
- -- update the content using user function
- content = fn(content)
- -- write the updated file
- local local_file_file = io.open(file_path,"w")
- local_file_file:write(content)
- local_file_file:close()
- os.execute("zip " .. odtname .. " " .. file_path)
- os.remove(file_path)
-end
-
-Make:match("tmp$", function(name, par)
- update_odt(name, "content.xml", function(content)
- return content:gsub("%&%#x([A-Fa-f0-9]+);", function(entity)
- -- convert hexadecimal entity to Unicode
- print(entity,utfchar(tonumber(entity, 16)))
- return utfchar(tonumber(entity, 16))
- end)
- end)
-end)
diff --git a/support/make4ht/mkutils.lua b/support/make4ht/mkutils.lua
index c182bfd9dd..6bcc4787c3 100644
--- a/support/make4ht/mkutils.lua
+++ b/support/make4ht/mkutils.lua
@@ -55,13 +55,31 @@ function remove_extension(path)
end
--
-
+-- check if file exists
function file_exists(file)
local f = io.open(file, "rb")
if f then f:close() end
return f ~= nil
end
+-- check if Lua module exists
+-- source: https://stackoverflow.com/a/15434737/2467963
+function isModuleAvailable(name)
+ if package.loaded[name] then
+ return true
+ else
+ for _, searcher in ipairs(package.searchers or package.loaders) do
+ local loader = searcher(name)
+ if type(loader) == 'function' then
+ package.preload[name] = loader
+ return true
+ end
+ end
+ return false
+ end
+end
+
+
-- searching for converted images
function parse_lg(filename)
log:info("Parse LG")
@@ -115,6 +133,10 @@ local cp_func = os.type == "unix" and "cp" or "copy"
-- in reality it isn't.
-- local cp_func = os.type == "unix" and "mv" or "move"
function cp(src,dest)
+ if not file_exists(src) then
+ -- 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)
@@ -362,9 +384,77 @@ end, {correct_exit= 0})
-env.Make:add("tex4ht","tex4ht ${tex4ht_par} \"${input}.${dvi}\"", nil, 1)
+-- env.Make:add("tex4ht","tex4ht ${tex4ht_par} \"${input}.${dvi}\"", nil, 1)
+env.Make:add("tex4ht",function(par)
+ -- detect if svg output is used
+ -- if yes, we need to pass the -g.svg option to tex4ht command
+ -- to support svg images for character pictures
+ local logfile = par.input .. ".log"
+ if file_exists(logfile) then
+ for line in io.lines(logfile) do
+ local options = line:match("TeX4ht package options:(.+)")
+ if options then
+ log:info(options)
+ if options:match("svg") then
+ par.tex4ht_par = (par.tex4ht_par or "") .. " -g.svg"
+ end
+ break
+ end
+ end
+ end
+ local command = "tex4ht ${tex4ht_par} \"${input}.${dvi}\"" % par
+ log:info("executing: " .. command)
+ return execute(command)
+end
+ , nil, 1)
env.Make:add("t4ht","t4ht ${t4ht_par} \"${input}.${ext}\"",{ext="dvi"},1)
+env.Make:add("clean", function(par)
+ -- remove all functions that process produced files
+ -- we will provide only one function, that remove all of them
+ Make.matches = {}
+ local main_name = par.input
+ local remove_file = function(filename)
+ if file_exists(filename) then
+ log:info("removing file: " .. filename)
+ os.remove(filename)
+ end
+ end
+ -- try to find if the last converted file was in the ODT format
+ local lg_file = parse_lg(main_name .. ".lg")
+ local is_odt = false
+ if lg_file and lg_file.files then
+ for _, x in ipairs(lg_file.files) do
+ is_odt = x:match("odt$") or is_odt
+ end
+ end
+ if is_odt then
+ Make:match("4om$",function(filename)
+ -- math temporary file
+ local to_remove = filename:gsub("4om$", "tmp")
+ remove_file(to_remove)
+ return false
+ end)
+ Make:match("4og$", remove_file)
+ end
+ Make:match("tmp$", function()
+ -- remove temporary and auxilary files
+ for _,ext in ipairs {"aux", "xref", "tmp", "4tc", "4ct", "idv", "lg","dvi", "log"} do
+ remove_file(main_name .. "." .. ext)
+ end
+ end)
+ Make:match(".*", function(filename, par)
+ -- remove only files that start with the input file basename
+ -- this should prevent removing of images. this also means that
+ -- images shouldn't be names as <filename>-hello.png for example
+ if filename:find(main_name, 1,true) then
+ -- log:info("Matched file", filename)
+ remove_file(filename)
+ end
+ end)
+
+end)
+
-- enable extension in the config file
-- the following two functions must be here and not in make4ht-lib.lua
-- because of the access to env.settings
diff --git a/support/make4ht/readme.tex b/support/make4ht/readme.tex
index 3810dbad36..1938c98a0a 100644
--- a/support/make4ht/readme.tex
+++ b/support/make4ht/readme.tex
@@ -232,6 +232,21 @@ compilation time:
$ make4ht -um draft filename.tex
\end{verbatim}
+Another buil-in mode is \texttt{clean}. It executes the
+\texttt{Make:clean()} command to remove all generated and temporary
+files from the current directory. No \LaTeX~compilation happens in this
+mode.
+
+It should be used in this way:
+
+\begin{verbatim}
+# copy generated files to a direcory
+$ make4ht -d outdir filename.tex
+# remove all generated files in the current dir
+# the -a info option will print files that are removed
+$ make4ht -m clean -a info filename.tex
+\end{verbatim}
+
More information about the build files can be found in section
\ref{sec:buildfiles}.
@@ -328,7 +343,8 @@ clean the output HTML files using filters.
\item[common\_domfilters]
clean the HTML file using DOM filters. It is more powerful than
\texttt{common\_filters}. Used DOM filters are \texttt{fixinlines},
-\texttt{idcolons}, \texttt{joincharacters}, and \texttt{tablerows}.
+\texttt{idcolons}, \texttt{joincharacters}, \texttt{sectionid} and
+\texttt{tablerows}.
\item[detect\_engine]
detect engine and format necessary for the document compilation from the
magic comments supported by \LaTeX~editors such as TeXShop or TeXWorks.
@@ -512,6 +528,10 @@ the TeX log file.
\item[\texttt{Make:htlatex}]
One call to the TeX engine with special configuration for loading of the
\texttt{tex4ht.sty} package.
+\item[\texttt{Make:clean}]
+This command removes all generated files, including images, HTML files
+and various auxilary files, from the current directory. It keeps files
+whose file names don't match the input file name.
\item[\texttt{Make:httex}]
Variant of \texttt{Make:htlatex} suitable for Plain \TeX.
\item[\texttt{Make:latexmk}]
@@ -723,6 +743,10 @@ format.
remove spurious rows from HTML tables.
\item[mathmlfixes]
fix common issues for MathML.
+\item[sectionid]
+create \texttt{id} attribute for HTML sectioning elements derived from
+the section title. It also updates links to these sections. Use the
+\texttt{notoc} command line option to prevent that.
\item[t4htlinks]
fix hyperlinks in the ODT format.
\end{description}
@@ -1023,12 +1047,15 @@ filter}{The collapsetoc dom filter}}\label{the-collapsetoc-dom-filter}}
\begin{description}
\item[\texttt{toc\_query}]
-CSS selector for selecting the table of contents container.
+CSS selector for selection of element that contains the table of
+contents.
\item[\texttt{title\_query}]
CSS selector for selecting all elements that contain the section ID
attribute.
\item[\texttt{toc\_levels}]
table containing a hierarchy of classes used in TOC
+\item[\texttt{max\_depth}]
+set detph of displayed children TOC levels
\end{description}
Default values:
@@ -1036,8 +1063,25 @@ Default values:
\begin{verbatim}
filter_settings "collapsetoc" {
toc_query = ".tableofcontents",
- title_query = ".partHead a, .chapterHead a, .sectionHead a, .subsectionHead a",
- toc_levels = {"partToc", "chapterToc", "sectionToc", "subsectionToc", "subsubsectionToc"}
+ title_query = "h1 a, h2 a, h3 a, h4 a, h5 a, h6 a",
+ max_depth = 1,
+ toc_levels = {
+ tocpart = 1,
+ toclikepart = 1,
+ tocappendix = 1,
+ toclikechapter = 2,
+ tocchapter = 2,
+ tocsection = 3,
+ toclikesection = 3,
+ tocsubsection = 4,
+ toclikesubsection = 4,
+ tocsubsubsection = 5,
+ toclikesubsubsection = 5,
+ tocparagraph = 6,
+ toclikeparagraph = 6,
+ tocsubparagraph = 7,
+ toclikesubparagraph = 7,
+ }
}
\end{verbatim}
@@ -1145,17 +1189,23 @@ pattern \texttt{\%Y-\%m-\%d-\$\{input\}} creates names in the form of
table with variables to be set in the YAML header in HTML files. If the
table value is a function, it is executed with current parameters and
HTML page DOM object as arguments.
+\item[remove\_maketitle]
+the \texttt{staticsite} extension removes text produced by the
+\texttt{\textbackslash{}maketitle} command by default. Set this option
+to \texttt{false} to disable the removal.
\end{description}
Example:
\begin{verbatim}
+-- set the environmental variable 'blog_root' with path to
+-- the directory that should hold the generated HTML files
local outdir = os.getenv "blog_root"
filter_settings "staticsite" {
site_root = outdir,
map = {
- [".css$"] = "../css/"
+ [".css$"] = "/css/"
},
header = {
layout="post",
@@ -1405,6 +1455,24 @@ $ make4ht hello.tex "customcfg,charset=utf-8" " -cunihtf -utf8" -d foo
The former way is preferable, though.
+\hypertarget{table-of-contents-points-to-a-wrong-destination}{%
+\subsection{Table of Contents points to a wrong
+destination}\label{table-of-contents-points-to-a-wrong-destination}}
+
+The \texttt{sectionid} DOM filter creates better link destinations for
+sectioning commands. In some cases, for example if you use Pandoc, the
+document may already contain the link destination with the same name. In
+such cases the original destination is preserved in the file. In this
+case links to the section will point to that place, instead of correct
+destination in the section. This may happen for example if you use
+Pandoc for the Markdown to \LaTeX~conversion. It creates
+\texttt{\textbackslash{}hypertarget} commands that are placed just
+before section. The links points to that place, instead of the actual
+section.
+
+In this case you don't want to update links. Use the \texttt{notoc}
+option to prevent that.
+
\hypertarget{filenames-containing-spaces}{%
\subsection{Filenames containing
spaces}\label{filenames-containing-spaces}}
diff --git a/support/tex4ebook/README b/support/tex4ebook/README
index 3634974ab8..f87bd02f42 100644
--- a/support/tex4ebook/README
+++ b/support/tex4ebook/README
@@ -46,7 +46,17 @@ But it is optional. You shouldn't need to modify your \TeX\ files
## Available commands
-- `\coverimage{coverimage.name}` - include cover image to the document.
+- `\coverimage[<graphicx options>]{coverimage.name}` - include cover image to
+ the document. You can pass the same options as to `\includegraphics` command
+ in the optional argument.
+
+For example:
+
+ \thispagestyle{empty}
+ \begin{document}
+ \coverimage[scale=0.8]{coverimage.name} % include scaled cover image
+ ...
+ \pagestyle{headings}
# Command line options
@@ -212,6 +222,42 @@ Add item to `<manifest>` section in the `OPF` file.
Add `XML` name space to the generated `XHTML` files. Useful in `EPUB 3`.
+### Example config file
+
+ \Preamble{xhtml}
+ \begin{document}
+ \Configure{DocumentLanguage}{de}
+ % Use following lines if your document has ISBN:
+ % \Configure{OpfScheme}{ISBN}
+ % \Configure{UniqueIdentifier}{3-0000-1111-X}
+ % Another possibility is URI that points for example to the ebook homepage:
+ \Configure{OpfScheme}{URI}
+ \Configure{UniqueIdentifier}
+ {https://de.wikipedia.org/wiki/Der_achte_Sch&ouml;pfungstag}
+ \Configure{CoverMimeType}{image/jpeg}
+ % If you don't use \coverimage in the document text,
+ % add cover image using this command:
+ \CoverMetadata{coverimage.jpg}
+ % You can also add more authors to your ebook metadata:
+ \Configure{OpfMetadata}
+ {\HCode{<dc:publisher>Deutscher Bücherbund</dc:publisher>}}
+ \Configure{OpfMetadata}
+ {\HCode{<dc:contributor>Image Artist</dc:contributor>}}
+ \Configure{OpfMetadata}
+ {\HCode{<dc:contributor>Trans Lator</dc:contributor>}}
+ \Configure{OpfMetadata}
+ {\HCode{<dc:date opf:event='original-publication'>1888</dc:date>}}
+ \EndPreamble
+
+Remarks:
+
+- Leading percent signs in the `.cfg` file introduce comments
+- If the unique identifier is a URI which contains diacritical characters, the
+ equivalent HTML code needs to be inserted. `UTF8` is not recognized at that place.
+- `UTF8` characters may be used in the `OpfMetadata` sections.
+
+
+
## Commands available in the config file
@@ -229,6 +275,7 @@ Add `XML` name space to the generated `XHTML` files. Useful in `EPUB 3`.
*Where do you start an ePUB and what is the `<guide>` section of the `.OPF` file?*^[http://epubsecrets.com/where-do-you-start-an-epub-and-what-is-the-guide-section-of-the-opf-file.php]
for some details. Note that `<guide>` is deprecated in `EPUB 3`.
+
## Build files
`tex4ebook` uses `make4ht`^[https://github.com/michal-h21/make4ht] as a build
@@ -254,10 +301,14 @@ See the `make4ht` documentation for an example and more information.
The basic support for the Fixed layout EPUB 3 can be enabled using the following configurations:
- \Configure{OpfMetadata}{\HCode{<meta property="rendition:layout">pre-paginated</meta>}}
- \Configure{OpfMetadata}{\HCode{<meta property="rendition:orientation">landscape</meta>}}
- \Configure{OpfMetadata}{\HCode{<meta property="rendition:spread">none</meta>}}
- \Configure{@HEAD}{\HCode{<meta name="viewport" content="width=1920, height=1080"/>\Hnewline}}
+ \Configure{OpfMetadata}
+ {\HCode{<meta property="rendition:layout">pre-paginated</meta>}}
+ \Configure{OpfMetadata}
+ {\HCode{<meta property="rendition:orientation">landscape</meta>}}
+ \Configure{OpfMetadata}
+ {\HCode{<meta property="rendition:spread">none</meta>}}
+ \Configure{@HEAD}
+ {\HCode{<meta name="viewport" content="width=1920, height=1080"/>\Hnewline}}
Modify the dimensions in the `<meta name="viewport>` element according to your needs.
diff --git a/support/tex4ebook/changelog.tex b/support/tex4ebook/changelog.tex
index 3d0d6c1c6c..f415f81c8c 100644
--- a/support/tex4ebook/changelog.tex
+++ b/support/tex4ebook/changelog.tex
@@ -3,6 +3,61 @@
\begin{itemize}
\item
+ 2021/07/26
+
+ \begin{itemize}
+ \tightlist
+ \item
+ released version \texttt{0.3d}
+ \end{itemize}
+\item
+ 2021/05/29
+
+ \begin{itemize}
+ \tightlist
+ \item
+ renamed \texttt{DeclareLanguage} to
+ \texttt{\textbackslash{}DeclareLanguageEbook}. Fixes
+ \href{https://github.com/michal-h21/tex4ebook/issues/78}{issue 78}.
+ \end{itemize}
+\item
+ 2021/05/15
+
+ \begin{itemize}
+ \tightlist
+ \item
+ use \texttt{assert} in checking of existence of the \texttt{zip}
+ command.
+ \item
+ replace colons in \texttt{OPF} \texttt{id} attributes and add
+ trailing \texttt{x} if the \texttt{id} starts with number. It should
+ fix some validation issues.
+ \end{itemize}
+\item
+ 2021/05/02
+
+ \begin{itemize}
+ \tightlist
+ \item
+ added more examples of configuration to the documentation.
+ \end{itemize}
+\item
+ 2020/11/09
+
+ \begin{itemize}
+ \tightlist
+ \item
+ set exit status
+ \end{itemize}
+\item
+ 2020/11/09
+
+ \begin{itemize}
+ \tightlist
+ \item
+ don't redefine \texttt{PicDisplay} configuration.
+ \end{itemize}
+\item
2020/11/06
\begin{itemize}
diff --git a/support/tex4ebook/readme.tex b/support/tex4ebook/readme.tex
index 0fdb16c1c9..428ac6c68c 100644
--- a/support/tex4ebook/readme.tex
+++ b/support/tex4ebook/readme.tex
@@ -53,10 +53,22 @@ But it is optional. You shouldn't need to modify your \TeX~files
\begin{itemize}
\tightlist
\item
- \texttt{\textbackslash{}coverimage\{coverimage.name\}} - include cover
- image to the document.
+ \texttt{\textbackslash{}coverimage{[}\textless{}graphicx\ options\textgreater{}{]}\{coverimage.name\}}
+ - include cover image to the document. You can pass the same options
+ as to \texttt{\textbackslash{}includegraphics} command in the optional
+ argument.
\end{itemize}
+For example:
+
+\begin{verbatim}
+\thispagestyle{empty}
+\begin{document}
+\coverimage[scale=0.8]{coverimage.name} % include scaled cover image
+...
+\pagestyle{headings}
+\end{verbatim}
+
\hypertarget{command-line-options}{%
\section{Command line options}\label{command-line-options}}
@@ -246,6 +258,52 @@ Add item to \texttt{\textless{}manifest\textgreater{}} section in the
Add \texttt{XML} name space to the generated \texttt{XHTML} files.
Useful in \texttt{EPUB\ 3}.
+\hypertarget{example-config-file}{%
+\subsubsection{Example config file}\label{example-config-file}}
+
+\begin{verbatim}
+\Preamble{xhtml}
+\begin{document}
+\Configure{DocumentLanguage}{de}
+% Use following lines if your document has ISBN:
+% \Configure{OpfScheme}{ISBN}
+% \Configure{UniqueIdentifier}{3-0000-1111-X}
+% Another possibility is URI that points for example to the ebook homepage:
+\Configure{OpfScheme}{URI}
+\Configure{UniqueIdentifier}
+{https://de.wikipedia.org/wiki/Der_achte_Sch&ouml;pfungstag}
+\Configure{CoverMimeType}{image/jpeg}
+% If you don't use \coverimage in the document text,
+% add cover image using this command:
+\CoverMetadata{coverimage.jpg}
+% You can also add more authors to your ebook metadata:
+\Configure{OpfMetadata}
+{\HCode{<dc:publisher>Deutscher Bücherbund</dc:publisher>}}
+\Configure{OpfMetadata}
+{\HCode{<dc:contributor>Image Artist</dc:contributor>}}
+\Configure{OpfMetadata}
+{\HCode{<dc:contributor>Trans Lator</dc:contributor>}}
+\Configure{OpfMetadata}
+{\HCode{<dc:date opf:event='original-publication'>1888</dc:date>}}
+\EndPreamble
+\end{verbatim}
+
+Remarks:
+
+\begin{itemize}
+\tightlist
+\item
+ Leading percent signs in the \texttt{.cfg} file introduce comments
+\item
+ If the unique identifier is a URI which contains diacritical
+ characters, the\\
+ equivalent HTML code needs to be inserted. \texttt{UTF8} is not
+ recognized at that place.
+\item
+ \texttt{UTF8} characters may be used in the \texttt{OpfMetadata}
+ sections.
+\end{itemize}
+
\hypertarget{commands-available-in-the-config-file}{%
\subsection{Commands available in the config
file}\label{commands-available-in-the-config-file}}
@@ -301,10 +359,14 @@ The basic support for the Fixed layout EPUB 3 can be enabled using the
following configurations:
\begin{verbatim}
-\Configure{OpfMetadata}{\HCode{<meta property="rendition:layout">pre-paginated</meta>}}
-\Configure{OpfMetadata}{\HCode{<meta property="rendition:orientation">landscape</meta>}}
-\Configure{OpfMetadata}{\HCode{<meta property="rendition:spread">none</meta>}}
-\Configure{@HEAD}{\HCode{<meta name="viewport" content="width=1920, height=1080"/>\Hnewline}}
+\Configure{OpfMetadata}
+{\HCode{<meta property="rendition:layout">pre-paginated</meta>}}
+\Configure{OpfMetadata}
+{\HCode{<meta property="rendition:orientation">landscape</meta>}}
+\Configure{OpfMetadata}
+{\HCode{<meta property="rendition:spread">none</meta>}}
+\Configure{@HEAD}
+{\HCode{<meta name="viewport" content="width=1920, height=1080"/>\Hnewline}}
\end{verbatim}
Modify the dimensions in the
diff --git a/support/tex4ebook/tex4ebook b/support/tex4ebook/tex4ebook
index 91df031ffb..2b2b38b113 100755
--- a/support/tex4ebook/tex4ebook
+++ b/support/tex4ebook/tex4ebook
@@ -67,7 +67,7 @@ else
end
if args.version then
- print "tex4ebook v0.3c"
+ print "tex4ebook v0.3d"
return
end
@@ -201,4 +201,5 @@ executor.run(input,params)
executor.writeContainer()
executor.clean()
log:status("Conversion finished")
+logging.exit_status()
--print(args[1])
diff --git a/support/tex4ebook/tex4ebook-doc.pdf b/support/tex4ebook/tex4ebook-doc.pdf
index 3546db973f..170a8fc4f1 100644
--- a/support/tex4ebook/tex4ebook-doc.pdf
+++ b/support/tex4ebook/tex4ebook-doc.pdf
Binary files differ
diff --git a/support/tex4ebook/tex4ebook-exec_epub.lua b/support/tex4ebook/tex4ebook-exec_epub.lua
index 75304e2494..539cf930ab 100644
--- a/support/tex4ebook/tex4ebook-exec_epub.lua
+++ b/support/tex4ebook/tex4ebook-exec_epub.lua
@@ -157,6 +157,10 @@ function make_opf()
local id=table.concat(dir_part,"-")..fname.."_"..ext
-- remove invalid characters from id start
id = id:gsub("^[%.%-]*","")
+ -- remove colons
+ id = id:gsub(":", "_")
+ -- id cannot start by number, add trailing "x" character
+ id = id:gsub("^([%d])", "x%1")
return "<item id='"..id .. "' href='"..item.."' media-type='"..mimetype.."' />",id
end
local find_all_files= function(s,r)
@@ -277,9 +281,9 @@ function make_opf()
end
end
local function find_zip()
- if io.popen("zip -v","r"):close() then
+ if assert(io.popen("zip -v","r"):close()) then
return "zip"
- elseif io.popen("miktex-zip -v","r"):close() then
+ elseif assert(io.popen("miktex-zip -v","r"):close()) then
return "miktex-zip"
end
log:warning "It appears you don't have zip command installed. I can't pack the ebook"
diff --git a/support/tex4ebook/tex4ebook.4ht b/support/tex4ebook/tex4ebook.4ht
index 6ee87ed3ae..0132463917 100644
--- a/support/tex4ebook/tex4ebook.4ht
+++ b/support/tex4ebook/tex4ebook.4ht
@@ -193,10 +193,6 @@ href="#1" media-type="\a:CoverMimeType" />}}
% Support for SVG isn't ready
%\Configure{Picture}{.svg}
\Configure{Picture}{.png}
-\Configure{PicDisplay}
- {\edef\MathPar{\ifvmode par-\fi}\IgnorePar\endgraf\EndP
- \HCode{<div class="\MathPar math-display">}}
- {\HCode{</div>}} {} {class="\MathPar math-display" }
\Configure{()}{$}{$}
\fi
\:CheckOption{kindle} \if:Option
diff --git a/support/tex4ebook/tex4ebook.sty b/support/tex4ebook/tex4ebook.sty
index 1b0114748c..4d8cb1db09 100644
--- a/support/tex4ebook/tex4ebook.sty
+++ b/support/tex4ebook/tex4ebook.sty
@@ -11,7 +11,7 @@
\def\opftable{}
%Declare RFC3066 language code for babel language name
-\def\DeclareLanguage#1#2{%
+\def\DeclareLanguageEbook#1#2{%
\csgdef{rfclang#1}{#2}%
}
\def\GetLanguage{%
@@ -21,96 +21,96 @@
\fi%
}
-\DeclareLanguage{UKenglish}{en-GB}
-\DeclareLanguage{USenglish}{en-US}
-\DeclareLanguage{acadian}{fr}
-\DeclareLanguage{albanian}{sq}
-\DeclareLanguage{american}{en-US}
-\DeclareLanguage{amharic}{am}
-\DeclareLanguage{arabic}{ar}
-\DeclareLanguage{armenian}{hy}
-\DeclareLanguage{australian}{en-US}
-\DeclareLanguage{austrian}{de}
-\DeclareLanguage{basque}{eu}
-\DeclareLanguage{bengali}{bn}
-\DeclareLanguage{brazilian}{pt}
-\DeclareLanguage{brazil}{pt}
-\DeclareLanguage{breton}{br}
-\DeclareLanguage{british}{en-GB}
-\DeclareLanguage{bulgarian}{bg}
-\DeclareLanguage{canadian}{en-US}
-\DeclareLanguage{canadien}{fr}
-\DeclareLanguage{catalan}{ca}
-\DeclareLanguage{croatian}{hr}
-\DeclareLanguage{czech}{cs-CZ}
-\DeclareLanguage{danish}{da}
-\DeclareLanguage{divehi}{dv}
-\DeclareLanguage{dutch}{nl}
-\DeclareLanguage{english}{en}
-\DeclareLanguage{esperanto}{eo}
-\DeclareLanguage{estonian}{et}
-\DeclareLanguage{finnish}{f\/i}
-\DeclareLanguage{francais}{fr}
-\DeclareLanguage{french}{fr}
-\DeclareLanguage{galician}{gl}
-\DeclareLanguage{germanb}{de}
-\DeclareLanguage{german}{de}
-\DeclareLanguage{greek}{el}
-\DeclareLanguage{hebrew}{he}
-\DeclareLanguage{hindi}{hi}
-\DeclareLanguage{hungarian}{hu}
-\DeclareLanguage{icelandic}{is}
-\DeclareLanguage{interlingua}{ia}
-\DeclareLanguage{irish}{ga}
-\DeclareLanguage{italian}{it}
-\DeclareLanguage{kannada}{kn}
-\DeclareLanguage{khmer}{km}
-\DeclareLanguage{korean}{ko}
-\DeclareLanguage{lao}{lo}
-\DeclareLanguage{latin}{la}
-\DeclareLanguage{latvian}{lv}
-\DeclareLanguage{lithuanian}{lt}
-\DeclareLanguage{lowersorbian}{dsb}
-\DeclareLanguage{magyar}{hu}
-\DeclareLanguage{malayalam}{ml}
-\DeclareLanguage{marathi}{mr}
-\DeclareLanguage{naustrian}{de}
-\DeclareLanguage{newzealand}{en}
-\DeclareLanguage{ngerman}{de}
-\DeclareLanguage{norsk}{no}
-\DeclareLanguage{norwegiannynorsk}{nn}
-\DeclareLanguage{nynorsk}{no}
-\DeclareLanguage{occitan}{oc}
-\DeclareLanguage{oldchurchslavonic}{cu}
-\DeclareLanguage{persian}{fa}
-\DeclareLanguage{polish}{pl-PL}
-\DeclareLanguage{polutonikogreek}{el}
-\DeclareLanguage{portuges}{pt}
-\DeclareLanguage{portuguese}{pt}
-\DeclareLanguage{romanian}{ro}
-\DeclareLanguage{romansh}{rm}
-\DeclareLanguage{russian}{ru}
-\DeclareLanguage{samin}{se}
-\DeclareLanguage{sanskrit}{sa}
-\DeclareLanguage{scottish}{gd}
-\DeclareLanguage{serbian}{sr}
-\DeclareLanguage{serbo-croatian}{sh}
-\DeclareLanguage{slovak}{sk}
-\DeclareLanguage{slovene}{sl}
-\DeclareLanguage{slovenian}{sl}
-\DeclareLanguage{spanish}{es}
-\DeclareLanguage{swedish}{sv}
-\DeclareLanguage{tamil}{ta}
-\DeclareLanguage{telugu}{te}
-\DeclareLanguage{thai}{th}
-\DeclareLanguage{tibetan}{bo}
-\DeclareLanguage{turkish}{tr}
-\DeclareLanguage{turkmen}{tk}
-\DeclareLanguage{ukrainian}{uk}
-\DeclareLanguage{uppersorbian}{hsb}
-\DeclareLanguage{urdu}{ur}
-\DeclareLanguage{vietnamese}{vi}
-\DeclareLanguage{welsh}{cy}
+\DeclareLanguageEbook{UKenglish}{en-GB}
+\DeclareLanguageEbook{USenglish}{en-US}
+\DeclareLanguageEbook{acadian}{fr}
+\DeclareLanguageEbook{albanian}{sq}
+\DeclareLanguageEbook{american}{en-US}
+\DeclareLanguageEbook{amharic}{am}
+\DeclareLanguageEbook{arabic}{ar}
+\DeclareLanguageEbook{armenian}{hy}
+\DeclareLanguageEbook{australian}{en-US}
+\DeclareLanguageEbook{austrian}{de}
+\DeclareLanguageEbook{basque}{eu}
+\DeclareLanguageEbook{bengali}{bn}
+\DeclareLanguageEbook{brazilian}{pt}
+\DeclareLanguageEbook{brazil}{pt}
+\DeclareLanguageEbook{breton}{br}
+\DeclareLanguageEbook{british}{en-GB}
+\DeclareLanguageEbook{bulgarian}{bg}
+\DeclareLanguageEbook{canadian}{en-US}
+\DeclareLanguageEbook{canadien}{fr}
+\DeclareLanguageEbook{catalan}{ca}
+\DeclareLanguageEbook{croatian}{hr}
+\DeclareLanguageEbook{czech}{cs-CZ}
+\DeclareLanguageEbook{danish}{da}
+\DeclareLanguageEbook{divehi}{dv}
+\DeclareLanguageEbook{dutch}{nl}
+\DeclareLanguageEbook{english}{en}
+\DeclareLanguageEbook{esperanto}{eo}
+\DeclareLanguageEbook{estonian}{et}
+\DeclareLanguageEbook{finnish}{f\/i}
+\DeclareLanguageEbook{francais}{fr}
+\DeclareLanguageEbook{french}{fr}
+\DeclareLanguageEbook{galician}{gl}
+\DeclareLanguageEbook{germanb}{de}
+\DeclareLanguageEbook{german}{de}
+\DeclareLanguageEbook{greek}{el}
+\DeclareLanguageEbook{hebrew}{he}
+\DeclareLanguageEbook{hindi}{hi}
+\DeclareLanguageEbook{hungarian}{hu}
+\DeclareLanguageEbook{icelandic}{is}
+\DeclareLanguageEbook{interlingua}{ia}
+\DeclareLanguageEbook{irish}{ga}
+\DeclareLanguageEbook{italian}{it}
+\DeclareLanguageEbook{kannada}{kn}
+\DeclareLanguageEbook{khmer}{km}
+\DeclareLanguageEbook{korean}{ko}
+\DeclareLanguageEbook{lao}{lo}
+\DeclareLanguageEbook{latin}{la}
+\DeclareLanguageEbook{latvian}{lv}
+\DeclareLanguageEbook{lithuanian}{lt}
+\DeclareLanguageEbook{lowersorbian}{dsb}
+\DeclareLanguageEbook{magyar}{hu}
+\DeclareLanguageEbook{malayalam}{ml}
+\DeclareLanguageEbook{marathi}{mr}
+\DeclareLanguageEbook{naustrian}{de}
+\DeclareLanguageEbook{newzealand}{en}
+\DeclareLanguageEbook{ngerman}{de}
+\DeclareLanguageEbook{norsk}{no}
+\DeclareLanguageEbook{norwegiannynorsk}{nn}
+\DeclareLanguageEbook{nynorsk}{no}
+\DeclareLanguageEbook{occitan}{oc}
+\DeclareLanguageEbook{oldchurchslavonic}{cu}
+\DeclareLanguageEbook{persian}{fa}
+\DeclareLanguageEbook{polish}{pl-PL}
+\DeclareLanguageEbook{polutonikogreek}{el}
+\DeclareLanguageEbook{portuges}{pt}
+\DeclareLanguageEbook{portuguese}{pt}
+\DeclareLanguageEbook{romanian}{ro}
+\DeclareLanguageEbook{romansh}{rm}
+\DeclareLanguageEbook{russian}{ru}
+\DeclareLanguageEbook{samin}{se}
+\DeclareLanguageEbook{sanskrit}{sa}
+\DeclareLanguageEbook{scottish}{gd}
+\DeclareLanguageEbook{serbian}{sr}
+\DeclareLanguageEbook{serbo-croatian}{sh}
+\DeclareLanguageEbook{slovak}{sk}
+\DeclareLanguageEbook{slovene}{sl}
+\DeclareLanguageEbook{slovenian}{sl}
+\DeclareLanguageEbook{spanish}{es}
+\DeclareLanguageEbook{swedish}{sv}
+\DeclareLanguageEbook{tamil}{ta}
+\DeclareLanguageEbook{telugu}{te}
+\DeclareLanguageEbook{thai}{th}
+\DeclareLanguageEbook{tibetan}{bo}
+\DeclareLanguageEbook{turkish}{tr}
+\DeclareLanguageEbook{turkmen}{tk}
+\DeclareLanguageEbook{ukrainian}{uk}
+\DeclareLanguageEbook{uppersorbian}{hsb}
+\DeclareLanguageEbook{urdu}{ur}
+\DeclareLanguageEbook{vietnamese}{vi}
+\DeclareLanguageEbook{welsh}{cy}
\AtEndDocument{%
\ncxtable