aboutsummaryrefslogtreecommitdiffstats
path: root/util/human/io.lua
diff options
context:
space:
mode:
Diffstat (limited to 'util/human/io.lua')
-rw-r--r--util/human/io.lua90
1 files changed, 69 insertions, 21 deletions
diff --git a/util/human/io.lua b/util/human/io.lua
index 7d7dea97..d6112b3b 100644
--- a/util/human/io.lua
+++ b/util/human/io.lua
@@ -1,5 +1,6 @@
-local array = require "util.array";
-local utf8 = rawget(_G, "utf8") or require"util.encodings".utf8;
+local array = require "prosody.util.array";
+local pposix = require "prosody.util.pposix";
+local utf8 = rawget(_G, "utf8") or require"prosody.util.encodings".utf8;
local len = utf8.len or function(s)
local _, count = s:gsub("[%z\001-\127\194-\253][\128-\191]*", "");
return count;
@@ -8,7 +9,7 @@ end;
local function getchar(n)
local stty_ret = os.execute("stty raw -echo 2>/dev/null");
local ok, char;
- if stty_ret == true or stty_ret == 0 then
+ if stty_ret then
ok, char = pcall(io.read, n or 1);
os.execute("stty sane");
else
@@ -30,15 +31,12 @@ local function getline()
end
local function getpass()
- local stty_ret, _, status_code = os.execute("stty -echo 2>/dev/null");
- if status_code then -- COMPAT w/ Lua 5.1
- stty_ret = status_code;
- end
- if stty_ret ~= 0 then
+ local stty_ret = os.execute("stty -echo 2>/dev/null");
+ if not stty_ret then
io.write("\027[08m"); -- ANSI 'hidden' text attribute
end
local ok, pass = pcall(io.read, "*l");
- if stty_ret == 0 then
+ if stty_ret then
os.execute("stty sane");
else
io.write("\027[00m");
@@ -111,14 +109,30 @@ if utf8.len and utf8.offset then
end
end
+local function term_width(default)
+ local env_cols = tonumber(os.getenv "COLUMNS");
+ if env_cols then return env_cols; end
+ if not pposix.isatty(io.stdout) then
+ return default;
+ end
+ local stty = io.popen("stty -a");
+ if not stty then return default; end
+ local result = stty:read("*a");
+ if result then
+ result = result:match("%f[%w]columns[ =]*(%d+)");
+ end
+ stty:close();
+ return tonumber(result or default);
+end
+
local function ellipsis(s, width)
if len(s) <= width then return s; end
- if width == 1 then return "…"; end
+ if width <= 1 then return "…"; end
return utf8_cut(s, width - 1) .. "…";
end
local function new_table(col_specs, max_width)
- max_width = max_width or tonumber(os.getenv("COLUMNS")) or 80;
+ max_width = max_width or term_width(80);
local separator = " | ";
local widths = {};
@@ -127,21 +141,28 @@ local function new_table(col_specs, max_width)
-- Calculate width of fixed-size columns
for i = 1, #col_specs do
local width = col_specs[i].width or "0";
- if not(type(width) == "string" and width:sub(-1) == "%") then
+ if not (type(width) == "string" and width:match("[p%%]$")) then
local title = col_specs[i].title;
width = math.max(tonumber(width), title and (#title+1) or 0);
widths[i] = width;
free_width = free_width - width;
- if i > 1 then
- free_width = free_width - #separator;
- end
end
end
- -- Calculate width of %-based columns
+
+ -- Calculate width of proportional columns
+ local total_proportional_width = 0;
for i = 1, #col_specs do
if not widths[i] then
- local pc_width = tonumber((col_specs[i].width:gsub("%%$", "")));
- widths[i] = math.floor(free_width*(pc_width/100));
+ local width_spec = col_specs[i].width:match("([%d%.]+)[p%%]");
+ total_proportional_width = total_proportional_width + tonumber(width_spec);
+ end
+ end
+
+ for i = 1, #col_specs do
+ if not widths[i] then
+ local width_spec = col_specs[i].width:match("([%d%.]+)[p%%]");
+ local rel_width = tonumber(width_spec);
+ widths[i] = math.floor(free_width*(rel_width/total_proportional_width));
end
end
@@ -155,7 +176,7 @@ local function new_table(col_specs, max_width)
local width = widths[i];
local v = row[not titles and column.key or i];
if not titles and column.mapper then
- v = column.mapper(v, row);
+ v = column.mapper(v, row, width, column);
end
if v == nil then
v = column.default or "";
@@ -169,12 +190,36 @@ local function new_table(col_specs, max_width)
v = padright(v, width);
end
elseif len(v) > width then
- v = ellipsis(v, width);
+ v = (column.ellipsis or ellipsis)(v, width);
end
table.insert(output, v);
end
return table.concat(output, separator);
- end;
+ end, max_width;
+end
+
+local day = 86400;
+local multipliers = {
+ d = day, w = day * 7, mon = 31 * day, y = 365.2425 * day;
+ s = 1, min = 60, h = 3600, ho = 3600
+};
+
+local function parse_duration(duration_string)
+ local n, m = duration_string:lower():match("(%d+)%s*([smhdwy]?[io]?n?)");
+ if not n or not multipliers[m] then return nil; end
+ return tonumber(n) * ( multipliers[m] or 1 );
+end
+
+local multipliers_lax = setmetatable({
+ m = multipliers.mon;
+ mo = multipliers.mon;
+ mi = multipliers.min;
+}, { __index = multipliers });
+
+local function parse_duration_lax(duration_string)
+ local n, m = duration_string:lower():match("(%d+)%s*([smhdwy]?[io]?)");
+ if not n then return nil; end
+ return tonumber(n) * ( multipliers_lax[m] or 1 );
end
return {
@@ -187,6 +232,9 @@ return {
printf = printf;
padleft = padleft;
padright = padright;
+ term_width = term_width;
ellipsis = ellipsis;
table = new_table;
+ parse_duration = parse_duration;
+ parse_duration_lax = parse_duration_lax;
};