diff options
Diffstat (limited to 'tex/context/base/node-rul.lua')
| -rw-r--r-- | tex/context/base/node-rul.lua | 778 | 
1 files changed, 389 insertions, 389 deletions
| diff --git a/tex/context/base/node-rul.lua b/tex/context/base/node-rul.lua index 00039550c..09300964e 100644 --- a/tex/context/base/node-rul.lua +++ b/tex/context/base/node-rul.lua @@ -1,389 +1,389 @@ -if not modules then modules = { } end modules ['node-rul'] = {
 -    version   = 1.001,
 -    comment   = "companion to node-rul.mkiv",
 -    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
 -    copyright = "PRAGMA ADE / ConTeXt Development Team",
 -    license   = "see context related readme files"
 -}
 -
 --- this will go to an auxiliary module
 --- beware: rules now have a dir field
 ---
 --- todo: make robust for layers ... order matters
 -
 -local attributes, nodes, node = attributes, nodes, node
 -
 -local nodecodes  = nodes.nodecodes
 -local tasks      = nodes.tasks
 -
 -local glyph_code = nodecodes.glyph
 -local disc_code  = nodecodes.disc
 -local rule_code  = nodecodes.rule
 -
 -function nodes.striprange(first,last) -- todo: dir
 -    if first and last then -- just to be sure
 -        if first == last then
 -            return first, last
 -        end
 -        while first and first ~= last do
 -            local id = first.id
 -            if id == glyph_code or id == disc_code then -- or id == rule_code
 -                break
 -            else
 -                first = first.next
 -            end
 -        end
 -        if not first then
 -            return nil, nil
 -        elseif first == last then
 -            return first, last
 -        end
 -        while last and last ~= first do
 -            local id = last.id
 -            if id == glyph_code or id == disc_code then -- or id == rule_code
 -                break
 -            else
 -                local prev = last.prev -- luatex < 0.70 has italic correction kern not prev'd
 -                if prev then
 -                    last = last.prev
 -                else
 -                    break
 -                end
 -            end
 -        end
 -        if not last then
 -            return nil, nil
 -        end
 -    end
 -    return first, last
 -end
 -
 --- todo: order and maybe other dimensions
 -
 -local floor = math.floor
 -
 -local trace_ruled        = false  trackers.register("nodes.rules", function(v) trace_ruled = v end)
 -local report_ruled       = logs.reporter("nodes","rules")
 -
 -local n_tostring         = nodes.idstostring
 -local n_tosequence       = nodes.tosequence
 -
 -local a_ruled            = attributes.private('ruled')
 -local a_color            = attributes.private('color')
 -local a_transparency     = attributes.private('transparency')
 -local a_colorspace       = attributes.private('colormodel')
 -
 -local insert_node_before = node.insert_before
 -local insert_node_after  = node.insert_after
 -local striprange         = nodes.striprange
 -local list_dimensions    = node.dimensions
 -
 -local hpack_nodes        = node.hpack
 -
 -local fontdata           = fonts.hashes.identifiers
 -local variables          = interfaces.variables
 -local dimenfactor        = fonts.helpers.dimenfactor
 -local splitdimen         = number.splitdimen
 -
 -local nodecodes          = nodes.nodecodes
 -local skipcodes          = nodes.skipcodes
 -local whatcodes          = nodes.whatcodes
 -local kerncodes          = nodes.kerncodes
 -
 -local glyph_code         = nodecodes.glyph
 -local disc_code          = nodecodes.disc
 -local glue_code          = nodecodes.glue
 -local penalty_code       = nodecodes.penalty
 -local kern_code          = nodecodes.kern
 -local hlist_code         = nodecodes.hlist
 -local vlist_code         = nodecodes.vlist
 -local rule_code          = nodecodes.rule
 -local whatsit_code       = nodecodes.whatsit
 -
 -local userskip_code      = skipcodes.userskip
 -local spaceskip_code     = skipcodes.spaceskip
 -local xspaceskip_code    = skipcodes.xspaceskip
 -
 -local dir_code           = whatcodes.dir
 -
 -local kerning_code       = kerncodes.kern
 -
 -local nodepool           = nodes.pool
 -
 -local new_rule           = nodepool.rule
 -local new_kern           = nodepool.kern
 -local new_glue           = nodepool.glue
 -
 --- we can use this one elsewhere too
 ---
 --- todo: functions: word, sentence
 ---
 --- glyph rule unset whatsit glue margin_kern kern math disc
 -
 -local checkdir = true
 -
 --- we assume {glyphruns} and no funny extra kerning, ok, maybe we need
 --- a dummy character as start and end; anyway we only collect glyphs
 ---
 --- this one needs to take layers into account (i.e. we need a list of
 --- critical attributes)
 -
 --- omkeren class en level -> scheelt functie call in analyze
 -
 --- todo: switching inside math
 -
 -local function processwords(attribute,data,flush,head,parent) -- we have hlistdir and local dir
 -    local n = head
 -    if n then
 -        local f, l, a, d, i, class
 -        local continue, done, strip, level = false, false, true, -1
 -        while n do
 -            local id = n.id
 -            if id == glyph_code or id == rule_code then
 -                local aa = n[attribute]
 -                if aa then
 -                    if aa == a then
 -                        if not f then -- ?
 -                            f = n
 -                        end
 -                        l = n
 -                    else
 -                        -- possible extensions: when in same class then keep spanning
 -                        local newlevel, newclass = floor(aa/1000), aa%1000
 ---~                         strip = not continue or level == 1 -- 0
 -                        if f then
 -                            if class == newclass then -- and newlevel > level then
 -                                head, done = flush(head,f,l,d,level,parent,false), true
 -                            else
 -                                head, done = flush(head,f,l,d,level,parent,strip), true
 -                            end
 -                        end
 -                        f, l, a = n, n, aa
 -                        level, class = newlevel, newclass
 -                        d = data[class]
 -                        continue = d.continue == variables.yes
 -                    end
 -                else
 -                    if f then
 -                        head, done = flush(head,f,l,d,level,parent,strip), true
 -                    end
 -                    f, l, a = nil, nil, nil
 -                end
 -            elseif f and (id == disc_code or (id == kern_code and n.subtype == kerning_code)) then
 -                l = n
 -            elseif id == hlist_code or id == vlist_code then
 -                if f then
 -                    head, done = flush(head,f,l,d,level,parent,strip), true
 -                    f, l, a = nil, nil, nil
 -                end
 -                local list = n.list
 -                if list then
 -                    n.list = processwords(attribute,data,flush,list,n)
 -                end
 -            elseif checkdir and id == whatsit_code and n.subtype == dir_code then -- only changes in dir, we assume proper boundaries
 -                if f and a then
 -                    l = n
 -                end
 -            elseif f then
 -                if continue then
 -                    if id == penalty_code then
 -                        l = n
 -                    elseif id == kern_code then
 -                        l = n
 -                    elseif id == glue_code then
 -                        -- catch \underbar{a} \underbar{a} (subtype test is needed)
 -                        local subtype = n.subtype
 -                        if continue and n[attribute] and
 -                            (subtype == userskip_code or subtype == spaceskip_code or subskip == xspaceskip_code) then
 -                            l = n
 -                        else
 -                            head, done = flush(head,f,l,d,level,parent,strip), true
 -                            f, l, a = nil, nil, nil
 -                        end
 -                    end
 -                else
 -                    head, done = flush(head,f,l,d,level,parent,strip), true
 -                    f, l, a = nil, nil, nil
 -                end
 -            end
 -            n = n.next
 -        end
 -        if f then
 -            head, done = flush(head,f,l,d,level,parent,strip), true
 -        end
 -        return head, true -- todo: done
 -    else
 -        return head, false
 -    end
 -end
 -
 -nodes.processwords = processwords
 -
 ---
 -
 -nodes.rules      = nodes.rules      or { }
 -nodes.rules.data = nodes.rules.data or { }
 -
 -storage.register("nodes/rules/data", nodes.rules.data, "nodes.rules.data")
 -
 -local data = nodes.rules.data
 -
 -function nodes.rules.define(settings)
 -    data[#data+1] = settings
 -    context(#data)
 -end
 -
 -local a_viewerlayer = attributes.private("viewerlayer")
 -
 -local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but acceptable for this purpose
 --- check for f and l
 -    if f.id ~= glyph_code then
 -        -- saveguard ... we need to deal with rules and so (math)
 -        return head
 -    end
 -    local r, m
 -    if strip then
 -        if trace_ruled then
 -            local before = n_tosequence(f,l,true)
 -            f, l = striprange(f,l)
 -            local after = n_tosequence(f,l,true)
 -            report_ruled("range stripper, before %a, after %a",before,after)
 -        else
 -            f, l = striprange(f,l)
 -        end
 -    end
 -    if not f then
 -        return head
 -    end
 -    local w = list_dimensions(parent.glue_set,parent.glue_sign,parent.glue_order,f,l.next)
 -    local method, offset, continue, dy, order, max = d.method, d.offset, d.continue, d.dy, d.order, d.max
 -    local rulethickness, unit = d.rulethickness, d.unit
 -    local ma, ca, ta = d.ma, d.ca, d.ta
 -    local colorspace   = (ma > 0 and ma) or f[a_colorspace] or 1
 -    local color        = (ca > 0 and ca) or f[a_color]
 -    local transparency = (ta > 0 and ta) or f[a_transparency]
 -    local foreground = order == variables.foreground
 -
 -    local e = dimenfactor(unit,fontdata[f.font]) -- what if no glyph node
 -
 -    local rt = tonumber(rulethickness)
 -    if rt then
 -        rulethickness = e * rulethickness / 2
 -    else
 -        local n, u = splitdimen(rulethickness)
 -        if n and u then -- we need to intercept ex and em and % and ...
 -            rulethickness = n * dimenfactor(u,fontdata[f.font]) / 2
 -        else
 -            rulethickness = 1/5
 -        end
 -    end
 -
 -    if level > max then
 -        level = max
 -    end
 -    if method == 0 then -- center
 -        offset = 2*offset
 ---         m = (offset+(level-1)*dy+rulethickness)*e/2
 -        m = (offset+(level-1)*dy)*e/2 + rulethickness/2
 -    else
 -        m = 0
 -    end
 -    for i=1,level do
 ---         local ht =  (offset+(i-1)*dy+rulethickness)*e - m
 ---         local dp = -(offset+(i-1)*dy-rulethickness)*e + m
 -        local ht =  (offset+(i-1)*dy)*e + rulethickness - m
 -        local dp = -(offset+(i-1)*dy)*e + rulethickness + m
 -        local r = new_rule(w,ht,dp)
 -        local v = f[a_viewerlayer]
 -        -- quick hack
 -        if v then
 -            r[a_viewerlayer] = v
 -        end
 -        --
 -        if color then
 -            r[a_colorspace] = colorspace
 -            r[a_color] = color
 -        end
 -        if transparency then
 -            r[a_transparency] = transparency
 -        end
 -        local k = new_kern(-w)
 -        if foreground then
 -            insert_node_after(head,l,k)
 -            insert_node_after(head,k,r)
 -            l = r
 -        else
 -            head = insert_node_before(head,f,r)
 -            insert_node_after(head,r,k)
 -        end
 -        if trace_ruled then
 -            report_ruled("level %a, width %p, height %p, depth %p, nodes %a, text %a",
 -                level,w,ht,dp,n_tostring(f,l),n_tosequence(f,l,true))
 -        end
 -    end
 -    return head
 -end
 -
 -local process = nodes.processwords
 -
 -nodes.rules.handler = function(head) return process(a_ruled,data,flush_ruled,head) end
 -
 -function nodes.rules.enable()
 -    tasks.enableaction("shipouts","nodes.rules.handler")
 -end
 -
 --- elsewhere:
 ---
 --- tasks.appendaction ("shipouts", "normalizers", "nodes.rules.handler")
 --- tasks.disableaction("shipouts",                "nodes.rules.handler") -- only kick in when used
 -
 -local trace_shifted = false  trackers.register("nodes.shifting", function(v) trace_shifted = v end)
 -
 -local report_shifted = logs.reporter("nodes","shifting")
 -
 -local a_shifted = attributes.private('shifted')
 -
 -nodes.shifts      = nodes.shifts      or { }
 -nodes.shifts.data = nodes.shifts.data or { }
 -
 -storage.register("nodes/shifts/data", nodes.shifts.data, "nodes.shifts.data")
 -
 -local data = nodes.shifts.data
 -
 -function nodes.shifts.define(settings)
 -    data[#data+1] = settings
 -    context(#data)
 -end
 -
 -local function flush_shifted(head,first,last,data,level,parent,strip) -- not that fast but acceptable for this purpose
 -    if true then
 -        first, last = striprange(first,last)
 -    end
 -    local prev, next = first.prev, last.next
 -    first.prev, last.next = nil, nil
 -    local width, height, depth = list_dimensions(parent.glue_set,parent.glue_sign,parent.glue_order,first,next)
 -    local list = hpack_nodes(first,width,"exactly")
 -    if first == head then
 -        head = list
 -    end
 -    if prev then
 -        prev.next, list.prev = list, prev
 -    end
 -    if next then
 -        next.prev, list.next = list, next
 -    end
 -    local raise = data.dy * dimenfactor(data.unit,fontdata[first.font])
 -    list.shift, list.height, list.depth = raise, height, depth
 -    if trace_shifted then
 -        report_shifted("width %p, nodes %a, text %a",width,n_tostring(first,last),n_tosequence(first,last,true))
 -    end
 -    return head
 -end
 -
 -local process = nodes.processwords
 -
 -nodes.shifts.handler = function(head) return process(a_shifted,data,flush_shifted,head) end
 -
 -function nodes.shifts.enable()
 -    tasks.enableaction("shipouts","nodes.shifts.handler")
 -end
 +if not modules then modules = { } end modules ['node-rul'] = { +    version   = 1.001, +    comment   = "companion to node-rul.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +-- this will go to an auxiliary module +-- beware: rules now have a dir field +-- +-- todo: make robust for layers ... order matters + +local attributes, nodes, node = attributes, nodes, node + +local nodecodes  = nodes.nodecodes +local tasks      = nodes.tasks + +local glyph_code = nodecodes.glyph +local disc_code  = nodecodes.disc +local rule_code  = nodecodes.rule + +function nodes.striprange(first,last) -- todo: dir +    if first and last then -- just to be sure +        if first == last then +            return first, last +        end +        while first and first ~= last do +            local id = first.id +            if id == glyph_code or id == disc_code then -- or id == rule_code +                break +            else +                first = first.next +            end +        end +        if not first then +            return nil, nil +        elseif first == last then +            return first, last +        end +        while last and last ~= first do +            local id = last.id +            if id == glyph_code or id == disc_code then -- or id == rule_code +                break +            else +                local prev = last.prev -- luatex < 0.70 has italic correction kern not prev'd +                if prev then +                    last = last.prev +                else +                    break +                end +            end +        end +        if not last then +            return nil, nil +        end +    end +    return first, last +end + +-- todo: order and maybe other dimensions + +local floor = math.floor + +local trace_ruled        = false  trackers.register("nodes.rules", function(v) trace_ruled = v end) +local report_ruled       = logs.reporter("nodes","rules") + +local n_tostring         = nodes.idstostring +local n_tosequence       = nodes.tosequence + +local a_ruled            = attributes.private('ruled') +local a_color            = attributes.private('color') +local a_transparency     = attributes.private('transparency') +local a_colorspace       = attributes.private('colormodel') + +local insert_node_before = node.insert_before +local insert_node_after  = node.insert_after +local striprange         = nodes.striprange +local list_dimensions    = node.dimensions + +local hpack_nodes        = node.hpack + +local fontdata           = fonts.hashes.identifiers +local variables          = interfaces.variables +local dimenfactor        = fonts.helpers.dimenfactor +local splitdimen         = number.splitdimen + +local nodecodes          = nodes.nodecodes +local skipcodes          = nodes.skipcodes +local whatcodes          = nodes.whatcodes +local kerncodes          = nodes.kerncodes + +local glyph_code         = nodecodes.glyph +local disc_code          = nodecodes.disc +local glue_code          = nodecodes.glue +local penalty_code       = nodecodes.penalty +local kern_code          = nodecodes.kern +local hlist_code         = nodecodes.hlist +local vlist_code         = nodecodes.vlist +local rule_code          = nodecodes.rule +local whatsit_code       = nodecodes.whatsit + +local userskip_code      = skipcodes.userskip +local spaceskip_code     = skipcodes.spaceskip +local xspaceskip_code    = skipcodes.xspaceskip + +local dir_code           = whatcodes.dir + +local kerning_code       = kerncodes.kern + +local nodepool           = nodes.pool + +local new_rule           = nodepool.rule +local new_kern           = nodepool.kern +local new_glue           = nodepool.glue + +-- we can use this one elsewhere too +-- +-- todo: functions: word, sentence +-- +-- glyph rule unset whatsit glue margin_kern kern math disc + +local checkdir = true + +-- we assume {glyphruns} and no funny extra kerning, ok, maybe we need +-- a dummy character as start and end; anyway we only collect glyphs +-- +-- this one needs to take layers into account (i.e. we need a list of +-- critical attributes) + +-- omkeren class en level -> scheelt functie call in analyze + +-- todo: switching inside math + +local function processwords(attribute,data,flush,head,parent) -- we have hlistdir and local dir +    local n = head +    if n then +        local f, l, a, d, i, class +        local continue, done, strip, level = false, false, true, -1 +        while n do +            local id = n.id +            if id == glyph_code or id == rule_code then +                local aa = n[attribute] +                if aa then +                    if aa == a then +                        if not f then -- ? +                            f = n +                        end +                        l = n +                    else +                        -- possible extensions: when in same class then keep spanning +                        local newlevel, newclass = floor(aa/1000), aa%1000 +--~                         strip = not continue or level == 1 -- 0 +                        if f then +                            if class == newclass then -- and newlevel > level then +                                head, done = flush(head,f,l,d,level,parent,false), true +                            else +                                head, done = flush(head,f,l,d,level,parent,strip), true +                            end +                        end +                        f, l, a = n, n, aa +                        level, class = newlevel, newclass +                        d = data[class] +                        continue = d.continue == variables.yes +                    end +                else +                    if f then +                        head, done = flush(head,f,l,d,level,parent,strip), true +                    end +                    f, l, a = nil, nil, nil +                end +            elseif f and (id == disc_code or (id == kern_code and n.subtype == kerning_code)) then +                l = n +            elseif id == hlist_code or id == vlist_code then +                if f then +                    head, done = flush(head,f,l,d,level,parent,strip), true +                    f, l, a = nil, nil, nil +                end +                local list = n.list +                if list then +                    n.list = processwords(attribute,data,flush,list,n) +                end +            elseif checkdir and id == whatsit_code and n.subtype == dir_code then -- only changes in dir, we assume proper boundaries +                if f and a then +                    l = n +                end +            elseif f then +                if continue then +                    if id == penalty_code then +                        l = n +                    elseif id == kern_code then +                        l = n +                    elseif id == glue_code then +                        -- catch \underbar{a} \underbar{a} (subtype test is needed) +                        local subtype = n.subtype +                        if continue and n[attribute] and +                            (subtype == userskip_code or subtype == spaceskip_code or subskip == xspaceskip_code) then +                            l = n +                        else +                            head, done = flush(head,f,l,d,level,parent,strip), true +                            f, l, a = nil, nil, nil +                        end +                    end +                else +                    head, done = flush(head,f,l,d,level,parent,strip), true +                    f, l, a = nil, nil, nil +                end +            end +            n = n.next +        end +        if f then +            head, done = flush(head,f,l,d,level,parent,strip), true +        end +        return head, true -- todo: done +    else +        return head, false +    end +end + +nodes.processwords = processwords + +-- + +nodes.rules      = nodes.rules      or { } +nodes.rules.data = nodes.rules.data or { } + +storage.register("nodes/rules/data", nodes.rules.data, "nodes.rules.data") + +local data = nodes.rules.data + +function nodes.rules.define(settings) +    data[#data+1] = settings +    context(#data) +end + +local a_viewerlayer = attributes.private("viewerlayer") + +local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but acceptable for this purpose +-- check for f and l +    if f.id ~= glyph_code then +        -- saveguard ... we need to deal with rules and so (math) +        return head +    end +    local r, m +    if strip then +        if trace_ruled then +            local before = n_tosequence(f,l,true) +            f, l = striprange(f,l) +            local after = n_tosequence(f,l,true) +            report_ruled("range stripper, before %a, after %a",before,after) +        else +            f, l = striprange(f,l) +        end +    end +    if not f then +        return head +    end +    local w = list_dimensions(parent.glue_set,parent.glue_sign,parent.glue_order,f,l.next) +    local method, offset, continue, dy, order, max = d.method, d.offset, d.continue, d.dy, d.order, d.max +    local rulethickness, unit = d.rulethickness, d.unit +    local ma, ca, ta = d.ma, d.ca, d.ta +    local colorspace   = (ma > 0 and ma) or f[a_colorspace] or 1 +    local color        = (ca > 0 and ca) or f[a_color] +    local transparency = (ta > 0 and ta) or f[a_transparency] +    local foreground = order == variables.foreground + +    local e = dimenfactor(unit,fontdata[f.font]) -- what if no glyph node + +    local rt = tonumber(rulethickness) +    if rt then +        rulethickness = e * rulethickness / 2 +    else +        local n, u = splitdimen(rulethickness) +        if n and u then -- we need to intercept ex and em and % and ... +            rulethickness = n * dimenfactor(u,fontdata[f.font]) / 2 +        else +            rulethickness = 1/5 +        end +    end + +    if level > max then +        level = max +    end +    if method == 0 then -- center +        offset = 2*offset +--         m = (offset+(level-1)*dy+rulethickness)*e/2 +        m = (offset+(level-1)*dy)*e/2 + rulethickness/2 +    else +        m = 0 +    end +    for i=1,level do +--         local ht =  (offset+(i-1)*dy+rulethickness)*e - m +--         local dp = -(offset+(i-1)*dy-rulethickness)*e + m +        local ht =  (offset+(i-1)*dy)*e + rulethickness - m +        local dp = -(offset+(i-1)*dy)*e + rulethickness + m +        local r = new_rule(w,ht,dp) +        local v = f[a_viewerlayer] +        -- quick hack +        if v then +            r[a_viewerlayer] = v +        end +        -- +        if color then +            r[a_colorspace] = colorspace +            r[a_color] = color +        end +        if transparency then +            r[a_transparency] = transparency +        end +        local k = new_kern(-w) +        if foreground then +            insert_node_after(head,l,k) +            insert_node_after(head,k,r) +            l = r +        else +            head = insert_node_before(head,f,r) +            insert_node_after(head,r,k) +        end +        if trace_ruled then +            report_ruled("level %a, width %p, height %p, depth %p, nodes %a, text %a", +                level,w,ht,dp,n_tostring(f,l),n_tosequence(f,l,true)) +        end +    end +    return head +end + +local process = nodes.processwords + +nodes.rules.handler = function(head) return process(a_ruled,data,flush_ruled,head) end + +function nodes.rules.enable() +    tasks.enableaction("shipouts","nodes.rules.handler") +end + +-- elsewhere: +-- +-- tasks.appendaction ("shipouts", "normalizers", "nodes.rules.handler") +-- tasks.disableaction("shipouts",                "nodes.rules.handler") -- only kick in when used + +local trace_shifted = false  trackers.register("nodes.shifting", function(v) trace_shifted = v end) + +local report_shifted = logs.reporter("nodes","shifting") + +local a_shifted = attributes.private('shifted') + +nodes.shifts      = nodes.shifts      or { } +nodes.shifts.data = nodes.shifts.data or { } + +storage.register("nodes/shifts/data", nodes.shifts.data, "nodes.shifts.data") + +local data = nodes.shifts.data + +function nodes.shifts.define(settings) +    data[#data+1] = settings +    context(#data) +end + +local function flush_shifted(head,first,last,data,level,parent,strip) -- not that fast but acceptable for this purpose +    if true then +        first, last = striprange(first,last) +    end +    local prev, next = first.prev, last.next +    first.prev, last.next = nil, nil +    local width, height, depth = list_dimensions(parent.glue_set,parent.glue_sign,parent.glue_order,first,next) +    local list = hpack_nodes(first,width,"exactly") +    if first == head then +        head = list +    end +    if prev then +        prev.next, list.prev = list, prev +    end +    if next then +        next.prev, list.next = list, next +    end +    local raise = data.dy * dimenfactor(data.unit,fontdata[first.font]) +    list.shift, list.height, list.depth = raise, height, depth +    if trace_shifted then +        report_shifted("width %p, nodes %a, text %a",width,n_tostring(first,last),n_tosequence(first,last,true)) +    end +    return head +end + +local process = nodes.processwords + +nodes.shifts.handler = function(head) return process(a_shifted,data,flush_shifted,head) end + +function nodes.shifts.enable() +    tasks.enableaction("shipouts","nodes.shifts.handler") +end | 
