infobar 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,131 @@
1
+ require 'term/ansicolor'
2
+ require 'stringio'
3
+ require 'infobar/frequency'
4
+
5
+ class Infobar::Display
6
+ class << self
7
+ prepend Tins::Delegate
8
+ end
9
+ include Term::ANSIColor
10
+
11
+ def self.default_style
12
+ {
13
+ done_fill: ?░,
14
+ done_fg_color: 22,
15
+ done_bg_color: 40,
16
+ todo_fill: ' ',
17
+ todo_fg_color: 40,
18
+ todo_bg_color: 22,
19
+ }
20
+ end
21
+
22
+ def initialize
23
+ self.output = $stdout
24
+ self.input = $stdin
25
+ self.frequency = 0.05
26
+ @show = true
27
+ self.style = self.class.default_style
28
+ end
29
+
30
+ def frequency=(duration)
31
+ @frequency = Infobar::Frequency.new(duration)
32
+ end
33
+
34
+ attr_reader :frequency
35
+
36
+ attr_accessor :show
37
+
38
+ def show?
39
+ @show
40
+ end
41
+
42
+ def output=(io)
43
+ @output = io
44
+ @output.ask_and_send(:respond_to?, :sync=, true)
45
+ end
46
+
47
+ def output
48
+ if show?
49
+ @output
50
+ else
51
+ NULL
52
+ end
53
+ end
54
+
55
+ attr_writer :input
56
+
57
+ def input
58
+ if show?
59
+ @input
60
+ else
61
+ NULL
62
+ end
63
+ end
64
+
65
+ def style
66
+ self.class.default_style.each_key.each_with_object({}) do |attribute, h|
67
+ h[attribute] = instance_variable_get "@#{attribute}"
68
+ end
69
+ end
70
+
71
+ def style=(new_style)
72
+ self.class.default_style.each_key do |attribute|
73
+ value = new_style[attribute]
74
+ value.nil? and next
75
+ instance_variable_set "@#{attribute}", value
76
+ end
77
+ self
78
+ end
79
+
80
+ def update(message:, progressed:, force: false, **options)
81
+ force and @frequency.reset
82
+ @frequency.call do
83
+ message = Infobar.convert_to_message(message)
84
+ carriage_return
85
+ self.style = options
86
+ cols = columns
87
+ todo = message.to_str.center cols, replace_character
88
+ done = todo.slice!(0, (progressed * cols))
89
+ done.gsub!(replace_character, @done_fill[0])
90
+ todo.gsub!(replace_character, @todo_fill[0])
91
+ output << color(@done_fg_color, on_color(@done_bg_color, done)) +
92
+ color(@todo_fg_color, on_color(@todo_bg_color, todo))
93
+ end
94
+ end
95
+
96
+ delegate :called, to: :frequency, as: :updates
97
+
98
+ def reset
99
+ clear
100
+ @frequency.reset
101
+ self.style = self.class.default_style
102
+ self
103
+ end
104
+
105
+ def clear
106
+ carriage_return
107
+ output << ' ' * columns
108
+ carriage_return
109
+ self
110
+ end
111
+
112
+ def carriage_return
113
+ output << ?\r
114
+ self
115
+ end
116
+
117
+ def newline
118
+ output << $/
119
+ self
120
+ end
121
+
122
+ private
123
+
124
+ def replace_character
125
+ "\uFFFC"
126
+ end
127
+
128
+ def columns
129
+ Tins::Terminal.columns
130
+ end
131
+ end
@@ -0,0 +1,15 @@
1
+ class Infobar::Duration
2
+ def initialize(value, format: nil)
3
+ duration = Tins::Duration.new(value)
4
+ @string =
5
+ if format
6
+ duration.format(format)
7
+ else
8
+ duration
9
+ end.to_s
10
+ end
11
+
12
+ def to_s
13
+ @string
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ module Infobar::FancyInterface
2
+ def ~
3
+ reset
4
+ end
5
+
6
+ def +@
7
+ progress by: 1
8
+ end
9
+
10
+ def +(by)
11
+ progress by: by
12
+ end
13
+
14
+ def coerce(other)
15
+ return self, other
16
+ end
17
+
18
+ def <<(item)
19
+ progress by: 1
20
+ end
21
+
22
+ def add(*items)
23
+ progress by: items.size
24
+ end
25
+ alias push add
26
+ end
@@ -0,0 +1,33 @@
1
+ class Infobar::Frequency
2
+ def initialize(duration)
3
+ @duration = duration.to_f
4
+ @called = 0
5
+ end
6
+
7
+ attr_reader :duration
8
+
9
+ attr_reader :called
10
+
11
+ def update(now: Time.now)
12
+ @update = now
13
+ @called += 1
14
+ end
15
+
16
+ def call(&block)
17
+ now = Time.now
18
+ if !@update || now - @update > @duration
19
+ update now: now
20
+ block.call
21
+ end
22
+ end
23
+
24
+ def reset
25
+ @update = nil
26
+ @called = 0
27
+ self
28
+ end
29
+
30
+ def to_s
31
+ @duration.to_s
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ module Infobar::InputOutput
2
+ def newline
3
+ @display.newline
4
+ self
5
+ end
6
+
7
+ def clear
8
+ @display.clear
9
+ self
10
+ end
11
+
12
+ %i[ print printf putc puts ].each do |method|
13
+ define_method(method) do |*a, &b|
14
+ @display.clear
15
+ @display.output.__send__(method, *a, &b)
16
+ end
17
+ end
18
+
19
+ %i[ gets readline readlines ].each do |method|
20
+ define_method(method) do |*a, &b|
21
+ @display.clear
22
+ @display.input.__send__(method, *a, &b)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,154 @@
1
+ require 'infobar/spinner'
2
+ require 'infobar/duration'
3
+ require 'infobar/number'
4
+
5
+ class Infobar::Message
6
+ class << self
7
+ prepend Tins::Delegate
8
+
9
+ def register(directive, **opts, &block)
10
+ directives.key?(directive) and
11
+ warn "Overwriting old directive #{directive}."
12
+ directives[directive] = block
13
+ directive_default_options[directive] = opts
14
+ self
15
+ end
16
+
17
+ def directives
18
+ @directives ||= {}
19
+ end
20
+
21
+ def directive_default_options
22
+ @directive_default_options ||= {}
23
+ end
24
+ end
25
+
26
+ # current counter value of items
27
+ register '%c' do
28
+ Infobar.counter.current
29
+ end
30
+
31
+ # total counter value of items
32
+ register '%t' do
33
+ Infobar.counter.total
34
+ end
35
+
36
+ # number of items to go
37
+ register '%T' do
38
+ Infobar.counter.to_go
39
+ end
40
+
41
+ # label of progress bar
42
+ register '%l' do
43
+ Infobar.label
44
+ end
45
+
46
+ # progressed so far as a float in 0..1
47
+ register('%p', format: '%.3f') do |directive, opts|
48
+ Infobar::Number.new(Infobar.counter.progressed, **opts)
49
+ end
50
+
51
+ # not yet progressed as a float in 0..1
52
+ register('%q', format: '%1.3f') do |directive, opts|
53
+ Infobar::Number.new(1 - Infobar.counter.progressed, **opts)
54
+ end
55
+
56
+ # progressed as a percentage float in 0..100
57
+ register('%P', format: '%3.2f') do |directive, opts|
58
+ Infobar::Number.new(100 * Infobar.counter.progressed, **opts)
59
+ end
60
+
61
+ # not yet progressed as a percentage float in 0..100
62
+ register('%Q', format: '%2.2f') do |directive, opts|
63
+ Infobar::Number.new(100 - 100 * Infobar.counter.progressed, **opts)
64
+ end
65
+
66
+ # time elapsed as a duration
67
+ register('%te', format: '%h:%m:%s') do |directive, opts|
68
+ Infobar::Duration.new(Infobar.counter.time_elapsed, **opts)
69
+ end
70
+
71
+ # total time as a duration
72
+ register('%tt', format: '%h:%m:%s') do |directive, opts|
73
+ Infobar::Duration.new(Infobar.counter.total_time, **opts)
74
+ end
75
+
76
+ # ETA as a duration
77
+ register('%e', format: '%h:%m:%s') do |directive, opts|
78
+ Infobar::Duration.new(Infobar.counter.time_remaining, **opts)
79
+ end
80
+
81
+ # ETA as a datetime
82
+ register('%E', format: '%T') do |directive, opts|
83
+ if format = opts[:format]
84
+ Infobar.counter.eta.strftime(format)
85
+ else
86
+ Infobar.counter.eta
87
+ end
88
+ end
89
+
90
+ # rate with or without units
91
+ register('%r', unit: nil, prefix: 1000, format: '%f %U') do |directive, opts|
92
+ if opts[:unit]
93
+ Tins::Unit.format(Infobar.counter.rate, **opts)
94
+ else
95
+ Infobar.counter.rate
96
+ end
97
+ end
98
+
99
+ # average time as a duration
100
+ register('%a', format: '%m:%s.%f') do |directive, opts|
101
+ Infobar::Duration.new(Infobar.counter.average_time, **opts)
102
+ end
103
+
104
+ # spinner
105
+ register('%s', frames: :pipe, message: ?✓) do |directive, opts|
106
+ if Infobar.finished?
107
+ if message = opts[:message]
108
+ Infobar.convert_to_message(message).to_str
109
+ end
110
+ elsif opts[:random]
111
+ Infobar::Spinner.new(opts[:frames]).spin(:random)
112
+ else
113
+ Infobar::Spinner.new(opts[:frames]).spin(Infobar.display.updates)
114
+ end
115
+ end
116
+
117
+ # literal percentag character
118
+ register '%%' do
119
+ ?%
120
+ end
121
+
122
+ def initialize(opts = {})
123
+ @format = opts.delete(:format) or
124
+ raise ArgumentError, 'format option required'
125
+ @opts = opts.each_with_object({}) { |(k, v), h| h[k.to_s] = v }
126
+ end
127
+
128
+ attr_reader :opts
129
+
130
+ delegate :directives, to: self
131
+
132
+ delegate :directive_default_options, to: self
133
+
134
+ def opts_for(directive)
135
+ @opts.fetch(directive, directive_default_options[directive])
136
+ end
137
+
138
+ def to_str
139
+ keys = directives.keys.sort_by { |k| -k.size }
140
+ @format.gsub(/(?<!%)(#{keys * ?|})/) do
141
+ directives[$1].call($1, opts_for($1))
142
+ end
143
+ end
144
+
145
+ attr_reader :format
146
+
147
+ alias to_s format
148
+
149
+ def to_hash
150
+ {
151
+ format: format,
152
+ }.merge(@opts)
153
+ end
154
+ end
@@ -0,0 +1,10 @@
1
+ class Infobar::Number
2
+ def initialize(value, format: nil)
3
+ duration = Tins::Duration.new(value)
4
+ @string = format ? (format % value) : value.to_s
5
+ end
6
+
7
+ def to_s
8
+ @string
9
+ end
10
+ end
@@ -0,0 +1,51 @@
1
+ class Infobar::Spinner
2
+ PREDEFINED = {
3
+ pipe: %w[ | / – \\ ],
4
+ arrow: %w[ ↑ ↗ → ↘ ↓ ↙ ← ↖ ],
5
+ bar1: %w[ ▁ ▂ ▃ ▄ ▅ ▆ ▇ █ ▇ ▆ ▅ ▄ ▃ ▂ ],
6
+ bar2: %w[ █ ▉ ▊ ▋ ▌ ▍ ▎ ▏ ▎ ▍ ▌ ▋ ▊ ▉ ],
7
+ braille7: %w[ ⣾ ⣽ ⣻ ⢿ ⡿ ⣟ ⣯ ⣷ ],
8
+ braille1: %w[ ⠁ ⠂ ⠄ ⡀ ⢀ ⠠ ⠐ ⠈ ],
9
+ square1: %w[ ▖ ▘ ▝ ▗ ],
10
+ square2: %w[ ◰ ◳ ◲ ◱ ],
11
+ tetris: %w[ ▌ ▀ ▐▄ ],
12
+ eyes: %w[ ◡◡ ⊙⊙ ◠◠ ],
13
+ corners: %w[ ┤ ┘ ┴ └ ├ ┌ ┬ ┐ ],
14
+ triangle: %w[ ◢ ◣ ◤ ◥ ],
15
+ circle1: %w[ ◴ ◷ ◶ ◵ ],
16
+ circle2: %w[ ◐ ◓ ◑ ◒ ],
17
+ circle3: %w[ ◜ ◝ ◞ ◟ ],
18
+ cross: %w[ + × ],
19
+ cylon: [ '● ', ' ● ', ' ●', ' ● ' ],
20
+ pacman: [ 'ᗧ∙∙∙∙●', ' O∙∙∙●', ' ᗧ∙∙●',' O∙●', ' ᗧ●', 'ᗣ O', ' ᗣ ᗤ', ' ᗣ O ', ' ᗣ ᗤ ', ' ᗣO ', ' ᗤ ', 'O ∞ ', 'ᗧ ∞ ', 'O ' ],
21
+ asteroids: [ 'ᐊ ◍', 'ᐃ ◍', 'ᐓ ◍', 'ᐅ· ◍', 'ᐅ ·◍', 'ᐅ ○', 'ᐅ ◌', 'ᐁ ' ],
22
+ }
23
+
24
+ def initialize(frames = nil)
25
+ @frames =
26
+ case frames
27
+ when Array
28
+ frames
29
+ when Symbol
30
+ PREDEFINED.fetch(frames) do
31
+ |k| raise KeyError, "frames #{k} not predefined"
32
+ end
33
+ when nil
34
+ PREDEFINED[:pipe]
35
+ end
36
+ end
37
+
38
+ def spin(count)
39
+ @string =
40
+ if count == :random
41
+ @frames[rand(@frames.size)]
42
+ else
43
+ @frames[count % @frames.size]
44
+ end
45
+ self
46
+ end
47
+
48
+ def to_s
49
+ @string
50
+ end
51
+ end