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.lua664
1 files changed, 439 insertions, 225 deletions
diff --git a/tex/context/base/typo-dir.lua b/tex/context/base/typo-dir.lua
index 16de85dd1..939850e81 100644
--- a/tex/context/base/typo-dir.lua
+++ b/tex/context/base/typo-dir.lua
@@ -6,28 +6,86 @@ if not modules then modules = { } end modules ['typo-dir'] = {
license = "see context related readme files"
}
--- todo: also use end_of_math here?
--- todo: use lpeg instead of match
+-- When we started with this, there were some issues in luatex so we needed to take care of
+-- intereferences. Some has been improved but we stil might end up with each node having a
+-- dir property. Now, the biggest problem is that there is an official bidi algorithm but
+-- some searching on the web shows that there are many confusing aspects and therefore
+-- proposals circulate about (sometimes imcompatible ?) improvements. In the end it all boils
+-- down to the lack of willingness to tag an input source. Of course tagging of each number
+-- and fenced strip is somewhat over the top, but now it has to be captured in logic. Texies
+-- normally have no problem with tagging but we need to handle any input. So, what we have
+-- done here (over the years) is starting from what we expect to see happen, especially with
+-- respect to punctation, numbers and fences. Eventually alternative algorithms will be provides
+-- so that users can choose (the reason why suggestion sfor improvements circulate on the web
+-- is that it is non trivial to predict the expected behaviour so one hopes that the ditor
+-- and the rest of the machinery match somehow. Anyway, the fun of tex is that it has no hard
+-- coded behavior. And ... we also want to have more debugging and extras and ... so we want
+-- a flexible approach. In the end we will have:
+--
+-- = full tagging (mechanism turned off)
+-- = 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
local utfchar = utf.char
local formatters = string.formatters
--- vertical space handler
-
local nodes, node = nodes, node
-local trace_directions = false trackers.register("typesetters.directions", function(v) trace_directions = v end)
+local trace_textdirections = false trackers.register("typesetters.directions.text", function(v) trace_textdirections = v end)
+local trace_mathdirections = false trackers.register("typesetters.directions.math", function(v) trace_mathdirections = v end)
+local trace_directions = false trackers.register("typesetters.directions", function(v) trace_textdirections = v trace_mathdirections = v end)
+
+local report_textdirections = logs.reporter("typesetting","text directions")
+local report_mathdirections = logs.reporter("typesetting","math directions")
-local report_directions = logs.reporter("typesetting","directions")
local traverse_id = node.traverse_id
local insert_node_before = node.insert_before
local insert_node_after = node.insert_after
local remove_node = nodes.remove
+local end_of_math = nodes.end_of_math
local texsetattribute = tex.setattribute
+local texsetcount = tex.setcount
local unsetvalue = attributes.unsetvalue
local nodecodes = nodes.nodecodes
@@ -42,6 +100,8 @@ local math_code = nodecodes.math
local penalty_code = nodecodes.penalty
local kern_code = nodecodes.kern
local glue_code = nodecodes.glue
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
local localpar_code = whatcodes.localpar
local dir_code = whatcodes.dir
@@ -50,191 +110,215 @@ local nodepool = nodes.pool
local new_textdir = nodepool.textdir
-local beginmath_code = mathcodes.beginmath
-local endmath_code = mathcodes.endmath
-
local fonthashes = fonts.hashes
local fontdata = fonthashes.identifiers
local fontchar = fonthashes.characters
-local chardata = characters.data
-local chardirs = characters.directions -- maybe make a special mirror table
-
---~ 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
-
-typesetters.directions = typesetters.directions or { }
-local directions = typesetters.directions
-
-local a_state = attributes.private('state')
-local a_directions = attributes.private('directions')
-
-local skipmath = true
-local strip = false
-
--- todo: delayed inserts here
--- todo: get rid of local functions here
-
--- beware, math adds whatsits afterwards so that will mess things up
-
-local finish, autodir, embedded, override, done = nil, 0, 0, 0, false
-local list, glyphs = nil, false
-local finished, finidir, finipos = nil, nil, 1
-local head, current, inserted = nil, nil, nil
-
-local function finish_auto_before()
- local fdir = "-" .. finish
- head, inserted = insert_node_before(head,current,new_textdir(fdir))
- finished, finidir, autodir = inserted, finish, 0
- if trace_directions 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 chardirections = characters.directions
+local charmirrors = characters.mirrors
+local charclasses = characters.textclasses
+
+local directions = typesetters.directions or { }
+typesetters.directions = directions
+
+local a_state = attributes.private('state')
+local a_directions = attributes.private('directions')
+local a_mathbidi = attributes.private('mathbidi')
+
+local strip = false
+
+local s_isol = fonts.analyzers.states.isol
-local function finish_auto_after()
- local fdir = "-" .. finish
- head, current = insert_node_after(head,current,new_textdir(fdir))
- finished, finidir, autodir = current, finish, 0
- if trace_directions then
- list[#list+1] = formatters["auto %a inserted after, autodir %a, embedded %a"](fdir,autodir,embedded)
- finipos = #list
+local variables = interfaces.variables
+local v_global = variables["global"]
+local v_local = variables["local"]
+local v_on = variables.on
+local v_yes = variables.yes
+
+local m_enabled = 2^6 -- 64
+local m_global = 2^7
+local m_fences = 2^8
+
+local handlers = { }
+local methods = { }
+local lastmethod = 0
+
+local function installhandler(name,handler)
+ local method = methods[name]
+ if not method then
+ lastmethod = lastmethod + 1
+ method = lastmethod
+ methods[name] = method
end
- finish, done = nil, true
+ handlers[method] = handler
+ return method
end
-local function force_auto_left_before(d)
- if finish then
- finish_auto_before()
- end
- if embedded >= 0 then
- finish, autodir, done = "TLT", 1, true
+directions.handlers = handlers
+directions.installhandler = installhandler
+
+local function tomode(specification)
+ local scope = specification.scope
+ local mode
+ if scope == v_global or scope == v_on then
+ mode = m_enabled + m_global
+ elseif scope == v_local then
+ mode = m_enabled
else
- finish, autodir, done = "TRT", -1, true
+ return 0
end
- if finidir == finish then
- head = remove_node(head,finished,true)
- if trace_directions 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
+ local method = methods[specification.method]
+ if method then
+ mode = mode + method
else
- head, inserted = insert_node_before(head,current,new_textdir("+"..finish))
- if trace_directions 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
+ return 0
+ end
+ if specification.fences == v_yes then
+ mode = mode + m_fences
end
+ return mode
end
-local function force_auto_right_before(d)
- if finish then
- finish_auto_before()
+local function getglobal(a)
+ return a and a > 0 and hasbit(a,m_global)
+end
+
+local function getfences(a)
+ return a and a > 0 and hasbit(a,m_fences)
+end
+
+local function getmethod(a)
+ return a and a > 0 and a % m_enabled or 0
+end
+
+directions.tomode = tomode
+directions.getscope = getscope
+directions.getfences = getfences
+directions.getmethod = getmethod
+directions.installhandler = installhandler
+
+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
- if embedded <= 0 then
- finish, autodir, done = "TRT", -1, true
- else
- finish, autodir, done = "TLT", 1, true
+
+ 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
- if finidir == finish then
- head = remove_node(head,finished,true)
- if trace_directions 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))
+
+ local function force_auto_left_before(d)
+ if finish then
+ finish_auto_before()
end
- else
- head, inserted = insert_node_before(head,current,new_textdir("+"..finish))
- if trace_directions then
- insert(list,#list,formatters["start text dir %a, auto right before, embedded %a, autodir %a, triggered by class %a"](finish,embedded,autodir,d))
+ 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
-end
-local function nextisright(current)
- repeat
- current = current.next
- local id = current.id
- if id == glyph_code then
- local char = current.char
- local d = chardirs[char]
- return d == "r" or d == "al" or d == "an" and current
--- elseif id == glue_code or id == kern_code or id == penalty_code then
--- -- too complex
+ local function force_auto_right_before(d)
+ if finish then
+ finish_auto_before()
+ end
+ if embedded <= 0 then
+ finish, autodir, done = "TRT", -1
else
- return
+ finish, autodir, done = "TLT", 1
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 = chardirs[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
+ 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
- return
+ 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
- until not current
-end
-
--- todo: use new dir functions
-
--- todo: use end_of_math
+ end
-local s_isol = fonts.analyzers.states.isol
+ 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
-function directions.process(namespace,attribute,start) -- todo: make faster
- if not start.next then
- return start, false
+ 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
- head, current, inserted = start, start, nil
- finish, autodir, embedded, override, done = nil, 0, 0, 0, false
- list, glyphs = trace_directions and { }, false
- finished, finidir, finipos = nil, nil, 1
- local stack, top, obsolete = { }, 0, { }
- local lro, rlo, prevattr, inmath = false, false, 0, false
+
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 skipmath and id == math_code then
- local subtype = current.subtype
- if subtype == beginmath_code then
- inmath = true
- elseif subtype == endmath_code then
- inmath = false
- else
- -- todo
- end
- current = current.next
- elseif inmath then
- current = current.next
+ -- 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
@@ -244,17 +328,17 @@ function directions.process(namespace,attribute,start) -- todo: make faster
elseif attr ~= prevattr then
-- no pop, grouped driven (2=normal,3=lro,4=rlo)
if attr == 3 then
- if trace_directions 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_directions then
+ if trace_textdirections then
list[#list+1] = formatters["override left -> right (rlo), bidi %a"](attr)
end
lro, rlo = false, true
else
- if trace_directions and
+ if trace_textdirections and
current ~= head then list[#list+1] = formatters["override reset, bidi %a"](attr)
end
lro, rlo = false, false
@@ -266,14 +350,14 @@ function directions.process(namespace,attribute,start) -- todo: make faster
glyphs = true
if attr and attr > 0 then
local char = current.char
- local d = chardirs[char]
+ local d = chardirections[char]
if rlo or override > 0 then
if d == "l" then
- if trace_directions 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_directions then
+ 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
@@ -283,18 +367,18 @@ function directions.process(namespace,attribute,start) -- todo: make faster
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_directions then
+ 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_directions then
+ 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_directions then
+ 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
@@ -302,11 +386,10 @@ function directions.process(namespace,attribute,start) -- todo: make faster
end
end
if d == "on" then
- local cdata = chardata[char]
- local mirror = cdata.mirror -- maybe make a special mirror table
+ local mirror = charmirrors[char]
if mirror and fontchar[current.font][mirror] then
-- todo: set attribute
- local class = cdata.textclass
+ local class = charclasses[char]
if class == "open" then
if nextisright(current) then
if autodir >= 0 then
@@ -333,7 +416,7 @@ function directions.process(namespace,attribute,start) -- todo: make faster
else
mirror = nil
end
- if trace_directions then
+ 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
@@ -351,14 +434,14 @@ function directions.process(namespace,attribute,start) -- todo: make faster
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_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_directions then
+ if trace_textdirections then
list[#list+1] = "override right -> left"
end
top = top + 1
@@ -366,7 +449,7 @@ function directions.process(namespace,attribute,start) -- todo: make faster
override = -1
obsolete[#obsolete+1] = current
elseif d == "rlo" then -- Right-to-Left Override -> left becomes right
- if trace_directions then
+ if trace_textdirections then
list[#list+1] = "override left -> right"
end
top = top + 1
@@ -374,7 +457,7 @@ function directions.process(namespace,attribute,start) -- todo: make faster
override = 1
obsolete[#obsolete+1] = current
elseif d == "lre" then -- Left-to-Right Embedding -> TLT
- if trace_directions then
+ if trace_textdirections then
list[#list+1] = "embedding left -> right"
end
top = top + 1
@@ -382,7 +465,7 @@ function directions.process(namespace,attribute,start) -- todo: make faster
embedded = 1
obsolete[#obsolete+1] = current
elseif d == "rle" then -- Right-to-Left Embedding -> TRT
- if trace_directions then
+ if trace_textdirections then
list[#list+1] = "embedding right -> left"
end
top = top + 1
@@ -390,69 +473,62 @@ function directions.process(namespace,attribute,start) -- todo: make faster
embedded = -1 -- was 1
obsolete[#obsolete+1] = current
elseif d == "pdf" then -- Pop Directional Format
- -- override = 0
+ -- override = 0
if top > 0 then
local s = stack[top]
override, embedded = s[1], s[2]
top = top - 1
- if trace_directions then
+ if trace_textdirections then
list[#list+1] = formatters["state: override %a, embedded %a, autodir %a"](override,embedded,autodir)
end
else
- if trace_directions then
+ if trace_textdirections then
list[#list+1] = "pop error: too many pops"
end
end
obsolete[#obsolete+1] = current
end
- elseif trace_directions then
+ elseif trace_textdirections then
local char = current.char
- local d = chardirs[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
- local d = sub(dir,2,2)
- if d == 'R' then -- find(dir,".R.") / dir == "TRT"
- autodir = -1
- else
- autodir = 1
- end
- -- embedded = autodir
- if trace_directions then
- list[#list+1] = formatters["pardir %a"](dir)
- end
--- end
- elseif subtype == dir_code then
- local dir = current.dir
- -- local sign = sub(dir,1,1)
- -- local dire = sub(dir,3,3)
- local sign, dire = match(dir,"^(.).(.)") -- splitter
- if dire == "R" then
- if sign == "+" then
- finish, autodir = "TRT", -1
- else
- finish, autodir = nil, 0
+ -- if false then
+ local dir = current.dir
+ if dir == 'TRT' then
+ autodir = -1
+ elseif dir == 'TLT' then
+ autodir = 1
end
- else
- if sign == "+" then
- finish, autodir = "TLT", 1
- else
- finish, autodir = nil, 0
+ -- 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_directions then
+ if trace_textdirections then
list[#list+1] = formatters["textdir %a, autodir %a"](dir,autodir)
end
end
else
- if trace_directions then
+ if trace_textdirections then
list[#list+1] = formatters["node %a, subtype %a"](nodecodes[id],current.subtype)
end
if finish then
@@ -468,23 +544,45 @@ function directions.process(namespace,attribute,start) -- todo: make faster
current = cn
end
end
- if trace_directions and glyphs then
- report_directions("start log")
+
+ if trace_textdirections and glyphs then
+ report_textdirections("start log")
for i=1,#list do
- report_directions("%02i: %s",i,list[i])
+ report_textdirections("%02i: %s",i,list[i])
end
- report_directions("stop log")
+ 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_directions("%s character nodes removed",n)
+ 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
+ end
+ local attr = head[a_directions]
+ if not attr or attr == 0 then
+ return head, false
+ end
+ local method = getmethod(attr)
+ local handler = handlers[method]
+ if not handler then
+ return head, false
+ end
+ return handler(namespace,attribute,head)
end
-- function directions.enable()
@@ -495,8 +593,8 @@ local enabled = false
function directions.set(n) -- todo: names and numbers
if not enabled then
- if trace_directions then
- report_breakpoints("enabling directions handler")
+ if trace_textdirections then
+ report_textdirections("enabling directions handler")
end
tasks.enableaction("processors","typesetters.directions.handler")
enabled = true
@@ -511,7 +609,123 @@ end
commands.setdirection = directions.set
directions.handler = nodes.installattributehandler {
- name = "directions",
+ name = "directions",
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,
+-- }