clack 0.4.5 → 0.4.6
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 +13 -0
- data/lib/clack/colors.rb +1 -6
- data/lib/clack/core/cursor.rb +1 -3
- data/lib/clack/core/prompt.rb +18 -3
- data/lib/clack/core/settings.rb +2 -2
- data/lib/clack/prompts/autocomplete.rb +1 -11
- data/lib/clack/prompts/autocomplete_multiselect.rb +2 -11
- data/lib/clack/prompts/confirm.rb +1 -11
- data/lib/clack/prompts/date.rb +26 -42
- data/lib/clack/prompts/group_multiselect.rb +1 -12
- data/lib/clack/prompts/multiselect.rb +2 -11
- data/lib/clack/prompts/password.rb +1 -11
- data/lib/clack/prompts/path.rb +0 -11
- data/lib/clack/prompts/range.rb +1 -11
- data/lib/clack/prompts/select.rb +1 -11
- data/lib/clack/prompts/select_key.rb +1 -11
- data/lib/clack/prompts/text.rb +0 -11
- data/lib/clack/symbols.rb +2 -3
- data/lib/clack/version.rb +1 -1
- data/lib/clack.rb +12 -7
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e27f6e6ab9835d2855570ebdcd9b74a581becaffad5ba6a814e54ec5d44097b2
|
|
4
|
+
data.tar.gz: 8788e05802f917a1a6abe06697a4ca47ff451da0235d7336b560adf8558451a0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 173ead18da184ea230092d263bb4e607eb623c788fcdfae7d4315afbebe140bbe5335e42fa7c7ee460481916e46a6fda464f9b13f8d011228648dcf13a799704
|
|
7
|
+
data.tar.gz: 56fd6c8cbca6c610cb73941f565c84e62c6bcc38d5b48741c35c52b86c14e45ff858219e5973669d1db7beb4bb045259d11daa60d172d3e2603ad16c04e2e812
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.6] - 2026-03-22
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- `Settings.printable?` now accepts combining characters and multi-codepoint grapheme clusters (accented letters, emoji)
|
|
7
|
+
- Signal handlers use `write_nonblock` instead of `print` for async safety
|
|
8
|
+
- `S_STEP_ERROR` ASCII fallback changed from `x` to `!` (was identical to `S_STEP_CANCEL`)
|
|
9
|
+
- CI mode validation warnings now print to stderr instead of stdout
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- Colors, Cursor, and Symbols ANSI detection unified through `Environment.colors_supported?`
|
|
13
|
+
- Extracted `build_final_frame` template into `Core::Prompt` with `final_display` hook (11 prompt classes simplified)
|
|
14
|
+
- Date prompt: consolidated duplicated segment logic into `update_segment`
|
|
15
|
+
|
|
3
16
|
## [0.4.5] - 2026-02-22
|
|
4
17
|
|
|
5
18
|
### Fixed
|
data/lib/clack/colors.rb
CHANGED
|
@@ -8,12 +8,7 @@ module Clack
|
|
|
8
8
|
# - FORCE_COLOR environment variable forces colors on
|
|
9
9
|
module Colors
|
|
10
10
|
class << self
|
|
11
|
-
def enabled?
|
|
12
|
-
return true if ENV["FORCE_COLOR"] && ENV["FORCE_COLOR"] != "0"
|
|
13
|
-
return false if ENV["NO_COLOR"]
|
|
14
|
-
|
|
15
|
-
$stdout.tty?
|
|
16
|
-
end
|
|
11
|
+
def enabled? = Environment.colors_supported?
|
|
17
12
|
|
|
18
13
|
# @!group Foreground Colors (standard)
|
|
19
14
|
|
data/lib/clack/core/cursor.rb
CHANGED
|
@@ -13,9 +13,7 @@ module Clack
|
|
|
13
13
|
def enabled?
|
|
14
14
|
return @enabled unless @enabled.nil?
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
return true if ENV["FORCE_COLOR"] && ENV["FORCE_COLOR"] != "0"
|
|
18
|
-
$stdout.tty? && ENV["TERM"] != "dumb" && !ENV["NO_COLOR"]
|
|
16
|
+
Environment.colors_supported?
|
|
19
17
|
end
|
|
20
18
|
|
|
21
19
|
# Visibility
|
data/lib/clack/core/prompt.rb
CHANGED
|
@@ -316,13 +316,23 @@ module Clack
|
|
|
316
316
|
end
|
|
317
317
|
|
|
318
318
|
# Build the final frame shown after interaction ends.
|
|
319
|
-
#
|
|
319
|
+
# Default renders a one-line summary: bar, symbol+message, styled final value.
|
|
320
|
+
# Override {#final_display} to customize what value is shown.
|
|
321
|
+
# Override this entirely for multi-line final output (e.g. MultilineText).
|
|
320
322
|
#
|
|
321
323
|
# @return [String] the final frame content
|
|
322
324
|
def build_final_frame
|
|
323
|
-
|
|
325
|
+
"#{bar}\n" \
|
|
326
|
+
"#{symbol_for_state} #{@message}\n" \
|
|
327
|
+
"#{bar} #{styled_final_display}\n"
|
|
324
328
|
end
|
|
325
329
|
|
|
330
|
+
# The text to display in the final frame after submit/cancel.
|
|
331
|
+
# Override in subclasses to customize (e.g. masked password, formatted date).
|
|
332
|
+
#
|
|
333
|
+
# @return [String]
|
|
334
|
+
def final_display = @value.to_s
|
|
335
|
+
|
|
326
336
|
# Check if prompt has reached a terminal state.
|
|
327
337
|
#
|
|
328
338
|
# @return [Boolean] true if state is :submit or :cancel
|
|
@@ -337,13 +347,18 @@ module Clack
|
|
|
337
347
|
def run_ci_mode
|
|
338
348
|
submit
|
|
339
349
|
if @state == :error
|
|
340
|
-
|
|
350
|
+
$stderr.print "#{Colors.yellow("!")} #{Colors.yellow("CI mode: validation failed for")} \"#{@message}\": #{@error_message}\n"
|
|
341
351
|
end
|
|
342
352
|
@value
|
|
343
353
|
end
|
|
344
354
|
|
|
345
355
|
private
|
|
346
356
|
|
|
357
|
+
def styled_final_display
|
|
358
|
+
text = final_display
|
|
359
|
+
(@state == :cancel) ? Colors.strikethrough(Colors.dim(text)) : Colors.dim(text)
|
|
360
|
+
end
|
|
361
|
+
|
|
347
362
|
def warn_narrow_terminal
|
|
348
363
|
return unless Environment.tty?(@output)
|
|
349
364
|
|
data/lib/clack/core/settings.rb
CHANGED
|
@@ -91,9 +91,9 @@ module Clack
|
|
|
91
91
|
aliases[key] if ACTIONS.include?(aliases[key])
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
# Check if a key is a printable character
|
|
94
|
+
# Check if a key is a printable character (handles combining marks and multi-codepoint grapheme clusters)
|
|
95
95
|
def printable?(key)
|
|
96
|
-
key && key.length == 1 && key.ord >= PRINTABLE_CHAR_MIN
|
|
96
|
+
key && key.grapheme_clusters.length == 1 && key.ord >= PRINTABLE_CHAR_MIN
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
# Check if a key is a backspace/delete
|
|
@@ -121,17 +121,7 @@ module Clack
|
|
|
121
121
|
lines.join
|
|
122
122
|
end
|
|
123
123
|
|
|
124
|
-
def
|
|
125
|
-
lines = []
|
|
126
|
-
lines << "#{bar}\n"
|
|
127
|
-
lines << "#{symbol_for_state} #{@message}\n"
|
|
128
|
-
|
|
129
|
-
display_value = @filtered[@selected_index]&.[](:label) || @value
|
|
130
|
-
display = (@state == :cancel) ? Colors.strikethrough(Colors.dim(display_value)) : Colors.dim(display_value)
|
|
131
|
-
lines << "#{bar} #{display}\n"
|
|
132
|
-
|
|
133
|
-
lines.join
|
|
134
|
-
end
|
|
124
|
+
def final_display = @filtered[@selected_index]&.[](:label) || @value
|
|
135
125
|
|
|
136
126
|
private
|
|
137
127
|
|
|
@@ -130,17 +130,8 @@ module Clack
|
|
|
130
130
|
lines.join
|
|
131
131
|
end
|
|
132
132
|
|
|
133
|
-
def
|
|
134
|
-
|
|
135
|
-
lines << "#{bar}\n"
|
|
136
|
-
lines << "#{symbol_for_state} #{@message}\n"
|
|
137
|
-
|
|
138
|
-
labels = @all_options.select { |o| @selected.include?(o[:value]) }.map { |o| o[:label] }
|
|
139
|
-
display_text = labels.join(", ")
|
|
140
|
-
display = (@state == :cancel) ? Colors.strikethrough(Colors.dim(display_text)) : Colors.dim(display_text)
|
|
141
|
-
lines << "#{bar} #{display}\n"
|
|
142
|
-
|
|
143
|
-
lines.join
|
|
133
|
+
def final_display
|
|
134
|
+
@all_options.select { |o| @selected.include?(o[:value]) }.map { |o| o[:label] }.join(", ")
|
|
144
135
|
end
|
|
145
136
|
|
|
146
137
|
private
|
|
@@ -71,17 +71,7 @@ module Clack
|
|
|
71
71
|
lines.join
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
def
|
|
75
|
-
lines = []
|
|
76
|
-
lines << "#{bar}\n"
|
|
77
|
-
lines << "#{symbol_for_state} #{@message}\n"
|
|
78
|
-
|
|
79
|
-
selected = @value ? @active_label : @inactive_label
|
|
80
|
-
display = (@state == :cancel) ? Colors.strikethrough(Colors.dim(selected)) : Colors.dim(selected)
|
|
81
|
-
lines << "#{bar} #{display}\n"
|
|
82
|
-
|
|
83
|
-
lines.join
|
|
84
|
-
end
|
|
74
|
+
def final_display = @value ? @active_label : @inactive_label
|
|
85
75
|
|
|
86
76
|
private
|
|
87
77
|
|
data/lib/clack/prompts/date.rb
CHANGED
|
@@ -99,17 +99,7 @@ module Clack
|
|
|
99
99
|
lines.join
|
|
100
100
|
end
|
|
101
101
|
|
|
102
|
-
def
|
|
103
|
-
lines = []
|
|
104
|
-
lines << "#{bar}\n"
|
|
105
|
-
lines << "#{symbol_for_state} #{@message}\n"
|
|
106
|
-
|
|
107
|
-
display_text = formatted_date
|
|
108
|
-
display = (@state == :cancel) ? Colors.strikethrough(Colors.dim(display_text)) : Colors.dim(display_text)
|
|
109
|
-
lines << "#{bar} #{display}\n"
|
|
110
|
-
|
|
111
|
-
lines.join
|
|
112
|
-
end
|
|
102
|
+
def final_display = formatted_date
|
|
113
103
|
|
|
114
104
|
private
|
|
115
105
|
|
|
@@ -164,28 +154,7 @@ module Clack
|
|
|
164
154
|
def adjust_segment(delta)
|
|
165
155
|
commit_input_buffer
|
|
166
156
|
@input_buffer = ""
|
|
167
|
-
|
|
168
|
-
case current_segment_type
|
|
169
|
-
when :year
|
|
170
|
-
@year = (@year + delta).clamp(1, 9999)
|
|
171
|
-
clamp_day_to_month
|
|
172
|
-
when :month
|
|
173
|
-
@month += delta
|
|
174
|
-
@month = wrap_value(@month, 1, 12)
|
|
175
|
-
clamp_day_to_month
|
|
176
|
-
when :day
|
|
177
|
-
max_day = days_in_month(@year, @month)
|
|
178
|
-
@day = wrap_value(@day + delta, 1, max_day)
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
enforce_bounds
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def wrap_value(val, min, max)
|
|
185
|
-
return min if val > max
|
|
186
|
-
return max if val < min
|
|
187
|
-
|
|
188
|
-
val
|
|
157
|
+
update_segment(segment_value + delta, wrap: true)
|
|
189
158
|
end
|
|
190
159
|
|
|
191
160
|
def handle_digit(digit)
|
|
@@ -201,23 +170,38 @@ module Clack
|
|
|
201
170
|
def commit_input_buffer
|
|
202
171
|
return if @input_buffer.empty?
|
|
203
172
|
|
|
204
|
-
|
|
173
|
+
update_segment(@input_buffer.to_i)
|
|
205
174
|
@input_buffer = ""
|
|
175
|
+
end
|
|
206
176
|
|
|
177
|
+
def segment_value
|
|
207
178
|
case current_segment_type
|
|
208
|
-
when :year
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
when :month
|
|
212
|
-
@month = value.clamp(1, 12)
|
|
213
|
-
clamp_day_to_month
|
|
214
|
-
when :day
|
|
215
|
-
@day = value.clamp(1, days_in_month(@year, @month))
|
|
179
|
+
when :year then @year
|
|
180
|
+
when :month then @month
|
|
181
|
+
when :day then @day
|
|
216
182
|
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def update_segment(value, wrap: false)
|
|
186
|
+
constrain = wrap ? method(:wrap_value) : :clamp.to_proc
|
|
217
187
|
|
|
188
|
+
case current_segment_type
|
|
189
|
+
when :year then @year = value.clamp(1, 9999)
|
|
190
|
+
when :month then @month = constrain.call(value, 1, 12)
|
|
191
|
+
when :day then @day = constrain.call(value, 1, days_in_month(@year, @month))
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
clamp_day_to_month
|
|
218
195
|
enforce_bounds
|
|
219
196
|
end
|
|
220
197
|
|
|
198
|
+
def wrap_value(val, min, max)
|
|
199
|
+
return min if val > max
|
|
200
|
+
return max if val < min
|
|
201
|
+
|
|
202
|
+
val
|
|
203
|
+
end
|
|
204
|
+
|
|
221
205
|
def current_segment_type = FORMATS[@format][:order][@segment]
|
|
222
206
|
|
|
223
207
|
def days_in_month(year, month)
|
|
@@ -126,18 +126,7 @@ module Clack
|
|
|
126
126
|
lines.join
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
def
|
|
130
|
-
lines = []
|
|
131
|
-
lines << "#{bar}\n"
|
|
132
|
-
lines << "#{symbol_for_state} #{@message}\n"
|
|
133
|
-
|
|
134
|
-
labels = selected_options.map { |o| o[:label] }
|
|
135
|
-
display_text = labels.join(", ")
|
|
136
|
-
display = (@state == :cancel) ? Colors.strikethrough(Colors.dim(display_text)) : Colors.dim(display_text)
|
|
137
|
-
lines << "#{bar} #{display}\n"
|
|
138
|
-
|
|
139
|
-
lines.join
|
|
140
|
-
end
|
|
129
|
+
def final_display = selected_options.map { |o| o[:label] }.join(", ")
|
|
141
130
|
|
|
142
131
|
private
|
|
143
132
|
|
|
@@ -103,17 +103,8 @@ module Clack
|
|
|
103
103
|
lines.join
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
def
|
|
107
|
-
|
|
108
|
-
lines << "#{bar}\n"
|
|
109
|
-
lines << "#{symbol_for_state} #{@message}\n"
|
|
110
|
-
|
|
111
|
-
labels = @options.select { |o| @selected.include?(o[:value]) }.map { |o| o[:label] }
|
|
112
|
-
display_text = labels.join(", ")
|
|
113
|
-
display = (@state == :cancel) ? Colors.strikethrough(Colors.dim(display_text)) : Colors.dim(display_text)
|
|
114
|
-
lines << "#{bar} #{display}\n"
|
|
115
|
-
|
|
116
|
-
lines.join
|
|
106
|
+
def final_display
|
|
107
|
+
@options.select { |o| @selected.include?(o[:value]) }.map { |o| o[:label] }.join(", ")
|
|
117
108
|
end
|
|
118
109
|
|
|
119
110
|
private
|
|
@@ -51,17 +51,7 @@ module Clack
|
|
|
51
51
|
lines.join
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
def
|
|
55
|
-
lines = []
|
|
56
|
-
lines << "#{bar}\n"
|
|
57
|
-
lines << "#{symbol_for_state} #{@message}\n"
|
|
58
|
-
|
|
59
|
-
masked = @mask * @value.grapheme_clusters.length
|
|
60
|
-
display = (@state == :cancel) ? Colors.strikethrough(Colors.dim(masked)) : Colors.dim(masked)
|
|
61
|
-
lines << "#{bar} #{display}\n"
|
|
62
|
-
|
|
63
|
-
lines.join
|
|
64
|
-
end
|
|
54
|
+
def final_display = @mask * @value.grapheme_clusters.length
|
|
65
55
|
|
|
66
56
|
private
|
|
67
57
|
|
data/lib/clack/prompts/path.rb
CHANGED
|
@@ -124,17 +124,6 @@ module Clack
|
|
|
124
124
|
lines.join
|
|
125
125
|
end
|
|
126
126
|
|
|
127
|
-
def build_final_frame
|
|
128
|
-
lines = []
|
|
129
|
-
lines << "#{bar}\n"
|
|
130
|
-
lines << "#{symbol_for_state} #{@message}\n"
|
|
131
|
-
|
|
132
|
-
display = (@state == :cancel) ? Colors.strikethrough(Colors.dim(@value)) : Colors.dim(@value)
|
|
133
|
-
lines << "#{bar} #{display}\n"
|
|
134
|
-
|
|
135
|
-
lines.join
|
|
136
|
-
end
|
|
137
|
-
|
|
138
127
|
private
|
|
139
128
|
|
|
140
129
|
def update_suggestions
|
data/lib/clack/prompts/range.rb
CHANGED
|
@@ -67,17 +67,7 @@ module Clack
|
|
|
67
67
|
lines.join
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
def
|
|
71
|
-
lines = []
|
|
72
|
-
lines << "#{bar}\n"
|
|
73
|
-
lines << "#{symbol_for_state} #{@message}\n"
|
|
74
|
-
|
|
75
|
-
display = format_value(@value)
|
|
76
|
-
styled = (@state == :cancel) ? Colors.strikethrough(Colors.dim(display)) : Colors.dim(display)
|
|
77
|
-
lines << "#{bar} #{styled}\n"
|
|
78
|
-
|
|
79
|
-
lines.join
|
|
80
|
-
end
|
|
70
|
+
def final_display = format_value(@value)
|
|
81
71
|
|
|
82
72
|
private
|
|
83
73
|
|
data/lib/clack/prompts/select.rb
CHANGED
|
@@ -80,17 +80,7 @@ module Clack
|
|
|
80
80
|
lines.join
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
-
def
|
|
84
|
-
lines = []
|
|
85
|
-
lines << "#{bar}\n"
|
|
86
|
-
lines << "#{symbol_for_state} #{@message}\n"
|
|
87
|
-
|
|
88
|
-
label = current_option[:label]
|
|
89
|
-
display = (@state == :cancel) ? Colors.strikethrough(Colors.dim(label)) : Colors.dim(label)
|
|
90
|
-
lines << "#{bar} #{display}\n"
|
|
91
|
-
|
|
92
|
-
lines.join
|
|
93
|
-
end
|
|
83
|
+
def final_display = current_option[:label]
|
|
94
84
|
|
|
95
85
|
private
|
|
96
86
|
|
|
@@ -63,17 +63,7 @@ module Clack
|
|
|
63
63
|
lines.join
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
-
def
|
|
67
|
-
lines = []
|
|
68
|
-
lines << "#{bar}\n"
|
|
69
|
-
lines << "#{symbol_for_state} #{@message}\n"
|
|
70
|
-
|
|
71
|
-
label = @options.find { |o| o[:value] == @value }&.dig(:label).to_s
|
|
72
|
-
display = (@state == :cancel) ? Colors.strikethrough(Colors.dim(label)) : Colors.dim(label)
|
|
73
|
-
lines << "#{bar} #{display}\n"
|
|
74
|
-
|
|
75
|
-
lines.join
|
|
76
|
-
end
|
|
66
|
+
def final_display = @options.find { |o| o[:value] == @value }&.dig(:label).to_s
|
|
77
67
|
|
|
78
68
|
private
|
|
79
69
|
|
data/lib/clack/prompts/text.rb
CHANGED
|
@@ -104,17 +104,6 @@ module Clack
|
|
|
104
104
|
lines.join
|
|
105
105
|
end
|
|
106
106
|
|
|
107
|
-
def build_final_frame
|
|
108
|
-
lines = []
|
|
109
|
-
lines << "#{bar}\n"
|
|
110
|
-
lines << "#{symbol_for_state} #{@message}\n"
|
|
111
|
-
|
|
112
|
-
display = (@state == :cancel) ? Colors.strikethrough(Colors.dim(@value)) : Colors.dim(@value)
|
|
113
|
-
lines << "#{bar} #{display}\n"
|
|
114
|
-
|
|
115
|
-
lines.join
|
|
116
|
-
end
|
|
117
|
-
|
|
118
107
|
private
|
|
119
108
|
|
|
120
109
|
# Complete the current input using the longest common prefix of matching candidates.
|
data/lib/clack/symbols.rb
CHANGED
|
@@ -26,8 +26,7 @@ module Clack
|
|
|
26
26
|
# Explicit override
|
|
27
27
|
return ENV["CLACK_UNICODE"] == "1" if ENV["CLACK_UNICODE"]
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
$stdout.tty? && ENV["TERM"] != "dumb" && !ENV["NO_COLOR"]
|
|
29
|
+
Environment.colors_supported?
|
|
31
30
|
end
|
|
32
31
|
end
|
|
33
32
|
|
|
@@ -36,7 +35,7 @@ module Clack
|
|
|
36
35
|
# Unicode cancel step indicator, or ASCII fallback.
|
|
37
36
|
S_STEP_CANCEL = unicode? ? "■" : "x"
|
|
38
37
|
# Unicode error step indicator, or ASCII fallback.
|
|
39
|
-
S_STEP_ERROR = unicode? ? "▲" : "
|
|
38
|
+
S_STEP_ERROR = unicode? ? "▲" : "!"
|
|
40
39
|
# Unicode submit step indicator, or ASCII fallback.
|
|
41
40
|
S_STEP_SUBMIT = unicode? ? "◇" : "o"
|
|
42
41
|
|
data/lib/clack/version.rb
CHANGED
data/lib/clack.rb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "clack/version"
|
|
4
|
+
require_relative "clack/environment"
|
|
4
5
|
require_relative "clack/symbols"
|
|
5
6
|
require_relative "clack/colors"
|
|
6
|
-
require_relative "clack/environment"
|
|
7
7
|
require_relative "clack/utils"
|
|
8
8
|
require_relative "clack/core/cursor"
|
|
9
9
|
require_relative "clack/core/settings"
|
|
@@ -508,15 +508,20 @@ module Clack
|
|
|
508
508
|
end
|
|
509
509
|
end
|
|
510
510
|
|
|
511
|
-
# Terminal cleanup on exit
|
|
511
|
+
# Terminal cleanup on exit — show cursor if it was hidden.
|
|
512
|
+
# Uses raw write(2) for async-signal safety in trap handlers.
|
|
513
|
+
CURSOR_SHOW = "\e[?25h"
|
|
514
|
+
|
|
512
515
|
at_exit do
|
|
513
|
-
print
|
|
516
|
+
$stdout.print Clack::Core::Cursor.show
|
|
517
|
+
rescue IOError, SystemCallError
|
|
518
|
+
# Output unavailable
|
|
514
519
|
end
|
|
515
520
|
|
|
516
|
-
# Chain INT handler to restore cursor before passing to previous handler
|
|
521
|
+
# Chain INT handler to restore cursor before passing to previous handler.
|
|
517
522
|
previous_int_handler = trap("INT") do
|
|
518
523
|
begin
|
|
519
|
-
|
|
524
|
+
$stdout.write_nonblock(CURSOR_SHOW)
|
|
520
525
|
rescue IOError, SystemCallError
|
|
521
526
|
# Output unavailable — nothing we can do
|
|
522
527
|
end
|
|
@@ -532,10 +537,10 @@ previous_int_handler = trap("INT") do
|
|
|
532
537
|
end
|
|
533
538
|
end
|
|
534
539
|
|
|
535
|
-
# Handle SIGTERM similarly to INT — restore cursor on graceful kill
|
|
540
|
+
# Handle SIGTERM similarly to INT — restore cursor on graceful kill.
|
|
536
541
|
trap("TERM") do
|
|
537
542
|
begin
|
|
538
|
-
|
|
543
|
+
$stdout.write_nonblock(CURSOR_SHOW)
|
|
539
544
|
rescue IOError, SystemCallError
|
|
540
545
|
# Output unavailable
|
|
541
546
|
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.
|
|
4
|
+
version: 0.4.6
|
|
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:
|
|
106
|
+
rubygems_version: 4.0.8
|
|
107
107
|
specification_version: 4
|
|
108
108
|
summary: Beautiful, minimal CLI prompts
|
|
109
109
|
test_files: []
|