diff options
Diffstat (limited to 'xmake/core/base/text.lua')
| -rw-r--r-- | xmake/core/base/text.lua | 146 |
1 files changed, 123 insertions, 23 deletions
diff --git a/xmake/core/base/text.lua b/xmake/core/base/text.lua index dad69fc86..83b2a229a 100644 --- a/xmake/core/base/text.lua +++ b/xmake/core/base/text.lua @@ -25,7 +25,101 @@ local text = text or {} local string = require("base/string") local colors = require("base/colors") local math = require("base/math") -local dump = require("base/dump") +local table = require("base/table") + + +function text._iswbr(ch) + if not text._CHARWBR then + text._CHARWBR = { + [(' '):byte()] = 100, + [('\n'):byte()] = 100, + [('\t'):byte()] = 100, + [('\v'):byte()] = 100, + [('\f'):byte()] = 100, + [('\r'):byte()] = 100, + [('-'):byte()] = 90, + [(')'):byte()] = 50, + [(']'):byte()] = 50, + [('}'):byte()] = 50, + [(','):byte()] = 50, + [('='):byte()] = 40, + [('|'):byte()] = 40, + } + end + return text._CHARWBR[ch] or false +end + +function text._charwidth(ch) + if ch == 0x09 then + -- TAB + return 4 + elseif ch == 0x08 then + -- BS + return -1 + elseif ch <= 0x1F or ch == 0x7F then + -- other control chars + return 0 + else + return 1 + end +end + +function text._nextwbr(self, iter) + local ptr = iter.pos + 1 + local width = iter.width + local str = self.str + local e = self.j + + if ptr > e then + return nil + end + + while ptr <= e do + local byte = str:byte(ptr) + + -- ansi sequence, skip it + if byte == 27 and ptr + 2 <= e and str:byte(ptr + 1) == 91 then + local ansiend = false + ptr = ptr + 2 + while ptr <= e do + local b = str:byte(ptr) + if b == 109 then + ansiend = true + break + end + ptr = ptr + 1 + end + if not ansiend then + -- ansi sequence not finished in [i, j], no more wbr in the range + return nil + end + else + width = width + text._charwidth(byte) + local wbr = text._iswbr(byte) + if wbr then + return { pos = ptr, width = width, quality = wbr } + end + end + ptr = ptr + 1 + end + + -- wbr at end of string + return { pos = e, width = width, quality = 100 } +end + +function text._iterwbr(str, i, j, wordbreak) + if not i then + i = 1 + elseif i < 0 then + i = #str + 1 + i + end + if not j then + j = #str + elseif j < 0 then + j = #str + 1 + j + end + return text._nextwbr, { str = str, i = i, j = j, wordbreak = wordbreak }, { pos = i - 1, width = 0 } +end -- @see https://unicode.org/reports/tr14/ function text._lastwbr(str, width, wordbreak) @@ -38,21 +132,27 @@ function text._lastwbr(str, width, wordbreak) return width else - if str:sub(width + 1, width + 1):find("[%s]") then + if (text._iswbr(str:byte(width + 1)) or -1) >= 100 then -- exact break return width end - local range = str:sub(1, width) - local poss = range:reverse():find("[%s-]") - if poss then - return #range - poss + 1 + local wbr_candidate + for wbr in text._iterwbr(str, 1, #str, wordbreak) do + if not wbr_candidate then + -- not candidate yet? always use a wbr + wbr_candidate = wbr + elseif (wbr.quality >= wbr_candidate.quality or wbr.quality >= 80) and wbr.width <= width then + -- in range, replace with a higher quality wbr + wbr_candidate = wbr + end + if wbr.width > width then + break + end end - -- not found in range, try afterwards - poss = str:find("[%s-]", width + 1) - if poss then - return poss + if wbr_candidate then + return wbr_candidate.pos end -- not found in all str @@ -71,7 +171,7 @@ function text.wordwrap(str, width, opt) end local lines = tostring(str):split("\n", {plain = true, strict = true}) - local result = {} + local result = table.new(#lines, 0) local actual_width = 0 -- handle lines @@ -110,7 +210,7 @@ function text.wordwrap(str, width, opt) end function text._format_cell(cell, width, opt) - local result = {} + local result = table.new(#cell, 0) local max_width = 0 for _, v in ipairs(cell) do local lines, aw = text.wordwrap(tostring(v), width[2], opt) @@ -165,7 +265,7 @@ function text.table(data, opt) opt.patch_reset = false -- col ordered cells - local cols = {} + local cols = table.new(1, 0) local n_row = table.maxn(data) local n_col = 1 @@ -193,7 +293,7 @@ function text.table(data, opt) end local col = cols[j] if not col then - col = {} + col = table.new(n_row, 0) cols[j] = col end if cell then @@ -206,21 +306,21 @@ function text.table(data, opt) end -- load column options - data.width = data.width or {} - data.align = data.align or {} - data.style = data.style or {} + data.width = data.width or table.new(n_col, 0) + data.align = data.align or table.new(n_col, 0) + data.style = data.style or table.new(n_col, 0) local style = "" if type(data.style) == "string" then style = data.style - data.style = {} + data.style = table.new(n_col, 0) data.sep = style .. data.sep .. "${reset}" end local align = "l" if type(data.align) == "string" then align = data.align - data.align = {} + data.align = table.new(n_col, 0) end local sep = colors.translate(data.sep, opt) @@ -305,12 +405,12 @@ function text.table(data, opt) -- render cells -- row ordered cells - local rows = {} + local rows = table.new(n_row, 0) -- reorder for i = 1, n_row do local d_row = data[i] or {} - local row = {} + local row = table.new(n_col, 0) local line = 1 for j = 1, n_col do local cell = cols[j][i] @@ -333,11 +433,11 @@ function text.table(data, opt) rows[i] = row end - local results = {} + local results = table.new(n_row, 0) local reset = colors.translate("${reset}", opt) for i, row in ipairs(rows) do for l = 1, row.line do - local cells = {} + local cells = table.new(n_col, 0) local j = 1 while j <= n_col do |
