tty-reader 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.
- checksums.yaml +4 -4
- data/.travis.yml +5 -5
- data/CHANGELOG.md +22 -1
- data/Gemfile +4 -5
- data/README.md +176 -27
- data/appveyor.yml +0 -4
- data/benchmarks/speed_read_char.rb +34 -0
- data/benchmarks/speed_read_line.rb +34 -0
- data/examples/keypress.rb +16 -0
- data/examples/line.rb +7 -0
- data/examples/multiline.rb +7 -0
- data/examples/noecho.rb +6 -0
- data/examples/shell.rb +12 -0
- data/lib/tty/reader.rb +121 -58
- data/lib/tty/reader/console.rb +2 -2
- data/lib/tty/reader/history.rb +6 -2
- data/lib/tty/reader/key_event.rb +4 -35
- data/lib/tty/reader/keys.rb +165 -0
- data/lib/tty/reader/line.rb +96 -9
- data/lib/tty/reader/version.rb +1 -1
- data/lib/tty/reader/win_console.rb +2 -2
- data/tty-reader.gemspec +7 -3
- metadata +46 -12
- data/lib/tty/reader/codes.rb +0 -120
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1b83301002055869c17bb4ecb0571be89b2d8e0
|
4
|
+
data.tar.gz: 39bd25b1b47c2542c000a407a2839bd4cba12c31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 08c4198829dcc5a4f95c865c4dfcb2c4be9711885a3d071c6f1d9f917e8dc20083d558dde98ffc38af0d7e6ce6de9f4fbfeecb1158109f2905adb047aa6970f1
|
7
|
+
data.tar.gz: 3899ba4f5461099024379df0058deb177dbf1a45d6fb250970f3a639adf792f9563773adeae1b240f2feb41241d6ec45b4a012c15f4b1c234ad6bf582f7c0ac4
|
data/.travis.yml
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
language: ruby
|
3
3
|
sudo: false
|
4
4
|
cache: bundler
|
5
|
+
before_install: "gem update bundler"
|
5
6
|
bundler_args: --without tools
|
6
7
|
script: "bundle exec rake ci"
|
7
8
|
rvm:
|
8
|
-
- 1.9.3
|
9
9
|
- 2.0.0
|
10
10
|
- 2.1.10
|
11
|
-
- 2.2.
|
12
|
-
- 2.3.
|
13
|
-
- 2.4.
|
11
|
+
- 2.2.9
|
12
|
+
- 2.3.6
|
13
|
+
- 2.4.3
|
14
14
|
- ruby-head
|
15
|
-
- jruby-
|
15
|
+
- jruby-9.1.1.0
|
16
16
|
- jruby-head
|
17
17
|
matrix:
|
18
18
|
allow_failures:
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,28 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.2.0] - 2018-01-01
|
4
|
+
|
5
|
+
### Added
|
6
|
+
* Add home & end keys support in #read_line
|
7
|
+
* Add tty-screen & tty-cursor dependencies
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
* Change Codes to Keys and inverse keys lookup to allow for different system keys matching same name.
|
11
|
+
* Change Reader#initialize to only accept options and make input and output options as well.
|
12
|
+
* Change #read_line to print newline character in noecho mode
|
13
|
+
* Change Reader::Line to include prompt prefix
|
14
|
+
* Change Reader#initialize to only accept options in place of positional arguments
|
15
|
+
* Change Reader to expose history options
|
16
|
+
|
17
|
+
### Fixed
|
18
|
+
* Fix issues with recognising :home & :end keys on different terminals
|
19
|
+
* Fix #read_line to work with strings spanning multiple screen widths and allow copy-pasting a long string without repeating prompt
|
20
|
+
* Fix backspace keystroke in cooked mode
|
21
|
+
* Fix history to only save lines in echo mode
|
22
|
+
|
3
23
|
## [v0.1.0] - 2017-08-30
|
4
24
|
|
5
25
|
* Initial implementation and release
|
6
26
|
|
7
|
-
[v0.
|
27
|
+
[v0.2.0]: https://github.com/piotrmurach/tty-reader/compare/v0.1.0...v0.2.0
|
28
|
+
[v0.1.0]: https://github.com/piotrmurach/tty-reader/compare/v0.1.0
|
data/Gemfile
CHANGED
@@ -5,10 +5,9 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
|
5
5
|
gemspec
|
6
6
|
|
7
7
|
group :test do
|
8
|
-
gem 'benchmark-ips', '~> 2.
|
9
|
-
gem 'simplecov', '~> 0.
|
10
|
-
gem 'coveralls', '~> 0.8.
|
11
|
-
gem 'term-ansicolor', '=1.3.2'
|
8
|
+
gem 'benchmark-ips', '~> 2.7.2'
|
9
|
+
gem 'simplecov', '~> 0.14.1'
|
10
|
+
gem 'coveralls', '~> 0.8.21'
|
12
11
|
end
|
13
12
|
|
14
13
|
group :tools do
|
@@ -16,6 +15,6 @@ group :tools do
|
|
16
15
|
end
|
17
16
|
|
18
17
|
group :metrics do
|
19
|
-
gem 'yard', '~> 0.
|
18
|
+
gem 'yard', '~> 0.9.12'
|
20
19
|
gem 'yardstick', '~> 0.9.9'
|
21
20
|
end
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
[][gem]
|
4
4
|
[][travis]
|
5
5
|
[][appveyor]
|
6
|
-
[][codeclimate]
|
7
7
|
[][coverage]
|
8
8
|
[][inchpages]
|
9
9
|
|
@@ -11,7 +11,7 @@
|
|
11
11
|
[gem]: http://badge.fury.io/rb/tty-reader
|
12
12
|
[travis]: http://travis-ci.org/piotrmurach/tty-reader
|
13
13
|
[appveyor]: https://ci.appveyor.com/project/piotrmurach/tty-reader
|
14
|
-
[codeclimate]: https://codeclimate.com/github/piotrmurach/tty-reader
|
14
|
+
[codeclimate]: https://codeclimate.com/github/piotrmurach/tty-reader/maintainability
|
15
15
|
[coverage]: https://coveralls.io/github/piotrmurach/tty-reader
|
16
16
|
[inchpages]: http://inch-ci.org/github/piotrmurach/tty-reader
|
17
17
|
|
@@ -19,13 +19,23 @@
|
|
19
19
|
|
20
20
|
**TTY::Reader** provides independent reader component for [TTY](https://github.com/piotrmurach/tty) toolkit.
|
21
21
|
|
22
|
+
## Compatibility
|
23
|
+
|
24
|
+
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.
|
25
|
+
|
26
|
+
`TTY::Reader` forges its own path to provide features necessary for building line editing in terminal applications!
|
27
|
+
|
22
28
|
## Features
|
23
29
|
|
24
|
-
*
|
30
|
+
* Pure Ruby
|
25
31
|
* Line editing
|
26
|
-
*
|
32
|
+
* Reading single keypress
|
33
|
+
* Reading multiline input
|
27
34
|
* History management
|
28
|
-
* Ability to register for
|
35
|
+
* Ability to register for keystroke events
|
36
|
+
* No global state
|
37
|
+
* Works on Linux, OS X, FreeBSD and Windows
|
38
|
+
* Supports Ruby versions `>= 2.0.0` & JRuby
|
29
39
|
|
30
40
|
## Installation
|
31
41
|
|
@@ -48,10 +58,16 @@ Or install it yourself as:
|
|
48
58
|
* [2.1 read_keypress](#21-read_keypress)
|
49
59
|
* [2.2 read_line](#22-read_line)
|
50
60
|
* [2.3 read_multiline](#23-read_multiline)
|
51
|
-
* [2.4
|
61
|
+
* [2.4 on](#24-on)
|
62
|
+
* [2.5 subscribe](#25-subscribe)
|
63
|
+
* [2.6 trigger](#26-trigger)
|
64
|
+
* [2.7 supported events](#27-supported-events)
|
52
65
|
* [3. Configuration](#3-configuration)
|
53
66
|
* [3.1 :interrupt](#31-interrupt)
|
54
|
-
* [3.2 :track_history](#
|
67
|
+
* [3.2 :track_history](#32-track_history)
|
68
|
+
* [3.3 :history_cycle](#33-history_cycle)
|
69
|
+
* [3.4 :history_duplicates](#34-history_duplicates)
|
70
|
+
* [3.5 :history_exclude](#35-history_exclude)
|
55
71
|
|
56
72
|
## Usage
|
57
73
|
|
@@ -70,24 +86,59 @@ reader.read_char
|
|
70
86
|
reader.read_keypress
|
71
87
|
```
|
72
88
|
|
73
|
-
|
89
|
+
### 2.2 read_line
|
90
|
+
|
91
|
+
By default `read_line` works in `raw mode` which means it behaves like a line editor that allows you to edit each character, respond to `control characters` such as `Control-A` to `Control-B` or navigate through history.
|
74
92
|
|
75
|
-
|
93
|
+
For example, to read a single line terminated by a new line character use `read_line` like so:
|
76
94
|
|
77
95
|
```ruby
|
78
96
|
reader.read_line
|
79
97
|
```
|
80
98
|
|
81
|
-
|
99
|
+
If you wish for the keystrokes to be interpreted by the terminal instead, use so called `cooked` mode by providing the `:raw` option set to `false`:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
reader.read_line(raw: false)
|
103
|
+
```
|
104
|
+
|
105
|
+
Any non-interpreted characters received are written back to terminal, however you can stop this by using `:echo` option set to `false`:
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
reader.read_line(echo: false)
|
109
|
+
```
|
110
|
+
|
111
|
+
You can also provide a line prefix displayed before input by passing it as a first aargument:
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
reader.read_line(">> ")
|
115
|
+
# >> input goes here ...
|
116
|
+
```
|
117
|
+
|
118
|
+
### 2.3 read_multiline
|
82
119
|
|
83
|
-
|
120
|
+
By default `read_multiline` works in `raw mode` which means it behaves like a multiline editor that allows you to edit each character, respond to `control characters` such as `Control-A` to `Control-B` or navigate through history.
|
121
|
+
|
122
|
+
For example, to read more than one line terminated by `Ctrl+d` or `Ctrl+z` use `read_multiline`:
|
84
123
|
|
85
124
|
```ruby
|
86
125
|
reader.read_multiline
|
87
126
|
# => [ "line1", "line2", ... ]
|
88
127
|
```
|
89
128
|
|
90
|
-
|
129
|
+
If you wish for the keystrokes to be interpreted by the terminal instead, use so called `cooked` mode by providing the `:raw` option set to `false`:
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
reader.read_line(raw: false)
|
133
|
+
```
|
134
|
+
|
135
|
+
You can also provide a linke prefix displayed before input by passing a string as a first argument:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
reader.read_multiline(">> ")
|
139
|
+
```
|
140
|
+
|
141
|
+
### 2.4 on
|
91
142
|
|
92
143
|
You can register to listen on a key pressed events. This can be done by calling `on` with a event name:
|
93
144
|
|
@@ -123,25 +174,92 @@ prompt.on(:keypress) { |key| ... }
|
|
123
174
|
.on(:keydown) { |key| ... }
|
124
175
|
```
|
125
176
|
|
126
|
-
|
177
|
+
### 2.5 subscribe
|
178
|
+
|
179
|
+
You can subscribe any object to listen for the emitted [key events](#27-supported-events) using the `subscribe` message. The listener would need to implement a method for every event it wishes to receive.
|
180
|
+
|
181
|
+
For example, if a `Context` class wishes to only listen for `keypress` event:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
class Context
|
185
|
+
def keypress(event)
|
186
|
+
...
|
187
|
+
end
|
188
|
+
end
|
189
|
+
```
|
190
|
+
|
191
|
+
Then subcribing is done:
|
192
|
+
|
193
|
+
```ruby
|
194
|
+
context = Context.new
|
195
|
+
reader.subscribe(context)
|
196
|
+
```
|
197
|
+
|
198
|
+
### 2.6 trigger
|
199
|
+
|
200
|
+
The signature for triggering key events is `trigger(event, args...)`. The first argument is a [key event name](#27-supported-events) followed by any number of actual values related to the event being triggered.
|
201
|
+
|
202
|
+
For example, to trigger `:keydown` event do:
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
reader.trigger(:keydown)
|
206
|
+
```
|
207
|
+
|
208
|
+
To add vim bindings for line editing you could discern between alphanumeric inputs like so:
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
reader.on(:keypress) do |event|
|
212
|
+
if event.value == 'j'
|
213
|
+
reader.trigger(:keydown)
|
214
|
+
end
|
215
|
+
if evevnt.value == 'k'
|
216
|
+
reader.trigger(:keup)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
```
|
220
|
+
|
221
|
+
### 2.7 supported events
|
222
|
+
|
223
|
+
The available key events for character input are:
|
127
224
|
|
128
225
|
* `:keypress`
|
129
|
-
* `:keydown`
|
130
|
-
* `:keyup`
|
131
|
-
* `:keyleft`
|
132
|
-
* `:keyright`
|
133
|
-
* `:keynum`
|
134
|
-
* `:keytab`
|
135
226
|
* `:keyenter`
|
136
227
|
* `:keyreturn`
|
228
|
+
* `:keytab`
|
229
|
+
* `:keybackspace`
|
137
230
|
* `:keyspace`
|
138
231
|
* `:keyescape`
|
139
232
|
* `:keydelete`
|
140
|
-
* `:
|
233
|
+
* `:keyalpha`
|
234
|
+
* `:keynum`
|
235
|
+
|
236
|
+
The navigation relted key events are:
|
237
|
+
|
238
|
+
* `:keydown`
|
239
|
+
* `:keyup`
|
240
|
+
* `:keyleft`
|
241
|
+
* `:keyright`
|
242
|
+
* `:keyhome`
|
243
|
+
* `:keyend`
|
244
|
+
* `:keyclear`
|
245
|
+
|
246
|
+
The specific `ctrl` key events:
|
247
|
+
|
248
|
+
* `:keyctrl_a`
|
249
|
+
* `:keyctrl_b`
|
250
|
+
* ...
|
251
|
+
* `:keyctrl_z`
|
252
|
+
|
253
|
+
The key events for functional keys `f*` are:
|
254
|
+
|
255
|
+
* `:keyf1`
|
256
|
+
* `:keyf2`
|
257
|
+
* ...
|
258
|
+
* `:keyf24`
|
141
259
|
|
142
260
|
## 3. Configuration
|
143
261
|
|
144
|
-
### 3.1.
|
262
|
+
### 3.1. `:interrupt`
|
145
263
|
|
146
264
|
By default `InputInterrupt` error will be raised when the user hits the interrupt key(Control-C). However, you can customise this behaviour by passing the `:interrupt` option. The available options are:
|
147
265
|
|
@@ -156,7 +274,7 @@ For example, to send interrupt signal do:
|
|
156
274
|
reader = TTY::Reader.new(interrupt: :signal)
|
157
275
|
```
|
158
276
|
|
159
|
-
### 3.2.
|
277
|
+
### 3.2. `:track_history`
|
160
278
|
|
161
279
|
The `read_line` and `read_multiline` provide history buffer that tracks all the lines entered during `TTY::Reader.new` interactions. The history buffer provides previoius or next lines when user presses up/down arrows respectively. However, if you wish to disable this behaviour use `:track_history` option like so:
|
162
280
|
|
@@ -164,15 +282,46 @@ The `read_line` and `read_multiline` provide history buffer that tracks all the
|
|
164
282
|
reader = TTY::Reader.new(track_history: false)
|
165
283
|
```
|
166
284
|
|
285
|
+
### 3.3. `:history_cycle`
|
286
|
+
|
287
|
+
This option determines whether the history buffer allows for infinite navigation. By default it is set to `false`. You can change this:
|
288
|
+
|
289
|
+
```ruby
|
290
|
+
reader = TTY::Reader.new(history_cycle: true)
|
291
|
+
```
|
292
|
+
|
293
|
+
### 3.4. `:history_duplicates`
|
294
|
+
|
295
|
+
This option controls whether duplicate lines are stored in history. By default set to `true`. You can change this:
|
296
|
+
|
297
|
+
```ruby
|
298
|
+
reader = TTY::Reader.new(history_duplicates: false)
|
299
|
+
```
|
300
|
+
|
301
|
+
### 3.5. `:history_exclude`
|
302
|
+
|
303
|
+
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 exlude empty lines. To change this:
|
304
|
+
|
305
|
+
```ruby
|
306
|
+
reader = TTY::Reader.new(history_exclude: ->(line) { ... })
|
307
|
+
```
|
308
|
+
|
167
309
|
## Development
|
168
310
|
|
169
311
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
170
312
|
|
171
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
172
|
-
|
173
313
|
## Contributing
|
174
314
|
|
175
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
315
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/piotrmurach/tty-reader. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
316
|
+
|
317
|
+
1. Clone the project on GitHub
|
318
|
+
2. Create a feature branch
|
319
|
+
3. Submit a Pull Request
|
320
|
+
|
321
|
+
Important notes:
|
322
|
+
- **All new features must include test coverage.** At a bare minimum, unit tests are required. It is preferred if you include acceptance tests as well.
|
323
|
+
- **The tests must be be idempotent.** Any test run should produce the same result when run over and over.
|
324
|
+
- **All new features must include source code & readme documentation** Any new method you add should include yarddoc style documentation with clearly specified parameter and return types.
|
176
325
|
|
177
326
|
## License
|
178
327
|
|
@@ -180,8 +329,8 @@ The gem is available as open source under the terms of the [MIT License](http://
|
|
180
329
|
|
181
330
|
## Code of Conduct
|
182
331
|
|
183
|
-
Everyone interacting in the
|
332
|
+
Everyone interacting in the TTY::Reader project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/piotrmurach/tty-reader/blob/master/CODE_OF_CONDUCT.md).
|
184
333
|
|
185
334
|
## Copyright
|
186
335
|
|
187
|
-
Copyright (c) 2017 Piotr Murach. See LICENSE for further details.
|
336
|
+
Copyright (c) 2017-2018 Piotr Murach. See LICENSE for further details.
|
data/appveyor.yml
CHANGED
@@ -9,7 +9,6 @@ test_script:
|
|
9
9
|
- bundle exec rake ci
|
10
10
|
environment:
|
11
11
|
matrix:
|
12
|
-
- ruby_version: "193"
|
13
12
|
- ruby_version: "200"
|
14
13
|
- ruby_version: "200-x64"
|
15
14
|
- ruby_version: "21"
|
@@ -20,6 +19,3 @@ environment:
|
|
20
19
|
- ruby_version: "23-x64"
|
21
20
|
- ruby_version: "24"
|
22
21
|
- ruby_version: "24-x64"
|
23
|
-
matrix:
|
24
|
-
allow_failures:
|
25
|
-
- ruby_version: "193"
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'benchmark/ips'
|
2
|
+
require 'tty-reader'
|
3
|
+
|
4
|
+
input = StringIO.new("a")
|
5
|
+
output = StringIO.new
|
6
|
+
$stdin = input
|
7
|
+
reader = TTY::Reader.new(input, output)
|
8
|
+
|
9
|
+
Benchmark.ips do |x|
|
10
|
+
x.report('getc') do
|
11
|
+
input.rewind
|
12
|
+
$stdin.getc
|
13
|
+
end
|
14
|
+
|
15
|
+
x.report('read_char') do
|
16
|
+
input.rewind
|
17
|
+
reader.read_char
|
18
|
+
end
|
19
|
+
|
20
|
+
x.compare!
|
21
|
+
end
|
22
|
+
|
23
|
+
# v0.1.0
|
24
|
+
#
|
25
|
+
# Calculating -------------------------------------
|
26
|
+
# getc 52462 i/100ms
|
27
|
+
# read_char 751 i/100ms
|
28
|
+
# -------------------------------------------------
|
29
|
+
# getc 2484819.4 (±4.1%) i/s - 12433494 in 5.013438s
|
30
|
+
# read_char 7736.4 (±2.9%) i/s - 39052 in 5.052628s
|
31
|
+
#
|
32
|
+
# Comparison:
|
33
|
+
# getc: 2484819.4 i/s
|
34
|
+
# read_char: 7736.4 i/s - 321.19x slower
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'benchmark/ips'
|
2
|
+
require 'tty-reader'
|
3
|
+
|
4
|
+
input = StringIO.new("abc\n")
|
5
|
+
output = StringIO.new
|
6
|
+
$stdin = input
|
7
|
+
reader = TTY::Reader.new(input, output)
|
8
|
+
|
9
|
+
Benchmark.ips do |x|
|
10
|
+
x.report('gets') do
|
11
|
+
input.rewind
|
12
|
+
$stdin.gets
|
13
|
+
end
|
14
|
+
|
15
|
+
x.report('read_line') do
|
16
|
+
input.rewind
|
17
|
+
reader.read_line
|
18
|
+
end
|
19
|
+
|
20
|
+
x.compare!
|
21
|
+
end
|
22
|
+
|
23
|
+
# v0.1.0
|
24
|
+
#
|
25
|
+
# Calculating -------------------------------------
|
26
|
+
# gets 51729 i/100ms
|
27
|
+
# read_line 164 i/100ms
|
28
|
+
# -------------------------------------------------
|
29
|
+
# gets 1955255.2 (±3.7%) i/s - 9776781 in 5.008004s
|
30
|
+
# read_line 1215.1 (±33.1%) i/s - 5248 in 5.066569s
|
31
|
+
#
|
32
|
+
# Comparison:
|
33
|
+
# gets: 1955255.2 i/s
|
34
|
+
# read_line: 1215.1 i/s - 1609.19x slower
|