asktty 2.0.0 → 3.0.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/README.md +6 -0
- data/lib/asktty/internal/ansi_style.rb +19 -42
- data/lib/asktty/internal/prompt.rb +106 -0
- data/lib/asktty/internal/rendering.rb +56 -142
- data/lib/asktty/internal/terminal.rb +89 -46
- data/lib/asktty/prompts/confirm_prompt.rb +25 -79
- data/lib/asktty/prompts/input_prompt.rb +86 -13
- data/lib/asktty/prompts/multi_select_prompt.rb +25 -95
- data/lib/asktty/prompts/select_prompt.rb +67 -78
- data/lib/asktty/prompts/text_prompt.rb +5 -12
- data/lib/asktty/version.rb +1 -1
- data/lib/asktty.rb +2 -3
- metadata +2 -4
- data/lib/asktty/internal/options.rb +0 -33
- data/lib/asktty/internal/text_input_prompt.rb +0 -156
- data/lib/asktty/internal/validation.rb +0 -19
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module AskTTY
|
|
4
|
-
module Internal
|
|
5
|
-
class TextInputPrompt
|
|
6
|
-
def initialize(title:, details: nil, placeholder: nil, value: nil, validator: nil, multiline: false)
|
|
7
|
-
@title = title.to_s
|
|
8
|
-
@details = details&.to_s
|
|
9
|
-
@placeholder = placeholder&.to_s
|
|
10
|
-
@value = value.to_s
|
|
11
|
-
@validator = validator
|
|
12
|
-
@multiline = multiline
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def ask
|
|
16
|
-
value = @value.dup
|
|
17
|
-
error_message = nil
|
|
18
|
-
validation_checked = false
|
|
19
|
-
|
|
20
|
-
Terminal.open do |session|
|
|
21
|
-
loop do
|
|
22
|
-
session.render(
|
|
23
|
-
render(
|
|
24
|
-
value,
|
|
25
|
-
width: session.width,
|
|
26
|
-
error_message: error_message
|
|
27
|
-
)
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
key = session.read_key
|
|
31
|
-
|
|
32
|
-
case key
|
|
33
|
-
when :enter
|
|
34
|
-
unless validation_checked
|
|
35
|
-
error_message = validation_message(value)
|
|
36
|
-
validation_checked = true
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
next if error_message
|
|
40
|
-
|
|
41
|
-
session.render(submitted_render(value, width: session.width))
|
|
42
|
-
return value
|
|
43
|
-
when :shift_enter, :ctrl_j
|
|
44
|
-
next unless @multiline
|
|
45
|
-
|
|
46
|
-
value << "\n"
|
|
47
|
-
error_message = validation_message(value)
|
|
48
|
-
validation_checked = true
|
|
49
|
-
when :backspace
|
|
50
|
-
updated_value = Rendering.chop_grapheme(value)
|
|
51
|
-
next if updated_value == value
|
|
52
|
-
|
|
53
|
-
value = updated_value
|
|
54
|
-
error_message = validation_message(value)
|
|
55
|
-
validation_checked = true
|
|
56
|
-
when String
|
|
57
|
-
next unless printable?(key)
|
|
58
|
-
|
|
59
|
-
value << key
|
|
60
|
-
error_message = validation_message(value)
|
|
61
|
-
validation_checked = true
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
private
|
|
68
|
-
|
|
69
|
-
def render(value, width:, error_message: nil)
|
|
70
|
-
Rendering.prompt_frame(
|
|
71
|
-
title: @title, details: @details, help_items: help_items, error_message: error_message, width: width
|
|
72
|
-
) do |content_width|
|
|
73
|
-
body_lines(value, content_width: content_width)
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def submitted_render(value, width:)
|
|
78
|
-
Rendering.submitted_frame(@title, summary_value(value), width: width)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def body_lines(value, content_width:)
|
|
82
|
-
return placeholder_lines(content_width) if @placeholder && value.empty?
|
|
83
|
-
|
|
84
|
-
render_segments(value_lines(value), content_width: content_width, show_cursor: true)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def placeholder_lines(content_width)
|
|
88
|
-
render_segments(
|
|
89
|
-
@placeholder.split("\n", -1),
|
|
90
|
-
content_width: content_width,
|
|
91
|
-
show_cursor: false,
|
|
92
|
-
first_style: method(:placeholder_first_line),
|
|
93
|
-
style: ANSIStyle.method(:muted)
|
|
94
|
-
)
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def value_lines(value)
|
|
98
|
-
return [value] unless @multiline
|
|
99
|
-
|
|
100
|
-
value.split("\n", -1)
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def help_items
|
|
104
|
-
return ["enter (submit)"] unless @multiline
|
|
105
|
-
|
|
106
|
-
["enter (submit)", "shift+enter/ctrl+j (new line)"]
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def placeholder_first_line(text)
|
|
110
|
-
Rendering.placeholder_with_cursor(text)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def printable?(character)
|
|
114
|
-
character.length == 1 && character >= " "
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def render_segments(
|
|
118
|
-
segments, content_width:, show_cursor:, first_style: ANSIStyle.method(:text), style: first_style
|
|
119
|
-
)
|
|
120
|
-
segments = [""] if segments.empty?
|
|
121
|
-
wrap_width = [content_width - 2, 1].max
|
|
122
|
-
last_index = segments.length - 1
|
|
123
|
-
|
|
124
|
-
segments.each_with_index.flat_map do |segment, segment_index|
|
|
125
|
-
wrapped_segments = Rendering.wrap_exact(segment, wrap_width)
|
|
126
|
-
|
|
127
|
-
if show_cursor && segment_index == last_index && Rendering.display_width(wrapped_segments.last) >= wrap_width
|
|
128
|
-
wrapped_segments << ""
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
wrapped_segments.each_with_index.map do |part, wrapped_index|
|
|
132
|
-
prefix = segment_index.zero? && wrapped_index.zero? ? ANSIStyle.prompt("> ") : " "
|
|
133
|
-
current_style = segment_index.zero? && wrapped_index.zero? ? first_style : style
|
|
134
|
-
line = prefix + current_style.call(part)
|
|
135
|
-
|
|
136
|
-
if show_cursor && segment_index == last_index && wrapped_index == wrapped_segments.length - 1
|
|
137
|
-
line << ANSIStyle.cursor
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
line
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
def summary_value(value)
|
|
146
|
-
return value unless @multiline
|
|
147
|
-
|
|
148
|
-
value.tr("\n", " ")
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
def validation_message(value)
|
|
152
|
-
Validation.message_for(value, @validator)
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module AskTTY
|
|
4
|
-
module Internal
|
|
5
|
-
module Validation
|
|
6
|
-
module_function
|
|
7
|
-
|
|
8
|
-
def message_for(value, validator)
|
|
9
|
-
return nil unless validator
|
|
10
|
-
|
|
11
|
-
result = validator.call(value)
|
|
12
|
-
return nil if result == true
|
|
13
|
-
return result if result.is_a?(String) && !result.empty?
|
|
14
|
-
|
|
15
|
-
raise AskTTY::Error, "validator must return true or a non-empty error message"
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|