Skip to content

Commit

Permalink
feat(packages): Support page ranges in indexer
Browse files Browse the repository at this point in the history
  • Loading branch information
Omikhleia authored and Didier Willis committed Jan 2, 2025
1 parent e823c98 commit 3f9a15c
Showing 1 changed file with 71 additions and 9 deletions.
80 changes: 71 additions & 9 deletions packages/indexer/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,88 @@ local base = require("packages.base")
local package = pl.class(base)
package._name = "indexer"

function package.buildIndex (class) -- Called from the class, not as a package method
local function isNotSamePage (p1, p2)
if not p1 then
return true
end
return p1.display ~= p2.display or p1.value ~= p2.value
end

local function groupPageRanges(pages)
local ret = {}
for _, page in ipairs(pages) do
if #ret == 0
or ret[#ret][#ret[#ret]].display ~= page.display
or ret[#ret][#ret[#ret]].value + 1 ~= page.value
then
table.insert(ret, { page })
else
table.insert(ret[#ret], page)
end
end
return ret
end

function package.buildIndex ()
local nodes = SILE.scratch.info.thispage.index
local thisPage = class.packages.counters:formatCounter(SILE.scratch.counters.folio)
local pageno = pl.tablex.copy(SILE.scratch.counters.folio)
if not nodes then
return
end
for _, node in ipairs(nodes) do
if not SILE.scratch.index[node.index] then
SILE.scratch.index[node.index] = {}
end
local thisIndex = SILE.scratch.index[node.index]
if not thisIndex[node.label] then
thisIndex[node.label] = {}
local index = SILE.scratch.index[node.index]
if not index[node.label] then
index[node.label] = {}
end
if not #thisIndex[node.label] or (thisIndex[node.label])[#thisIndex[node.label]] ~= thisPage then
table.insert(thisIndex[node.label], thisPage)
local pages = index[node.label]
if not #pages or isNotSamePage(pages[#pages], pageno) then
table.insert(pages, pageno)
end
end
end

function package:_init ()
function package:_init (options)
base._init(self)
self.config = pl.tablex.merge({
["page-range-format"] = "expanded",
["page-range-delimiter"] = "",
["page-delimiter"] = ", "
}, options, true)
self:loadPackage("infonode")
self.class:registerHook("endpage", self.buildIndex)
if not SILE.scratch.index then
SILE.scratch.index = {}
end
end

function package:formatPageRanges (pages)
local ranges = {}
for _, range in ipairs(groupPageRanges(pages)) do
if #range == 1 then
table.insert(ranges, self.class.packages.counters:formatCounter(range[1]))
else
table.insert(ranges,
self.class.packages.counters:formatCounter(range[1])
.. self.config['page-range-delimiter']
.. self.class.packages.counters:formatCounter(range[#range]))
end
end
return table.concat(ranges, self.config['page-delimiter'])
end

function package:formatPages (pages)
if self.config['page-range-format'] ~= 'none' then
return self:formatPageRanges(pages)
end
local ret = pl.tablex.map(function (page)
return self.class.packages.counters:formatCounter(page)
end, pages)
return table.concat(ret, self.config['page-delimiter'])
end

function package:registerCommands ()
self:registerCommand("indexentry", function (options, content)
if not options.label then
Expand Down Expand Up @@ -64,7 +117,7 @@ function package:registerCommands ()
SU.collatedSort(sortedIndex)
SILE.call("bigskip")
for _, k in ipairs(sortedIndex) do
local pageno = table.concat(index[k], ", ")
local pageno = self:formatPages(index[k])
SILE.call("index:item", { pageno = pageno }, { k })
end
end)
Expand All @@ -85,6 +138,15 @@ end
package.documentation = [[
\begin{document}
An index is essentially the same thing as a table of contents, but sorted.
The package accepts several configuration options:
\begin{itemize}
\item{\autodoc:parameter{page-range-format}: The format of the page range.
Possible values are \autodoc:parameter{expanded} (default), \autodoc:parameter{none}.}
\item{\autodoc:parameter{page-range-delimiter}: The delimiter between the start and end of a page range.}
\item{\autodoc:parameter{page-delimiter}: The delimiter between pages.}
\end{itemize}
This package provides the \autodoc:command{\indexentry} command, which can be called as either \autodoc:command{\indexentry[label=<text>]} or \autodoc:command{\indexentry{<text>}} (so that it can be called from a macro).
Index entries are collated at the end of each page, and the command \autodoc:command{\printindex} will deposit them in a list.
The entry can be styled using the \autodoc:command{\index:item} command.
Expand Down

0 comments on commit 3f9a15c

Please sign in to comment.