diff options
Diffstat (limited to 'tex/context/base/lang-rep.lua')
-rw-r--r-- | tex/context/base/lang-rep.lua | 98 |
1 files changed, 91 insertions, 7 deletions
diff --git a/tex/context/base/lang-rep.lua b/tex/context/base/lang-rep.lua index fb136b551..be74d597a 100644 --- a/tex/context/base/lang-rep.lua +++ b/tex/context/base/lang-rep.lua @@ -7,9 +7,21 @@ if not modules then modules = { } end modules ['lang-rep'] = { } -- A BachoTeX 2013 experiment, probably not that useful. Eventually I used a simpler --- more generic example. +-- more generic example. I'm sure no one ever notices of even needs this code. +-- +-- As a follow up on a question by Alan about special treatment of dropped caps I wonder +-- if I can make this one more clever (probably in a few more dev steps). For instance +-- injecting nodes or replacing nodes. It's a prelude to a kind of lpeg for nodes, +-- although (given experiences so far) we don't really need that. After all, each problem +-- is somewhat unique. +local type = type local utfbyte, utfsplit = utf.byte, utf.split +local P, C, U, Cc, Ct, lpegmatch = lpeg.P, lpeg.C, lpeg.patterns.utf8character, lpeg.Cc, lpeg.Ct, lpeg.match +local find = string.find + +local grouped = P("{") * ( Ct((U/utfbyte-P("}"))^1) + Cc(false) ) * P("}")-- grouped +local splitter = Ct((Ct(Cc("discretionary") * grouped * grouped * grouped) + U/utfbyte)^1) local trace_replacements = false trackers.register("languages.replacements", function(v) trace_replacements = v end) local trace_detail = false trackers.register("languages.replacements.detail", function(v) trace_detail = v end) @@ -24,6 +36,7 @@ local tonode = nuts.tonode local setfield = nuts.setfield local getnext = nuts.getnext +local getprev = nuts.getprev local getattr = nuts.getattr local getid = nuts.getid local getchar = nuts.getchar @@ -31,6 +44,12 @@ local getchar = nuts.getchar local insert_node_before = nuts.insert_before local remove_node = nuts.remove local copy_node = nuts.copy +local flush_list = nuts.flush_list +local insert_after = nuts.insert_after + +local nodepool = nuts.pool +local new_glyph = nodepool.glyph +local new_disc = nodepool.disc local texsetattribute = tex.setattribute local unsetvalue = attributes.unsetvalue @@ -56,6 +75,8 @@ table.setmetatableindex(lists,function(lists,name) return data end) +-- todo: glue kern + local function add(root,word,replacement) local list = utfsplit(word,true) local size = #list @@ -65,15 +86,19 @@ local function add(root,word,replacement) root[l] = { } end if i == size then - local newlist = utfsplit(replacement,true) - for i=1,#newlist do - newlist[i] = utfbyte(newlist[i]) - end + -- local newlist = utfsplit(replacement,true) + -- for i=1,#newlist do + -- newlist[i] = utfbyte(newlist[i]) + -- end + local special = find(replacement,"{") + local newlist = lpegmatch(splitter,replacement) + -- root[l].final = { word = word, replacement = replacement, oldlength = size, newcodes = newlist, + special = special, } end root = root[l] @@ -124,6 +149,21 @@ local function hit(a,head) end end +local function tonodes(list,template) + local head, current + for i=1,#list do + local new = copy_node(template) + setfield(new,"char",list[i]) + if head then + head, current = insert_after(head,current,new) + else + head, current = new, new + end + end + return head +end + + function replacements.handler(head) head = tonut(head) local current = head @@ -137,10 +177,54 @@ function replacements.handler(head) local oldlength = final.oldlength local newcodes = final.newcodes local newlength = #newcodes - if report_replacement then + if trace_replacement then report_replacement("replacing word %a by %a",final.word,final.replacement) end - if oldlength == newlength then -- #old == #new + if final.special then + -- easier is to delete and insert (a simple callout to tex would be more efficient) + -- maybe just walk over a replacement string instead + local prev = getprev(current) + local next = getnext(last) + local list = current + setfield(last,"next",nil) + setfield(prev,"next",next) + if next then + setfield(next,"prev",prev) + end + current = prev + if not current then + head = nil + end + for i=1,newlength do + local codes = newcodes[i] + local new = nil + if type(codes) == "table" then + local method = codes[1] + if method == "discretionary" then + local pre, post, replace = codes[2], codes[3], codes[4] + new = new_disc() + if pre then + setfield(new,"pre",tonodes(pre,last)) + end + if post then + setfield(new,"post",tonodes(post,last)) + end + if replace then + setfield(new,"replace",tonodes(replace,last)) + end + else + -- todo + end + else + new = copy_node(last) + setfield(new,"char",codes) + end + if new then + head, current = insert_after(head,current,new) + end + end + flush_list(list) + elseif oldlength == newlength then -- #old == #new for i=1,newlength do setfield(current,"char",newcodes[i]) current = getnext(current) |