clack 0.6.0 → 0.6.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b4723c11dc0a0944ea3a56337800aac60ec1ae3db29094f7f98e77f87b38caa2
4
- data.tar.gz: 8b9bc87d58955147a0d000e94db0094832cb02dea4a92fd13d11618322fe5578
3
+ metadata.gz: 01366d1d6cc81f2514adc5c7bbdc726b3dec22d6697ae2bf26077c2db84efa1b
4
+ data.tar.gz: e1e96b35ef913ee377ed38c0fd98612aa1d758760991ee39ba27ac1cf8dc6136
5
5
  SHA512:
6
- metadata.gz: 70f8abc4ace88dd272abb4022b29819acc7ce3be50b6d1fa0926a4e3e70cc46f48de71ec3840229b55ac7f4cf857d7551d5ff55d35063e96992e1d73e418d1ff
7
- data.tar.gz: 82950f8271b8e672c95d4f05c77749566e54d01db88fe62635ff7dd45b75fb846076497e8d5d6fee41fbf45f3088939f1f4eab13020fcbcc482ad0e7d2366e66
6
+ metadata.gz: ac79a1a3887e261b9d2f14b989381430c35796a1acac47a449e44c773314bcea8985b294880a646213c53bd004900e9e749f9a0d69db55a19dfecd2b4d6eab34
7
+ data.tar.gz: 891cea3cc9b0047602a627396c40950c4397a968aa2ca021b4e2f71719ce40463d62b01db19c3b59ea92fd9efd9e0807b9120afa6cfacbbe5df90fcb391d328a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.6.1] - 2026-06-21
4
+
5
+ ### Added
6
+ - `CLACK_ESCAPE_TIMEOUT` env var to tune the Escape-sequence detection window (milliseconds) for high-latency links like slow SSH, where arrow keys could otherwise be misread as a standalone Escape
7
+
8
+ ### Changed
9
+ - `multiselect`, `group_multiselect`, and `autocomplete_multiselect` now warn on stderr when `initial_values` contains values that don't match any option (still dropped, but no longer silently)
10
+
3
11
  ## [0.6.0] - 2026-05-30
4
12
 
5
13
  ### Added
data/README.md CHANGED
@@ -7,6 +7,9 @@
7
7
  <i>CLI prompts for Ruby. Zero dependencies.</i>
8
8
  <br>
9
9
  <br>
10
+ <sub>A faithful Ruby port of <a href="https://github.com/bombshell-dev/clack"><code>@clack/prompts</code></a>.</sub>
11
+ <br>
12
+ <br>
10
13
  <a href="https://rubygems.org/gems/clack"><img src="https://img.shields.io/gem/v/clack?style=flat-square&color=cc342d" alt="Gem Version"></a>
11
14
  <a href="https://github.com/swhitt/clackrb/actions"><img src="https://img.shields.io/github/actions/workflow/status/swhitt/clackrb/ci.yml?style=flat-square&label=tests" alt="Tests"></a>
12
15
  <a href="https://www.ruby-lang.org"><img src="https://img.shields.io/badge/ruby-3.2%2B-cc342d?style=flat-square" alt="Ruby 3.2+"></a>
@@ -782,7 +785,7 @@ COVERAGE=true bundle exec rake spec # With coverage
782
785
 
783
786
  ## Credits
784
787
 
785
- This is a Ruby port of [Clack](https://github.com/bombshell-dev/clack), created by [Nate Moore](https://github.com/natemoo-re) and the [Astro](https://astro.build) team.
788
+ This is a Ruby port of [`@clack/prompts`](https://github.com/bombshell-dev/clack), created by [Nate Moore](https://github.com/natemoo-re) and the [Astro](https://astro.build) team.
786
789
 
787
790
  ## License
788
791
 
@@ -6,15 +6,10 @@ module Clack
6
6
  module Core
7
7
  # Reads single keystrokes from the terminal in raw mode.
8
8
  # Handles escape sequences for arrow keys and other special keys.
9
+ #
10
+ # The Escape detection window is tunable via the +CLACK_ESCAPE_TIMEOUT+
11
+ # env var (see {Environment.escape_timeout}) for high-latency links.
9
12
  module KeyReader
10
- # Timeout for detecting if Escape is part of a sequence (50ms).
11
- # If no follow-up character arrives, treat Escape as a standalone key.
12
- ESCAPE_TIMEOUT = 0.05
13
-
14
- # Timeout for reading additional characters in a CSI sequence (10ms).
15
- # Short because subsequent bytes in a sequence arrive almost instantly.
16
- SEQUENCE_TIMEOUT = 0.01
17
-
18
13
  class << self
19
14
  # Read a single keystroke in raw mode.
20
15
  # When input is an IO backed by a console, uses raw mode.
@@ -42,14 +37,20 @@ module Clack
42
37
  return char if char.nil? # EOF
43
38
  return char unless char == "\e"
44
39
 
40
+ escape_timeout = Environment.escape_timeout
41
+ # Subsequent bytes in a sequence normally arrive almost instantly, so
42
+ # the inter-byte wait stays much shorter, but it scales with the
43
+ # escape timeout so high-latency links still assemble full sequences.
44
+ sequence_timeout = escape_timeout / 5.0
45
+
45
46
  # Check for escape sequence - wait briefly for follow-up
46
- return char unless io.respond_to?(:wait_readable) && io.wait_readable(ESCAPE_TIMEOUT)
47
+ return char unless io.respond_to?(:wait_readable) && io.wait_readable(escape_timeout)
47
48
 
48
49
  seq = io.getc.to_s
49
50
  return "\e#{seq}" unless seq == "["
50
51
 
51
52
  # Read CSI sequence until no more characters arrive
52
- while io.respond_to?(:wait_readable) && io.wait_readable(SEQUENCE_TIMEOUT)
53
+ while io.respond_to?(:wait_readable) && io.wait_readable(sequence_timeout)
53
54
  seq += io.getc.to_s
54
55
  end
55
56
  "\e[#{seq[1..]}"
@@ -11,6 +11,24 @@ module Clack
11
11
  module SelectionManager
12
12
  REQUIRED_ERROR = "Please select at least one option. Press %s to select, %s to submit"
13
13
 
14
+ # Resolve requested pre-selections against the selectable option values.
15
+ #
16
+ # Values that don't match any current option are dropped and reported on
17
+ # stderr, since they're almost always a typo in +initial_values+ rather
18
+ # than an intentional no-op.
19
+ #
20
+ # @param initial_values [Array] the requested pre-selections
21
+ # @param valid_values [Set] the set of selectable option values
22
+ # @return [Set] the subset of initial_values that map to real options
23
+ def resolve_initial_selection(initial_values, valid_values)
24
+ requested = Set.new(initial_values)
25
+ unknown = requested - valid_values
26
+ unless unknown.empty?
27
+ warn "[clack] ignoring unknown initial_values: #{unknown.to_a.inspect}"
28
+ end
29
+ requested & valid_values
30
+ end
31
+
14
32
  # Toggle a value in the selection set.
15
33
  # @param value [Object] the value to toggle
16
34
  def toggle_value(value)
@@ -6,6 +6,9 @@ module Clack
6
6
  # Environment detection utilities for cross-platform compatibility
7
7
  # and CI/terminal environment awareness.
8
8
  module Environment
9
+ # Default Escape-sequence detection timeout, in seconds.
10
+ DEFAULT_ESCAPE_TIMEOUT = 0.05
11
+
9
12
  class << self
10
13
  # Check if running on Windows
11
14
  # @return [Boolean]
@@ -127,6 +130,29 @@ module Clack
127
130
  end
128
131
  end
129
132
 
133
+ # Escape-sequence detection timeout, in seconds.
134
+ #
135
+ # After an Escape byte arrives, the key reader waits this long for a
136
+ # follow-up byte to decide whether it's a standalone Escape or the start
137
+ # of an arrow-key / CSI sequence. The 50ms default is fine locally but too
138
+ # tight over high-latency links (slow SSH, mosh), where the follow-up
139
+ # bytes lag and arrow keys get misread as a bare Escape (cancelling the
140
+ # prompt). Override with the +CLACK_ESCAPE_TIMEOUT+ env var, in
141
+ # milliseconds, e.g. +CLACK_ESCAPE_TIMEOUT=250+ for a slow connection.
142
+ #
143
+ # Invalid or non-positive values fall back to the default.
144
+ #
145
+ # @return [Float] timeout in seconds
146
+ def escape_timeout
147
+ raw = ENV["CLACK_ESCAPE_TIMEOUT"]
148
+ return DEFAULT_ESCAPE_TIMEOUT unless raw
149
+
150
+ ms = Float(raw, exception: false)
151
+ return DEFAULT_ESCAPE_TIMEOUT unless ms&.positive?
152
+
153
+ ms / 1000.0
154
+ end
155
+
130
156
  # Reset cached environment checks (useful for testing)
131
157
  def reset!
132
158
  remove_instance_variable(:@windows) if defined?(@windows)
@@ -56,7 +56,7 @@ module Clack
56
56
  @option_index = 0
57
57
  @scroll_offset = 0
58
58
  valid_values = Set.new(@all_options.map { |o| o.value })
59
- @selected = Set.new(initial_values) & valid_values
59
+ @selected = resolve_initial_selection(initial_values, valid_values)
60
60
  update_filtered
61
61
  end
62
62
 
@@ -61,7 +61,7 @@ module Clack
61
61
  @groups = normalize_groups(options)
62
62
  @flat_items = build_flat_items
63
63
  valid_values = Set.new(@flat_items.select { |item| item.is_a?(Core::GroupOption) }.map(&:value))
64
- @selected = Set.new(initial_values) & valid_values
64
+ @selected = resolve_initial_selection(initial_values, valid_values)
65
65
  @required = required
66
66
  @selectable_groups = selectable_groups
67
67
  @group_spacing = group_spacing
@@ -45,7 +45,7 @@ module Clack
45
45
  super(message:, **opts)
46
46
  @options = normalize_options(options)
47
47
  valid_values = Set.new(@options.map { |o| o.value })
48
- @selected = Set.new(initial_values) & valid_values
48
+ @selected = resolve_initial_selection(initial_values, valid_values)
49
49
  @required = required
50
50
  @max_items = max_items
51
51
  @scroll_offset = 0
data/lib/clack/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Clack
4
4
  # Current gem version.
5
- VERSION = "0.6.0"
5
+ VERSION = "0.6.1"
6
6
  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.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Whittaker
@@ -103,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
103
  - !ruby/object:Gem::Version
104
104
  version: '0'
105
105
  requirements: []
106
- rubygems_version: 3.6.9
106
+ rubygems_version: 4.0.10
107
107
  specification_version: 4
108
108
  summary: Beautiful, minimal CLI prompts
109
109
  test_files: []