Skip to content

Commit a84d4ef

Browse files
OmikhleiaDidier Willis
authored andcommitted
feat(packages): Support page ranges in indexer
1 parent 5db2dcd commit a84d4ef

1 file changed

Lines changed: 71 additions & 9 deletions

File tree

packages/indexer/init.lua

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,88 @@ local base = require("packages.base")
33
local package = pl.class(base)
44
package._name = "indexer"
55

6-
function package.buildIndex (class) -- Called from the class, not as a package method
6+
local function isNotSamePage (p1, p2)
7+
if not p1 then
8+
return true
9+
end
10+
return p1.display ~= p2.display or p1.value ~= p2.value
11+
end
12+
13+
local function groupPageRanges(pages)
14+
local ret = {}
15+
for _, page in ipairs(pages) do
16+
if #ret == 0
17+
or ret[#ret][#ret[#ret]].display ~= page.display
18+
or ret[#ret][#ret[#ret]].value + 1 ~= page.value
19+
then
20+
table.insert(ret, { page })
21+
else
22+
table.insert(ret[#ret], page)
23+
end
24+
end
25+
return ret
26+
end
27+
28+
function package.buildIndex ()
729
local nodes = SILE.scratch.info.thispage.index
8-
local thisPage = class.packages.counters:formatCounter(SILE.scratch.counters.folio)
30+
local pageno = pl.tablex.copy(SILE.scratch.counters.folio)
931
if not nodes then
1032
return
1133
end
1234
for _, node in ipairs(nodes) do
1335
if not SILE.scratch.index[node.index] then
1436
SILE.scratch.index[node.index] = {}
1537
end
16-
local thisIndex = SILE.scratch.index[node.index]
17-
if not thisIndex[node.label] then
18-
thisIndex[node.label] = {}
38+
local index = SILE.scratch.index[node.index]
39+
if not index[node.label] then
40+
index[node.label] = {}
1941
end
20-
if not #thisIndex[node.label] or (thisIndex[node.label])[#thisIndex[node.label]] ~= thisPage then
21-
table.insert(thisIndex[node.label], thisPage)
42+
local pages = index[node.label]
43+
if not #pages or isNotSamePage(pages[#pages], pageno) then
44+
table.insert(pages, pageno)
2245
end
2346
end
2447
end
2548

26-
function package:_init ()
49+
function package:_init (options)
2750
base._init(self)
51+
self.config = pl.tablex.merge({
52+
["page-range-format"] = "expanded",
53+
["page-range-delimiter"] = "",
54+
["page-delimiter"] = ", "
55+
}, options, true)
2856
self:loadPackage("infonode")
2957
self.class:registerHook("endpage", self.buildIndex)
3058
if not SILE.scratch.index then
3159
SILE.scratch.index = {}
3260
end
3361
end
3462

63+
function package:formatPageRanges (pages)
64+
local ranges = {}
65+
for _, range in ipairs(groupPageRanges(pages)) do
66+
if #range == 1 then
67+
table.insert(ranges, self.class.packages.counters:formatCounter(range[1]))
68+
else
69+
table.insert(ranges,
70+
self.class.packages.counters:formatCounter(range[1])
71+
.. self.config['page-range-delimiter']
72+
.. self.class.packages.counters:formatCounter(range[#range]))
73+
end
74+
end
75+
return table.concat(ranges, self.config['page-delimiter'])
76+
end
77+
78+
function package:formatPages (pages)
79+
if self.config['page-range-format'] ~= 'none' then
80+
return self:formatPageRanges(pages)
81+
end
82+
local ret = pl.tablex.map(function (page)
83+
return self.class.packages.counters:formatCounter(page)
84+
end, pages)
85+
return table.concat(ret, self.config['page-delimiter'])
86+
end
87+
3588
function package:registerCommands ()
3689
self:registerCommand("indexentry", function (options, content)
3790
if not options.label then
@@ -64,7 +117,7 @@ function package:registerCommands ()
64117
SU.collatedSort(sortedIndex)
65118
SILE.call("bigskip")
66119
for _, k in ipairs(sortedIndex) do
67-
local pageno = table.concat(index[k], ", ")
120+
local pageno = self:formatPages(index[k])
68121
SILE.call("index:item", { pageno = pageno }, { k })
69122
end
70123
end)
@@ -85,6 +138,15 @@ end
85138
package.documentation = [[
86139
\begin{document}
87140
An index is essentially the same thing as a table of contents, but sorted.
141+
142+
The package accepts several configuration options:
143+
\begin{itemize}
144+
\item{\autodoc:parameter{page-range-format}: The format used to display page ranges.
145+
Possible values are \autodoc:parameter{expanded} (default), \autodoc:parameter{none}.}
146+
\item{\autodoc:parameter{page-range-delimiter}: The delimiter between the start and end of a page range.}
147+
\item{\autodoc:parameter{page-delimiter}: The delimiter between pages.}
148+
\end{itemize}
149+
88150
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).
89151
Index entries are collated at the end of each page, and the command \autodoc:command{\printindex} will deposit them in a list.
90152
The entry can be styled using the \autodoc:command{\index:item} command.

0 commit comments

Comments
 (0)