summaryrefslogtreecommitdiff
path: root/tex/context/base/typo-dir.lua
blob: 482b7114d6363e94353440f99105578eccfd1d53 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
if not modules then modules = { } end modules ['typo-dir'] = {
    version   = 1.001,
    comment   = "companion to typo-dir.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

-- 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)

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

local nodes, node = nodes, node

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 hasbit                = number.hasbit

local texsetattribute       = tex.setattribute
local unsetvalue            = attributes.unsetvalue

local tasks                 = nodes.tasks
local tracers               = nodes.tracers
local setcolor              = tracers.colors.set
local resetcolor            = tracers.colors.reset

local implement             = interfaces.implement

local directions            = typesetters.directions or { }
typesetters.directions      = directions

local a_directions          = attributes.private('directions')

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
    handlers[method] = handler
    return method
end

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
        return 0
    end
    local method = methods[specification.method]
    if method then
        mode = mode + method
    else
        return 0
    end
    if specification.fences == v_yes then
        mode = mode + m_fences
    end
    return mode
end

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.getglobal      = getglobal
directions.getfences      = getfences
directions.getmethod      = getmethod
directions.installhandler = installhandler

-- beware: in dha we have character properties and in dua|b we have direction properties

function directions.setcolor(current,direction,reversed,mirror)
    if mirror then
        setcolor(current,"bidi:mirrored")
    elseif direction == "l" then
        setcolor(current,reversed and "bidi:left:reversed" or "bidi:left:original")
    elseif direction == "r" then
        setcolor(current,reversed and "bidi:right:reversed" or "bidi:right:original")
    else
        resetcolor(current)
    end
end

implement {
    name      = "getbidimode",
    actions   = { tomode, context },
    arguments = {
        {
            { "scope" },
            { "method" },
            { "fences" },
        }
    }
}

local enabled = false

local starttiming = statistics.starttiming
local stoptiming  = statistics.stoptiming

function directions.handler(head) -- ,_,_,_,direction) -- nodes not nuts | 5th arg is direction
    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
    starttiming(directions)
    local head, done = handler(head)
    stoptiming(directions)
    return head, done
end

statistics.register("text directions", function()
    if enabled then
        return statistics.elapsedseconds(directions)
    end
end)

-- function directions.enable()
--     tasks.enableaction("processors","directions.handler")
-- end

function directions.set(n) -- todo: names and numbers
    if not enabled then
        if trace_textdirections then
            report_textdirections("enabling directions handler")
        end
        tasks.enableaction("processors","typesetters.directions.handler")
        enabled = true
    end
    if not n or n == 0 then
        n = unsetvalue
        -- maybe tracing
    end
    texsetattribute(a_directions,n)
end

implement {
    name      = "setdirection",
    arguments = "integer",
    actions   = directions.set
}