summaryrefslogtreecommitdiff
path: root/tex/context/base/typo-dir.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/typo-dir.lua')
-rw-r--r--tex/context/base/typo-dir.lua522
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,
--- }