diff options
Diffstat (limited to 'tex/context/base/typo-dir.lua')
-rw-r--r-- | tex/context/base/typo-dir.lua | 522 |
1 files changed, 1 insertions, 521 deletions
diff --git a/tex/context/base/typo-dir.lua b/tex/context/base/typo-dir.lua index 939850e81..04528f137 100644 --- a/tex/context/base/typo-dir.lua +++ b/tex/context/base/typo-dir.lua @@ -26,42 +26,6 @@ if not modules then modules = { } end modules ['typo-dir'] = { -- = half tagging (the current implementation) -- = unicode version x interpretation (several depending on the evolution) --- Some analysis by Idris: --- --- 1. Assuming the reading- vs word-order distinction (bidi-char types) is governing; --- 2. Assuming that 'ARAB' represents an actual arabic string in raw input order, not word-order; --- 3. Assuming that 'BARA' represent the correct RL word order; --- --- Then we have, with input: LATIN ARAB --- --- \textdir TLT LATIN ARAB => LATIN BARA --- \textdir TRT LATIN ARAB => LATIN BARA --- \textdir TRT LRO LATIN ARAB => LATIN ARAB --- \textdir TLT LRO LATIN ARAB => LATIN ARAB --- \textdir TLT RLO LATIN ARAB => NITAL ARAB --- \textdir TRT RLO LATIN ARAB => NITAL ARAB - --- elseif d == "es" then -- European Number Separator --- elseif d == "et" then -- European Number Terminator --- elseif d == "cs" then -- Common Number Separator --- elseif d == "nsm" then -- Non-Spacing Mark --- elseif d == "bn" then -- Boundary Neutral --- elseif d == "b" then -- Paragraph Separator --- elseif d == "s" then -- Segment Separator --- elseif d == "ws" then -- Whitespace --- elseif d == "on" then -- Other Neutrals - --- todo : delayed inserts here --- todo : get rid of local functions here --- beware: math adds whatsits afterwards so that will mess things up --- todo : use new dir functions --- todo : make faster --- todo : also use end_of_math here? --- todo : use lpeg instead of match --- todo : move dir info into nodes --- todo : swappable tables and floats i.e. start-end overloads (probably loop in builders) --- todo : check if we still have crashes in luatex when non-matched (used to be the case) --- todo : look into the (new) unicode logic (non intuitive stuff) local next, type = next, type local format, insert, sub, find, match = string.format, table.insert, string.sub, string.find, string.match @@ -192,7 +156,7 @@ local function getmethod(a) end directions.tomode = tomode -directions.getscope = getscope +directions.getglobal = getglobal directions.getfences = getfences directions.getmethod = getmethod directions.installhandler = installhandler @@ -201,374 +165,6 @@ function commands.getbidimode(specification) context(tomode(specification)) -- hash at tex end end -local function process_direct(namespace,attribute,start) - - local head = start - - local current, inserted = head, nil - local finish, autodir, embedded, override, done = nil, 0, 0, 0, false - local list, glyphs = trace_textdirections and { }, false - local finished, finidir, finipos = nil, nil, 1 - local stack, top, obsolete = { }, 0, { } - local lro, rlo, prevattr = false, false, 0 - - local function finish_auto_before() - local fdir = finish == "TRT" and "-TRT" or "-TLT" - head, inserted = insert_node_before(head,current,new_textdir(fdir)) - finished, finidir, autodir = inserted, finish, 0 - if trace_textdirections then - insert(list,#list,formatters["auto %a inserted before, autodir %a, embedded %a"](fdir,autodir,embedded)) - finipos = #list - 1 - end - finish, done = nil, true - end - - local function finish_auto_after() - local fdir = finish == "TRT" and "-TRT" or "-TLT" - head, current = insert_node_after(head,current,new_textdir(fdir)) - finished, finidir, autodir = current, finish, 0 - if trace_textdirections then - list[#list+1] = formatters["auto %a inserted after, autodir %a, embedded %a"](fdir,autodir,embedded) - finipos = #list - end - finish, done = nil, true - end - - local function force_auto_left_before(d) - if finish then - finish_auto_before() - end - if embedded >= 0 then - finish, autodir = "TLT", 1 - else - finish, autodir = "TRT", -1 - end - done = true - if finidir == finish then - head = remove_node(head,finished,true) - if trace_textdirections then - list[finipos] = list[finipos] .. ", deleted afterwards" - insert(list,#list,formatters["start text dir %a, auto left before, embedded %a, autodir %a, triggered by class %a"](finish,embedded,autodir,d)) - end - else - head, inserted = insert_node_before(head,current,new_textdir("+"..finish)) - if trace_textdirections then - insert(list,#list,formatters["start text dir %a, auto left before, embedded %a, autodir %a, triggered by class %a"](finish,embedded,autodir,d)) - end - end - end - - local function force_auto_right_before(d) - if finish then - finish_auto_before() - end - if embedded <= 0 then - finish, autodir, done = "TRT", -1 - else - finish, autodir, done = "TLT", 1 - end - done = true - if finidir == finish then - head = remove_node(head,finished,true) - if trace_textdirections then - list[finipos] = list[finipos] .. ", deleted afterwards" - insert(list,#list,formatters["start text dir %a, auto right before, embedded %a, autodir %a, triggered by class %a"](finish,embedded,autodir,d)) - end - else - head, inserted = insert_node_before(head,current,new_textdir("+"..finish)) - if trace_textdirections then - insert(list,#list,formatters["start text dir %a, auto right before, embedded %a, autodir %a, triggered by class %a"](finish,embedded,autodir,d)) - end - end - end - - local function nextisright(current) - -- repeat - current = current.next - local id = current.id - if id == glyph_code then - local char = current.char - local d = chardirections[char] - return d == "r" or d == "al" or d == "an" - -- elseif id == glue_code or id == kern_code or id == penalty_code then - -- -- too complex - -- else - -- return - end - -- until not current - end - - local function previsright(current) - -- repeat - current = current.prev - local id = current.id - if id == glyph_code then - local char = current.char - local d = chardirections[char] - return d == "r" or d == "al" or d == "an" - -- elseif id == glue_code or id == kern_code or id == penalty_code then - -- -- too complex - -- else - -- return - end - -- until not current - end - - while current do - local id = current.id - -- list[#list+1] = formatters["state: node %a, finish %a, autodir %a, embedded %a"](nutstring(current),finish or "unset",autodir,embedded) - if id == math_code then - current = end_of_math(current.next).next - else - local attr = current[attribute] - if attr and attr > 0 then - -- current[attribute] = unsetvalue -- slow, needed? - if attr == 1 then - -- bidi parsing mode - elseif attr ~= prevattr then - -- no pop, grouped driven (2=normal,3=lro,4=rlo) - if attr == 3 then - if trace_textdirections then - list[#list+1] = formatters["override right -> left (lro), bidi %a"](attr) - end - lro, rlo = true, false - elseif attr == 4 then - if trace_textdirections then - list[#list+1] = formatters["override left -> right (rlo), bidi %a"](attr) - end - lro, rlo = false, true - else - if trace_textdirections and - current ~= head then list[#list+1] = formatters["override reset, bidi %a"](attr) - end - lro, rlo = false, false - end - prevattr = attr - end - end - if id == glyph_code then - glyphs = true - if attr and attr > 0 then - local char = current.char - local d = chardirections[char] - if rlo or override > 0 then - if d == "l" then - if trace_textdirections then - list[#list+1] = formatters["char %C of class %a overridden to r, bidi %a)"](char,d,attr) - end - d = "r" - elseif trace_textdirections then - if d == "lro" or d == "rlo" or d == "pdf" then -- else side effects on terminal - list[#list+1] = formatters["override char of class %a, bidi %a"](d,attr) - else -- todo: rle lre - list[#list+1] = formatters["char %C of class %a, bidi %a"](char,d,attr) - end - end - elseif lro or override < 0 then - if d == "r" or d == "al" then - current[a_state] = s_isol -- maybe better have a special bidi attr value -> override (9) -> todo - if trace_textdirections then - list[#list+1] = formatters["char %C of class %a overridden to l, bidi %a, state 'isol'"](char,d,attr) - end - d = "l" - elseif trace_textdirections then - if d == "lro" or d == "rlo" or d == "pdf" then -- else side effects on terminal - list[#list+1] = formatters["override char of class %a, bidi %a"](d,attr) - else -- todo: rle lre - list[#list+1] = formatters["char %C of class %a, bidi %a"](char,d,attr) - end - end - elseif trace_textdirections then - if d == "lro" or d == "rlo" or d == "pdf" then -- else side effects on terminal - list[#list+1] = formatters["override char of class %a, bidi %a"](d,attr) - else -- todo: rle lre - list[#list+1] = formatters["char %C of class %a, bidi %a"](char,d,attr) - end - end - if d == "on" then - local mirror = charmirrors[char] - if mirror and fontchar[current.font][mirror] then - -- todo: set attribute - local class = charclasses[char] - if class == "open" then - if nextisright(current) then - if autodir >= 0 then - force_auto_right_before(d) - end - current.char = mirror - done = true - else - mirror = nil - if autodir <= 0 then - force_auto_left_before(d) - end - end - elseif class == "close" then - if previsright(current) then - current.char = mirror - done = true - else - mirror = nil - end - elseif autodir < 0 then - current.char = mirror - done = true - else - mirror = nil - end - if trace_textdirections then - if mirror then - list[#list+1] = formatters["mirroring char %C of class %a to %C, autodir %a, bidi %a"](char,d,mirror,autodir,attr) - else - list[#list+1] = formatters["not mirroring char %C of class %a, autodir %a, bidi %a"](char,d,autodir,attr) - end - end - end - elseif d == "l" or d == "en" then -- european number - if autodir <= 0 then -- could be option - force_auto_left_before(d) - end - elseif d == "r" or d == "al" then -- arabic number - if autodir >= 0 then - force_auto_right_before(d) - end - elseif d == "an" then -- arabic number - -- actually this is language dependent ... - -- if autodir <= 0 then - -- force_auto_left_before(d) - -- end - if autodir >= 0 then - force_auto_right_before(d) - end - elseif d == "lro" then -- Left-to-Right Override -> right becomes left - if trace_textdirections then - list[#list+1] = "override right -> left" - end - top = top + 1 - stack[top] = { override, embedded } - override = -1 - obsolete[#obsolete+1] = current - elseif d == "rlo" then -- Right-to-Left Override -> left becomes right - if trace_textdirections then - list[#list+1] = "override left -> right" - end - top = top + 1 - stack[top] = { override, embedded } - override = 1 - obsolete[#obsolete+1] = current - elseif d == "lre" then -- Left-to-Right Embedding -> TLT - if trace_textdirections then - list[#list+1] = "embedding left -> right" - end - top = top + 1 - stack[top] = { override, embedded } - embedded = 1 - obsolete[#obsolete+1] = current - elseif d == "rle" then -- Right-to-Left Embedding -> TRT - if trace_textdirections then - list[#list+1] = "embedding right -> left" - end - top = top + 1 - stack[top] = { override, embedded } - embedded = -1 -- was 1 - obsolete[#obsolete+1] = current - elseif d == "pdf" then -- Pop Directional Format - -- override = 0 - if top > 0 then - local s = stack[top] - override, embedded = s[1], s[2] - top = top - 1 - if trace_textdirections then - list[#list+1] = formatters["state: override %a, embedded %a, autodir %a"](override,embedded,autodir) - end - else - if trace_textdirections then - list[#list+1] = "pop error: too many pops" - end - end - obsolete[#obsolete+1] = current - end - elseif trace_textdirections then - local char = current.char - local d = chardirections[char] - list[#list+1] = formatters["char %C of class %a, bidi %a"](char,d or "?") - end - elseif id == whatsit_code then - -- we have less directions now so we can do hard checks for strings instead of splitting into pieces - if finish then - finish_auto_before() - end - local subtype = current.subtype - if subtype == localpar_code then - -- if false then - local dir = current.dir - if dir == 'TRT' then - autodir = -1 - elseif dir == 'TLT' then - autodir = 1 - end - -- embedded = autodir - if trace_textdirections then - list[#list+1] = formatters["pardir %a"](dir) - end - -- end - elseif subtype == dir_code then - local dir = current.dir - if dir == "+TRT" then - finish, autodir = "TRT", -1 - elseif dir == "-TRT" then - finish, autodir = nil, 0 - elseif dir == "+TLT" then - finish, autodir = "TLT", 1 - elseif dir == "-TLT" then - finish, autodir = nil, 0 - end - if trace_textdirections then - list[#list+1] = formatters["textdir %a, autodir %a"](dir,autodir) - end - end - else - if trace_textdirections then - list[#list+1] = formatters["node %a, subtype %a"](nodecodes[id],current.subtype) - end - if finish then - finish_auto_before() - end - end - local cn = current.next - if not cn then - if finish then - finish_auto_after() - end - end - current = cn - end - end - - if trace_textdirections and glyphs then - report_textdirections("start log") - for i=1,#list do - report_textdirections("%02i: %s",i,list[i]) - end - report_textdirections("stop log") - end - - if done and strip then - local n = #obsolete - if n > 0 then - for i=1,n do - remove_node(head,obsolete[i],true) - end - report_textdirections("%s character nodes removed",n) - end - end - - return head, done - -end - -installhandler(variables.default,process_direct) - function directions.process(namespace,attribute,head) -- nodes not nuts if not head.next then return head, false @@ -613,119 +209,3 @@ directions.handler = nodes.installattributehandler { namespace = directions, processor = directions.process, } - --- As I'm wrapping up the updated math support (for CTX/TUG 2013) I wondered about numbers in --- r2l math mode. Googling lead me to TUGboat, Volume 25 (2004), No. 2 where I see numbers --- running from left to right. Makes me wonder how far we should go. And as I was looking --- into bidi anyway, it's a nice distraction. --- --- I first tried to hook something into noads but that gets pretty messy due to indirectness --- char noads. If needed, I'll do it that way. With regards to spacing: as we can assume that --- only numbers are involved we can safely swap them and the same is true for mirroring. But --- anyway, I'm not too happy with this solution so eventually I'll do something with noads (as --- an alternative method). - -local function processmath(head) - local current = head - local done = false - local start = nil - local stop = nil - local function capsulate() - head = insert_node_before(head,start,new_textdir("+TLT")) - insert_node_after(head,stop,new_textdir("-TLT")) - if trace_mathdirections then - report_mathdirections("reversed: %s",nodes.listtoutf(start,false,false,stop)) - end - done = true - start = false - stop = nil - end - while current do - local id = current.id - if id == glyph_code then - local char = current.char - local cdir = chardirections[char] - if cdir == "en" or cdir == "an" then -- we could check for mathclass punctuation - if not start then - start = current - end - stop = current - else - if not start then - -- nothing - elseif start == stop then - start = nil - else - capsulate() - end - if cdir == "on" then - local mirror = charmirrors[char] - if mirror then - local class = charclasses[char] - if class == "open" or class == "close" then - current.char = mirror - if trace_mathdirections then - report_mathdirections("mirrored: %C to %C",char,mirror) - end - done = true - end - end - end - end - elseif not start then - -- nothing - elseif start == stop then - start = nil - else - capsulate(head,start,stop) - -- math can pack things into hlists .. we need to make sure we don't process - -- too often: needs checking - if id == hlist_code or id == vlist_code then - local list, d = processmath(current.list) - current.list = list - if d then - done = true - end - end - end - current = current.next - end - if not start then - -- nothing - elseif start == stop then - -- nothing - else - capsulate() - end - return head, done -end - -local enabled = false - -function directions.processmath(head) -- style, penalties - if enabled then - local a = head[a_mathbidi] - if a and a > 0 then - return processmath(head) - end - end - return head, false -end - -function directions.setmath(n) - if not enabled and n and n > 0 then - if trace_mathdirections then - report_mathdirections("enabling directions handler") - end - nodes.tasks.enableaction("math","typesetters.directions.processmath") - enabled = true - end -end - -commands.setmathdirection = directions.setmath - --- directions.mathhandler = nodes.installattributehandler { --- name = "directions", --- namespace = directions, --- processor = directions.processmath, --- } |