gorails 0.1.2 → 0.1.5

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -1
  3. data/Gemfile.lock +1 -6
  4. data/bin/update-deps +95 -0
  5. data/exe/gorails +2 -1
  6. data/gorails.gemspec +0 -2
  7. data/lib/gorails/commands/railsbytes.rb +10 -10
  8. data/lib/gorails/commands/version.rb +15 -0
  9. data/lib/gorails/commands.rb +2 -5
  10. data/lib/gorails/version.rb +1 -1
  11. data/lib/gorails.rb +11 -20
  12. data/vendor/deps/cli-kit/REVISION +1 -0
  13. data/vendor/deps/cli-kit/lib/cli/kit/args/definition.rb +301 -0
  14. data/vendor/deps/cli-kit/lib/cli/kit/args/evaluation.rb +237 -0
  15. data/vendor/deps/cli-kit/lib/cli/kit/args/parser/node.rb +131 -0
  16. data/vendor/deps/cli-kit/lib/cli/kit/args/parser.rb +128 -0
  17. data/vendor/deps/cli-kit/lib/cli/kit/args/tokenizer.rb +132 -0
  18. data/vendor/deps/cli-kit/lib/cli/kit/args.rb +15 -0
  19. data/vendor/deps/cli-kit/lib/cli/kit/base_command.rb +29 -0
  20. data/vendor/deps/cli-kit/lib/cli/kit/command_help.rb +256 -0
  21. data/vendor/deps/cli-kit/lib/cli/kit/command_registry.rb +141 -0
  22. data/vendor/deps/cli-kit/lib/cli/kit/config.rb +137 -0
  23. data/vendor/deps/cli-kit/lib/cli/kit/core_ext.rb +30 -0
  24. data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +165 -0
  25. data/vendor/deps/cli-kit/lib/cli/kit/executor.rb +99 -0
  26. data/vendor/deps/cli-kit/lib/cli/kit/ini.rb +94 -0
  27. data/vendor/deps/cli-kit/lib/cli/kit/levenshtein.rb +89 -0
  28. data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +95 -0
  29. data/vendor/deps/cli-kit/lib/cli/kit/opts.rb +284 -0
  30. data/vendor/deps/cli-kit/lib/cli/kit/resolver.rb +67 -0
  31. data/vendor/deps/cli-kit/lib/cli/kit/sorbet_runtime_stub.rb +142 -0
  32. data/vendor/deps/cli-kit/lib/cli/kit/support/test_helper.rb +253 -0
  33. data/vendor/deps/cli-kit/lib/cli/kit/support.rb +10 -0
  34. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +350 -0
  35. data/vendor/deps/cli-kit/lib/cli/kit/util.rb +133 -0
  36. data/vendor/deps/cli-kit/lib/cli/kit/version.rb +7 -0
  37. data/vendor/deps/cli-kit/lib/cli/kit.rb +151 -0
  38. data/vendor/deps/cli-ui/REVISION +1 -0
  39. data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +180 -0
  40. data/vendor/deps/cli-ui/lib/cli/ui/color.rb +98 -0
  41. data/vendor/deps/cli-ui/lib/cli/ui/formatter.rb +216 -0
  42. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +116 -0
  43. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/box.rb +176 -0
  44. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +149 -0
  45. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +112 -0
  46. data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +300 -0
  47. data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +92 -0
  48. data/vendor/deps/cli-ui/lib/cli/ui/os.rb +58 -0
  49. data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +72 -0
  50. data/vendor/deps/cli-ui/lib/cli/ui/progress.rb +102 -0
  51. data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +534 -0
  52. data/vendor/deps/cli-ui/lib/cli/ui/prompt/options_handler.rb +36 -0
  53. data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +354 -0
  54. data/vendor/deps/cli-ui/lib/cli/ui/sorbet_runtime_stub.rb +143 -0
  55. data/vendor/deps/cli-ui/lib/cli/ui/spinner/async.rb +46 -0
  56. data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +292 -0
  57. data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +82 -0
  58. data/vendor/deps/cli-ui/lib/cli/ui/stdout_router.rb +264 -0
  59. data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +53 -0
  60. data/vendor/deps/cli-ui/lib/cli/ui/truncater.rb +107 -0
  61. data/vendor/deps/cli-ui/lib/cli/ui/version.rb +6 -0
  62. data/vendor/deps/cli-ui/lib/cli/ui/widgets/base.rb +37 -0
  63. data/vendor/deps/cli-ui/lib/cli/ui/widgets/status.rb +75 -0
  64. data/vendor/deps/cli-ui/lib/cli/ui/widgets.rb +91 -0
  65. data/vendor/deps/cli-ui/lib/cli/ui/wrap.rb +63 -0
  66. data/vendor/deps/cli-ui/lib/cli/ui.rb +356 -0
  67. metadata +58 -29
@@ -0,0 +1,112 @@
1
+ # typed: true
2
+ require 'cli/ui/frame'
3
+
4
+ module CLI
5
+ module UI
6
+ module Frame
7
+ module FrameStyle
8
+ include Kernel
9
+ extend T::Sig
10
+ extend T::Helpers
11
+ abstract!
12
+
13
+ autoload(:Box, 'cli/ui/frame/frame_style/box')
14
+ autoload(:Bracket, 'cli/ui/frame/frame_style/bracket')
15
+
16
+ MAP = {
17
+ box: -> { FrameStyle::Box },
18
+ bracket: -> { FrameStyle::Bracket },
19
+ }
20
+
21
+ # Lookup a frame style via its name
22
+ #
23
+ # ==== Attributes
24
+ #
25
+ # * +symbol+ - frame style name to lookup
26
+ sig { params(name: T.any(String, Symbol)).returns(FrameStyle) }
27
+ def self.lookup(name)
28
+ MAP.fetch(name.to_sym).call
29
+ rescue KeyError
30
+ raise(InvalidFrameStyleName, name)
31
+ end
32
+
33
+ sig { abstract.returns(Symbol) }
34
+ def style_name; end
35
+
36
+ # Returns the character(s) that should be printed at the beginning
37
+ # of lines inside this frame
38
+ sig { abstract.returns(String) }
39
+ def prefix; end
40
+
41
+ # Returns the printing width of the prefix
42
+ sig { returns(Integer) }
43
+ def prefix_width
44
+ CLI::UI::ANSI.printing_width(prefix)
45
+ end
46
+
47
+ # Draws the "Open" line for this frame style
48
+ #
49
+ # ==== Attributes
50
+ #
51
+ # * +text+ - (required) the text/title to output in the frame
52
+ #
53
+ # ==== Options
54
+ #
55
+ # * +:color+ - (required) The color of the frame.
56
+ #
57
+ sig { abstract.params(text: String, color: CLI::UI::Color).returns(String) }
58
+ def start(text, color:); end
59
+
60
+ # Draws the "Close" line for this frame style
61
+ #
62
+ # ==== Attributes
63
+ #
64
+ # * +text+ - (required) the text/title to output in the frame
65
+ #
66
+ # ==== Options
67
+ #
68
+ # * +:color+ - (required) The color of the frame.
69
+ # * +:right_text+ - Text to print at the right of the line. Defaults to nil
70
+ #
71
+ sig { abstract.params(text: String, color: CLI::UI::Color, right_text: T.nilable(String)).returns(String) }
72
+ def close(text, color:, right_text: nil); end
73
+
74
+ # Draws a "divider" line for the current frame style
75
+ #
76
+ # ==== Attributes
77
+ #
78
+ # * +text+ - (required) the text/title to output in the frame
79
+ #
80
+ # ==== Options
81
+ #
82
+ # * +:color+ - (required) The color of the frame.
83
+ #
84
+ sig { abstract.params(text: String, color: CLI::UI::Color).returns(String) }
85
+ def divider(text, color:); end
86
+
87
+ sig { params(x: Integer, str: String).returns(String) }
88
+ def print_at_x(x, str)
89
+ CLI::UI::ANSI.cursor_horizontal_absolute(1 + x) + str
90
+ end
91
+
92
+ class InvalidFrameStyleName < ArgumentError
93
+ extend T::Sig
94
+
95
+ sig { params(name: T.any(String, Symbol)).void }
96
+ def initialize(name)
97
+ super
98
+ @name = name
99
+ end
100
+
101
+ sig { returns(String) }
102
+ def message
103
+ keys = FrameStyle::MAP.keys.map(&:inspect).join(', ')
104
+ "invalid frame style: #{@name.inspect}" \
105
+ ' -- must be one of CLI::UI::Frame::FrameStyle::MAP ' \
106
+ "(#{keys})"
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,300 @@
1
+ # coding: utf-8
2
+
3
+ # typed: true
4
+
5
+ require 'cli/ui'
6
+ require 'cli/ui/frame/frame_stack'
7
+ require 'cli/ui/frame/frame_style'
8
+
9
+ module CLI
10
+ module UI
11
+ module Frame
12
+ class UnnestedFrameException < StandardError; end
13
+ DEFAULT_FRAME_COLOR = CLI::UI.resolve_color(:cyan)
14
+
15
+ class << self
16
+ extend T::Sig
17
+
18
+ sig { returns(FrameStyle) }
19
+ def frame_style
20
+ @frame_style ||= FrameStyle::Box
21
+ end
22
+
23
+ # Set the default frame style.
24
+ #
25
+ # Raises ArgumentError if +frame_style+ is not valid
26
+ #
27
+ # ==== Attributes
28
+ #
29
+ # * +symbol+ or +FrameStyle+ - the default frame style to use for frames
30
+ #
31
+ sig { params(frame_style: FrameStylable).void }
32
+ def frame_style=(frame_style)
33
+ @frame_style = CLI::UI.resolve_style(frame_style)
34
+ end
35
+
36
+ # Opens a new frame. Can be nested
37
+ # Can be invoked in two ways: block and blockless
38
+ # * In block form, the frame is closed automatically when the block returns
39
+ # * In blockless form, caller MUST call +Frame.close+ when the frame is logically done
40
+ # * Blockless form is strongly discouraged in cases where block form can be made to work
41
+ #
42
+ # https://user-images.githubusercontent.com/3074765/33799861-cb5dcb5c-dd01-11e7-977e-6fad38cee08c.png
43
+ #
44
+ # The return value of the block determines if the block is a "success" or a "failure"
45
+ #
46
+ # ==== Attributes
47
+ #
48
+ # * +text+ - (required) the text/title to output in the frame
49
+ #
50
+ # ==== Options
51
+ #
52
+ # * +:color+ - The color of the frame. Defaults to +DEFAULT_FRAME_COLOR+
53
+ # * +:failure_text+ - If the block failed, what do we output? Defaults to nil
54
+ # * +:success_text+ - If the block succeeds, what do we output? Defaults to nil
55
+ # * +:timing+ - How long did the frame content take? Invalid for blockless. Defaults to true for the block form
56
+ # * +frame_style+ - The frame style to use for this frame
57
+ #
58
+ # ==== Example
59
+ #
60
+ # ===== Block Form (Assumes +CLI::UI::StdoutRouter.enable+ has been called)
61
+ #
62
+ # CLI::UI::Frame.open('Open') { puts 'hi' }
63
+ #
64
+ # Default Output:
65
+ # ┏━━ Open ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
66
+ # ┃ hi
67
+ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ (0.0s) ━━
68
+ #
69
+ # ===== Blockless Form
70
+ #
71
+ # CLI::UI::Frame.open('Open')
72
+ #
73
+ # Default Output:
74
+ # ┏━━ Open ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
75
+ #
76
+ #
77
+ sig do
78
+ type_parameters(:T).params(
79
+ text: String,
80
+ color: Colorable,
81
+ failure_text: T.nilable(String),
82
+ success_text: T.nilable(String),
83
+ timing: T.any(T::Boolean, Numeric),
84
+ frame_style: FrameStylable,
85
+ block: T.nilable(T.proc.returns(T.type_parameter(:T)))
86
+ ).returns(T.nilable(T.type_parameter(:T)))
87
+ end
88
+ def open(
89
+ text,
90
+ color: DEFAULT_FRAME_COLOR,
91
+ failure_text: nil,
92
+ success_text: nil,
93
+ timing: block_given?,
94
+ frame_style: self.frame_style,
95
+ &block
96
+ )
97
+ frame_style = CLI::UI.resolve_style(frame_style)
98
+ color = CLI::UI.resolve_color(color)
99
+
100
+ unless block_given?
101
+ if failure_text
102
+ raise ArgumentError, 'failure_text is not compatible with blockless invocation'
103
+ elsif success_text
104
+ raise ArgumentError, 'success_text is not compatible with blockless invocation'
105
+ elsif timing
106
+ raise ArgumentError, 'timing is not compatible with blockless invocation'
107
+ end
108
+ end
109
+
110
+ t_start = Time.now
111
+ CLI::UI.raw do
112
+ print(prefix.chop)
113
+ puts frame_style.start(text, color: color)
114
+ end
115
+ FrameStack.push(color: color, style: frame_style)
116
+
117
+ return unless block_given?
118
+
119
+ closed = false
120
+ begin
121
+ success = false
122
+ success = yield
123
+ rescue
124
+ closed = true
125
+ t_diff = elapsed(t_start, timing)
126
+ close(failure_text, color: :red, elapsed: t_diff)
127
+ raise
128
+ else
129
+ success
130
+ ensure
131
+ unless closed
132
+ t_diff = elapsed(t_start, timing)
133
+ if T.unsafe(success) != false
134
+ close(success_text, color: color, elapsed: t_diff)
135
+ else
136
+ close(failure_text, color: :red, elapsed: t_diff)
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ # Adds a divider in a frame
143
+ # Used to separate information within a single frame
144
+ #
145
+ # ==== Attributes
146
+ #
147
+ # * +text+ - (required) the text/title to output in the frame
148
+ #
149
+ # ==== Options
150
+ #
151
+ # * +:color+ - The color of the frame. Defaults to +DEFAULT_FRAME_COLOR+
152
+ # * +frame_style+ - The frame style to use for this frame
153
+ #
154
+ # ==== Example
155
+ #
156
+ # CLI::UI::Frame.open('Open') { CLI::UI::Frame.divider('Divider') }
157
+ #
158
+ # Default Output:
159
+ # ┏━━ Open ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
160
+ # ┣━━ Divider ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
161
+ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
162
+ #
163
+ # ==== Raises
164
+ #
165
+ # MUST be inside an open frame or it raises a +UnnestedFrameException+
166
+ #
167
+ sig { params(text: T.nilable(String), color: T.nilable(Colorable), frame_style: T.nilable(FrameStylable)).void }
168
+ def divider(text, color: nil, frame_style: nil)
169
+ fs_item = FrameStack.pop
170
+ raise UnnestedFrameException, 'No frame nesting to unnest' unless fs_item
171
+
172
+ divider_color = CLI::UI.resolve_color(color || fs_item.color)
173
+ frame_style = CLI::UI.resolve_style(frame_style || fs_item.frame_style)
174
+
175
+ CLI::UI.raw do
176
+ print(prefix.chop)
177
+ puts frame_style.divider(text.to_s, color: divider_color)
178
+ end
179
+
180
+ FrameStack.push(fs_item)
181
+ end
182
+
183
+ # Closes a frame
184
+ # Automatically called for a block-form +open+
185
+ #
186
+ # ==== Attributes
187
+ #
188
+ # * +text+ - (required) the text/title to output in the frame
189
+ #
190
+ # ==== Options
191
+ #
192
+ # * +:color+ - The color of the frame. Defaults to nil
193
+ # * +:elapsed+ - How long did the frame take? Defaults to nil
194
+ # * +frame_style+ - The frame style to use for this frame. Defaults to nil
195
+ #
196
+ # ==== Example
197
+ #
198
+ # CLI::UI::Frame.close('Close')
199
+ #
200
+ # Default Output:
201
+ # ┗━━ Close ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
202
+ #
203
+ # ==== Raises
204
+ #
205
+ # MUST be inside an open frame or it raises a +UnnestedFrameException+
206
+ #
207
+ sig do
208
+ params(
209
+ text: T.nilable(String),
210
+ color: T.nilable(Colorable),
211
+ elapsed: T.nilable(Numeric),
212
+ frame_style: T.nilable(FrameStylable)
213
+ ).void
214
+ end
215
+ def close(text, color: nil, elapsed: nil, frame_style: nil)
216
+ fs_item = FrameStack.pop
217
+ raise UnnestedFrameException, 'No frame nesting to unnest' unless fs_item
218
+
219
+ close_color = CLI::UI.resolve_color(color || fs_item.color)
220
+ frame_style = CLI::UI.resolve_style(frame_style || fs_item.frame_style)
221
+ elapsed_string = elapsed ? "(#{elapsed.round(2)}s)" : nil
222
+
223
+ CLI::UI.raw do
224
+ print(prefix.chop)
225
+ puts frame_style.close(text.to_s, color: close_color, right_text: elapsed_string)
226
+ end
227
+ end
228
+
229
+ # Determines the prefix of a frame entry taking multi-nested frames into account
230
+ #
231
+ # ==== Options
232
+ #
233
+ # * +:color+ - The color of the prefix. Defaults to +Thread.current[:cliui_frame_color_override]+
234
+ #
235
+ sig { params(color: T.nilable(Colorable)).returns(String) }
236
+ def prefix(color: Thread.current[:cliui_frame_color_override])
237
+ +''.tap do |output|
238
+ items = FrameStack.items
239
+
240
+ items[0..-2].to_a.each do |item|
241
+ output << item.color.code << item.frame_style.prefix
242
+ end
243
+
244
+ if (item = items.last)
245
+ final_color = color || item.color
246
+ output << CLI::UI.resolve_color(final_color).code \
247
+ << item.frame_style.prefix \
248
+ << ' ' \
249
+ << CLI::UI::Color::RESET.code
250
+ end
251
+ end
252
+ end
253
+
254
+ # The width of a prefix given the number of Frames in the stack
255
+ sig { returns(Integer) }
256
+ def prefix_width
257
+ w = FrameStack.items.reduce(0) do |width, item|
258
+ width + item.frame_style.prefix_width
259
+ end
260
+
261
+ w.zero? ? w : w + 1
262
+ end
263
+
264
+ # Override a color for a given thread.
265
+ #
266
+ # ==== Attributes
267
+ #
268
+ # * +color+ - The color to override to
269
+ #
270
+ sig do
271
+ type_parameters(:T)
272
+ .params(color: Colorable, block: T.proc.returns(T.type_parameter(:T)))
273
+ .returns(T.type_parameter(:T))
274
+ end
275
+ def with_frame_color_override(color, &block)
276
+ prev = Thread.current[:cliui_frame_color_override]
277
+ Thread.current[:cliui_frame_color_override] = color
278
+ yield
279
+ ensure
280
+ Thread.current[:cliui_frame_color_override] = prev
281
+ end
282
+
283
+ private
284
+
285
+ # If timing is:
286
+ # Numeric: return it
287
+ # false: return nil
288
+ # true: defaults to Time.new
289
+ sig { params(start: Time, timing: T.any(Numeric, T::Boolean)).returns(T.nilable(Numeric)) }
290
+ def elapsed(start, timing)
291
+ return timing if timing.is_a?(Numeric)
292
+ return if timing.is_a?(FalseClass)
293
+
294
+ timing = Time.new
295
+ timing - start
296
+ end
297
+ end
298
+ end
299
+ end
300
+ end
@@ -0,0 +1,92 @@
1
+ # typed: true
2
+ require 'cli/ui'
3
+
4
+ module CLI
5
+ module UI
6
+ class Glyph
7
+ extend T::Sig
8
+
9
+ class InvalidGlyphHandle < ArgumentError
10
+ extend T::Sig
11
+
12
+ sig { params(handle: String).void }
13
+ def initialize(handle)
14
+ super
15
+ @handle = handle
16
+ end
17
+
18
+ sig { returns(String) }
19
+ def message
20
+ keys = Glyph.available.join(',')
21
+ "invalid glyph handle: #{@handle} " \
22
+ "-- must be one of CLI::UI::Glyph.available (#{keys})"
23
+ end
24
+ end
25
+
26
+ sig { returns(String) }
27
+ attr_reader :handle, :to_s, :fmt, :char
28
+
29
+ sig { returns(T.any(Integer, T::Array[Integer])) }
30
+ attr_reader :codepoint
31
+
32
+ sig { returns(Color) }
33
+ attr_reader :color
34
+
35
+ # Creates a new glyph
36
+ #
37
+ # ==== Attributes
38
+ #
39
+ # * +handle+ - The handle in the +MAP+ constant
40
+ # * +codepoint+ - The codepoint used to create the glyph (e.g. +0x2717+ for a ballot X)
41
+ # * +plain+ - A fallback plain string to be used in case glyphs are disabled
42
+ # * +color+ - What color to output the glyph. Check +CLI::UI::Color+ for options.
43
+ #
44
+ sig { params(handle: String, codepoint: T.any(Integer, T::Array[Integer]), plain: String, color: Color).void }
45
+ def initialize(handle, codepoint, plain, color)
46
+ @handle = handle
47
+ @codepoint = codepoint
48
+ @color = color
49
+ @char = CLI::UI::OS.current.use_emoji? ? Array(codepoint).pack('U*') : plain
50
+ @to_s = color.code + @char + Color::RESET.code
51
+ @fmt = "{{#{color.name}:#{@char}}}"
52
+
53
+ MAP[handle] = self
54
+ end
55
+
56
+ # Mapping of glyphs to terminal output
57
+ MAP = {}
58
+ STAR = new('*', 0x2b51, '*', Color::YELLOW) # YELLOW SMALL STAR (⭑)
59
+ INFO = new('i', 0x1d4be, 'i', Color::BLUE) # BLUE MATHEMATICAL SCRIPT SMALL i (𝒾)
60
+ QUESTION = new('?', 0x003f, '?', Color::BLUE) # BLUE QUESTION MARK (?)
61
+ CHECK = new('v', 0x2713, '√', Color::GREEN) # GREEN CHECK MARK (✓)
62
+ X = new('x', 0x2717, 'X', Color::RED) # RED BALLOT X (✗)
63
+ BUG = new('b', 0x1f41b, '!', Color::WHITE) # Bug emoji (🐛)
64
+ CHEVRON = new('>', 0xbb, '»', Color::YELLOW) # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (»)
65
+ HOURGLASS = new('H', [0x231b, 0xfe0e], 'H', Color::BLUE) # HOURGLASS + VARIATION SELECTOR 15 (⌛︎)
66
+ WARNING = new('!', [0x26a0, 0xfe0f], '!', Color::YELLOW) # WARNING SIGN + VARIATION SELECTOR 16 (⚠️ )
67
+
68
+ # Looks up a glyph by name
69
+ #
70
+ # ==== Raises
71
+ # Raises a InvalidGlyphHandle if the glyph is not available
72
+ # You likely need to create it with +.new+ or you made a typo
73
+ #
74
+ # ==== Returns
75
+ # Returns a terminal output-capable string
76
+ #
77
+ sig { params(name: String).returns(Glyph) }
78
+ def self.lookup(name)
79
+ MAP.fetch(name.to_s)
80
+ rescue KeyError
81
+ raise InvalidGlyphHandle, name
82
+ end
83
+
84
+ # All available glyphs by name
85
+ #
86
+ sig { returns(T::Array[String]) }
87
+ def self.available
88
+ MAP.keys
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,58 @@
1
+ # typed: true
2
+ require 'rbconfig'
3
+
4
+ module CLI
5
+ module UI
6
+ class OS
7
+ extend T::Sig
8
+
9
+ sig { params(emoji: T::Boolean, color_prompt: T::Boolean, arrow_keys: T::Boolean, shift_cursor: T::Boolean).void }
10
+ def initialize(emoji: true, color_prompt: true, arrow_keys: true, shift_cursor: false)
11
+ @emoji = emoji
12
+ @color_prompt = color_prompt
13
+ @arrow_keys = arrow_keys
14
+ @shift_cursor = shift_cursor
15
+ end
16
+
17
+ sig { returns(T::Boolean) }
18
+ def use_emoji?
19
+ @emoji
20
+ end
21
+
22
+ sig { returns(T::Boolean) }
23
+ def use_color_prompt?
24
+ @color_prompt
25
+ end
26
+
27
+ sig { returns(T::Boolean) }
28
+ def suggest_arrow_keys?
29
+ @arrow_keys
30
+ end
31
+
32
+ sig { returns(T::Boolean) }
33
+ def shift_cursor_back_on_horizontal_absolute?
34
+ @shift_cursor
35
+ end
36
+
37
+ sig { returns(OS) }
38
+ def self.current
39
+ @current_os ||= case RbConfig::CONFIG['host_os']
40
+ when /darwin/
41
+ MAC
42
+ when /linux/
43
+ LINUX
44
+ else
45
+ if RUBY_PLATFORM !~ /cygwin/ && ENV['OS'] == 'Windows_NT'
46
+ WINDOWS
47
+ else
48
+ raise "Could not determine OS from host_os #{RbConfig::CONFIG["host_os"]}"
49
+ end
50
+ end
51
+ end
52
+
53
+ MAC = OS.new
54
+ LINUX = OS.new
55
+ WINDOWS = OS.new(emoji: false, color_prompt: false, arrow_keys: false, shift_cursor: true)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,72 @@
1
+ # typed: true
2
+ require 'cli/ui'
3
+
4
+ module CLI
5
+ module UI
6
+ class Printer
7
+ extend T::Sig
8
+
9
+ # Print a message to a stream with common utilities.
10
+ # Allows overriding the color, encoding, and target stream.
11
+ # By default, it formats the string using CLI:UI and rescues common stream errors.
12
+ #
13
+ # ==== Attributes
14
+ #
15
+ # * +msg+ - (required) the string to output. Can be frozen.
16
+ #
17
+ # ==== Options
18
+ #
19
+ # * +:frame_color+ - Override the frame color. Defaults to nil.
20
+ # * +:to+ - Target stream, like $stdout or $stderr. Can be anything with a puts method. Defaults to $stdout.
21
+ # * +:encoding+ - Force the output to be in a certain encoding. Defaults to UTF-8.
22
+ # * +:format+ - Whether to format the string using CLI::UI.fmt. Defaults to true.
23
+ # * +:graceful+ - Whether to gracefully ignore common I/O errors. Defaults to true.
24
+ # * +:wrap+ - Whether to wrap text at word boundaries to terminal width. Defaults to true.
25
+ #
26
+ # ==== Returns
27
+ # Returns whether the message was successfully printed,
28
+ # which can be useful if +:graceful+ is set to true.
29
+ #
30
+ # ==== Example
31
+ #
32
+ # CLI::UI::Printer.puts('{{x}} Ouch', to: $stderr)
33
+ #
34
+ sig do
35
+ params(
36
+ msg: String,
37
+ frame_color: T.nilable(Colorable),
38
+ to: IOLike,
39
+ encoding: T.nilable(Encoding),
40
+ format: T::Boolean,
41
+ graceful: T::Boolean,
42
+ wrap: T::Boolean
43
+ ).returns(T::Boolean)
44
+ end
45
+ def self.puts(
46
+ msg,
47
+ frame_color: nil,
48
+ to: $stdout,
49
+ encoding: Encoding::UTF_8,
50
+ format: true,
51
+ graceful: true,
52
+ wrap: true
53
+ )
54
+ msg = (+msg).force_encoding(encoding) if encoding
55
+ msg = CLI::UI.fmt(msg) if format
56
+ msg = CLI::UI.wrap(msg) if wrap
57
+
58
+ if frame_color
59
+ CLI::UI::Frame.with_frame_color_override(frame_color) { to.puts(msg) }
60
+ else
61
+ to.puts(msg)
62
+ end
63
+
64
+ true
65
+ rescue Errno::EIO, Errno::EPIPE, IOError => e
66
+ raise(e) unless graceful
67
+
68
+ false
69
+ end
70
+ end
71
+ end
72
+ end