cli-ui 1.5.1 → 2.2.3
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/README.md +28 -17
- data/lib/cli/ui/ansi.rb +172 -129
- data/lib/cli/ui/color.rb +39 -20
- data/lib/cli/ui/formatter.rb +46 -21
- data/lib/cli/ui/frame/frame_stack.rb +30 -50
- data/lib/cli/ui/frame/frame_style/box.rb +16 -5
- data/lib/cli/ui/frame/frame_style/bracket.rb +19 -8
- data/lib/cli/ui/frame/frame_style.rb +84 -87
- data/lib/cli/ui/frame.rb +79 -32
- data/lib/cli/ui/glyph.rb +44 -31
- data/lib/cli/ui/os.rb +44 -48
- data/lib/cli/ui/printer.rb +65 -47
- data/lib/cli/ui/progress.rb +50 -33
- data/lib/cli/ui/prompt/interactive_options.rb +114 -68
- data/lib/cli/ui/prompt/options_handler.rb +8 -0
- data/lib/cli/ui/prompt.rb +168 -58
- data/lib/cli/ui/sorbet_runtime_stub.rb +169 -0
- data/lib/cli/ui/spinner/async.rb +15 -4
- data/lib/cli/ui/spinner/spin_group.rb +174 -36
- data/lib/cli/ui/spinner.rb +48 -28
- data/lib/cli/ui/stdout_router.rb +229 -47
- data/lib/cli/ui/terminal.rb +37 -25
- data/lib/cli/ui/truncater.rb +7 -2
- data/lib/cli/ui/version.rb +3 -1
- data/lib/cli/ui/widgets/base.rb +23 -4
- data/lib/cli/ui/widgets/status.rb +19 -1
- data/lib/cli/ui/widgets.rb +42 -23
- data/lib/cli/ui/wrap.rb +8 -1
- data/lib/cli/ui.rb +336 -188
- data/vendor/reentrant_mutex.rb +78 -0
- metadata +11 -9
data/lib/cli/ui/frame.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
|
3
|
+
# typed: true
|
4
|
+
|
2
5
|
require 'cli/ui'
|
3
6
|
require 'cli/ui/frame/frame_stack'
|
4
7
|
require 'cli/ui/frame/frame_style'
|
@@ -7,9 +10,12 @@ module CLI
|
|
7
10
|
module UI
|
8
11
|
module Frame
|
9
12
|
class UnnestedFrameException < StandardError; end
|
13
|
+
DEFAULT_FRAME_COLOR = CLI::UI.resolve_color(:cyan)
|
14
|
+
|
10
15
|
class << self
|
11
|
-
|
16
|
+
extend T::Sig
|
12
17
|
|
18
|
+
sig { returns(FrameStyle) }
|
13
19
|
def frame_style
|
14
20
|
@frame_style ||= FrameStyle::Box
|
15
21
|
end
|
@@ -22,6 +28,7 @@ module CLI
|
|
22
28
|
#
|
23
29
|
# * +symbol+ or +FrameStyle+ - the default frame style to use for frames
|
24
30
|
#
|
31
|
+
sig { params(frame_style: FrameStylable).void }
|
25
32
|
def frame_style=(frame_style)
|
26
33
|
@frame_style = CLI::UI.resolve_style(frame_style)
|
27
34
|
end
|
@@ -47,6 +54,8 @@ module CLI
|
|
47
54
|
# * +:success_text+ - If the block succeeds, what do we output? Defaults to nil
|
48
55
|
# * +:timing+ - How long did the frame content take? Invalid for blockless. Defaults to true for the block form
|
49
56
|
# * +frame_style+ - The frame style to use for this frame
|
57
|
+
# * +:to+ - Target stream, like $stdout or $stderr. Can be anything with print and puts methods,
|
58
|
+
# or under Sorbet, IO or StringIO. Defaults to $stdout.
|
50
59
|
#
|
51
60
|
# ==== Example
|
52
61
|
#
|
@@ -67,13 +76,27 @@ module CLI
|
|
67
76
|
# ┏━━ Open ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
68
77
|
#
|
69
78
|
#
|
79
|
+
sig do
|
80
|
+
type_parameters(:T).params(
|
81
|
+
text: String,
|
82
|
+
color: Colorable,
|
83
|
+
failure_text: T.nilable(String),
|
84
|
+
success_text: T.nilable(String),
|
85
|
+
timing: T.any(T::Boolean, Numeric),
|
86
|
+
frame_style: FrameStylable,
|
87
|
+
to: IOLike,
|
88
|
+
block: T.nilable(T.proc.returns(T.type_parameter(:T))),
|
89
|
+
).returns(T.nilable(T.type_parameter(:T)))
|
90
|
+
end
|
70
91
|
def open(
|
71
92
|
text,
|
72
93
|
color: DEFAULT_FRAME_COLOR,
|
73
94
|
failure_text: nil,
|
74
95
|
success_text: nil,
|
75
|
-
timing:
|
76
|
-
frame_style:
|
96
|
+
timing: block_given?,
|
97
|
+
frame_style: self.frame_style,
|
98
|
+
to: $stdout,
|
99
|
+
&block
|
77
100
|
)
|
78
101
|
frame_style = CLI::UI.resolve_style(frame_style)
|
79
102
|
color = CLI::UI.resolve_color(color)
|
@@ -90,8 +113,8 @@ module CLI
|
|
90
113
|
|
91
114
|
t_start = Time.now
|
92
115
|
CLI::UI.raw do
|
93
|
-
print(prefix.chop)
|
94
|
-
puts
|
116
|
+
to.print(prefix.chop)
|
117
|
+
to.puts(frame_style.start(text, color: color))
|
95
118
|
end
|
96
119
|
FrameStack.push(color: color, style: frame_style)
|
97
120
|
|
@@ -103,18 +126,18 @@ module CLI
|
|
103
126
|
success = yield
|
104
127
|
rescue
|
105
128
|
closed = true
|
106
|
-
t_diff =
|
107
|
-
close(failure_text, color: :red, elapsed: t_diff)
|
129
|
+
t_diff = elapsed(t_start, timing)
|
130
|
+
close(failure_text, color: :red, elapsed: t_diff, to: to)
|
108
131
|
raise
|
109
132
|
else
|
110
133
|
success
|
111
134
|
ensure
|
112
135
|
unless closed
|
113
|
-
t_diff =
|
114
|
-
if success != false
|
115
|
-
close(success_text, color: color, elapsed: t_diff)
|
136
|
+
t_diff = elapsed(t_start, timing)
|
137
|
+
if T.unsafe(success) != false
|
138
|
+
close(success_text, color: color, elapsed: t_diff, to: to)
|
116
139
|
else
|
117
|
-
close(failure_text, color: :red, elapsed: t_diff)
|
140
|
+
close(failure_text, color: :red, elapsed: t_diff, to: to)
|
118
141
|
end
|
119
142
|
end
|
120
143
|
end
|
@@ -131,6 +154,8 @@ module CLI
|
|
131
154
|
#
|
132
155
|
# * +:color+ - The color of the frame. Defaults to +DEFAULT_FRAME_COLOR+
|
133
156
|
# * +frame_style+ - The frame style to use for this frame
|
157
|
+
# * +:to+ - Target stream, like $stdout or $stderr. Can be anything with print and puts methods,
|
158
|
+
# or under Sorbet, IO or StringIO. Defaults to $stdout.
|
134
159
|
#
|
135
160
|
# ==== Example
|
136
161
|
#
|
@@ -145,16 +170,24 @@ module CLI
|
|
145
170
|
#
|
146
171
|
# MUST be inside an open frame or it raises a +UnnestedFrameException+
|
147
172
|
#
|
148
|
-
|
173
|
+
sig do
|
174
|
+
params(
|
175
|
+
text: T.nilable(String),
|
176
|
+
color: T.nilable(Colorable),
|
177
|
+
frame_style: T.nilable(FrameStylable),
|
178
|
+
to: IOLike,
|
179
|
+
).void
|
180
|
+
end
|
181
|
+
def divider(text, color: nil, frame_style: nil, to: $stdout)
|
149
182
|
fs_item = FrameStack.pop
|
150
183
|
raise UnnestedFrameException, 'No frame nesting to unnest' unless fs_item
|
151
184
|
|
152
|
-
|
153
|
-
frame_style = CLI::UI.resolve_style(frame_style
|
185
|
+
divider_color = CLI::UI.resolve_color(color || fs_item.color)
|
186
|
+
frame_style = CLI::UI.resolve_style(frame_style || fs_item.frame_style)
|
154
187
|
|
155
188
|
CLI::UI.raw do
|
156
|
-
print(prefix.chop)
|
157
|
-
puts
|
189
|
+
to.print(prefix.chop)
|
190
|
+
to.puts(frame_style.divider(text.to_s, color: divider_color))
|
158
191
|
end
|
159
192
|
|
160
193
|
FrameStack.push(fs_item)
|
@@ -172,6 +205,8 @@ module CLI
|
|
172
205
|
# * +:color+ - The color of the frame. Defaults to nil
|
173
206
|
# * +:elapsed+ - How long did the frame take? Defaults to nil
|
174
207
|
# * +frame_style+ - The frame style to use for this frame. Defaults to nil
|
208
|
+
# * +:to+ - Target stream, like $stdout or $stderr. Can be anything with print and puts methods,
|
209
|
+
# or under Sorbet, IO or StringIO. Defaults to $stdout.
|
175
210
|
#
|
176
211
|
# ==== Example
|
177
212
|
#
|
@@ -184,21 +219,26 @@ module CLI
|
|
184
219
|
#
|
185
220
|
# MUST be inside an open frame or it raises a +UnnestedFrameException+
|
186
221
|
#
|
187
|
-
|
222
|
+
sig do
|
223
|
+
params(
|
224
|
+
text: T.nilable(String),
|
225
|
+
color: T.nilable(Colorable),
|
226
|
+
elapsed: T.nilable(Numeric),
|
227
|
+
frame_style: T.nilable(FrameStylable),
|
228
|
+
to: IOLike,
|
229
|
+
).void
|
230
|
+
end
|
231
|
+
def close(text, color: nil, elapsed: nil, frame_style: nil, to: $stdout)
|
188
232
|
fs_item = FrameStack.pop
|
189
233
|
raise UnnestedFrameException, 'No frame nesting to unnest' unless fs_item
|
190
234
|
|
191
|
-
|
192
|
-
frame_style = CLI::UI.resolve_style(frame_style
|
193
|
-
|
194
|
-
kwargs = {}
|
195
|
-
if elapsed
|
196
|
-
kwargs[:right_text] = "(#{elapsed.round(2)}s)"
|
197
|
-
end
|
235
|
+
close_color = CLI::UI.resolve_color(color || fs_item.color)
|
236
|
+
frame_style = CLI::UI.resolve_style(frame_style || fs_item.frame_style)
|
237
|
+
elapsed_string = elapsed ? "(#{elapsed.round(2)}s)" : nil
|
198
238
|
|
199
239
|
CLI::UI.raw do
|
200
|
-
print(prefix.chop)
|
201
|
-
puts
|
240
|
+
to.print(prefix.chop)
|
241
|
+
to.puts(frame_style.close(text.to_s, color: close_color, right_text: elapsed_string))
|
202
242
|
end
|
203
243
|
end
|
204
244
|
|
@@ -208,11 +248,12 @@ module CLI
|
|
208
248
|
#
|
209
249
|
# * +:color+ - The color of the prefix. Defaults to +Thread.current[:cliui_frame_color_override]+
|
210
250
|
#
|
251
|
+
sig { params(color: T.nilable(Colorable)).returns(String) }
|
211
252
|
def prefix(color: Thread.current[:cliui_frame_color_override])
|
212
253
|
+''.tap do |output|
|
213
254
|
items = FrameStack.items
|
214
255
|
|
215
|
-
items[0..-2].each do |item|
|
256
|
+
items[0..-2].to_a.each do |item|
|
216
257
|
output << item.color.code << item.frame_style.prefix
|
217
258
|
end
|
218
259
|
|
@@ -227,6 +268,7 @@ module CLI
|
|
227
268
|
end
|
228
269
|
|
229
270
|
# The width of a prefix given the number of Frames in the stack
|
271
|
+
sig { returns(Integer) }
|
230
272
|
def prefix_width
|
231
273
|
w = FrameStack.items.reduce(0) do |width, item|
|
232
274
|
width + item.frame_style.prefix_width
|
@@ -241,7 +283,12 @@ module CLI
|
|
241
283
|
#
|
242
284
|
# * +color+ - The color to override to
|
243
285
|
#
|
244
|
-
|
286
|
+
sig do
|
287
|
+
type_parameters(:T)
|
288
|
+
.params(color: Colorable, block: T.proc.returns(T.type_parameter(:T)))
|
289
|
+
.returns(T.type_parameter(:T))
|
290
|
+
end
|
291
|
+
def with_frame_color_override(color, &block)
|
245
292
|
prev = Thread.current[:cliui_frame_color_override]
|
246
293
|
Thread.current[:cliui_frame_color_override] = color
|
247
294
|
yield
|
@@ -254,13 +301,13 @@ module CLI
|
|
254
301
|
# If timing is:
|
255
302
|
# Numeric: return it
|
256
303
|
# false: return nil
|
257
|
-
# true
|
258
|
-
|
259
|
-
def
|
304
|
+
# true: defaults to Time.new
|
305
|
+
sig { params(start: Time, timing: T.any(Numeric, T::Boolean)).returns(T.nilable(Numeric)) }
|
306
|
+
def elapsed(start, timing)
|
260
307
|
return timing if timing.is_a?(Numeric)
|
261
308
|
return if timing.is_a?(FalseClass)
|
262
309
|
|
263
|
-
timing = Time.new
|
310
|
+
timing = Time.new
|
264
311
|
timing - start
|
265
312
|
end
|
266
313
|
end
|
data/lib/cli/ui/glyph.rb
CHANGED
@@ -1,14 +1,22 @@
|
|
1
|
+
# typed: true
|
2
|
+
|
1
3
|
require 'cli/ui'
|
2
4
|
|
3
5
|
module CLI
|
4
6
|
module UI
|
5
7
|
class Glyph
|
8
|
+
extend T::Sig
|
9
|
+
|
6
10
|
class InvalidGlyphHandle < ArgumentError
|
11
|
+
extend T::Sig
|
12
|
+
|
13
|
+
sig { params(handle: String).void }
|
7
14
|
def initialize(handle)
|
8
15
|
super
|
9
16
|
@handle = handle
|
10
17
|
end
|
11
18
|
|
19
|
+
sig { returns(String) }
|
12
20
|
def message
|
13
21
|
keys = Glyph.available.join(',')
|
14
22
|
"invalid glyph handle: #{@handle} " \
|
@@ -16,7 +24,14 @@ module CLI
|
|
16
24
|
end
|
17
25
|
end
|
18
26
|
|
19
|
-
|
27
|
+
sig { returns(String) }
|
28
|
+
attr_reader :handle, :to_s, :fmt, :char
|
29
|
+
|
30
|
+
sig { returns(T.any(Integer, T::Array[Integer])) }
|
31
|
+
attr_reader :codepoint
|
32
|
+
|
33
|
+
sig { returns(Color) }
|
34
|
+
attr_reader :color
|
20
35
|
|
21
36
|
# Creates a new glyph
|
22
37
|
#
|
@@ -27,26 +42,18 @@ module CLI
|
|
27
42
|
# * +plain+ - A fallback plain string to be used in case glyphs are disabled
|
28
43
|
# * +color+ - What color to output the glyph. Check +CLI::UI::Color+ for options.
|
29
44
|
#
|
45
|
+
sig { params(handle: String, codepoint: T.any(Integer, T::Array[Integer]), plain: String, color: Color).void }
|
30
46
|
def initialize(handle, codepoint, plain, color)
|
31
47
|
@handle = handle
|
32
48
|
@codepoint = codepoint
|
33
49
|
@color = color
|
34
|
-
@
|
35
|
-
@
|
36
|
-
@
|
37
|
-
@fmt = "{{#{color.name}:#{char}}}"
|
50
|
+
@char = CLI::UI::OS.current.use_emoji? ? Array(codepoint).pack('U*') : plain
|
51
|
+
@to_s = color.code + @char + Color::RESET.code
|
52
|
+
@fmt = "{{#{color.name}:#{@char}}}"
|
38
53
|
|
39
54
|
MAP[handle] = self
|
40
55
|
end
|
41
56
|
|
42
|
-
# Fetches the actual character(s) to be displayed for a glyph, based on the current OS support
|
43
|
-
#
|
44
|
-
# ==== Returns
|
45
|
-
# Returns the glyph string
|
46
|
-
def char
|
47
|
-
CLI::UI::OS.current.supports_emoji? ? @char : @plain
|
48
|
-
end
|
49
|
-
|
50
57
|
# Mapping of glyphs to terminal output
|
51
58
|
MAP = {}
|
52
59
|
STAR = new('*', 0x2b51, '*', Color::YELLOW) # YELLOW SMALL STAR (⭑)
|
@@ -59,25 +66,31 @@ module CLI
|
|
59
66
|
HOURGLASS = new('H', [0x231b, 0xfe0e], 'H', Color::BLUE) # HOURGLASS + VARIATION SELECTOR 15 (⌛︎)
|
60
67
|
WARNING = new('!', [0x26a0, 0xfe0f], '!', Color::YELLOW) # WARNING SIGN + VARIATION SELECTOR 16 (⚠️ )
|
61
68
|
|
62
|
-
|
63
|
-
|
64
|
-
# ==== Raises
|
65
|
-
# Raises a InvalidGlyphHandle if the glyph is not available
|
66
|
-
# You likely need to create it with +.new+ or you made a typo
|
67
|
-
#
|
68
|
-
# ==== Returns
|
69
|
-
# Returns a terminal output-capable string
|
70
|
-
#
|
71
|
-
def self.lookup(name)
|
72
|
-
MAP.fetch(name.to_s)
|
73
|
-
rescue KeyError
|
74
|
-
raise InvalidGlyphHandle, name
|
75
|
-
end
|
69
|
+
class << self
|
70
|
+
extend T::Sig
|
76
71
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
72
|
+
# Looks up a glyph by name
|
73
|
+
#
|
74
|
+
# ==== Raises
|
75
|
+
# Raises a InvalidGlyphHandle if the glyph is not available
|
76
|
+
# You likely need to create it with +.new+ or you made a typo
|
77
|
+
#
|
78
|
+
# ==== Returns
|
79
|
+
# Returns a terminal output-capable string
|
80
|
+
#
|
81
|
+
sig { params(name: String).returns(Glyph) }
|
82
|
+
def lookup(name)
|
83
|
+
MAP.fetch(name.to_s)
|
84
|
+
rescue KeyError
|
85
|
+
raise InvalidGlyphHandle, name
|
86
|
+
end
|
87
|
+
|
88
|
+
# All available glyphs by name
|
89
|
+
#
|
90
|
+
sig { returns(T::Array[String]) }
|
91
|
+
def available
|
92
|
+
MAP.keys
|
93
|
+
end
|
81
94
|
end
|
82
95
|
end
|
83
96
|
end
|
data/lib/cli/ui/os.rb
CHANGED
@@ -1,67 +1,63 @@
|
|
1
|
+
# typed: true
|
2
|
+
|
1
3
|
require 'rbconfig'
|
2
4
|
|
3
5
|
module CLI
|
4
6
|
module UI
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
else
|
15
|
-
if RUBY_PLATFORM !~ /cygwin/ && ENV['OS'] == 'Windows_NT'
|
16
|
-
Windows
|
17
|
-
else
|
18
|
-
raise "Could not determine OS from host_os #{RbConfig::CONFIG["host_os"]}"
|
19
|
-
end
|
20
|
-
end
|
7
|
+
class OS
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { params(emoji: T::Boolean, color_prompt: T::Boolean, arrow_keys: T::Boolean, shift_cursor: T::Boolean).void }
|
11
|
+
def initialize(emoji: true, color_prompt: true, arrow_keys: true, shift_cursor: false)
|
12
|
+
@emoji = emoji
|
13
|
+
@color_prompt = color_prompt
|
14
|
+
@arrow_keys = arrow_keys
|
15
|
+
@shift_cursor = shift_cursor
|
21
16
|
end
|
22
17
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
true
|
27
|
-
end
|
28
|
-
|
29
|
-
def supports_color_prompt?
|
30
|
-
true
|
31
|
-
end
|
32
|
-
|
33
|
-
def supports_arrow_keys?
|
34
|
-
true
|
35
|
-
end
|
36
|
-
|
37
|
-
def shift_cursor_on_line_reset?
|
38
|
-
false
|
39
|
-
end
|
40
|
-
end
|
18
|
+
sig { returns(T::Boolean) }
|
19
|
+
def use_emoji?
|
20
|
+
@emoji
|
41
21
|
end
|
42
22
|
|
43
|
-
|
23
|
+
sig { returns(T::Boolean) }
|
24
|
+
def use_color_prompt?
|
25
|
+
@color_prompt
|
44
26
|
end
|
45
27
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
28
|
+
sig { returns(T::Boolean) }
|
29
|
+
def suggest_arrow_keys?
|
30
|
+
@arrow_keys
|
31
|
+
end
|
51
32
|
|
52
|
-
|
53
|
-
|
54
|
-
|
33
|
+
sig { returns(T::Boolean) }
|
34
|
+
def shift_cursor_back_on_horizontal_absolute?
|
35
|
+
@shift_cursor
|
36
|
+
end
|
55
37
|
|
56
|
-
|
57
|
-
|
58
|
-
end
|
38
|
+
class << self
|
39
|
+
extend T::Sig
|
59
40
|
|
60
|
-
|
61
|
-
|
41
|
+
sig { returns(OS) }
|
42
|
+
def current
|
43
|
+
@current_os ||= case RbConfig::CONFIG['host_os']
|
44
|
+
when /darwin/
|
45
|
+
MAC
|
46
|
+
when /linux/
|
47
|
+
LINUX
|
48
|
+
else
|
49
|
+
if RUBY_PLATFORM !~ /cygwin/ && ENV['OS'] == 'Windows_NT'
|
50
|
+
WINDOWS
|
51
|
+
else
|
52
|
+
raise "Could not determine OS from host_os #{RbConfig::CONFIG["host_os"]}"
|
53
|
+
end
|
62
54
|
end
|
63
55
|
end
|
64
56
|
end
|
57
|
+
|
58
|
+
MAC = OS.new
|
59
|
+
LINUX = OS.new
|
60
|
+
WINDOWS = OS.new(emoji: false, color_prompt: false, arrow_keys: false, shift_cursor: true)
|
65
61
|
end
|
66
62
|
end
|
67
63
|
end
|
data/lib/cli/ui/printer.rb
CHANGED
@@ -1,58 +1,76 @@
|
|
1
|
+
# typed: true
|
2
|
+
|
1
3
|
require 'cli/ui'
|
2
4
|
|
3
5
|
module CLI
|
4
6
|
module UI
|
5
7
|
class Printer
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
# ==== Attributes
|
11
|
-
#
|
12
|
-
# * +msg+ - (required) the string to output. Can be frozen.
|
13
|
-
#
|
14
|
-
# ==== Options
|
15
|
-
#
|
16
|
-
# * +:frame_color+ - Override the frame color. Defaults to nil.
|
17
|
-
# * +:to+ - Target stream, like $stdout or $stderr. Can be anything with a puts method. Defaults to $stdout.
|
18
|
-
# * +:encoding+ - Force the output to be in a certain encoding. Defaults to UTF-8.
|
19
|
-
# * +:format+ - Whether to format the string using CLI::UI.fmt. Defaults to true.
|
20
|
-
# * +:graceful+ - Whether to gracefully ignore common I/O errors. Defaults to true.
|
21
|
-
# * +:wrap+ - Whether to wrap text at word boundaries to terminal width. Defaults to true.
|
22
|
-
#
|
23
|
-
# ==== Returns
|
24
|
-
# Returns whether the message was successfully printed,
|
25
|
-
# which can be useful if +:graceful+ is set to true.
|
26
|
-
#
|
27
|
-
# ==== Example
|
28
|
-
#
|
29
|
-
# CLI::UI::Printer.puts('{{x}} Ouch', to: $stderr)
|
30
|
-
#
|
31
|
-
def self.puts(
|
32
|
-
msg,
|
33
|
-
frame_color:
|
34
|
-
nil,
|
35
|
-
to:
|
36
|
-
$stdout,
|
37
|
-
encoding: Encoding::UTF_8,
|
38
|
-
format: true,
|
39
|
-
graceful: true,
|
40
|
-
wrap: true
|
41
|
-
)
|
42
|
-
msg = (+msg).force_encoding(encoding) if encoding
|
43
|
-
msg = CLI::UI.fmt(msg) if format
|
44
|
-
msg = CLI::UI.wrap(msg) if wrap
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
class << self
|
11
|
+
extend T::Sig
|
45
12
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
13
|
+
# Print a message to a stream with common utilities.
|
14
|
+
# Allows overriding the color, encoding, and target stream.
|
15
|
+
# By default, it formats the string using CLI:UI and rescues common stream errors.
|
16
|
+
#
|
17
|
+
# ==== Attributes
|
18
|
+
#
|
19
|
+
# * +msg+ - (required) the string to output. Can be frozen.
|
20
|
+
#
|
21
|
+
# ==== Options
|
22
|
+
#
|
23
|
+
# * +:frame_color+ - Override the frame color. Defaults to nil.
|
24
|
+
# * +:to+ - Target stream, like $stdout or $stderr. Can be anything with a puts method. Defaults to $stdout.
|
25
|
+
# * +:encoding+ - Force the output to be in a certain encoding. Defaults to UTF-8.
|
26
|
+
# * +:format+ - Whether to format the string using CLI::UI.fmt. Defaults to true.
|
27
|
+
# * +:graceful+ - Whether to gracefully ignore common I/O errors. Defaults to true.
|
28
|
+
# * +:wrap+ - Whether to wrap text at word boundaries to terminal width. Defaults to true.
|
29
|
+
#
|
30
|
+
# ==== Returns
|
31
|
+
# Returns whether the message was successfully printed,
|
32
|
+
# which can be useful if +:graceful+ is set to true.
|
33
|
+
#
|
34
|
+
# ==== Example
|
35
|
+
#
|
36
|
+
# CLI::UI::Printer.puts('{{x}} Ouch', to: $stderr)
|
37
|
+
#
|
38
|
+
sig do
|
39
|
+
params(
|
40
|
+
msg: String,
|
41
|
+
frame_color: T.nilable(Colorable),
|
42
|
+
to: IOLike,
|
43
|
+
encoding: T.nilable(Encoding),
|
44
|
+
format: T::Boolean,
|
45
|
+
graceful: T::Boolean,
|
46
|
+
wrap: T::Boolean,
|
47
|
+
).returns(T::Boolean)
|
50
48
|
end
|
49
|
+
def puts(
|
50
|
+
msg,
|
51
|
+
frame_color: nil,
|
52
|
+
to: $stdout,
|
53
|
+
encoding: Encoding::UTF_8,
|
54
|
+
format: true,
|
55
|
+
graceful: true,
|
56
|
+
wrap: true
|
57
|
+
)
|
58
|
+
msg = (+msg).force_encoding(encoding) if encoding
|
59
|
+
msg = CLI::UI.fmt(msg) if format
|
60
|
+
msg = CLI::UI.wrap(msg) if wrap
|
61
|
+
|
62
|
+
if frame_color
|
63
|
+
CLI::UI::Frame.with_frame_color_override(frame_color) { to.puts(msg) }
|
64
|
+
else
|
65
|
+
to.puts(msg)
|
66
|
+
end
|
51
67
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
68
|
+
true
|
69
|
+
rescue Errno::EIO, Errno::EPIPE, IOError => e
|
70
|
+
raise(e) unless graceful
|
71
|
+
|
72
|
+
false
|
73
|
+
end
|
56
74
|
end
|
57
75
|
end
|
58
76
|
end
|