term 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|