clack 0.6.2 → 0.7.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 +4 -4
- data/CHANGELOG.md +55 -0
- data/README.md +281 -14
- data/examples/migration_from_tty_prompt.rb +13 -4
- data/lib/clack/box.rb +11 -5
- data/lib/clack/colors.rb +9 -4
- data/lib/clack/core/chrome.rb +139 -0
- data/lib/clack/core/ci_mode.rb +6 -3
- data/lib/clack/core/key_reader.rb +78 -18
- data/lib/clack/core/options_helper.rb +43 -6
- data/lib/clack/core/prompt.rb +47 -72
- data/lib/clack/core/settings.rb +87 -6
- data/lib/clack/environment.rb +28 -4
- data/lib/clack/errors.rb +19 -0
- data/lib/clack/log.rb +31 -17
- data/lib/clack/note.rb +12 -5
- data/lib/clack/prompts/autocomplete.rb +13 -12
- data/lib/clack/prompts/autocomplete_multiselect.rb +12 -21
- data/lib/clack/prompts/confirm.rb +30 -12
- data/lib/clack/prompts/date.rb +1 -1
- data/lib/clack/prompts/group_multiselect.rb +48 -32
- data/lib/clack/prompts/multiline_text.rb +6 -6
- data/lib/clack/prompts/multiselect.rb +12 -19
- data/lib/clack/prompts/password.rb +2 -2
- data/lib/clack/prompts/path.rb +14 -3
- data/lib/clack/prompts/range.rb +37 -4
- data/lib/clack/prompts/select.rb +8 -1
- data/lib/clack/prompts/select_key.rb +53 -30
- data/lib/clack/prompts/spinner.rb +198 -17
- data/lib/clack/prompts/tasks.rb +34 -11
- data/lib/clack/prompts/text.rb +2 -2
- data/lib/clack/stream.rb +38 -18
- data/lib/clack/symbols.rb +6 -1
- data/lib/clack/task_log.rb +24 -8
- data/lib/clack/utils.rb +18 -6
- data/lib/clack/validators.rb +136 -7
- data/lib/clack/version.rb +1 -1
- data/lib/clack.rb +197 -31
- metadata +3 -1
data/lib/clack.rb
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "clack/version"
|
|
4
|
+
require_relative "clack/errors"
|
|
4
5
|
require_relative "clack/environment"
|
|
5
6
|
require_relative "clack/symbols"
|
|
6
7
|
require_relative "clack/colors"
|
|
7
8
|
require_relative "clack/utils"
|
|
8
9
|
require_relative "clack/core/cursor"
|
|
9
10
|
require_relative "clack/core/settings"
|
|
11
|
+
require_relative "clack/core/chrome"
|
|
10
12
|
require_relative "clack/core/key_reader"
|
|
11
13
|
require_relative "clack/core/prompt"
|
|
12
14
|
require_relative "clack/core/options_helper"
|
|
@@ -101,7 +103,9 @@ module Clack
|
|
|
101
103
|
# Useful for guard clauses in CLI scripts.
|
|
102
104
|
#
|
|
103
105
|
# @param value [Object] the result from a prompt
|
|
104
|
-
# @param message [String] message to display if cancelled
|
|
106
|
+
# @param message [String, nil] message to display if cancelled (default: the global
|
|
107
|
+
# messages[:cancel], "Cancelled"; see {#update_settings})
|
|
108
|
+
# @param with_guide [Boolean, nil] show the guide symbol (default: Clack.settings[:with_guide])
|
|
105
109
|
# @param output [IO] output stream
|
|
106
110
|
# @return [Boolean] true if cancelled
|
|
107
111
|
#
|
|
@@ -111,41 +115,53 @@ module Clack
|
|
|
111
115
|
#
|
|
112
116
|
# @example With custom message
|
|
113
117
|
# return if Clack.handle_cancel(name, "Aborted by user")
|
|
114
|
-
def handle_cancel(value, message =
|
|
118
|
+
def handle_cancel(value, message = nil, with_guide: nil, output: $stdout)
|
|
115
119
|
return false unless cancel?(value)
|
|
116
120
|
|
|
117
|
-
cancel(message, output:
|
|
121
|
+
cancel(message || Core::Settings.message(:cancel), with_guide:, output:)
|
|
118
122
|
true
|
|
119
123
|
end
|
|
120
124
|
|
|
121
125
|
# Display an intro banner at the start of a CLI session.
|
|
122
126
|
#
|
|
123
127
|
# @param title [String, nil] optional title text
|
|
128
|
+
# @param with_guide [Boolean, nil] show the guide symbol (default: Clack.settings[:with_guide])
|
|
124
129
|
# @param output [IO] output stream (default: $stdout)
|
|
125
130
|
# @return [void]
|
|
126
|
-
def intro(title = nil, output: $stdout)
|
|
127
|
-
|
|
131
|
+
def intro(title = nil, with_guide: nil, output: $stdout)
|
|
132
|
+
prefix = Core::Settings.with_guide?(with_guide) ? "#{Colors.gray(Symbols::S_BAR_START)} " : ""
|
|
133
|
+
output.puts "#{prefix}#{title}"
|
|
128
134
|
end
|
|
129
135
|
|
|
130
136
|
# Display an outro banner at the end of a CLI session.
|
|
131
137
|
#
|
|
132
138
|
# @param message [String, nil] optional closing message
|
|
139
|
+
# @param with_guide [Boolean, nil] show the guide symbol (default: Clack.settings[:with_guide])
|
|
133
140
|
# @param output [IO] output stream (default: $stdout)
|
|
134
141
|
# @return [void]
|
|
135
|
-
def outro(message = nil, output: $stdout)
|
|
136
|
-
|
|
137
|
-
|
|
142
|
+
def outro(message = nil, with_guide: nil, output: $stdout)
|
|
143
|
+
if Core::Settings.with_guide?(with_guide)
|
|
144
|
+
output.puts Colors.gray(Symbols::S_BAR)
|
|
145
|
+
output.puts "#{Colors.gray(Symbols::S_BAR_END)} #{message}"
|
|
146
|
+
else
|
|
147
|
+
output.puts message.to_s
|
|
148
|
+
end
|
|
138
149
|
output.puts
|
|
139
150
|
end
|
|
140
151
|
|
|
141
152
|
# Display a cancellation message (typically after user presses Escape).
|
|
142
153
|
#
|
|
143
154
|
# @param message [String, nil] optional cancellation message
|
|
155
|
+
# @param with_guide [Boolean, nil] show the guide symbol (default: Clack.settings[:with_guide])
|
|
144
156
|
# @param output [IO] output stream (default: $stdout)
|
|
145
157
|
# @return [void]
|
|
146
|
-
def cancel(message = nil, output: $stdout)
|
|
147
|
-
|
|
148
|
-
|
|
158
|
+
def cancel(message = nil, with_guide: nil, output: $stdout)
|
|
159
|
+
if Core::Settings.with_guide?(with_guide)
|
|
160
|
+
output.puts Colors.gray(Symbols::S_BAR)
|
|
161
|
+
output.puts "#{Colors.gray(Symbols::S_BAR_END)} #{Colors.red(message)}"
|
|
162
|
+
else
|
|
163
|
+
output.puts Colors.red(message)
|
|
164
|
+
end
|
|
149
165
|
output.puts
|
|
150
166
|
end
|
|
151
167
|
|
|
@@ -156,9 +172,12 @@ module Clack
|
|
|
156
172
|
# @option opts [String, nil] :default_value value used if submitted empty
|
|
157
173
|
# @option opts [String, nil] :initial_value pre-filled editable text
|
|
158
174
|
# @option opts [Array<String>, Proc, nil] :completions tab completion candidates (array or proc)
|
|
159
|
-
# @option opts [Proc,
|
|
175
|
+
# @option opts [Proc, Regexp, Symbol, Array, Hash, nil, false] :validate validator (see {Validators.resolve});
|
|
176
|
+
# a proc returns an error string, Warning, or nil; nil or false disables validation
|
|
160
177
|
# @option opts [Symbol, Proc, nil] :transform transform function to normalize the value
|
|
161
178
|
# @option opts [String, nil] :help help text shown below the message
|
|
179
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
180
|
+
# @option opts [String, Array<String>, nil] :instructions custom keyboard hint footer text, rendered verbatim on one line (newlines are not re-prefixed)
|
|
162
181
|
# @return [String, CANCEL] user input or CANCEL if cancelled
|
|
163
182
|
def text(message:, **opts)
|
|
164
183
|
Prompts::Text.new(message:, **opts).run
|
|
@@ -171,8 +190,11 @@ module Clack
|
|
|
171
190
|
#
|
|
172
191
|
# @param message [String] the prompt message
|
|
173
192
|
# @option opts [String, nil] :initial_value pre-filled editable text (can contain newlines)
|
|
174
|
-
# @option opts [Proc,
|
|
193
|
+
# @option opts [Proc, Regexp, Symbol, Array, Hash, nil, false] :validate validator (see {Validators.resolve});
|
|
194
|
+
# a proc returns an error string, Warning, or nil; nil or false disables validation
|
|
175
195
|
# @option opts [String, nil] :help help text shown below the message
|
|
196
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
197
|
+
# @option opts [String, Array<String>, nil] :instructions custom keyboard hint footer text, rendered verbatim on one line (newlines are not re-prefixed)
|
|
176
198
|
# @return [String, CANCEL] user input (lines joined with \n) or CANCEL if cancelled
|
|
177
199
|
def multiline_text(message:, **opts)
|
|
178
200
|
Prompts::MultilineText.new(message:, **opts).run
|
|
@@ -182,8 +204,11 @@ module Clack
|
|
|
182
204
|
#
|
|
183
205
|
# @param message [String] the prompt message
|
|
184
206
|
# @option opts [String] :mask character to display for each input character (default: ▪)
|
|
185
|
-
# @option opts [Proc,
|
|
207
|
+
# @option opts [Proc, Regexp, Symbol, Array, Hash, nil, false] :validate validator (see {Validators.resolve});
|
|
208
|
+
# a proc returns an error string, Warning, or nil; nil or false disables validation
|
|
186
209
|
# @option opts [String, nil] :help help text shown below the message
|
|
210
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
211
|
+
# @option opts [String, Array<String>, nil] :instructions custom keyboard hint footer text, rendered verbatim on one line (newlines are not re-prefixed)
|
|
187
212
|
# @return [String, CANCEL] password or CANCEL if cancelled
|
|
188
213
|
def password(message:, **opts)
|
|
189
214
|
Prompts::Password.new(message:, **opts).run
|
|
@@ -194,8 +219,22 @@ module Clack
|
|
|
194
219
|
# @param message [String] the prompt message
|
|
195
220
|
# @option opts [String] :active label for "yes" option (default: "Yes")
|
|
196
221
|
# @option opts [String] :inactive label for "no" option (default: "No")
|
|
197
|
-
# @option opts [
|
|
222
|
+
# @option opts [Object] :initial_value default selection (default: true); coerced to a
|
|
223
|
+
# Boolean, so nil and false start on "no" and any other value starts on "yes"
|
|
224
|
+
# @option opts [Boolean] :vertical render the two options on separate lines instead of
|
|
225
|
+
# side by side (default: false); handy for long or localized labels
|
|
226
|
+
# @option opts [String, nil] :help help text shown below the message
|
|
227
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
228
|
+
# @option opts [String, Array<String>, nil] :instructions custom keyboard hint footer text, rendered verbatim on one line (newlines are not re-prefixed)
|
|
198
229
|
# @return [Boolean, CANCEL] true/false or CANCEL if cancelled
|
|
230
|
+
#
|
|
231
|
+
# @example Stacked layout
|
|
232
|
+
# Clack.confirm(
|
|
233
|
+
# message: "Overwrite ~/.zshrc?",
|
|
234
|
+
# active: "Yes, back it up and replace it",
|
|
235
|
+
# inactive: "No, keep my existing file",
|
|
236
|
+
# vertical: true
|
|
237
|
+
# )
|
|
199
238
|
def confirm(message:, **opts)
|
|
200
239
|
Prompts::Confirm.new(message:, **opts).run
|
|
201
240
|
end
|
|
@@ -203,10 +242,18 @@ module Clack
|
|
|
203
242
|
# Prompt to select one option from a list.
|
|
204
243
|
#
|
|
205
244
|
# @param message [String] the prompt message
|
|
206
|
-
# @param options [Array<Hash, String
|
|
245
|
+
# @param options [Array<Hash, String>, Hash] list of options, or a Hash of value => label
|
|
246
|
+
# (or value => {label:, hint:, disabled:}); see README "Option shorthands"
|
|
207
247
|
# @option opts [Object, nil] :initial_value value of initially selected option
|
|
208
248
|
# @option opts [Integer, nil] :max_items max visible items (enables scrolling)
|
|
249
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
250
|
+
# @option opts [Boolean, nil] :show_instructions show the keyboard hint footer (default: Clack.settings[:show_instructions])
|
|
251
|
+
# @option opts [String, Array<String>, nil] :instructions custom keyboard hint footer text, rendered verbatim on one line (newlines are not re-prefixed)
|
|
209
252
|
# @return [Object, CANCEL] selected value or CANCEL if cancelled
|
|
253
|
+
#
|
|
254
|
+
# @example Hash shorthand
|
|
255
|
+
# db = Clack.select(message: "Database?", options: {pg: "PostgreSQL", mysql: "MySQL"})
|
|
256
|
+
# # => :pg
|
|
210
257
|
def select(message:, options:, **opts)
|
|
211
258
|
Prompts::Select.new(message:, options: options, **opts).run
|
|
212
259
|
end
|
|
@@ -214,11 +261,15 @@ module Clack
|
|
|
214
261
|
# Prompt to select multiple options from a list.
|
|
215
262
|
#
|
|
216
263
|
# @param message [String] the prompt message
|
|
217
|
-
# @param options [Array<Hash, String
|
|
264
|
+
# @param options [Array<Hash, String>, Hash] list of options, or a Hash of value => label
|
|
265
|
+
# (or value => {label:, hint:, disabled:})
|
|
218
266
|
# @option opts [Array, nil] :initial_values initially selected values
|
|
219
267
|
# @option opts [Boolean] :required require at least one selection (default: true)
|
|
220
268
|
# @option opts [Integer, nil] :max_items max visible items (enables scrolling)
|
|
221
269
|
# @option opts [Object, nil] :cursor_at value of initially focused option
|
|
270
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
271
|
+
# @option opts [Boolean, nil] :show_instructions show the keyboard hint footer (default: Clack.settings[:show_instructions])
|
|
272
|
+
# @option opts [String, Array<String>, nil] :instructions custom keyboard hint footer text, rendered verbatim on one line (newlines are not re-prefixed)
|
|
222
273
|
# @return [Array, CANCEL] selected values or CANCEL if cancelled
|
|
223
274
|
def multiselect(message:, options:, **opts)
|
|
224
275
|
Prompts::Multiselect.new(message:, options: options, **opts).run
|
|
@@ -230,17 +281,42 @@ module Clack
|
|
|
230
281
|
# @option opts [Array<String>, nil] :frames custom animation frames
|
|
231
282
|
# @option opts [Float, nil] :delay seconds between frames
|
|
232
283
|
# @option opts [Proc, nil] :style_frame proc to style each frame
|
|
284
|
+
# @option opts [String, nil] :cancel_message text for #cancel with no argument and for
|
|
285
|
+
# Ctrl+C / exit while running (default: the global messages[:cancel], "Cancelled")
|
|
286
|
+
# @option opts [String, nil] :error_message text for #error with no argument and for an
|
|
287
|
+
# uncaught exception while running (default: the global messages[:error],
|
|
288
|
+
# "Something went wrong")
|
|
289
|
+
# @option opts [#call, nil] :on_cancel called with no arguments after the spinner is
|
|
290
|
+
# cancelled, whether by #cancel, Ctrl+C, exit, or an early exit from a Clack.spin
|
|
291
|
+
# block; a StandardError raised by the hook is reported with Kernel#warn and swallowed
|
|
233
292
|
# @option opts [IO] :output output stream (default: $stdout)
|
|
293
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
234
294
|
# @return [Prompts::Spinner] spinner instance (call #start, #stop, #error, #cancel, #clear)
|
|
295
|
+
# @raise [ArgumentError] if cancel_message/error_message are not Strings or on_cancel
|
|
296
|
+
# does not respond to #call
|
|
297
|
+
#
|
|
298
|
+
# @example Custom cancel and error messages
|
|
299
|
+
# s = Clack.spinner(cancel_message: "Deploy aborted", error_message: "Deploy failed",
|
|
300
|
+
# on_cancel: -> { release_lock })
|
|
301
|
+
# s.start("Deploying")
|
|
235
302
|
def spinner(**opts)
|
|
236
303
|
Prompts::Spinner.new(**opts)
|
|
237
304
|
end
|
|
238
305
|
|
|
239
306
|
# Run a block with a spinner, handling success/error automatically.
|
|
240
307
|
#
|
|
308
|
+
# If the block does not complete, the spinner still ends with a final line before the
|
|
309
|
+
# exception or non-local exit propagates: the cancel message for exit (any status),
|
|
310
|
+
# Ctrl+C, break, and throw; +error+ or the exception message for anything raised.
|
|
311
|
+
#
|
|
241
312
|
# @param message [String] initial spinner message
|
|
242
313
|
# @param success [String, nil] message on success (defaults to message)
|
|
243
314
|
# @param error [String, nil] message on error (defaults to exception message)
|
|
315
|
+
# @option opts [String, nil] :cancel_message see {#spinner}
|
|
316
|
+
# @option opts [String, nil] :error_message see {#spinner}; note that an exception
|
|
317
|
+
# raised by the block uses +error:+ or the exception message, not this
|
|
318
|
+
# @option opts [#call, nil] :on_cancel see {#spinner}
|
|
319
|
+
# @option opts [Boolean, nil] :with_guide see {#spinner}
|
|
244
320
|
# @return [Object] the block's return value
|
|
245
321
|
# @raise [Exception] re-raises any exception from the block
|
|
246
322
|
#
|
|
@@ -257,6 +333,10 @@ module Clack
|
|
|
257
333
|
# s.message "Step 2..."
|
|
258
334
|
# do_step_2
|
|
259
335
|
# end
|
|
336
|
+
#
|
|
337
|
+
# @example Early exit still prints a final line
|
|
338
|
+
# Clack.spin("Building", cancel_message: "Build cancelled") { exit 2 }
|
|
339
|
+
# # => "■ Build cancelled", then the process exits with status 2
|
|
260
340
|
def spin(message, success: nil, error: nil, **opts)
|
|
261
341
|
s = spinner(**opts)
|
|
262
342
|
s.start(message)
|
|
@@ -264,21 +344,31 @@ module Clack
|
|
|
264
344
|
result = yield(s)
|
|
265
345
|
s.stop(success || message)
|
|
266
346
|
result
|
|
267
|
-
rescue
|
|
347
|
+
rescue SystemExit, SignalException
|
|
348
|
+
s.cancel
|
|
349
|
+
raise
|
|
350
|
+
rescue Exception => exception # standard:disable Lint/RescueException
|
|
268
351
|
s.error(error || exception.message)
|
|
269
352
|
raise
|
|
353
|
+
ensure
|
|
354
|
+
# break or throw out of the block leave no exception in flight; a
|
|
355
|
+
# no-op when one of the clauses above already finished the spinner.
|
|
356
|
+
s.abandon
|
|
270
357
|
end
|
|
271
358
|
end
|
|
272
359
|
|
|
273
360
|
# Prompt with type-to-filter autocomplete.
|
|
274
361
|
#
|
|
275
362
|
# @param message [String] the prompt message
|
|
276
|
-
# @param options [Array<Hash, String
|
|
363
|
+
# @param options [Array<Hash, String>, Hash] list of options to filter, or a Hash of value => label
|
|
277
364
|
# @option opts [String, nil] :placeholder placeholder text
|
|
278
365
|
# @option opts [Proc, nil] :filter custom filter proc receiving (option_hash, query_string)
|
|
279
366
|
# and returning true/false. Defaults to fuzzy matching across label, value, and hint,
|
|
280
367
|
# sorted by relevance score.
|
|
281
368
|
# @option opts [Integer, nil] :max_items max visible items (enables scrolling, default: 5)
|
|
369
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
370
|
+
# @option opts [Boolean, nil] :show_instructions show the keyboard hint footer (default: Clack.settings[:show_instructions])
|
|
371
|
+
# @option opts [String, Array<String>, nil] :instructions custom keyboard hint footer text, rendered verbatim on one line (newlines are not re-prefixed)
|
|
282
372
|
# @return [Object, CANCEL] selected value or CANCEL if cancelled
|
|
283
373
|
def autocomplete(message:, options:, **opts)
|
|
284
374
|
Prompts::Autocomplete.new(message:, options: options, **opts).run
|
|
@@ -287,7 +377,7 @@ module Clack
|
|
|
287
377
|
# Prompt with type-to-filter autocomplete and multiselect.
|
|
288
378
|
#
|
|
289
379
|
# @param message [String] the prompt message
|
|
290
|
-
# @param options [Array<Hash, String
|
|
380
|
+
# @param options [Array<Hash, String>, Hash] list of options to filter, or a Hash of value => label
|
|
291
381
|
# @option opts [String, nil] :placeholder placeholder text
|
|
292
382
|
# @option opts [Boolean] :required require at least one selection (default: true)
|
|
293
383
|
# @option opts [Array, nil] :initial_values initially selected values
|
|
@@ -295,6 +385,9 @@ module Clack
|
|
|
295
385
|
# and returning true/false. Defaults to fuzzy matching across label, value, and hint,
|
|
296
386
|
# sorted by relevance score.
|
|
297
387
|
# @option opts [Integer, nil] :max_items max visible items (enables scrolling, default: 5)
|
|
388
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
389
|
+
# @option opts [Boolean, nil] :show_instructions show the keyboard hint footer (default: Clack.settings[:show_instructions])
|
|
390
|
+
# @option opts [String, Array<String>, nil] :instructions custom keyboard hint footer text, rendered verbatim on one line (newlines are not re-prefixed)
|
|
298
391
|
# @return [Array, CANCEL] selected values or CANCEL if cancelled
|
|
299
392
|
def autocomplete_multiselect(message:, options:, **opts)
|
|
300
393
|
Prompts::AutocompleteMultiselect.new(message:, options: options, **opts).run
|
|
@@ -306,6 +399,11 @@ module Clack
|
|
|
306
399
|
# @option opts [String] :root starting directory (default: ".")
|
|
307
400
|
# @option opts [Boolean] :only_directories only show directories (default: false)
|
|
308
401
|
# @option opts [Integer, nil] :max_items max visible items (enables scrolling, default: 5)
|
|
402
|
+
# @option opts [Proc, Regexp, Symbol, Array, Hash, nil, false] :validate validator for the resolved
|
|
403
|
+
# absolute path (see {Validators.resolve}); +:directory_exists+ and +:path_exists+ fit here
|
|
404
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
405
|
+
# @option opts [Boolean, nil] :show_instructions show the keyboard hint footer (default: Clack.settings[:show_instructions])
|
|
406
|
+
# @option opts [String, Array<String>, nil] :instructions custom keyboard hint footer text, rendered verbatim on one line (newlines are not re-prefixed)
|
|
309
407
|
# @return [String, CANCEL] selected path or CANCEL if cancelled
|
|
310
408
|
def path(message:, **opts)
|
|
311
409
|
Prompts::Path.new(message:, **opts).run
|
|
@@ -322,9 +420,43 @@ module Clack
|
|
|
322
420
|
|
|
323
421
|
# Prompt to select an option by pressing a key.
|
|
324
422
|
#
|
|
423
|
+
# Each option carries a single-character +:key+ (defaults to the first
|
|
424
|
+
# character of the value). Pressing that key selects the option and
|
|
425
|
+
# submits immediately, so there is no cursor to move. Enter only does
|
|
426
|
+
# something when +:initial_value+ highlights a default. Option keys win
|
|
427
|
+
# over custom key aliases (except aliases mapped to +:cancel+).
|
|
428
|
+
#
|
|
325
429
|
# @param message [String] the prompt message
|
|
326
|
-
# @param options [Array<Hash
|
|
430
|
+
# @param options [Array<Hash>, Hash] options with :value, :label, and optionally :key and :hint, or a Hash of
|
|
431
|
+
# value => label (key defaults to the first character of the value) or value => {label:, key:, hint:}
|
|
432
|
+
# @option opts [Boolean] :case_sensitive match keys exactly instead of ignoring case (default: false)
|
|
433
|
+
# @option opts [Object, nil] :initial_value value of the option highlighted at start; Enter submits it
|
|
434
|
+
# and CI mode returns it (default: nil). The highlight is a color effect, so when colors are off
|
|
435
|
+
# (NO_COLOR, piped output) mark the default in that option's :hint. A value that matches no option
|
|
436
|
+
# is ignored with a warning on stderr
|
|
437
|
+
# @option opts [Proc, Regexp, Symbol, Array, Hash, nil, false] :validate validator (see {Validators.resolve});
|
|
438
|
+
# a proc returns an error string, Warning, or nil; nil or false disables validation
|
|
439
|
+
# @option opts [Symbol, Proc, nil] :transform transform function to normalize the value
|
|
440
|
+
# @option opts [String, nil] :help help text shown below the message
|
|
441
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
442
|
+
# @option opts [String, Array<String>, nil] :instructions custom keyboard hint footer text, rendered verbatim on one line (newlines are not re-prefixed)
|
|
327
443
|
# @return [Object, CANCEL] selected value or CANCEL if cancelled
|
|
444
|
+
#
|
|
445
|
+
# @example Distinct upper- and lowercase keys with a safe default
|
|
446
|
+
# Clack.select_key(
|
|
447
|
+
# message: "Apply migration?",
|
|
448
|
+
# options: [
|
|
449
|
+
# { value: :yes_all, label: "Yes to all", key: "Y" },
|
|
450
|
+
# { value: :yes, label: "Yes", key: "y" },
|
|
451
|
+
# { value: :no, label: "No", key: "n", hint: "default" }
|
|
452
|
+
# ],
|
|
453
|
+
# case_sensitive: true,
|
|
454
|
+
# initial_value: :no
|
|
455
|
+
# )
|
|
456
|
+
#
|
|
457
|
+
# @example Hash shorthand
|
|
458
|
+
# Clack.select_key(message: "Action?", options: {create: "Create", open: "Open", quit: "Quit"})
|
|
459
|
+
# # press "o" => :open
|
|
328
460
|
def select_key(message:, options:, **opts)
|
|
329
461
|
Prompts::SelectKey.new(message:, options: options, **opts).run
|
|
330
462
|
end
|
|
@@ -332,6 +464,7 @@ module Clack
|
|
|
332
464
|
# Run multiple tasks with progress indicators.
|
|
333
465
|
#
|
|
334
466
|
# @param tasks [Array<Hash>] tasks with :title, :task (Proc), and optional :enabled (Boolean, default: true)
|
|
467
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
335
468
|
# @return [Array<Hash>] task results
|
|
336
469
|
def tasks(tasks:, **opts)
|
|
337
470
|
Prompts::Tasks.new(tasks: tasks, **opts).run
|
|
@@ -340,12 +473,16 @@ module Clack
|
|
|
340
473
|
# Prompt to select multiple options organized in groups.
|
|
341
474
|
#
|
|
342
475
|
# @param message [String] the prompt message
|
|
343
|
-
# @param options [Array<Hash
|
|
476
|
+
# @param options [Array<Hash>, Hash] groups with :label and :options, or a Hash of
|
|
477
|
+
# group label => options (each options list accepts an Array or a value => label Hash)
|
|
344
478
|
# @option opts [Array, nil] :initial_values initially selected values
|
|
345
479
|
# @option opts [Boolean] :required require at least one selection (default: true)
|
|
346
480
|
# @option opts [Object, nil] :cursor_at value of initially focused option
|
|
347
481
|
# @option opts [Boolean] :selectable_groups allow toggling entire groups (default: false)
|
|
348
482
|
# @option opts [Integer] :group_spacing lines between groups (default: 0)
|
|
483
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
484
|
+
# @option opts [Boolean, nil] :show_instructions show the keyboard hint footer (default: Clack.settings[:show_instructions])
|
|
485
|
+
# @option opts [String, Array<String>, nil] :instructions custom keyboard hint footer text, rendered verbatim on one line (newlines are not re-prefixed)
|
|
349
486
|
# @return [Array, CANCEL] selected values or CANCEL if cancelled
|
|
350
487
|
def group_multiselect(message:, options:, **opts)
|
|
351
488
|
Prompts::GroupMultiselect.new(message:, options: options, **opts).run
|
|
@@ -361,8 +498,11 @@ module Clack
|
|
|
361
498
|
# @option opts [Date, Time, String, nil] :initial_value initial date value (default: today)
|
|
362
499
|
# @option opts [Date, nil] :min minimum allowed date
|
|
363
500
|
# @option opts [Date, nil] :max maximum allowed date
|
|
364
|
-
# @option opts [Proc, nil] :validate
|
|
501
|
+
# @option opts [Proc, Regexp, Symbol, Array, Hash, nil, false] :validate validator (see {Validators.resolve});
|
|
502
|
+
# a proc returns an error string, Warning, or nil; nil or false disables validation
|
|
365
503
|
# @option opts [String, nil] :help help text shown below the message
|
|
504
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
505
|
+
# @option opts [String, Array<String>, nil] :instructions custom keyboard hint footer text, rendered verbatim on one line (newlines are not re-prefixed)
|
|
366
506
|
# @return [Date, CANCEL] selected date or CANCEL if cancelled
|
|
367
507
|
def date(message:, **opts)
|
|
368
508
|
Prompts::Date.new(message:, **opts).run
|
|
@@ -375,14 +515,24 @@ module Clack
|
|
|
375
515
|
# @param message [String] the prompt message
|
|
376
516
|
# @option opts [Numeric] :min minimum value (default: 0)
|
|
377
517
|
# @option opts [Numeric] :max maximum value (default: 100)
|
|
378
|
-
# @option opts [Numeric] :step increment size (default: 1)
|
|
518
|
+
# @option opts [Numeric] :step increment size (default: 1); fractional steps
|
|
519
|
+
# such as 0.1 are snapped exactly, so three steps from 0 is 0.3
|
|
379
520
|
# @option opts [Numeric, nil] :initial_value initial value (defaults to min)
|
|
380
|
-
# @option opts [Proc, nil] :validate
|
|
521
|
+
# @option opts [Proc, Regexp, Symbol, Array, Hash, nil, false] :validate validator (see {Validators.resolve});
|
|
522
|
+
# a proc returns an error string, Warning, or nil; nil or false disables validation
|
|
381
523
|
# @option opts [String, nil] :help help text shown below the message
|
|
382
|
-
# @
|
|
524
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
525
|
+
# @option opts [String, Array<String>, nil] :instructions custom keyboard hint footer text, rendered verbatim on one line (newlines are not re-prefixed)
|
|
526
|
+
# @return [Numeric, CANCEL] the selected value (Integer when min and
|
|
527
|
+
# step are both Integers, Float when either is a Float; Rational inputs
|
|
528
|
+
# return Rational) or CANCEL if cancelled
|
|
383
529
|
#
|
|
384
530
|
# @example Basic usage
|
|
385
531
|
# volume = Clack.range(message: "Volume", min: 0, max: 100, step: 5)
|
|
532
|
+
#
|
|
533
|
+
# @example Fractional step
|
|
534
|
+
# opacity = Clack.range(message: "Opacity", min: 0, max: 1, step: 0.1)
|
|
535
|
+
# # => 0.3 after three right arrows
|
|
386
536
|
def range(message:, **opts)
|
|
387
537
|
Prompts::Range.new(message:, **opts).run
|
|
388
538
|
end
|
|
@@ -405,6 +555,7 @@ module Clack
|
|
|
405
555
|
#
|
|
406
556
|
# @param message [String] the note content
|
|
407
557
|
# @param title [String, nil] optional title
|
|
558
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
408
559
|
# @return [void]
|
|
409
560
|
def note(message = "", title: nil, **opts)
|
|
410
561
|
Note.render(message, title: title, **opts)
|
|
@@ -418,6 +569,7 @@ module Clack
|
|
|
418
569
|
# @option opts [:left, :center, :right] :title_align title alignment
|
|
419
570
|
# @option opts [Integer, :auto] :width box width
|
|
420
571
|
# @option opts [Boolean] :rounded use rounded corners
|
|
572
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
421
573
|
# @return [void]
|
|
422
574
|
def box(message = "", title: "", **opts)
|
|
423
575
|
Box.render(message, title: title, **opts)
|
|
@@ -429,13 +581,14 @@ module Clack
|
|
|
429
581
|
# @param title [String] title displayed at the top
|
|
430
582
|
# @option opts [Integer, nil] :limit max lines to show (older lines scroll out)
|
|
431
583
|
# @option opts [Boolean] :retain_log keep full log history for display on error
|
|
584
|
+
# @option opts [Boolean, nil] :with_guide show the guide rail (default: Clack.settings[:with_guide])
|
|
432
585
|
# @return [TaskLog] task log instance
|
|
433
586
|
def task_log(title:, **opts)
|
|
434
587
|
TaskLog.new(title: title, **opts)
|
|
435
588
|
end
|
|
436
589
|
|
|
437
590
|
# Access global settings
|
|
438
|
-
# @return [Hash] Current configuration
|
|
591
|
+
# @return [Hash] Current configuration (:aliases, :with_guide, :show_instructions, :ci_mode, :messages)
|
|
439
592
|
# @see Core::Settings.update for modifying settings
|
|
440
593
|
def settings
|
|
441
594
|
Core::Settings.config
|
|
@@ -443,21 +596,34 @@ module Clack
|
|
|
443
596
|
|
|
444
597
|
# Update global settings
|
|
445
598
|
# @option opts [Hash, nil] :aliases Custom key to action mappings
|
|
446
|
-
# @option opts [Boolean, nil] :with_guide Whether to show guide bars
|
|
447
|
-
# @option opts [Boolean,
|
|
599
|
+
# @option opts [Boolean, nil] :with_guide Whether to show guide bars (the gray rail and corners around prompts)
|
|
600
|
+
# @option opts [Boolean, nil] :show_instructions Whether list prompts show their keyboard hint footer
|
|
601
|
+
# @option opts [Boolean, Symbol, nil] :ci_mode CI mode: true (always), :auto (active when
|
|
602
|
+
# the prompt's input is not a TTY, or a CI env var is set), false (never)
|
|
603
|
+
# @option opts [Hash{Symbol=>String}, nil] :messages Cancel/error strings used by spinners
|
|
604
|
+
# and {#handle_cancel}: +{cancel: "Cancelled", error: "Something went wrong"}+.
|
|
605
|
+
# Keys are merged, so either can be given alone.
|
|
448
606
|
# @return [Hash] Updated configuration
|
|
607
|
+
# @raise [ArgumentError] for an unknown messages key or a non-String value
|
|
449
608
|
#
|
|
450
609
|
# @example Custom key bindings
|
|
451
610
|
# Clack.update_settings(aliases: { "y" => :enter, "n" => :cancel })
|
|
452
611
|
#
|
|
453
|
-
# @example Disable guide bars
|
|
612
|
+
# @example Disable guide bars everywhere (per-call with_guide: overrides this)
|
|
454
613
|
# Clack.update_settings(with_guide: false)
|
|
455
614
|
#
|
|
615
|
+
# @example Hide keyboard hint footers
|
|
616
|
+
# Clack.update_settings(show_instructions: false)
|
|
617
|
+
#
|
|
456
618
|
# @example Enable CI mode (auto-submit with defaults)
|
|
457
619
|
# Clack.update_settings(ci_mode: true)
|
|
458
620
|
#
|
|
459
|
-
# @example Auto-detect CI mode (
|
|
621
|
+
# @example Auto-detect CI mode (piped input or CI environment)
|
|
622
|
+
# # Without this, prompting on a piped stdin raises Clack::NotATerminalError.
|
|
460
623
|
# Clack.update_settings(ci_mode: :auto)
|
|
624
|
+
#
|
|
625
|
+
# @example Localize cancel and error messages
|
|
626
|
+
# Clack.update_settings(messages: {cancel: "Abgebrochen", error: "Etwas ging schief"})
|
|
461
627
|
def update_settings(**opts)
|
|
462
628
|
Core::Settings.update(**opts)
|
|
463
629
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: clack
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Steve Whittaker
|
|
@@ -43,6 +43,7 @@ files:
|
|
|
43
43
|
- lib/clack.rb
|
|
44
44
|
- lib/clack/box.rb
|
|
45
45
|
- lib/clack/colors.rb
|
|
46
|
+
- lib/clack/core/chrome.rb
|
|
46
47
|
- lib/clack/core/ci_mode.rb
|
|
47
48
|
- lib/clack/core/cursor.rb
|
|
48
49
|
- lib/clack/core/fuzzy_matcher.rb
|
|
@@ -54,6 +55,7 @@ files:
|
|
|
54
55
|
- lib/clack/core/settings.rb
|
|
55
56
|
- lib/clack/core/text_input_helper.rb
|
|
56
57
|
- lib/clack/environment.rb
|
|
58
|
+
- lib/clack/errors.rb
|
|
57
59
|
- lib/clack/group.rb
|
|
58
60
|
- lib/clack/log.rb
|
|
59
61
|
- lib/clack/note.rb
|