1if not modules then modules = { } end modules ['typo-dir'] = {
2 version = 1.001,
3 comment = "companion to typo-dir.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29local next, type = next, type
30local format, insert, sub, find, match = string.format, table.insert, string.sub, string.find, string.match
31
32local nodes, node = nodes, node
33
34local trace_textdirections = false trackers.register("typesetters.directions.text", function(v) trace_textdirections = v end)
35local trace_mathdirections = false trackers.register("typesetters.directions.math", function(v) trace_mathdirections = v end)
36local trace_directions = false trackers.register("typesetters.directions", function(v) trace_textdirections = v trace_mathdirections = v end)
37
38local one_too = false directives.register("typesetters.directions.onetoo", function(v) one_too = v end)
39
40local report_textdirections = logs.reporter("typesetting","text directions")
41
42
43local texsetattribute = tex.setattribute
44
45local unsetvalue <const> = attributes.unsetvalue
46
47local nuts = nodes.nuts
48local getnext = nuts.getnext
49local getattr = nuts.getattr
50
51local enableaction = nodes.tasks.enableaction
52local tracers = nodes.tracers
53local setcolor = tracers.colors.set
54local resetcolor = tracers.colors.reset
55
56local implement = interfaces.implement
57
58local directions = typesetters.directions or { }
59typesetters.directions = directions
60
61local a_directions <const> = attributes.private('directions')
62
63local variables = interfaces.variables
64local v_global <const> = variables["global"]
65local v_local <const> = variables["local"]
66local v_on <const> = variables.on
67local v_yes <const> = variables.yes
68
69local m_enabled <const> = 0x00000040
70local m_global <const> = 0x00000080
71local m_fences <const> = 0x00000100
72
73local handlers = { }
74local methods = { }
75local lastmethod = 0
76
77local function installhandler(name,handler)
78 local method = methods[name]
79 if not method then
80 lastmethod = lastmethod + 1
81 method = lastmethod
82 methods[name] = method
83 end
84 handlers[method] = handler
85 return method
86end
87
88directions.handlers = handlers
89directions.installhandler = installhandler
90
91local function tomode(specification)
92 local scope = specification.scope
93 local mode
94 if scope == v_global or scope == v_on then
95 mode = m_enabled + m_global
96 elseif scope == v_local then
97 mode = m_enabled
98 else
99 return 0
100 end
101 local method = methods[specification.method]
102 if method then
103 mode = mode + method
104 else
105 return 0
106 end
107 if specification.fences == v_yes then
108 mode = mode + m_fences
109 end
110 return mode
111end
112
113local function getglobal(a)
114 return a and a > 0 and (a & m_global) ~= 0
115end
116
117local function getfences(a)
118 return a and a > 0 and (a & m_fences) ~= 0
119end
120
121local function getmethod(a)
122 return a and a > 0 and a % m_enabled or 0
123end
124
125directions.tomode = tomode
126directions.getglobal = getglobal
127directions.getfences = getfences
128directions.getmethod = getmethod
129directions.installhandler = installhandler
130
131
132
133function directions.setcolor(current,direction,reversed,mirror)
134 if mirror then
135 setcolor(current,"bidi:mirrored")
136 elseif direction == "l" then
137 setcolor(current,reversed and "bidi:left:reversed" or "bidi:left:original")
138 elseif direction == "r" then
139 setcolor(current,reversed and "bidi:right:reversed" or "bidi:right:original")
140 else
141 resetcolor(current)
142 end
143end
144
145implement {
146 name = "getbidimode",
147 actions = { tomode, context },
148 arguments = {
149 {
150 { "scope" },
151 { "method" },
152 { "fences" },
153 }
154 }
155}
156
157local enabled = false
158
159local starttiming = statistics.starttiming
160local stoptiming = statistics.stoptiming
161
162
163
164
165
166
167
168function directions.handler(head,where,direction)
169 local only_one = not getnext(head)
170 if only_one and not one_too then
171 return head
172 end
173 local attr = getattr(head,a_directions)
174 if not attr or attr == 0 then
175 return head
176 end
177 local method = getmethod(attr)
178 local handler = handlers[method]
179 if not handler then
180 return head
181 end
182 starttiming(directions)
183 head = handler(head,direction,only_one,where)
184 stoptiming(directions)
185 return head
186end
187
188statistics.register("text directions", function()
189 if enabled then
190 return statistics.elapsedseconds(directions)
191 end
192end)
193
194function directions.set(n)
195 if not enabled then
196 if trace_textdirections then
197 report_textdirections("enabling directions handler")
198 end
199 enableaction("processors","typesetters.directions.handler")
200 enabled = true
201 end
202 if not n or n == 0 then
203 n = unsetvalue
204
205 end
206 texsetattribute(a_directions,n)
207end
208
209implement {
210 name = "setdirection",
211 arguments = "integer",
212 actions = directions.set
213}
214 |