@@ -3,19 +3,30 @@ local base = require("packages.base")
33local package = pl .class (base )
44package ._name = " indexer"
55
6- local function isNotSamePage (p1 , p2 )
6+ if not SILE .scratch .pdf_destination_counter then
7+ SILE .scratch .pdf_destination_counter = 1
8+ end
9+
10+ -- Check if page p2 is not the same as previous page p1.
11+ -- @tparam table p1 A page counter value or nil (if no previous page yet).
12+ -- @tparam table p2 A page counter value.
13+ -- @treturn boolean True if p2 is not the same as p1.
14+ local function _isNotSamePage (p1 , p2 )
715 if not p1 then
816 return true
917 end
1018 return p1 .display ~= p2 .display or p1 .value ~= p2 .value
1119end
1220
13- local function groupPageRanges (pages )
21+ -- Group pages into ranges of consecutive pages.
22+ -- @tparam table pages A list of pages with pageno and link fields.
23+ -- @treturn table A list of ranges, each containing a list of pages.
24+ local function _groupPageRanges (pages )
1425 local ret = {}
1526 for _ , page in ipairs (pages ) do
1627 if # ret == 0
17- or ret [# ret ][# ret [# ret ]].display ~= page .display
18- or ret [# ret ][# ret [# ret ]].value + 1 ~= page .value
28+ or ret [# ret ][# ret [# ret ]].pageno . display ~= page . pageno .display
29+ or ret [# ret ][# ret [# ret ]].pageno . value + 1 ~= page . pageno .value
1930 then
2031 table.insert (ret , { page })
2132 else
@@ -25,6 +36,33 @@ local function groupPageRanges(pages)
2536 return ret
2637end
2738
39+ -- Wrap content in a link if a destination is provided.
40+ -- @tparam string dest The destination name.
41+ -- @tparam string page The page number.
42+ -- @treturn table The content AST, possibly wrapped in a link.
43+ local function _linkWrapper (dest , page )
44+ if dest and SILE .Commands [" pdf:link" ] then
45+ return SU .ast .createCommand (" pdf:link" , { dest = dest }, page )
46+ end
47+ return page
48+ end
49+
50+ -- Add a delimiter between elements of a table.
51+ -- @tparam table t A list of elements.
52+ -- @tparam string sep The delimiter.
53+ -- @treturn table A new list with the delimiter inserted between elements.
54+ local function _addDelimiter (t , sep )
55+ local ret = {}
56+ for i = 1 , # t - 1 do
57+ table.insert (ret , t [i ])
58+ table.insert (ret , sep )
59+ end
60+ if # t > 0 then
61+ table.insert (ret , t [# t ])
62+ end
63+ return ret
64+ end
65+
2866function package .buildIndex ()
2967 local nodes = SILE .scratch .info .thispage .index
3068 local pageno = pl .tablex .copy (SILE .scratch .counters .folio )
@@ -40,8 +78,8 @@ function package.buildIndex ()
4078 index [node .label ] = {}
4179 end
4280 local pages = index [node .label ]
43- if not # pages or isNotSamePage (pages [# pages ], pageno ) then
44- table.insert (pages , pageno )
81+ if not # pages or _isNotSamePage (pages [# pages ], pageno ) then
82+ table.insert (pages , { pageno = pageno , link = node . link } )
4583 end
4684 end
4785end
62100
63101function package :formatPageRanges (pages )
64102 local ranges = {}
65- for _ , range in ipairs (groupPageRanges (pages )) do
103+ for _ , range in ipairs (_groupPageRanges (pages )) do
66104 if # range == 1 then
67- table.insert (ranges , self .class .packages .counters :formatCounter (range [1 ]))
105+ table.insert (ranges , _linkWrapper ( range [ 1 ]. link , self .class .packages .counters :formatCounter (range [1 ]. pageno ) ))
68106 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 ]))
107+ table.insert (ranges , {
108+ _linkWrapper (range [1 ].link , self .class .packages .counters :formatCounter (range [1 ].pageno )),
109+ self .config [' page-range-delimiter' ],
110+ _linkWrapper (range [# range ].link , self .class .packages .counters :formatCounter (range [# range ].pageno ))
111+ })
73112 end
74113 end
75- return table.concat (ranges , self .config [' page-delimiter' ])
114+ return _addDelimiter (ranges , self .config [' page-delimiter' ])
76115end
77116
78117function package :formatPages (pages )
79118 if self .config [' page-range-format' ] ~= ' none' then
80119 return self :formatPageRanges (pages )
81120 end
82121 local ret = pl .tablex .map (function (page )
83- return self .class .packages .counters :formatCounter (page )
122+ return _linkWrapper ( page . link , self .class .packages .counters :formatCounter (page . pageno ) )
84123 end , pages )
85- return table.concat (ret , self .config [' page-delimiter' ])
124+ return _addDelimiter (ret , self .config [' page-delimiter' ])
86125end
87126
88127function package :registerCommands ()
@@ -102,8 +141,21 @@ function package:registerCommands ()
102141 if not options .index then
103142 options .index = " main"
104143 end
105- SILE .call (" info" , { category = " index" , value = { index = options .index , label = options .label } })
106- end )
144+ local dest
145+ if SILE .Commands [" pdf:destination" ] then
146+ dest = " dest" .. tostring (SILE .scratch .pdf_destination_counter )
147+ SILE .call (" pdf:destination" , { name = dest })
148+ SILE .scratch .pdf_destination_counter = SILE .scratch .pdf_destination_counter + 1
149+ end
150+ SILE .call (" info" , {
151+ category = " index" ,
152+ value = {
153+ index = options .index ,
154+ label = options .label ,
155+ link = dest
156+ }
157+ })
158+ end , " Add an entry to the index" )
107159
108160 self :registerCommand (" printindex" , function (options , _ )
109161 if not options .index then
@@ -120,19 +172,20 @@ function package:registerCommands ()
120172 local pageno = self :formatPages (index [k ])
121173 SILE .call (" index:item" , { pageno = pageno }, { k })
122174 end
123- end )
175+ end , " Print the index " )
124176
125177 self :registerCommand (" index:item" , function (options , content )
178+ -- Unconventional: options.pageno is an AST
126179 SILE .settings :temporarily (function ()
127180 SILE .settings :set (" typesetter.parfillskip" , SILE .types .node .glue ())
128181 SILE .settings :set (" current.parindent" , SILE .types .node .glue ())
129182 SILE .call (" code" , {}, content )
130183 -- Ideally, leaders
131184 SILE .call (" hss" )
132- SILE .typesetter : typeset (options .pageno )
185+ SILE .process (options .pageno )
133186 SILE .call (" smallskip" )
134187 end )
135- end )
188+ end , " Output an index item " )
136189end
137190
138191package .documentation = [[
@@ -153,6 +206,8 @@ The entry can be styled using the \autodoc:command{\index:item} command.
153206
154207Multiple indexes are available and an index can be selected by passing the \autodoc:parameter{index=<name>} parameter to \autodoc:command{\indexentry} and \autodoc:command{\printindex}.
155208
209+ If the \autodoc:package{pdf} package is loaded, then pages in the index will be hyperlinked to the relevant references.
210+
156211\end{document}
157212]]
158213
0 commit comments