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 band = bit32.band
44
45local texsetattribute = tex.setattribute
46local unsetvalue = attributes.unsetvalue
47
48local nuts = nodes.nuts
49local getnext = nuts.getnext
50local getattr = nuts.getattr
51
52local enableaction = nodes.tasks.enableaction
53local tracers = nodes.tracers
54local setcolor = tracers.colors.set
55local resetcolor = tracers.colors.reset
56
57local implement = interfaces.implement
58
59local directions = typesetters.directions or { }
60typesetters.directions = directions
61
62local a_directions = attributes.private('directions')
63
64local variables = interfaces.variables
65local v_global = variables["global"]
66local v_local = variables["local"]
67local v_on = variables.on
68local v_yes = variables.yes
69
70local m_enabled = 0x00000040
71local m_global = 0x00000080
72local m_fences = 0x00000100
73
74local handlers = { }
75local methods = { }
76local lastmethod = 0
77
78local function installhandler(name,handler)
79 local method = methods[name]
80 if not method then
81 lastmethod = lastmethod + 1
82 method = lastmethod
83 methods[name] = method
84 end
85 handlers[method] = handler
86 return method
87end
88
89directions.handlers = handlers
90directions.installhandler = installhandler
91
92local function tomode(specification)
93 local scope = specification.scope
94 local mode
95 if scope == v_global or scope == v_on then
96 mode = m_enabled + m_global
97 elseif scope == v_local then
98 mode = m_enabled
99 else
100 return 0
101 end
102 local method = methods[specification.method]
103 if method then
104 mode = mode + method
105 else
106 return 0
107 end
108 if specification.fences == v_yes then
109 mode = mode + m_fences
110 end
111 return mode
112end
113
114local function getglobal(a)
115 return a and a > 0 and band(a,m_global) ~= 0
116end
117
118local function getfences(a)
119 return a and a > 0 and band(a,m_fences) ~= 0
120end
121
122local function getmethod(a)
123 return a and a > 0 and a % m_enabled or 0
124end
125
126directions.tomode = tomode
127directions.getglobal = getglobal
128directions.getfences = getfences
129directions.getmethod = getmethod
130directions.installhandler = installhandler
131
132
133
134function directions.setcolor(current,direction,reversed,mirror)
135 if mirror then
136 setcolor(current,"bidi:mirrored")
137 elseif direction == "l" then
138 setcolor(current,reversed and "bidi:left:reversed" or "bidi:left:original")
139 elseif direction == "r" then
140 setcolor(current,reversed and "bidi:right:reversed" or "bidi:right:original")
141 else
142 resetcolor(current)
143 end
144end
145
146implement {
147 name = "getbidimode",
148 actions = { tomode, context },
149 arguments = {
150 {
151 { "scope" },
152 { "method" },
153 { "fences" },
154 }
155 }
156}
157
158local enabled = false
159
160local starttiming = statistics.starttiming
161local stoptiming = statistics.stoptiming
162
163
164
165
166
167
168
169function directions.handler(head,where,_,_,direction)
170 local only_one = not getnext(head)
171 if only_one and not one_too then
172 return head
173 end
174 local attr = getattr(head,a_directions)
175 if not attr or attr == 0 then
176 return head
177 end
178 local method = getmethod(attr)
179 local handler = handlers[method]
180 if not handler then
181 return head
182 end
183 starttiming(directions)
184 head = handler(head,direction,only_one,where)
185 stoptiming(directions)
186 return head
187end
188
189statistics.register("text directions", function()
190 if enabled then
191 return statistics.elapsedseconds(directions)
192 end
193end)
194
195function directions.set(n)
196 if not enabled then
197 if trace_textdirections then
198 report_textdirections("enabling directions handler")
199 end
200 enableaction("processors","typesetters.directions.handler")
201 enabled = true
202 end
203 if not n or n == 0 then
204 n = unsetvalue
205
206 end
207 texsetattribute(a_directions,n)
208end
209
210implement {
211 name = "setdirection",
212 arguments = "integer",
213 actions = directions.set
214}
215 |