term 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/lib/term.rb +21 -0
- data/lib/term/bell.rb +14 -0
- data/lib/term/checkbox.rb +85 -0
- data/lib/term/code.rb +24 -0
- data/lib/term/color.rb +252 -0
- data/lib/term/confirm.rb +64 -0
- data/lib/term/cursor.rb +177 -0
- data/lib/term/font.rb +23 -0
- data/lib/term/input.rb +42 -0
- data/lib/term/password.rb +63 -0
- data/lib/term/process_bar.rb +24 -0
- data/lib/term/qrcode.rb +15 -0
- data/lib/term/redio.rb +68 -0
- data/lib/term/style.rb +126 -0
- data/lib/term/table.rb +76 -0
- data/lib/term/version.rb +6 -0
- data/lib/term/window.rb +50 -0
- metadata +245 -0
data/lib/term/confirm.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# cording: utf-8
|
2
|
+
|
3
|
+
require 'term/redio'
|
4
|
+
|
5
|
+
require 'term/color'
|
6
|
+
|
7
|
+
# @author {mailto:cuihaiqin@gmail.com cuihq}
|
8
|
+
class String
|
9
|
+
|
10
|
+
def ok?
|
11
|
+
print "#{self}? ".green
|
12
|
+
@begin_confirm_pos = IO.hide.pos
|
13
|
+
process_confirm_input
|
14
|
+
IO.show
|
15
|
+
@res
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# print confirm.
|
21
|
+
def print_confirm(confirm, run)
|
22
|
+
IO.to @begin_confirm_pos
|
23
|
+
if @res = confirm
|
24
|
+
print '✔'.red
|
25
|
+
print ' ✖' if run
|
26
|
+
else
|
27
|
+
print '✔ ' if run
|
28
|
+
print '✖'.red
|
29
|
+
end
|
30
|
+
@confirm_loop = run
|
31
|
+
end
|
32
|
+
|
33
|
+
# process confirm input confirm event.
|
34
|
+
def process_confirm_input
|
35
|
+
print_confirm(true, true)
|
36
|
+
@confirm_loop = true
|
37
|
+
while @confirm_loop
|
38
|
+
input = IO.input
|
39
|
+
process_confirm_mouse_click input
|
40
|
+
process_confirm_keyboard_input input[:key]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# process confirm mouse confirm event.
|
45
|
+
def process_confirm_mouse_click(input)
|
46
|
+
if (input[:type] == :left_pressed) && (input[:pos][:y] == @begin_confirm_pos[:y])
|
47
|
+
if input[:pos][:x] == @begin_confirm_pos[:x]
|
48
|
+
print_confirm(true, false)
|
49
|
+
elsif input[:pos][:x] == @begin_confirm_pos[:x] + 2
|
50
|
+
print_confirm(false, false)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# process confirm keyboard confirm event.
|
56
|
+
def process_confirm_keyboard_input(key)
|
57
|
+
case key
|
58
|
+
when :enter then print_confirm(@res, false)
|
59
|
+
when :Y, :y then print_confirm(true, false)
|
60
|
+
when :N, :n then print_confirm(false, false)
|
61
|
+
when :tab, :down, :left, :space, :up, :right then print_confirm(!@res, true)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/term/cursor.rb
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'io/console'
|
4
|
+
|
5
|
+
# @author {mailto:cuihaiqin@gmail.com cuihq}
|
6
|
+
class IO
|
7
|
+
# move cursor to home position (0-0).
|
8
|
+
#
|
9
|
+
# @return [self] Term self.
|
10
|
+
def self.home
|
11
|
+
print "\e[H"
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
# save current cursor position & attrs.
|
16
|
+
#
|
17
|
+
# @return [Term] Term self.
|
18
|
+
def self.save
|
19
|
+
print "\e7"
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
# restore saved cursor position & attrs.
|
24
|
+
#
|
25
|
+
# @return [Term] Term self.
|
26
|
+
def self.restore
|
27
|
+
print "\e8"
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
# make cursor invisible.
|
32
|
+
#
|
33
|
+
# @return [Term] Term self.
|
34
|
+
def self.hide
|
35
|
+
print "\e[?25l"
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
# make cursor visible.
|
40
|
+
#
|
41
|
+
# @return [Term] Term self.
|
42
|
+
def self.show
|
43
|
+
print "\e[?25h"
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
# query cursor position.
|
48
|
+
#
|
49
|
+
# @return [Hash] pos cursor position.
|
50
|
+
def self.pos
|
51
|
+
$stdin.raw do
|
52
|
+
print "\e[6n"
|
53
|
+
y_axis, x_axis = $stdin.gets('R')[2..-2].split(';')
|
54
|
+
{ x: x_axis.to_i - 1, y: y_axis.to_i - 1 }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# home-positioning to x and y coordinates.
|
59
|
+
# @param pos [Hash] opt the coordinates
|
60
|
+
# @option opt [Integer] x the x coordinates, default 0
|
61
|
+
# @option opt [Integer] y the y coordinates, default 0
|
62
|
+
# @return [Term] Term self.
|
63
|
+
def self.to(pos)
|
64
|
+
x_axis = pos[:x] || 0
|
65
|
+
y_axis = pos[:y] || 0
|
66
|
+
print "\e[#{y_axis + 1};#{x_axis + 1}H" # ANSI uses 1-1 as home
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
# moves the cursor up by num rows.
|
71
|
+
#
|
72
|
+
# @param num [Integer] the rows, the default num is 1.
|
73
|
+
# @return [Term] Term self.
|
74
|
+
def self.up(num = 1)
|
75
|
+
print "\e[#{num}A" # CUU
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
# moves the cursor down by num rows.
|
80
|
+
#
|
81
|
+
# @param num [Integer] the rows, the default num is 1.
|
82
|
+
# @return [Term] Term self.
|
83
|
+
def self.down(num = 1)
|
84
|
+
print "\e[#{num}B" # CUD
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
# moves the cursor forward by num columns.
|
89
|
+
#
|
90
|
+
# @param num [Integer] the columns, the default num is 1.
|
91
|
+
# @return [Term] Term self.
|
92
|
+
def self.forward(num = 1)
|
93
|
+
print "\e[#{num}C" # CUF
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
# moves the cursor backward by num columns.
|
98
|
+
#
|
99
|
+
# @param num [Integer] the columns, the default num is 1.
|
100
|
+
# @return [Term] Term self.
|
101
|
+
def self.backward(num = 1)
|
102
|
+
print "\e[#{num}D" # CUB
|
103
|
+
self
|
104
|
+
end
|
105
|
+
|
106
|
+
# cursor next line num times.
|
107
|
+
#
|
108
|
+
# @param num [Integer] the times, the default num is 1.
|
109
|
+
# @return [Term] Term self.
|
110
|
+
def self.next_line(num = 1)
|
111
|
+
print "\e[#{num}E"
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
115
|
+
# cursor preceding line num times.
|
116
|
+
#
|
117
|
+
# @param num [Integer] the times, the default num is 1.
|
118
|
+
# @return [Term] Term self.
|
119
|
+
def self.prev_line(num = 1)
|
120
|
+
print "\e[#{num}F"
|
121
|
+
self
|
122
|
+
end
|
123
|
+
|
124
|
+
# clear screen.
|
125
|
+
#
|
126
|
+
# @note cursor position unchanged
|
127
|
+
# @return [Term] Term self.
|
128
|
+
def self.clear
|
129
|
+
print "\e[2J"
|
130
|
+
self
|
131
|
+
end
|
132
|
+
|
133
|
+
# clear line from current cursor position to end of line.
|
134
|
+
#
|
135
|
+
# @note cursor position unchanged
|
136
|
+
# @return [Term] Term self.
|
137
|
+
def self.clear_forward
|
138
|
+
print "\e[K"
|
139
|
+
self
|
140
|
+
end
|
141
|
+
|
142
|
+
# clear line from beginning to current cursor position.
|
143
|
+
#
|
144
|
+
# @note cursor position unchanged
|
145
|
+
# @return [Term] Term self.
|
146
|
+
def self.clear_backward
|
147
|
+
print "\e[1K"
|
148
|
+
self
|
149
|
+
end
|
150
|
+
|
151
|
+
# clear whole line.
|
152
|
+
#
|
153
|
+
# @note cursor position unchanged
|
154
|
+
# @return [Term] Term self.
|
155
|
+
def self.clear_line
|
156
|
+
print "\e[2K"
|
157
|
+
self
|
158
|
+
end
|
159
|
+
|
160
|
+
# erase the screen from the current line up to the top of the screen.
|
161
|
+
#
|
162
|
+
# @note cursor position unchanged
|
163
|
+
# @return [Term] Term self.
|
164
|
+
def self.clear_up
|
165
|
+
print "\e[1J"
|
166
|
+
self
|
167
|
+
end
|
168
|
+
|
169
|
+
# erase the screen from the current line down to the top of the screen.
|
170
|
+
#
|
171
|
+
# @note cursor position unchanged
|
172
|
+
# @return [Term] Term self.
|
173
|
+
def self.clear_down
|
174
|
+
print "\e[J"
|
175
|
+
self
|
176
|
+
end
|
177
|
+
end
|
data/lib/term/font.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# cording: utf-8
|
2
|
+
|
3
|
+
require 'artii'
|
4
|
+
|
5
|
+
# @author {mailto:cuihaiqin@gmail.com cuihq}
|
6
|
+
class String
|
7
|
+
# string fonts builder cache hash.
|
8
|
+
class << self; attr_accessor :fonts end
|
9
|
+
@fonts = {}
|
10
|
+
|
11
|
+
# set the font.
|
12
|
+
#
|
13
|
+
# @note using `artii` gem.
|
14
|
+
# typing `artii -l` to see all fonts.
|
15
|
+
# @example
|
16
|
+
# puts "term".font('big')
|
17
|
+
# @param name [String] the font name
|
18
|
+
# @return [String] string with the font style.
|
19
|
+
def font(name)
|
20
|
+
font_builder = self.class.fonts[name.to_s] ||= Artii::Base.new(font: name)
|
21
|
+
font_builder.output self
|
22
|
+
end
|
23
|
+
end
|
data/lib/term/input.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'term/cursor'
|
4
|
+
|
5
|
+
# @author {mailto:cuihaiqin@gmail.com cuihq}
|
6
|
+
class IO
|
7
|
+
# get keybord & mouse key.
|
8
|
+
#
|
9
|
+
# @return [Hash] keybord & mouse key
|
10
|
+
def self.input
|
11
|
+
$stdin.raw do
|
12
|
+
print "\e[?1000h" # DEC Private Mode Set
|
13
|
+
str = $stdin.readpartial(4096).force_encoding('utf-8')
|
14
|
+
print "\e[?1000l" # DEC Private Mode Reset
|
15
|
+
parse_key_str str
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# keybord & mouse hash.
|
20
|
+
KEY = {
|
21
|
+
"\e[A" => :up,
|
22
|
+
"\e[B" => :down,
|
23
|
+
"\e[C" => :right,
|
24
|
+
"\e[D" => :left,
|
25
|
+
"\t" => :tab,
|
26
|
+
"\r" => :enter,
|
27
|
+
' ' => :space,
|
28
|
+
"\e\[M" => :mouse
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
# parse key str
|
32
|
+
def self.parse_key_str(str)
|
33
|
+
key = KEY[str[0, 3]] || str.to_sym
|
34
|
+
if key == :mouse
|
35
|
+
type, mouse_x, mouse_y = str[3, 3].unpack('CCC')
|
36
|
+
type = %i(left_pressed scroll_down right_pressed released)[type & 0b11]
|
37
|
+
{ key: key, type: type, pos: { x: mouse_x - 33, y: mouse_y - 33 } }
|
38
|
+
else
|
39
|
+
{ key: key }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'term/input'
|
4
|
+
|
5
|
+
# @author {mailto:cuihaiqin@gmail.com cuihq}
|
6
|
+
class IO
|
7
|
+
# get password.
|
8
|
+
#
|
9
|
+
# @return [String] password
|
10
|
+
def self.password
|
11
|
+
@begin_password_pos = IO.hide.pos
|
12
|
+
hide_password_text
|
13
|
+
process_password_input
|
14
|
+
IO.show
|
15
|
+
@password_text || ''
|
16
|
+
end
|
17
|
+
|
18
|
+
# process password input event.
|
19
|
+
def self.process_password_input
|
20
|
+
@redio_loop = true
|
21
|
+
while @redio_loop
|
22
|
+
input = IO.input
|
23
|
+
process_password_mouse_click input
|
24
|
+
process_password_keyboard_input input[:key]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
private_class_method :process_password_input
|
28
|
+
|
29
|
+
# process keyboard input event.
|
30
|
+
def self.process_password_keyboard_input(key)
|
31
|
+
@password_text ||= ''
|
32
|
+
@password_text << key.to_s if key.size == 1
|
33
|
+
@redio_loop = false if key == :enter
|
34
|
+
end
|
35
|
+
private_class_method :process_password_keyboard_input
|
36
|
+
|
37
|
+
# process mouse click event.
|
38
|
+
def self.process_password_mouse_click(input)
|
39
|
+
type = input[:type]
|
40
|
+
pos = input[:pos]
|
41
|
+
if (type == :left_pressed) && (pos == @end_password_pos)
|
42
|
+
show_password_text
|
43
|
+
else
|
44
|
+
hide_password_text
|
45
|
+
end
|
46
|
+
end
|
47
|
+
private_class_method :process_password_mouse_click
|
48
|
+
|
49
|
+
# hide password text.
|
50
|
+
def self.hide_password_text
|
51
|
+
IO.to(@begin_password_pos).clear_forward
|
52
|
+
print '🔑 : ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ ⚫ 👁️'
|
53
|
+
@end_password_pos ||= IO.pos
|
54
|
+
end
|
55
|
+
private_class_method :hide_password_text
|
56
|
+
|
57
|
+
# show password text.
|
58
|
+
def self.show_password_text
|
59
|
+
IO.to(@begin_password_pos).clear_forward
|
60
|
+
print "🔑 : #{@password_text || ''}"
|
61
|
+
end
|
62
|
+
private_class_method :show_password_text
|
63
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'term/window'
|
4
|
+
|
5
|
+
# @author {mailto:cuihaiqin@gmail.com cuihq}
|
6
|
+
class Numeric
|
7
|
+
# get process bar.
|
8
|
+
#
|
9
|
+
# @example process bar
|
10
|
+
# print i.process_bar
|
11
|
+
# @param width [Integer] process width
|
12
|
+
# @return [String] process bar
|
13
|
+
def process_bar(width = IO.width - 8)
|
14
|
+
percent = format(' %3d%', self)
|
15
|
+
line = '-' * width
|
16
|
+
if self <= 0
|
17
|
+
"[#{line.insert(0, '🛫')}]#{percent}"
|
18
|
+
elsif self >= 100
|
19
|
+
"[#{line.insert(-1, '🛬')}]#{percent}"
|
20
|
+
else
|
21
|
+
"[#{line.insert((self / 100.0 * width).to_i, '✈️')}]#{percent}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/term/qrcode.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'rqrcode'
|
4
|
+
|
5
|
+
require 'term/color'
|
6
|
+
|
7
|
+
# @author {mailto:cuihaiqin@gmail.com cuihq}
|
8
|
+
class String
|
9
|
+
# get qrcode.
|
10
|
+
#
|
11
|
+
# @return [String] qrcode
|
12
|
+
def qrcode
|
13
|
+
RQRCode::QRCode.new(self).as_ansi(quiet_zone_size: 0)
|
14
|
+
end
|
15
|
+
end
|
data/lib/term/redio.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'term/cursor'
|
4
|
+
require 'term/input'
|
5
|
+
|
6
|
+
# @author {mailto:cuihaiqin@gmail.com cuihq}
|
7
|
+
module Enumerable
|
8
|
+
# the redio Component.
|
9
|
+
#
|
10
|
+
# @example redio
|
11
|
+
# ['a', 'b', 7].redio
|
12
|
+
# @return [Object] the redio val
|
13
|
+
def redio
|
14
|
+
size.times { print $/ }
|
15
|
+
@begin_pos = IO.up(size).hide.pos
|
16
|
+
process_input_redio
|
17
|
+
IO.show
|
18
|
+
@redio_res
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# print redio.
|
24
|
+
def print_redio(index = 0)
|
25
|
+
IO.to @begin_pos
|
26
|
+
@redio_res = index.to_i % size
|
27
|
+
@item_ys = []
|
28
|
+
each_with_index do |item, num|
|
29
|
+
print_redio_item item, num
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# print redio item.
|
34
|
+
def print_redio_item(item, num)
|
35
|
+
@item_ys[num] = IO.pos[:y]
|
36
|
+
print "#{@redio_res == num ? '🔘' : '⭕️'} #{num}. #{item}#{$/}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# process redio input.
|
40
|
+
def process_input_redio
|
41
|
+
print_redio
|
42
|
+
@redio_loop = true
|
43
|
+
while @redio_loop
|
44
|
+
input = IO.input
|
45
|
+
process_redio_mouse_click input
|
46
|
+
process_redio_keyboard_input input[:key]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# process redio mouse click event.
|
51
|
+
def process_redio_mouse_click(input)
|
52
|
+
if input[:type] == :left_pressed
|
53
|
+
list_item = @item_ys.find_index input[:pos][:y]
|
54
|
+
print_redio list_item if list_item
|
55
|
+
@redio_loop = false
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# process redio keyboard input event.
|
60
|
+
def process_redio_keyboard_input(key)
|
61
|
+
case key
|
62
|
+
when :enter then @redio_loop = false
|
63
|
+
when /\d/ then print_redio(key.to_s)
|
64
|
+
when :tab, :down, :left, :space then print_redio(@redio_res.succ)
|
65
|
+
when :up, :right then print_redio(@redio_res.pred)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|