annotate util/human/io.lua @ 14229:ce31fdde0ad1 default tip

net.unbound: Simplify conditional
author Kim Alvefur <zash@zash.se>
date Sat, 13 Jun 2026 11:35:18 +0200
parents 565debd9c37a
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
12975
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12783
diff changeset
1 local array = require "prosody.util.array";
13210
8dbe693ded6b util.human.io: Fix stray 'stty' error by only querying width of real ttys
Kim Alvefur <zash@zash.se>
parents: 13199
diff changeset
2 local pposix = require "prosody.util.pposix";
12975
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12783
diff changeset
3 local utf8 = rawget(_G, "utf8") or require"prosody.util.encodings".utf8;
11896
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
4 local len = utf8.len or function(s)
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
5 local _, count = s:gsub("[%z\001-\127\194-\253][\128-\191]*", "");
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
6 return count;
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
7 end;
10894
d15a4284fdf8 util.human.io: table: Return title row when no row data passed
Matthew Wild <mwild1@gmail.com>
parents: 10893
diff changeset
8
10870
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
9 local function getchar(n)
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
10 local stty_ret = os.execute("stty raw -echo 2>/dev/null");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
11 local ok, char;
12783
d513e4bd4928 util.human.io: Fix handling of os.execute() return values in Lua 5.2+
Kim Alvefur <zash@zash.se>
parents: 12573
diff changeset
12 if stty_ret then
10870
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
13 ok, char = pcall(io.read, n or 1);
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
14 os.execute("stty sane");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
15 else
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
16 ok, char = pcall(io.read, "*l");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
17 if ok then
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
18 char = char:sub(1, n or 1);
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
19 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
20 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
21 if ok then
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
22 return char;
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
23 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
24 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
25
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
26 local function getline()
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
27 local ok, line = pcall(io.read, "*l");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
28 if ok then
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
29 return line;
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
30 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
31 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
32
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
33 local function getpass()
12573
0f4feaf9ca64 util: Remove various Lua 5.1 compatibility hacks
Kim Alvefur <zash@zash.se>
parents: 11897
diff changeset
34 local stty_ret = os.execute("stty -echo 2>/dev/null");
12783
d513e4bd4928 util.human.io: Fix handling of os.execute() return values in Lua 5.2+
Kim Alvefur <zash@zash.se>
parents: 12573
diff changeset
35 if not stty_ret then
10870
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
36 io.write("\027[08m"); -- ANSI 'hidden' text attribute
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
37 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
38 local ok, pass = pcall(io.read, "*l");
12783
d513e4bd4928 util.human.io: Fix handling of os.execute() return values in Lua 5.2+
Kim Alvefur <zash@zash.se>
parents: 12573
diff changeset
39 if stty_ret then
10870
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
40 os.execute("stty sane");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
41 else
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
42 io.write("\027[00m");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
43 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
44 io.write("\n");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
45 if ok then
14119
519c16c2eb21 util.human.io: Trim any trailing newline from password entry
Matthew Wild <mwild1@gmail.com>
parents: 13367
diff changeset
46 return (pass:gsub("\n$", ""));
10870
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
47 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
48 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
49
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
50 local function show_yesno(prompt)
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
51 io.write(prompt, " ");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
52 local choice = getchar():lower();
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
53 io.write("\n");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
54 if not choice:match("%a") then
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
55 choice = prompt:match("%[.-(%U).-%]$");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
56 if not choice then return nil; end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
57 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
58 return (choice == "y");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
59 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
60
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
61 local function read_password()
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
62 local password;
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
63 while true do
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
64 io.write("Enter new password: ");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
65 password = getpass();
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
66 if not password then
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
67 print("No password - cancelled");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
68 return;
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
69 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
70 io.write("Retype new password: ");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
71 if getpass() ~= password then
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
72 if not show_yesno [=[Passwords did not match, try again? [Y/n]]=] then
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
73 return;
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
74 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
75 else
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
76 break;
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
77 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
78 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
79 return password;
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
80 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
81
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
82 local function show_prompt(prompt)
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
83 io.write(prompt, " ");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
84 local line = getline();
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
85 line = line and line:gsub("\n$","");
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
86 return (line and #line > 0) and line or nil;
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
87 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
88
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
89 local function printf(fmt, ...)
10872
a3f3f42736f2 util.human.io: Fix variable name [luacheck]
Matthew Wild <mwild1@gmail.com>
parents: 10870
diff changeset
90 print(fmt:format(...));
10870
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
91 end
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
92
10891
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
93 local function padright(s, width)
11897
e84ea5b58b29 util.human.io: Use UTF-8-aware length check in padding functions
Kim Alvefur <zash@zash.se>
parents: 11896
diff changeset
94 return s..string.rep(" ", width-len(s));
10891
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
95 end
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
96
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
97 local function padleft(s, width)
11897
e84ea5b58b29 util.human.io: Use UTF-8-aware length check in padding functions
Kim Alvefur <zash@zash.se>
parents: 11896
diff changeset
98 return string.rep(" ", width-len(s))..s;
10891
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
99 end
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
100
11896
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
101 local pat = "[%z\001-\127\194-\253][\128-\191]*";
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
102 local function utf8_cut(s, pos)
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
103 return s:match("^"..pat:rep(pos)) or s;
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
104 end
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
105
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
106 if utf8.len and utf8.offset then
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
107 function utf8_cut(s, pos)
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
108 return s:sub(1, utf8.offset(s, pos+1)-1);
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
109 end
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
110 end
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
111
13044
5bd272095388 util.human.io: Add term_width() method to discover the terminal width
Matthew Wild <mwild1@gmail.com>
parents: 13040
diff changeset
112 local function term_width(default)
13051
164c2787901a util.human.io: Coerce $COLUMNS to number
Kim Alvefur <zash@zash.se>
parents: 13049
diff changeset
113 local env_cols = tonumber(os.getenv "COLUMNS");
13047
d939bf469057 util.human.io: Prefer using the $COLUMNS environment variable if set (by readline)
Kim Alvefur <zash@zash.se>
parents: 13045
diff changeset
114 if env_cols then return env_cols; end
13210
8dbe693ded6b util.human.io: Fix stray 'stty' error by only querying width of real ttys
Kim Alvefur <zash@zash.se>
parents: 13199
diff changeset
115 if not pposix.isatty(io.stdout) then
8dbe693ded6b util.human.io: Fix stray 'stty' error by only querying width of real ttys
Kim Alvefur <zash@zash.se>
parents: 13199
diff changeset
116 return default;
8dbe693ded6b util.human.io: Fix stray 'stty' error by only querying width of real ttys
Kim Alvefur <zash@zash.se>
parents: 13199
diff changeset
117 end
13044
5bd272095388 util.human.io: Add term_width() method to discover the terminal width
Matthew Wild <mwild1@gmail.com>
parents: 13040
diff changeset
118 local stty = io.popen("stty -a");
5bd272095388 util.human.io: Add term_width() method to discover the terminal width
Matthew Wild <mwild1@gmail.com>
parents: 13040
diff changeset
119 if not stty then return default; end
5bd272095388 util.human.io: Add term_width() method to discover the terminal width
Matthew Wild <mwild1@gmail.com>
parents: 13040
diff changeset
120 local result = stty:read("*a");
5bd272095388 util.human.io: Add term_width() method to discover the terminal width
Matthew Wild <mwild1@gmail.com>
parents: 13040
diff changeset
121 if result then
5bd272095388 util.human.io: Add term_width() method to discover the terminal width
Matthew Wild <mwild1@gmail.com>
parents: 13040
diff changeset
122 result = result:match("%f[%w]columns[ =]*(%d+)");
5bd272095388 util.human.io: Add term_width() method to discover the terminal width
Matthew Wild <mwild1@gmail.com>
parents: 13040
diff changeset
123 end
5bd272095388 util.human.io: Add term_width() method to discover the terminal width
Matthew Wild <mwild1@gmail.com>
parents: 13040
diff changeset
124 stty:close();
5bd272095388 util.human.io: Add term_width() method to discover the terminal width
Matthew Wild <mwild1@gmail.com>
parents: 13040
diff changeset
125 return tonumber(result or default);
5bd272095388 util.human.io: Add term_width() method to discover the terminal width
Matthew Wild <mwild1@gmail.com>
parents: 13040
diff changeset
126 end
5bd272095388 util.human.io: Add term_width() method to discover the terminal width
Matthew Wild <mwild1@gmail.com>
parents: 13040
diff changeset
127
11894
57106c61d104 util.human.io: Factor out ellipsis function
Kim Alvefur <zash@zash.se>
parents: 11893
diff changeset
128 local function ellipsis(s, width)
11896
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
129 if len(s) <= width then return s; end
13067
386ca97bec5b util.human.io: Fix error with ellipsis to negative length
Kim Alvefur <zash@zash.se>
parents: 13054
diff changeset
130 if width <= 1 then return "…"; end
11896
93e9f7ae2f9b util.human.io: Fix cutting of UTF-8 into pieces
Kim Alvefur <zash@zash.se>
parents: 11895
diff changeset
131 return utf8_cut(s, width - 1) .. "…";
11894
57106c61d104 util.human.io: Factor out ellipsis function
Kim Alvefur <zash@zash.se>
parents: 11893
diff changeset
132 end
57106c61d104 util.human.io: Factor out ellipsis function
Kim Alvefur <zash@zash.se>
parents: 11893
diff changeset
133
13935
6a493e41c2cc util.human.io: Factor out column width calculation
Kim Alvefur <zash@zash.se>
parents: 13367
diff changeset
134 local function calculate_column_widths(col_specs, separator, max_width)
10891
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
135 local widths = {};
10907
6af28c756752 util.human.io: Draw a separator between columns
Kim Alvefur <zash@zash.se>
parents: 10904
diff changeset
136 local total_width = max_width - #separator * (#col_specs-1);
10891
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
137 local free_width = total_width;
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
138 -- Calculate width of fixed-size columns
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
139 for i = 1, #col_specs do
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
140 local width = col_specs[i].width or "0";
13030
1f89a2a9f532 util.human.io: Support for dynamic "proportional" columns
Matthew Wild <mwild1@gmail.com>
parents: 12975
diff changeset
141 if not (type(width) == "string" and width:match("[p%%]$")) then
10891
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
142 local title = col_specs[i].title;
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
143 width = math.max(tonumber(width), title and (#title+1) or 0);
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
144 widths[i] = width;
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
145 free_width = free_width - width;
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
146 end
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
147 end
13030
1f89a2a9f532 util.human.io: Support for dynamic "proportional" columns
Matthew Wild <mwild1@gmail.com>
parents: 12975
diff changeset
148
1f89a2a9f532 util.human.io: Support for dynamic "proportional" columns
Matthew Wild <mwild1@gmail.com>
parents: 12975
diff changeset
149 -- Calculate width of proportional columns
1f89a2a9f532 util.human.io: Support for dynamic "proportional" columns
Matthew Wild <mwild1@gmail.com>
parents: 12975
diff changeset
150 local total_proportional_width = 0;
10891
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
151 for i = 1, #col_specs do
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
152 if not widths[i] then
13031
1023c3faffac util.human.io: Fix pattern to support fractional proportions
Matthew Wild <mwild1@gmail.com>
parents: 13030
diff changeset
153 local width_spec = col_specs[i].width:match("([%d%.]+)[p%%]");
13030
1f89a2a9f532 util.human.io: Support for dynamic "proportional" columns
Matthew Wild <mwild1@gmail.com>
parents: 12975
diff changeset
154 total_proportional_width = total_proportional_width + tonumber(width_spec);
1f89a2a9f532 util.human.io: Support for dynamic "proportional" columns
Matthew Wild <mwild1@gmail.com>
parents: 12975
diff changeset
155 end
1f89a2a9f532 util.human.io: Support for dynamic "proportional" columns
Matthew Wild <mwild1@gmail.com>
parents: 12975
diff changeset
156 end
1f89a2a9f532 util.human.io: Support for dynamic "proportional" columns
Matthew Wild <mwild1@gmail.com>
parents: 12975
diff changeset
157
1f89a2a9f532 util.human.io: Support for dynamic "proportional" columns
Matthew Wild <mwild1@gmail.com>
parents: 12975
diff changeset
158 for i = 1, #col_specs do
1f89a2a9f532 util.human.io: Support for dynamic "proportional" columns
Matthew Wild <mwild1@gmail.com>
parents: 12975
diff changeset
159 if not widths[i] then
13031
1023c3faffac util.human.io: Fix pattern to support fractional proportions
Matthew Wild <mwild1@gmail.com>
parents: 13030
diff changeset
160 local width_spec = col_specs[i].width:match("([%d%.]+)[p%%]");
13030
1f89a2a9f532 util.human.io: Support for dynamic "proportional" columns
Matthew Wild <mwild1@gmail.com>
parents: 12975
diff changeset
161 local rel_width = tonumber(width_spec);
1f89a2a9f532 util.human.io: Support for dynamic "proportional" columns
Matthew Wild <mwild1@gmail.com>
parents: 12975
diff changeset
162 widths[i] = math.floor(free_width*(rel_width/total_proportional_width));
10891
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
163 end
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
164 end
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
165
13935
6a493e41c2cc util.human.io: Factor out column width calculation
Kim Alvefur <zash@zash.se>
parents: 13367
diff changeset
166 return widths;
6a493e41c2cc util.human.io: Factor out column width calculation
Kim Alvefur <zash@zash.se>
parents: 13367
diff changeset
167 end
6a493e41c2cc util.human.io: Factor out column width calculation
Kim Alvefur <zash@zash.se>
parents: 13367
diff changeset
168
13936
4f1b6f6e68c0 util.human.io: Allow specifying a different column separator
Kim Alvefur <zash@zash.se>
parents: 13935
diff changeset
169 local function new_table(col_specs, max_width, separator)
4f1b6f6e68c0 util.human.io: Allow specifying a different column separator
Kim Alvefur <zash@zash.se>
parents: 13935
diff changeset
170 separator = separator or " | ";
13935
6a493e41c2cc util.human.io: Factor out column width calculation
Kim Alvefur <zash@zash.se>
parents: 13367
diff changeset
171
13937
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
172 local widths;
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
173 if max_width ~= -1 then
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
174 max_width = max_width or term_width(80);
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
175 widths = calculate_column_widths(col_specs, separator, max_width)
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
176 else
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
177 widths = {};
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
178 end
13935
6a493e41c2cc util.human.io: Factor out column width calculation
Kim Alvefur <zash@zash.se>
parents: 13367
diff changeset
179
10893
a256044c1d12 util.human.io: table: switch row function to simply returning prepared row string
Matthew Wild <mwild1@gmail.com>
parents: 10891
diff changeset
180 return function (row)
10896
c7a0eab27165 util.human.io: table: Fix title printing when columns use named keys
Matthew Wild <mwild1@gmail.com>
parents: 10894
diff changeset
181 local titles;
10894
d15a4284fdf8 util.human.io: table: Return title row when no row data passed
Matthew Wild <mwild1@gmail.com>
parents: 10893
diff changeset
182 if not row then
10896
c7a0eab27165 util.human.io: table: Fix title printing when columns use named keys
Matthew Wild <mwild1@gmail.com>
parents: 10894
diff changeset
183 titles, row = true, array.pluck(col_specs, "title", "");
10894
d15a4284fdf8 util.human.io: table: Return title row when no row data passed
Matthew Wild <mwild1@gmail.com>
parents: 10893
diff changeset
184 end
10893
a256044c1d12 util.human.io: table: switch row function to simply returning prepared row string
Matthew Wild <mwild1@gmail.com>
parents: 10891
diff changeset
185 local output = {};
10891
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
186 for i, column in ipairs(col_specs) do
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
187 local width = widths[i];
11892
e712133b4de1 util.human.io: Pass nil to cell mapper to signal missing value
Kim Alvefur <zash@zash.se>
parents: 10917
diff changeset
188 local v = row[not titles and column.key or i];
e712133b4de1 util.human.io: Pass nil to cell mapper to signal missing value
Kim Alvefur <zash@zash.se>
parents: 10917
diff changeset
189 if not titles and column.mapper then
13040
0cbe400ebab4 util.human.io: Pass the whole column definition to mapper function
Kim Alvefur <zash@zash.se>
parents: 13039
diff changeset
190 v = column.mapper(v, row, width, column);
11892
e712133b4de1 util.human.io: Pass nil to cell mapper to signal missing value
Kim Alvefur <zash@zash.se>
parents: 10917
diff changeset
191 end
e712133b4de1 util.human.io: Pass nil to cell mapper to signal missing value
Kim Alvefur <zash@zash.se>
parents: 10917
diff changeset
192 if v == nil then
11893
afef1e170de7 util.human.io: Support specifying column defaults in tables
Kim Alvefur <zash@zash.se>
parents: 11892
diff changeset
193 v = column.default or "";
11892
e712133b4de1 util.human.io: Pass nil to cell mapper to signal missing value
Kim Alvefur <zash@zash.se>
parents: 10917
diff changeset
194 else
e712133b4de1 util.human.io: Pass nil to cell mapper to signal missing value
Kim Alvefur <zash@zash.se>
parents: 10917
diff changeset
195 v = tostring(v);
e712133b4de1 util.human.io: Pass nil to cell mapper to signal missing value
Kim Alvefur <zash@zash.se>
parents: 10917
diff changeset
196 end
13937
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
197 if width then
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
198 if len(v) < width then
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
199 if column.align == "right" then
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
200 v = padleft(v, width);
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
201 else
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
202 v = padright(v, width);
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
203 end
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
204 elseif len(v) > width then
cfe3e85e715f util.human.io: Support disabling column widths
Kim Alvefur <zash@zash.se>
parents: 13936
diff changeset
205 v = (column.ellipsis or ellipsis)(v, width);
10891
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
206 end
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
207 end
10893
a256044c1d12 util.human.io: table: switch row function to simply returning prepared row string
Matthew Wild <mwild1@gmail.com>
parents: 10891
diff changeset
208 table.insert(output, v);
10891
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
209 end
10907
6af28c756752 util.human.io: Draw a separator between columns
Kim Alvefur <zash@zash.se>
parents: 10904
diff changeset
210 return table.concat(output, separator);
13048
946442df65d3 util.human.io: table: Return determined width as a second result
Matthew Wild <mwild1@gmail.com>
parents: 13047
diff changeset
211 end, max_width;
10891
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
212 end
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
213
13054
f4d7fe919969 util.human.io: Add parse_duration() method to parse a duration string
Matthew Wild <mwild1@gmail.com>
parents: 13051
diff changeset
214 local day = 86400;
f4d7fe919969 util.human.io: Add parse_duration() method to parse a duration string
Matthew Wild <mwild1@gmail.com>
parents: 13051
diff changeset
215 local multipliers = {
13367
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
216 d = day, w = day * 7, mon = 31 * day, y = 365.2425 * day;
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
217 s = 1, min = 60, h = 3600, ho = 3600
13054
f4d7fe919969 util.human.io: Add parse_duration() method to parse a duration string
Matthew Wild <mwild1@gmail.com>
parents: 13051
diff changeset
218 };
13367
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
219
13054
f4d7fe919969 util.human.io: Add parse_duration() method to parse a duration string
Matthew Wild <mwild1@gmail.com>
parents: 13051
diff changeset
220 local function parse_duration(duration_string)
13367
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
221 local n, m = duration_string:lower():match("(%d+)%s*([smhdwy]?[io]?n?)");
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
222 if not n or not multipliers[m] then return nil; end
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
223 return tonumber(n) * ( multipliers[m] or 1 );
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
224 end
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
225
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
226 local multipliers_lax = setmetatable({
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
227 m = multipliers.mon;
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
228 mo = multipliers.mon;
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
229 mi = multipliers.min;
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
230 }, { __index = multipliers });
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
231
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
232 local function parse_duration_lax(duration_string)
13199
278920294dfe util.human.io: Fix pattern in parse_duration() to cover all used letters
Kim Alvefur <zash@zash.se>
parents: 13068
diff changeset
233 local n, m = duration_string:lower():match("(%d+)%s*([smhdwy]?[io]?)");
13054
f4d7fe919969 util.human.io: Add parse_duration() method to parse a duration string
Matthew Wild <mwild1@gmail.com>
parents: 13051
diff changeset
234 if not n then return nil; end
13367
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
235 return tonumber(n) * ( multipliers_lax[m] or 1 );
13054
f4d7fe919969 util.human.io: Add parse_duration() method to parse a duration string
Matthew Wild <mwild1@gmail.com>
parents: 13051
diff changeset
236 end
f4d7fe919969 util.human.io: Add parse_duration() method to parse a duration string
Matthew Wild <mwild1@gmail.com>
parents: 13051
diff changeset
237
14217
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
238 -- Compares simple version strings (numeric only, not semver compatible)
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
239 -- (can be passed to table.sort)
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
240 local function simple_version_compare(a, b)
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
241 local a_f, a_s, a_part = a:gmatch("%d+");
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
242 local b_f, b_s, b_part = b:gmatch("%d+");
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
243
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
244 a_part = a_f(a_s, a_part);
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
245 b_part = b_f(b_s, b_part);
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
246
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
247 while a_part and b_part do
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
248 local an, bn = tonumber(a_part), tonumber(b_part);
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
249 if an ~= bn then
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
250 return an < bn;
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
251 end
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
252 a_part = a_f(a_s, a_part);
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
253 b_part = b_f(b_s, b_part);
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
254 end
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
255
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
256 -- return true (a is lower) if b is exhausted
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
257 -- otherwise, they are equal or b is longer/greater (-> return false)
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
258 return b_part ~= nil;
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
259 end
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
260
10870
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
261 return {
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
262 getchar = getchar;
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
263 getline = getline;
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
264 getpass = getpass;
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
265 show_yesno = show_yesno;
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
266 read_password = read_password;
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
267 show_prompt = show_prompt;
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
268 printf = printf;
10891
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
269 padleft = padleft;
8d47858805c9 util.human.io: Add padleft, padright and a table printing function
Matthew Wild <mwild1@gmail.com>
parents: 10872
diff changeset
270 padright = padright;
13044
5bd272095388 util.human.io: Add term_width() method to discover the terminal width
Matthew Wild <mwild1@gmail.com>
parents: 13040
diff changeset
271 term_width = term_width;
11894
57106c61d104 util.human.io: Factor out ellipsis function
Kim Alvefur <zash@zash.se>
parents: 11893
diff changeset
272 ellipsis = ellipsis;
10893
a256044c1d12 util.human.io: table: switch row function to simply returning prepared row string
Matthew Wild <mwild1@gmail.com>
parents: 10891
diff changeset
273 table = new_table;
13054
f4d7fe919969 util.human.io: Add parse_duration() method to parse a duration string
Matthew Wild <mwild1@gmail.com>
parents: 13051
diff changeset
274 parse_duration = parse_duration;
13367
82513890a1d8 util.human.io: Don't accept ambiguous durations by default
Matthew Wild <mwild1@gmail.com>
parents: 13210
diff changeset
275 parse_duration_lax = parse_duration_lax;
14217
7eb0e47418ab util.human.io: Add simple version comparison
Matthew Wild <mwild1@gmail.com>
parents: 14119
diff changeset
276 simple_version_compare = simple_version_compare;
10870
3f1889608f3e util.human.io: New central place for UI helpers
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
277 };