diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkxl/strc-not.lmt')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkxl/strc-not.lmt | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkxl/strc-not.lmt b/Master/texmf-dist/tex/context/base/mkxl/strc-not.lmt new file mode 100644 index 00000000000..e05228b2b51 --- /dev/null +++ b/Master/texmf-dist/tex/context/base/mkxl/strc-not.lmt @@ -0,0 +1,530 @@ +if not modules then modules = { } end modules ['strc-not'] = { + version = 1.001, + comment = "companion to strc-not.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local format = string.format +local next = next + +local trace_notes = false trackers.register("structures.notes", function(v) trace_notes = v end) +local trace_references = false trackers.register("structures.notes.references", function(v) trace_references = v end) + +local report_notes = logs.reporter("structure","notes") + +local structures = structures +local helpers = structures.helpers +local lists = structures.lists +local sections = structures.sections +local counters = structures.counters +local notes = structures.notes +local references = structures.references +local counterspecials = counters.specials + +local texgetcount = tex.getcount +local texgetbox = tex.getbox + +-- todo: allocate + +notes.states = notes.states or { } +lists.enhancers = lists.enhancers or { } +notes.numbers = notes.numbers or { } + +storage.register("structures/notes/states", notes.states, "structures.notes.states") +storage.register("structures/notes/numbers", notes.numbers, "structures.notes.numbers") + +local notestates = notes.states +local notedata = table.setmetatableindex("table") + +local variables = interfaces.variables +local context = context +local commands = commands + +local implement = interfaces.implement + +-- state: store, insert, postpone + +local function store(tag,n) + -- somewhat weird but this is a cheap hook spot + if not counterspecials[tag] then + counterspecials[tag] = function(tag) + context.doresetlinenotecompression(tag) -- maybe flag that controls it + end + end + -- + local nd = notedata[tag] + local nnd = #nd + 1 + nd[nnd] = n + local state = notestates[tag] + if not state then + report_notes("unknown state for %a",tag) + elseif state.kind ~= "insert" then + if trace_notes then + report_notes("storing %a with state %a as %a",tag,state.kind,nnd) + end + state.start = state.start or nnd + end + return nnd +end + +notes.store = store + +implement { + name = "storenote", + actions = { store, context }, + arguments = { "string", "integer" } +} + +local function get(tag,n) -- tricky ... only works when defined + local nd = notedata[tag] + if not n then + n = #nd + end + nd = nd[n] + if nd then + if trace_notes then + report_notes("getting note %a of %a with listindex %a",n,tag,nd) + end + -- is this right? + local newdata = lists.cached[nd] + return newdata + end +end + +local function getn(tag) + return #notedata[tag] +end + +notes.get = get +notes.getn = getn + +-- we could make a special enhancer + +local function listindex(tag,n) + local ndt = notedata[tag] + return ndt and ndt[n] +end + +notes.listindex = listindex + +implement { + name = "notelistindex", + actions = { listindex, context }, + arguments = { "string", "integer" } +} + +local function setstate(tag,newkind) + local state = notestates[tag] + if trace_notes then + report_notes("setting state of %a from %s to %s",tag,(state and state.kind) or "unset",newkind) + end + if not state then + state = { + kind = newkind + } + notestates[tag] = state + elseif newkind == "insert" then + if not state.start then + state.kind = newkind + end + else +-- if newkind == "postpone" and state.kind == "store" then +-- else + state.kind = newkind +-- end + end + -- state.start can already be set and will be set when an entry is added or flushed + return state +end + +local function getstate(tag) + local state = notestates[tag] + return state and state.kind or "unknown" +end + +notes.setstate = setstate +notes.getstate = getstate + + + +implement { + name = "setnotestate", + actions = setstate, + arguments = "2 strings", +} + +implement { + name = "getnotestate", + actions = { getstate, context }, + arguments = "string" +} + +function notes.define(tag,kind,number) + local state = setstate(tag,kind) + notes.numbers[number] = state + state.number = number +end + +implement { + name = "definenote", + actions = notes.define, + arguments = { "string", "string", "integer" } +} + +function notes.save(tag,newkind) + local state = notestates[tag] + if state and not state.saved then + if trace_notes then + report_notes("saving state of %a, old: %a, new %a",tag,state.kind,newkind or state.kind) + end + state.saveddata = notedata[tag] + state.savedkind = state.kind + state.kind = newkind or state.kind + state.saved = true + notedata[tag] = { } + end +end + +function notes.restore(tag,forcedstate) + local state = notestates[tag] + if state and state.saved then + if trace_notes then + report_notes("restoring state of %a, old: %a, new: %a",tag,state.kind,state.savedkind) + end + notedata[tag] = state.saveddata + state.kind = forcedstate or state.savedkind + state.saveddata = nil + state.saved = false + end +end + +implement { name = "savenote", actions = notes.save, arguments = "2 strings" } +implement { name = "restorenote", actions = notes.restore, arguments = "2 strings" } + +local function hascontent(tag) + local ok = notestates[tag] + if ok then + if ok.kind == "insert" then + ok = texgetbox(ok.number) + if ok then + ok = tbs.list + ok = lst and lst.next + end + else + ok = ok.start + end + end + return ok and true or false +end + +notes.hascontent = hascontent + +implement { + name = "doifnotecontent", + actions = { hascontent, commands.doif }, + arguments = "string", +} + +local function internal(tag,n) + local nd = get(tag,n) + if nd then + local r = nd.references + if r then + local i = r.internal + return i and references.internals[i] -- dependency on references + end + end + return nil +end + +local function ordered(kind,name,n) + local o = lists.ordered[kind] + o = o and o[name] + return o and o[n] +end + +notes.internal = internal +notes.ordered = ordered + +-- local function onsamepageasprevious(tag) +-- local same = false +-- local n = getn(tag,n) +-- local current = get(tag,n) +-- local previous = get(tag,n-1) +-- if current and previous then +-- local cr = current.references +-- local pr = previous.references +-- same = cr and pr and cr.realpage == pr.realpage +-- end +-- return same and true or false +-- end + +local function onsamepageasprevious(tag) + local n = getn(tag,n) + local current = get(tag,n) + if not current then + return false + end + local cr = current.references + if not cr then + return false + end + local previous = get(tag,n-1) + if not previous then + return false + end + local pr = previous.references + if not pr then + return false + end + return cr.realpage == pr.realpage +end + +notes.doifonsamepageasprevious = onsamepageasprevious + +implement { + name = "doifnoteonsamepageasprevious", + actions = { onsamepageasprevious, commands.doifelse }, + arguments = "string", +} + +function notes.checkpagechange(tag) -- called before increment ! + local nd = notedata[tag] -- can be unset at first entry + if nd then + local current = ordered("note",tag,#nd) + local nextone = ordered("note",tag,#nd+1) + if nextone then + -- we can use data from the previous pass + if nextone.pagenumber.number > current.pagenumber.number then + counters.reset(tag) + end + elseif current then + -- we need to locate the next one, best guess + if texgetcount("realpageno") > current.pagenumber.number then + counters.reset(tag) + end + end + end +end + +function notes.postpone() + if trace_notes then + report_notes("postponing all insert notes") + end + for tag, state in next, notestates do + if state.kind ~= "store" then + setstate(tag,"postpone") + end + end +end + +implement { + name = "postponenotes", + actions = notes.postpone +} + +local function getinternal(tag,n) + local li = internal(tag,n) + if li then + local references = li.references + if references then + return references.internal or 0 + end + end + return 0 +end + +local function getdeltapage(tag,n) + -- 0:unknown 1:textbefore, 2:textafter, 3:samepage + local li = internal(tag,n) + if li then + local references = li.references + if references then + -- local symb = structures.references.collected[""]["symb:"..tag..":"..n] + local rymb = structures.references.collected[""] + local symb = rymb and rymb["*"..(references.internal or 0)] + local notepage = references.realpage or 0 + local symbolpage = symb and symb.references.realpage or -1 + if trace_references then + report_notes("note number %a of %a points from page %a to page %a",n,tag,symbolpage,notepage) + end + if notepage < symbolpage then + return 3 -- after + elseif notepage > symbolpage then + return 2 -- before + elseif notepage > 0 then + return 1 -- same + end + else + -- might be a note that is not flushed due to to deep + -- nesting in a vbox + end + end + return 0 +end + +notes.getinternal = getinternal +notes.getdeltapage = getdeltapage + +implement { name = "noteinternal", actions = { getinternal, context }, arguments = { "string", "integer" } } +implement { name = "notedeltapage", actions = { getdeltapage, context }, arguments = { "string", "integer" } } + +local function flushnotes(tag,whatkind,how) -- store and postpone + local state = notestates[tag] + local kind = state.kind + if kind == whatkind then + local nd = notedata[tag] + local ns = state.start -- first index + if kind == "postpone" then + if nd and ns then + if trace_notes then + report_notes("flushing state %a of %a from %a to %a",whatkind,tag,ns,#nd) + end + for i=ns,#nd do + context.handlenoteinsert(tag,i) + end + end + state.start = nil + state.kind = "insert" + elseif kind == "store" then + if nd and ns then + if trace_notes then + report_notes("flushing state %a of %a from %a to %a",whatkind,tag,ns,#nd) + end + -- todo: as registers: start, stop, inbetween + for i=ns,#nd do + -- tricky : trialtypesetting + if how == variables.page then + local rp = get(tag,i) + rp = rp and rp.references + rp = rp and rp.symbolpage or 0 + if rp > texgetcount("realpageno") then + state.start = i + return + end + end + if i > ns then + context.betweennoteitself(tag) + end + context.handlenoteitself(tag,i) + end + end + state.start = nil + elseif kind == "reset" then + if nd and ns then + if trace_notes then + report_notes("flushing state %a of %a from %a to %a",whatkind,tag,ns,#nd) + end + end + state.start = nil + elseif trace_notes then + report_notes("not flushing state %a of %a",whatkind,tag) + end + elseif trace_notes then + report_notes("not flushing state %a of %a",whatkind,tag) + end +end + +local function flushpostponednotes() + if trace_notes then + report_notes("flushing all postponed notes") + end + for tag, _ in next, notestates do + flushnotes(tag,"postpone") + end +end + +implement { + name = "flushpostponednotes", + actions = flushpostponednotes +} + +implement { + name = "flushnotes", + actions = flushnotes, + arguments = "3 strings", +} + +function notes.resetpostponed() + if trace_notes then + report_notes("resetting all postponed notes") + end + for tag, state in next, notestates do + if state.kind == "postpone" then + state.start = nil + state.kind = "insert" + end + end +end + +implement { + name = "notetitle", + actions = function(tag,n) lists.savedlisttitle(tag,notedata[tag][n]) end, + arguments = { "string", "integer" } +} + +implement { + name = "noteprefixednumber", + actions = function(tag,n) lists.savedlistprefixednumber(tag,notedata[tag][n]) end, + arguments = { "string", "integer" } +} + +function notes.internalid(tag,n) + local nd = get(tag,n) + if nd then + local r = nd.references + return r.internal + end +end + +-- for the moment here but better in some builder modules + +-- gets register "n" and location "i" (where 1 is before) + +-- this is an experiment, we will make a more general handler instead +-- of the current note one + +local report_insert = logs.reporter("pagebuilder","insert") +local trace_insert = false trackers.register("pagebuilder.insert",function(v) trace_insert = v end) + +local texgetglue = tex.getglue +----- texsetglue = tex.setglue + +local tonode = nodes.nuts.tonode +local newgluespec = nodes.nuts.pool.gluespec -- nodes.pool.gluespec + +-- needs to be sorted out! + +local function check_spacing(index,slot) + -- we can also check for tex.insertheights > 0 (instead of i > 1) + local gn, pn, mn = tex.getinsertdistance(index) -- ,true so no testing needed + if not pn then pn = 0 end + if not mn then mn = 0 end + local gi, pi, mi = texgetglue(slot > 1 and "s_strc_notes_inbetween" or "s_strc_notes_before") + if not pi then pi = 0 end + if not mi then mi = 0 end + local gt = gn + gi + local pt = pn + pi + local mt = mn + mi + if trace_insert then + report_insert("%s %i: %p plus %p minus %p","always ",index,gn,pn,mn) + report_insert("%s %i: %p plus %p minus %p",slot > 1 and "inbetween" or "before ",index,gi,pi,mi) + report_insert("%s %i: %p plus %p minus %p","effective",index,gt,pt,mt) + end + return gt, pt, mt +end + +notes.check_spacing = check_spacing + +-- only notes, kind of hardcoded .. bah + +callback.register("build_page_insert", function(index,slot) + local state = notes.numbers[index] + if state then + return tonode(newgluespec(check_spacing(index,slot))) + else + return tonode(newgluespec()) + end +end) |