Software /
code /
prosody
Comparison
util/human/io.lua @ 11120:b2331f3dfeea
Merge 0.11->trunk
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Wed, 30 Sep 2020 09:50:33 +0100 |
parent | 10917:1eb83bc6f706 |
child | 11892:e712133b4de1 |
comparison
equal
deleted
inserted
replaced
11119:68df52bf08d5 | 11120:b2331f3dfeea |
---|---|
1 local array = require "util.array"; | |
2 | |
3 local function getchar(n) | |
4 local stty_ret = os.execute("stty raw -echo 2>/dev/null"); | |
5 local ok, char; | |
6 if stty_ret == true or stty_ret == 0 then | |
7 ok, char = pcall(io.read, n or 1); | |
8 os.execute("stty sane"); | |
9 else | |
10 ok, char = pcall(io.read, "*l"); | |
11 if ok then | |
12 char = char:sub(1, n or 1); | |
13 end | |
14 end | |
15 if ok then | |
16 return char; | |
17 end | |
18 end | |
19 | |
20 local function getline() | |
21 local ok, line = pcall(io.read, "*l"); | |
22 if ok then | |
23 return line; | |
24 end | |
25 end | |
26 | |
27 local function getpass() | |
28 local stty_ret, _, status_code = os.execute("stty -echo 2>/dev/null"); | |
29 if status_code then -- COMPAT w/ Lua 5.1 | |
30 stty_ret = status_code; | |
31 end | |
32 if stty_ret ~= 0 then | |
33 io.write("\027[08m"); -- ANSI 'hidden' text attribute | |
34 end | |
35 local ok, pass = pcall(io.read, "*l"); | |
36 if stty_ret == 0 then | |
37 os.execute("stty sane"); | |
38 else | |
39 io.write("\027[00m"); | |
40 end | |
41 io.write("\n"); | |
42 if ok then | |
43 return pass; | |
44 end | |
45 end | |
46 | |
47 local function show_yesno(prompt) | |
48 io.write(prompt, " "); | |
49 local choice = getchar():lower(); | |
50 io.write("\n"); | |
51 if not choice:match("%a") then | |
52 choice = prompt:match("%[.-(%U).-%]$"); | |
53 if not choice then return nil; end | |
54 end | |
55 return (choice == "y"); | |
56 end | |
57 | |
58 local function read_password() | |
59 local password; | |
60 while true do | |
61 io.write("Enter new password: "); | |
62 password = getpass(); | |
63 if not password then | |
64 print("No password - cancelled"); | |
65 return; | |
66 end | |
67 io.write("Retype new password: "); | |
68 if getpass() ~= password then | |
69 if not show_yesno [=[Passwords did not match, try again? [Y/n]]=] then | |
70 return; | |
71 end | |
72 else | |
73 break; | |
74 end | |
75 end | |
76 return password; | |
77 end | |
78 | |
79 local function show_prompt(prompt) | |
80 io.write(prompt, " "); | |
81 local line = getline(); | |
82 line = line and line:gsub("\n$",""); | |
83 return (line and #line > 0) and line or nil; | |
84 end | |
85 | |
86 local function printf(fmt, ...) | |
87 print(fmt:format(...)); | |
88 end | |
89 | |
90 local function padright(s, width) | |
91 return s..string.rep(" ", width-#s); | |
92 end | |
93 | |
94 local function padleft(s, width) | |
95 return string.rep(" ", width-#s)..s; | |
96 end | |
97 | |
98 local function new_table(col_specs, max_width) | |
99 max_width = max_width or tonumber(os.getenv("COLUMNS")) or 80; | |
100 local separator = " | "; | |
101 | |
102 local widths = {}; | |
103 local total_width = max_width - #separator * (#col_specs-1); | |
104 local free_width = total_width; | |
105 -- Calculate width of fixed-size columns | |
106 for i = 1, #col_specs do | |
107 local width = col_specs[i].width or "0"; | |
108 if not(type(width) == "string" and width:sub(-1) == "%") then | |
109 local title = col_specs[i].title; | |
110 width = math.max(tonumber(width), title and (#title+1) or 0); | |
111 widths[i] = width; | |
112 free_width = free_width - width; | |
113 if i > 1 then | |
114 free_width = free_width - #separator; | |
115 end | |
116 end | |
117 end | |
118 -- Calculate width of %-based columns | |
119 for i = 1, #col_specs do | |
120 if not widths[i] then | |
121 local pc_width = tonumber((col_specs[i].width:gsub("%%$", ""))); | |
122 widths[i] = math.floor(free_width*(pc_width/100)); | |
123 end | |
124 end | |
125 | |
126 return function (row) | |
127 local titles; | |
128 if not row then | |
129 titles, row = true, array.pluck(col_specs, "title", ""); | |
130 end | |
131 local output = {}; | |
132 for i, column in ipairs(col_specs) do | |
133 local width = widths[i]; | |
134 local v = (not titles and column.mapper or tostring)(row[not titles and column.key or i] or "", row); | |
135 if #v < width then | |
136 if column.align == "right" then | |
137 v = padleft(v, width); | |
138 else | |
139 v = padright(v, width); | |
140 end | |
141 elseif #v > width then | |
142 v = v:sub(1, width-1) .. "…"; | |
143 end | |
144 table.insert(output, v); | |
145 end | |
146 return table.concat(output, separator); | |
147 end; | |
148 end | |
149 | |
150 return { | |
151 getchar = getchar; | |
152 getline = getline; | |
153 getpass = getpass; | |
154 show_yesno = show_yesno; | |
155 read_password = read_password; | |
156 show_prompt = show_prompt; | |
157 printf = printf; | |
158 padleft = padleft; | |
159 padright = padright; | |
160 table = new_table; | |
161 }; |