Differences From
Artifact [e8a2cf6308]:
136 136 end;
137 137 [true] = function (job, ctx, words)
138 138 local _, op, val = words(2)
139 139 if op == nil then
140 140 local toc = {kind='toc'}
141 141 ctx:insert(toc)
142 142 -- same deal here -- directives are processed as part of
143 - -- the parse job, which is forked off the document job,
144 - -- so we need to climb the jobstack
143 + -- the parse job, which is forked off the document job;
144 + -- if we want state that can persist into the render job,
145 + -- we need to climb the jobstack
145 146 job:unwind(1).state.toc_custom_position = true
146 147 job:hook('ext_toc_position', ctx, toc)
147 148 else
148 149 ctx:fail 'bad %toc directive'
149 150 end
150 151 end;
151 152 };
................................................................................
188 189 -- each node.
189 190 local stack = {lst}
190 191 local top = function() return stack[#stack] end
191 192 -- job.doc is the document the render job is bound to, and
192 193 -- its secorder field is a list of all the doc's sections in
193 194 -- the order they occur ("doc.sections" is a hashmap from name
194 195 -- to section object)
195 - local all = job.doc.secorder
196 + local all = {}
197 +
198 + local function blockHasSubdoc(b)
199 + local subdocBlockKinds = {
200 + quote = true;
201 + embed = true;
202 + macro = true;
203 + }
204 + return subdocBlockKinds[b.kind] and ct.doc.is(b.doc)
205 + end
206 +
207 + local function scandoc(doc, depth)
208 + for i, sec in ipairs(doc.secorder) do
209 + table.insert(all, {ref = sec, depth = sec.depth + depth})
210 + for j, block in ipairs(sec.blocks) do
211 + if blockHasSubdoc(block) then
212 + scandoc(block.doc, depth + sec.depth-1)
213 + end
214 + end
215 + end
216 + end
217 +
218 + scandoc(job.doc,0)
196 219
197 - for i, sec in ipairs(all) do
220 + for i, secptr in ipairs(all) do
221 + local sec = secptr.ref
198 222 if sec.heading_node then -- does this section have a label?
199 223 local ent = tag('li',nil,
200 224 catenate{tag('a', {href='#'..getSafeID(sec)},
201 225 sr.htmlSpan(sec.heading_node.spans, sec.heading_node, sec))})
202 - if sec.depth > #stack then
226 + if secptr.depth > #stack then
203 227 local n = {tag = 'ol', attrs={}, nodes={ent}}
204 228 table.insert(top().nodes[#top().nodes].nodes, n)
205 229 table.insert(stack, n)
206 230 else
207 - if sec.depth < #stack then
208 - for j=#stack,sec.depth+1,-1 do stack[j] = nil end
231 + if secptr.depth < #stack then
232 + for j=#stack,secptr.depth+1,-1 do stack[j] = nil end
209 233 end
210 234 table.insert(top().nodes, ent)
211 235 end
212 236
213 237 -- now we need to assemble a list of items within the
214 238 -- section worthy of an entry on their own. currently
215 239 -- this is only anchors created with %toc mark|name
................................................................................
234 258 local nn = {
235 259 tag = 'a';
236 260 attrs = {href = '#' .. l.id};
237 261 nodes = {sr.htmlSpan(l.label, l.block, sec)};
238 262 }
239 263 table.insert(n.nodes, {tag = 'li', attrs = {}, nodes={nn}})
240 264 end
241 - table.insert(ent.nodes, n)
265 + table.insert(top().nodes, n)
266 + table.insert(stack, n)
242 267 end
243 268 end
244 269 end
245 270 return lst
246 271 end;
247 272
248 273 [true] = function() end; -- fallback // convert to different node types
249 274 };
250 275 };
251 276 }