fluid_cli 0.1.2
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 +7 -0
- data/README.md +1 -0
- data/dev.yml +5 -0
- data/exe/fluid +24 -0
- data/lib/fluid_cli/api.rb +135 -0
- data/lib/fluid_cli/assets/post_auth_page/index.html.erb +34 -0
- data/lib/fluid_cli/assets/post_auth_page/style.css +58 -0
- data/lib/fluid_cli/command.rb +55 -0
- data/lib/fluid_cli/commands/help.rb +21 -0
- data/lib/fluid_cli/commands/login.rb +30 -0
- data/lib/fluid_cli/commands/logout.rb +38 -0
- data/lib/fluid_cli/commands/switch.rb +23 -0
- data/lib/fluid_cli/commands/theme/common/company_helper.rb +15 -0
- data/lib/fluid_cli/commands/theme/common/root_helper.rb +95 -0
- data/lib/fluid_cli/commands/theme/dev.rb +61 -0
- data/lib/fluid_cli/commands/theme/help.rb +21 -0
- data/lib/fluid_cli/commands/theme/init.rb +46 -0
- data/lib/fluid_cli/commands/theme/pull.rb +68 -0
- data/lib/fluid_cli/commands/theme/push.rb +132 -0
- data/lib/fluid_cli/commands/theme.rb +23 -0
- data/lib/fluid_cli/commands/whoami.rb +23 -0
- data/lib/fluid_cli/commands.rb +19 -0
- data/lib/fluid_cli/company_switcher.rb +69 -0
- data/lib/fluid_cli/context.rb +691 -0
- data/lib/fluid_cli/db.rb +114 -0
- data/lib/fluid_cli/entry_point.rb +10 -0
- data/lib/fluid_cli/environment.rb +32 -0
- data/lib/fluid_cli/file_system_listener.rb +29 -0
- data/lib/fluid_cli/form.rb +42 -0
- data/lib/fluid_cli/git.rb +319 -0
- data/lib/fluid_cli/http_request.rb +54 -0
- data/lib/fluid_cli/identity_auth/servlet.rb +39 -0
- data/lib/fluid_cli/identity_auth.rb +126 -0
- data/lib/fluid_cli/options.rb +38 -0
- data/lib/fluid_cli/theme/dev_server/certificate_manager.rb +79 -0
- data/lib/fluid_cli/theme/dev_server/errors.rb +9 -0
- data/lib/fluid_cli/theme/dev_server/header_hash.rb +98 -0
- data/lib/fluid_cli/theme/dev_server/hooks/file_change_hook.rb +39 -0
- data/lib/fluid_cli/theme/dev_server/hot_reload/resources/hot-reload-no-script.html +27 -0
- data/lib/fluid_cli/theme/dev_server/hot_reload/resources/hot_reload.js +28 -0
- data/lib/fluid_cli/theme/dev_server/hot_reload/resources/sse_client.js +43 -0
- data/lib/fluid_cli/theme/dev_server/hot_reload/resources/theme.js +16 -0
- data/lib/fluid_cli/theme/dev_server/hot_reload/script_injector.rb +54 -0
- data/lib/fluid_cli/theme/dev_server/hot_reload.rb +75 -0
- data/lib/fluid_cli/theme/dev_server/local_assets.rb +92 -0
- data/lib/fluid_cli/theme/dev_server/proxy.rb +235 -0
- data/lib/fluid_cli/theme/dev_server/proxy_param_builder.rb +82 -0
- data/lib/fluid_cli/theme/dev_server/reload_mode.rb +34 -0
- data/lib/fluid_cli/theme/dev_server/sse.rb +75 -0
- data/lib/fluid_cli/theme/dev_server/watcher.rb +57 -0
- data/lib/fluid_cli/theme/dev_server/web_server.rb +140 -0
- data/lib/fluid_cli/theme/dev_server.rb +289 -0
- data/lib/fluid_cli/theme/development_theme.rb +101 -0
- data/lib/fluid_cli/theme/file.rb +105 -0
- data/lib/fluid_cli/theme/forms/select.rb +33 -0
- data/lib/fluid_cli/theme/mime_type.rb +34 -0
- data/lib/fluid_cli/theme/presenters/theme_presenter.rb +49 -0
- data/lib/fluid_cli/theme/presenters/themes_presenter.rb +31 -0
- data/lib/fluid_cli/theme/root.rb +62 -0
- data/lib/fluid_cli/theme/syncer/checksums.rb +66 -0
- data/lib/fluid_cli/theme/syncer/downloader.rb +54 -0
- data/lib/fluid_cli/theme/syncer/error_reporter.rb +45 -0
- data/lib/fluid_cli/theme/syncer/merger.rb +53 -0
- data/lib/fluid_cli/theme/syncer/operation.rb +58 -0
- data/lib/fluid_cli/theme/syncer/standard_reporter.rb +32 -0
- data/lib/fluid_cli/theme/syncer/unsupported_script_warning.rb +90 -0
- data/lib/fluid_cli/theme/syncer/uploader/forms/apply_to_all.rb +41 -0
- data/lib/fluid_cli/theme/syncer/uploader/forms/apply_to_all_form.rb +37 -0
- data/lib/fluid_cli/theme/syncer/uploader/forms/base_strategy_form.rb +64 -0
- data/lib/fluid_cli/theme/syncer/uploader/forms/select_delete_strategy.rb +29 -0
- data/lib/fluid_cli/theme/syncer/uploader/forms/select_update_strategy.rb +30 -0
- data/lib/fluid_cli/theme/syncer/uploader/json_delete_handler.rb +49 -0
- data/lib/fluid_cli/theme/syncer/uploader/json_update_handler.rb +71 -0
- data/lib/fluid_cli/theme/syncer/uploader.rb +105 -0
- data/lib/fluid_cli/theme/syncer.rb +412 -0
- data/lib/fluid_cli/theme/theme.rb +186 -0
- data/lib/fluid_cli/theme/ui/sync_progress_bar.rb +22 -0
- data/lib/fluid_cli/thread_pool/job.rb +35 -0
- data/lib/fluid_cli/thread_pool.rb +49 -0
- data/lib/fluid_cli/version.rb +3 -0
- data/lib/fluid_cli.rb +59 -0
- data/vendor/deps/base64/.document +5 -0
- data/vendor/deps/base64/.gitignore +9 -0
- data/vendor/deps/base64/BSDL +22 -0
- data/vendor/deps/base64/COPYING +56 -0
- data/vendor/deps/base64/Gemfile +9 -0
- data/vendor/deps/base64/LEGAL +60 -0
- data/vendor/deps/base64/README.md +48 -0
- data/vendor/deps/base64/Rakefile +31 -0
- data/vendor/deps/base64/base64.gemspec +28 -0
- data/vendor/deps/base64/bin/console +14 -0
- data/vendor/deps/base64/bin/setup +8 -0
- data/vendor/deps/base64/lib/base64.rb +382 -0
- data/vendor/deps/base64/sig/base64.rbs +358 -0
- data/vendor/deps/base64/test/base64/test_base64.rb +115 -0
- data/vendor/deps/base64/test_sig/test_base64.rb +44 -0
- data/vendor/deps/cli-kit/REVISION +1 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/definition.rb +286 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/evaluation.rb +215 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/parser/node.rb +128 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/parser.rb +125 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/tokenizer.rb +130 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args.rb +16 -0
- data/vendor/deps/cli-kit/lib/cli/kit/base_command.rb +30 -0
- data/vendor/deps/cli-kit/lib/cli/kit/command_help.rb +268 -0
- data/vendor/deps/cli-kit/lib/cli/kit/command_registry.rb +150 -0
- data/vendor/deps/cli-kit/lib/cli/kit/config.rb +137 -0
- data/vendor/deps/cli-kit/lib/cli/kit/core_ext.rb +28 -0
- data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +166 -0
- data/vendor/deps/cli-kit/lib/cli/kit/executor.rb +92 -0
- data/vendor/deps/cli-kit/lib/cli/kit/ini.rb +91 -0
- data/vendor/deps/cli-kit/lib/cli/kit/levenshtein.rb +92 -0
- data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +94 -0
- data/vendor/deps/cli-kit/lib/cli/kit/opts.rb +248 -0
- data/vendor/deps/cli-kit/lib/cli/kit/parse_args.rb +55 -0
- data/vendor/deps/cli-kit/lib/cli/kit/resolver.rb +66 -0
- data/vendor/deps/cli-kit/lib/cli/kit/support/test_helper.rb +260 -0
- data/vendor/deps/cli-kit/lib/cli/kit/support.rb +11 -0
- data/vendor/deps/cli-kit/lib/cli/kit/system.rb +290 -0
- data/vendor/deps/cli-kit/lib/cli/kit/util.rb +118 -0
- data/vendor/deps/cli-kit/lib/cli/kit/version.rb +7 -0
- data/vendor/deps/cli-kit/lib/cli/kit.rb +139 -0
- data/vendor/deps/cli-ui/REVISION +1 -0
- data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +218 -0
- data/vendor/deps/cli-ui/lib/cli/ui/color.rb +101 -0
- data/vendor/deps/cli-ui/lib/cli/ui/formatter.rb +219 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +67 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/box.rb +179 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +152 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +127 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +286 -0
- data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +92 -0
- data/vendor/deps/cli-ui/lib/cli/ui/os.rb +63 -0
- data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +64 -0
- data/vendor/deps/cli-ui/lib/cli/ui/progress.rb +132 -0
- data/vendor/deps/cli-ui/lib/cli/ui/progress_reporter.rb +209 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +583 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/options_handler.rb +36 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +381 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner/async.rb +48 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +602 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +79 -0
- data/vendor/deps/cli-ui/lib/cli/ui/stdout_router.rb +399 -0
- data/vendor/deps/cli-ui/lib/cli/ui/table.rb +83 -0
- data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +55 -0
- data/vendor/deps/cli-ui/lib/cli/ui/truncater.rb +106 -0
- data/vendor/deps/cli-ui/lib/cli/ui/version.rb +8 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets/base.rb +46 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets/status.rb +79 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets.rb +89 -0
- data/vendor/deps/cli-ui/lib/cli/ui/work_queue.rb +142 -0
- data/vendor/deps/cli-ui/lib/cli/ui/wrap.rb +61 -0
- data/vendor/deps/cli-ui/lib/cli/ui.rb +359 -0
- data/vendor/deps/cli-ui/vendor/reentrant_mutex.rb +78 -0
- data/vendor/deps/debug/CONTRIBUTING.md +573 -0
- data/vendor/deps/debug/Gemfile +10 -0
- data/vendor/deps/debug/LICENSE.txt +22 -0
- data/vendor/deps/debug/README.md +996 -0
- data/vendor/deps/debug/Rakefile +57 -0
- data/vendor/deps/debug/TODO.md +23 -0
- data/vendor/deps/debug/debug.gemspec +33 -0
- data/vendor/deps/debug/exe/rdbg +53 -0
- data/vendor/deps/debug/ext/debug/Makefile +273 -0
- data/vendor/deps/debug/ext/debug/debug.c +228 -0
- data/vendor/deps/debug/ext/debug/debug_version.h +1 -0
- data/vendor/deps/debug/ext/debug/extconf.rb +27 -0
- data/vendor/deps/debug/ext/debug/iseq_collector.c +93 -0
- data/vendor/deps/debug/lib/debug/abbrev_command.rb +77 -0
- data/vendor/deps/debug/lib/debug/breakpoint.rb +556 -0
- data/vendor/deps/debug/lib/debug/client.rb +263 -0
- data/vendor/deps/debug/lib/debug/color.rb +123 -0
- data/vendor/deps/debug/lib/debug/config.rb +592 -0
- data/vendor/deps/debug/lib/debug/console.rb +224 -0
- data/vendor/deps/debug/lib/debug/dap_custom/traceInspector.rb +336 -0
- data/vendor/deps/debug/lib/debug/debug.bundle +0 -0
- data/vendor/deps/debug/lib/debug/frame_info.rb +190 -0
- data/vendor/deps/debug/lib/debug/irb_integration.rb +37 -0
- data/vendor/deps/debug/lib/debug/local.rb +115 -0
- data/vendor/deps/debug/lib/debug/open.rb +13 -0
- data/vendor/deps/debug/lib/debug/open_nonstop.rb +15 -0
- data/vendor/deps/debug/lib/debug/prelude.rb +50 -0
- data/vendor/deps/debug/lib/debug/server.rb +534 -0
- data/vendor/deps/debug/lib/debug/server_cdp.rb +1348 -0
- data/vendor/deps/debug/lib/debug/server_dap.rb +1108 -0
- data/vendor/deps/debug/lib/debug/session.rb +2667 -0
- data/vendor/deps/debug/lib/debug/source_repository.rb +150 -0
- data/vendor/deps/debug/lib/debug/start.rb +5 -0
- data/vendor/deps/debug/lib/debug/thread_client.rb +1457 -0
- data/vendor/deps/debug/lib/debug/tracer.rb +241 -0
- data/vendor/deps/debug/lib/debug/version.rb +5 -0
- data/vendor/deps/debug/lib/debug.rb +9 -0
- data/vendor/deps/debug/misc/README.md.erb +660 -0
- data/vendor/deps/listen/.github/release-drafter.yml +17 -0
- data/vendor/deps/listen/.github/workflows/development.yml +67 -0
- data/vendor/deps/listen/.github/workflows/push.yml +12 -0
- data/vendor/deps/listen/.gitignore +28 -0
- data/vendor/deps/listen/.rspec +3 -0
- data/vendor/deps/listen/.rubocop.yml +283 -0
- data/vendor/deps/listen/.yardopts +11 -0
- data/vendor/deps/listen/CHANGELOG.md +1 -0
- data/vendor/deps/listen/CONTRIBUTING.md +45 -0
- data/vendor/deps/listen/Gemfile +33 -0
- data/vendor/deps/listen/Guardfile +26 -0
- data/vendor/deps/listen/LICENSE.txt +22 -0
- data/vendor/deps/listen/README.md +490 -0
- data/vendor/deps/listen/Rakefile +154 -0
- data/vendor/deps/listen/bin/listen +11 -0
- data/vendor/deps/listen/lib/listen/adapter/base.rb +129 -0
- data/vendor/deps/listen/lib/listen/adapter/bsd.rb +104 -0
- data/vendor/deps/listen/lib/listen/adapter/config.rb +31 -0
- data/vendor/deps/listen/lib/listen/adapter/darwin.rb +77 -0
- data/vendor/deps/listen/lib/listen/adapter/linux.rb +108 -0
- data/vendor/deps/listen/lib/listen/adapter/polling.rb +40 -0
- data/vendor/deps/listen/lib/listen/adapter/windows.rb +96 -0
- data/vendor/deps/listen/lib/listen/adapter.rb +43 -0
- data/vendor/deps/listen/lib/listen/backend.rb +40 -0
- data/vendor/deps/listen/lib/listen/change.rb +69 -0
- data/vendor/deps/listen/lib/listen/cli.rb +65 -0
- data/vendor/deps/listen/lib/listen/directory.rb +93 -0
- data/vendor/deps/listen/lib/listen/error.rb +11 -0
- data/vendor/deps/listen/lib/listen/event/config.rb +39 -0
- data/vendor/deps/listen/lib/listen/event/loop.rb +92 -0
- data/vendor/deps/listen/lib/listen/event/processor.rb +128 -0
- data/vendor/deps/listen/lib/listen/event/queue.rb +52 -0
- data/vendor/deps/listen/lib/listen/file.rb +95 -0
- data/vendor/deps/listen/lib/listen/fsm.rb +131 -0
- data/vendor/deps/listen/lib/listen/listener/config.rb +41 -0
- data/vendor/deps/listen/lib/listen/listener.rb +136 -0
- data/vendor/deps/listen/lib/listen/logger.rb +65 -0
- data/vendor/deps/listen/lib/listen/monotonic_time.rb +27 -0
- data/vendor/deps/listen/lib/listen/options.rb +24 -0
- data/vendor/deps/listen/lib/listen/queue_optimizer.rb +129 -0
- data/vendor/deps/listen/lib/listen/record/entry.rb +66 -0
- data/vendor/deps/listen/lib/listen/record/symlink_detector.rb +47 -0
- data/vendor/deps/listen/lib/listen/record.rb +122 -0
- data/vendor/deps/listen/lib/listen/silencer/controller.rb +50 -0
- data/vendor/deps/listen/lib/listen/silencer.rb +106 -0
- data/vendor/deps/listen/lib/listen/thread.rb +54 -0
- data/vendor/deps/listen/lib/listen/version.rb +5 -0
- data/vendor/deps/listen/lib/listen.rb +47 -0
- data/vendor/deps/listen/listen.gemspec +40 -0
- data/vendor/deps/listen/spec/acceptance/listen_spec.rb +320 -0
- data/vendor/deps/listen/spec/lib/listen/adapter/base_spec.rb +101 -0
- data/vendor/deps/listen/spec/lib/listen/adapter/bsd_spec.rb +13 -0
- data/vendor/deps/listen/spec/lib/listen/adapter/config_spec.rb +122 -0
- data/vendor/deps/listen/spec/lib/listen/adapter/darwin_spec.rb +82 -0
- data/vendor/deps/listen/spec/lib/listen/adapter/linux_spec.rb +199 -0
- data/vendor/deps/listen/spec/lib/listen/adapter/polling_spec.rb +83 -0
- data/vendor/deps/listen/spec/lib/listen/adapter/windows_spec.rb +13 -0
- data/vendor/deps/listen/spec/lib/listen/adapter_spec.rb +69 -0
- data/vendor/deps/listen/spec/lib/listen/backend_spec.rb +82 -0
- data/vendor/deps/listen/spec/lib/listen/change_spec.rb +102 -0
- data/vendor/deps/listen/spec/lib/listen/cli_spec.rb +116 -0
- data/vendor/deps/listen/spec/lib/listen/directory_spec.rb +284 -0
- data/vendor/deps/listen/spec/lib/listen/event/config_spec.rb +33 -0
- data/vendor/deps/listen/spec/lib/listen/event/loop_spec.rb +118 -0
- data/vendor/deps/listen/spec/lib/listen/event/processor_spec.rb +250 -0
- data/vendor/deps/listen/spec/lib/listen/event/queue_spec.rb +118 -0
- data/vendor/deps/listen/spec/lib/listen/file_spec.rb +254 -0
- data/vendor/deps/listen/spec/lib/listen/fsm_spec.rb +147 -0
- data/vendor/deps/listen/spec/lib/listen/listener/config_spec.rb +29 -0
- data/vendor/deps/listen/spec/lib/listen/listener_spec.rb +321 -0
- data/vendor/deps/listen/spec/lib/listen/logger_spec.rb +212 -0
- data/vendor/deps/listen/spec/lib/listen/monotonic_time_spec.rb +58 -0
- data/vendor/deps/listen/spec/lib/listen/queue_optimizer_spec.rb +111 -0
- data/vendor/deps/listen/spec/lib/listen/record_spec.rb +424 -0
- data/vendor/deps/listen/spec/lib/listen/silencer/controller_spec.rb +97 -0
- data/vendor/deps/listen/spec/lib/listen/silencer_spec.rb +109 -0
- data/vendor/deps/listen/spec/lib/listen/thread_spec.rb +133 -0
- data/vendor/deps/listen/spec/lib/listen_spec.rb +25 -0
- data/vendor/deps/listen/spec/spec_helper.rb +49 -0
- data/vendor/deps/listen/spec/support/acceptance_helper.rb +260 -0
- data/vendor/deps/listen/spec/support/fixtures_helper.rb +32 -0
- data/vendor/deps/listen/spec/support/platform_helper.rb +17 -0
- data/vendor/deps/observer/.github/dependabot.yml +6 -0
- data/vendor/deps/observer/.github/workflows/test.yml +33 -0
- data/vendor/deps/observer/.gitignore +8 -0
- data/vendor/deps/observer/BSDL +22 -0
- data/vendor/deps/observer/COPYING +56 -0
- data/vendor/deps/observer/Gemfile +9 -0
- data/vendor/deps/observer/README.md +139 -0
- data/vendor/deps/observer/Rakefile +10 -0
- data/vendor/deps/observer/bin/console +14 -0
- data/vendor/deps/observer/bin/setup +8 -0
- data/vendor/deps/observer/lib/observer.rb +229 -0
- data/vendor/deps/observer/observer.gemspec +32 -0
- data/vendor/deps/observer/test/test_observer.rb +66 -0
- data/vendor/deps/webrick/.gitignore +9 -0
- data/vendor/deps/webrick/Gemfile +3 -0
- data/vendor/deps/webrick/LICENSE.txt +22 -0
- data/vendor/deps/webrick/README.md +61 -0
- data/vendor/deps/webrick/Rakefile +10 -0
- data/vendor/deps/webrick/lib/webrick/accesslog.rb +157 -0
- data/vendor/deps/webrick/lib/webrick/cgi.rb +313 -0
- data/vendor/deps/webrick/lib/webrick/compat.rb +36 -0
- data/vendor/deps/webrick/lib/webrick/config.rb +158 -0
- data/vendor/deps/webrick/lib/webrick/cookie.rb +172 -0
- data/vendor/deps/webrick/lib/webrick/htmlutils.rb +30 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/authenticator.rb +117 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/basicauth.rb +116 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/digestauth.rb +395 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/htdigest.rb +132 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/htgroup.rb +97 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/htpasswd.rb +158 -0
- data/vendor/deps/webrick/lib/webrick/httpauth/userdb.rb +53 -0
- data/vendor/deps/webrick/lib/webrick/httpauth.rb +96 -0
- data/vendor/deps/webrick/lib/webrick/httpproxy.rb +354 -0
- data/vendor/deps/webrick/lib/webrick/httprequest.rb +636 -0
- data/vendor/deps/webrick/lib/webrick/httpresponse.rb +564 -0
- data/vendor/deps/webrick/lib/webrick/https.rb +152 -0
- data/vendor/deps/webrick/lib/webrick/httpserver.rb +294 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/abstract.rb +152 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/cgi_runner.rb +47 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/cgihandler.rb +126 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/erbhandler.rb +88 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/filehandler.rb +552 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet/prochandler.rb +47 -0
- data/vendor/deps/webrick/lib/webrick/httpservlet.rb +23 -0
- data/vendor/deps/webrick/lib/webrick/httpstatus.rb +194 -0
- data/vendor/deps/webrick/lib/webrick/httputils.rb +512 -0
- data/vendor/deps/webrick/lib/webrick/httpversion.rb +76 -0
- data/vendor/deps/webrick/lib/webrick/log.rb +156 -0
- data/vendor/deps/webrick/lib/webrick/server.rb +381 -0
- data/vendor/deps/webrick/lib/webrick/ssl.rb +215 -0
- data/vendor/deps/webrick/lib/webrick/utils.rb +265 -0
- data/vendor/deps/webrick/lib/webrick/version.rb +18 -0
- data/vendor/deps/webrick/lib/webrick.rb +232 -0
- data/vendor/deps/webrick/webrick.gemspec +74 -0
- metadata +412 -0
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# typed: true
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
|
|
5
|
+
require 'io/console'
|
|
6
|
+
|
|
7
|
+
module CLI
|
|
8
|
+
module UI
|
|
9
|
+
module Prompt
|
|
10
|
+
class InteractiveOptions
|
|
11
|
+
DONE = 'Done'
|
|
12
|
+
CHECKBOX_ICON = { false => '☐', true => '☑' }
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
# Prompts the user with options
|
|
16
|
+
# Uses an interactive session to allow the user to pick an answer
|
|
17
|
+
# Can use arrows, y/n, numbers (1/2), and vim bindings to control
|
|
18
|
+
# For more than 9 options, hitting 'e', ':', or 'G' will enter select
|
|
19
|
+
# mode allowing the user to type in longer numbers
|
|
20
|
+
# Pressing 'f' or '/' will allow the user to filter the results
|
|
21
|
+
#
|
|
22
|
+
# https://user-images.githubusercontent.com/3074765/33797984-0ebb5e64-dcdf-11e7-9e7e-7204f279cece.gif
|
|
23
|
+
#
|
|
24
|
+
# ==== Example Usage:
|
|
25
|
+
#
|
|
26
|
+
# Ask an interactive question
|
|
27
|
+
# CLI::UI::Prompt::InteractiveOptions.call(%w(rails go python))
|
|
28
|
+
#
|
|
29
|
+
#: (Array[String] options, ?multiple: bool, ?default: (String | Array[String])?) -> (String | Array[String])
|
|
30
|
+
def call(options, multiple: false, default: nil)
|
|
31
|
+
list = new(options, multiple: multiple, default: default)
|
|
32
|
+
selected = list.call
|
|
33
|
+
case selected
|
|
34
|
+
when Array
|
|
35
|
+
selected.map do |s|
|
|
36
|
+
options[s - 1] #: as !nil
|
|
37
|
+
end
|
|
38
|
+
else
|
|
39
|
+
options[selected - 1] #: as !nil
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Initializes a new +InteractiveOptions+
|
|
45
|
+
# Usually called from +self.call+
|
|
46
|
+
#
|
|
47
|
+
# ==== Example Usage:
|
|
48
|
+
#
|
|
49
|
+
# CLI::UI::Prompt::InteractiveOptions.new(%w(rails go python))
|
|
50
|
+
#
|
|
51
|
+
#: (Array[String] options, ?multiple: bool, ?default: (String | Array[String])?) -> void
|
|
52
|
+
def initialize(options, multiple: false, default: nil)
|
|
53
|
+
@options = options
|
|
54
|
+
@active = if default && (i = options.index(default))
|
|
55
|
+
i + 1
|
|
56
|
+
else
|
|
57
|
+
1
|
|
58
|
+
end
|
|
59
|
+
@marker = '>'
|
|
60
|
+
@answer = nil
|
|
61
|
+
@state = :root
|
|
62
|
+
@multiple = multiple
|
|
63
|
+
# Indicate that an extra line (the "metadata" line) is present and
|
|
64
|
+
# the terminal output should be drawn over when processing user input
|
|
65
|
+
@displaying_metadata = false
|
|
66
|
+
@filter = ''
|
|
67
|
+
# 0-indexed array representing if selected
|
|
68
|
+
# @options[0] is selected if @chosen[0]
|
|
69
|
+
if multiple
|
|
70
|
+
@chosen = if default
|
|
71
|
+
@options.map { |option| default.include?(option) }
|
|
72
|
+
else
|
|
73
|
+
Array.new(@options.size) { false }
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
@redraw = true
|
|
77
|
+
@presented_options = [] #: Array[[String, Integer?]]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Calls the +InteractiveOptions+ and asks the question
|
|
81
|
+
# Usually used from +self.call+
|
|
82
|
+
#
|
|
83
|
+
#: -> (Integer | Array[Integer])
|
|
84
|
+
def call
|
|
85
|
+
calculate_option_line_lengths
|
|
86
|
+
CLI::UI.raw { print(ANSI.hide_cursor) }
|
|
87
|
+
while @answer.nil?
|
|
88
|
+
render_options
|
|
89
|
+
process_input_until_redraw_required
|
|
90
|
+
reset_position
|
|
91
|
+
end
|
|
92
|
+
clear_output
|
|
93
|
+
|
|
94
|
+
@answer
|
|
95
|
+
ensure
|
|
96
|
+
CLI::UI.raw do
|
|
97
|
+
print(ANSI.show_cursor)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
#: -> void
|
|
104
|
+
def calculate_option_line_lengths
|
|
105
|
+
@terminal_width_at_calculation_time = CLI::UI::Terminal.width
|
|
106
|
+
# options will be an array of questions but each option can be multi-line
|
|
107
|
+
# so to get the # of lines, you need to join then split
|
|
108
|
+
|
|
109
|
+
# since lines may be longer than the terminal is wide, we need to
|
|
110
|
+
# determine how many extra lines would be taken up by them.
|
|
111
|
+
#
|
|
112
|
+
# To accomplish this we split the string by new lines and add the
|
|
113
|
+
# prefix to the first line. We use the options count as the number since
|
|
114
|
+
# it will be the widest number we will display, and we pad the others to
|
|
115
|
+
# align with it. Then we calculate how many lines would be needed to
|
|
116
|
+
# render the string based on the terminal width.
|
|
117
|
+
prefix = "#{@marker} #{@options.count}. #{@multiple ? "☐ " : ""}"
|
|
118
|
+
|
|
119
|
+
@option_lengths = @options.map do |text|
|
|
120
|
+
next 1 if text.empty?
|
|
121
|
+
|
|
122
|
+
# Find the length of all the lines in this string
|
|
123
|
+
non_empty_line_lengths = "#{prefix}#{text}".split("\n").reject(&:empty?).map do |line|
|
|
124
|
+
CLI::UI.fmt(line, enable_color: false).length
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Finally, we need to calculate how many lines each one will take. We can do that by dividing each one
|
|
128
|
+
# by the width of the terminal, rounding up to the nearest natural number
|
|
129
|
+
non_empty_line_lengths.sum { |length| (length.to_f / @terminal_width_at_calculation_time).ceil }
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
#: (?Integer number_of_lines) -> void
|
|
134
|
+
def reset_position(number_of_lines = num_lines)
|
|
135
|
+
# This will put us back at the beginning of the options
|
|
136
|
+
# When we redraw the options, they will be overwritten
|
|
137
|
+
CLI::UI.raw do
|
|
138
|
+
number_of_lines.times { print(ANSI.previous_line) }
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
#: (?Integer number_of_lines) -> void
|
|
143
|
+
def clear_output(number_of_lines = num_lines)
|
|
144
|
+
CLI::UI.raw do
|
|
145
|
+
# Write over all lines with whitespace
|
|
146
|
+
number_of_lines.times { puts(' ' * CLI::UI::Terminal.width) }
|
|
147
|
+
end
|
|
148
|
+
reset_position(number_of_lines)
|
|
149
|
+
|
|
150
|
+
# Update if metadata is being displayed
|
|
151
|
+
# This must be done _after_ the output is cleared or it won't draw over
|
|
152
|
+
# the entire output
|
|
153
|
+
@displaying_metadata = display_metadata?
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Don't use this in place of +@displaying_metadata+, this updates too
|
|
157
|
+
# quickly to be useful when drawing to the screen.
|
|
158
|
+
#: -> bool
|
|
159
|
+
def display_metadata?
|
|
160
|
+
filtering? || selecting? || has_filter?
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
#: -> Integer
|
|
164
|
+
def num_lines
|
|
165
|
+
calculate_option_line_lengths if terminal_width_changed?
|
|
166
|
+
|
|
167
|
+
option_length = presented_options.reduce(0) do |total_length, (_, option_number)|
|
|
168
|
+
# Handle continuation markers and "Done" option when multiple is true
|
|
169
|
+
next total_length + 1 if option_number.nil? || option_number.zero?
|
|
170
|
+
|
|
171
|
+
total_length + @option_lengths[option_number - 1]
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
option_length + (@displaying_metadata ? 1 : 0)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
#: -> bool
|
|
178
|
+
def terminal_width_changed?
|
|
179
|
+
@terminal_width_at_calculation_time != CLI::UI::Terminal.width
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
ESC = "\e"
|
|
183
|
+
BACKSPACE = "\u007F"
|
|
184
|
+
CTRL_C = "\u0003"
|
|
185
|
+
CTRL_D = "\u0004"
|
|
186
|
+
|
|
187
|
+
#: -> void
|
|
188
|
+
def up
|
|
189
|
+
active_index = @filtered_options.index { |_, num| num == @active } || 0
|
|
190
|
+
|
|
191
|
+
previous_visible = @filtered_options[active_index - 1]
|
|
192
|
+
previous_visible ||= @filtered_options.last
|
|
193
|
+
|
|
194
|
+
@active = previous_visible ? previous_visible.last : -1
|
|
195
|
+
@redraw = true
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
#: -> void
|
|
199
|
+
def down
|
|
200
|
+
active_index = @filtered_options.index { |_, num| num == @active } || 0
|
|
201
|
+
|
|
202
|
+
next_visible = @filtered_options[active_index + 1]
|
|
203
|
+
next_visible ||= @filtered_options.first
|
|
204
|
+
|
|
205
|
+
@active = next_visible ? next_visible.last : -1
|
|
206
|
+
@redraw = true
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
#: -> void
|
|
210
|
+
def first_option
|
|
211
|
+
@active = @filtered_options.first&.last || -1
|
|
212
|
+
@redraw = true
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
#: -> void
|
|
216
|
+
def last_option
|
|
217
|
+
@active = @filtered_options.last&.last || -1
|
|
218
|
+
@redraw = true
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
#: -> void
|
|
222
|
+
def next_page
|
|
223
|
+
active_index = @filtered_options.index { |_, num| num == @active } || 0
|
|
224
|
+
|
|
225
|
+
previous_visible = @filtered_options[active_index + max_lines]
|
|
226
|
+
previous_visible ||= @filtered_options.last
|
|
227
|
+
|
|
228
|
+
@active = previous_visible ? previous_visible.last : -1
|
|
229
|
+
@redraw = true
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
#: -> void
|
|
233
|
+
def previous_page
|
|
234
|
+
active_index = @filtered_options.index { |_, num| num == @active } || 0
|
|
235
|
+
|
|
236
|
+
# do not jump into the end of the options if the subtraction result is non-positive
|
|
237
|
+
previous_visible = @filtered_options[active_index - max_lines] if active_index - max_lines >= 0
|
|
238
|
+
previous_visible ||= @filtered_options.first
|
|
239
|
+
|
|
240
|
+
@active = previous_visible ? previous_visible.last : -1
|
|
241
|
+
@redraw = true
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# n is 1-indexed selection
|
|
245
|
+
# n == 0 if "Done" was selected in @multiple mode
|
|
246
|
+
#: (Integer n, ?final: bool) -> void
|
|
247
|
+
def select_n(n, final: false)
|
|
248
|
+
if @multiple
|
|
249
|
+
if n == 0
|
|
250
|
+
@answer = []
|
|
251
|
+
@chosen.each_with_index do |selected, i|
|
|
252
|
+
@answer << i + 1 if selected
|
|
253
|
+
end
|
|
254
|
+
else
|
|
255
|
+
@active = n
|
|
256
|
+
@chosen[n - 1] = !@chosen[n - 1]
|
|
257
|
+
end
|
|
258
|
+
elsif n == 0
|
|
259
|
+
# Ignore pressing "0" when not in multiple mode
|
|
260
|
+
elsif !final && should_enter_select_mode?(n)
|
|
261
|
+
# When we have more than 9 options, we need to enter select mode
|
|
262
|
+
# to avoid pre-selecting (e.g) 1 when the user wanted 10.
|
|
263
|
+
# This also applies to 2 and 20+ options, 3/30+, etc.
|
|
264
|
+
start_line_select
|
|
265
|
+
@active = n
|
|
266
|
+
else
|
|
267
|
+
@active = n
|
|
268
|
+
@answer = n
|
|
269
|
+
end
|
|
270
|
+
@redraw = true
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
#: (Integer n) -> bool
|
|
274
|
+
def should_enter_select_mode?(n)
|
|
275
|
+
# If we have less than 10 options, we don't need to enter select mode
|
|
276
|
+
# and we can just select the option directly. This just keeps the code easier
|
|
277
|
+
# by making the cases simpler to understand
|
|
278
|
+
return false if @options.length <= 9
|
|
279
|
+
|
|
280
|
+
# At this point we have 10+ options so always need to check if we should run.
|
|
281
|
+
# This can be simplified to checking if the length of options is >= to the option selected * 10:
|
|
282
|
+
# n == 1 && options.length >= 10 (1 * 10), n == 2 && options.length >= 20 (2 * 10), etc.
|
|
283
|
+
# which can be further simplified to just:
|
|
284
|
+
@options.length >= (n * 10)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
#: (String char) -> void
|
|
288
|
+
def select_bool(char)
|
|
289
|
+
return unless (@options - ['yes', 'no']).empty?
|
|
290
|
+
|
|
291
|
+
index = @options.index { |o| o.start_with?(char) } #: as !nil
|
|
292
|
+
@active = index + 1
|
|
293
|
+
@answer = index + 1
|
|
294
|
+
@redraw = true
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
#: (String char) -> void
|
|
298
|
+
def build_selection(char)
|
|
299
|
+
@active = (@active.to_s + char).to_i
|
|
300
|
+
@redraw = true
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
#: -> void
|
|
304
|
+
def chop_selection
|
|
305
|
+
@active = @active.to_s.chop.to_i
|
|
306
|
+
@redraw = true
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
#: (String char) -> void
|
|
310
|
+
def update_search(char)
|
|
311
|
+
@redraw = true
|
|
312
|
+
|
|
313
|
+
# Control+D or Backspace on empty search closes search
|
|
314
|
+
if (char == CTRL_D) || (@filter.empty? && (char == BACKSPACE))
|
|
315
|
+
@filter = ''
|
|
316
|
+
@state = :root
|
|
317
|
+
return
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
if char == BACKSPACE
|
|
321
|
+
@filter.chop!
|
|
322
|
+
else
|
|
323
|
+
@filter += char
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
#: -> void
|
|
328
|
+
def select_current
|
|
329
|
+
# Prevent selection of invisible options
|
|
330
|
+
return unless presented_options.any? { |_, num| num == @active }
|
|
331
|
+
|
|
332
|
+
select_n(@active, final: true)
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
#: -> void
|
|
336
|
+
def process_input_until_redraw_required
|
|
337
|
+
@redraw = false
|
|
338
|
+
wait_for_user_input until @redraw
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# rubocop:disable Style/WhenThen,Layout/SpaceBeforeSemicolon,Style/Semicolon
|
|
342
|
+
#: -> void
|
|
343
|
+
def wait_for_user_input
|
|
344
|
+
char = Prompt.read_char
|
|
345
|
+
@last_char = char
|
|
346
|
+
|
|
347
|
+
case char
|
|
348
|
+
when CTRL_C, nil ; raise Interrupt
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
max_digit = [@options.size, 9].min.to_s
|
|
352
|
+
case @state
|
|
353
|
+
when :root
|
|
354
|
+
case char
|
|
355
|
+
when ESC ; @state = :esc
|
|
356
|
+
when 'k' ; up
|
|
357
|
+
when 'j' ; down
|
|
358
|
+
when 'e', ':', 'G' ; start_line_select
|
|
359
|
+
when 'f', '/' ; start_filter
|
|
360
|
+
when ('0'..max_digit) ; select_n(char.to_i)
|
|
361
|
+
when 'y', 'n' ; select_bool(char)
|
|
362
|
+
when ' ', "\r", "\n" ; select_current # <enter>
|
|
363
|
+
end
|
|
364
|
+
when :filter
|
|
365
|
+
case char
|
|
366
|
+
when ESC ; @state = :esc
|
|
367
|
+
when "\r", "\n" ; select_current
|
|
368
|
+
when "\b" ; update_search(BACKSPACE) # Happens on Windows
|
|
369
|
+
else ; update_search(char)
|
|
370
|
+
end
|
|
371
|
+
when :line_select
|
|
372
|
+
case char
|
|
373
|
+
when ESC ; @state = :esc
|
|
374
|
+
when 'k' ; up ; @state = :root
|
|
375
|
+
when 'j' ; down ; @state = :root
|
|
376
|
+
when 'e', ':', 'G', 'q' ; stop_line_select
|
|
377
|
+
when '0'..'9' ; build_selection(char)
|
|
378
|
+
when BACKSPACE ; chop_selection # Pop last input on backspace
|
|
379
|
+
when ' ', "\r", "\n" ; select_current
|
|
380
|
+
end
|
|
381
|
+
when :esc
|
|
382
|
+
case char
|
|
383
|
+
when '[' ; @state = :esc_bracket
|
|
384
|
+
else ; raise Interrupt # unhandled escape sequence.
|
|
385
|
+
end
|
|
386
|
+
when :esc_bracket
|
|
387
|
+
@state = has_filter? ? :filter : :root
|
|
388
|
+
case char
|
|
389
|
+
when 'A' ; up
|
|
390
|
+
when 'B' ; down
|
|
391
|
+
when 'C' ; # Ignore right key
|
|
392
|
+
when 'D' ; # Ignore left key
|
|
393
|
+
when '3' ; print("\a")
|
|
394
|
+
when '5' ; previous_page
|
|
395
|
+
when '6' ; next_page
|
|
396
|
+
when 'H' ; first_option
|
|
397
|
+
when 'F' ; last_option
|
|
398
|
+
else ; raise Interrupt # unhandled escape sequence.
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
end
|
|
402
|
+
# rubocop:enable Style/WhenThen,Layout/SpaceBeforeSemicolon,Style/Semicolon
|
|
403
|
+
|
|
404
|
+
#: -> bool
|
|
405
|
+
def selecting?
|
|
406
|
+
@state == :line_select
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
#: -> bool
|
|
410
|
+
def filtering?
|
|
411
|
+
@state == :filter
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
#: -> bool
|
|
415
|
+
def has_filter?
|
|
416
|
+
!@filter.empty?
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
#: -> void
|
|
420
|
+
def start_filter
|
|
421
|
+
@state = :filter
|
|
422
|
+
@redraw = true
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
#: -> void
|
|
426
|
+
def start_line_select
|
|
427
|
+
@state = :line_select
|
|
428
|
+
@active = 0
|
|
429
|
+
@redraw = true
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
#: -> void
|
|
433
|
+
def stop_line_select
|
|
434
|
+
@state = :root
|
|
435
|
+
@active = 1 if @active.zero?
|
|
436
|
+
@redraw = true
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
#: (?recalculate: bool) -> Array[[String, Integer?]]
|
|
440
|
+
def presented_options(recalculate: false)
|
|
441
|
+
return @presented_options unless recalculate
|
|
442
|
+
|
|
443
|
+
@presented_options = @options.zip(1..)
|
|
444
|
+
if has_filter?
|
|
445
|
+
@presented_options.select! { |option, _| option.downcase.include?(@filter.downcase) }
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
# Used for selection purposes
|
|
449
|
+
@presented_options.push([DONE, 0]) if @multiple
|
|
450
|
+
@filtered_options = @presented_options.dup
|
|
451
|
+
|
|
452
|
+
ensure_visible_is_active if has_filter?
|
|
453
|
+
|
|
454
|
+
# Must have more lines before the selection than we can display
|
|
455
|
+
if distance_from_start_to_selection > max_lines
|
|
456
|
+
@presented_options.shift(distance_from_start_to_selection - max_lines)
|
|
457
|
+
ensure_first_item_is_continuation_marker
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
# Must have more lines after the selection than we can display
|
|
461
|
+
if distance_from_selection_to_end > max_lines
|
|
462
|
+
@presented_options.pop(distance_from_selection_to_end - max_lines)
|
|
463
|
+
ensure_last_item_is_continuation_marker
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
while num_lines > max_lines
|
|
467
|
+
# try to keep the selection centered in the window:
|
|
468
|
+
if distance_from_selection_to_end > distance_from_start_to_selection
|
|
469
|
+
# selection is closer to top than bottom, so trim a row from the bottom
|
|
470
|
+
ensure_last_item_is_continuation_marker
|
|
471
|
+
@presented_options.delete_at(-2)
|
|
472
|
+
else
|
|
473
|
+
# selection is closer to bottom than top, so trim a row from the top
|
|
474
|
+
ensure_first_item_is_continuation_marker
|
|
475
|
+
@presented_options.delete_at(1)
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
@presented_options
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
#: -> void
|
|
483
|
+
def ensure_visible_is_active
|
|
484
|
+
unless presented_options.any? { |_, num| num == @active }
|
|
485
|
+
@active = presented_options.first&.last.to_i
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
#: -> Integer
|
|
490
|
+
def distance_from_selection_to_end
|
|
491
|
+
@presented_options.count - index_of_active_option
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
#: -> Integer
|
|
495
|
+
def distance_from_start_to_selection
|
|
496
|
+
index_of_active_option
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
#: -> Integer
|
|
500
|
+
def index_of_active_option
|
|
501
|
+
@presented_options.index { |_, num| num == @active }.to_i
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
#: -> void
|
|
505
|
+
def ensure_last_item_is_continuation_marker
|
|
506
|
+
@presented_options.push(['...', nil]) if @presented_options.last&.last
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
#: -> void
|
|
510
|
+
def ensure_first_item_is_continuation_marker
|
|
511
|
+
@presented_options.unshift(['...', nil]) if @presented_options.first&.last
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
#: -> Integer
|
|
515
|
+
def max_lines
|
|
516
|
+
CLI::UI::Terminal.height - (@displaying_metadata ? 3 : 2) # Keeps a one line question visible
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
#: -> void
|
|
520
|
+
def render_options
|
|
521
|
+
previously_displayed_lines = num_lines
|
|
522
|
+
|
|
523
|
+
@displaying_metadata = display_metadata?
|
|
524
|
+
|
|
525
|
+
options = presented_options(recalculate: true)
|
|
526
|
+
|
|
527
|
+
clear_output(previously_displayed_lines) if previously_displayed_lines > num_lines
|
|
528
|
+
|
|
529
|
+
max_num_length = (@options.size + 1).to_s.length
|
|
530
|
+
|
|
531
|
+
metadata_text = if selecting?
|
|
532
|
+
select_text = @active
|
|
533
|
+
select_text = '{{info:e, q, or up/down anytime to exit}}' if @active == 0
|
|
534
|
+
"Select: #{select_text}"
|
|
535
|
+
elsif filtering? || has_filter?
|
|
536
|
+
filter_text = @filter
|
|
537
|
+
filter_text = '{{info:Ctrl-D anytime or Backspace now to exit}}' if @filter.empty?
|
|
538
|
+
"Filter: #{filter_text}"
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
puts CLI::UI.fmt(" {{green:#{metadata_text}}}#{ANSI.clear_to_end_of_line}") if metadata_text
|
|
542
|
+
|
|
543
|
+
options.each do |choice, num|
|
|
544
|
+
is_chosen = @multiple && num && @chosen[num - 1] && num != 0
|
|
545
|
+
|
|
546
|
+
padding = ' ' * (max_num_length - num.to_s.length)
|
|
547
|
+
message = " #{num}#{num ? "." : " "}#{padding}"
|
|
548
|
+
|
|
549
|
+
format = '%s'
|
|
550
|
+
# If multiple, bold selected. If not multiple, do not bold any options.
|
|
551
|
+
# Bolding options can cause confusion as some users may perceive bold white (default color) as selected
|
|
552
|
+
# rather than the actual selected color.
|
|
553
|
+
format = "{{bold:#{format}}}" if @multiple && is_chosen
|
|
554
|
+
format = "{{cyan:#{format}}}" if @multiple && is_chosen && num != @active
|
|
555
|
+
format = " #{format}"
|
|
556
|
+
|
|
557
|
+
message += format(format, CHECKBOX_ICON[is_chosen]) if @multiple && num && num > 0
|
|
558
|
+
message += format_choice(format, choice)
|
|
559
|
+
|
|
560
|
+
if num == @active
|
|
561
|
+
|
|
562
|
+
color = filtering? || selecting? ? 'green' : 'blue'
|
|
563
|
+
message = message.split("\n").map { |l| "{{#{color}:#{@marker} #{l.strip}}}" }.join("\n")
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
puts CLI::UI.fmt(message)
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
#: (String format, String choice) -> String
|
|
571
|
+
def format_choice(format, choice)
|
|
572
|
+
eol = CLI::UI::ANSI.clear_to_end_of_line
|
|
573
|
+
lines = choice.split("\n")
|
|
574
|
+
|
|
575
|
+
return eol if lines.empty? # Handle blank options
|
|
576
|
+
|
|
577
|
+
lines.map! { |l| format(format, l) + eol }
|
|
578
|
+
lines.join("\n")
|
|
579
|
+
end
|
|
580
|
+
end
|
|
581
|
+
end
|
|
582
|
+
end
|
|
583
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module CLI
|
|
5
|
+
module UI
|
|
6
|
+
module Prompt
|
|
7
|
+
# A class that handles the various options of an InteractivePrompt and their callbacks
|
|
8
|
+
class OptionsHandler
|
|
9
|
+
#: -> void
|
|
10
|
+
def initialize
|
|
11
|
+
@options = {}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
#: -> Array[String]
|
|
15
|
+
def options
|
|
16
|
+
@options.keys
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
#: (String option) { (String option) -> String } -> void
|
|
20
|
+
def option(option, &handler)
|
|
21
|
+
@options[option] = handler
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
#: ((Array[String] | String) options) -> String
|
|
25
|
+
def call(options)
|
|
26
|
+
case options
|
|
27
|
+
when Array
|
|
28
|
+
options.map { |option| @options[option].call(options) }
|
|
29
|
+
else
|
|
30
|
+
@options[options].call(options)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|