natty-ui 0.6.0 → 0.8.0
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 +4 -4
- data/.yardopts +12 -0
- data/README.md +25 -48
- data/examples/24bit-colors.rb +23 -0
- data/examples/3bit-colors.rb +13 -0
- data/examples/8bit-colors.rb +31 -0
- data/examples/attributes.rb +41 -134
- data/examples/demo.rb +217 -0
- data/examples/illustration.png +0 -0
- data/examples/illustration.rb +26 -0
- data/examples/list_in_columns.rb +10 -17
- data/examples/progress.rb +24 -29
- data/examples/query.rb +22 -21
- data/examples/table.rb +18 -0
- data/lib/natty-ui/ansi.rb +111 -92
- data/lib/natty-ui/ansi_wrapper.rb +93 -161
- data/lib/natty-ui/features.rb +12 -19
- data/lib/natty-ui/version.rb +2 -2
- data/lib/natty-ui/wrapper/ask.rb +26 -20
- data/lib/natty-ui/wrapper/element.rb +19 -23
- data/lib/natty-ui/wrapper/framed.rb +23 -18
- data/lib/natty-ui/wrapper/heading.rb +26 -53
- data/lib/natty-ui/wrapper/horizontal_rule.rb +37 -0
- data/lib/natty-ui/wrapper/list_in_columns.rb +66 -10
- data/lib/natty-ui/wrapper/message.rb +20 -27
- data/lib/natty-ui/{mixins.rb → wrapper/mixins.rb} +2 -2
- data/lib/natty-ui/wrapper/progress.rb +11 -9
- data/lib/natty-ui/wrapper/query.rb +37 -30
- data/lib/natty-ui/wrapper/quote.rb +25 -0
- data/lib/natty-ui/wrapper/request.rb +27 -5
- data/lib/natty-ui/wrapper/section.rb +42 -40
- data/lib/natty-ui/wrapper/table.rb +298 -0
- data/lib/natty-ui/wrapper/task.rb +9 -12
- data/lib/natty-ui/wrapper.rb +117 -44
- data/lib/natty-ui.rb +48 -50
- data/lib/natty_ui.rb +3 -0
- metadata +18 -9
- data/examples/basic.rb +0 -62
data/examples/list_in_columns.rb
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'natty-ui'
|
4
4
|
|
5
|
-
UI = NattyUI::StdOut
|
6
|
-
|
7
5
|
LOREM = <<~LOREM
|
8
6
|
Lorem ipsum dolor sit
|
9
7
|
amet, consectetur adipisicing
|
@@ -14,7 +12,7 @@ LOREM = <<~LOREM
|
|
14
12
|
nostrud exercitation ullamco
|
15
13
|
laboris nisi ut aliquip ex
|
16
14
|
ea commodo [[bold]]consequat[[/]]. Duis
|
17
|
-
aute irure dolor in
|
15
|
+
aute irure [[bold green]]dolor[[/]] in
|
18
16
|
reprehenderit in voluptate
|
19
17
|
velit [[underline]]esse cillum[[/]] dolore eu
|
20
18
|
fugiat nulla pariatur.
|
@@ -24,20 +22,15 @@ LOREM = <<~LOREM
|
|
24
22
|
deserunt mollit anim id
|
25
23
|
est laborum.
|
26
24
|
LOREM
|
27
|
-
WORDS = LOREM.split(/\W+/).uniq.sort!.freeze
|
28
|
-
|
29
|
-
UI.space
|
30
|
-
UI.h2 'Print a list in columns'
|
31
|
-
UI.space
|
32
25
|
|
33
|
-
|
34
|
-
|
35
|
-
|
26
|
+
ui.space
|
27
|
+
ui.h1 'Print a list in columns'
|
28
|
+
ui.space
|
36
29
|
|
37
|
-
|
38
|
-
|
39
|
-
|
30
|
+
ui.h2 'Lorem ipsum lines (compact)'
|
31
|
+
ui.ls LOREM.lines(chomp: true), glyph: 1
|
32
|
+
ui.space
|
40
33
|
|
41
|
-
|
42
|
-
|
43
|
-
|
34
|
+
ui.h2 'Lorem ipsum lines (row-wise)'
|
35
|
+
ui.ls LOREM.lines(chomp: true), glyph: 1, compact: false
|
36
|
+
ui.space
|
data/examples/progress.rb
CHANGED
@@ -2,67 +2,62 @@
|
|
2
2
|
|
3
3
|
require 'natty-ui'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
UI.h1 'NattyUI Progress Indication Demo'
|
9
|
-
UI.space
|
5
|
+
ui.space
|
6
|
+
ui.h1 'NattyUI Progress Indication Demo'
|
7
|
+
ui.space
|
10
8
|
|
11
9
|
# just simulate some work
|
12
10
|
def something = sleep(0.5)
|
13
11
|
def some = sleep(0.15)
|
14
12
|
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
ui.info 'Tasks are sections to visualize step by step processing.' do
|
14
|
+
ui.task 'Assemble assets' do
|
15
|
+
ui.task('Initialize') { something }
|
18
16
|
|
19
|
-
progress =
|
17
|
+
progress = ui.progress 'Connect to server...'
|
20
18
|
20.times do
|
21
19
|
progress.step
|
22
20
|
some
|
23
21
|
end
|
24
22
|
progress.ok 'Connected'
|
25
23
|
|
26
|
-
|
24
|
+
ui.task('Collect files...') { something }
|
27
25
|
|
28
|
-
|
26
|
+
ui.task 'Compile files...' do
|
29
27
|
%w[readme.txt main.css main.html sub.html].each do |name|
|
30
|
-
|
28
|
+
ui.msg "Compile file [[bright_yellow]]./source/#{name}[[/]]..."
|
31
29
|
something
|
32
30
|
end
|
33
|
-
|
31
|
+
ui.done 'Files compiled.'
|
34
32
|
end
|
35
33
|
|
36
|
-
progress =
|
34
|
+
progress = ui.progress('Compress files', max_value: 11)
|
37
35
|
11.times do
|
38
36
|
progress.step
|
39
37
|
something
|
40
38
|
end
|
41
39
|
progress.done 'All compressed'
|
42
40
|
|
43
|
-
|
41
|
+
ui.task('Signing') { something }
|
44
42
|
|
45
|
-
|
43
|
+
ui.task('Store assembled results') { something }
|
46
44
|
end
|
47
|
-
|
45
|
+
|
46
|
+
ui.puts(
|
48
47
|
'The details are removed ([[italic]]in ANSI version[[/]]) when the task',
|
49
48
|
'ended sucessfully.'
|
50
49
|
)
|
51
50
|
end
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
progress.step
|
60
|
-
some
|
52
|
+
ui.info 'Details of failed tasks will not be cleaned.' do
|
53
|
+
ui.task 'Assemble assets' do
|
54
|
+
ui.task('Initialize') { something }
|
55
|
+
ui.task('Connect to Server') do
|
56
|
+
something
|
57
|
+
ui.failed 'Unable to connect to server'
|
61
58
|
end
|
62
|
-
|
63
|
-
|
64
|
-
task.error 'This code will not be reachd!'
|
59
|
+
ui.error 'This code will not be reachd!'
|
65
60
|
end
|
66
61
|
end
|
67
62
|
|
68
|
-
|
63
|
+
ui.space
|
data/examples/query.rb
CHANGED
@@ -2,35 +2,36 @@
|
|
2
2
|
|
3
3
|
require 'natty-ui'
|
4
4
|
|
5
|
-
|
5
|
+
ui.space
|
6
|
+
ui.h1 'NattyUI Query Demo'
|
7
|
+
ui.space
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
# little helper
|
10
|
+
def abort!
|
11
|
+
ui.failed 'aborted'
|
12
|
+
exit
|
13
|
+
end
|
10
14
|
|
11
|
-
unless
|
12
|
-
|
15
|
+
unless ui.ask('Do you like to continute? (Y|n): ')
|
16
|
+
ui.info 'ok, try later!'
|
13
17
|
exit
|
14
18
|
end
|
15
19
|
|
16
20
|
choice =
|
17
|
-
|
21
|
+
ui.query(
|
18
22
|
'Which fruits do you prefer?',
|
19
23
|
'Apples',
|
20
|
-
'Bananas',
|
24
|
+
'[[yellow]]Bananas[[/]]',
|
21
25
|
'Cherries',
|
22
|
-
x: 'No fruits'
|
23
|
-
result: :choice
|
26
|
+
x: 'No fruits'
|
24
27
|
)
|
25
|
-
unless choice
|
26
|
-
|
27
|
-
exit false
|
28
|
-
end
|
29
|
-
UI.info "Your choice: #{choice}"
|
28
|
+
abort! unless choice
|
29
|
+
ui.info "Your choice: #{choice}"
|
30
30
|
|
31
|
-
answer =
|
32
|
-
unless answer
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
31
|
+
answer = ui.request 'What is your favorite verb?: '
|
32
|
+
abort! unless answer
|
33
|
+
ui.info "Your answer: #{answer.inspect}"
|
34
|
+
|
35
|
+
answer = ui.request('What is your current password?:', password: true)
|
36
|
+
abort! unless answer
|
37
|
+
ui.info "I'll keep your secret!"
|
data/examples/table.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'natty-ui'
|
4
|
+
|
5
|
+
User = Struct.new(:id, :name, :address)
|
6
|
+
|
7
|
+
USERS = [
|
8
|
+
User.new(1, 'Henry', 'henry@some.test'),
|
9
|
+
User.new(2, 'Sam', 'sam-sam@some.test'),
|
10
|
+
User.new(3, 'Taylor', 'taylor@some.test'),
|
11
|
+
User.new(3, 'Max', 'maxxx@some.test')
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
ui.space
|
15
|
+
ui.h1 'The User List'
|
16
|
+
ui.space
|
17
|
+
|
18
|
+
ui.table(User.members, *USERS)
|
data/lib/natty-ui/ansi.rb
CHANGED
@@ -5,44 +5,85 @@ module NattyUI
|
|
5
5
|
# Helper module for ANSI escape codes.
|
6
6
|
#
|
7
7
|
module Ansi
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
# ANSI code to move the cursor down.
|
9
|
+
CURSOR_DOWN = "\e[B"
|
10
|
+
|
11
|
+
# ANSI code to move the cursor up.
|
12
|
+
CURSOR_UP = "\e[A"
|
13
|
+
|
14
|
+
# ANSI code to move the cursor left.
|
15
|
+
CURSOR_LEFT = "\e[D"
|
16
|
+
|
17
|
+
# ANSI code to move the cursor right.
|
18
|
+
CURSOR_RIGHT = "\e[C"
|
19
|
+
|
20
|
+
# ANSI code to move the cursor to beginning of the line below.
|
21
|
+
CURSOR_LINE_DOWN = "\e[E"
|
22
|
+
|
23
|
+
# ANSI code to move the cursor to beginning of the line up.
|
24
|
+
CURSOR_LINE_UP = "\e[F"
|
25
|
+
|
26
|
+
# ANSI code to hide the cursor.
|
27
|
+
CURSOR_HIDE = "\e[?25l"
|
28
|
+
|
29
|
+
# ANSI code to show the cursor (again).
|
30
|
+
CURSOR_SHOW = "\e[?25h"
|
31
|
+
|
32
|
+
# ANSI code to save current cursor position.
|
33
|
+
CURSOR_SAVE_POS = "\e[s"
|
34
|
+
|
35
|
+
# ANSI code to restore saved cursor position.
|
36
|
+
CURSOR_RESTORE_POS = "\e[u"
|
37
|
+
|
38
|
+
# ANSI code to set cursor position on upper left corner.
|
39
|
+
CURSOR_HOME = "\e[H"
|
40
|
+
|
41
|
+
# ANSI code to erase current line and position to first column.
|
42
|
+
LINE_CLEAR = "\e[1K\e[0G"
|
43
|
+
|
44
|
+
# ANSI code to erase current line.
|
45
|
+
LINE_ERASE = "\e[2K"
|
46
|
+
|
47
|
+
# ANSI code to erase to end of current line.
|
48
|
+
LINE_ERASE_TO_END = "\e[0K"
|
49
|
+
|
50
|
+
# ANSI code to erase to begin of current line.
|
51
|
+
LINE_ERASE_TO_BEGIN = "\e[1K"
|
11
52
|
|
12
|
-
|
13
|
-
|
53
|
+
# ANSI code to save current screen state.
|
54
|
+
SCREEN_SAVE = "\e[?47h"
|
14
55
|
|
15
|
-
|
16
|
-
|
56
|
+
# ANSI code to restore screen state.
|
57
|
+
SCREEN_RESTORE = "\e[?47l"
|
17
58
|
|
18
|
-
|
19
|
-
|
59
|
+
# ANSI code to erase screen.
|
60
|
+
SCREEN_ERASE = "\e[2J"
|
20
61
|
|
21
|
-
|
22
|
-
|
62
|
+
# ANSI code to erase screen below current cursor position.
|
63
|
+
SCREEN_ERASE_BELOW = "\e[0J"
|
23
64
|
|
24
|
-
|
25
|
-
|
65
|
+
# ANSI code to erase screen above current cursor position.
|
66
|
+
SCREEN_ERASE_ABOVE = "\e[1J"
|
26
67
|
|
27
|
-
|
28
|
-
|
68
|
+
# ANSI code to alternate screen
|
69
|
+
SCREEN_ALTERNATIVE = "\e[?1049h"
|
29
70
|
|
30
|
-
|
31
|
-
|
71
|
+
# ANSI code to set alternate screen off.
|
72
|
+
SCREEN_ALTERNATIVE_OFF = "\e[?1049l"
|
32
73
|
|
33
|
-
|
34
|
-
|
74
|
+
# ANSI code to reset all attributes.
|
75
|
+
RESET = "\e[0m"
|
35
76
|
|
36
|
-
|
37
|
-
|
77
|
+
# @!visibility private
|
78
|
+
CURSOR_RIGHT_ALIGNED = "\e[9999G\e[D\e[C"
|
38
79
|
|
39
|
-
|
40
|
-
|
80
|
+
# @!visibility private
|
81
|
+
BLANK_SLATE = "\e[0m\e[s\e[?47h\e[H\e[2J"
|
41
82
|
|
42
|
-
|
43
|
-
|
44
|
-
def line_clear = "\e[1K\e[0G"
|
83
|
+
# @!visibility private
|
84
|
+
UNBLANK_SLATE = "\e[?47l\e[u\e[0m"
|
45
85
|
|
86
|
+
class << self
|
46
87
|
# @param lines [Integer] number of lines
|
47
88
|
# @return [String] ANSI code to move the cursor up
|
48
89
|
def cursor_up(lines = nil) = "\e[#{lines}A"
|
@@ -60,37 +101,18 @@ module NattyUI
|
|
60
101
|
def cursor_left(columns = nil) = "\e[#{columns}D"
|
61
102
|
|
62
103
|
# @param lines [Integer] number of lines
|
63
|
-
# @return [String] ANSI code to move the cursor to beginning of
|
64
|
-
#
|
104
|
+
# @return [String] ANSI code to move the cursor to beginning of some lines
|
105
|
+
# below
|
65
106
|
def cursor_line_down(lines = nil) = "\e[#{lines}E"
|
66
107
|
|
67
108
|
# @param lines [Integer] number of lines
|
68
|
-
# @return [String] ANSI code to move the cursor to beginning of
|
69
|
-
#
|
109
|
+
# @return [String] ANSI code to move the cursor to beginning of some lines
|
110
|
+
# up
|
70
111
|
def cursor_line_up(lines = nil) = "\e[#{lines}F"
|
71
112
|
|
72
|
-
# @param
|
113
|
+
# @param column [Integer] column number
|
73
114
|
# @return [String] ANSI code to move the cursor to given column
|
74
|
-
def cursor_column(
|
75
|
-
|
76
|
-
# @return [String] ANSI code poition the cursor on right hand side of the
|
77
|
-
# terminal
|
78
|
-
def cursor_right_aligned = "\e[9999G\e[D\e[C"
|
79
|
-
|
80
|
-
# @return [String] ANSI code to hide the cursor
|
81
|
-
def cursor_hide = "\e[?25l"
|
82
|
-
|
83
|
-
# @return [String] ANSI code to show the cursor (again)
|
84
|
-
def cursor_show = "\e[?25h"
|
85
|
-
|
86
|
-
# @return [String] ANSI code to save current cursor position
|
87
|
-
def cursor_save_pos = "\e[s"
|
88
|
-
|
89
|
-
# @return [String] ANSI code to restore saved cursor position
|
90
|
-
def cursor_restore_pos = "\e[u"
|
91
|
-
|
92
|
-
# @return [String] ANSI code to set cursor position on upper left corner
|
93
|
-
def cursor_home = "\e[H"
|
115
|
+
def cursor_column(column = nil) = "\e[#{column}G"
|
94
116
|
|
95
117
|
# @param row [Integer] row to set cursor
|
96
118
|
# @param column [Integer] column to set cursor
|
@@ -100,27 +122,26 @@ module NattyUI
|
|
100
122
|
column ? "\e[;#{column}H" : "\e[H"
|
101
123
|
end
|
102
124
|
|
103
|
-
# Decorate given `
|
125
|
+
# Decorate given `str` with ANSI `attributes`.
|
104
126
|
#
|
105
127
|
# @see []
|
106
128
|
#
|
107
|
-
# @param
|
129
|
+
# @param str [#to_s] object to be decorated
|
108
130
|
# @param attributes [Symbol, String] attribute names to be used
|
109
131
|
# @param reset [Boolean] whether to include reset code for ANSI attributes
|
110
|
-
# @return [String] `
|
111
|
-
def embellish(
|
132
|
+
# @return [String] `str` converted and decorated with the ANSI `attributes`
|
133
|
+
def embellish(str, *attributes, reset: true)
|
112
134
|
attributes = self[*attributes]
|
113
|
-
attributes.empty? ?
|
135
|
+
attributes.empty? ? str.to_s : "#{attributes}#{str}#{"\e[0m" if reset}"
|
114
136
|
end
|
115
137
|
|
116
138
|
# Remove ANSI attribtes from given string.
|
117
|
-
# This will only remove attributes and colors, not other control codes.
|
118
139
|
#
|
119
140
|
# @see embellish
|
120
141
|
#
|
121
142
|
# @param str [#to_s] string to be modified
|
122
143
|
# @return [String] string without ANSI attributes
|
123
|
-
def blemish(str) = str.to_s.gsub(/(\x1b\[(?~
|
144
|
+
def blemish(str) = str.to_s.gsub(/(\x1b\[(?~[a-zA-Z])[a-zA-Z])/, '')
|
124
145
|
|
125
146
|
# Combine given ANSI `attributes`.
|
126
147
|
#
|
@@ -228,12 +249,9 @@ module NattyUI
|
|
228
249
|
# @return [String] combined ANSI attributes
|
229
250
|
# @return [nil] when string does not contain valid attributes
|
230
251
|
def try_convert(attributes)
|
231
|
-
attributes = attributes.to_s.split
|
232
|
-
return if attributes.empty?
|
252
|
+
return if (attributes = attributes.to_s.split).empty?
|
233
253
|
"\e[#{
|
234
|
-
attributes
|
235
|
-
.map { |arg| ATTRIBUTES[arg] || color(arg) || return }
|
236
|
-
.join(';')
|
254
|
+
attributes.map { ATTRIBUTES[_1] || color(_1) || return }.join(';')
|
237
255
|
}m"
|
238
256
|
end
|
239
257
|
|
@@ -247,36 +265,37 @@ module NattyUI
|
|
247
265
|
)
|
248
266
|
end
|
249
267
|
|
250
|
-
def color(
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
268
|
+
def color(val)
|
269
|
+
val = val.to_s.downcase
|
270
|
+
base =
|
271
|
+
if val.delete_prefix!('fg')
|
272
|
+
val.delete_prefix!(':') || val.delete_prefix!('_')
|
273
|
+
'38;'
|
274
|
+
elsif val.delete_prefix!('ul')
|
275
|
+
val.delete_prefix!(':') || val.delete_prefix!('_')
|
276
|
+
'58;'
|
277
|
+
elsif val.delete_prefix!('bg') || val.delete_prefix!('on')
|
278
|
+
val.delete_prefix!(':') || val.delete_prefix!('_')
|
279
|
+
'48;'
|
280
|
+
else
|
281
|
+
'38;'
|
282
|
+
end
|
283
|
+
val.delete_prefix!('#')
|
284
|
+
case val.size
|
285
|
+
when 1, 2
|
286
|
+
"#{base}5;#{val.hex}" if /\A[[:xdigit:]]+\z/.match?(val)
|
287
|
+
when 3
|
288
|
+
if /\A[[:xdigit:]]+\z/.match?(val)
|
289
|
+
"#{base}2;#{(val[0] * 2).hex};#{(val[1] * 2).hex};#{
|
290
|
+
(val[2] * 2).hex
|
291
|
+
}"
|
292
|
+
end
|
293
|
+
when 6
|
294
|
+
if /\A[[:xdigit:]]+\z/.match?(val)
|
295
|
+
"#{base}2;#{val[0, 2].hex};#{val[2, 2].hex};#{val[4, 2].hex}"
|
296
|
+
end
|
270
297
|
end
|
271
298
|
end
|
272
|
-
|
273
|
-
def hex_rgb_short(base, str)
|
274
|
-
"#{base};2;#{(str[0] * 2).hex};#{(str[1] * 2).hex};#{(str[2] * 2).hex}"
|
275
|
-
end
|
276
|
-
|
277
|
-
def hex_rgb(base, str)
|
278
|
-
"#{base};2;#{str[0, 2].hex};#{str[2, 2].hex};#{str[4, 2].hex}"
|
279
|
-
end
|
280
299
|
end
|
281
300
|
|
282
301
|
ATTRIBUTES =
|
@@ -434,7 +453,7 @@ module NattyUI
|
|
434
453
|
ul_bright_magenta: '58;2;255;0;255',
|
435
454
|
ul_bright_cyan: '58;2;0;255;255',
|
436
455
|
ul_bright_white: '58;2;255;255;255'
|
437
|
-
}.tap {
|
456
|
+
}.tap { _1.merge!(_1.transform_keys(&:to_s)).freeze }
|
438
457
|
private_constant :ATTRIBUTES
|
439
458
|
end
|
440
459
|
end
|