diff options
author | Karl Berry <karl@freefriends.org> | 2015-04-18 22:52:45 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2015-04-18 22:52:45 +0000 |
commit | 16aa5a7c87f18a2483d0d61795899f886781b51c (patch) | |
tree | 1d72f00b2a4185425393598402fe055c61d1de58 /Master/texmf-dist/tex/context/base/strc-bkm.lua | |
parent | e68dc4d5506d46bf72823234f902bc76d1f70352 (diff) |
context, from www.pragma-ade.com/context/beta/cont-tmf.zip (18apr15)
git-svn-id: svn://tug.org/texlive/trunk@36923 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/strc-bkm.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/strc-bkm.lua | 425 |
1 files changed, 335 insertions, 90 deletions
diff --git a/Master/texmf-dist/tex/context/base/strc-bkm.lua b/Master/texmf-dist/tex/context/base/strc-bkm.lua index c38ab3c2e8c..1ff75aa5f72 100644 --- a/Master/texmf-dist/tex/context/base/strc-bkm.lua +++ b/Master/texmf-dist/tex/context/base/strc-bkm.lua @@ -13,14 +13,15 @@ if not modules then modules = { } end modules ['strc-bkm'] = { -- we should hook the placement into everystoptext ... needs checking -local format, concat, gsub = string.format, table.concat, string.gsub +-- todo: make an lpeg for stripped + +local next, type = next, type +local gsub, lower = string.gsub, string.lower +local concat = table.concat local utfvalues = utf.values local settings_to_hash = utilities.parsers.settings_to_hash -local codeinjections = backends.codeinjections - -local trace_bookmarks = false trackers.register("references.bookmarks", function(v) trace_bookmarks = v end) - +local trace_bookmarks = false trackers.register("references.bookmarks", function(v) trace_bookmarks = v end) local report_bookmarks = logs.reporter("structure","bookmarks") local structures = structures @@ -30,13 +31,17 @@ structures.bookmarks = structures.bookmarks or { } local bookmarks = structures.bookmarks local sections = structures.sections local lists = structures.lists - local levelmap = sections.levelmap local variables = interfaces.variables +local implement = interfaces.implement +local codeinjections = backends.codeinjections -bookmarks.method = "internal" -- or "page" +bookmarks.method = "internal" -- or "page" -local names, opened, forced, numbered = { }, { }, { }, { } +local names = { } +local opened = { } +local forced = { } +local numbered = { } function bookmarks.register(settings) local force = settings.force == variables.yes @@ -78,8 +83,13 @@ function bookmarks.overload(name,text) end end if ls then - ls.titledata.bookmark = text + local titledata = ls.titledata + if titledata then + titledata.bookmark = text + end end + -- last resort + -- context.writetolist({name},text,"") end local function stripped(str) -- kind of generic @@ -101,54 +111,6 @@ function bookmarks.setup(spec) end end --- function bookmarks.place() --- if next(names) then --- local list = lists.filtercollected(names,"all",nil,lists.collected,forced) --- if #list > 0 then --- local levels, noflevels, lastlevel = { }, 0, 1 --- for i=1,#list do --- local li = list[i] --- local metadata = li.metadata --- local name = metadata.name --- if not metadata.nolist or forced[name] then -- and levelmap[name] then --- local titledata = li.titledata --- if titledata then --- local structural = levelmap[name] --- lastlevel = structural or lastlevel --- local title = titledata.bookmark --- if not title or title == "" then --- -- We could typeset the title and then convert it. --- if not structural then --- -- placeholder, todo: bookmarklabel --- title = name .. ": " .. (titledata.title or "?") --- else --- title = titledata.title or "?" --- end --- end --- if numbered[name] then --- local sectiondata = sections.collected[li.references.section] --- local numberdata = li.numberdata --- if sectiondata and numberdata and not numberdata.hidenumber then --- -- we could typeset the number and convert it --- title = concat(sections.typesetnumber(sectiondata,"direct",numberspec,sectiondata)) .. " " .. title --- end --- end --- noflevels = noflevels + 1 --- levels[noflevels] = { --- lastlevel, --- stripped(title), -- can be replaced by converter --- li.references, -- has internal and realpage --- allopen or opened[name] --- } --- end --- end --- end --- bookmarks.finalize(levels) --- end --- function bookmarks.place() end -- prevent second run --- end --- end - function bookmarks.place() if next(names) then local levels = { } @@ -157,26 +119,51 @@ function bookmarks.place() local nofblocks = #lists.sectionblocks -- always >= 1 local showblocktitle = toboolean(numberspec.showblocktitle,true) for i=1,nofblocks do - local block = lists.sectionblocks[i] + local block = lists.sectionblocks[i] local blockdone = nofblocks == 1 - local list = lists.filtercollected(names,block..":all",nil,lists.collected,forced) + local list = lists.filter { + names = names, + criterium = block .. ":all", + forced = forced, + } for i=1,#list do local li = list[i] local metadata = li.metadata local name = metadata.name if not metadata.nolist or forced[name] then -- and levelmap[name] then local titledata = li.titledata + -- + if not titledata then + local userdata = li.userdata + if userdata then + local first = userdata.first + local second = userdata.second + if first then + if second then + titledata = { title = first .. " " .. second } + else + titledata = { title = first } + end + else + titledata = { title = second } + end + end + end + -- if titledata then if not blockdone then if showblocktitle then -- add block entry local blockdata = sections.sectionblockdata[block] noflevels = noflevels + 1 + local references = li.references levels[noflevels] = { - 1, -- toplevel - stripped(blockdata.bookmark ~= "" and blockdata.bookmark or block), - li.references, - allopen or opened[name] -- same as first entry + level = 1, -- toplevel + title = stripped(blockdata.bookmark ~= "" and blockdata.bookmark or block), + reference = references, + opened = allopen or opened[name], -- same as first entry + realpage = references and references.realpage or 0, -- handy for later + usedpage = true, } end blockdone = true @@ -190,27 +177,36 @@ function bookmarks.place() local title = titledata.bookmark if not title or title == "" then -- We could typeset the title and then convert it. - if not structural then - -- placeholder, todo: bookmarklabel - title = name .. ": " .. (titledata.title or "?") - else + -- if not structural then + -- title = titledata.title or "?") + -- else title = titledata.title or "?" - end + -- end end if numbered[name] then local sectiondata = sections.collected[li.references.section] local numberdata = li.numberdata - if sectiondata and numberdata and not numberdata.hidenumber then + if sectiondata and numberdata then + if not numberdata.hidenumber then -- we could typeset the number and convert it - title = concat(sections.typesetnumber(sectiondata,"direct",numberspec,sectiondata)) .. " " .. title + local number = sections.typesetnumber(sectiondata,"direct",numberspec,sectiondata) + if number and #number > 0 then + title = concat(number) .. " " .. title + end + end end end noflevels = noflevels + 1 + local references = li.references levels[noflevels] = { - lastlevel, - stripped(title), -- can be replaced by converter - li.references, -- has internal and realpage - allopen or opened[name] + level = lastlevel, + title = stripped(title), -- can be replaced by converter + reference = references, -- has internal and realpage + opened = allopen or opened[name], + realpage = references and references.realpage or 0, -- handy for later + usedpage = true, + structural = structural, + name = name, } end end @@ -222,47 +218,296 @@ function bookmarks.place() end function bookmarks.flatten(levels) + if not levels then + -- a plugin messed up + return { } + end -- This function promotes leading structurelements with a higher level -- to the next lower level. Such situations are the result of lack of -- structure: a subject preceding a chapter in a sectionblock. So, the -- following code runs over section blocks as well. (bookmarks-007.tex) local noflevels = #levels if noflevels > 1 then - local skip, start, one = false, 1, levels[1] - local first, block = one[1], one[3].block + local function showthem() + for i=1,noflevels do + local level = levels[i] + -- if level.structural then + -- report_bookmarks("%i > %s > %s",level.level,level.reference.block,level.title) + -- else + report_bookmarks("%i > %s > %s > %s",level.level,level.reference.block,level.name,level.title) + -- end + end + end + if trace_bookmarks then + report_bookmarks("checking structure") + showthem() + end + local skip = false + local done = 0 + local start = 1 + local one = levels[1] + local first = one.level + local block = one.reference.block for i=2,noflevels do - local li = levels[i] - local new, newblock = li[1], li[3].block + local current = levels[i] + local new = current.level + local reference = current.reference + local newblock = type(reference) == "table" and current.reference.block or block if newblock ~= block then - first, block, start, skip = new, newblock, i, false + first = new + block = newblock + start = i + skip = false elseif skip then -- go on elseif new > first then skip = true elseif new < first then for j=start,i-1 do - local lj = levels[j] - local old = lj[1] - lj[1] = new + local previous = levels[j] + local old = previous.level + previous.level = new if trace_bookmarks then - report_bookmarks("promoting entry %a from level %a to %a: %s",j,old,new,lj[2]) + report_bookmarks("promoting entry %a from level %a to %a: %s",j,old,new,previous.title) end + done = done + 1 end skip = true end end + if trace_bookmarks then + if done > 0 then + report_bookmarks("%a entries promoted") + showthem() + else + report_bookmarks("nothing promoted") + end + end + end + return levels +end + +local extras = { } +local lists = { } +local names = { } + +bookmarks.extras = extras + +local function cleanname(name) + return lower(file.basename(name)) +end + +function extras.register(name,levels) + if name and levels then + name = cleanname(name) + local found = names[name] + if found then + lists[found].levels = levels + else + lists[#lists+1] = { + name = name, + levels = levels, + } + names[name] = #lists + end + end +end + +function extras.get(name) + if name then + local found = names[cleanname(name)] + if found then + return lists[found].levels + end + else + return lists + end +end + +function extras.reset(name) + local l, n = { }, { } + if name then + name = cleanname(name) + for i=1,#lists do + local li = lists[i] + local ln = li.name + if name == ln then + -- skip + else + local m = #l + 1 + l[m] = li + n[ln] = m + end + end + end + lists, names = l, n +end + +local function checklists() + for i=1,#lists do + local levels = lists[i].levels + for j=1,#levels do + local entry = levels[j] + local pageindex = entry.pageindex + if pageindex then + entry.reference = figures.getrealpage(pageindex) + entry.pageindex = nil + end + end end end +function extras.tosections(levels) + local sections = { } + local noflists = #lists + for i=1,noflists do + local levels = lists[i].levels + local data = { } + sections[i] = data + for j=1,#levels do + local entry = levels[j] + if entry.usedpage then + local section = entry.section + local d = data[section] + if d then + d[#d+1] = entry + else + data[section] = { entry } + end + end + end + end + return sections +end + +function extras.mergesections(levels,sections) + if not sections or #sections == 0 then + return levels + elseif not levels then + return { } + else + local merge = { } + local noflists = #lists + if #levels == 0 then + local level = 0 + local section = 0 + for i=1,noflists do + local entries = sections[i][0] + if entries then + for i=1,#entries do + local entry = entries[i] + merge[#merge+1] = entry + entry.level = entry.level + level + end + end + end + else + for j=1,#levels do + local entry = levels[j] + merge[#merge+1] = entry + local section = entry.reference.section + local level = entry.level + entry.section = section -- for tracing + for i=1,noflists do + local entries = sections[i][section] + if entries then + for i=1,#entries do + local entry = entries[i] + merge[#merge+1] = entry + entry.level = entry.level + level + end + end + end + end + end + return merge + end +end + +function bookmarks.merge(levels,mode) + return extras.mergesections(levels,extras.tosections()) +end + +local sequencers = utilities.sequencers +local appendgroup = sequencers.appendgroup +local appendaction = sequencers.appendaction + +local bookmarkactions = sequencers.new { + arguments = "levels,method", + returnvalues = "levels", + results = "levels", +} + +appendgroup(bookmarkactions,"before") -- user +appendgroup(bookmarkactions,"system") -- private +appendgroup(bookmarkactions,"after" ) -- user + +appendaction(bookmarkactions,"system",bookmarks.flatten) +appendaction(bookmarkactions,"system",bookmarks.merge) + function bookmarks.finalize(levels) - -- This function can be overloaded by an optional converter - -- that uses nodes.toutf on a typeset stream. This is something - -- that we will support when the main loop has become a coroutine. - codeinjections.addbookmarks(levels,bookmarks.method) + local method = bookmarks.method or "internal" + checklists() -- so that plugins have the adapted page number + levels = bookmarkactions.runner(levels,method) + if levels and #levels > 0 then + -- normally this is not needed + local purged = { } + for i=1,#levels do + local l = levels[i] + if l.usedpage ~= false then + purged[#purged+1] = l + end + end + -- + codeinjections.addbookmarks(purged,method) + else + -- maybe a plugin messed up + end +end + +function bookmarks.installhandler(what,where,func) + if not func then + where, func = "after", where + end + if where == "before" or where == "after" then + sequencers.appendaction(bookmarkactions,where,func) + else + report_tex("installing bookmark %a handlers in %a is not possible",what,tostring(where)) + end end -- interface -commands.overloadbookmark = bookmarks.overload -commands.registerbookmark = bookmarks.register -commands.setupbookmarks = bookmarks.setup +implement { + name = "setupbookmarks", + actions = bookmarks.setup, + arguments = { + { + { "separatorset" }, + { "conversionset" }, + { "starter" }, + { "stopper" }, + { "segments" }, + { "showblocktitle" }, + } + } +} + +implement { + name = "registerbookmark", + actions = bookmarks.register, + arguments = { + { + { "names" }, + { "opened" }, + { "force" }, + { "number" }, + } + } +} + +implement { + name = "overloadbookmark", + actions = bookmarks.overload, + arguments = { "string", "string" } +} |