diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/font-ots.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkiv/font-ots.lua | 500 |
1 files changed, 253 insertions, 247 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-ots.lua b/Master/texmf-dist/tex/context/base/mkiv/font-ots.lua index 563094fc17b..25083dfcef8 100644 --- a/Master/texmf-dist/tex/context/base/mkiv/font-ots.lua +++ b/Master/texmf-dist/tex/context/base/mkiv/font-ots.lua @@ -82,7 +82,7 @@ mechanisms. Both put some constraints on the code here.</p> -- Todo: check if we copy attributes to disc nodes if needed. -- -- Todo: it would be nice if we could get rid of components. In other places we can use --- the unicode properties. We can just keep a lua table. +-- the unicode properties. -- -- Remark: We do some disc juggling where we need to keep in mind that the pre, post and -- replace fields can have prev pointers to a nesting node ... I wonder if that is still @@ -176,6 +176,8 @@ registertracker("otf.sample", "otf.steps","otf.substitutions","otf.positi registertracker("otf.sample.silent", "otf.steps=silent","otf.substitutions","otf.positions","otf.analyzing") local nuts = nodes.nuts +local tonode = nuts.tonode +local tonut = nuts.tonut local getfield = nuts.getfield local getnext = nuts.getnext @@ -189,6 +191,7 @@ local getattr = nuts.getattr local setattr = nuts.setattr local getprop = nuts.getprop local setprop = nuts.setprop +local getfont = nuts.getfont local getsubtype = nuts.getsubtype local setsubtype = nuts.setsubtype local getchar = nuts.getchar @@ -198,10 +201,10 @@ local setdisc = nuts.setdisc local setlink = nuts.setlink local getcomponents = nuts.getcomponents -- the original one, not yet node-aux local setcomponents = nuts.setcomponents -- the original one, not yet node-aux +local getdir = nuts.getdir local getwidth = nuts.getwidth local ischar = nuts.is_char -local isglyph = nuts.isglyph local usesfont = nuts.uses_font local insert_node_after = nuts.insert_after @@ -212,12 +215,17 @@ local find_node_tail = nuts.tail local flush_node_list = nuts.flush_list local flush_node = nuts.flush_node local end_of_math = nuts.end_of_math +local traverse_nodes = nuts.traverse +----- traverse_id = nuts.traverse_id +local set_components = nuts.set_components +local take_components = nuts.take_components +local count_components = nuts.count_components +local copy_no_components = nuts.copy_no_components +local copy_only_glyphs = nuts.copy_only_glyphs local setmetatable = setmetatable local setmetatableindex = table.setmetatableindex -local nextnode = nuts.traversers.node - ----- zwnj = 0x200C ----- zwj = 0x200D @@ -232,8 +240,8 @@ local math_code = nodecodes.math local dir_code = nodecodes.dir local localpar_code = nodecodes.localpar -local discretionarydisc_code = disccodes.discretionary -local ligatureglyph_code = glyphcodes.ligature +local discretionary_code = disccodes.discretionary +local ligature_code = glyphcodes.ligature local a_state = attributes.private('state') local a_noligature = attributes.private("noligature") @@ -450,28 +458,26 @@ end -- start is a mark and we need to keep that one -local copy_no_components = nuts.copy_no_components -local copy_only_glyphs = nuts.copy_only_glyphs - -local set_components = setcomponents -local take_components = getcomponents +local take_components = getcomponents -- we overload here (for now) +local set_components = setcomponents -- we overload here (for now) +----- get_components = getcomponents -- we overload here (for now) local function count_components(start,marks) - local char = isglyph(start) - if char then - if getsubtype(start) == ligatureglyph_code then - local i = 0 - local components = getcomponents(start) - while components do - i = i + count_components(components,marks) - components = getnext(components) - end - return i - elseif not marks[char] then - return 1 + if getid(start) ~= glyph_code then + return 0 + elseif getsubtype(start) == ligature_code then + local i = 0 + local components = getcomponents(start) + while components do + i = i + count_components(components,marks) + components = getnext(components) end + return i + elseif not marks[getchar(start)] then + return 1 + else + return 0 end - return 0 end local function markstoligature(head,start,stop,char) @@ -488,7 +494,7 @@ local function markstoligature(head,start,stop,char) end resetinjection(base) setchar(base,char) - setsubtype(base,ligatureglyph_code) + setsubtype(base,ligature_code) set_components(base,start) setlink(prev,base,next) return head, base @@ -524,7 +530,7 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou end resetinjection(base) setchar(base,char) - setsubtype(base,ligatureglyph_code) + setsubtype(base,ligature_code) set_components(base,comp) setlink(prev,base,next) if not discfound then @@ -606,7 +612,7 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou set_components(base,copied) replace = base if forcediscretionaries then - setdisc(discfound,pre,post,replace,discretionarydisc_code) + setdisc(discfound,pre,post,replace,discretionary_code) else setdisc(discfound,pre,post,replace) end @@ -617,7 +623,7 @@ local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfou return head, base end -local function multiple_glyphs(head,start,multiple,skiphash,what,stop) -- what to do with skiphash matches here +local function multiple_glyphs(head,start,multiple,skiphash,what) -- what to do with skiphash matches here local nofmultiples = #multiple if nofmultiples > 0 then resetinjection(start) @@ -778,17 +784,23 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip -- ok, goto next lookup end end - else + else -- is the check for disc still valid here ? and why only replace then local discfound = false + local lastdisc = nil local hasmarks = marks[startchar] while current do local char, id = ischar(current,currentfont) if char then if skiphash and skiphash[char] then current = getnext(current) - else - local lg = ligature[char] + -- if stop then stop = current end -- ? + else -- ligature is a tree + local lg = ligature[char] -- can there be multiple in a row? maybe in a bad font if lg then + if not discfound and lastdisc then + discfound = lastdisc + lastdisc = nil + end if marks[char] then hasmarks = true end @@ -803,76 +815,47 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip -- kind of weird break elseif id == disc_code then - discfound = current - break - else - break - end - end - -- of{f-}{}{f}e o{f-}{}{f}fe o{-}{}{ff}e (oe and ff ligature) - -- we can end up here when we have a start run .. testruns start at a disc but - -- so here we have the other case: char + disc - if discfound then - -- don't assume marks in a disc and we don't run over a disc (for now) - local pre, post, replace = getdisc(discfound) - local match - if replace then - local char = ischar(replace,currentfont) - if char and ligature[char] then - match = true - end - end - if not match and pre then - local char = ischar(pre,currentfont) - if char and ligature[char] then - match = true - end - end - if not match and not pre or not replace then - local n = getnext(discfound) - local char = ischar(n,currentfont) - if char and ligature[char] then - match = true - end - end - if match then - -- we force a restart - local ishead = head == start - local prev = getprev(start) - if stop then - setnext(stop) - local tail = getprev(stop) - local copy = copy_node_list(start) - local liat = find_node_tail(copy) - if pre then - setlink(liat,pre) - end - if replace then - setlink(tail,replace) - end - pre = copy - replace = start - else - setnext(start) - local copy = copy_node(start) - if pre then - setlink(copy,pre) - end - if replace then - setlink(start,replace) + -- + -- Kai: see chainprocs, we probably could do the same here or was there a reason + -- why we kept the replace check here. + -- + -- if not discfound then + -- discfound = current + -- end + -- if current == stop then + -- break -- okay? or before the disc + -- else + -- current = getnext(current) + -- end + -- + local replace = getfield(current,"replace") -- hm: pre and post + if replace then + -- of{f-}{}{f}e o{f-}{}{f}fe o{-}{}{ff}e (oe and ff ligature) + -- we can end up here when we have a start run .. testruns start at a disc but + -- so here we have the other case: char + disc + while replace do + local char, id = ischar(replace,currentfont) + if char then + local lg = ligature[char] -- can there be multiple in a row? maybe in a bad font + if lg then + if marks[char] then + hasmarks = true -- very unlikely + end + ligature = lg + replace = getnext(replace) + else + return head, start, false, false + end + else + return head, start, false, false + end end - pre = copy - replace = start - end - setdisc(discfound,pre,post,replace) - if prev then - setlink(prev,discfound) - else - setprev(discfound) - head = discfound + stop = current end - start = discfound - return head, start, true, true + lastdisc = current + current = getnext(current) + else + break end end local lig = ligature.ligature @@ -880,12 +863,10 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip if stop then if trace_ligatures then local stopchar = getchar(stop) - -- head, start = toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound,hasmarks) - head, start = toligature(head,start,stop,lig,dataset,sequence,skiphash,false,hasmarks) + head, start = toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound,hasmarks) logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(lig)) else - -- head, start = toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound,hasmarks) - head, start = toligature(head,start,stop,lig,dataset,sequence,skiphash,false,hasmarks) + head, start = toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound,hasmarks) end else -- weird but happens (in some arabic font) @@ -895,12 +876,12 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(dataset,sequence),gref(startchar),gref(lig)) end end - return head, start, true, false + return head, start, true, discfound else -- weird but happens, pseudo ligatures ... just the components end end - return head, start, false, false + return head, start, false, discfound end function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection) @@ -939,8 +920,7 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,st end local format = step.format if format == "pair" then - local a = krn[1] - local b = krn[2] + local a, b = krn[1], krn[2] if a == true then -- zero elseif a then -- #a > 0 @@ -1290,14 +1270,6 @@ local function getmapping(dataset,sequence,currentlookup) end end -function chainprocs.gsub_remove(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) - if trace_chains then - logprocess("%s: removing character %s",cref(dataset,sequence,chainindex),gref(getchar(start))) - end - head, start = remove_node(head,start,true) - return head, getprev(start), true -end - function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) local mapping = currentlookup.mapping if mapping == nil then @@ -1408,7 +1380,7 @@ function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup if trace_multiples then logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement)) end - return multiple_glyphs(head,start,replacement,skiphash,dataset[1],stop) + return multiple_glyphs(head,start,replacement,skiphash,dataset[1]) end end return head, start, false @@ -1560,8 +1532,7 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm end local format = currentlookup.format if format == "pair" then - local a = krn[1] - local b = krn[2] + local a, b = krn[1], krn[2] if a == true then -- zero elseif a then @@ -2015,9 +1986,6 @@ local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck) logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind) end end - else - -- we skip but we could also delete as option .. what does an empty lookup actually mean - -- in opentype ... anyway, we could map it onto gsub_remove if needed end i = i + 1 if i > size or not start then @@ -2657,7 +2625,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s end end else - -- notmatchreplace[prev] = true -- not according to Kai + notmatchreplace[prev] = true -- new, for Kai to check end end prev = getprev(prev) @@ -2786,7 +2754,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s end end else - -- notmatchreplace[current] = true -- not according to Kai + notmatchreplace[current] = true -- new, for Kai to check end current = getnext(current) elseif id == glue_code then @@ -2834,9 +2802,6 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,s notmatchpre = { } notmatchpost = { } notmatchreplace = { } - -- notmatchpre = { a = 1, b = 1 } notmatchpre .a = nil notmatchpre .b = nil - -- notmatchpost = { a = 1, b = 1 } notmatchpost .a = nil notmatchpost .b = nil - -- notmatchreplace = { a = 1, b = 1 } notmatchreplace.a = nil notmatchreplace.b = nil end return head, start, done end @@ -3194,7 +3159,7 @@ local function testrun(disc,t_run,c_run,...) local d = d_replace > d_post and d_replace or d_post local head = getnext(disc) -- is: next local tail = head - for i=2,d do -- must start at 2 according to Kai + for i=1,d do local nx = getnext(tail) local id = getid(nx) if id == disc_code then @@ -3454,7 +3419,7 @@ local function k_run_single(sub,injection,last,font,attr,lookupcache,step,datase a = getattr(sub,0) end if not a or (a == attr) then - for n in nextnode, sub do -- only gpos + for n in traverse_nodes(sub) do -- only gpos if n == last then break end @@ -3619,7 +3584,7 @@ local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,datase a = getattr(sub,0) end if not a or (a == attr) then - for n in nextnode, sub do -- only gpos + for n in traverse_nodes(sub) do -- only gpos if n == last then break end @@ -3641,57 +3606,129 @@ local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,datase end end -local txtdirstate, pardirstate do -- this might change (no need for nxt in pardirstate) - - local getdirection = nuts.getdirection - local lefttoright = 0 - local righttoleft = 1 +-- to be checked, nowadays we probably can assume properly matched directions +-- so maybe we no longer need a stack + +-- local function txtdirstate(start,stack,top,rlparmode) +-- local dir = getdir(start) +-- local new = 1 +-- if dir == "+TRT" then +-- top = top + 1 +-- stack[top] = dir +-- new = -1 +-- elseif dir == "+TLT" then +-- top = top + 1 +-- stack[top] = dir +-- elseif dir == "-TRT" or dir == "-TLT" then +-- if top == 1 then +-- top = 0 +-- new = rlparmode +-- else +-- top = top - 1 +-- if stack[top] == "+TRT" then +-- new = -1 +-- end +-- end +-- else +-- new = rlparmode +-- end +-- return getnext(start), top, new +-- end +-- +-- local function pardirstate(start) +-- local dir = getdir(start) +-- local new = 0 +-- if dir == "TLT" then +-- new = 1 +-- elseif dir == "TRT" then +-- new = -1 +-- end +-- return getnext(start), new, new +-- end - txtdirstate = function(start,stack,top,rlparmode) - local dir, pop = getdirection(start) - if pop then - if top == 1 then - return 0, rlparmode +local function txtdirstate(start,stack,top,rlparmode) + local nxt = getnext(start) + local dir = getdir(start) + if dir == "+TRT" then + top = top + 1 + stack[top] = dir + return nxt, top, -1 + elseif dir == "+TLT" then + top = top + 1 + stack[top] = dir + return nxt, top, 1 + elseif dir == "-TRT" or dir == "-TLT" then + if top == 1 then + return nxt, 0, rlparmode + else + top = top - 1 + if stack[top] == "+TRT" then + return nxt, top, -1 else - top = top - 1 - if stack[top] == righttoleft then - return top, -1 - else - return top, 1 - end + return nxt, top, 1 end - elseif dir == lefttoright then - top = top + 1 - stack[top] = lefttoright - return top, 1 - elseif dir == righttoleft then - top = top + 1 - stack[top] = righttoleft - return top, -1 - else - return top, rlparmode end + else + return nxt, top, rlparmode end +end - pardirstate = function(start) - local dir = getdirection(start) - if dir == lefttoright then - return 1, 1 - elseif dir == righttoleft then - return -1, -1 - -- for old times sake we we handle strings too - elseif dir == "TLT" then - return 1, 1 - elseif dir == "TRT" then - return -1, -1 - else - return 0, 0 - end +local function pardirstate(start) + local nxt = getnext(start) + local dir = getdir(start) + if dir == "TLT" then + return nxt, 1, 1 + elseif dir == "TRT" then + return nxt, -1, -1 + else + return nxt, 0, 0 end - end --- These are non public helpers that can change without notice! +-- -- this will become: +-- +-- local getdirection = nuts.getdirection +-- +-- local function txtdirstate1(start,stack,top,rlparmode) +-- local nxt = getnext(start) +-- local dir, sub = getdirection(start) +-- if sub then +-- if top == 1 then +-- return nxt, 0, rlparmode +-- elseif dir < 2 then +-- top = top - 1 +-- if stack[top] == 1 then +-- return nxt, top, -1 +-- else +-- return nxt, top, 1 +-- end +-- else +-- return nxt, top, rlparmode +-- end +-- elseif dir == 1 then +-- top = top + 1 +-- stack[top] = 1 +-- return nxt, top, -1 +-- elseif dir == 0 then +-- top = top + 1 +-- stack[top] = 0 +-- return nxt, top, 1 +-- else +-- return nxt, top, rlparmode +-- end +-- end +-- +-- local function pardirstate1(start) +-- local nxt = getnext(start) +-- local dir = getdirection(start) +-- if dir == 0 then +-- return nxt, 1, 1 +-- elseif dir == 1 then +-- return nxt, -1, -1 +-- else +-- return nxt, 0, 0 +-- end +-- end otf.helpers = otf.helpers or { } otf.helpers.txtdirstate = txtdirstate @@ -3795,23 +3832,20 @@ do -- attr = false -- end + local head = tonut(head) + if trace_steps then checkstep(head) end - local initialrl = 0 - - if getid(head) == localpar_code and getsubtype(head) == 0 then - initialrl = pardirstate(head) - elseif direction == 1 or direction == "TRT" then - initialrl = -1 - end + local initialrl = direction == "TRT" and -1 or 0 + -- local initialrl = (direction == 1 or direction == "TRT") and -1 or 0 - -- local done = false + local done = false + -- local datasets = otf.dataset(tfmdata,font,attr) local datasets = otfdataset(tfmdata,font,attr) - local dirstack = { nil } -- could move outside function but we can have local runs + local dirstack = { } -- could move outside function but we can have local runs sweephead = { } - -- sweephead = { a = 1, b = 1 } sweephead.a = nil sweephead.b = nil -- Keeping track of the headnode is needed for devanagari. (I generalized it a bit -- so that multiple cases are also covered.) We could prepend a temp node. @@ -3838,9 +3872,9 @@ do -- are not frozen as we might extend or change this. Is this used at all apart from some -- experiments? local h, ok = handler(head,dataset,sequence,initialrl,font,attr) -- less arguments now - -- if ok then - -- done = true - -- end + if ok then + done = true + end if h and h ~= head then head = h end @@ -3873,7 +3907,7 @@ do local ok head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step) if ok then - -- done = true + done = true break end end @@ -3914,14 +3948,12 @@ do a = true end if a then - local ok, df - head, start, ok, df = handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step) - -- if ok then - -- done = true - -- end - if df then --- print("restart 1",typ) - elseif start then + local ok + head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step) + if ok then + done = true + end + if start then start = getnext(start) end else @@ -3944,20 +3976,18 @@ do else start, ok = comprun(start,c_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) end - -- if ok then - -- done = true - -- end + if ok then + done = true + end else start = getnext(start) end elseif id == math_code then start = getnext(end_of_math(start)) elseif id == dir_code then - topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode) - start = getnext(start) - -- elseif id == localpar_code then - -- rlparmode, rlmode = pardirstate(start) - -- start = getnext(start) + start, topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode) + elseif id == localpar_code then + start, rlparmode, rlmode = pardirstate(start) else start = getnext(start) end @@ -3981,7 +4011,6 @@ do a = true end if a then - local ok, df for i=m[1],m[2] do local step = steps[i] -- for i=1,#m do @@ -3990,12 +4019,10 @@ do local lookupmatch = lookupcache[char] if lookupmatch then -- we could move all code inline but that makes things even more unreadable --- local ok, df - head, start, ok, df = handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step) - if df then - break - elseif ok then - -- done = true + local ok + head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step) + if ok then + done = true break elseif not start then -- don't ask why ... shouldn't happen @@ -4003,9 +4030,7 @@ do end end end - if df then --- print("restart 2",typ) - elseif start then + if start then start = getnext(start) end else @@ -4028,20 +4053,18 @@ do else start, ok = comprun(start,c_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) end - -- if ok then - -- done = true - -- end + if ok then + done = true + end else start = getnext(start) end elseif id == math_code then start = getnext(end_of_math(start)) elseif id == dir_code then - topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode) - start = getnext(start) - -- elseif id == localpar_code then - -- rlparmode, rlmode = pardirstate(start) - -- start = getnext(start) + start, topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode) + elseif id == localpar_code then + start, rlparmode, rlmode = pardirstate(start) else start = getnext(start) end @@ -4056,12 +4079,12 @@ do end nesting = nesting - 1 + head = tonode(head) - -- return head, done - return head + return head, done end - -- This is not an official helper and used for tracing experiments. It can be changed as I like + -- This is not an official helpoer and used for tracing experiments. It can be changed as I like -- at any moment. At some point it might be used in a module that can help font development. function otf.datasetpositionprocessor(head,font,direction,dataset) @@ -4095,10 +4118,12 @@ do local steps = sequence.steps local nofsteps = sequence.nofsteps + local head = tonut(head) local done = false - local dirstack = { nil } -- could move outside function but we can have local runs (maybe a few more nils) + local dirstack = { } -- could move outside function but we can have local runs local start = head - local initialrl = (direction == 1 or direction == "TRT") and -1 or 0 + local initialrl = direction == "TRT" and -1 or 0 + -- local initialrl = (direction == 1 or direction == "TRT") and -1 or 0 local rlmode = initialrl local rlparmode = initialrl local topstack = 0 @@ -4148,17 +4173,15 @@ do elseif id == math_code then start = getnext(end_of_math(start)) elseif id == dir_code then - topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode) - start = getnext(start) - -- elseif id == localpar_code then - -- rlparmode, rlmode = pardirstate(start) - -- start = getnext(start) + start, topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode) + elseif id == localpar_code then + start, rlparmode, rlmode = pardirstate(start) else start = getnext(start) end end - return head + return tonode(head) -- , matches end -- end of experiment @@ -4170,26 +4193,9 @@ end local plugins = { } otf.plugins = plugins -local report = logs.reporter("fonts") - function otf.registerplugin(name,f) if type(name) == "string" and type(f) == "function" then plugins[name] = { name, f } - report() - report("plugin %a has been loaded, please be aware of possible side effects",name) - report() - if logs.pushtarget then - logs.pushtarget("log") - end - report("Plugins are not officially supported unless stated otherwise. This is because") - report("they bypass the regular font handling and therefore some features in ConTeXt") - report("(especially those related to fonts) might not work as expected or might not work") - report("at all. Some plugins are for testing and development only and might change") - report("whenever we feel the need for it.") - report() - if logs.poptarget then - logs.poptarget() - end end end |