tty-prompt 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -2
  3. data/CHANGELOG.md +12 -0
  4. data/README.md +223 -59
  5. data/lib/tty/prompt/choice.rb +83 -0
  6. data/lib/tty/prompt/choices.rb +92 -0
  7. data/lib/tty/prompt/codes.rb +32 -0
  8. data/lib/tty/prompt/cursor.rb +131 -0
  9. data/lib/tty/prompt/list.rb +209 -0
  10. data/lib/tty/prompt/mode/echo.rb +10 -9
  11. data/lib/tty/prompt/mode/raw.rb +10 -9
  12. data/lib/tty/prompt/multi_list.rb +105 -0
  13. data/lib/tty/prompt/question/validation.rb +12 -27
  14. data/lib/tty/prompt/question.rb +58 -107
  15. data/lib/tty/prompt/reader.rb +44 -11
  16. data/lib/tty/prompt/response.rb +31 -36
  17. data/lib/tty/prompt/response_delegation.rb +3 -2
  18. data/lib/tty/prompt/statement.rb +10 -10
  19. data/lib/tty/prompt/test.rb +15 -0
  20. data/lib/tty/prompt/version.rb +3 -3
  21. data/lib/tty/prompt.rb +72 -9
  22. data/lib/tty-prompt.rb +11 -0
  23. data/spec/unit/ask_spec.rb +32 -35
  24. data/spec/unit/choice/eql_spec.rb +24 -0
  25. data/spec/unit/choice/from_spec.rb +25 -0
  26. data/spec/unit/choices/add_spec.rb +14 -0
  27. data/spec/unit/choices/each_spec.rb +15 -0
  28. data/spec/unit/choices/new_spec.rb +12 -0
  29. data/spec/unit/choices/pluck_spec.rb +11 -0
  30. data/spec/unit/cursor/new_spec.rb +74 -0
  31. data/spec/unit/error_spec.rb +4 -8
  32. data/spec/unit/multi_select_spec.rb +163 -0
  33. data/spec/unit/question/character_spec.rb +5 -16
  34. data/spec/unit/question/default_spec.rb +4 -10
  35. data/spec/unit/question/in_spec.rb +15 -12
  36. data/spec/unit/question/initialize_spec.rb +1 -6
  37. data/spec/unit/question/modify_spec.rb +25 -24
  38. data/spec/unit/question/required_spec.rb +31 -0
  39. data/spec/unit/question/validate_spec.rb +25 -17
  40. data/spec/unit/question/validation/call_spec.rb +22 -0
  41. data/spec/unit/response/read_bool_spec.rb +38 -27
  42. data/spec/unit/response/read_char_spec.rb +5 -8
  43. data/spec/unit/response/read_date_spec.rb +8 -12
  44. data/spec/unit/response/read_email_spec.rb +25 -22
  45. data/spec/unit/response/read_multiple_spec.rb +11 -13
  46. data/spec/unit/response/read_number_spec.rb +12 -16
  47. data/spec/unit/response/read_range_spec.rb +10 -13
  48. data/spec/unit/response/read_spec.rb +39 -38
  49. data/spec/unit/response/read_string_spec.rb +7 -12
  50. data/spec/unit/say_spec.rb +10 -14
  51. data/spec/unit/select_spec.rb +192 -0
  52. data/spec/unit/statement/initialize_spec.rb +0 -4
  53. data/spec/unit/suggest_spec.rb +6 -9
  54. data/spec/unit/warn_spec.rb +4 -8
  55. metadata +32 -8
  56. data/spec/unit/question/argument_spec.rb +0 -30
  57. data/spec/unit/question/valid_spec.rb +0 -46
  58. data/spec/unit/question/validation/valid_value_spec.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 74106ace23d50cc8593146b1b90c3b19ceca9914
4
- data.tar.gz: d1719d051b15c93a321df9192315c8e4633b9e4d
3
+ metadata.gz: 5e24965d09c08a3bf136438bad66551d05f25a0f
4
+ data.tar.gz: 476702a67dd13fe4796c888d089107f4b6f7f18d
5
5
  SHA512:
6
- metadata.gz: 6a5d268782541918e2f59b3e5c260c25fcd015e14004a1233ae69d5163ac8d76ffda6467ad29a2750efe561575639e355593403b426dd6fcbfb0aeda83fa4d77
7
- data.tar.gz: df72ebf11ee221b0d9a49c9c4e8d6398afe161e4db3f48fed012aebf9f3a15dfe11caab3bb46def1837baddf864ff8d2291e522df4bb63ab49532ed1651f0f63
6
+ metadata.gz: 0645bb40ca7b847976e69d0d3c65e4e0a9441f4e3bade6ef1e0d38e7d9ef28e66132645aa30740c7a258939fe262664ed93306968eb76969bee768029d19c406
7
+ data.tar.gz: 70c03c2eb72010d0efe7d8a125c285dc32ec34117e29e2a44b17839c645a8b1650dd14d1184b7b8a871dc92b2c44121ab1e727aa9f5ca41c893184b678171fc8
data/.travis.yml CHANGED
@@ -17,8 +17,6 @@ matrix:
17
17
  allow_failures:
18
18
  - rvm: ruby-head
19
19
  - rvm: jruby-head
20
- - rvm: jruby-20mode
21
- - rvm: jruby-21mode
22
20
  fast_finish: true
23
21
  branches:
24
22
  only: master
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ 0.2.0 (Nov 23, 2015)
2
+
3
+ * Add ability to select choice form list #select
4
+ * Add ability to select multiple options #multi_select
5
+ * Change #ask api to be similar to #select and #multi_select behaviour
6
+ * Change #ask :argument option to be :required
7
+ * Add :read option to #ask for reading specific type input
8
+ * Remove :valid option from #ask as #select is a better solution
9
+
10
+ 0.1.0 (Nov 1, 2015)
11
+
12
+ * Initial implementation and release
data/README.md CHANGED
@@ -17,8 +17,8 @@
17
17
 
18
18
  ## Features
19
19
 
20
+ * Number of prompt types for gathering user input
20
21
  * A robust API for getting and validating complex inputs
21
- * Number of coercion methods for converting response into Ruby types
22
22
 
23
23
  ## Installation
24
24
 
@@ -41,10 +41,12 @@ Or install it yourself as:
41
41
  * [1. Usage](#1-usage)
42
42
  * [2. Interface](#2-interface)
43
43
  * [2.1 ask](#21-ask)
44
- * [2.2 read](#22-read)
45
- * [2.3 say](#23-say)
46
- * [2.4 suggest](#24-suggest)
47
-
44
+ * [2.1.1 settings](#211-settings)
45
+ * [2.1.2 valid read keywords](#212-valid-read-keywords)
46
+ * [2.2 select](#22-select)
47
+ * [2.3 multi_select](#23-multi_select)
48
+ * [2.4 say](#25-say)
49
+ * [2.5 suggest](#26-suggest)
48
50
 
49
51
  ## 1. Usage
50
52
 
@@ -54,101 +56,263 @@ In order to start asking questions on the command line, create prompt:
54
56
  prompt = TTY::Prompt.new
55
57
  ```
56
58
 
57
- and then call `ask` with the question message:
59
+ and then call `ask` with the question for simple input:
58
60
 
59
61
  ```ruby
60
- question = prompt.ask('Do you like Ruby?')
62
+ prompt.ask('Do you like Ruby?', type: :bool) # => true
61
63
  ```
62
64
 
63
- Finally, read and convert answer back to Ruby built-in type:
65
+ Asking question with list of options couldn't be easier using `select` like so:
64
66
 
65
67
  ```ruby
66
- answer = question.read_bool
68
+ prompt.select("Choose your destiny?", %w(Scorpion Kano Jax))
69
+ # =>
70
+ # Choose your destiny? (Use arrow keys, press Enter to select)
71
+ # ‣ Scorpion
72
+ # Kano
73
+ # Jax
74
+ ```
75
+
76
+ Also, asking multiple choice questions is a breeze with `multi_select`:
77
+
78
+ ```ruby
79
+ choices = %w(vodka beer wine whisky bourbon)
80
+ prompt.select("Select drinks?", choices)
81
+ # =>
82
+ #
83
+ # Select drinks? (Use arrow keys, press Space to select and Enter to finish)"
84
+ # ‣ ⬡ vodka
85
+ # ⬡ beer
86
+ # ⬡ wine
87
+ # ⬡ whisky
88
+ # ⬡ bourbon
67
89
  ```
68
90
 
69
91
  ## 2. Interface
70
92
 
71
93
  ### 2.1 ask
72
94
 
73
- In order to ask a basic question and parse an answer do:
95
+ In order to ask a basic question with a string answer do:
74
96
 
75
97
  ```ruby
76
- answer = prompt.ask("What is your name?").read_string
98
+ answer = prompt.ask("What is your name?")
77
99
  ```
78
100
 
79
- The **TTY::Prompt** provides small DSL to help with parsing and asking precise questions
101
+ In order to prompt for more complex input you can use robust API by passing hash of properties or using block:
102
+
103
+ ```ruby
104
+ prompt.ask("What is your name?") do |q|
105
+ q.required true
106
+ q.validate /\A\w+\Z/
107
+ q.modify :capitalize
108
+ end
109
+ ```
110
+
111
+ #### 2.1.1 settings
112
+
113
+ Below is a list of the settings that may be used for customizing `ask` method behaviour:
80
114
 
81
115
  ```ruby
82
- argument # :required or :optional
83
116
  char # turn character based input, otherwise line (default: false)
84
- clean # reset question
85
117
  default # default value used if none is provided
86
118
  echo # turn echo on and off (default: true)
119
+ in # specify range '0-9', '0..9', '0...9' or negative '-1..-9'
87
120
  mask # mask characters i.e '****' (default: false)
88
121
  modify # apply answer modification :upcase, :downcase, :trim, :chomp etc..
89
- in # specify range '0-9', '0..9', '0...9' or negative '-1..-9'
90
- validate # regex against which stdin input is checked
91
- valid # a list of expected valid options
122
+ read # Specifies the type of input such as :bool, :string [see](#211-valid-read-keywords)
123
+ required # If true, value entered must be non-empty (default: false)
124
+ validate # regex, proc against which stdin input is checked
92
125
  ```
93
126
 
94
- You can chain question methods or configure them inside a block:
127
+ Validate setting can take `Regex`, `Proc` like so:
95
128
 
96
129
  ```ruby
97
- prompt.ask("What is your name?").argument(:required).default('Piotr').validate(/\w+\s\w+/).read_string
130
+ prompt.ask('What is your username?') { |q|
131
+ q.validate { |input| input =~ (/^[^\.]+\.[^\.]+/) }
132
+ }
133
+ ```
134
+
135
+ For example, if we wanted to ask a user for a single digit in given range
98
136
 
99
- prompt.ask "What is your name?" do
100
- argument :required
101
- default 'Piotr'
102
- validate /\w+\s\w+/
103
- valid ['Piotr', 'Piotrek']
104
- modify :capitalize
105
- end.read_string
137
+ ```ruby
138
+ ask("Provide number in range: 0-9") { |q| q.in('0-9') }
106
139
  ```
107
140
 
108
- ### 2.2 read
141
+ #### 2.1.2 valid read keywords
109
142
 
110
- To start reading the input from stdin simply call `read` method:
143
+ The most common thing to do is to cast the answer to specific type. The `read` property is used for that. By default `:string` answer is assumed but this can be changed using one of the following custom readers:
111
144
 
112
145
  ```ruby
113
- prompt.read
146
+ :bool # true or false for strings such as "Yes", "No"
147
+ :char # first character
148
+ :date # date type
149
+ :datetime # datetime type
150
+ :email # validate answer against email regex
151
+ :file # a File object
152
+ :float # decimal or error if cannot convert
153
+ :int # integer or error if cannot convert
154
+ :multiline # multiple line string
155
+ :password # string with echo turned off
156
+ :range # range type
157
+ :regex # regex expression
158
+ :string # string
159
+ :symbol # symbol
160
+ :text # multiline string
161
+ :keypress # the key pressed
114
162
  ```
115
163
 
116
- However, there will be cases when your codebase expects answer to be of certain type. **TTY::Prompt** allows reading of answers and converting them into required types with custom readers:
164
+ For example, if you are interested in range type as answer do the following:
117
165
 
118
166
  ```ruby
119
- read_bool # return true or false for strings such as "Yes", "No"
120
- read_char # return first character
121
- read_date # return date type
122
- read_datetime # return datetime type
123
- read_email # validate answer against email regex
124
- read_file # return a File object
125
- read_float # return decimal or error if cannot convert
126
- read_int # return integer or error if cannot convert
127
- read_multiple # return multiple line string
128
- read_password # return string with echo turned off
129
- read_range # return range type
130
- read_regex # return regex expression
131
- read_string # return string
132
- read_symbol # return symbol
133
- read_text # return multiline string
134
- read_keypress # return the key pressed
167
+ ask("Provide range of numbers?", read: :range)
135
168
  ```
136
169
 
137
- For example, if we wanted to ask a user for a single digit in given range
170
+ ### 2.2 select
171
+
172
+ For asking questions involving list of options use `select` method by passing the question and possible choices:
173
+
174
+ ```ruby
175
+ prompt.select("Choose your destiny?", %w(Scorpion Kano Jax))
176
+ # =>
177
+ # Choose your destiny? (Use arrow keys, press Enter to select)
178
+ # ‣ Scorpion
179
+ # Kano
180
+ # Jax
181
+ ```
182
+
183
+ You can also provide options through DSL using the `choice` method for single entry and/or `choices` call for more than one choice:
184
+
185
+ ```ruby
186
+ prompt.select("Choose your destiny?") do |menu|
187
+ menu.choice 'Scorpion'
188
+ menu.choice 'Kano'
189
+ menu.choice 'Jax'
190
+ end
191
+ # =>
192
+ # Choose your destiny? (Use arrow keys, press Enter to select)
193
+ # ‣ Scorpion
194
+ # Kano
195
+ # Jax
196
+ ```
197
+
198
+ By default the choice name is used as return value, but you can provide your custom values:
199
+
200
+ ```ruby
201
+ prompt.select("Choose your destiny?") do |menu|
202
+ menu.choice 'Scorpion', 1
203
+ menu.choice 'Kano', 2
204
+ menu.choice 'Jax', 3
205
+ end
206
+ # =>
207
+ # Choose your destiny? (Use arrow keys, press Enter to select)
208
+ # ‣ Scorpion
209
+ # Kano
210
+ # Jax
211
+ ```
212
+
213
+ If you wish you can also provide a simple hash to denote choice name and its value like so:
138
214
 
139
215
  ```ruby
140
- ask("Provide number in range: 0-9").in('0-9') do
141
- on_error :retry
142
- end.read_int
216
+ choices = {'Scorpion' => 1, 'Kano' => 2, 'Jax' => 3}
217
+ prompt.select("Choose your destiny?", choices)
218
+ ```
219
+
220
+ To mark particular answer as selected use `default` with index of the option starting from `1`:
221
+
222
+ ```ruby
223
+ prompt.select("Choose your destiny?") do |menu|
224
+ menu.default 3
225
+
226
+ menu.choice 'Scorpion', 1
227
+ menu.choice 'Kano', 2
228
+ menu.choice 'Jax', 3
229
+ end
230
+ # =>
231
+ # Choose your destiny? (Use arrow keys, press Enter to select)
232
+ # Scorpion
233
+ # Kano
234
+ # ‣ Jax
235
+ ```
236
+
237
+ You can configure help message, marker like so
238
+
239
+ ```ruby
240
+ choices = %w(Scorpion Kano Jax)
241
+ prompt.select("Choose your destiny?", choices, help: "(Bash keyboard)")
242
+ # =>
243
+ # Choose your destiny? (Bash keyboard)
244
+ # ‣ Scorpion
245
+ # Kano
246
+ # Jax
247
+ ```
248
+
249
+ ### 2.3 multi_select
250
+
251
+ For asking questions involving multiple selection list use `multi_select` method by passing the question and possible choices:
252
+
253
+ ```ruby
254
+ choices = %w(vodka beer wine whisky bourbon)
255
+ prompt.select("Select drinks?", choices)
256
+ # =>
257
+ #
258
+ # Select drinks? (Use arrow keys, press Space to select and Enter to finish)"
259
+ # ‣ ⬡ vodka
260
+ # ⬡ beer
261
+ # ⬡ wine
262
+ # ⬡ whisky
263
+ # ⬡ bourbon
264
+ ```
265
+
266
+ As a return value, the `multi_select` will always return an array by default populated with the names of the choices. If you wish to return custom values for the available choices do:
267
+
268
+ ```ruby
269
+ choices = {vodka: 1, beer: 2, wine: 3, whisky: 4, bourbon: 5}
270
+ prompt.select("Select drinks?", choices)
271
+
272
+ # Provided that vodka and beer have been selected, the function will return
273
+ # => [1, 2]
274
+ ```
275
+
276
+ Similar to `select` method, you can also provide options through DSL using the `choice` method for single entry and/or `choices` call for more than one choice:
277
+
278
+ ```ruby
279
+ prompt.multi_select("Select drinks?") do |menu|
280
+ menu.choice :vodka, {score: 1}
281
+ menu.choice :beer, 2
282
+ menu.choice :wine, 3
283
+ menu.choices whisky: 4, bourbon: 5
284
+ end
285
+ ```
286
+
287
+ To mark choice(s) as selected use the `default` option with index(s) of the option(s) starting from `1`:
288
+
289
+ ```ruby
290
+ prompt.multi_select("Select drinks?") do |menu|
291
+ menu.default 2, 5
292
+
293
+ menu.choice :vodka, {score: 10}
294
+ menu.choice :beer, {score: 20}
295
+ menu.choice :wine, {score: 30}
296
+ menu.choice :whisky, {score: 40}
297
+ menu.choice :bourbon, {score: 50}
298
+ end
299
+ # =>
300
+ # Select drinks? beer, bourbon
301
+ # ⬡ vodka
302
+ # ⬢ beer
303
+ # ⬡ wine
304
+ # ⬡ whisky
305
+ # ‣ ⬢ bourbon
143
306
  ```
144
307
 
145
- on the other hand, if we are interested in range answer then
308
+ And when you press enter you will see the following selected:
146
309
 
147
310
  ```ruby
148
- ask("Provide range of numbers?").read_range
311
+ # Select drinks? beer, bourbon
312
+ # => [{score: 20}, {score: 50}]
149
313
  ```
150
314
 
151
- ### 2.3 say
315
+ ### 2.4 say
152
316
 
153
317
  To simply print message out to stdout use `say` like so:
154
318
 
@@ -164,16 +328,16 @@ prompt.warn # print message(s) in yellow
164
328
  prompt.error # print message(s) in red
165
329
  ```
166
330
 
167
- ### 2.4 suggest
331
+ ### 2.5 suggest
168
332
 
169
333
  To suggest possible matches for the user input use `suggest` method like so:
170
334
 
171
335
  ```ruby
172
336
  prompt.suggest('sta', ['stage', 'stash', 'commit', 'branch'])
173
337
  # =>
174
- Did you mean one of these?
175
- stage
176
- stash
338
+ # Did you mean one of these?
339
+ # stage
340
+ # stash
177
341
  ```
178
342
 
179
343
  To cusomize query text presented pass `:single_text` and `:plural_text` options to respectively change the message when one match is found or many.
@@ -182,8 +346,8 @@ To cusomize query text presented pass `:single_text` and `:plural_text` options
182
346
  possible = %w(status stage stash commit branch blame)
183
347
  prompt.suggest('b', possible, indent: 4, single_text: 'Perhaps you meant?')
184
348
  # =>
185
- Perhaps you meant?
186
- blame
349
+ # Perhaps you meant?
350
+ # blame
187
351
  ```
188
352
 
189
353
  ## Contributing
@@ -0,0 +1,83 @@
1
+ # encoding: utf-8
2
+
3
+ module TTY
4
+ class Prompt
5
+ # A single choice option
6
+ #
7
+ # @api public
8
+ class Choice
9
+ # The label name
10
+ #
11
+ # @api public
12
+ attr_reader :name
13
+
14
+ # Create a Choice instance
15
+ #
16
+ # @api public
17
+ def initialize(name, value)
18
+ @name = name
19
+ @value = value
20
+ end
21
+
22
+ # Create choice from value
23
+ #
24
+ # @example
25
+ # Choice.from(:option_1)
26
+ # Choice.from([:option_1, 1])
27
+ #
28
+ # @param [Object] val
29
+ # the value to be converted
30
+ #
31
+ # @raise [ArgumentError]
32
+ #
33
+ # @return [Choice]
34
+ #
35
+ # @api public
36
+ def self.from(val)
37
+ case val
38
+ when Choice
39
+ return val
40
+ when String, Symbol
41
+ new(val, val)
42
+ when Array
43
+ new("#{val.first}", val.last)
44
+ when Hash
45
+ new("#{val.keys.first}", val.values.first)
46
+ else
47
+ raise ArgumentError, "#{val} cannot be coerced into Choice"
48
+ end
49
+ end
50
+
51
+ # Read value and evaluate
52
+ #
53
+ # @api public
54
+ def value
55
+ case @value
56
+ when Proc
57
+ @value.call
58
+ else
59
+ @value
60
+ end
61
+ end
62
+
63
+ # Object equality comparison
64
+ #
65
+ # @return [Boolean]
66
+ #
67
+ # @api public
68
+ def ==(other)
69
+ return false unless other.is_a?(self.class)
70
+ name == other.name && value == other.value
71
+ end
72
+
73
+ # Object string representation
74
+ #
75
+ # @return [String]
76
+ #
77
+ # @api public
78
+ def to_s
79
+ "#{name}"
80
+ end
81
+ end # Choice
82
+ end # Prompt
83
+ end # TTY
@@ -0,0 +1,92 @@
1
+ # encoding: utf-8
2
+
3
+ require 'forwardable'
4
+
5
+ module TTY
6
+ class Prompt
7
+ # A class responsible for storing a collection of choices
8
+ #
9
+ # @api private
10
+ class Choices
11
+ include Enumerable
12
+ extend Forwardable
13
+
14
+ # The actual collection choices
15
+ #
16
+ # @return [Array[Choice]]
17
+ #
18
+ # @api public
19
+ attr_reader :choices
20
+
21
+ def_delegators :choices, :length, :size, :to_ary, :empty?, :values_at
22
+
23
+ # Convenience for creating choices
24
+ #
25
+ # @param [Array[Object]] choices
26
+ # the choice objects
27
+ #
28
+ # @return [Choices]
29
+ # the choices collection
30
+ #
31
+ # @api public
32
+ def self.[](*choices)
33
+ new(choices)
34
+ end
35
+
36
+ # Create Choices collection
37
+ #
38
+ # @param [Array[Choice]] choices
39
+ # the choices to add to collection
40
+ #
41
+ # @api public
42
+ def initialize(choices = [])
43
+ @choices = choices.map do |choice|
44
+ Choice.from(choice)
45
+ end
46
+ end
47
+
48
+ # Iterate over all choices in the collection
49
+ #
50
+ # @yield [Choice]
51
+ #
52
+ # @api public
53
+ def each(&block)
54
+ return to_enum unless block_given?
55
+ choices.each(&block)
56
+ end
57
+
58
+ # Add choice to collection
59
+ #
60
+ # @param [Object] choice
61
+ # the choice to add
62
+ #
63
+ # @api public
64
+ def <<(choice)
65
+ choices << Choice.from(choice)
66
+ end
67
+
68
+ # Access choice by index
69
+ #
70
+ # @param [Integer] index
71
+ #
72
+ # @return [Choice]
73
+ #
74
+ # @api public
75
+ def [](index)
76
+ @choices[index]
77
+ end
78
+
79
+ # Pluck a choice by its name from collection
80
+ #
81
+ # @param [String] name
82
+ # the label name for the choice
83
+ #
84
+ # @return [Choice]
85
+ #
86
+ # @api public
87
+ def pluck(name)
88
+ find { |choice| choice.name == name }
89
+ end
90
+ end # Choices
91
+ end # Prompt
92
+ end # TTY
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ module TTY
4
+ class Prompt
5
+ module Codes
6
+ BACKSPACE = "\177"
7
+ DELETE = "\004"
8
+ ESCAPE = "\e"
9
+ LINEFEED = "\n"
10
+ RETURN = "\r"
11
+ SPACE = " "
12
+ TAB = "\t"
13
+
14
+ KEY_UP = "\e[A"
15
+ KEY_DOWN = "\e[B"
16
+ KEY_RIGHT = "\e[C"
17
+ KEY_LEFT = "\e[D"
18
+ KEY_DELETE = "\e[3"
19
+
20
+ CTRL_J = "\x0A"
21
+ CTRL_N = "\x0E"
22
+ CTRL_K = "\x0B"
23
+ CTRL_P = "\x10"
24
+ SIGINT = "\x03"
25
+
26
+ ITEM_SECURE = "•"
27
+ ITEM_SELECTED = "‣"
28
+ RADIO_CHECKED = "⬢"
29
+ RADIO_UNCHECKED = "⬡"
30
+ end # Codes
31
+ end # Prompt
32
+ end # TTY