shopify-cli 0.9.2 โ 0.9.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/CHANGELOG.md +5 -0
- data/docs/_config.yml +3 -0
- data/docs/_data/nav.yml +9 -0
- data/docs/getting-started/index.md +5 -40
- data/docs/getting-started/install/index.md +39 -0
- data/docs/getting-started/migrate/index.md +63 -0
- data/docs/getting-started/uninstall/index.md +37 -0
- data/docs/getting-started/upgrade/index.md +37 -0
- data/docs/index.md +5 -6
- data/lib/project_types/extension/cli.rb +2 -1
- data/lib/project_types/extension/commands/tunnel.rb +1 -1
- data/lib/project_types/extension/forms/register.rb +2 -3
- data/lib/project_types/extension/graphql/get_app_by_api_key.graphql +9 -0
- data/lib/project_types/extension/tasks/converters/app_converter.rb +27 -0
- data/lib/project_types/extension/tasks/get_app.rb +22 -0
- data/lib/project_types/extension/tasks/get_apps.rb +1 -6
- data/lib/project_types/script/cli.rb +3 -2
- data/lib/project_types/script/commands/create.rb +5 -4
- data/lib/project_types/script/errors.rb +1 -0
- data/lib/project_types/script/forms/create.rb +8 -4
- data/lib/project_types/script/layers/application/create_script.rb +11 -18
- data/lib/project_types/script/layers/application/project_dependencies.rb +0 -5
- data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +106 -0
- data/lib/project_types/script/layers/infrastructure/errors.rb +1 -1
- data/lib/project_types/script/layers/infrastructure/project_creator.rb +23 -0
- data/lib/project_types/script/layers/infrastructure/script_repository.rb +0 -33
- data/lib/project_types/script/messages/messages.rb +5 -6
- data/lib/project_types/script/templates/ts/as-pect.d.ts +1 -0
- data/lib/project_types/script/ui/error_handler.rb +5 -0
- data/lib/shopify-cli/tunnel.rb +33 -1
- data/lib/shopify-cli/version.rb +1 -1
- data/vendor/deps/cli-ui/REVISION +1 -1
- data/vendor/deps/cli-ui/lib/cli/ui.rb +52 -11
- data/vendor/deps/cli-ui/lib/cli/ui/color.rb +11 -7
- data/vendor/deps/cli-ui/lib/cli/ui/formatter.rb +34 -21
- data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +107 -149
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +99 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +119 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/box.rb +158 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +112 -0
- data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +9 -15
- data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +47 -0
- data/vendor/deps/cli-ui/lib/cli/ui/progress.rb +9 -7
- data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +39 -14
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +62 -44
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/options_handler.rb +7 -2
- data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +23 -3
- data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +34 -10
- data/vendor/deps/cli-ui/lib/cli/ui/stdout_router.rb +12 -7
- data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +26 -16
- data/vendor/deps/cli-ui/lib/cli/ui/truncater.rb +3 -3
- data/vendor/deps/cli-ui/lib/cli/ui/widgets.rb +75 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets/base.rb +27 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets/status.rb +61 -0
- metadata +20 -7
- data/lib/project_types/extension/features/tunnel_url.rb +0 -20
- data/lib/project_types/script/layers/infrastructure/assemblyscript_dependency_manager.rb +0 -51
- data/lib/project_types/script/layers/infrastructure/dependency_manager.rb +0 -36
- data/lib/project_types/script/layers/infrastructure/test_suite_repository.rb +0 -62
- data/vendor/deps/cli-ui/lib/cli/ui/box.rb +0 -15
@@ -29,7 +29,7 @@ module CLI
|
|
29
29
|
@handle = handle
|
30
30
|
@codepoint = codepoint
|
31
31
|
@color = color
|
32
|
-
@char =
|
32
|
+
@char = Array(codepoint).pack('U*')
|
33
33
|
@to_s = color.code + char + Color::RESET.code
|
34
34
|
@fmt = "{{#{color.name}:#{char}}}"
|
35
35
|
|
@@ -38,20 +38,14 @@ module CLI
|
|
38
38
|
|
39
39
|
# Mapping of glyphs to terminal output
|
40
40
|
MAP = {}
|
41
|
-
#
|
42
|
-
|
43
|
-
# BLUE
|
44
|
-
|
45
|
-
#
|
46
|
-
|
47
|
-
#
|
48
|
-
|
49
|
-
# RED BALLOT X (โ)
|
50
|
-
X = new('x', 0x2717, Color::RED)
|
51
|
-
# Bug emoji (๐)
|
52
|
-
BUG = new('b', 0x1f41b, Color::WHITE)
|
53
|
-
# RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (ยป)
|
54
|
-
CHEVRON = new('>', 0xbb, Color::YELLOW)
|
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 (โ๏ธ)
|
55
49
|
|
56
50
|
# Looks up a glyph by name
|
57
51
|
#
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'cli/ui'
|
2
|
+
|
3
|
+
module CLI
|
4
|
+
module UI
|
5
|
+
class Printer
|
6
|
+
# Print a message to a stream with common utilities.
|
7
|
+
# Allows overriding the color, encoding, and target stream.
|
8
|
+
# By default, it formats the string using CLI:UI and rescues common stream errors.
|
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
|
+
#
|
22
|
+
# ==== Returns
|
23
|
+
# Returns whether the message was successfully printed,
|
24
|
+
# which can be useful if +:graceful+ is set to true.
|
25
|
+
#
|
26
|
+
# ==== Example
|
27
|
+
#
|
28
|
+
# CLI::UI::Printer.puts('{x} Ouch', stream: $stderr, color: :red)
|
29
|
+
#
|
30
|
+
def self.puts(msg, frame_color: nil, to: $stdout, encoding: Encoding::UTF_8, format: true, graceful: true)
|
31
|
+
msg = (+msg).force_encoding(encoding) if encoding
|
32
|
+
msg = CLI::UI.fmt(msg) if format
|
33
|
+
|
34
|
+
if frame_color
|
35
|
+
CLI::UI::Frame.with_frame_color_override(frame_color) { to.puts(msg) }
|
36
|
+
else
|
37
|
+
to.puts(msg)
|
38
|
+
end
|
39
|
+
|
40
|
+
true
|
41
|
+
rescue Errno::EIO, Errno::EPIPE, IOError => e
|
42
|
+
raise(e) unless graceful
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -26,11 +26,11 @@ module CLI
|
|
26
26
|
#
|
27
27
|
# Increase the percent by X
|
28
28
|
# CLI::UI::Progress.progress do |bar|
|
29
|
-
# bar.tick(percent:
|
29
|
+
# bar.tick(percent: 0.05)
|
30
30
|
# end
|
31
31
|
def self.progress(width: Terminal.width)
|
32
32
|
bar = Progress.new(width: width)
|
33
|
-
print
|
33
|
+
print(CLI::UI::ANSI.hide_cursor)
|
34
34
|
yield(bar)
|
35
35
|
ensure
|
36
36
|
puts bar.to_s
|
@@ -59,14 +59,16 @@ module CLI
|
|
59
59
|
# * +:percent+ - Increment progress by a specific percent amount
|
60
60
|
# * +:set_percent+ - Set progress to a specific percent
|
61
61
|
#
|
62
|
+
# *Note:* The +:percent+ and +:set_percent must be between 0.00 and 1.0
|
63
|
+
#
|
62
64
|
def tick(percent: 0.01, set_percent: nil)
|
63
65
|
raise ArgumentError, 'percent and set_percent cannot both be specified' if percent != 0.01 && set_percent
|
64
66
|
@percent_done += percent
|
65
67
|
@percent_done = set_percent if set_percent
|
66
68
|
@percent_done = [@percent_done, 1.0].min # Make sure we can't go above 1.0
|
67
69
|
|
68
|
-
print
|
69
|
-
print
|
70
|
+
print(to_s)
|
71
|
+
print(CLI::UI::ANSI.previous_line + "\n")
|
70
72
|
end
|
71
73
|
|
72
74
|
# Format the progress bar to be printed to terminal
|
@@ -77,11 +79,11 @@ module CLI
|
|
77
79
|
filled = [(@percent_done * workable_width.to_f).ceil, 0].max
|
78
80
|
unfilled = [workable_width - filled, 0].max
|
79
81
|
|
80
|
-
CLI::UI.resolve_text
|
82
|
+
CLI::UI.resolve_text([
|
81
83
|
FILLED_BAR + ' ' * filled,
|
82
84
|
UNFILLED_BAR + ' ' * unfilled,
|
83
|
-
CLI::UI::Color::RESET.code + suffix
|
84
|
-
].join
|
85
|
+
CLI::UI::Color::RESET.code + suffix,
|
86
|
+
].join)
|
85
87
|
end
|
86
88
|
end
|
87
89
|
end
|
@@ -36,7 +36,8 @@ module CLI
|
|
36
36
|
# * +:select_ui+ - Enable long-form option selection (default: true)
|
37
37
|
#
|
38
38
|
# Note:
|
39
|
-
# * +:options+ or providing a +Block+ conflicts with +:default+ and +:is_file+,
|
39
|
+
# * +:options+ or providing a +Block+ conflicts with +:default+ and +:is_file+,
|
40
|
+
# you cannot set options with either of these keywords
|
40
41
|
# * +:default+ conflicts with +:allow_empty:, you cannot set these together
|
41
42
|
# * +:options+ conflicts with providing a +Block+ , you may only set one
|
42
43
|
# * +:multiple+ can only be used with +:options+ or a +Block+; it is ignored, otherwise.
|
@@ -49,7 +50,7 @@ module CLI
|
|
49
50
|
# ==== Return Value
|
50
51
|
#
|
51
52
|
# * If a +Block+ was not provided, the selected option or response to the free form question will be returned
|
52
|
-
# * If a +Block+ was provided, the
|
53
|
+
# * If a +Block+ was provided, the evaluated value of the +Block+ will be returned
|
53
54
|
#
|
54
55
|
# ==== Example Usage:
|
55
56
|
#
|
@@ -76,13 +77,35 @@ module CLI
|
|
76
77
|
# handler.option('python') { |selection| selection }
|
77
78
|
# end
|
78
79
|
#
|
79
|
-
def ask(
|
80
|
-
|
80
|
+
def ask(
|
81
|
+
question,
|
82
|
+
options: nil,
|
83
|
+
default: nil,
|
84
|
+
is_file: nil,
|
85
|
+
allow_empty: true,
|
86
|
+
multiple: false,
|
87
|
+
filter_ui: true,
|
88
|
+
select_ui: true,
|
89
|
+
&options_proc
|
90
|
+
)
|
91
|
+
if (options || block_given?) && ((default && !multiple) || is_file)
|
81
92
|
raise(ArgumentError, 'conflicting arguments: options provided with default or is_file')
|
82
93
|
end
|
83
94
|
|
95
|
+
if options && multiple && default && !(default - options).empty?
|
96
|
+
raise(ArgumentError, 'conflicting arguments: default should only include elements present in options')
|
97
|
+
end
|
98
|
+
|
84
99
|
if options || block_given?
|
85
|
-
ask_interactive(
|
100
|
+
ask_interactive(
|
101
|
+
question,
|
102
|
+
options,
|
103
|
+
multiple: multiple,
|
104
|
+
default: default,
|
105
|
+
filter_ui: filter_ui,
|
106
|
+
select_ui: select_ui,
|
107
|
+
&options_proc
|
108
|
+
)
|
86
109
|
else
|
87
110
|
ask_free_form(question, default, is_file, allow_empty)
|
88
111
|
end
|
@@ -132,7 +155,9 @@ module CLI
|
|
132
155
|
private
|
133
156
|
|
134
157
|
def ask_free_form(question, default, is_file, allow_empty)
|
135
|
-
|
158
|
+
if default && !allow_empty
|
159
|
+
raise(ArgumentError, 'conflicting arguments: default enabled but allow_empty is false')
|
160
|
+
end
|
136
161
|
|
137
162
|
if default
|
138
163
|
puts_question("#{question} (empty = #{default})")
|
@@ -155,7 +180,7 @@ module CLI
|
|
155
180
|
end
|
156
181
|
end
|
157
182
|
|
158
|
-
def ask_interactive(question, options = nil, multiple: false, filter_ui: true, select_ui: true)
|
183
|
+
def ask_interactive(question, options = nil, multiple: false, default: nil, filter_ui: true, select_ui: true)
|
159
184
|
raise(ArgumentError, 'conflicting arguments: options and block given') if options && block_given?
|
160
185
|
|
161
186
|
options ||= if block_given?
|
@@ -167,14 +192,14 @@ module CLI
|
|
167
192
|
raise(ArgumentError, 'insufficient options') if options.nil? || options.empty?
|
168
193
|
instructions = (multiple ? "Toggle options. " : "") + "Choose with โ โ โ"
|
169
194
|
instructions += ", filter with 'f'" if filter_ui
|
170
|
-
instructions += ", enter option with 'e'" if select_ui
|
195
|
+
instructions += ", enter option with 'e'" if select_ui && (options.size > 9)
|
171
196
|
puts_question("#{question} {{yellow:(#{instructions})}}")
|
172
|
-
resp = interactive_prompt(options, multiple: multiple)
|
197
|
+
resp = interactive_prompt(options, multiple: multiple, default: default)
|
173
198
|
|
174
199
|
# Clear the line
|
175
|
-
print
|
200
|
+
print(ANSI.previous_line + ANSI.clear_to_end_of_line)
|
176
201
|
# Force StdoutRouter to prefix
|
177
|
-
print
|
202
|
+
print(ANSI.previous_line + "\n")
|
178
203
|
|
179
204
|
# reset the question to include the answer
|
180
205
|
resp_text = resp
|
@@ -195,8 +220,8 @@ module CLI
|
|
195
220
|
end
|
196
221
|
|
197
222
|
# Useful for stubbing in tests
|
198
|
-
def interactive_prompt(options, multiple: false)
|
199
|
-
InteractiveOptions.call(options, multiple: multiple)
|
223
|
+
def interactive_prompt(options, multiple: false, default: nil)
|
224
|
+
InteractiveOptions.call(options, multiple: multiple, default: default)
|
200
225
|
end
|
201
226
|
|
202
227
|
def write_default_over_empty_input(default)
|
@@ -235,7 +260,7 @@ module CLI
|
|
235
260
|
|
236
261
|
begin
|
237
262
|
line = Readline.readline(prompt, true)
|
238
|
-
print
|
263
|
+
print(CLI::UI::Color::RESET.code)
|
239
264
|
line.to_s.chomp
|
240
265
|
rescue Interrupt
|
241
266
|
CLI::UI.raw { STDERR.puts('^C' + CLI::UI::Color::RESET.code) }
|
@@ -22,8 +22,8 @@ module CLI
|
|
22
22
|
# Ask an interactive question
|
23
23
|
# CLI::UI::Prompt::InteractiveOptions.call(%w(rails go python))
|
24
24
|
#
|
25
|
-
def self.call(options, multiple: false)
|
26
|
-
list = new(options, multiple: multiple)
|
25
|
+
def self.call(options, multiple: false, default: nil)
|
26
|
+
list = new(options, multiple: multiple, default: default)
|
27
27
|
selected = list.call
|
28
28
|
if multiple
|
29
29
|
selected.map { |s| options[s - 1] }
|
@@ -39,7 +39,7 @@ module CLI
|
|
39
39
|
#
|
40
40
|
# CLI::UI::Prompt::InteractiveOptions.new(%w(rails go python))
|
41
41
|
#
|
42
|
-
def initialize(options, multiple: false)
|
42
|
+
def initialize(options, multiple: false, default: nil)
|
43
43
|
@options = options
|
44
44
|
@active = 1
|
45
45
|
@marker = '>'
|
@@ -52,7 +52,13 @@ module CLI
|
|
52
52
|
@filter = ''
|
53
53
|
# 0-indexed array representing if selected
|
54
54
|
# @options[0] is selected if @chosen[0]
|
55
|
-
|
55
|
+
if multiple
|
56
|
+
@chosen = if default
|
57
|
+
@options.map { |option| default.include?(option) }
|
58
|
+
else
|
59
|
+
Array.new(@options.size) { false }
|
60
|
+
end
|
61
|
+
end
|
56
62
|
@redraw = true
|
57
63
|
@presented_options = []
|
58
64
|
end
|
@@ -95,16 +101,16 @@ module CLI
|
|
95
101
|
@option_lengths = @options.map do |text|
|
96
102
|
width = 1 if text.empty?
|
97
103
|
width ||= text
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
104
|
+
.split("\n")
|
105
|
+
.reject(&:empty?)
|
106
|
+
.map { |l| (CLI::UI.fmt(l, enable_color: false).length / max_width).ceil }
|
107
|
+
.reduce(&:+)
|
102
108
|
|
103
109
|
width
|
104
110
|
end
|
105
111
|
end
|
106
112
|
|
107
|
-
def reset_position(number_of_lines=num_lines)
|
113
|
+
def reset_position(number_of_lines = num_lines)
|
108
114
|
# This will put us back at the beginning of the options
|
109
115
|
# When we redraw the options, they will be overwritten
|
110
116
|
CLI::UI.raw do
|
@@ -112,12 +118,12 @@ module CLI
|
|
112
118
|
end
|
113
119
|
end
|
114
120
|
|
115
|
-
def clear_output(number_of_lines=num_lines)
|
121
|
+
def clear_output(number_of_lines = num_lines)
|
116
122
|
CLI::UI.raw do
|
117
123
|
# Write over all lines with whitespace
|
118
124
|
number_of_lines.times { puts(' ' * CLI::UI::Terminal.width) }
|
119
125
|
end
|
120
|
-
reset_position
|
126
|
+
reset_position(number_of_lines)
|
121
127
|
|
122
128
|
# Update if metadata is being displayed
|
123
129
|
# This must be done _after_ the output is cleared or it won't draw over
|
@@ -128,7 +134,7 @@ module CLI
|
|
128
134
|
# Don't use this in place of +@displaying_metadata+, this updates too
|
129
135
|
# quickly to be useful when drawing to the screen.
|
130
136
|
def display_metadata?
|
131
|
-
filtering?
|
137
|
+
filtering? || selecting? || has_filter?
|
132
138
|
end
|
133
139
|
|
134
140
|
def num_lines
|
@@ -136,7 +142,7 @@ module CLI
|
|
136
142
|
|
137
143
|
option_length = presented_options.reduce(0) do |total_length, (_, option_number)|
|
138
144
|
# Handle continuation markers and "Done" option when multiple is true
|
139
|
-
next total_length + 1 if option_number.nil?
|
145
|
+
next total_length + 1 if option_number.nil? || option_number.zero?
|
140
146
|
total_length + @option_lengths[option_number - 1]
|
141
147
|
end
|
142
148
|
|
@@ -153,7 +159,7 @@ module CLI
|
|
153
159
|
CTRL_D = "\u0004"
|
154
160
|
|
155
161
|
def up
|
156
|
-
active_index = @filtered_options.index { |_,num| num == @active } || 0
|
162
|
+
active_index = @filtered_options.index { |_, num| num == @active } || 0
|
157
163
|
|
158
164
|
previous_visible = @filtered_options[active_index - 1]
|
159
165
|
previous_visible ||= @filtered_options.last
|
@@ -163,7 +169,7 @@ module CLI
|
|
163
169
|
end
|
164
170
|
|
165
171
|
def down
|
166
|
-
active_index = @filtered_options.index { |_,num| num == @active } || 0
|
172
|
+
active_index = @filtered_options.index { |_, num| num == @active } || 0
|
167
173
|
|
168
174
|
next_visible = @filtered_options[active_index + 1]
|
169
175
|
next_visible ||= @filtered_options.first
|
@@ -216,7 +222,7 @@ module CLI
|
|
216
222
|
@redraw = true
|
217
223
|
|
218
224
|
# Control+D or Backspace on empty search closes search
|
219
|
-
if char == CTRL_D
|
225
|
+
if (char == CTRL_D) || (@filter.empty? && (char == BACKSPACE))
|
220
226
|
@filter = ''
|
221
227
|
@state = :root
|
222
228
|
return
|
@@ -231,7 +237,7 @@ module CLI
|
|
231
237
|
|
232
238
|
def select_current
|
233
239
|
# Prevent selection of invisible options
|
234
|
-
return unless presented_options.any? { |_,num| num == @active }
|
240
|
+
return unless presented_options.any? { |_, num| num == @active }
|
235
241
|
select_n(@active)
|
236
242
|
end
|
237
243
|
|
@@ -240,7 +246,7 @@ module CLI
|
|
240
246
|
wait_for_user_input until @redraw
|
241
247
|
end
|
242
248
|
|
243
|
-
# rubocop:disable Style/WhenThen,Layout/SpaceBeforeSemicolon
|
249
|
+
# rubocop:disable Style/WhenThen,Layout/SpaceBeforeSemicolon,Style/Semicolon
|
244
250
|
def wait_for_user_input
|
245
251
|
char = read_char
|
246
252
|
@last_char = char
|
@@ -250,17 +256,18 @@ module CLI
|
|
250
256
|
when CTRL_C ; raise Interrupt
|
251
257
|
end
|
252
258
|
|
259
|
+
max_digit = [@options.size, 9].min.to_s
|
253
260
|
case @state
|
254
261
|
when :root
|
255
262
|
case char
|
256
|
-
when ESC
|
257
|
-
when 'k'
|
258
|
-
when 'j'
|
259
|
-
when 'e', ':', 'G'
|
260
|
-
when 'f', '/'
|
261
|
-
when ('0'
|
262
|
-
when 'y', 'n'
|
263
|
-
when " ", "\r", "\n"
|
263
|
+
when ESC ; @state = :esc
|
264
|
+
when 'k' ; up
|
265
|
+
when 'j' ; down
|
266
|
+
when 'e', ':', 'G' ; start_line_select
|
267
|
+
when 'f', '/' ; start_filter
|
268
|
+
when ('0'..max_digit) ; select_n(char.to_i)
|
269
|
+
when 'y', 'n' ; select_bool(char)
|
270
|
+
when " ", "\r", "\n" ; select_current # <enter>
|
264
271
|
end
|
265
272
|
when :filter
|
266
273
|
case char
|
@@ -273,9 +280,9 @@ module CLI
|
|
273
280
|
when ESC ; @state = :esc
|
274
281
|
when 'k' ; up ; @state = :root
|
275
282
|
when 'j' ; down ; @state = :root
|
276
|
-
when 'e',':','G','q' ; stop_line_select
|
283
|
+
when 'e', ':', 'G', 'q' ; stop_line_select
|
277
284
|
when '0'..'9' ; build_selection(char)
|
278
|
-
when BACKSPACE ; chop_selection
|
285
|
+
when BACKSPACE ; chop_selection # Pop last input on backspace
|
279
286
|
when ' ', "\r", "\n" ; select_current
|
280
287
|
end
|
281
288
|
when :esc
|
@@ -347,16 +354,27 @@ module CLI
|
|
347
354
|
|
348
355
|
@presented_options = @options.zip(1..Float::INFINITY)
|
349
356
|
if has_filter?
|
350
|
-
@presented_options.select! { |option,_| option.downcase.include?(@filter.downcase) }
|
357
|
+
@presented_options.select! { |option, _| option.downcase.include?(@filter.downcase) }
|
351
358
|
end
|
352
359
|
|
353
360
|
# Used for selection purposes
|
361
|
+
@presented_options.push([DONE, 0]) if @multiple
|
354
362
|
@filtered_options = @presented_options.dup
|
355
363
|
|
356
|
-
@presented_options.unshift([DONE, 0]) if @multiple
|
357
|
-
|
358
364
|
ensure_visible_is_active if has_filter?
|
359
365
|
|
366
|
+
# Must have more lines before the selection than we can display
|
367
|
+
if distance_from_start_to_selection > max_lines
|
368
|
+
@presented_options.shift(distance_from_start_to_selection - max_lines)
|
369
|
+
ensure_first_item_is_continuation_marker
|
370
|
+
end
|
371
|
+
|
372
|
+
# Must have more lines after the selection than we can display
|
373
|
+
if distance_from_selection_to_end > max_lines
|
374
|
+
@presented_options.pop(distance_from_selection_to_end - max_lines)
|
375
|
+
ensure_last_item_is_continuation_marker
|
376
|
+
end
|
377
|
+
|
360
378
|
while num_lines > max_lines
|
361
379
|
# try to keep the selection centered in the window:
|
362
380
|
if distance_from_selection_to_end > distance_from_start_to_selection
|
@@ -388,7 +406,7 @@ module CLI
|
|
388
406
|
end
|
389
407
|
|
390
408
|
def index_of_active_option
|
391
|
-
@presented_options.index { |_,num| num == @active }.to_i
|
409
|
+
@presented_options.index { |_, num| num == @active }.to_i
|
392
410
|
end
|
393
411
|
|
394
412
|
def ensure_last_item_is_continuation_marker
|
@@ -415,14 +433,14 @@ module CLI
|
|
415
433
|
max_num_length = (@options.size + 1).to_s.length
|
416
434
|
|
417
435
|
metadata_text = if selecting?
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
436
|
+
select_text = @active
|
437
|
+
select_text = '{{info:e, q, or up/down anytime to exit}}' if @active == 0
|
438
|
+
"Select: #{select_text}"
|
439
|
+
elsif filtering? || has_filter?
|
440
|
+
filter_text = @filter
|
441
|
+
filter_text = '{{info:Ctrl-D anytime or Backspace now to exit}}' if @filter.empty?
|
442
|
+
"Filter: #{filter_text}"
|
443
|
+
end
|
426
444
|
|
427
445
|
if metadata_text
|
428
446
|
CLI::UI.with_frame_color(:blue) do
|
@@ -431,7 +449,7 @@ module CLI
|
|
431
449
|
end
|
432
450
|
|
433
451
|
options.each do |choice, num|
|
434
|
-
is_chosen = @multiple && num && @chosen[num - 1]
|
452
|
+
is_chosen = @multiple && num && @chosen[num - 1] && num != 0
|
435
453
|
|
436
454
|
padding = ' ' * (max_num_length - num.to_s.length)
|
437
455
|
message = " #{num}#{num ? '.' : ' '}#{padding}"
|
@@ -442,12 +460,12 @@ module CLI
|
|
442
460
|
format = "{{cyan:#{format}}}" if @multiple && is_chosen && num != @active
|
443
461
|
format = " #{format}"
|
444
462
|
|
445
|
-
message +=
|
463
|
+
message += format(format, CHECKBOX_ICON[is_chosen]) if @multiple && num && num > 0
|
446
464
|
message += format_choice(format, choice)
|
447
465
|
|
448
466
|
if num == @active
|
449
467
|
|
450
|
-
color =
|
468
|
+
color = filtering? || selecting? ? 'green' : 'blue'
|
451
469
|
message = message.split("\n").map { |l| "{{#{color}:> #{l.strip}}}" }.join("\n")
|
452
470
|
end
|
453
471
|
|
@@ -463,7 +481,7 @@ module CLI
|
|
463
481
|
|
464
482
|
return eol if lines.empty? # Handle blank options
|
465
483
|
|
466
|
-
lines.map! { |l|
|
484
|
+
lines.map! { |l| format(format, l) + eol }
|
467
485
|
lines.join("\n")
|
468
486
|
end
|
469
487
|
end
|