natty-ui 0.7.0 → 0.9.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 +7 -3
- data/README.md +25 -47
- data/examples/24bit-colors.rb +27 -0
- data/examples/3bit-colors.rb +14 -0
- data/examples/8bit-colors.rb +31 -0
- data/examples/animate.rb +24 -0
- data/examples/attributes.rb +25 -159
- data/examples/demo.rb +53 -0
- data/examples/illustration.png +0 -0
- data/examples/illustration.rb +29 -0
- data/examples/{list_in_columns.rb → ls.rb} +13 -20
- data/examples/message.rb +30 -0
- data/examples/progress.rb +25 -30
- data/examples/query.rb +26 -28
- data/examples/read_key.rb +13 -0
- data/examples/table.rb +36 -0
- data/lib/natty-ui/ansi.rb +351 -305
- data/lib/natty-ui/ansi_constants.rb +73 -0
- data/lib/natty-ui/ansi_wrapper.rb +136 -162
- data/lib/natty-ui/features.rb +11 -18
- data/lib/natty-ui/key_map.rb +119 -0
- data/lib/natty-ui/line_animation/default.rb +35 -0
- data/lib/natty-ui/line_animation/matrix.rb +28 -0
- data/lib/natty-ui/line_animation/rainbow.rb +30 -0
- data/lib/natty-ui/line_animation/test.rb +29 -0
- data/lib/natty-ui/line_animation/type_writer.rb +64 -0
- data/lib/natty-ui/line_animation.rb +54 -0
- data/lib/natty-ui/version.rb +2 -2
- data/lib/natty-ui/wrapper/animate.rb +17 -0
- data/lib/natty-ui/wrapper/ask.rb +21 -21
- data/lib/natty-ui/wrapper/element.rb +19 -23
- data/lib/natty-ui/wrapper/framed.rb +29 -19
- 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 +71 -12
- data/lib/natty-ui/wrapper/message.rb +20 -27
- data/lib/natty-ui/wrapper/progress.rb +40 -13
- data/lib/natty-ui/wrapper/query.rb +34 -31
- data/lib/natty-ui/wrapper/quote.rb +25 -0
- data/lib/natty-ui/wrapper/request.rb +21 -10
- data/lib/natty-ui/wrapper/section.rb +55 -39
- data/lib/natty-ui/wrapper/table.rb +298 -0
- data/lib/natty-ui/wrapper/task.rb +6 -7
- data/lib/natty-ui/wrapper.rb +123 -41
- data/lib/natty-ui.rb +65 -40
- metadata +28 -9
- data/examples/basic.rb +0 -62
@@ -11,10 +11,38 @@ module NattyUI
|
|
11
11
|
# The non-compact format prints all columns in same width and order the list
|
12
12
|
# items row-wise.
|
13
13
|
#
|
14
|
+
# @example simple compact list
|
15
|
+
# ui.ls('apple', 'banana', 'blueberry', 'pineapple', 'strawberry')
|
16
|
+
# # => apple banana blueberry pineapple strawberry
|
17
|
+
#
|
18
|
+
# @example (unordered) list with red dot
|
19
|
+
# ui.ls('apple', 'banana', 'blueberry', 'pineapple', 'strawberry', glyph: '[[red]]•[[/]]')
|
20
|
+
# # => • apple • banana • blueberry • pineapple • strawberry
|
21
|
+
#
|
22
|
+
# @example ordered list
|
23
|
+
# ui.ls('apple', 'banana', 'blueberry', 'pineapple', 'strawberry', glyph: 1)
|
24
|
+
# # => 1 apple 2 banana 3 blueberry 4 pineapple 5 strawberry
|
25
|
+
#
|
26
|
+
# @example ordered list, start at 100
|
27
|
+
# ui.ls('apple', 'banana', 'blueberry', 'pineapple', 'strawberry', glyph: 100)
|
28
|
+
# # => 100 apple 101 banana 102 blueberry 103 pineapple 104 strawberry
|
29
|
+
#
|
30
|
+
# @example ordered list using, uppercase characters
|
31
|
+
# ui.ls('apple', 'banana', 'blueberry', 'pineapple', 'strawberry', glyph: :A)
|
32
|
+
# # => A apple B banana C blueberry D pineapple E strawberry
|
33
|
+
#
|
34
|
+
# @example ordered list, using lowercase characters
|
35
|
+
# ui.ls('apple', 'banana', 'blueberry', 'pineapple', 'strawberry', glyph: :a)
|
36
|
+
# # => a apple b banana c blueberry d pineapple e strawberry
|
37
|
+
#
|
14
38
|
# @param [Array<#to_s>] args items to print
|
15
39
|
# @param [Boolean] compact whether to use compact format
|
40
|
+
# @param [nil,#to_s,Integer,Symbol] glyph optional glyph used as element
|
41
|
+
# prefix
|
16
42
|
# @return [Wrapper, Wrapper::Element] itself
|
17
|
-
def ls(*args, compact: true
|
43
|
+
def ls(*args, compact: true, glyph: nil)
|
44
|
+
_element(:ListInColumns, args, compact, glyph)
|
45
|
+
end
|
18
46
|
end
|
19
47
|
|
20
48
|
class Wrapper
|
@@ -25,22 +53,52 @@ module NattyUI
|
|
25
53
|
class ListInColumns < Element
|
26
54
|
protected
|
27
55
|
|
28
|
-
def
|
56
|
+
def call(list, compact, glyph)
|
57
|
+
return @parent if list.empty?
|
29
58
|
list.flatten!
|
30
|
-
|
31
|
-
list.map!
|
59
|
+
cvt = cvt(glyph, list.size)
|
60
|
+
list.map! do |item|
|
61
|
+
Item.new(item = cvt[item], NattyUI.display_width(item))
|
62
|
+
end
|
32
63
|
if compact
|
33
|
-
each_compacted(list, available_width) {
|
64
|
+
each_compacted(list, available_width - 1) { @parent.puts(_1) }
|
65
|
+
else
|
66
|
+
each(list, available_width - 1) { @parent.puts(_1) }
|
67
|
+
end
|
68
|
+
@parent
|
69
|
+
end
|
70
|
+
|
71
|
+
def cvt(glyph, size)
|
72
|
+
case glyph
|
73
|
+
when nil, false
|
74
|
+
->(s) { NattyUI.embellish(s) }
|
75
|
+
when :hex
|
76
|
+
pad = size.to_s(16).size
|
77
|
+
glyph = 0
|
78
|
+
lambda do |s|
|
79
|
+
"#{(glyph += 1).to_s(16).rjust(pad, '0')} #{NattyUI.embellish(s)}"
|
80
|
+
end
|
81
|
+
when Integer
|
82
|
+
pad = (glyph + size).to_s.size
|
83
|
+
glyph -= 1
|
84
|
+
->(s) { "#{(glyph += 1).to_s.rjust(pad)} #{NattyUI.embellish(s)}" }
|
85
|
+
when Symbol
|
86
|
+
lambda do |s|
|
87
|
+
"#{
|
88
|
+
t = glyph
|
89
|
+
glyph = glyph.succ
|
90
|
+
t
|
91
|
+
} #{NattyUI.embellish(s)}"
|
92
|
+
end
|
34
93
|
else
|
35
|
-
|
94
|
+
->(s) { "#{glyph} #{NattyUI.embellish(s)}" }
|
36
95
|
end
|
37
|
-
parent
|
38
96
|
end
|
39
97
|
|
40
98
|
def each(list, max_width)
|
41
99
|
width = list.max_by(&:width).width + 3
|
42
100
|
list.each_slice(max_width / width) do |slice|
|
43
|
-
yield(slice.map {
|
101
|
+
yield(slice.map { _1.to_s(width) }.join)
|
44
102
|
end
|
45
103
|
end
|
46
104
|
|
@@ -58,7 +116,7 @@ module NattyUI
|
|
58
116
|
widths = [list.max_by(&:width).width]
|
59
117
|
1.upto(list.size - 1) do |slice_size|
|
60
118
|
candidate = list.each_slice(list.size / slice_size).to_a
|
61
|
-
cwidths = candidate.map {
|
119
|
+
cwidths = candidate.map { _1.max_by(&:width).width + 3 }
|
62
120
|
cwidths[-1] -= 3
|
63
121
|
break if cwidths.sum > max_width
|
64
122
|
found = candidate
|
@@ -68,14 +126,15 @@ module NattyUI
|
|
68
126
|
end
|
69
127
|
|
70
128
|
def fill(ary, size)
|
71
|
-
diff = size - ary.size
|
72
|
-
ary.fill(nil, ary.size, diff) if diff.positive?
|
129
|
+
(diff = size - ary.size).positive? && ary.fill(nil, ary.size, diff)
|
73
130
|
end
|
74
131
|
|
75
132
|
Item =
|
76
|
-
|
133
|
+
Struct.new(:str, :width) do
|
77
134
|
def to_s(in_width) = "#{str}#{' ' * (in_width - width)}"
|
78
135
|
end
|
136
|
+
|
137
|
+
private_constant :Item
|
79
138
|
end
|
80
139
|
end
|
81
140
|
end
|
@@ -4,17 +4,17 @@ require_relative 'section'
|
|
4
4
|
|
5
5
|
module NattyUI
|
6
6
|
module Features
|
7
|
-
# Creates a
|
8
|
-
#
|
7
|
+
# Creates a section with a highlighted `title` and prints given additional
|
8
|
+
# arguments as lines into the section.
|
9
9
|
#
|
10
10
|
# @param [#to_s] title object to print as section title
|
11
11
|
# @param [Array<#to_s>] args more objects to print
|
12
|
-
# @param [#to_s]
|
12
|
+
# @param [#to_s] glyph glyph/prefix used for the title
|
13
13
|
# @yieldparam [Wrapper::Message] message the created section
|
14
14
|
# @return [Object] the result of the code block
|
15
15
|
# @return [Wrapper::Message] itself, when no code block is given
|
16
|
-
def message(title, *args,
|
17
|
-
_section(
|
16
|
+
def message(title, *args, glyph: :default, &block)
|
17
|
+
_section(:Message, args, title: title, glyph: glyph, &block)
|
18
18
|
end
|
19
19
|
alias msg message
|
20
20
|
|
@@ -26,7 +26,7 @@ module NattyUI
|
|
26
26
|
# @yieldparam (see #message)
|
27
27
|
# @return (see #message)
|
28
28
|
def information(title, *args, &block)
|
29
|
-
_section(
|
29
|
+
_section(:Message, args, title: title, glyph: :information, &block)
|
30
30
|
end
|
31
31
|
alias info information
|
32
32
|
|
@@ -37,7 +37,7 @@ module NattyUI
|
|
37
37
|
# @yieldparam (see #message)
|
38
38
|
# @return (see #message)
|
39
39
|
def warning(title, *args, &block)
|
40
|
-
_section(
|
40
|
+
_section(:Message, args, title: title, glyph: :warning, &block)
|
41
41
|
end
|
42
42
|
alias warn warning
|
43
43
|
|
@@ -48,7 +48,7 @@ module NattyUI
|
|
48
48
|
# @yieldparam (see #message)
|
49
49
|
# @return (see #message)
|
50
50
|
def error(title, *args, &block)
|
51
|
-
_section(
|
51
|
+
_section(:Message, args, title: title, glyph: :error, &block)
|
52
52
|
end
|
53
53
|
alias err error
|
54
54
|
|
@@ -61,7 +61,7 @@ module NattyUI
|
|
61
61
|
# @yieldparam (see #message)
|
62
62
|
# @return (see #message)
|
63
63
|
def completed(title, *args, &block)
|
64
|
-
_section(
|
64
|
+
_section(:Message, args, title: title, glyph: :completed, &block)
|
65
65
|
end
|
66
66
|
alias done completed
|
67
67
|
alias ok completed
|
@@ -76,7 +76,7 @@ module NattyUI
|
|
76
76
|
# @yieldparam (see #message)
|
77
77
|
# @return (see #message)
|
78
78
|
def failed(title, *args, &block)
|
79
|
-
_section(
|
79
|
+
_section(:Message, args, title: title, glyph: :failed, &block)
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
@@ -93,24 +93,17 @@ module NattyUI
|
|
93
93
|
class Message < Section
|
94
94
|
protected
|
95
95
|
|
96
|
-
def initialize(parent, title:,
|
97
|
-
|
98
|
-
|
96
|
+
def initialize(parent, title:, glyph:)
|
97
|
+
glyph = parent.wrapper.glyph(glyph) || glyph
|
98
|
+
prefix_width = NattyUI.display_width(glyph) + 1
|
99
|
+
super(
|
100
|
+
parent,
|
101
|
+
prefix: ' ' * prefix_width,
|
102
|
+
prefix_width: prefix_width,
|
103
|
+
suffix_width: 0
|
104
|
+
)
|
105
|
+
parent.puts(title, prefix: "#{glyph} ", prefix_width: prefix_width)
|
99
106
|
end
|
100
|
-
|
101
|
-
def title_attr(str, _symbol) = { prefix: "#{str} " }
|
102
|
-
def as_symbol_str(symbol) = (SYMBOL[symbol] || symbol)
|
103
|
-
|
104
|
-
SYMBOL = {
|
105
|
-
default: '•',
|
106
|
-
information: 'i',
|
107
|
-
warning: '!',
|
108
|
-
error: 'X',
|
109
|
-
completed: '✓',
|
110
|
-
failed: 'F',
|
111
|
-
query: '▶︎',
|
112
|
-
task: '➔'
|
113
|
-
}.compare_by_identity.freeze
|
114
107
|
end
|
115
108
|
end
|
116
109
|
end
|
@@ -7,14 +7,23 @@ module NattyUI
|
|
7
7
|
module Features
|
8
8
|
# Creates progress element implementing additional {ProgressAttributes}.
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
10
|
+
# When a `max_value` is given, the progress will by displayed as a bar.
|
11
|
+
# Otherwise the `spinner` is used for a little animation.
|
12
|
+
#
|
13
|
+
# When no pre-defined spinner is specified then spinner will be
|
14
|
+
# used char-wise as a string for the progress animation.
|
15
|
+
#
|
16
|
+
# A progress element has additional states and can be closed with
|
17
|
+
# {#completed} or {#failed}.
|
12
18
|
#
|
13
19
|
# @param [#to_s] title object to print as progress title
|
14
|
-
# @param [
|
20
|
+
# @param [#to_f] max_value maximum value of the progress
|
21
|
+
# @param [:bar, :blink, :blocks, :braile, :circle, :colors, :pulse,
|
22
|
+
# :snake, :swap, :triangles, :vintage, #to_s] spinner type of spinner or
|
23
|
+
# spinner elements
|
15
24
|
# @return [Wrapper::Progress] the created progress element
|
16
|
-
def progress(title, max_value: nil)
|
17
|
-
|
25
|
+
def progress(title, max_value: nil, spinner: :pulse)
|
26
|
+
_element(:Progress, title, max_value, spinner)
|
18
27
|
end
|
19
28
|
end
|
20
29
|
|
@@ -29,16 +38,34 @@ module NattyUI
|
|
29
38
|
|
30
39
|
protected
|
31
40
|
|
32
|
-
def
|
33
|
-
super(parent, **opts)
|
41
|
+
def call(title, max_value, spinner)
|
34
42
|
@final_text = [title]
|
35
43
|
@max_value = [0, max_value.to_f].max if max_value
|
36
|
-
@value = 0
|
37
|
-
|
38
|
-
|
44
|
+
@value = @progress = 0
|
45
|
+
draw(title, SPINNER[spinner] || spinner.to_s)
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
SPINNER = {
|
50
|
+
bar: '▁▂▃▄▅▆▇█▇▆▅▄▃▂',
|
51
|
+
blink: '■□▪▫',
|
52
|
+
blocks: '▖▘▝▗',
|
53
|
+
braile: '⣷⣯⣟⡿⢿⣻⣽⣾',
|
54
|
+
braile_reverse: '⡿⣟⣯⣷⣾⣽⣻⢿',
|
55
|
+
circle: '◐◓◑◒',
|
56
|
+
colors: '🟨🟧🟥🟦🟪🟩',
|
57
|
+
pulse: '•✺◉●◉✺',
|
58
|
+
snake: '⠁⠉⠙⠸⢰⣠⣄⡆⠇⠃',
|
59
|
+
swap: '㊂㊀㊁',
|
60
|
+
triangles: '◢◣◤◥',
|
61
|
+
vintage: '-\\|/'
|
62
|
+
}.compare_by_identity.freeze
|
63
|
+
private_constant :SPINNER
|
64
|
+
|
65
|
+
def draw(title, _spinner)
|
66
|
+
(wrapper.stream << @parent.prefix << "➔ #{title} ").flush
|
39
67
|
end
|
40
68
|
|
41
|
-
def draw(title) = (wrapper.stream << prefix << "➔ #{title} ").flush
|
42
69
|
def end_draw = (wrapper.stream << "\n")
|
43
70
|
|
44
71
|
def redraw
|
@@ -53,11 +80,11 @@ module NattyUI
|
|
53
80
|
end_draw
|
54
81
|
return @parent.failed(*@final_text) if failed?
|
55
82
|
_section(
|
56
|
-
@parent,
|
57
83
|
:Message,
|
58
84
|
@final_text,
|
85
|
+
owner: @parent,
|
59
86
|
title: @final_text.shift,
|
60
|
-
|
87
|
+
glyph: @status = :completed
|
61
88
|
)
|
62
89
|
end
|
63
90
|
end
|
@@ -7,7 +7,7 @@ module NattyUI
|
|
7
7
|
# Request a choice from user.
|
8
8
|
#
|
9
9
|
# @example Select by Index
|
10
|
-
# choice =
|
10
|
+
# choice = ui.query(
|
11
11
|
# 'Which fruits do you prefer?',
|
12
12
|
# 'Apples',
|
13
13
|
# 'Bananas',
|
@@ -16,7 +16,7 @@ module NattyUI
|
|
16
16
|
# # => '1' or '2' or '3' or nil if user aborted
|
17
17
|
#
|
18
18
|
# @example Select by given char
|
19
|
-
# choice =
|
19
|
+
# choice = ui.query(
|
20
20
|
# 'Which fruits do you prefer?',
|
21
21
|
# a: 'Apples',
|
22
22
|
# b: 'Bananas',
|
@@ -29,13 +29,14 @@ module NattyUI
|
|
29
29
|
# @param question [#to_s] Question to display
|
30
30
|
# @param choices [#to_s] choices selectable via index (0..9)
|
31
31
|
# @param result [Symbol] defines how the result will be returned
|
32
|
+
# @param display [Symbol] display choices as `:list` or `:compact`
|
32
33
|
# @param kw_choices [{Char => #to_s}] choices selectable with given char
|
33
34
|
# @return [Char] when `result` is configured as `:char`
|
34
35
|
# @return [#to_s] when `result` is configured as `:choice`
|
35
36
|
# @return [[Char, #to_s]] when `result` is configured as `:both`
|
36
|
-
# @return [nil] when input was aborted with
|
37
|
-
def query(question, *choices, result: :char, **kw_choices)
|
38
|
-
_element(:Query, question, choices, kw_choices, result)
|
37
|
+
# @return [nil] when input was aborted with `^C` or `^D`
|
38
|
+
def query(question, *choices, result: :char, display: :list, **kw_choices)
|
39
|
+
_element(:Query, question, choices, kw_choices, result, display)
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
@@ -47,41 +48,43 @@ module NattyUI
|
|
47
48
|
class Query < Element
|
48
49
|
protected
|
49
50
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
:
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
)
|
61
|
-
read(choices, result_type)
|
51
|
+
def call(question, choices, kw_choices, result, display)
|
52
|
+
return if choices.empty? && kw_choices.empty?
|
53
|
+
choices = as_choices(choices, kw_choices)
|
54
|
+
text = choices.map { |k, v| "⦗#{CHOICE_MARK}#{k}#{Ansi::RESET}⦘ #{v}" }
|
55
|
+
@parent.wrapper.temporary do
|
56
|
+
if display == :compact
|
57
|
+
@parent.msg(question, glyph: :query).ls(text)
|
58
|
+
else
|
59
|
+
@parent.msg(question, *text, glyph: :query)
|
60
|
+
end
|
61
|
+
read(choices, result)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
def
|
65
|
+
def as_choices(choices, kw_choices)
|
66
|
+
choices
|
67
|
+
.take(9)
|
68
|
+
.each_with_index
|
69
|
+
.to_h { |str, i| [i + 1, str] }
|
70
|
+
.merge!(kw_choices)
|
71
|
+
.transform_keys!(&:to_s)
|
72
|
+
.transform_values! { _1.to_s.gsub(/[[:space:]]/, ' ') }
|
73
|
+
end
|
74
|
+
|
75
|
+
def read(choices, result)
|
66
76
|
while true
|
67
|
-
char = NattyUI.
|
68
|
-
return if
|
77
|
+
char = NattyUI.read_key
|
78
|
+
return if char == 'Ctrl+C'
|
69
79
|
next unless choices.key?(char)
|
70
|
-
return char if
|
71
|
-
return choices[char] if
|
80
|
+
return char if result == :char
|
81
|
+
return choices[char] if result == :title
|
72
82
|
return char, choices[char]
|
73
83
|
end
|
74
84
|
end
|
75
85
|
|
76
|
-
|
77
|
-
|
78
|
-
.new(choices.size) { |i| i + 1 }
|
79
|
-
.zip(choices)
|
80
|
-
.to_h
|
81
|
-
.merge!(kw_choices)
|
82
|
-
.transform_keys! { |k| [k.to_s[0], ' '].max }
|
83
|
-
.transform_values! { |v| v.to_s.tr("\r\n\t", ' ') }
|
84
|
-
end
|
86
|
+
CHOICE_MARK = Ansi[:bold, 34]
|
87
|
+
private_constant :CHOICE_MARK
|
85
88
|
end
|
86
89
|
end
|
87
90
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'element'
|
4
|
+
|
5
|
+
module NattyUI
|
6
|
+
module Features
|
7
|
+
# Creates a quotation section and prints given arguments as lines
|
8
|
+
# into the section.
|
9
|
+
#
|
10
|
+
# @param (see #section)
|
11
|
+
# @yieldparam (see #section)
|
12
|
+
# @return [Object] the result of the code block
|
13
|
+
# @return [Wrapper::Quote] itself, when no code block is given
|
14
|
+
def quote(*args, &block) = _section(:Quote, args, prefix: '▍ ', &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
class Wrapper
|
18
|
+
#
|
19
|
+
# A quotation {Section}.
|
20
|
+
#
|
21
|
+
# @see Features#quote
|
22
|
+
class Quote < Section
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -23,21 +23,32 @@ module NattyUI
|
|
23
23
|
class Request < Element
|
24
24
|
protected
|
25
25
|
|
26
|
-
def
|
27
|
-
|
28
|
-
NattyUI.
|
26
|
+
def call(question, password)
|
27
|
+
draw(question)
|
28
|
+
return NattyUI.in_stream.getpass if password
|
29
|
+
NattyUI.in_stream.gets(chomp: true)
|
30
|
+
rescue Interrupt, SystemCallError
|
31
|
+
nil
|
29
32
|
ensure
|
30
|
-
|
33
|
+
(wrapper = @parent.wrapper).ansi? and
|
34
|
+
(wrapper.stream << ANSI_FINISH).flush
|
31
35
|
end
|
32
36
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
37
|
+
def draw(question)
|
38
|
+
wrapper = @parent.wrapper
|
39
|
+
glyph = wrapper.glyph(:query)
|
40
|
+
@parent.print(
|
41
|
+
question,
|
42
|
+
prefix: "#{glyph} #{Ansi[255]}",
|
43
|
+
prefix_width: NattyUI.display_width(glyph) + 1,
|
44
|
+
suffix_width: 0
|
45
|
+
)
|
46
|
+
(wrapper.stream << ANSI_PREFIX).flush if wrapper.ansi?
|
38
47
|
end
|
39
48
|
|
40
|
-
|
49
|
+
ANSI_PREFIX = Ansi::RESET + Ansi::ITALIC
|
50
|
+
ANSI_FINISH = Ansi::RESET + Ansi::LINE_PREVIOUS + Ansi::LINE_ERASE
|
51
|
+
private_constant :ANSI_PREFIX, :ANSI_FINISH
|
41
52
|
end
|
42
53
|
end
|
43
54
|
end
|
@@ -7,24 +7,16 @@ module NattyUI
|
|
7
7
|
# Creates a default section and prints given arguments as lines
|
8
8
|
# into the section.
|
9
9
|
#
|
10
|
-
# @param [Array<#to_s>] args objects to print
|
10
|
+
# @param [Array<#to_s>] args optional objects to print
|
11
|
+
# @param [String] prefix used for each printed line
|
12
|
+
# @param [String] suffix used for each printed line
|
11
13
|
# @yieldparam [Wrapper::Section] section the created section
|
12
14
|
# @return [Object] the result of the code block
|
13
15
|
# @return [Wrapper::Section] itself, when no code block is given
|
14
|
-
def section(*args, &block)
|
15
|
-
_section(
|
16
|
+
def section(*args, prefix: ' ', suffix: ' ', &block)
|
17
|
+
_section(:Section, args, prefix: prefix, suffix: suffix, &block)
|
16
18
|
end
|
17
19
|
alias sec section
|
18
|
-
|
19
|
-
# Creates a quotation section and prints given arguments as lines
|
20
|
-
# into the section.
|
21
|
-
#
|
22
|
-
# @param (see #section)
|
23
|
-
# @yieldparam (see #section)
|
24
|
-
# @return (see #section)
|
25
|
-
def quote(*args, &block)
|
26
|
-
_section(self, :Section, args, prefix: '▍ ', prefix_attr: 39, &block)
|
27
|
-
end
|
28
20
|
end
|
29
21
|
|
30
22
|
class Wrapper
|
@@ -34,47 +26,57 @@ module NattyUI
|
|
34
26
|
# A section can contain other elements and sections.
|
35
27
|
#
|
36
28
|
# @see Features#section
|
37
|
-
# @see Features#quote
|
38
29
|
class Section < Element
|
39
|
-
#
|
40
|
-
|
41
|
-
|
42
|
-
|
30
|
+
# @return [Integer] available columns count within the section
|
31
|
+
def available_width
|
32
|
+
@available_width ||=
|
33
|
+
@parent.available_width - @prefix_width - @suffix_width
|
34
|
+
end
|
43
35
|
|
44
|
-
# Print given arguments
|
45
|
-
# Optionally limit the line width to given `max_width`.
|
36
|
+
# Print given arguments line-wise into the section.
|
46
37
|
#
|
47
|
-
# @overload puts(
|
38
|
+
# @overload puts(...)
|
48
39
|
# @param [#to_s] ... objects to print
|
49
|
-
# @param [Integer, nil] max_width maximum line width
|
50
|
-
# @comment @param [#to_s, nil] prefix line prefix
|
51
|
-
# @comment @param [#to_s, nil] suffix line suffix
|
52
40
|
# @return [Section] itself
|
53
|
-
def puts(*args,
|
41
|
+
def puts(*args, **kwargs)
|
54
42
|
return self if @status
|
55
43
|
@parent.puts(
|
56
44
|
*args,
|
57
|
-
|
58
|
-
|
59
|
-
|
45
|
+
**kwargs.merge!(
|
46
|
+
prefix: "#{@prefix}#{kwargs[:prefix]}",
|
47
|
+
prefix_width: @prefix_width + kwargs[:prefix_width].to_i,
|
48
|
+
suffix: "#{kwargs[:suffix]}#{@suffix}",
|
49
|
+
suffix_width: @suffix_width + kwargs[:suffix_width].to_i
|
50
|
+
)
|
60
51
|
)
|
61
52
|
self
|
62
53
|
end
|
63
|
-
alias add puts
|
64
54
|
|
65
|
-
#
|
55
|
+
# Print given arguments into the section.
|
66
56
|
#
|
67
|
-
# @
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
57
|
+
# @overload print(...)
|
58
|
+
# @param [#to_s] ... objects to print
|
59
|
+
# @return [Section] itself
|
60
|
+
def print(*args, **kwargs)
|
61
|
+
return self if @status
|
62
|
+
@parent.print(
|
63
|
+
*args,
|
64
|
+
**kwargs.merge!(
|
65
|
+
prefix: "#{@prefix}#{kwargs[:prefix]}",
|
66
|
+
prefix_width: @prefix_width + kwargs[:prefix_width].to_i,
|
67
|
+
suffix: "#{kwargs[:suffix]}#{@suffix}",
|
68
|
+
suffix_width: @suffix_width + kwargs[:suffix_width].to_i
|
69
|
+
)
|
74
70
|
)
|
75
71
|
self
|
76
72
|
end
|
77
73
|
|
74
|
+
# Add at least one empty line
|
75
|
+
#
|
76
|
+
# @param [#to_i] lines count of lines
|
77
|
+
# @return [Section] itself
|
78
|
+
def space(lines = 1) = puts("\n" * [1, lines.to_i].max)
|
79
|
+
|
78
80
|
# @note The screen manipulation is only available in ANSI mode see {#ansi?}
|
79
81
|
#
|
80
82
|
# Resets the part of the screen written below the current output line when
|
@@ -90,12 +92,26 @@ module NattyUI
|
|
90
92
|
# @return [Object] block result
|
91
93
|
def temporary = block_given? ? yield(self) : self
|
92
94
|
|
95
|
+
# @!visibility private
|
96
|
+
def inspect = @status ? "#{_to_s[..-2]} status=#{@status}>" : _to_s
|
97
|
+
|
98
|
+
# @!visibility private
|
99
|
+
def rcol = @parent.rcol - @suffix_width
|
100
|
+
|
93
101
|
protected
|
94
102
|
|
95
|
-
def initialize(
|
96
|
-
|
103
|
+
def initialize(
|
104
|
+
parent,
|
105
|
+
prefix:,
|
106
|
+
prefix_width: NattyUI.display_width(prefix),
|
107
|
+
suffix: nil,
|
108
|
+
suffix_width: NattyUI.display_width(suffix)
|
109
|
+
)
|
110
|
+
super(parent)
|
97
111
|
@prefix = prefix
|
98
112
|
@suffix = suffix
|
113
|
+
@prefix_width = prefix_width
|
114
|
+
@suffix_width = suffix_width
|
99
115
|
end
|
100
116
|
end
|
101
117
|
end
|