summaryrefslogtreecommitdiff
path: root/tex/context/base/mkxl/typo-syn.lmt
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkxl/typo-syn.lmt')
-rw-r--r--tex/context/base/mkxl/typo-syn.lmt452
1 files changed, 341 insertions, 111 deletions
diff --git a/tex/context/base/mkxl/typo-syn.lmt b/tex/context/base/mkxl/typo-syn.lmt
index dbc5b27ff..fc03ccb3b 100644
--- a/tex/context/base/mkxl/typo-syn.lmt
+++ b/tex/context/base/mkxl/typo-syn.lmt
@@ -16,39 +16,38 @@ local enableaction = tasks.enableaction
local nuts = nodes.nuts
local tonut = nodes.tonut
-local getnext = nuts.getnext
-local getprev = nuts.getprev
-local getid = nuts.getid
-local getsubtype = nuts.getsubtype
local getattr = nuts.getattr
-local setattrlist = nuts.setattrlist
local getattrlist = nuts.getattrlist
-
+local getdepth = nuts.getdepth
+local getdirection = nuts.getdirection
+local getdisc = nuts.getdisc
+local getglue = nuts.getglue
+local getheight = nuts.getheight
+local getid = nuts.getid
+local getlist = nuts.getlist
+local getnext = nuts.getnext
+local getprev = nuts.getprev
local getprop = nuts.getprop
-local setprop = nuts.setprop
-
-local setlink = nuts.setlink
-local setprev = nuts.setprev
-local setnext = nuts.setnext
-local setoffsets = nuts.setoffsets
-
+local getsubtype = nuts.getsubtype
+local gettotal = nuts.gettotal
local getwhd = nuts.getwhd
-
local getwidth = nuts.getwidth
-local setwidth = nuts.setwidth
-local getdepth = nuts.getdepth
+local setattrlist = nuts.setattrlist
local setdepth = nuts.setdepth
-local getheight = nuts.getheight
+local setdisc = nuts.setdisc
local setheight = nuts.setheight
-local gettotal = nuts.gettotal
-local getlist = nuts.getlist
+local setlink = nuts.setlink
local setlist = nuts.setlist
-local getdisc = nuts.getdisc
-local setdisc = nuts.setdisc
+local setnext = nuts.setnext
+local setoffsets = nuts.setoffsets
+local setprev = nuts.setprev
+local setprop = nuts.setprop
+local setwidth = nuts.setwidth
local hpack = nuts.hpack
local rangedimensions = nuts.rangedimensions
local insertbefore = nuts.insertbefore
+local insertafter = nuts.insertafter
local removenode = nuts.remove
local flushnode = nuts.flush
@@ -57,28 +56,33 @@ local traverselist = nuts.traverselist
local nodecodes = nodes.nodecodes
local glyph_code = nodecodes.glyph
local rule_code = nodecodes.rule
+local dir_code = nodecodes.dir
local disc_code = nodecodes.disc
local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
+local math_code = nodecodes.math
local glue_code = nodecodes.glue
local kern_code = nodecodes.kern
local penalty_code = nodecodes.penalty
-local line_code = nodes.listcodes.line
-local fontkern_code = nodes.kerncodes.fontkern
-local parfillrightskip_code = nodes.gluecodes.parfillrightskip
-local baselineskip_code = nodes.gluecodes.baselineskip
+local line_code = nodes.listcodes.line
+local fontkern_code = nodes.kerncodes.fontkern
+local parfillskip_code = nodes.gluecodes.parfillrightskip
+local baselineskip_code = nodes.gluecodes.baselineskip
------------------
+local new_direction = nuts.pool.direction
-local a_synchronize = attributes.private("synchronize")
+local runningrule = tex.magicconstants.runningrule
-local parallels = typesetters.parallels or { }
-typesetters.parallels = parallels or { }
+-----------------
+
+local synchronize = typesetters.synchronize or { }
+typesetters.synchronize = synchronize or { }
-local registervalue = attributes.registervalue
-local getvalue = attributes.getvalue
-local hasvalues = attributes.hasvalues
+local a_synchronize = attributes.private("synchronize")
+local registervalue = attributes.registervalue
+local getvalue = attributes.getvalue
+local hasvalues = attributes.hasvalues
local trace = false
-- local trace = true
@@ -88,21 +92,21 @@ local pushsavelevel = tex.pushsavelevel -- token.expandmacro("bgroup")
local popsavelevel = tex.popsavelevel -- token.expandmacro("egroup")
local dontcomplain = tex.dontcomplain
-local slack = 6553.6
local index = 0
local lastattr = nil
local lastline = nil
interfaces.implement {
name = "registersynchronize",
- arguments = { "dimen", "dimen", "box" },
- actions = function(ht,dp,box)
+ arguments = { "dimen", "dimen", "dimen", "box" },
+ actions = function(ht,dp,slack,box)
index = index + 1
box = tonut(box)
local t = {
index = index,
lineheight = ht,
linedepth = dp,
+ slack = slack,
height = getheight(height),
depth = getheight(depth),
box = box,
@@ -110,94 +114,147 @@ interfaces.implement {
local v = registervalue(a_synchronize,t)
tex.setattribute(a_synchronize,v)
if index > 0 then
- enableaction("vboxbuilders", "typesetters.parallels.handler")
- enableaction("mvlbuilders", "typesetters.parallels.handler")
+ enableaction("vboxbuilders", "typesetters.synchronize.handler")
+ enableaction("mvlbuilders", "typesetters.synchronize.handler")
end
end,
-
}
-local function hsplit(box,width)
- local first = getlist(box)
- local last = first
- local current = first
- local previous = current
- local sofar = 0
- local lastdisc = nil
- -- todo: option
- width = width - slack
- --
+-- When this is stable it can become a proper helper and primitive.
+
+local function hsplit(box,targetwidth,targetheight,targetdepth,mcriterium,pcriterium,upto)
+ local first = getlist(box)
+ local last = first
+ local current = first
+ local previous = current
+ local lastdisc = nil
+ local lastglyph = nil
+ -- local stretch = 0
+ -- local shrink = 0
+ local width = 0
+ local height = 0
+ local depth = 0
+ local dirstack = { } -- can move to outer
+ local dirtop = 0
+ local minwidth = targetwidth
+ local maxwidth = targetwidth
+ local usedwidth = targetwidth
while true do
previous = current
local id = getid(current)
if id == glyph_code then
- local wd = getwidth(current)
- if sofar + wd > width then
+ local wd, ht, dp = getwhd(current)
+ -- find next break first
+ local newwidth = width + wd
+ if newwidth >= usedwidth then
+ if not lastdisc and lastglyph then
+ last = getprev(lastglyph)
+ end
break
else
- sofar = sofar + wd
+ width = newwidth
+ if ht > height then
+ height = ht
+ end
+ if dp > depth then
+ depth = dp
+ end
+ end
+ if not lastglyph then
+ lastglyph = current
end
elseif id == kern_code then
+ local wd = getwidth(current)
+ local newwidth = width + wd
if getsubtype(current) == fontkern_code then
-- assume sane kerns
- local wd = getwidth(current)
- sofar = sofar + wd
+ width = newwidth
else
last = previous
- local wd = getwidth(current)
- if sofar + wd > width then
+ if newwidth >= usedwidth then
break
else
- sofar = sofar + wd
+ width = newwidth
end
- lastdisc = nil
+ lastdisc = nil
+ lastglyph = nil
end
elseif id == disc_code then
- -- move on / inject post if needed
local pre, post, replace = getdisc(current)
- local wdr = replace and rangedimensions(box,replace) or 0
- if sofar + wdr > width then
- -- handle post and pre here
- last = previous
+ local wd = replace and rangedimensions(box,replace) or 0
+ local newwidth = width + wd
+ if newwidth >= usedwidth then
break
end
- local wdp = pre and rangedimensions(box,pre) or 0
--- if sofar + wdp > width then
--- last = previous
---lastdisc = current
--- break
--- end
- sofar = sofar + wdr
- lastdisc = current
- elseif id == glue_code then
- last = previous
- local wd = getwidth(current)
- if sofar + wd > width then
+ local wd = pre and rangedimensions(box,pre) or 0
+ local prewidth = width + wd
+ if prewidth >= usedwidth then
break
- else
- sofar = sofar + wd
end
- lastdisc = nil
- elseif id == hlist_code or id == vlist_code then
- last = previous
- local wd = getwidth(current)
- if sofar + wd > width then
- break
- else
- sofar = sofar + wd
- end
- lastdisc = nil
- elseif id == rule_code then
- last = previous
- local wd = getwidth(current)
- if sofar + wd > width then
- break
- else
- sofar = sofar + wd
- end
- lastdisc = nil
+ width = newwidth
+ lastdisc = current
else
- lastdisc = nil
+ -- common code at the end
+ if id == glue_code or id == math_code then -- refactor : common code
+ -- leaders
+ last = previous
+ local wd, more, less = getglue(current)
+ local newwidth = width + wd
+ if newwidth >= usedwidth then
+ break
+ else
+ width = newwidth
+ -- stretch = stretch + more
+ -- shrink = shrink + less
+ -- also for statistics
+ maxwidth = maxwidth + more
+ minwidth = minwidth + less
+ -- can become an option:
+ usedwidth = minwidth
+ end
+ elseif id == hlist_code or id == vlist_code then
+ last = previous
+ local wd, ht, dp = getwhd(current)
+ local newwidth = width + wd
+ if newwidth >= usedwidth then
+ break
+ else
+ width = newwidth
+ if ht > height then
+ height = ht
+ end
+ if dp > depth then
+ depth = dp
+ end
+ end
+ elseif id == rule_code then
+ last = previous
+ local wd, ht, dp = getwhd(current)
+ local newwidth = width + wd
+ if newwidth >= usedwidth then
+ break
+ else
+ width = newwidth
+ if ht ~= runningrule and ht > height then
+ height = ht
+ end
+ if dp ~= runningrule and dp > depth then
+ depth = dp
+ end
+ end
+ elseif id == dir_code then
+ local dir, cancel = getdirection(current)
+ if cancel then
+ if dirtop > 0 then
+ dirtop = dirtop - 1
+ end
+ else
+ dirtop = dirtop + 1
+ dirstack[dirtop] = dir
+ end
+ end
+ lastdisc = nil
+ lastglyph = nil
end
local next = getnext(current)
if next then
@@ -209,7 +266,7 @@ local function hsplit(box,width)
end
local next
if lastdisc then
- local pre, post, replace = getdisc(lastdisc)
+ local pre, post, replace, pretail, posttail, replacetail = getdisc(lastdisc,true)
last = getprev(lastdisc)
--
next = getnext(lastdisc)
@@ -218,8 +275,9 @@ local function hsplit(box,width)
end
--
setlink(last,pre)
+ last = pretail
if post then
- setlink(post,next)
+ setlink(posttail,next)
next = post
end
setdisc(lastdisc,nil,nil,replace)
@@ -234,28 +292,140 @@ local function hsplit(box,width)
while last do
local id = getid(last)
if id == glue_code or id == penalty_code then
+ -- if id == glue_code then
+ -- local wd, more, less = getglue(last)
+ -- -- stretch = stretch - more
+ -- -- shrink = shrink - less
+ -- width = width - wd
+ -- -- also for statistics
+ -- maxwidth = maxwidth - more
+ -- minwidth = minwidth - less
+ -- -- can become an option:
+ -- usedwidth = minwidth
+ -- end
first, last = removenode(first,last,true)
else
break
end
end
+ if dirtop > 0 then
+ for i=dirtop,1,-1 do
+ local d = new_direction(dirstack[i],true)
+ first, last = insertafter(first,last,d)
+ end
+ for i=1,dirtop do
+ local d = new_direction(dirstack[i],false)
+ next = insertbefore(next,next,d)
+ end
+ end
if first then
- pushsavelevel()
- dontcomplain()
- local result, badness = hpack(first,width,"exactly")
- if badness > 200 then
+ -- pushsavelevel()
+ -- dontcomplain()
+ local result
+ if upto then
result = hpack(first)
+ else
+ local badness, overshoot
+ result, badness, overshoot = hpack(first,targetwidth,"exactly")
+ local pdone = pcriterium and badness > pcriterium
+ local mdone = mcriterium and badness > mcriterium
+ if overshoot > 0 then
+ if pdone then
+ result = hpack(first)
+ end
+ elseif overshoot < 0 then
+ if mdone then
+ result = hpack(first)
+ end
+ else
+ if pdone or mdone then
+ result = hpack(first)
+ end
+ end
end
- popsavelevel()
+ -- popsavelevel()
setattrlist(result,getattrlist(box)) -- useattrlist(result,box)
- setheight(result,getheight(box))
- setdepth(result,getdepth(box))
+ setheight(result,targetheight or height)
+ setdepth(result,targetdepth or depth)
setlist(box,next)
setwidth(box,rangedimensions(box,next))
return result
end
end
+do
+
+ local scanners = tokens.scanners
+ local scanword = scanners.word
+ local scaninteger = scanners.integer
+ local scandimen = scanners.dimen
+
+ local tonode = nuts.tonode
+ local getbox = nuts.getbox
+ local setbox = nuts.setbox
+
+ local direct_value = tokens.values.direct
+ local none_value = tokens.values.none
+
+ interfaces.implement {
+ name = "hsplit",
+ protected = true,
+ public = true,
+ usage = "value",
+ actions = function(what)
+ local n = scaninteger()
+ local w = 0
+ local h = false
+ local d = false
+ local pcriterium = false
+ local mcriterium = false
+ local upto = false
+ while true do
+ local key = scanword()
+ if key == "to" then
+ upto = false
+ w = scandimen()
+ elseif key == "upto" then
+ upto = true
+ w = scandimen()
+ elseif key == "width" then
+ w = scandimen()
+ elseif key == "height" then
+ h = scandimen()
+ elseif key == "depth" then
+ d = scandimen()
+ elseif key == "criterium" then
+ pcriterium = scaninteger()
+ mcriterium = scaninteger()
+ elseif key == "shrinkcriterium" then
+ mcriterium = scaninteger()
+ elseif key == "stretchcriteriun" then
+ pcriterium = scaninteger()
+ else
+ break
+ end
+ end
+ pushsavelevel()
+ dontcomplain()
+ local r = hsplit(getbox(n),w,h,d,mcriterium,pcriterium,upto)
+ popsavelevel()
+ if r then
+ if what == "value" then
+ return direct_value, r
+ else
+ context(tonode(r))
+ end
+ else
+ setbox(n)
+ if what == "value" then
+ return none_value, nil
+ end
+ end
+ end,
+ }
+
+end
+
local function getproperties(parent)
local props = getprop(parent,"parallel")
if not props then
@@ -304,7 +474,7 @@ local function flush(head,first,last,a,parent,nesting)
if upto and getid(upto) == penalty_code then
upto = getnext(upto)
end
- if upto and getid(upto) == glue_code and getsubtype(upto) == parfillrightskip_code then
+ if upto and getid(upto) == glue_code and getsubtype(upto) == parfillskip_code then
upto = getnext(upto)
end
local props = getproperties(parent)
@@ -322,7 +492,7 @@ local function flush(head,first,last,a,parent,nesting)
local result = nil
local cwidth = getwidth(content)
local ctotal = gettotal(content)
- if cwidth <= width then -- slack
+ if cwidth <= width then
if trace then
report("index %i, available %p, content %p, verdict %a",index,width,cwidth,"fit")
end
@@ -332,7 +502,7 @@ local function flush(head,first,last,a,parent,nesting)
if trace then
report("index %i, available %p, content %p, verdict %a",index,width,cwidth,"overflow")
end
- result = hsplit(content,width)
+ result = hsplit(content,width-(data.slack or 0),nil,nil,200)
lastattr = a
lastline = parent
else
@@ -383,7 +553,7 @@ local function lastflush(lastline,lastattr)
local total = 0
local cwidth = getwidth(content)
local ctotal = gettotal(content)
- if cwidth <= width then -- slack
+ if cwidth <= width then
if trace then
report("index %i, available %p, content %p, verdict %a",index,width,cwidth,"fit")
end
@@ -393,7 +563,7 @@ local function lastflush(lastline,lastattr)
if trace then
report("index %i, available %p, content %p, verdict %a",index,width,cwidth,"overflow")
end
- result = hsplit(content,width)
+ result = hsplit(content,width-(data.slack or 0),nil,nil,200)
else
report("index %i, verdict %a",index,"weird")
end
@@ -413,7 +583,7 @@ end
local processranges = nuts.processranges
-function parallels.handler(head,where)
+function synchronize.handler(head,where)
if where == "hmodepar" and hasvalues(a_synchronize) then
lastattr = nil
lastline = nil
@@ -433,3 +603,63 @@ function parallels.handler(head,where)
end
return head
end
+
+--
+
+local settings_to_array = utilities.parsers.settings_to_array
+local get_buffer_content = buffers.getcontent
+local splitlines = string.splitlines
+
+interfaces.implement {
+ name = "synchronizesteps",
+ arguments = { {
+ { "list" },
+ { "split" },
+ { "buffer" },
+ { "text" },
+ } },
+ actions = function(t)
+ local split = t.split -- not used yet
+ local list = t.list
+ local buffer = t.buffer
+ local text = t.text
+ local data = false
+ if buffer and buffer ~= "" then
+ data = settings_to_array(buffer)
+ if #data == 2 then
+ for i=1,#data do
+ data[i] = splitlines(get_buffer_content(data[i]) or "")
+ end
+ else
+ return
+ end
+ elseif text and text ~= "" then
+ data = settings_to_array(text)
+ if #data == 2 then
+ for i=1,#data do
+ data[i] = settings_to_array(data[i])
+ end
+ else
+ return
+ end
+ else
+ return
+ end
+ if list and list ~= "" then
+ list = settings_to_array(list)
+ else
+ list = { }
+ end
+ local done = data[1]
+ local dtwo = data[2]
+ if #done == #dtwo then
+ local lone = list[1] or ""
+ local ltwo = list[2] or ""
+ for i=1,#done do
+ context.dosplitsynchronize(lone,ltwo,done[i],dtwo[i])
+ end
+ else
+ context.type("[different sizes in synchronize]")
+ end
+ end,
+}