tty-reader 0.3.0 → 0.8.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 +5 -5
- data/CHANGELOG.md +45 -0
- data/README.md +66 -17
- data/lib/tty-reader.rb +0 -2
- data/lib/tty/reader.rb +38 -28
- data/lib/tty/reader/console.rb +15 -6
- data/lib/tty/reader/history.rb +2 -3
- data/lib/tty/reader/key_event.rb +4 -5
- data/lib/tty/reader/keys.rb +15 -16
- data/lib/tty/reader/line.rb +30 -17
- data/lib/tty/reader/mode.rb +1 -2
- data/lib/tty/reader/version.rb +2 -2
- data/lib/tty/reader/win_api.rb +2 -5
- data/lib/tty/reader/win_console.rb +5 -6
- metadata +32 -63
- data/.gitignore +0 -12
- data/.rspec +0 -3
- data/.travis.yml +0 -26
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -20
- data/Rakefile +0 -10
- data/appveyor.yml +0 -23
- data/benchmarks/speed_read_char.rb +0 -34
- data/benchmarks/speed_read_line.rb +0 -34
- data/bin/console +0 -6
- data/bin/setup +0 -8
- data/examples/keypress.rb +0 -16
- data/examples/line.rb +0 -7
- data/examples/multiline.rb +0 -7
- data/examples/noecho.rb +0 -6
- data/examples/shell.rb +0 -12
- data/tasks/console.rake +0 -11
- data/tasks/coverage.rake +0 -11
- data/tasks/spec.rake +0 -29
- data/tty-reader.gemspec +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7f034dd9a1da1468f59ef2cf8c1ef164c5d85991d7aa0d9760eca05558d09978
|
4
|
+
data.tar.gz: '097df714a88a98b2352e202e69c7da48db124a8f637516449676a8647aee31f3'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 04cf6b1571693791baadf0f686f320393e17a0bd6b1a51aa61c28a34b20e65cb5a6efcca77a3ef21b0c4e2ff422ce3467cea3285b7c477783a5c91f3b1f08bde
|
7
|
+
data.tar.gz: ef5d9d50c2bad451a4cb326547e979a36bca173c0f02df90c202fc702823bd12c2bed8c47d0b47e16ccd6a9d1b644552d1ecea3f605629afaa0b975ac60d0b2b
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,45 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.8.0] - 2020-06-28
|
4
|
+
|
5
|
+
### Changed
|
6
|
+
* Change gemspec to load version directly and remove test artefacts
|
7
|
+
* Change to update tty-screen dependency
|
8
|
+
* Change to remove bundler dev dependency and relax wisper version
|
9
|
+
|
10
|
+
## [v0.7.0] - 2019-11-24
|
11
|
+
|
12
|
+
### Added
|
13
|
+
* Add support for a multi-line prompt by Katelyn Schiesser(@slowbro)
|
14
|
+
* Add metadata to gemspec
|
15
|
+
|
16
|
+
## [v0.6.0] - 2019-05-27
|
17
|
+
|
18
|
+
### Added
|
19
|
+
* Add :value option to #read_line to allow pre-populating of line content
|
20
|
+
|
21
|
+
### Changed
|
22
|
+
* Change to make InputInterrupt to derive from Interrupt by Samuel Williams(@ioquatix)
|
23
|
+
* Change #read_line to trigger before line is printed to allow for line changes in key callbacks
|
24
|
+
* Change Console#get_char :nonblock option to wait for readable input without blocking
|
25
|
+
* Change to remove bundler version constraints
|
26
|
+
* Change to update tty-screen dependency
|
27
|
+
* Change to update tty-cursor dependency
|
28
|
+
|
29
|
+
## [v0.5.0] - 2018-11-24
|
30
|
+
|
31
|
+
### Added
|
32
|
+
* Add KeyEvent#line to expose current line in key event callbacks
|
33
|
+
|
34
|
+
### Fixed
|
35
|
+
* Fix Esc key by differentiating between escaped keys and actual escape input
|
36
|
+
* Fix line editing to correctly insert next to last character
|
37
|
+
|
38
|
+
## [v0.4.0] - 2018-08-05
|
39
|
+
|
40
|
+
### Changed
|
41
|
+
* Change to update tty-screen & tty-cursor dependencies
|
42
|
+
|
3
43
|
## [v0.3.0] - 2018-04-29
|
4
44
|
|
5
45
|
### Added
|
@@ -33,6 +73,11 @@
|
|
33
73
|
|
34
74
|
* Initial implementation and release
|
35
75
|
|
76
|
+
[v0.8.0]: https://github.com/piotrmurach/tty-reader/compare/v0.7.0...v0.8.0
|
77
|
+
[v0.7.0]: https://github.com/piotrmurach/tty-reader/compare/v0.6.0...v0.7.0
|
78
|
+
[v0.6.0]: https://github.com/piotrmurach/tty-reader/compare/v0.5.0...v0.6.0
|
79
|
+
[v0.5.0]: https://github.com/piotrmurach/tty-reader/compare/v0.4.0...v0.5.0
|
80
|
+
[v0.4.0]: https://github.com/piotrmurach/tty-reader/compare/v0.3.0...v0.4.0
|
36
81
|
[v0.3.0]: https://github.com/piotrmurach/tty-reader/compare/v0.2.0...v0.3.0
|
37
82
|
[v0.2.0]: https://github.com/piotrmurach/tty-reader/compare/v0.1.0...v0.2.0
|
38
83
|
[v0.1.0]: https://github.com/piotrmurach/tty-reader/compare/v0.1.0
|
data/README.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
<div align="center">
|
2
|
+
<a href="https://piotrmurach.github.io/tty" target="_blank"><img width="130" src="https://cdn.rawgit.com/piotrmurach/tty/master/images/tty.png" alt="tty logo" /></a>
|
3
|
+
</div>
|
4
|
+
|
1
5
|
# TTY::Reader [][gitter]
|
2
6
|
|
3
7
|
[][gem]
|
@@ -15,10 +19,12 @@
|
|
15
19
|
[coverage]: https://coveralls.io/github/piotrmurach/tty-reader
|
16
20
|
[inchpages]: http://inch-ci.org/github/piotrmurach/tty-reader
|
17
21
|
|
18
|
-
> A pure Ruby library that provides a set of methods for processing keyboard input in character, line and multiline modes.
|
22
|
+
> A pure Ruby library that provides a set of methods for processing keyboard input in character, line and multiline modes. It maintains history of entered input with an ability to recall and re-edit those inputs. It lets you register to listen for keystroke events and trigger custom key events yourself.
|
19
23
|
|
20
24
|
**TTY::Reader** provides independent reader component for [TTY](https://github.com/piotrmurach/tty) toolkit.
|
21
25
|
|
26
|
+

|
27
|
+
|
22
28
|
## Compatibility
|
23
29
|
|
24
30
|
The `tty-reader` is not compatible with the GNU Readline and doesn't aim to be. It originated from [tty-prompt](https://github.com/piotrmurach/tty-prompt) project to provide flexibility, independence from underlying operating system and Ruby like API interface for creating different prompts.
|
@@ -28,11 +34,11 @@ The `tty-reader` is not compatible with the GNU Readline and doesn't aim to be.
|
|
28
34
|
## Features
|
29
35
|
|
30
36
|
* Pure Ruby
|
31
|
-
*
|
32
|
-
*
|
33
|
-
* Reading multiline input
|
34
|
-
*
|
35
|
-
*
|
37
|
+
* Reading [single keypress](#21-read_keypress)
|
38
|
+
* [Line editing](#22-read_line)
|
39
|
+
* Reading [multiline input](#23-read_multiline)
|
40
|
+
* Ability to [register](#24-on) for keystroke events
|
41
|
+
* Track input [history](#32-track_history)
|
36
42
|
* No global state
|
37
43
|
* Works on Linux, OS X, FreeBSD and Windows
|
38
44
|
* Supports Ruby versions `>= 2.0.0` & JRuby
|
@@ -72,10 +78,31 @@ Or install it yourself as:
|
|
72
78
|
|
73
79
|
## Usage
|
74
80
|
|
81
|
+
In just a few lines you can recreate IRB prompt.
|
82
|
+
|
83
|
+
Initialize the reader:
|
84
|
+
|
75
85
|
```ruby
|
76
86
|
reader = TTY::Reader.new
|
77
87
|
```
|
78
88
|
|
89
|
+
Then register to listen for key events, in this case listen for `Ctrl-X` or `Esc` keys to exit:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
reader.on(:keyctrl_x, :keyescape) do
|
93
|
+
puts "Exiting..."
|
94
|
+
exit
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
Finally, keep asking user for line input with a `=>` as a prompt:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
loop do
|
102
|
+
reader.read_line('=> ')
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
79
106
|
## API
|
80
107
|
|
81
108
|
### 2.1 read_keypress
|
@@ -85,6 +112,7 @@ To read a single key stroke from the user use `read_char` or `read_keypress`:
|
|
85
112
|
```ruby
|
86
113
|
reader.read_char
|
87
114
|
reader.read_keypress
|
115
|
+
reader.read_keypress(nonblock: true)
|
88
116
|
```
|
89
117
|
|
90
118
|
### 2.2 read_line
|
@@ -109,11 +137,18 @@ Any non-interpreted characters received are written back to terminal, however yo
|
|
109
137
|
reader.read_line(echo: false)
|
110
138
|
```
|
111
139
|
|
112
|
-
You can also provide a line prefix displayed before input by passing it as a first
|
140
|
+
You can also provide a line prefix displayed before input by passing it as a first argument:
|
113
141
|
|
114
142
|
```ruby
|
115
143
|
reader.read_line(">> ")
|
116
|
-
# >>
|
144
|
+
# >>
|
145
|
+
```
|
146
|
+
|
147
|
+
To pre-populate the line content for editing use `:value` option:
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
reader.read_line("> ", value: "edit me")
|
151
|
+
# > edit me
|
117
152
|
```
|
118
153
|
|
119
154
|
### 2.3 read_multiline
|
@@ -133,7 +168,7 @@ If you wish for the keystrokes to be interpreted by the terminal instead, use so
|
|
133
168
|
reader.read_line(raw: false)
|
134
169
|
```
|
135
170
|
|
136
|
-
You can also provide a
|
171
|
+
You can also provide a line prefix displayed before input by passing a string as a first argument:
|
137
172
|
|
138
173
|
```ruby
|
139
174
|
reader.read_multiline(">> ")
|
@@ -141,13 +176,27 @@ reader.read_multiline(">> ")
|
|
141
176
|
|
142
177
|
### 2.4 on
|
143
178
|
|
144
|
-
You can register to listen on a key pressed events. This can be done by calling `on` with a event name:
|
179
|
+
You can register to listen on a key pressed events. This can be done by calling `on` with a event name(s):
|
145
180
|
|
146
181
|
```ruby
|
147
182
|
reader.on(:keypress) { |event| .... }
|
148
183
|
```
|
149
184
|
|
150
|
-
|
185
|
+
or listen for multiple events:
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
reader.on(:keyctrl_x, :keyescape) { |event| ... }
|
189
|
+
```
|
190
|
+
|
191
|
+
The `KeyEvent` object is yielded to a block whenever a particular key event fires. The event responds to:
|
192
|
+
|
193
|
+
* `key` - key pressed
|
194
|
+
* `value` - value of the key pressed
|
195
|
+
* `line` - the content of the currently edited line, empty otherwise
|
196
|
+
|
197
|
+
The `value` returns the actual key pressed and the `line` the content for the currently edited line or is empty.
|
198
|
+
|
199
|
+
The `key` is an object that responds to following messages:
|
151
200
|
|
152
201
|
* `name` - the name of the event such as :up, :down, letter or digit
|
153
202
|
* `meta` - true if event is non-standard key associated
|
@@ -189,13 +238,13 @@ class MyListener
|
|
189
238
|
end
|
190
239
|
```
|
191
240
|
|
192
|
-
Then
|
241
|
+
Then subscribing is done:
|
193
242
|
|
194
243
|
```ruby
|
195
244
|
reader.subscribe(MyListener.new)
|
196
245
|
```
|
197
246
|
|
198
|
-
Alternatively, `subscribe` allows you to listen to events only for the
|
247
|
+
Alternatively, `subscribe` allows you to listen to events only for the duration of block execution like so:
|
199
248
|
|
200
249
|
```ruby
|
201
250
|
reader.subscribe(MyListener) do
|
@@ -249,7 +298,7 @@ The available key events for character input are:
|
|
249
298
|
* `:keyalpha`
|
250
299
|
* `:keynum`
|
251
300
|
|
252
|
-
The navigation
|
301
|
+
The navigation related key events are:
|
253
302
|
|
254
303
|
* `:keydown`
|
255
304
|
* `:keyup`
|
@@ -292,7 +341,7 @@ reader = TTY::Reader.new(interrupt: :signal)
|
|
292
341
|
|
293
342
|
### 3.2. `:track_history`
|
294
343
|
|
295
|
-
The `read_line` and `read_multiline` provide history buffer that tracks all the lines entered during `TTY::Reader.new` interactions. The history buffer provides
|
344
|
+
The `read_line` and `read_multiline` provide history buffer that tracks all the lines entered during `TTY::Reader.new` interactions. The history buffer provides previous or next lines when user presses up/down arrows respectively. However, if you wish to disable this behaviour use `:track_history` option like so:
|
296
345
|
|
297
346
|
```ruby
|
298
347
|
reader = TTY::Reader.new(track_history: false)
|
@@ -316,7 +365,7 @@ reader = TTY::Reader.new(history_duplicates: false)
|
|
316
365
|
|
317
366
|
### 3.5. `:history_exclude`
|
318
367
|
|
319
|
-
This option allows you to exclude lines from being stored in history. It accepts a `Proc` with a line as a first argument. By default it is set to
|
368
|
+
This option allows you to exclude lines from being stored in history. It accepts a `Proc` with a line as a first argument. By default it is set to exclude empty lines. To change this:
|
320
369
|
|
321
370
|
```ruby
|
322
371
|
reader = TTY::Reader.new(history_exclude: ->(line) { ... })
|
@@ -349,4 +398,4 @@ Everyone interacting in the TTY::Reader project’s codebases, issue trackers, c
|
|
349
398
|
|
350
399
|
## Copyright
|
351
400
|
|
352
|
-
Copyright (c) 2017
|
401
|
+
Copyright (c) 2017 Piotr Murach. See LICENSE for further details.
|
data/lib/tty-reader.rb
CHANGED
data/lib/tty/reader.rb
CHANGED
@@ -1,16 +1,15 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
3
|
+
require "tty-cursor"
|
4
|
+
require "tty-screen"
|
5
|
+
require "wisper"
|
7
6
|
|
8
|
-
require_relative
|
9
|
-
require_relative
|
10
|
-
require_relative
|
11
|
-
require_relative
|
12
|
-
require_relative
|
13
|
-
require_relative
|
7
|
+
require_relative "reader/history"
|
8
|
+
require_relative "reader/line"
|
9
|
+
require_relative "reader/key_event"
|
10
|
+
require_relative "reader/console"
|
11
|
+
require_relative "reader/win_console"
|
12
|
+
require_relative "reader/version"
|
14
13
|
|
15
14
|
module TTY
|
16
15
|
# A class responsible for reading character input from STDIN
|
@@ -24,7 +23,7 @@ module TTY
|
|
24
23
|
# Raised when the user hits the interrupt key(Control-C)
|
25
24
|
#
|
26
25
|
# @api public
|
27
|
-
InputInterrupt = Class.new(
|
26
|
+
InputInterrupt = Class.new(Interrupt)
|
28
27
|
|
29
28
|
# Check if Windowz mode
|
30
29
|
#
|
@@ -32,7 +31,7 @@ module TTY
|
|
32
31
|
#
|
33
32
|
# @api public
|
34
33
|
def self.windows?
|
35
|
-
::File::ALT_SEPARATOR ==
|
34
|
+
::File::ALT_SEPARATOR == "\\"
|
36
35
|
end
|
37
36
|
|
38
37
|
attr_reader :input
|
@@ -75,7 +74,7 @@ module TTY
|
|
75
74
|
|
76
75
|
@track_history = options.fetch(:track_history) { true }
|
77
76
|
@history_cycle = options.fetch(:history_cycle) { false }
|
78
|
-
exclude_proc = ->(line) { line.strip ==
|
77
|
+
exclude_proc = ->(line) { line.strip == "" }
|
79
78
|
@history_exclude = options.fetch(:history_exclude) { exclude_proc }
|
80
79
|
@history_duplicates = options.fetch(:history_duplicates) { false }
|
81
80
|
|
@@ -132,7 +131,7 @@ module TTY
|
|
132
131
|
#
|
133
132
|
# @api private
|
134
133
|
def select_console(input)
|
135
|
-
if self.class.windows? && !env[
|
134
|
+
if self.class.windows? && !env["TTY_TEST"]
|
136
135
|
WinConsole.new(input)
|
137
136
|
else
|
138
137
|
Console.new(input)
|
@@ -173,7 +172,7 @@ module TTY
|
|
173
172
|
def read_keypress(options = {})
|
174
173
|
opts = { echo: false, raw: true }.merge(options)
|
175
174
|
codes = unbufferred { get_codes(opts) }
|
176
|
-
char = codes ? codes.pack(
|
175
|
+
char = codes ? codes.pack("U*") : nil
|
177
176
|
|
178
177
|
trigger_key_event(char) if char
|
179
178
|
char
|
@@ -202,8 +201,10 @@ module TTY
|
|
202
201
|
}
|
203
202
|
|
204
203
|
while console.escape_codes.any?(&condition)
|
205
|
-
get_codes(options, codes)
|
204
|
+
char_codes = get_codes(options.merge(nonblock: true), codes)
|
205
|
+
break if char_codes.nil?
|
206
206
|
end
|
207
|
+
|
207
208
|
codes
|
208
209
|
end
|
209
210
|
|
@@ -214,24 +215,30 @@ module TTY
|
|
214
215
|
# @param [String] prompt
|
215
216
|
# the prompt to display before input
|
216
217
|
#
|
218
|
+
# @param [String] value
|
219
|
+
# the value to pre-populate line with
|
220
|
+
#
|
217
221
|
# @param [Boolean] echo
|
218
222
|
# if true echo back characters, output nothing otherwise
|
219
223
|
#
|
220
224
|
# @return [String]
|
221
225
|
#
|
222
226
|
# @api public
|
223
|
-
def read_line(prompt =
|
227
|
+
def read_line(prompt = "", **options)
|
224
228
|
opts = { echo: true, raw: true }.merge(options)
|
225
|
-
|
229
|
+
value = options.fetch(:value, "")
|
230
|
+
line = Line.new(value, prompt: prompt)
|
226
231
|
screen_width = TTY::Screen.width
|
227
232
|
|
228
|
-
output.print(line
|
233
|
+
output.print(line)
|
229
234
|
|
230
235
|
while (codes = get_codes(opts)) && (code = codes[0])
|
231
|
-
char = codes.pack(
|
232
|
-
trigger_key_event(char)
|
236
|
+
char = codes.pack("U*")
|
233
237
|
|
234
|
-
|
238
|
+
if [:ctrl_d, :ctrl_z].include?(console.keys[char])
|
239
|
+
trigger_key_event(char, line: line.to_s)
|
240
|
+
break
|
241
|
+
end
|
235
242
|
|
236
243
|
if opts[:raw] && opts[:echo]
|
237
244
|
clear_display(line, screen_width)
|
@@ -249,7 +256,7 @@ module TTY
|
|
249
256
|
elsif console.keys[char] == :up
|
250
257
|
line.replace(history_previous) if history_previous?
|
251
258
|
elsif console.keys[char] == :down
|
252
|
-
line.replace(history_next? ? history_next :
|
259
|
+
line.replace(history_next? ? history_next : "")
|
253
260
|
elsif console.keys[char] == :left
|
254
261
|
line.left
|
255
262
|
elsif console.keys[char] == :right
|
@@ -270,10 +277,13 @@ module TTY
|
|
270
277
|
if opts[:raw]
|
271
278
|
output.print("\e[1X") unless line.start?
|
272
279
|
else
|
273
|
-
output.print(?\s + (line.start? ?
|
280
|
+
output.print(?\s + (line.start? ? "" : ?\b))
|
274
281
|
end
|
275
282
|
end
|
276
283
|
|
284
|
+
# trigger before line is printed to allow for line changes
|
285
|
+
trigger_key_event(char, line: line.to_s)
|
286
|
+
|
277
287
|
if opts[:raw] && opts[:echo]
|
278
288
|
output.print(line.to_s)
|
279
289
|
if char == "\n"
|
@@ -352,7 +362,7 @@ module TTY
|
|
352
362
|
lines = []
|
353
363
|
loop do
|
354
364
|
line = read_line(*args)
|
355
|
-
break if !line || line ==
|
365
|
+
break if !line || line == ""
|
356
366
|
next if line !~ /\S/ && !@stop
|
357
367
|
if block_given?
|
358
368
|
yield(line) unless line.to_s.empty?
|
@@ -421,8 +431,8 @@ module TTY
|
|
421
431
|
# @return [nil]
|
422
432
|
#
|
423
433
|
# @api private
|
424
|
-
def trigger_key_event(char)
|
425
|
-
event = KeyEvent.from(console.keys, char)
|
434
|
+
def trigger_key_event(char, line: "")
|
435
|
+
event = KeyEvent.from(console.keys, char, line)
|
426
436
|
trigger(:"key#{event.key.name}", event) if event.trigger?
|
427
437
|
trigger(:keypress, event)
|
428
438
|
end
|
@@ -433,7 +443,7 @@ module TTY
|
|
433
443
|
def handle_interrupt
|
434
444
|
case @interrupt
|
435
445
|
when :signal
|
436
|
-
Process.kill(
|
446
|
+
Process.kill("SIGINT", Process.pid)
|
437
447
|
when :exit
|
438
448
|
exit(130)
|
439
449
|
when Proc
|
data/lib/tty/reader/console.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
5
|
-
|
3
|
+
require "io/wait"
|
4
|
+
|
5
|
+
require_relative "keys"
|
6
|
+
require_relative "mode"
|
6
7
|
|
7
8
|
module TTY
|
8
9
|
class Reader
|
9
10
|
class Console
|
10
|
-
ESC = "\e"
|
11
|
-
CSI = "\e["
|
11
|
+
ESC = "\e"
|
12
|
+
CSI = "\e["
|
13
|
+
|
14
|
+
TIMEOUT = 0.1
|
12
15
|
|
13
16
|
# Key codes
|
14
17
|
#
|
@@ -42,7 +45,13 @@ module TTY
|
|
42
45
|
# @api private
|
43
46
|
def get_char(options)
|
44
47
|
mode.raw(options[:raw]) do
|
45
|
-
mode.echo(options[:echo])
|
48
|
+
mode.echo(options[:echo]) do
|
49
|
+
if options[:nonblock]
|
50
|
+
input.wait_readable(TIMEOUT) ? input.getc : nil
|
51
|
+
else
|
52
|
+
input.getc
|
53
|
+
end
|
54
|
+
end
|
46
55
|
end
|
47
56
|
end
|
48
57
|
|