1if not modules then modules = { } end modules ['typo-chr'] = {
2 version = 1.001,
3 comment = "companion to typo-bld.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
12local insert, remove = table.insert, table.remove
13
14local context = context
15local ctx_doifelse = commands.doifelse
16
17local nodecodes = nodes.nodecodes
18local boundarycodes = nodes.boundarycodes
19local subtypes = nodes.subtypes
20
21local glyph_code = nodecodes.glyph
22local par_code = nodecodes.par
23local boundary_code = nodecodes.boundary
24
25local wordboundary_code = boundarycodes.word
26
27local texgetnest = tex.getnest
28local texsetcount = tex.setcount
29
30local flushnode = nodes.flushnode
31local flushlist = nodes.flushlist
32
33local settexattribute = tex.setattribute
34local ispunctuation = characters.is_punctuation
35
36local variables = interfaces.variables
37local v_all = variables.all
38local v_reset = variables.reset
39
40local stack = { }
41
42local a_marked = attributes.numbers['marked']
43local lastmarked = 0
44local marked = {
45 [v_all] = 1,
46 [""] = 1,
47 [v_reset] = attributes.unsetvalue,
48}
49
50local function pickup()
51 local list = texgetnest()
52 if list then
53 local tail = list.tail
54 if tail and tail.id == glyph_code and ispunctuation[tail.char] then
55 local prev = tail.prev
56 list.tail = prev
57 if prev then
58 prev.next = nil
59 end
60 list.tail = prev
61 tail.prev = nil
62 return tail
63 end
64 end
65end
66
67local actions = {
68 remove = function(specification)
69 local n = pickup()
70 if n then
71 flushnode(n)
72 end
73 end,
74 push = function(specification)
75 local n = pickup()
76 if n then
77 insert(stack,n or false)
78 end
79 end,
80 pop = function(specification)
81 local n = remove(stack)
82 if n then
83 context(n)
84 end
85 end,
86}
87
88local function pickuppunctuation(specification)
89 local action = actions[specification.action or "remove"]
90 if action then
91 action(specification)
92 end
93end
94
95
96
97
98local function pickup(head,tail,str)
99 local attr = marked[str]
100 local last = tail
101 if last[a_marked] == attr then
102 local first = last
103 while true do
104 local prev = first.prev
105 if prev and prev[a_marked] == attr then
106 if prev.id == par_code then
107 break
108 else
109 first = prev
110 end
111 else
112 break
113 end
114 end
115 return first, last
116 end
117end
118
119local function found(str)
120 local list = texgetnest()
121 if list then
122 local tail = list.tail
123 return tail and tail[a_marked] == marked[str]
124 end
125end
126
127local actions = {
128 remove = function(specification)
129 local list = texgetnest()
130 if list then
131 local head = list.head
132 local tail = list.tail
133 local first, last = pickup(head,tail,specification.mark)
134 if first then
135 if first == head then
136 list.head = nil
137 list.tail = nil
138 else
139 local prev = first.prev
140 list.tail = prev
141 prev.next = nil
142 end
143 flushlist(first)
144 end
145 end
146 end,
147}
148
149local function pickupmarkedcontent(specification)
150 local action = actions[specification.action or "remove"]
151 if action then
152 action(specification)
153 end
154end
155
156local function markcontent(str)
157 local currentmarked = marked[str or v_all]
158 if not currentmarked then
159 lastmarked = lastmarked + 1
160 currentmarked = lastmarked
161 marked[str] = currentmarked
162 end
163 settexattribute(a_marked,currentmarked)
164end
165
166interfaces.implement {
167 name = "pickuppunctuation",
168 actions = pickuppunctuation,
169 arguments = {
170 {
171 { "action" }
172 }
173 }
174}
175
176interfaces.implement {
177 name = "pickupmarkedcontent",
178 actions = pickupmarkedcontent,
179 arguments = {
180 {
181 { "action" },
182 { "mark" }
183 }
184 }
185}
186
187interfaces.implement {
188 name = "markcontent",
189 actions = markcontent,
190 arguments = "string",
191}
192
193interfaces.implement {
194 name = "doifelsemarkedcontent",
195 actions = function(str) ctx_doifelse(found(str)) end,
196 arguments = "string",
197}
198
199
200
201interfaces.implement {
202 name = "lastnodeidstring",
203 public = true,
204 actions = function()
205 local list = texgetnest()
206 local okay = false
207 if list then
208 local tail = list.tail
209 if tail then
210 okay = nodecodes[tail.id]
211 end
212 end
213 context(okay or "")
214 end,
215}
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231local c_syst_last_node_id = tex.iscount("c_syst_last_node_id")
232
233interfaces.implement {
234 name = "lastnodeid",
235 actions = function()
236 local list = texgetnest()
237 local okay = -1
238 if list then
239 local tail = list.tail
240 if tail then
241 okay = tail.id
242 end
243 end
244 texsetcount(c_syst_last_node_id,okay)
245 end,
246}
247
248interfaces.implement {
249 name = "lastnodesubtypestring",
250 public = true,
251 actions = function()
252 local list = texgetnest()
253 local okay = false
254 if list then
255 local tail = list.tail
256 if head then
257 okay = subtypes[tail.id][tail.subtype]
258 end
259 end
260 context(okay or "")
261 end,
262}
263
264local function lastnodeequals(id,subtype)
265 local list = texgetnest()
266 local okay = false
267 if list then
268 local tail = list.tail
269 if tail then
270 local i = tail.id
271 okay = i == id or i == nodecodes[id]
272 if subtype then
273 local s = tail.subtype
274 okay = s == subtype or s == subtypes[i][subtype]
275 end
276 end
277 end
278 ctx_doifelse(okay)
279end
280
281interfaces.implement {
282 name = "lastnodeequals",
283 arguments = "2 strings",
284 actions = lastnodeequals,
285}
286
287interfaces.implement {
288 name = "atwordboundary",
289 actions = function()
290 lastnodeequals(boundary_code,wordboundary_code)
291 end,
292}
293
294 |