diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/typo-dub.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkiv/typo-dub.lua | 271 |
1 files changed, 173 insertions, 98 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/typo-dub.lua b/Master/texmf-dist/tex/context/base/mkiv/typo-dub.lua index f27e4047660..d0747ae6ccd 100644 --- a/Master/texmf-dist/tex/context/base/mkiv/typo-dub.lua +++ b/Master/texmf-dist/tex/context/base/mkiv/typo-dub.lua @@ -55,6 +55,8 @@ local mirrordata = characters.mirrors local textclassdata = characters.textclasses local nuts = nodes.nuts +local tonut = nuts.tonut +local tonode = nuts.tonode local getnext = nuts.getnext local getid = nuts.getid @@ -63,11 +65,11 @@ local getlist = nuts.getlist local getchar = nuts.getchar local getattr = nuts.getattr local getprop = nuts.getprop -local getdirection = nuts.getdirection +local getdir = nuts.getdir local setprop = nuts.setprop local setchar = nuts.setchar -local setdirection = nuts.setdirection +local setdir = nuts.setdir local setattrlist = nuts.setattrlist local remove_node = nuts.remove @@ -75,10 +77,10 @@ local insert_node_after = nuts.insert_after local insert_node_before = nuts.insert_before local nodepool = nuts.pool -local new_direction = nodepool.direction +local new_textdir = nodepool.textdir local nodecodes = nodes.nodecodes -local gluecodes = nodes.gluecodes +local skipcodes = nodes.skipcodes local glyph_code = nodecodes.glyph local glue_code = nodecodes.glue @@ -87,29 +89,24 @@ local vlist_code = nodecodes.vlist local math_code = nodecodes.math local dir_code = nodecodes.dir local localpar_code = nodecodes.localpar +local parfillskip_code = skipcodes.parfillskip -local parfillskip_code = gluecodes.parfillskip - -local dirvalues = nodes.dirvalues -local lefttoright_code = dirvalues.lefttoright -local righttoleft_code = dirvalues.righttoleft - -local maximum_stack = 0xFF - -local a_directions = attributes.private('directions') +local maximum_stack = 0xFF -- unicode: 60, will be jumped to 125, we don't care too much local directions = typesetters.directions local setcolor = directions.setcolor local getfences = directions.getfences +local a_directions = attributes.private('directions') + local remove_controls = true directives.register("typesetters.directions.removecontrols",function(v) remove_controls = v end) ----- analyze_fences = true directives.register("typesetters.directions.analyzefences", function(v) analyze_fences = v end) -local report_directions = logs.reporter("typesetting","directions three") +local trace_directions = false trackers .register("typesetters.directions.two", function(v) trace_directions = v end) +local trace_details = false trackers .register("typesetters.directions.two.details", function(v) trace_details = v end) +local trace_list = false trackers .register("typesetters.directions.two.list", function(v) trace_list = v end) -local trace_directions = false trackers.register("typesetters.directions", function(v) trace_directions = v end) -local trace_details = false trackers.register("typesetters.directions.details", function(v) trace_details = v end) -local trace_list = false trackers.register("typesetters.directions.list", function(v) trace_list = v end) +local report_directions = logs.reporter("typesetting","directions two") -- strong (old): -- @@ -120,7 +117,7 @@ local trace_list = false trackers.register("typesetters.directions.list -- lre : left to right embedding -- rle : left to left embedding -- al : right to legt arabic (esp punctuation issues) --- + -- weak: -- -- en : english number @@ -130,23 +127,23 @@ local trace_list = false trackers.register("typesetters.directions.list -- cs : common number separator -- nsm : nonspacing mark -- bn : boundary neutral --- + -- neutral: -- -- b : paragraph separator -- s : segment separator -- ws : whitespace -- on : other neutrals --- + -- interesting: this is indeed better (and more what we expect i.e. we already use this split -- in the old original (also these isolates) --- + -- strong (new): -- -- l : left to right -- r : right to left -- al : right to left arabic (esp punctuation issues) --- + -- explicit: (new) -- -- lro : left to right override @@ -209,28 +206,27 @@ end local function show_done(list,size) local joiner = utfchar(0x200C) local result = { } - local format = formatters["<%s>"] for i=1,size do local entry = list[i] local character = entry.char local begindir = entry.begindir local enddir = entry.enddir if begindir then - result[#result+1] = format(begindir) + result[#result+1] = formatters["<%s>"](begindir) end if entry.remove then -- continue elseif character == 0xFFFC then - result[#result+1] = format("?") + result[#result+1] = formatters["<%s>"]("?") elseif character == 0x0020 then - result[#result+1] = format(" ") + result[#result+1] = formatters["<%s>"](" ") elseif character >= 0x202A and character <= 0x202C then - result[#result+1] = format(entry.original) + result[#result+1] = formatters["<%s>"](entry.original) else result[#result+1] = utfchar(character) end if enddir then - result[#result+1] = format(enddir) + result[#result+1] = formatters["<%s>"](enddir) end end return concat(result,joiner) @@ -240,7 +236,17 @@ end -- char is only used for mirror, so in fact we can as well only store it for -- glyphs only -local function build_list(head) +-- using metatable is slightly faster so maybe some day ... + +-- local space = { char = 0x0020, direction = "ws", original = "ws" } +-- local lre = { char = 0x202A, direction = "lre", original = "lre" } +-- local rle = { char = 0x202B, direction = "rle", original = "rle" } +-- local pdf = { char = 0x202C, direction = "pdf", original = "pdf" } +-- local object = { char = 0xFFFC, direction = "on", original = "on" } +-- +-- local t = { level = 0 } setmetatable(t,space) list[size] = t + +local function build_list(head) -- todo: store node pointer ... saves loop -- P1 local current = head local list = { } @@ -276,19 +282,13 @@ local function build_list(head) list[size] = { char = 0x0020, direction = "ws", original = "ws", level = 0 } current = getnext(current) elseif id == dir_code then - local direction, pop = getdirection(current) - if direction == lefttoright_code then - if pop then - list[size] = { char = 0x202C, direction = "pdf", original = "pdf", level = 0 } - else - list[size] = { char = 0x202A, direction = "lre", original = "lre", level = 0 } - end - elseif direction == righttoleft_code then - if pop then - list[size] = { char = 0x202C, direction = "pdf", original = "pdf", level = 0 } - else - list[size] = { char = 0x202B, direction = "rle", original = "rle", level = 0 } - end + local dir = getdir(current) + if dir == "+TLT" then + list[size] = { char = 0x202A, direction = "lre", original = "lre", level = 0 } + elseif dir == "+TRT" then + list[size] = { char = 0x202B, direction = "rle", original = "rle", level = 0 } + elseif dir == "-TLT" or dir == "-TRT" then + list[size] = { char = 0x202C, direction = "pdf", original = "pdf", level = 0 } else list[size] = { char = 0xFFFC, direction = "on", original = "on", level = 0, id = id } -- object replacement character end @@ -343,8 +343,8 @@ end local function resolve_fences(list,size,start,limit) -- N0: funny effects, not always better, so it's an option - local stack = { } - local nofstack = 0 + local stack = { } + local top = 0 for i=start,limit do local entry = list[i] if entry.direction == "on" then @@ -355,15 +355,15 @@ local function resolve_fences(list,size,start,limit) entry.mirror = mirror entry.class = class if class == "open" then - nofstack = nofstack + 1 - stack[nofstack] = { mirror, i, false } - elseif nofstack == 0 then + top = top + 1 + stack[top] = { mirror, i, false } + elseif top == 0 then -- skip elseif class == "close" then - while nofstack > 0 do - local stacktop = stack[nofstack] - if stacktop[1] == char then - local open = stacktop[2] + while top > 0 do + local s = stack[top] + if s[1] == char then + local open = s[2] local close = i list[open ].paired = close list[close].paired = open @@ -371,7 +371,7 @@ local function resolve_fences(list,size,start,limit) else -- do we mirror or not end - nofstack = nofstack - 1 + top = top - 1 end end end @@ -394,32 +394,27 @@ end -- the action -local function get_baselevel(head,list,size,direction) - if direction == lefttoright_code or direction == righttoleft_code then - return direction, true - elseif getid(head) == localpar_code and getsubtype(head) == 0 then - direction = getdirection(head) - if direction == lefttoright_code or direction == righttoleft_code then - return direction, true +local function get_baselevel(head,list,size) -- todo: skip if first is object (or pass head and test for localpar) + local id = getid(head) + if id == localpar_code then + if getdir(head) == "TRT" then + return 1, "TRT", true + else + return 0, "TLT", true end - end - -- for old times sake we we handle strings too - if direction == "TLT" then - return lefttoright_code, true - elseif direction == "TRT" then - return righttoleft_code, true - end - -- P2, P3 - for i=1,size do - local entry = list[i] - local direction = entry.direction - if direction == "r" or direction == "al" then -- and an ? - return righttoleft_code, true - elseif direction == "l" then - return lefttoright_code, true + else + -- P2, P3 + for i=1,size do + local entry = list[i] + local direction = entry.direction + if direction == "r" or direction == "al" then -- and an ? + return 1, "TRT", true + elseif direction == "l" then + return 0, "TLT", true + end end + return 0, "TLT", false end - return lefttoright_code, false end local function resolve_explicit(list,size,baselevel) @@ -485,17 +480,16 @@ local function resolve_explicit(list,size,baselevel) end -- X7 elseif direction == "pdf" then - if nofstack > 0 then + if nofstack < maximum_stack then local stacktop = stack[nofstack] + nofstack = nofstack - 1 level = stacktop[1] override = stacktop[2] - nofstack = nofstack - 1 entry.level = level entry.direction = "bn" entry.remove = true elseif trace_directions then - report_directions("stack underflow at position %a with direction %a", - i, direction) + report_directions("stack overflow at position %a with direction %a",i,direction) end -- X6 else @@ -694,6 +688,33 @@ local function resolve_neutral(list,size,start,limit,orderbefore,orderafter) end end +-- local function resolve_implicit(list,size,start,limit,orderbefore,orderafter) +-- -- I1 +-- for i=start,limit do +-- local entry = list[i] +-- local level = entry.level +-- if level % 2 ~= 1 then -- not odd(level) +-- local direction = entry.direction +-- if direction == "r" then +-- entry.level = level + 1 +-- elseif direction == "an" or direction == "en" then +-- entry.level = level + 2 +-- end +-- end +-- end +-- -- I2 +-- for i=start,limit do +-- local entry = list[i] +-- local level = entry.level +-- if level % 2 == 1 then -- odd(level) +-- local direction = entry.direction +-- if direction == "l" or direction == "en" or direction == "an" then +-- entry.level = level + 1 +-- end +-- end +-- end +-- end + local function resolve_implicit(list,size,start,limit,orderbefore,orderafter,baselevel) for i=start,limit do local entry = list[i] @@ -793,6 +814,52 @@ local function resolve_levels(list,size,baselevel,analyze_fences) end end +-- local function insert_dir_points(list,size) +-- -- L2, but no actual reversion is done, we simply annotate where +-- -- begindir/endddir node will be inserted. +-- local maxlevel = 0 +-- local finaldir = false +-- for i=1,size do +-- local level = list[i].level +-- if level > maxlevel then +-- maxlevel = level +-- end +-- end +-- for level=0,maxlevel do +-- local started = false +-- local begindir = nil +-- local enddir = nil +-- if level % 2 == 1 then +-- begindir = "+TRT" +-- enddir = "-TRT" +-- else +-- begindir = "+TLT" +-- enddir = "-TLT" +-- end +-- for i=1,size do +-- local entry = list[i] +-- if entry.level >= level then +-- if not started then +-- entry.begindir = begindir +-- started = true +-- end +-- else +-- if started then +-- list[i-1].enddir = enddir +-- started = false +-- end +-- end +-- end +-- -- make sure to close the run at end of line +-- if started then +-- finaldir = enddir +-- end +-- end +-- if finaldir then +-- list[size].enddir = finaldir +-- end +-- end + local function insert_dir_points(list,size) -- L2, but no actual reversion is done, we simply annotate where -- begindir/endddir node will be inserted. @@ -810,12 +877,12 @@ local function insert_dir_points(list,size) local enddir -- = nil local prev -- = nil if toggle then - begindir = lefttoright_code - enddir = lefttoright_code + begindir = "+TLT" + enddir = "-TLT" toggle = false else - begindir = righttoleft_code - enddir = righttoleft_code + begindir = "+TRT" + enddir = "-TRT" toggle = true end for i=1,size do @@ -855,7 +922,7 @@ local function insert_dir_points(list,size) if trace_list and n > 1 then report_directions("unbalanced list") end - last.enddir = s[n] == righttoleft_code and righttoleft_code or lefttoright_code + last.enddir = s[n] == "+TRT" and "-TRT" or "-TLT" end end end @@ -863,6 +930,7 @@ end local function apply_to_list(list,size,head,pardir) local index = 1 local current = head + local done = false if trace_list then report_directions("start run") end @@ -896,31 +964,34 @@ local function apply_to_list(list,size,head,pardir) setcolor(current,direction,false,mirror) end elseif id == hlist_code or id == vlist_code then - setdirection(current,pardir) -- is this really needed? + setdir(current,pardir) -- is this really needed? elseif id == glue_code then if enddir and getsubtype(current) == parfillskip_code then -- insert the last enddir before \parfillskip glue - local d = new_direction(enddir,true) - -- setprop(d,"directions",true) + local d = new_textdir(enddir) + setprop(d,"directions",true) -- setattrlist(d,current) head = insert_node_before(head,current,d) enddir = false + done = true end elseif begindir then - if id == localpar_code and getsubtype(current) == 0 then + if id == localpar_code then -- localpar should always be the 1st node - local d = new_direction(begindir) - -- setprop(d,"directions",true) + local d = new_textdir(begindir) + setprop(d,"directions",true) -- setattrlist(d,current) head, current = insert_node_after(head,current,d) begindir = nil + done = true end end if begindir then - local d = new_direction(begindir) - -- setprop(d,"directions",true) + local d = new_textdir(begindir) + setprop(d,"directions",true) -- setattrlist(d,current) head = insert_node_before(head,current,d) + done = true end local skip = entry.skip if skip and skip > 0 then @@ -930,16 +1001,18 @@ local function apply_to_list(list,size,head,pardir) end end if enddir then - local d = new_direction(enddir,true) - -- setprop(d,"directions",true) + local d = new_textdir(enddir) + setprop(d,"directions",true) -- setattrlist(d,current) head, current = insert_node_after(head,current,d) + done = true end if not entry.remove then current = getnext(current) elseif remove_controls then -- X9 head, current = remove_node(head,current,true) + done = true else current = getnext(current) end @@ -948,16 +1021,17 @@ local function apply_to_list(list,size,head,pardir) if trace_list then report_directions("stop run") end - return head + return head, done end -local function process(head,direction,only_one,where) +local function process(head) + head = tonut(head) -- for the moment a whole paragraph property local attr = getattr(head,a_directions) local analyze_fences = getfences(attr) -- local list, size = build_list(head) - local baselevel, dirfound = get_baselevel(head,list,size,direction) + local baselevel, pardir, dirfound = get_baselevel(head,list,size) -- we always have an inline dir node in context if not dirfound and trace_details then report_directions("no initial direction found, gambling") end @@ -971,7 +1045,8 @@ local function process(head,direction,only_one,where) report_directions("after : %s",show_list(list,size,"direction")) report_directions("result : %s",show_done(list,size)) end - return apply_to_list(list,size,head,baselevel) + local head, done = apply_to_list(list,size,head,pardir) + return tonode(head), done end directions.installhandler(interfaces.variables.two,process) |