shopify-cli 1.0.4 โ†’ 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CONTRIBUTING.md +1 -1
  3. data/.travis.yml +3 -2
  4. data/CHANGELOG.md +21 -1
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +13 -13
  7. data/bin/load_shopify.rb +3 -1
  8. data/bin/shopify +2 -0
  9. data/docs/Gemfile.lock +23 -13
  10. data/docs/getting-started/index.md +3 -2
  11. data/docs/getting-started/install/index.md +55 -9
  12. data/docs/getting-started/uninstall/index.md +1 -1
  13. data/docs/getting-started/upgrade/index.md +8 -4
  14. data/ext/shopify-cli/extconf.rb +40 -20
  15. data/lib/project_types/extension/cli.rb +1 -0
  16. data/lib/project_types/extension/features/argo_config.rb +60 -0
  17. data/lib/project_types/extension/messages/messages.rb +3 -0
  18. data/lib/project_types/extension/models/type.rb +1 -0
  19. data/lib/project_types/extension/models/types/checkout_post_purchase.rb +5 -2
  20. data/lib/project_types/extension/tasks/create_extension.rb +1 -1
  21. data/lib/project_types/extension/tasks/get_app.rb +1 -1
  22. data/lib/project_types/extension/tasks/update_draft.rb +1 -1
  23. data/lib/project_types/node/commands/create.rb +4 -4
  24. data/lib/project_types/node/commands/deploy/heroku.rb +6 -1
  25. data/lib/project_types/node/commands/generate/billing.rb +7 -5
  26. data/lib/project_types/node/commands/generate/page.rb +9 -5
  27. data/lib/project_types/node/commands/generate/webhook.rb +5 -1
  28. data/lib/project_types/node/commands/serve.rb +5 -5
  29. data/lib/project_types/node/messages/messages.rb +5 -1
  30. data/lib/project_types/rails/commands/create.rb +56 -5
  31. data/lib/project_types/rails/commands/generate.rb +1 -0
  32. data/lib/project_types/rails/commands/generate/webhook.rb +3 -2
  33. data/lib/project_types/rails/commands/serve.rb +11 -7
  34. data/lib/project_types/rails/gem.rb +61 -6
  35. data/lib/project_types/rails/messages/messages.rb +32 -12
  36. data/lib/project_types/script/commands/create.rb +1 -5
  37. data/lib/project_types/script/commands/disable.rb +1 -2
  38. data/lib/project_types/script/commands/enable.rb +5 -5
  39. data/lib/project_types/script/commands/push.rb +1 -6
  40. data/lib/project_types/script/config/extension_points.yml +4 -4
  41. data/lib/project_types/script/errors.rb +8 -0
  42. data/lib/project_types/script/forms/create.rb +1 -1
  43. data/lib/project_types/script/layers/domain/errors.rb +2 -0
  44. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +36 -1
  45. data/lib/project_types/script/layers/infrastructure/errors.rb +8 -0
  46. data/lib/project_types/script/layers/infrastructure/script_service.rb +6 -2
  47. data/lib/project_types/script/messages/messages.rb +22 -48
  48. data/lib/project_types/script/ui/error_handler.rb +12 -0
  49. data/lib/rubygems_plugin.rb +18 -10
  50. data/lib/shopify-cli/admin_api/populate_resource_command.rb +1 -1
  51. data/lib/shopify-cli/command.rb +12 -6
  52. data/lib/shopify-cli/commands/connect.rb +7 -75
  53. data/lib/shopify-cli/commands/create.rb +1 -1
  54. data/lib/shopify-cli/commands/system.rb +21 -12
  55. data/lib/shopify-cli/context.rb +68 -0
  56. data/lib/shopify-cli/core/entry_point.rb +4 -1
  57. data/lib/shopify-cli/core/executor.rb +3 -5
  58. data/lib/shopify-cli/core/monorail.rb +1 -1
  59. data/lib/shopify-cli/db.rb +1 -1
  60. data/lib/shopify-cli/git.rb +1 -1
  61. data/lib/shopify-cli/heroku.rb +21 -5
  62. data/lib/shopify-cli/js_deps.rb +2 -2
  63. data/lib/shopify-cli/js_system.rb +2 -2
  64. data/lib/shopify-cli/messages/messages.rb +35 -25
  65. data/lib/shopify-cli/process_supervision.rb +60 -21
  66. data/lib/shopify-cli/project.rb +17 -9
  67. data/lib/shopify-cli/project_type.rb +3 -2
  68. data/lib/shopify-cli/sub_command.rb +1 -0
  69. data/lib/shopify-cli/task.rb +2 -2
  70. data/lib/shopify-cli/tasks.rb +11 -4
  71. data/lib/shopify-cli/tasks/ensure_env.rb +74 -17
  72. data/lib/shopify-cli/tunnel.rb +22 -7
  73. data/lib/shopify-cli/version.rb +1 -1
  74. data/lib/shopify_cli.rb +35 -9
  75. data/shopify-cli.gemspec +4 -1
  76. data/vendor/deps/cli-kit/REVISION +1 -1
  77. data/vendor/deps/cli-kit/lib/cli/kit.rb +1 -1
  78. data/vendor/deps/cli-kit/lib/cli/kit/autocall.rb +2 -2
  79. data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +12 -6
  80. data/vendor/deps/cli-kit/lib/cli/kit/executor.rb +9 -11
  81. data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +8 -2
  82. data/vendor/deps/cli-kit/lib/cli/kit/support/test_helper.rb +7 -7
  83. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +48 -17
  84. data/vendor/deps/cli-ui/REVISION +1 -1
  85. data/vendor/deps/cli-ui/lib/cli/ui.rb +5 -4
  86. data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +9 -3
  87. data/vendor/deps/cli-ui/lib/cli/ui/color.rb +1 -0
  88. data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +3 -2
  89. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +1 -0
  90. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/box.rb +13 -5
  91. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +29 -2
  92. data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +21 -10
  93. data/vendor/deps/cli-ui/lib/cli/ui/os.rb +63 -0
  94. data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +11 -2
  95. data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +1 -0
  96. data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +3 -3
  97. data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +6 -8
  98. data/vendor/deps/cli-ui/lib/cli/ui/widgets.rb +2 -0
  99. data/vendor/gen/lib/gen.rb +39 -0
  100. data/vendor/gen/lib/gen/commands.rb +18 -0
  101. data/vendor/gen/lib/gen/commands/help.rb +20 -0
  102. data/vendor/gen/lib/gen/commands/new.rb +21 -0
  103. data/vendor/gen/lib/gen/entry_point.rb +10 -0
  104. data/vendor/gen/lib/gen/generator.rb +165 -0
  105. data/vendor/gen/template/.gitignore +2 -0
  106. data/vendor/gen/template/Gemfile +10 -0
  107. data/vendor/gen/template/README.md +1 -0
  108. data/vendor/gen/template/bin/testunit +23 -0
  109. data/vendor/gen/template/bin/update-deps +97 -0
  110. data/vendor/gen/template/dev-gems.yml +3 -0
  111. data/vendor/gen/template/dev-vendor.yml +4 -0
  112. data/vendor/gen/template/exe/__app__-gems +17 -0
  113. data/vendor/gen/template/exe/__app__-vendor +18 -0
  114. data/vendor/gen/template/lib/__app__.rb +33 -0
  115. data/vendor/gen/template/lib/__app__/commands.rb +18 -0
  116. data/vendor/gen/template/lib/__app__/commands/example.rb +19 -0
  117. data/vendor/gen/template/lib/__app__/commands/help.rb +21 -0
  118. data/vendor/gen/template/lib/__app__/entry_point.rb +10 -0
  119. data/vendor/gen/template/test/example_test.rb +17 -0
  120. data/vendor/gen/template/test/test_helper.rb +22 -0
  121. metadata +26 -4
  122. data/Vagrantfile +0 -17
  123. data/lib/project_types/script/forms/script_form.rb +0 -69
@@ -10,7 +10,7 @@ module CLI
10
10
  def assert_all_commands_run(should_raise: true)
11
11
  errors = CLI::Kit::System.error_message
12
12
  CLI::Kit::System.reset!
13
- assert false, errors if should_raise && !errors.nil?
13
+ assert(false, errors) if should_raise && !errors.nil?
14
14
  errors
15
15
  end
16
16
 
@@ -196,22 +196,22 @@ module CLI
196
196
 
197
197
  unless errors[:unexpected].empty?
198
198
  final_error << CLI::UI.fmt(<<~EOF)
199
- {{bold:Unexpected command invocations:}}
200
- {{command:#{errors[:unexpected].join("\n")}}}
199
+ {{bold:Unexpected command invocations:}}
200
+ {{command:#{errors[:unexpected].join("\n")}}}
201
201
  EOF
202
202
  end
203
203
 
204
204
  unless errors[:not_run].empty?
205
205
  final_error << CLI::UI.fmt(<<~EOF)
206
- {{bold:Expected commands were not run:}}
207
- {{command:#{errors[:not_run].join("\n")}}}
206
+ {{bold:Expected commands were not run:}}
207
+ {{command:#{errors[:not_run].join("\n")}}}
208
208
  EOF
209
209
  end
210
210
 
211
211
  unless errors[:other].empty?
212
212
  final_error << CLI::UI.fmt(<<~EOF)
213
- {{bold:Commands were not run as expected:}}
214
- #{errors[:other].map { |cmd, msg| "{{command:#{cmd}}}\n#{msg}" }.join("\n\n")}
213
+ {{bold:Commands were not run as expected:}}
214
+ #{errors[:other].map { |cmd, msg| "{{command:#{cmd}}}\n#{msg}" }.join("\n\n")}
215
215
  EOF
216
216
  end
217
217
 
@@ -19,7 +19,7 @@ module CLI
19
19
  #
20
20
  def sudo_reason(msg)
21
21
  # See if sudo has a cached password
22
- `env SUDO_ASKPASS=/usr/bin/false sudo -A true`
22
+ %x(env SUDO_ASKPASS=/usr/bin/false sudo -A true)
23
23
  return if $CHILD_STATUS.success?
24
24
  CLI::UI.with_frame_color(:blue) do
25
25
  puts(CLI::UI.fmt("{{i}} #{msg}"))
@@ -90,6 +90,18 @@ module CLI
90
90
  delegate_open3(*a, sudo: sudo, env: env, method: :capture3, **kwargs)
91
91
  end
92
92
 
93
+ def popen2(*a, sudo: false, env: ENV, **kwargs, &block)
94
+ delegate_open3(*a, sudo: sudo, env: env, method: :popen2, **kwargs, &block)
95
+ end
96
+
97
+ def popen2e(*a, sudo: false, env: ENV, **kwargs)
98
+ delegate_open3(*a, sudo: sudo, env: env, method: :popen2e, **kwargs, &block)
99
+ end
100
+
101
+ def popen3(*a, sudo: false, env: ENV, **kwargs)
102
+ delegate_open3(*a, sudo: sudo, env: env, method: :popen3, **kwargs, &block)
103
+ end
104
+
93
105
  # Execute a command in the user's environment
94
106
  # Outputs result of the command without capturing it
95
107
  #
@@ -130,13 +142,11 @@ module CLI
130
142
 
131
143
  readers, = IO.select(ios)
132
144
  readers.each do |io|
133
- begin
134
- data, trailing = split_partial_characters(io.readpartial(4096))
135
- handlers[io].call(previous_trailing[io] + data)
136
- previous_trailing[io] = trailing
137
- rescue IOError
138
- io.close
139
- end
145
+ data, trailing = split_partial_characters(io.readpartial(4096))
146
+ handlers[io].call(previous_trailing[io] + data)
147
+ previous_trailing[io] = trailing
148
+ rescue IOError
149
+ io.close
140
150
  end
141
151
  end
142
152
 
@@ -163,6 +173,14 @@ module CLI
163
173
  [data.byteslice(0...partial_character_index), data.byteslice(partial_character_index..-1)]
164
174
  end
165
175
 
176
+ def os
177
+ return :mac if /darwin/.match(RUBY_PLATFORM)
178
+ return :linux if /linux/.match(RUBY_PLATFORM)
179
+ return :windows if /mingw32/.match(RUBY_PLATFORM)
180
+
181
+ raise "Could not determine OS from platform #{RUBY_PLATFORM}"
182
+ end
183
+
166
184
  private
167
185
 
168
186
  def apply_sudo(*a, sudo)
@@ -171,9 +189,9 @@ module CLI
171
189
  a
172
190
  end
173
191
 
174
- def delegate_open3(*a, sudo: raise, env: raise, method: raise, **kwargs)
192
+ def delegate_open3(*a, sudo: raise, env: raise, method: raise, **kwargs, &block)
175
193
  a = apply_sudo(*a, sudo)
176
- Open3.send(method, env, *resolve_path(a, env), **kwargs)
194
+ Open3.send(method, env, *resolve_path(a, env), **kwargs, &block)
177
195
  rescue Errno::EINTR
178
196
  raise(Errno::EINTR, "command interrupted: #{a.join(' ')}")
179
197
  end
@@ -189,17 +207,30 @@ module CLI
189
207
  # See https://github.com/Shopify/dev/pull/625 for more details.
190
208
  def resolve_path(a, env)
191
209
  # If only one argument was provided, make sure it's interpreted by a shell.
192
- return ["true ; " + a[0]] if a.size == 1
210
+ if a.size == 1
211
+ if os == :windows
212
+ return ["break && " + a[0]]
213
+ else
214
+ return ["true ; " + a[0]]
215
+ end
216
+ end
193
217
  return a if a.first.include?('/')
194
218
 
195
- paths = env.fetch('PATH', '').split(':')
196
- item = paths.detect do |f|
197
- command_path = "#{f}/#{a.first}"
198
- File.executable?(command_path) && File.file?(command_path)
219
+ item = which(a.first, env)
220
+ a[0] = item if item
221
+ a
222
+ end
223
+
224
+ def which(cmd, env)
225
+ exts = os == :windows ? env.fetch('PATHEXT').split(';') : ['']
226
+ env.fetch('PATH', '').split(File::PATH_SEPARATOR).each do |path|
227
+ exts.each do |ext|
228
+ exe = File.join(path, "#{cmd}#{ext}")
229
+ return exe if File.executable?(exe) && !File.directory?(exe)
230
+ end
199
231
  end
200
232
 
201
- a[0] = "#{item}/#{a.first}" if item
202
- a
233
+ nil
203
234
  end
204
235
  end
205
236
  end
@@ -1 +1 @@
1
- c59f601fe271432dfe304f30f08a48b2a343606e
1
+ 5ea578d3110af35c73837a8008147ce53a4b56ed (dirty)
@@ -4,6 +4,7 @@ module CLI
4
4
  autoload :Glyph, 'cli/ui/glyph'
5
5
  autoload :Color, 'cli/ui/color'
6
6
  autoload :Frame, 'cli/ui/frame'
7
+ autoload :OS, 'cli/ui/os'
7
8
  autoload :Printer, 'cli/ui/printer'
8
9
  autoload :Progress, 'cli/ui/progress'
9
10
  autoload :Prompt, 'cli/ui/prompt'
@@ -131,8 +132,8 @@ module CLI
131
132
  # * +args+ - arguments for +Frame.open+
132
133
  # * +block+ - block for +Frame.open+
133
134
  #
134
- def self.frame(*args, &block)
135
- CLI::UI::Frame.open(*args, &block)
135
+ def self.frame(*args, **kwargs, &block)
136
+ CLI::UI::Frame.open(*args, **kwargs, &block)
136
137
  end
137
138
 
138
139
  # Convenience Method for +CLI::UI::Spinner.spin+
@@ -142,8 +143,8 @@ module CLI
142
143
  # * +args+ - arguments for +Spinner.open+
143
144
  # * +block+ - block for +Spinner.open+
144
145
  #
145
- def self.spinner(*args, &block)
146
- CLI::UI::Spinner.spin(*args, &block)
146
+ def self.spinner(*args, **kwargs, &block)
147
+ CLI::UI::Spinner.spin(*args, **kwargs, &block)
147
148
  end
148
149
 
149
150
  # Convenience Method to override frame color using +CLI::UI::Frame.with_frame_color+
@@ -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
@@ -48,6 +48,7 @@ module CLI
48
48
 
49
49
  class InvalidColorName < ArgumentError
50
50
  def initialize(name)
51
+ super
51
52
  @name = name
52
53
  end
53
54
 
@@ -227,11 +227,12 @@ module CLI
227
227
  end
228
228
 
229
229
  # The width of a prefix given the number of Frames in the stack
230
- # Does _not_ account for the space at the end of the final prefix
231
230
  def prefix_width
232
- FrameStack.items.reduce(0) do |width, item|
231
+ w = FrameStack.items.reduce(0) do |width, item|
233
232
  width + item.frame_style.prefix_width
234
233
  end
234
+
235
+ w.zero? ? w : w + 1
235
236
  end
236
237
 
237
238
  # Override a color for a given thread.
@@ -32,6 +32,7 @@ module CLI
32
32
 
33
33
  class InvalidFrameStyleName < ArgumentError
34
34
  def initialize(name)
35
+ super
35
36
  @name = name
36
37
  end
37
38
 
@@ -20,10 +20,6 @@ module CLI
20
20
  VERTICAL
21
21
  end
22
22
 
23
- def prefix_width
24
- CLI::UI::ANSI.printing_width(prefix)
25
- end
26
-
27
23
  # Draws the "Open" line for this frame style
28
24
  #
29
25
  # ==== Attributes
@@ -103,7 +99,10 @@ module CLI
103
99
 
104
100
  preamble_width = CLI::UI::ANSI.printing_width(preamble)
105
101
  preamble_start = Frame.prefix_width
106
- preamble_end = preamble_start + preamble_width
102
+ # If prefix_width is non-zero, we need to subtract the width of
103
+ # the final space, since we're going to write over it.
104
+ preamble_start -= 1 unless preamble_start.zero?
105
+ preamble_end = preamble_start + preamble_width
107
106
 
108
107
  suffix_width = CLI::UI::ANSI.printing_width(suffix)
109
108
  suffix_end = termwidth - 2
@@ -139,6 +138,15 @@ module CLI
139
138
  # reset to column 1 so that things like ^C don't ruin formatting
140
139
  o << "\r"
141
140
 
141
+ # This code will print out a full line with the given preamble and
142
+ # suffix, as exemplified below.
143
+ #
144
+ # preamble_start suffix_start
145
+ # | preamble_end | suffix_end
146
+ # | | | | termwidth
147
+ # | | | | |
148
+ # V V V V V
149
+ # --- Preamble text --------------------- suffix text --
142
150
  o << color.code
143
151
  o << print_at_x(preamble_start, HORIZONTAL * (termwidth - preamble_start)) # draw a full line
144
152
  o << print_at_x(preamble_start, preamble)
@@ -97,8 +97,35 @@ module CLI
97
97
 
98
98
  o = +''
99
99
 
100
- o << color.code << preamble
101
- o << color.code << suffix
100
+ # Shopify's CI system supports terminal emulation, but not some of
101
+ # the fancier features that we normally use to draw frames
102
+ # extra-reliably, so we fall back to a less foolproof strategy. This
103
+ # is probably better in general for cases with impoverished terminal
104
+ # emulators and no active user.
105
+ unless [0, '', nil].include?(ENV['CI'])
106
+ o << color.code << preamble
107
+ o << color.code << suffix
108
+ o << CLI::UI::Color::RESET.code
109
+ o << "\n"
110
+
111
+ return o
112
+ end
113
+
114
+ preamble_start = Frame.prefix_width
115
+
116
+ # If prefix_width is non-zero, we need to subtract the width of
117
+ # the final space, since we're going to write over it.
118
+ preamble_start -= 1 unless preamble_start.zero?
119
+
120
+ # Prefix_width includes the width of the terminal space, which we
121
+ # want to remove. The clamping is done to avoid a negative
122
+ # preamble start which can occur for the first frame.
123
+ o << CLI::UI::ANSI.hide_cursor
124
+
125
+ # reset to column 1 so that things like ^C don't ruin formatting
126
+ o << "\r"
127
+ o << color.code
128
+ o << print_at_x(preamble_start, preamble + color.code + suffix)
102
129
  o << CLI::UI::Color::RESET.code
103
130
  o << "\n"
104
131
 
@@ -5,6 +5,7 @@ module CLI
5
5
  class Glyph
6
6
  class InvalidGlyphHandle < ArgumentError
7
7
  def initialize(handle)
8
+ super
8
9
  @handle = handle
9
10
  end
10
11
 
@@ -15,7 +16,7 @@ module CLI
15
16
  end
16
17
  end
17
18
 
18
- attr_reader :handle, :codepoint, :color, :char, :to_s, :fmt
19
+ attr_reader :handle, :codepoint, :color, :to_s, :fmt
19
20
 
20
21
  # Creates a new glyph
21
22
  #
@@ -23,12 +24,14 @@ module CLI
23
24
  #
24
25
  # * +handle+ - The handle in the +MAP+ constant
25
26
  # * +codepoint+ - The codepoint used to create the glyph (e.g. +0x2717+ for a ballot X)
27
+ # * +plain+ - A fallback plain string to be used in case glyphs are disabled
26
28
  # * +color+ - What color to output the glyph. Check +CLI::UI::Color+ for options.
27
29
  #
28
- def initialize(handle, codepoint, color)
30
+ def initialize(handle, codepoint, plain, color)
29
31
  @handle = handle
30
32
  @codepoint = codepoint
31
33
  @color = color
34
+ @plain = plain
32
35
  @char = Array(codepoint).pack('U*')
33
36
  @to_s = color.code + char + Color::RESET.code
34
37
  @fmt = "{{#{color.name}:#{char}}}"
@@ -36,16 +39,24 @@ module CLI
36
39
  MAP[handle] = self
37
40
  end
38
41
 
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
+
39
50
  # Mapping of glyphs to terminal output
40
51
  MAP = {}
41
- STAR = new('*', 0x2b51, Color::YELLOW) # YELLOW SMALL STAR (โญ‘)
42
- INFO = new('i', 0x1d4be, Color::BLUE) # BLUE MATHEMATICAL SCRIPT SMALL i (๐’พ)
43
- QUESTION = new('?', 0x003f, Color::BLUE) # BLUE QUESTION MARK (?)
44
- CHECK = new('v', 0x2713, Color::GREEN) # GREEN CHECK MARK (โœ“)
45
- X = new('x', 0x2717, Color::RED) # RED BALLOT X (โœ—)
46
- BUG = new('b', 0x1f41b, Color::WHITE) # Bug emoji (๐Ÿ›)
47
- CHEVRON = new('>', 0xbb, Color::YELLOW) # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (ยป)
48
- HOURGLASS = new('H', [0x231b, 0xfe0e], Color::BLUE) # HOURGLASS + VARIATION SELECTOR 15 (โŒ›๏ธŽ)
52
+ STAR = new('*', 0x2b51, '*', Color::YELLOW) # YELLOW SMALL STAR (โญ‘)
53
+ INFO = new('i', 0x1d4be, 'i', Color::BLUE) # BLUE MATHEMATICAL SCRIPT SMALL i (๐’พ)
54
+ QUESTION = new('?', 0x003f, '?', Color::BLUE) # BLUE QUESTION MARK (?)
55
+ CHECK = new('v', 0x2713, 'โˆš', Color::GREEN) # GREEN CHECK MARK (โœ“)
56
+ X = new('x', 0x2717, 'X', Color::RED) # RED BALLOT X (โœ—)
57
+ BUG = new('b', 0x1f41b, '!', Color::WHITE) # Bug emoji (๐Ÿ›)
58
+ CHEVRON = new('>', 0xbb, 'ยป', Color::YELLOW) # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (ยป)
59
+ HOURGLASS = new('H', [0x231b, 0xfe0e], 'H', Color::BLUE) # HOURGLASS + VARIATION SELECTOR 15 (โŒ›๏ธŽ)
49
60
 
50
61
  # Looks up a glyph by name
51
62
  #
@@ -0,0 +1,63 @@
1
+ module CLI
2
+ module UI
3
+ module OS
4
+ # Determines which OS is currently running the UI, to make it easier to
5
+ # adapt its behaviour to the features of the OS.
6
+ def self.current
7
+ @current_os ||= case RUBY_PLATFORM
8
+ when /darwin/
9
+ Mac
10
+ when /linux/
11
+ Linux
12
+ when /mingw32/
13
+ Windows
14
+ else
15
+ raise "Could not determine OS from platform #{RUBY_PLATFORM}"
16
+ end
17
+ end
18
+
19
+ class Mac
20
+ class << self
21
+ def supports_emoji?
22
+ true
23
+ end
24
+
25
+ def supports_color_prompt?
26
+ true
27
+ end
28
+
29
+ def supports_arrow_keys?
30
+ true
31
+ end
32
+
33
+ def shift_cursor_on_line_reset?
34
+ false
35
+ end
36
+ end
37
+ end
38
+
39
+ class Linux < Mac
40
+ end
41
+
42
+ class Windows
43
+ class << self
44
+ def supports_emoji?
45
+ false
46
+ end
47
+
48
+ def supports_color_prompt?
49
+ false
50
+ end
51
+
52
+ def supports_arrow_keys?
53
+ false
54
+ end
55
+
56
+ def shift_cursor_on_line_reset?
57
+ true
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end