diff options
Diffstat (limited to 'Master/texmf-dist/tex/luatex/lutabulartools/lutabulartools.lua')
-rw-r--r-- | Master/texmf-dist/tex/luatex/lutabulartools/lutabulartools.lua | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/luatex/lutabulartools/lutabulartools.lua b/Master/texmf-dist/tex/luatex/lutabulartools/lutabulartools.lua new file mode 100644 index 00000000000..40f916e3bc1 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/lutabulartools/lutabulartools.lua @@ -0,0 +1,287 @@ +--% Kale Ewasiuk (kalekje@gmail.com) +--% 2021-10-13 +--% +--% Copyright (C) 2021 Kale Ewasiuk +--% +--% Permission is hereby granted, free of charge, to any person obtaining a copy +--% of this software and associated documentation files (the "Software"), to deal +--% in the Software without restriction, including without limitation the rights +--% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +--% copies of the Software, and to permit persons to whom the Software is +--% furnished to do so, subject to the following conditions: +--% +--% The above copyright notice and this permission notice shall be included in +--% all copies or substantial portions of the Software. +--% +--% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +--% ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +--% TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +--% PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +--% SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +--% ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +--% ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +--% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +--% OR OTHER DEALINGS IN THE SOFTWARE. + +local ltt = {} + +--todo clean up the code, make some stuff local +--todo maybe add the penlight lua table to latex tabular? + +--integrate current cell +--todo check if S[] column cells work!!! +--todo might be smarter to just append this to tabular commands and read argument + +-- Initialize counter variable +ltt.NumTabCols = 0 +ltt.NumTabColsAbv = 0 -- num of tab columns if above 1 +ltt.TabColSpec = '' +ltt.TabColSpecAbv = '' -- tab column spec if above 1 +ltt.CurTabColAbv = '' -- current tab column spec if above 1 +ltt.TabColNum = 0 +ltt.NumBkts = 0 +ltt.NumTabColsMX = 0 + + +--todo re=enable +local glue_t, unset_t, tabskip_st = node.id'glue', node.id'unset' +local tabskip_st = table.swapped(node.subtypes'glue').tabskip +assert(tabskip_st) + + +function ltt.get_TabColNum() + local nest + for i = tex.nest.ptr, 1, -1 do + local tail = tex.nest[i].tail + if tail.id == glue_t and tail.subtype == tabskip_st then + nest = tex.nest[i] + break + end + end + if nest then + local col = 1 + for _, sub in node.traverse_id(unset_t, nest.head) do + col = col + sub + 1 + end + ltt.TabColNum = col + else + ltt.TabColNum = 1 + end + ltt.CurTabColAbv = ltt.TabColSpecAbv:sub(ltt.TabColNum,ltt.TabColNum) + ltt.NumTabColsMX = math.max(ltt.NumTabColsMX, ltt.TabColNum) -- a different way to calculate total cols + return ltt.TabColNum +end + + +function ltt.get_TabRowNum() + return tex.count['c@RowNumCnt'] -- access latex counter +end + +-- The next function computes the number of columns from +-- contents of string 'zz' +function ltt.calc_NumTabCols( zz ) + --help_wrt(zz, 'col spec OG') + -- -- NOT NEEDED: zz = zz:gsub ( "^.-(%b{}).-$", "%1" ) -- retain the first "{....}" substring + zz = zz:gsub ( "%*%s-{(%d-)}%s-(%b{})" , -- expand expressions such as "*{5}{l}" to "lllll" + function(y, z ) z = z:sub (2 , -2) return string.rep (z, y) end ) -- + zz = zz:gsub ( "%b{}" , "" ) -- omit all stuff in curly braces and square + zz = zz:gsub ( "%b[]" , "" ) + zz = zz:gsub ( "[@!|><%s%*\']" , "" ) -- some more characters to ignore + -- todo: any columns defined that break into more than one column should be expanded here + --help_wrt(zz, 'col spec CLEAN') + ltt.TabColSpec = zz -- stripped column spec with no {} or < + ltt.NumTabCols = string.len(ltt.TabColSpec) + if ltt.NumTabCols > 1 then + ltt.TabColSpecAbv = ltt.TabColSpec + ltt.NumTabColsAbv = ltt.NumTabCols + end +end + +--todo fix square brackets after letters, expand multiple +--calc_NumTabCols('ss') +--calc_NumTabCols('*{6}{s}') +--calc_NumTabCols('l*{6}{l}') +--calc_NumTabCols('lll') +--calc_NumTabCols('ll[]') +--calc_NumTabCols('ll[]*{6}{l}') +--calc_NumTabCols('*{6}{l}') +--calc_NumTabCols('y*{6}{sq}x') +--print(_TabColSpec.. '<---Column spec') + +--http://ctan.mirror.rafal.ca/macros/latex/contrib/multirow/multirow.pdf +--http://ctan.mirror.colo-serv.net/macros/latex/contrib/makecell/makecell.pdf +-- todo CONSIDER THIS +-- https://tex.stackexchange.com/questions/331716/newline-in-multirow-environment + + + +--todo +-- if p{} column, and multirow is 1, use {=} instead of {*} +-- but note, makecell will not work. So you may want to skip it.multicolumn +-- this case should be considered in this code. +-- for example: \multirow{2}{=} + +function ltt.MagicCell(s0,spec,mcspec,pre,content) + -- + local STR = '' + reset_bkt_cnt() + + local v, h, r, c, mrowsym, skipmakecell = ltt.parse_MagicCell_spec(spec) -- get v/h align, number rows/columns + + local mcspec = mcspec or '' + + h, mcspec, c = ltt.get_HColSpec(h, mcspec, c) -- infer horizontal alignment, num columns + + --help_wrt(_CurTabColAbv,'current column') + if s0 == _xTrue or (pl.List({'S', 'Q', 'L', 'R'}):contains(ltt.CurTabColAbv) -- special columns for SI + and c == '') then -- multicolumn cannot have {} around it todo test with siunitx, num rows, num columns + STR = STR .. '{' -- multirow and makcell must have {} around it S column is used + add_bkt_cnt() + end + + if c ~= '' then + STR = STR .. "\\multicolumn{"..c.."}{"..mcspec.."}{" + add_bkt_cnt() + end + + if r ~= '' then + STR = STR .."\\multirow["..v.."]{"..r.."}{"..mrowsym.."}{" -- optional arg here + add_bkt_cnt() + end + + if not skipmakecell then + if pre ~= '' then + STR = STR.."\\renewcommand{\\cellset}{"..pre.."}" + end + + STR = STR.."\\makecell[{"..v.."}{"..h.."}]{" + add_bkt_cnt() + else + content = content:gsub('\\\\', '\\newline') + end + + STR = STR..content..close_bkt_cnt() + --Troubleshooting + --help_wrt(STR..' <<< magic cell string') + tex.sprint(STR)--tex print the STR +end + + +function ltt.parse_MagicCell_spec(spec) + local mrowsym = '*' + local skipmakecell = false + if string.find(spec, '=') then + spec = spec:gsub('=', '') + mrowsym = '=' + skipmakecell = true + end + + spec = spec:lower():gsub('%s','') -- take lower case and remove + local vh, rc = spec:gextract('%a') -- extract characters + local v = vh:gfirst({'t', 'm', 'b'}) or 't' + local h = vh:gfirst({'l', 'c', 'r'}) or '' + v = v:gsub('m', 'c') + + local rc_ = (rc):split(',') + local c = rc_[1] or '' --num columns, width + local r = rc_[2] or '' --num rows, height + if c == '0' or c == '1' then c = '' end + if r == '0' or r == '1' then r = '' end + + return v, h, r, c, mrowsym, skipmakecell +end + + +ltt.TabColMapping = { -- horizontal cell alignment that multicolumn should use if () or [hori] not passed to func + l = 'l', + c = 'c', + r = 'r', + p = 'p', + P = 'c', + X = 'l', + Y = 'c', + Z = 'l', + N = 'c', + L = 'l', + R = 'r', + C = 'c', +} + +function ltt.get_HColSpec(h, mcspec, c) -- take horizontal alignment + -- c is num columns, h is horizontal alginment, + --Assumes _TabColNum was calculated previosly + ltt.get_TabColNum() + if c == '+' then -- fill row to end + c = tostring(ltt.NumTabColsAbv - ltt.TabColNum + 1) + end + if h == '' then -- if horizontal not provided, use declared column + h = ltt.TabColMapping[ltt.CurTabColAbv] or 'l' + end + if c ~= '' then -- only make new mcspec if column nums > 0 + if mcspec == '' then -- and if no mcspec was passed + mcspec = h + if ltt.TabColNum == 1 then -- if first column, auto detect padding + mcspec = '@{}'..mcspec + end + if (ltt.TabColNum + tonumber(c) - 1) == ltt.NumTabColsAbv then -- if end on last column + mcspec = mcspec..'@{}' + end + else -- if mcspec if given, extract the alignment + ltt.calc_NumTabCols(mcspec) + h = ltt.TabColSpec -- get 1 character column spec from mcspec and override h + end + end + return h, mcspec, c +end + + +-- midrule stuff + +function ltt.get_midrule_col(s) + if string.find(s, '+') then + s = s:gsub('+', '') + if (s == '') or (s == '0') then + s = 1 + end + s = tostring(ltt.NumTabColsAbv - tonumber(s) + 1) -- use number of tabular columns above 0, + end + return s +end + +--todo if comma present, create multiple according to spec. Also allow LR in [] + +--- midrule stuff --- + +function ltt.make1cmidrule(s, r, c, cmd) -- s=square r=round c=curly + cmd = '\\'..cmd + if s ~= '' then + cmd = cmd..'['..s..']' + end + if r ~= '' then + cmd = cmd..'('..r..')' + end + t = string.split(c, '-') + if t[2] == '' then + t[2] = '+' + end + if t[2] == nil then + t[2] = t[1] + end + c = ltt.get_midrule_col(t[1])..'-'..ltt.get_midrule_col(t[2]) + cmd = cmd..'{'..c..'}' + --help_wrt(cmd) + tex.print(cmd) +end + +function ltt.makecmidrules(s, r, c, cmd) + for k, c1 in pairs(string.split(c, ',')) do + r1, c2 = c1:gextract('%a') + if r1 == '' then -- if nothing passed in with the column + r1 = r -- set to the global value passed in round brackets + end + ltt.make1cmidrule(s, r1:strip(), c2:strip(), cmd) + end +end + + +return ltt -- lutabulartools
\ No newline at end of file |