natty-ui 0.34.0 → 1.0.2
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 +0 -1
- data/README.md +6 -6
- data/examples/24bit-colors.rb +9 -5
- data/examples/3bit-colors.rb +7 -7
- data/examples/8bit-colors.rb +5 -5
- data/examples/attributes.rb +2 -3
- data/examples/elements.rb +9 -6
- data/examples/examples.rb +9 -9
- data/examples/frames.rb +31 -0
- data/examples/hbars.rb +6 -3
- data/examples/info.rb +13 -10
- data/examples/key-codes.rb +8 -9
- data/examples/ls.rb +24 -22
- data/examples/named-colors.rb +4 -3
- data/examples/sections.rb +27 -17
- data/examples/select.rb +28 -0
- data/examples/sh.rb +25 -7
- data/examples/tables.rb +19 -37
- data/examples/tasks.rb +32 -22
- data/examples/vbars.rb +5 -3
- data/lib/natty-ui/dumb_progress.rb +68 -0
- data/lib/natty-ui/element.rb +64 -65
- data/lib/natty-ui/features.rb +773 -872
- data/lib/natty-ui/frame.rb +87 -0
- data/lib/natty-ui/helper/table.rb +1376 -0
- data/lib/natty-ui/margin.rb +83 -0
- data/lib/natty-ui/progress.rb +116 -149
- data/lib/natty-ui/renderer/bars.rb +93 -0
- data/lib/natty-ui/renderer/choice.rb +56 -0
- data/lib/natty-ui/renderer/dumb_choice.rb +34 -0
- data/lib/natty-ui/renderer/dumb_select.rb +60 -0
- data/lib/natty-ui/renderer/dumb_shell_runner.rb +19 -0
- data/lib/natty-ui/renderer/heading.rb +26 -0
- data/lib/natty-ui/renderer/horizontal_rule.rb +32 -0
- data/lib/natty-ui/{ls_renderer.rb → renderer/ls.rb} +15 -27
- data/lib/natty-ui/renderer/mark.rb +13 -0
- data/lib/natty-ui/renderer/quote.rb +13 -0
- data/lib/natty-ui/renderer/select.rb +63 -0
- data/lib/natty-ui/renderer/shell.rb +15 -0
- data/lib/natty-ui/renderer/shell_runner.rb +29 -0
- data/lib/natty-ui/renderer/table_renderer.rb +429 -0
- data/lib/natty-ui/section.rb +142 -41
- data/lib/natty-ui/task.rb +39 -27
- data/lib/natty-ui/temporary.rb +27 -14
- data/lib/natty-ui/utils/border.rb +139 -0
- data/lib/natty-ui/utils/str_const.rb +62 -0
- data/lib/natty-ui/utils/utils.rb +47 -0
- data/lib/natty-ui/version.rb +1 -1
- data/lib/natty-ui.rb +87 -30
- metadata +31 -28
- data/examples/cols.rb +0 -38
- data/examples/illustration.rb +0 -60
- data/examples/options.rb +0 -28
- data/examples/themes.rb +0 -51
- data/lib/natty-ui/attributes.rb +0 -593
- data/lib/natty-ui/choice.rb +0 -67
- data/lib/natty-ui/dumb_choice.rb +0 -47
- data/lib/natty-ui/dumb_options.rb +0 -64
- data/lib/natty-ui/framed.rb +0 -51
- data/lib/natty-ui/hbars_renderer.rb +0 -66
- data/lib/natty-ui/options.rb +0 -78
- data/lib/natty-ui/shell_renderer.rb +0 -91
- data/lib/natty-ui/table.rb +0 -325
- data/lib/natty-ui/table_renderer.rb +0 -165
- data/lib/natty-ui/theme.rb +0 -403
- data/lib/natty-ui/utils.rb +0 -111
- data/lib/natty-ui/vbars_renderer.rb +0 -49
- data/lib/natty-ui/width_finder.rb +0 -137
- data/natty-ui.gemspec +0 -34
data/examples/tasks.rb
CHANGED
|
@@ -2,51 +2,61 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative '../lib/natty-ui'
|
|
4
4
|
|
|
5
|
-
ui.
|
|
5
|
+
ui.begin '[b]ᓚᕠᗢ NattyUI[/b] [i green]Tasks' do
|
|
6
6
|
ui.space
|
|
7
7
|
ui.puts <<~TEXT, eol: false
|
|
8
|
-
Tasks are sections that are
|
|
9
|
-
message.
|
|
10
|
-
consist of
|
|
11
|
-
exception to this, some elements can be “pinned” as
|
|
8
|
+
[i]Tasks[/i] are sections that are either completed successfully or result
|
|
9
|
+
in an error message. Upon successful completion, their content is displayed
|
|
10
|
+
only temporarily and may consist of any other elements, including additional
|
|
11
|
+
(sub)tasks. As an exception to this, some elements can be “pinned” as
|
|
12
|
+
permanent content.
|
|
12
13
|
TEXT
|
|
13
14
|
|
|
14
15
|
# to simulate some work:
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
simulate =
|
|
17
|
+
Module.new do
|
|
18
|
+
if ENV.key?('NO_SLEEP')
|
|
19
|
+
def self.work = nil
|
|
20
|
+
def self.heavy_work = nil
|
|
21
|
+
else
|
|
22
|
+
def self.work = sleep(0.2)
|
|
23
|
+
def self.heavy_work = sleep(1)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
17
26
|
|
|
18
27
|
ui.space
|
|
19
|
-
ui.task '
|
|
20
|
-
ui.puts 'This is
|
|
28
|
+
ui.task 'Update Reading List' do
|
|
29
|
+
ui.puts 'This is an example which actualizes the book reading list.'
|
|
21
30
|
|
|
22
31
|
ui.task 'Connect to Library' do
|
|
23
|
-
|
|
32
|
+
simulate.work
|
|
24
33
|
ui.mark 'Server Found', mark: :checkmark
|
|
25
|
-
ui.task('Login...') {
|
|
34
|
+
ui.task('Login...') { simulate.heavy_work }
|
|
26
35
|
end
|
|
27
36
|
|
|
28
|
-
ui.task('Request New Books') {
|
|
37
|
+
ui.task('Request New Books') { simulate.heavy_work }
|
|
29
38
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
39
|
+
ui.progress('Loading Books...') do |progress|
|
|
40
|
+
while progress.value < 17
|
|
41
|
+
simulate.work
|
|
42
|
+
progress.step
|
|
43
|
+
end
|
|
34
44
|
end
|
|
35
|
-
|
|
45
|
+
ui.ok '17 Books Loaded'
|
|
36
46
|
|
|
37
|
-
ui.task('Disconnect from Library') {
|
|
47
|
+
ui.task('Disconnect from Library') { simulate.heavy_work }
|
|
38
48
|
|
|
39
|
-
ui.progress 'Read Cover Images', max:
|
|
49
|
+
ui.progress 'Read Cover Images', max: 13 do |progress|
|
|
40
50
|
while progress.value < progress.max
|
|
41
|
-
|
|
51
|
+
simulate.work
|
|
42
52
|
progress.step
|
|
43
53
|
end
|
|
44
54
|
end
|
|
45
55
|
|
|
46
56
|
ui.pin 'New Books Marked', mark: :checkmark
|
|
47
57
|
|
|
48
|
-
ui.task('Optimize Database') {
|
|
58
|
+
ui.task('Optimize Database') { simulate.heavy_work }
|
|
49
59
|
|
|
50
|
-
ui.task('Remove Dust') {
|
|
60
|
+
ui.task('Remove Dust') { simulate.heavy_work }
|
|
51
61
|
end
|
|
52
62
|
end
|
data/examples/vbars.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative '../lib/natty-ui'
|
|
4
4
|
|
|
5
|
-
ui.
|
|
5
|
+
ui.begin '[b]ᓚᕠᗢ NattyUI[/b] [i green]Print Vertical Bars' do
|
|
6
6
|
values = [
|
|
7
7
|
11.97,
|
|
8
8
|
14.35,
|
|
@@ -27,13 +27,15 @@ ui.message '[b]ᓚᕠᗢ NattyUI[/b] [i green]Print Vertical Bars[/]' do
|
|
|
27
27
|
].freeze
|
|
28
28
|
|
|
29
29
|
ui.space
|
|
30
|
-
ui.vbars values, style: :blue
|
|
30
|
+
ui.vbars values, style: :blue, bar_width: :auto
|
|
31
31
|
ui.puts 'NattyUI can quick dump values as vertical bars.'
|
|
32
32
|
|
|
33
33
|
ui.space
|
|
34
|
-
ui.vbars values, style: :green, normalize: true
|
|
34
|
+
ui.vbars values, style: :green, normalize: true
|
|
35
35
|
ui.puts <<~INFO, eol: false
|
|
36
36
|
These are the same values but [i]normalized[/i]
|
|
37
37
|
and printed with a fixed bar width.
|
|
38
38
|
INFO
|
|
39
|
+
|
|
40
|
+
ui.space
|
|
39
41
|
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'element'
|
|
4
|
+
|
|
5
|
+
module NattyUI
|
|
6
|
+
# @private
|
|
7
|
+
class DumbProgress < Element
|
|
8
|
+
# @return [Numeric]
|
|
9
|
+
attr_reader :max
|
|
10
|
+
|
|
11
|
+
# @return [Numeric]
|
|
12
|
+
attr_reader :value
|
|
13
|
+
|
|
14
|
+
# @attribute [w] value
|
|
15
|
+
def value=(val)
|
|
16
|
+
return if @done != 0
|
|
17
|
+
return if @value == (val = @max ? val.clamp(0, @max) : [0, val].max)
|
|
18
|
+
@value = val
|
|
19
|
+
draw_bar if @max
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def update(*title, value: nil, **)
|
|
23
|
+
return if @done != 0
|
|
24
|
+
draw_title(*title, **) unless title.empty?
|
|
25
|
+
if value
|
|
26
|
+
self.value = value
|
|
27
|
+
elsif @max
|
|
28
|
+
draw_bar
|
|
29
|
+
end
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def step(*, count: 1, **) = update(*, value: value + count, **)
|
|
34
|
+
|
|
35
|
+
# @private
|
|
36
|
+
def puts(...) = @done == 0 ? super : self
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def done
|
|
41
|
+
@done += 1
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def draw_bar
|
|
45
|
+
diff = @value / @max.to_f
|
|
46
|
+
return if (fill = '█' * (20 * diff)).empty? || @last == fill
|
|
47
|
+
percent = diff == 1 ? '100.0%' : format('%.2f%%', 100 * diff)
|
|
48
|
+
percent = "0#{percent}" if percent.size < 6
|
|
49
|
+
@parent.puts(
|
|
50
|
+
"#{percent}▕#{@last = fill}#{'░' * (20 - fill.size)}▏",
|
|
51
|
+
prefix: @prefix
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def draw_title(*, **options)
|
|
56
|
+
options[:cprefix] = Utils.mark[:active]
|
|
57
|
+
options[:prefix] = @prefix = Utils.mark[:none]
|
|
58
|
+
@parent.puts(*, **options)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def initialize(parent, max, *title, **)
|
|
62
|
+
super(parent)
|
|
63
|
+
@value = 0
|
|
64
|
+
@max = [0, max].max if max
|
|
65
|
+
draw_title(*title, **) unless title.empty?
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
data/lib/natty-ui/element.rb
CHANGED
|
@@ -3,32 +3,80 @@
|
|
|
3
3
|
require_relative 'features'
|
|
4
4
|
|
|
5
5
|
module NattyUI
|
|
6
|
-
# Base
|
|
6
|
+
# Base class for all UI container elements.
|
|
7
7
|
#
|
|
8
|
+
# Instances are never created directly; they are returned (or yielded) by the
|
|
9
|
+
# section-opening methods on {Features}: {#section}, {#frame},
|
|
10
|
+
# {#task}, {#progress}, {#margin}, {#temporary}, and their typed variants.
|
|
11
|
+
#
|
|
12
|
+
# Every `Element` includes {Features}, so all output and section methods are
|
|
13
|
+
# available on the element itself.
|
|
14
|
+
#
|
|
15
|
+
# @example Using an element returned without a block
|
|
16
|
+
# frm = ui.frame 'Progress'
|
|
17
|
+
# frm.puts 'Loading…'
|
|
18
|
+
# frm.end # closes the frame
|
|
19
|
+
#
|
|
20
|
+
# @example The element is also yielded inside a block
|
|
21
|
+
# ui.section 'Summary' do |sec|
|
|
22
|
+
# sec.ok 'Done'
|
|
23
|
+
# end
|
|
8
24
|
class Element
|
|
9
25
|
include Features
|
|
10
26
|
|
|
27
|
+
#
|
|
28
|
+
# @!group Section elements
|
|
29
|
+
#
|
|
30
|
+
|
|
31
|
+
# Closes this element and returns the parent element.
|
|
32
|
+
#
|
|
33
|
+
# Calling `end` on an already-closed element is a no-op. All output
|
|
34
|
+
# methods on this element become no-ops after `end` is called.
|
|
35
|
+
#
|
|
36
|
+
# @example
|
|
37
|
+
# frm = ui.frame 'Results'
|
|
38
|
+
# ui.puts 'Content'
|
|
39
|
+
# frm.end # closes the frame, returns NattyUI (or the parent element)
|
|
40
|
+
#
|
|
41
|
+
# @return [Features] the parent element (or {NattyUI} if this was the
|
|
42
|
+
# outermost element)
|
|
43
|
+
def end = NattyUI.__send__(:_end, self)
|
|
44
|
+
|
|
45
|
+
#
|
|
46
|
+
# @!endgroup
|
|
47
|
+
#
|
|
48
|
+
|
|
11
49
|
# @private
|
|
12
|
-
def columns
|
|
50
|
+
def columns
|
|
51
|
+
ret = @parent.columns
|
|
52
|
+
ret -= @prefix.width if @prefix
|
|
53
|
+
@suffix ? ret - @suffix.width : ret
|
|
54
|
+
end
|
|
13
55
|
|
|
14
56
|
# @private
|
|
15
|
-
def puts(
|
|
57
|
+
def puts(*, **options)
|
|
16
58
|
if @prefix
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
59
|
+
pref = options[:prefix]
|
|
60
|
+
if (cpref = options[:cprefix]).nil? || cpref == true
|
|
61
|
+
options[:prefix] = pref ? @prefix + pref : @prefix
|
|
62
|
+
else
|
|
63
|
+
cpref = StrConst[cpref] unless StrConst === cpref
|
|
64
|
+
options[:cprefix] = @prefix + cpref
|
|
65
|
+
options[:prefix] = @prefix + (pref || StrConst.spacer(cpref.width))
|
|
24
66
|
end
|
|
25
67
|
end
|
|
26
68
|
if @suffix
|
|
27
|
-
|
|
28
|
-
|
|
69
|
+
suff = options[:suffix]
|
|
70
|
+
if (csuff = options[:csuffix]).nil? || csuff == true
|
|
71
|
+
options[:suffix] = suff ? suff + @suffix : @suffix
|
|
72
|
+
else
|
|
73
|
+
csuff = StrConst[csuff] unless StrConst === csuff
|
|
74
|
+
options[:csuffix] = csuff + @suffix
|
|
75
|
+
options[:suffix] = (suff || StrConst.spacer(csuff.width)) + @suffix
|
|
76
|
+
end
|
|
29
77
|
end
|
|
30
78
|
# options[:max_width] = @max_width if @max_width
|
|
31
|
-
@parent.puts(
|
|
79
|
+
@parent.puts(*, **options)
|
|
32
80
|
self
|
|
33
81
|
end
|
|
34
82
|
|
|
@@ -40,60 +88,11 @@ module NattyUI
|
|
|
40
88
|
|
|
41
89
|
private
|
|
42
90
|
|
|
91
|
+
def done = raise(NotImplementedError)
|
|
92
|
+
|
|
43
93
|
def initialize(parent)
|
|
44
94
|
@parent = parent
|
|
45
|
-
@
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# Methods for elements with status like {ProgressHelper}, {Section}, {Task}.
|
|
50
|
-
#
|
|
51
|
-
module WithStatus
|
|
52
|
-
# @return [Symbol, nil] element's current status
|
|
53
|
-
attr_reader :status
|
|
54
|
-
|
|
55
|
-
# @attribute [r] active?
|
|
56
|
-
# @return [true, false] whether the element is still active
|
|
57
|
-
def active? = @status.nil?
|
|
58
|
-
|
|
59
|
-
# @attribute [r] closed?
|
|
60
|
-
# @return [true, false] whether the element is closed
|
|
61
|
-
def closed? = !active?
|
|
62
|
-
|
|
63
|
-
# @attribute [r] closed?
|
|
64
|
-
# @return [true, false] whether the element is completed
|
|
65
|
-
def ok? = @state == :ok
|
|
66
|
-
|
|
67
|
-
# @attribute [r] failed?
|
|
68
|
-
# @return [true, false] whether the element is completed with failure
|
|
69
|
-
def failed? = @state == :failed
|
|
70
|
-
|
|
71
|
-
# Close the element.
|
|
72
|
-
#
|
|
73
|
-
# @param [#to_s] text optional message
|
|
74
|
-
# @return [Element] itself
|
|
75
|
-
def ok(*text)
|
|
76
|
-
return self if @state
|
|
77
|
-
text = [@title] if text.empty? && @title
|
|
78
|
-
_done(text)
|
|
79
|
-
@state = :ok
|
|
80
|
-
self
|
|
81
|
-
end
|
|
82
|
-
alias done ok
|
|
83
|
-
|
|
84
|
-
# Close the element with a failure.
|
|
85
|
-
#
|
|
86
|
-
# @param text [#to_s] optional message
|
|
87
|
-
# @yield optionally, when block is given
|
|
88
|
-
# @yieldparam failed [Section] see {Features.failed}
|
|
89
|
-
# @return [Element] itself
|
|
90
|
-
def failed(*text, &block)
|
|
91
|
-
return self if @state
|
|
92
|
-
_failed
|
|
93
|
-
@state = :failed
|
|
94
|
-
text = [@title] if text.empty? && @title
|
|
95
|
-
@parent.failed(*text, &block)
|
|
96
|
-
self
|
|
95
|
+
@done = 0
|
|
97
96
|
end
|
|
98
97
|
end
|
|
99
98
|
end
|