summaryrefslogtreecommitdiff
path: root/xmake/core/base/text.lua
diff options
context:
space:
mode:
Diffstat (limited to 'xmake/core/base/text.lua')
-rw-r--r--xmake/core/base/text.lua146
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