dry-cli-ui 0.6.0 → 0.7.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/CHANGELOG.md +24 -0
- data/README.md +246 -18
- data/examples/Gemfile.lock +20 -7
- data/lib/dry/cli/ui/configuration.rb +27 -2
- data/lib/dry/cli/ui/console.rb +31 -4
- data/lib/dry/cli/ui/flags.rb +143 -0
- data/lib/dry/cli/ui/invocation.rb +100 -0
- data/lib/dry/cli/ui/logging.rb +192 -0
- data/lib/dry/cli/ui/report.rb +16 -0
- data/lib/dry/cli/ui/reporting.rb +134 -0
- data/lib/dry/cli/ui/terminal.rb +19 -2
- data/lib/dry/cli/ui/version.rb +1 -1
- data/lib/dry/cli/ui/widgets/legend.rb +48 -0
- data/lib/dry/cli/ui/widgets/multi.rb +20 -3
- data/lib/dry/cli/ui/widgets/multi_progress.rb +36 -28
- data/lib/dry/cli/ui/widgets/outcome.rb +4 -2
- data/lib/dry/cli/ui/widgets/progress.rb +291 -43
- data/lib/dry/cli/ui/widgets/prompt.rb +6 -2
- data/lib/dry/cli/ui/widgets.rb +1 -0
- data/lib/dry/cli/ui.rb +76 -10
- data/sig/dry/cli/ui.rbs +91 -2
- metadata +49 -1
data/lib/dry/cli/ui.rb
CHANGED
|
@@ -34,14 +34,25 @@ module Dry
|
|
|
34
34
|
autoload :Configuration, File.expand_path("ui/configuration", __dir__)
|
|
35
35
|
autoload :Console, File.expand_path("ui/console", __dir__)
|
|
36
36
|
autoload :Duration, File.expand_path("ui/duration", __dir__)
|
|
37
|
+
autoload :Flags, File.expand_path("ui/flags", __dir__)
|
|
38
|
+
autoload :Invocation, File.expand_path("ui/invocation", __dir__)
|
|
37
39
|
autoload :Line, File.expand_path("ui/line", __dir__)
|
|
40
|
+
autoload :Logging, File.expand_path("ui/logging", __dir__)
|
|
41
|
+
autoload :Report, File.expand_path("ui/report", __dir__)
|
|
42
|
+
autoload :Reporting, File.expand_path("ui/reporting", __dir__)
|
|
38
43
|
autoload :Stop, File.expand_path("ui/stop", __dir__)
|
|
39
44
|
autoload :StatusBar, File.expand_path("ui/status_bar", __dir__)
|
|
40
45
|
autoload :Terminal, File.expand_path("ui/terminal", __dir__)
|
|
41
46
|
autoload :Theme, File.expand_path("ui/theme", __dir__)
|
|
42
47
|
autoload :Widgets, File.expand_path("ui/widgets", __dir__)
|
|
43
48
|
|
|
49
|
+
@started_at = ::Time.now
|
|
50
|
+
|
|
44
51
|
class << self
|
|
52
|
+
# @return [Time] when this gem loaded, which stands for when the process started. Stamps
|
|
53
|
+
# the file name of a report `-o` writes.
|
|
54
|
+
attr_reader :started_at
|
|
55
|
+
|
|
45
56
|
# Make process-wide settings. A block taking an argument receives the
|
|
46
57
|
# configuration; any other block runs against it.
|
|
47
58
|
#
|
|
@@ -69,23 +80,78 @@ module Dry
|
|
|
69
80
|
def reset!
|
|
70
81
|
@config = nil
|
|
71
82
|
end
|
|
83
|
+
|
|
84
|
+
# The IO beneath a dry-cli stream, or the stream itself when it is not one.
|
|
85
|
+
#
|
|
86
|
+
# Asks for the class rather than for `raw`, which `io/console` also defines on every IO, to
|
|
87
|
+
# put a terminal into raw mode.
|
|
88
|
+
#
|
|
89
|
+
# @param stream [IO, Dry::CLI::Stream]
|
|
90
|
+
# @return [IO]
|
|
91
|
+
def raw(stream)
|
|
92
|
+
defined?(Dry::CLI::Stream) && stream.is_a?(Dry::CLI::Stream) ? stream.raw : stream
|
|
93
|
+
end
|
|
72
94
|
end
|
|
73
95
|
|
|
74
|
-
# The console this command presents through.
|
|
75
|
-
# `out` and `err` when dry-cli has set them, and to `$stdout` and
|
|
76
|
-
# `$stderr` otherwise.
|
|
96
|
+
# The console this command presents through.
|
|
77
97
|
#
|
|
78
|
-
#
|
|
98
|
+
# In a dry-cli command it writes to the command's own `stdout` and `stderr`, and reads prompt
|
|
99
|
+
# answers from its `stdin`: the streams the CLI was called with. Under dry-cli 1.4 and
|
|
100
|
+
# earlier, which give a command only `out` and `err`, it writes to those and reads `$stdin`.
|
|
101
|
+
# Anywhere else it uses `$stdout`, `$stderr` and `$stdin`.
|
|
79
102
|
#
|
|
80
|
-
#
|
|
81
|
-
#
|
|
103
|
+
# The console is built again whenever those streams change. A command registered as an
|
|
104
|
+
# instance is used for every call to its CLI, each time with that call's streams, as when a
|
|
105
|
+
# test suite runs the CLI in-process with a StringIO per test.
|
|
106
|
+
#
|
|
107
|
+
# Configure the console by overriding {#ui_options}.
|
|
82
108
|
#
|
|
83
109
|
# @return [Dry::CLI::UI::Console]
|
|
84
110
|
def ui
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
)
|
|
111
|
+
streams = ui_streams
|
|
112
|
+
@ui = nil unless @ui_streams && streams.all? { |name, io| @ui_streams[name].equal?(io) }
|
|
113
|
+
@ui_streams = streams
|
|
114
|
+
@ui ||= Console.new(**streams, invocation: Invocation.for(self), **ui_options)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
private
|
|
118
|
+
|
|
119
|
+
# The streams {#ui} presents through, as keywords for {Console#initialize}.
|
|
120
|
+
#
|
|
121
|
+
# A dry-cli command gives its own public `stdout`, `stderr` and `stdin`. Its output streams
|
|
122
|
+
# render dry-cli's own styles; the console writes to the IO beneath them, since it decides
|
|
123
|
+
# colour for itself.
|
|
124
|
+
#
|
|
125
|
+
# @return [Hash{Symbol => IO}] `out:`, `err:` and `input:`
|
|
126
|
+
def ui_streams
|
|
127
|
+
{
|
|
128
|
+
out: UI.raw(ui_stream(:stdout, :out) || $stdout),
|
|
129
|
+
err: UI.raw(ui_stream(:stderr, :err) || $stderr),
|
|
130
|
+
input: respond_to?(:stdin) ? stdin : $stdin
|
|
131
|
+
}
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# One of the command's output streams: the public one, or the protected one dry-cli 1.4 and
|
|
135
|
+
# earlier set on a command it runs.
|
|
136
|
+
#
|
|
137
|
+
# @param name [Symbol] the public reader, `:stdout` or `:stderr`
|
|
138
|
+
# @param legacy_name [Symbol] the protected reader, `:out` or `:err`
|
|
139
|
+
# @return [IO, Dry::CLI::Stream, nil] nil when the command has neither, or was never run
|
|
140
|
+
def ui_stream(name, legacy_name)
|
|
141
|
+
return public_send(name) if respond_to?(name)
|
|
142
|
+
|
|
143
|
+
__send__(legacy_name) if respond_to?(legacy_name, true)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Options for {Console#initialize} other than its streams. Override it to configure the
|
|
147
|
+
# console {#ui} builds.
|
|
148
|
+
#
|
|
149
|
+
# @example
|
|
150
|
+
# def ui_options = { box_width: 72 }
|
|
151
|
+
#
|
|
152
|
+
# @return [Hash{Symbol => Object}]
|
|
153
|
+
def ui_options
|
|
154
|
+
{}
|
|
89
155
|
end
|
|
90
156
|
end
|
|
91
157
|
end
|
data/sig/dry/cli/ui.rbs
CHANGED
|
@@ -11,9 +11,69 @@ module Dry
|
|
|
11
11
|
|
|
12
12
|
def ui: () -> Console
|
|
13
13
|
|
|
14
|
+
private def ui_streams: () -> { out: untyped, err: untyped, input: untyped }
|
|
15
|
+
private def ui_stream: (Symbol name, Symbol legacy_name) -> untyped
|
|
16
|
+
private def ui_options: () -> Hash[Symbol, untyped]
|
|
17
|
+
|
|
18
|
+
def self.raw: (untyped stream) -> untyped
|
|
19
|
+
|
|
14
20
|
def self.configure: () { (Configuration config) -> void } -> Configuration
|
|
15
21
|
def self.config: () -> Configuration
|
|
16
22
|
def self.reset!: () -> void
|
|
23
|
+
def self.started_at: () -> Time
|
|
24
|
+
|
|
25
|
+
module Flags
|
|
26
|
+
OPTIONS: Hash[Symbol, Hash[Symbol, Hash[Symbol, untyped]]]
|
|
27
|
+
OPTIONAL_VALUES: Array[Symbol]
|
|
28
|
+
SWITCHES: Array[String]
|
|
29
|
+
|
|
30
|
+
def self.arguments: (Array[String] argv, ?switches: Array[String]) -> Array[String]
|
|
31
|
+
def self.switches: (untyped command) -> Array[String]
|
|
32
|
+
def flags: (*Symbol names) -> Array[Symbol]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class Invocation
|
|
36
|
+
attr_reader executable: String
|
|
37
|
+
attr_reader action: String?
|
|
38
|
+
attr_reader name: String
|
|
39
|
+
attr_reader started_at: Time
|
|
40
|
+
attr_reader directory: String
|
|
41
|
+
|
|
42
|
+
def self.new: (executable: String, action: String?, name: String, started_at: Time, directory: String) -> Invocation
|
|
43
|
+
def self.for: (?untyped command, ?program: String, ?started_at: Time, ?directory: String) -> Invocation
|
|
44
|
+
def self.root: (String directory) -> String
|
|
45
|
+
def basename: () -> String
|
|
46
|
+
def report_path: (String? value) -> String?
|
|
47
|
+
def log_path: (String? value) -> String?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class Report
|
|
51
|
+
def color?: () -> true
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
class Logging
|
|
55
|
+
LEVELS: Array[String]
|
|
56
|
+
FORMATS: Hash[String, Symbol]
|
|
57
|
+
INSPECT_LIMIT: Integer
|
|
58
|
+
FRAME_LIMIT: Integer
|
|
59
|
+
|
|
60
|
+
def self.level: (String | Symbol name) -> Symbol
|
|
61
|
+
def self.formatter: (String | Symbol name) -> untyped
|
|
62
|
+
def self.formats: () -> Array[String]
|
|
63
|
+
def self.logger: (String name) -> untyped
|
|
64
|
+
def self.locals: (Exception exception) -> Array[Hash[Symbol, untyped]]?
|
|
65
|
+
def self.record: (Exception exception) -> void
|
|
66
|
+
def initialize: (String? target, io: untyped, level: String | Symbol, format: String | Symbol) -> void
|
|
67
|
+
def run: [T] () { () -> T } -> T
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
module Reporting
|
|
71
|
+
def output: [T] (?String? value) { (untyped io) -> T } -> T
|
|
72
|
+
def logging: [T] (String? value, ?level: String | Symbol, ?format: String | Symbol) { () -> T } -> T
|
|
73
|
+
def with_flags: [T] (?output: String?, ?log: String?, ?log_level: String | Symbol, ?log_format: String | Symbol, **untyped) { (untyped io) -> T } -> T
|
|
74
|
+
def logger: () -> untyped
|
|
75
|
+
def log_exception: (Exception exception, ?String? message, ?level: String | Symbol) -> nil
|
|
76
|
+
end
|
|
17
77
|
|
|
18
78
|
class Configuration
|
|
19
79
|
type spinner_definition = Symbol | { interval: Numeric, frames: Array[String] | String }
|
|
@@ -27,6 +87,10 @@ module Dry
|
|
|
27
87
|
def bar_color=: (Symbol? value) -> Symbol?
|
|
28
88
|
def bar_background: (?Symbol? value) -> Symbol?
|
|
29
89
|
def bar_background=: (Symbol? value) -> Symbol?
|
|
90
|
+
def bar_failed_color: (?Symbol? value) -> Symbol?
|
|
91
|
+
def bar_failed_color=: (Symbol? value) -> Symbol?
|
|
92
|
+
def bar_aux_color: (?Symbol? value) -> Symbol?
|
|
93
|
+
def bar_aux_color=: (Symbol? value) -> Symbol?
|
|
30
94
|
def spinner_frames: () -> Array[String]
|
|
31
95
|
def spinner_frame_seconds: () -> Float
|
|
32
96
|
def bar_complete: () -> String
|
|
@@ -44,6 +108,28 @@ module Dry
|
|
|
44
108
|
def summary: (String label) -> String
|
|
45
109
|
end
|
|
46
110
|
|
|
111
|
+
module Widgets
|
|
112
|
+
class Progress
|
|
113
|
+
class Handle
|
|
114
|
+
type outcome = :ok | :aux | :failed
|
|
115
|
+
|
|
116
|
+
OUTCOMES: Array[outcome]
|
|
117
|
+
|
|
118
|
+
def total: () -> Integer?
|
|
119
|
+
def total=: (Integer value) -> Integer
|
|
120
|
+
def color: () -> Symbol?
|
|
121
|
+
def current: () -> Integer
|
|
122
|
+
def counts: () -> { ok: Integer, aux: Integer, failed: Integer }
|
|
123
|
+
def advance: (?Integer step, ?as: outcome) -> self
|
|
124
|
+
def fail: (?_ToS? reason) -> self
|
|
125
|
+
def failed?: () -> bool
|
|
126
|
+
def reason: () -> String?
|
|
127
|
+
def finish: () -> self
|
|
128
|
+
def summary: (String label) -> String
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
47
133
|
class Stop
|
|
48
134
|
def stopped?: () -> bool
|
|
49
135
|
def stop!: () -> self
|
|
@@ -51,6 +137,8 @@ module Dry
|
|
|
51
137
|
end
|
|
52
138
|
|
|
53
139
|
class Console
|
|
140
|
+
include Reporting
|
|
141
|
+
|
|
54
142
|
def debug: (*_ToS paragraphs, ?width: Integer?) -> nil
|
|
55
143
|
def info: (*_ToS paragraphs, ?width: Integer?) -> nil
|
|
56
144
|
def success: (*_ToS paragraphs, ?width: Integer?) -> nil
|
|
@@ -62,14 +150,15 @@ module Dry
|
|
|
62
150
|
def popup: (*_ToS paragraphs, ?title: String?, ?width: Integer?) -> nil
|
|
63
151
|
def spinner: [T] (String label) { (Line line) -> T } -> T
|
|
64
152
|
def multi_spinner: (String title, ?concurrent: (bool | Integer), ?stop: Stop?) { (untyped spinners) -> void } -> Array[untyped]
|
|
65
|
-
def progress: [T] (String label, total: Integer, ?color: Symbol?) { (
|
|
153
|
+
def progress: [T] (String label, total: Integer, ?color: Symbol?) { (Widgets::Progress::Handle progress) -> T } -> T
|
|
154
|
+
def legend: (?failed: _ToS?, ?aux: _ToS?, ?ok: _ToS?) -> nil
|
|
66
155
|
def multi_progress: (String title, ?concurrent: (bool | Integer), ?count: (:units | :jobs), ?total: Integer?, ?stop: Stop?) { (untyped bars) -> void } -> Array[untyped]
|
|
67
156
|
def stoppable: [T] () { (Stop stop) -> T } -> T
|
|
68
157
|
def status_bar: [T] (?String? title, ?hints: Array[String] | String) { () -> T } -> T
|
|
69
158
|
def tasks: (?String? title, ?concurrent: (bool | Integer)) { (untyped tasks) -> void } -> nil
|
|
70
159
|
def table: (Array[Array[_ToS]] rows, ?header: Array[_ToS]?) -> nil
|
|
71
160
|
def prompt: (String question, ?default: untyped, ?choices: (Array[String] | Hash[String, untyped])?) -> untyped
|
|
72
|
-
def confirm: (String question, ?default: bool) -> bool
|
|
161
|
+
def confirm: (String question, ?default: bool, ?yes: bool) -> bool
|
|
73
162
|
end
|
|
74
163
|
end
|
|
75
164
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dry-cli-ui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Konstantin Gredeskoul
|
|
@@ -9,6 +9,20 @@ bindir: bin
|
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: binding_of_caller
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '2.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '2.0'
|
|
12
26
|
- !ruby/object:Gem::Dependency
|
|
13
27
|
name: concurrent-ruby
|
|
14
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -37,6 +51,20 @@ dependencies:
|
|
|
37
51
|
- - ">="
|
|
38
52
|
- !ruby/object:Gem::Version
|
|
39
53
|
version: '1.0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: logger
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '1.6'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '1.6'
|
|
40
68
|
- !ruby/object:Gem::Dependency
|
|
41
69
|
name: pastel
|
|
42
70
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -51,6 +79,20 @@ dependencies:
|
|
|
51
79
|
- - "~>"
|
|
52
80
|
- !ruby/object:Gem::Version
|
|
53
81
|
version: '0.8'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: semantic_logger
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "~>"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '5.1'
|
|
89
|
+
type: :runtime
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '5.1'
|
|
54
96
|
- !ruby/object:Gem::Dependency
|
|
55
97
|
name: strings
|
|
56
98
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -187,7 +229,12 @@ files:
|
|
|
187
229
|
- lib/dry/cli/ui/configuration.rb
|
|
188
230
|
- lib/dry/cli/ui/console.rb
|
|
189
231
|
- lib/dry/cli/ui/duration.rb
|
|
232
|
+
- lib/dry/cli/ui/flags.rb
|
|
233
|
+
- lib/dry/cli/ui/invocation.rb
|
|
190
234
|
- lib/dry/cli/ui/line.rb
|
|
235
|
+
- lib/dry/cli/ui/logging.rb
|
|
236
|
+
- lib/dry/cli/ui/report.rb
|
|
237
|
+
- lib/dry/cli/ui/reporting.rb
|
|
191
238
|
- lib/dry/cli/ui/status_bar.rb
|
|
192
239
|
- lib/dry/cli/ui/stop.rb
|
|
193
240
|
- lib/dry/cli/ui/terminal.rb
|
|
@@ -195,6 +242,7 @@ files:
|
|
|
195
242
|
- lib/dry/cli/ui/version.rb
|
|
196
243
|
- lib/dry/cli/ui/widgets.rb
|
|
197
244
|
- lib/dry/cli/ui/widgets/box.rb
|
|
245
|
+
- lib/dry/cli/ui/widgets/legend.rb
|
|
198
246
|
- lib/dry/cli/ui/widgets/multi.rb
|
|
199
247
|
- lib/dry/cli/ui/widgets/multi_progress.rb
|
|
200
248
|
- lib/dry/cli/ui/widgets/multi_spinner.rb
|