cli-ui 1.2.0 → 1.4.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 +5 -5
- data/.dependabot/config.yml +8 -0
- data/.github/CODEOWNERS +1 -0
- data/.github/probots.yml +2 -0
- data/.gitignore +0 -1
- data/.rubocop.yml +23 -2
- data/.travis.yml +4 -2
- data/Gemfile.lock +56 -0
- data/README.md +50 -3
- data/Rakefile +1 -1
- data/cli-ui.gemspec +4 -4
- data/dev.yml +1 -1
- data/lib/cli/ui.rb +61 -20
- data/lib/cli/ui/ansi.rb +9 -3
- data/lib/cli/ui/color.rb +12 -7
- data/lib/cli/ui/formatter.rb +34 -21
- data/lib/cli/ui/frame.rb +108 -149
- data/lib/cli/ui/frame/frame_stack.rb +98 -0
- data/lib/cli/ui/frame/frame_style.rb +120 -0
- data/lib/cli/ui/frame/frame_style/box.rb +166 -0
- data/lib/cli/ui/frame/frame_style/bracket.rb +139 -0
- data/lib/cli/ui/glyph.rb +22 -17
- data/lib/cli/ui/os.rb +63 -0
- data/lib/cli/ui/printer.rb +47 -0
- data/lib/cli/ui/progress.rb +10 -8
- data/lib/cli/ui/prompt.rb +88 -17
- data/lib/cli/ui/prompt/interactive_options.rb +261 -50
- data/lib/cli/ui/prompt/options_handler.rb +7 -2
- data/lib/cli/ui/spinner.rb +23 -5
- data/lib/cli/ui/spinner/spin_group.rb +39 -11
- data/lib/cli/ui/stdout_router.rb +12 -7
- data/lib/cli/ui/terminal.rb +26 -16
- data/lib/cli/ui/truncater.rb +3 -3
- data/lib/cli/ui/version.rb +1 -1
- data/lib/cli/ui/widgets.rb +77 -0
- data/lib/cli/ui/widgets/base.rb +27 -0
- data/lib/cli/ui/widgets/status.rb +61 -0
- metadata +21 -24
- data/lib/cli/ui/box.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e8c6abe82a837c62e28cded106185a5ce2d09413637b94fb5bdb6524552648ac
|
4
|
+
data.tar.gz: 780168b9d23cd55acd5e95e6abcb7b5b0732c694db2feb0f73d5b04ce71dcd63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cea8f4f738765f77a8474221a9449da3f7bb1cae7610fb5d21dc2ee02f7c03996fc26b661db4eefb1af924ab2b7af0469539040763804c7154353037100fdd0f
|
7
|
+
data.tar.gz: bfe35b8ded93b0fe857d55836fd0b1aef67b6c5cb036550a152db464e3657607c0fde84621ccfd2541bb477d262b16e3adef0b320a1b037b3664f2141df99404
|
data/.github/CODEOWNERS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
* @Shopify/dev-infra
|
data/.github/probots.yml
ADDED
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -2,10 +2,19 @@ inherit_from:
|
|
2
2
|
- http://shopify.github.io/ruby-style-guide/rubocop.yml
|
3
3
|
|
4
4
|
AllCops:
|
5
|
-
|
5
|
+
Exclude:
|
6
|
+
- vendor/**/*
|
7
|
+
TargetRubyVersion: 2.5
|
8
|
+
|
9
|
+
Style/FrozenStringLiteralComment:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
# This doesn't understand that <<~ doesn't exist in 2.0
|
13
|
+
Layout/HeredocIndentation:
|
14
|
+
Enabled: false
|
6
15
|
|
7
16
|
# This doesn't take into account retrying from an exception
|
8
|
-
Lint/
|
17
|
+
Lint/SuppressedException:
|
9
18
|
Enabled: false
|
10
19
|
|
11
20
|
# allow String.new to create mutable strings
|
@@ -15,3 +24,15 @@ Style/EmptyLiteral:
|
|
15
24
|
# allow the use of globals which makes sense in a CLI app like this
|
16
25
|
Style/GlobalVars:
|
17
26
|
Enabled: false
|
27
|
+
|
28
|
+
# allow using %r{} for regexes
|
29
|
+
Style/RegexpLiteral:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
# allow readable Dev::Util.begin formatting
|
33
|
+
Style/MultilineBlockChain:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
# we prefer rescue to align with the beginning of the line containing begin, not begin itself
|
37
|
+
Layout/RescueEnsureAlignment:
|
38
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
cli-ui (1.4.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ansi (1.5.0)
|
10
|
+
ast (2.4.1)
|
11
|
+
builder (3.2.4)
|
12
|
+
byebug (11.1.3)
|
13
|
+
method_source (1.0.0)
|
14
|
+
minitest (5.14.2)
|
15
|
+
minitest-reporters (1.4.2)
|
16
|
+
ansi
|
17
|
+
builder
|
18
|
+
minitest (>= 5.0)
|
19
|
+
ruby-progressbar
|
20
|
+
mocha (1.11.2)
|
21
|
+
parallel (1.19.2)
|
22
|
+
parser (2.7.2.0)
|
23
|
+
ast (~> 2.4.1)
|
24
|
+
rainbow (3.0.0)
|
25
|
+
rake (13.0.1)
|
26
|
+
regexp_parser (1.8.2)
|
27
|
+
rexml (3.2.4)
|
28
|
+
rubocop (1.1.0)
|
29
|
+
parallel (~> 1.10)
|
30
|
+
parser (>= 2.7.1.5)
|
31
|
+
rainbow (>= 2.2.2, < 4.0)
|
32
|
+
regexp_parser (>= 1.8)
|
33
|
+
rexml
|
34
|
+
rubocop-ast (>= 1.0.1)
|
35
|
+
ruby-progressbar (~> 1.7)
|
36
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
37
|
+
rubocop-ast (1.1.0)
|
38
|
+
parser (>= 2.7.1.5)
|
39
|
+
ruby-progressbar (1.10.1)
|
40
|
+
unicode-display_width (1.7.0)
|
41
|
+
|
42
|
+
PLATFORMS
|
43
|
+
ruby
|
44
|
+
|
45
|
+
DEPENDENCIES
|
46
|
+
byebug
|
47
|
+
cli-ui!
|
48
|
+
method_source
|
49
|
+
minitest (>= 5.0.0)
|
50
|
+
minitest-reporters
|
51
|
+
mocha
|
52
|
+
rake (~> 13.0)
|
53
|
+
rubocop
|
54
|
+
|
55
|
+
BUNDLED WITH
|
56
|
+
2.1.0
|
data/README.md
CHANGED
@@ -34,7 +34,7 @@ To handle content flow (see example below)
|
|
34
34
|
CLI::UI::StdoutRouter.enable
|
35
35
|
CLI::UI::Frame.open('Frame 1') do
|
36
36
|
CLI::UI::Frame.open('Frame 2') { puts "inside frame 2" }
|
37
|
-
puts "inside frame 1"
|
37
|
+
puts "inside frame 1"
|
38
38
|
end
|
39
39
|
```
|
40
40
|
|
@@ -43,7 +43,10 @@ end
|
|
43
43
|
---
|
44
44
|
|
45
45
|
### Interactive Prompts
|
46
|
-
Prompt user with options and ask them to choose. Can answer using arrow keys,
|
46
|
+
Prompt user with options and ask them to choose. Can answer using arrow keys, vim bindings (`j`/`k`), or numbers (or y/n for yes/no questions).
|
47
|
+
|
48
|
+
For large numbers of options, using `e`, `:`, or `G` will toggle "line select" mode which allows numbers greater than 9 to be typed and
|
49
|
+
`f` or `/` will allow the user to filter options using a free-form text input.
|
47
50
|
|
48
51
|
```ruby
|
49
52
|
CLI::UI.ask('What language/framework do you use?', options: %w(rails go ruby python))
|
@@ -105,13 +108,26 @@ puts CLI::UI.fmt "{{red:Red}} {{green:Green}}"
|
|
105
108
|
e.g. `{{*}}` => a yellow ⭑
|
106
109
|
|
107
110
|
```ruby
|
108
|
-
puts CLI::UI.fmt "{{*}} {{
|
111
|
+
puts CLI::UI.fmt "{{*}} {{v}} {{?}} {{x}}"
|
109
112
|
```
|
110
113
|
|
111
114
|

|
112
115
|
|
113
116
|
---
|
114
117
|
|
118
|
+
### Status Widget
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
CLI::UI::Spinner.spin("building packages: {{@widget/status:1:2:3:4}}") do |spinner|
|
122
|
+
# spinner.update_title(...)
|
123
|
+
sleep(3)
|
124
|
+
end
|
125
|
+
```
|
126
|
+
|
127
|
+

|
128
|
+
|
129
|
+
---
|
130
|
+
|
115
131
|
### Progress Bar
|
116
132
|
|
117
133
|
Show progress of a process or operation.
|
@@ -128,6 +144,37 @@ end
|
|
128
144
|
|
129
145
|
---
|
130
146
|
|
147
|
+
### Frame Styles
|
148
|
+
|
149
|
+
Modify the appearance of CLI::UI both globally and on an individual frame level.
|
150
|
+
|
151
|
+
To set the default style:
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
CLI::UI.frame_style = :box
|
155
|
+
```
|
156
|
+
|
157
|
+
To style an individual frame:
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
CLI::UI.frame('New Style!', frame_style: :bracket) { puts 'It's pretty cool!' }
|
161
|
+
```
|
162
|
+
|
163
|
+
The default style - `:box` - is what has been used up until now. The other style - `:bracket` - looks like this:
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
CLI::UI.frame_style = :bracket
|
167
|
+
CLI::UI::StdoutRouter.enable
|
168
|
+
CLI::UI::Frame.open('Frame 1') do
|
169
|
+
CLI::UI::Frame.open('Frame 2') { puts "inside frame 2" }
|
170
|
+
puts "inside frame 1"
|
171
|
+
end
|
172
|
+
```
|
173
|
+
|
174
|
+

|
175
|
+
|
176
|
+
---
|
177
|
+
|
131
178
|
## Example Usage
|
132
179
|
|
133
180
|
The following code makes use of nested-framing, multi-threaded spinners, formatted text, and more.
|
data/Rakefile
CHANGED
data/cli-ui.gemspec
CHANGED
@@ -14,14 +14,14 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.homepage = "https://github.com/shopify/cli-ui"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
|
-
spec.files =
|
17
|
+
spec.files = %x(git ls-files -z).split("\x0").reject do |f|
|
18
18
|
f.match(%r{^(test|spec|features)/})
|
19
19
|
end
|
20
20
|
spec.bindir = "exe"
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
-
spec.add_development_dependency "bundler", "~>
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
24
|
+
# spec.add_development_dependency "bundler", "~> 2.0"
|
25
|
+
spec.add_development_dependency("rake", "~> 13.0")
|
26
|
+
spec.add_development_dependency("minitest", "~> 5.0")
|
27
27
|
end
|
data/dev.yml
CHANGED
data/lib/cli/ui.rb
CHANGED
@@ -3,14 +3,16 @@ module CLI
|
|
3
3
|
autoload :ANSI, 'cli/ui/ansi'
|
4
4
|
autoload :Glyph, 'cli/ui/glyph'
|
5
5
|
autoload :Color, 'cli/ui/color'
|
6
|
-
autoload :Box, 'cli/ui/box'
|
7
6
|
autoload :Frame, 'cli/ui/frame'
|
7
|
+
autoload :OS, 'cli/ui/os'
|
8
|
+
autoload :Printer, 'cli/ui/printer'
|
8
9
|
autoload :Progress, 'cli/ui/progress'
|
9
10
|
autoload :Prompt, 'cli/ui/prompt'
|
10
11
|
autoload :Terminal, 'cli/ui/terminal'
|
11
12
|
autoload :Truncater, 'cli/ui/truncater'
|
12
13
|
autoload :Formatter, 'cli/ui/formatter'
|
13
14
|
autoload :Spinner, 'cli/ui/spinner'
|
15
|
+
autoload :Widgets, 'cli/ui/widgets'
|
14
16
|
|
15
17
|
# Convenience accessor to +CLI::UI::Spinner::SpinGroup+
|
16
18
|
SpinGroup = Spinner::SpinGroup
|
@@ -27,7 +29,7 @@ module CLI
|
|
27
29
|
end
|
28
30
|
|
29
31
|
# Color resolution using +CLI::UI::Color.lookup+
|
30
|
-
# Will lookup using +Color.lookup+
|
32
|
+
# Will lookup using +Color.lookup+ unless it's already a CLI::UI::Color (or nil)
|
31
33
|
#
|
32
34
|
# ==== Attributes
|
33
35
|
#
|
@@ -35,35 +37,50 @@ module CLI
|
|
35
37
|
#
|
36
38
|
def self.resolve_color(input)
|
37
39
|
case input
|
38
|
-
when
|
39
|
-
|
40
|
+
when CLI::UI::Color, nil
|
41
|
+
input
|
40
42
|
else
|
43
|
+
CLI::UI::Color.lookup(input)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Frame style resolution using +CLI::UI::Frame::FrameStyle.lookup+.
|
48
|
+
# Will lookup using +FrameStyle.lookup+ unless it's already a CLI::UI::Frame::FrameStyle(or nil)
|
49
|
+
#
|
50
|
+
# ==== Attributes
|
51
|
+
#
|
52
|
+
# * +input+ - frame style to resolve
|
53
|
+
def self.resolve_style(input)
|
54
|
+
case input
|
55
|
+
when CLI::UI::Frame::FrameStyle, nil
|
41
56
|
input
|
57
|
+
else
|
58
|
+
CLI::UI::Frame::FrameStyle.lookup(input)
|
42
59
|
end
|
43
60
|
end
|
44
61
|
|
45
|
-
#
|
62
|
+
# Convenience Method for +CLI::UI::Prompt.confirm+
|
46
63
|
#
|
47
64
|
# ==== Attributes
|
48
65
|
#
|
49
66
|
# * +question+ - question to confirm
|
50
67
|
#
|
51
|
-
def self.confirm(question)
|
52
|
-
CLI::UI::Prompt.confirm(question)
|
68
|
+
def self.confirm(question, **kwargs)
|
69
|
+
CLI::UI::Prompt.confirm(question, **kwargs)
|
53
70
|
end
|
54
71
|
|
55
|
-
#
|
72
|
+
# Convenience Method for +CLI::UI::Prompt.ask+
|
56
73
|
#
|
57
74
|
# ==== Attributes
|
58
75
|
#
|
59
76
|
# * +question+ - question to ask
|
60
|
-
# * +kwargs+ -
|
77
|
+
# * +kwargs+ - arguments for +Prompt.ask+
|
61
78
|
#
|
62
79
|
def self.ask(question, **kwargs)
|
63
80
|
CLI::UI::Prompt.ask(question, **kwargs)
|
64
81
|
end
|
65
82
|
|
66
|
-
#
|
83
|
+
# Convenience Method to resolve text using +CLI::UI::Formatter.format+
|
67
84
|
# Check +CLI::UI::Formatter::SGR_MAP+ for available formatting options
|
68
85
|
#
|
69
86
|
# ==== Attributes
|
@@ -75,10 +92,10 @@ module CLI
|
|
75
92
|
return input if input.nil?
|
76
93
|
formatted = CLI::UI::Formatter.new(input).format
|
77
94
|
return formatted unless truncate_to
|
78
|
-
|
95
|
+
CLI::UI::Truncater.call(formatted, truncate_to)
|
79
96
|
end
|
80
97
|
|
81
|
-
#
|
98
|
+
# Convenience Method to format text using +CLI::UI::Formatter.format+
|
82
99
|
# Check +CLI::UI::Formatter::SGR_MAP+ for available formatting options
|
83
100
|
#
|
84
101
|
# https://user-images.githubusercontent.com/3074765/33799827-6d0721a2-dd01-11e7-9ab5-c3d455264afe.png
|
@@ -96,29 +113,40 @@ module CLI
|
|
96
113
|
CLI::UI::Formatter.new(input).format(enable_color: enable_color)
|
97
114
|
end
|
98
115
|
|
99
|
-
#
|
116
|
+
# Convenience Method for +CLI::UI::Printer.puts+
|
117
|
+
#
|
118
|
+
# ==== Attributes
|
119
|
+
#
|
120
|
+
# * +msg+ - Message to print
|
121
|
+
# * +kwargs+ - keyword arguments for +Printer.puts+
|
122
|
+
#
|
123
|
+
def self.puts(msg, **kwargs)
|
124
|
+
CLI::UI::Printer.puts(msg, **kwargs)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Convenience Method for +CLI::UI::Frame.open+
|
100
128
|
#
|
101
129
|
# ==== Attributes
|
102
130
|
#
|
103
131
|
# * +args+ - arguments for +Frame.open+
|
104
132
|
# * +block+ - block for +Frame.open+
|
105
133
|
#
|
106
|
-
def self.frame(*args, &block)
|
107
|
-
CLI::UI::Frame.open(*args, &block)
|
134
|
+
def self.frame(*args, **kwargs, &block)
|
135
|
+
CLI::UI::Frame.open(*args, **kwargs, &block)
|
108
136
|
end
|
109
137
|
|
110
|
-
#
|
138
|
+
# Convenience Method for +CLI::UI::Spinner.spin+
|
111
139
|
#
|
112
140
|
# ==== Attributes
|
113
141
|
#
|
114
142
|
# * +args+ - arguments for +Spinner.open+
|
115
143
|
# * +block+ - block for +Spinner.open+
|
116
144
|
#
|
117
|
-
def self.spinner(*args, &block)
|
118
|
-
CLI::UI::Spinner.spin(*args, &block)
|
145
|
+
def self.spinner(*args, **kwargs, &block)
|
146
|
+
CLI::UI::Spinner.spin(*args, **kwargs, &block)
|
119
147
|
end
|
120
148
|
|
121
|
-
#
|
149
|
+
# Convenience Method to override frame color using +CLI::UI::Frame.with_frame_color+
|
122
150
|
#
|
123
151
|
# ==== Attributes
|
124
152
|
#
|
@@ -142,7 +170,7 @@ module CLI
|
|
142
170
|
CLI::UI::StdoutRouter.duplicate_output_to = File.open(path, 'w')
|
143
171
|
yield
|
144
172
|
ensure
|
145
|
-
if file_descriptor = CLI::UI::StdoutRouter.duplicate_output_to
|
173
|
+
if (file_descriptor = CLI::UI::StdoutRouter.duplicate_output_to)
|
146
174
|
file_descriptor.close
|
147
175
|
CLI::UI::StdoutRouter.duplicate_output_to = nil
|
148
176
|
end
|
@@ -181,6 +209,19 @@ module CLI
|
|
181
209
|
end
|
182
210
|
|
183
211
|
self.enable_color = $stdout.tty?
|
212
|
+
|
213
|
+
# Set the default frame style.
|
214
|
+
# Convenience method for setting the default frame style with +CLI::UI::Frame.frame_style=+
|
215
|
+
#
|
216
|
+
# Raises ArgumentError if +frame_style+ is not valid
|
217
|
+
#
|
218
|
+
# ==== Attributes
|
219
|
+
#
|
220
|
+
# * +symbol+ - the default frame style to use for frames
|
221
|
+
#
|
222
|
+
def self.frame_style=(frame_style)
|
223
|
+
Frame.frame_style = frame_style.to_sym
|
224
|
+
end
|
184
225
|
end
|
185
226
|
end
|
186
227
|
|
data/lib/cli/ui/ansi.rb
CHANGED
@@ -106,7 +106,9 @@ module CLI
|
|
106
106
|
# * +n+ - The column to move to
|
107
107
|
#
|
108
108
|
def self.cursor_horizontal_absolute(n = 1)
|
109
|
-
control(n.to_s, 'G')
|
109
|
+
cmd = control(n.to_s, 'G')
|
110
|
+
cmd += control('1', 'D') if CLI::UI::OS.current.shift_cursor_on_line_reset?
|
111
|
+
cmd
|
110
112
|
end
|
111
113
|
|
112
114
|
# Show the cursor
|
@@ -136,13 +138,17 @@ module CLI
|
|
136
138
|
# Move to the next line
|
137
139
|
#
|
138
140
|
def self.next_line
|
139
|
-
cursor_down + control('1', 'G')
|
141
|
+
cmd = cursor_down + control('1', 'G')
|
142
|
+
cmd += control('1', 'D') if CLI::UI::OS.current.shift_cursor_on_line_reset?
|
143
|
+
cmd
|
140
144
|
end
|
141
145
|
|
142
146
|
# Move to the previous line
|
143
147
|
#
|
144
148
|
def self.previous_line
|
145
|
-
cursor_up + control('1', 'G')
|
149
|
+
cmd = cursor_up + control('1', 'G')
|
150
|
+
cmd += control('1', 'D') if CLI::UI::OS.current.shift_cursor_on_line_reset?
|
151
|
+
cmd
|
146
152
|
end
|
147
153
|
|
148
154
|
def self.clear_to_end_of_line
|