tty-prompt 0.1.0 → 0.2.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.
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