https://github.com/piotrmurach/tty-reader
A set of methods for processing keyboard input in character, line and multiline modes.
https://github.com/piotrmurach/tty-reader
Keywords
cli console line-editing ruby ruby-gem terminal tty word-completion
Keywords from Contributors
menus prompt ruby-cli terminal-input terminal-menu tty-components user-interface
Last synced: about 6 hours ago
JSON representation
Repository metadata
A set of methods for processing keyboard input in character, line and multiline modes.
- Host: GitHub
- URL: https://github.com/piotrmurach/tty-reader
- Owner: piotrmurach
- License: mit
- Created: 2017-08-30T18:33:59.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2023-11-09T11:18:46.000Z (about 2 years ago)
- Last Synced: 2025-11-21T10:04:20.797Z (21 days ago)
- Topics: cli, console, line-editing, ruby, ruby-gem, terminal, tty, word-completion
- Language: Ruby
- Homepage: https://ttytoolkit.org
- Size: 1010 KB
- Stars: 96
- Watchers: 1
- Forks: 17
- Open Issues: 13
- Releases: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
- License: LICENSE.txt
- Code of conduct: CODE_OF_CONDUCT.md
README.md
TTY::Reader 
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.
TTY::Reader provides independent reader component for TTY toolkit.

Compatibility
The tty-reader is not compatible with the GNU Readline and doesn't aim to be. It originated from tty-prompt project to provide flexibility, independence from underlying operating system and Ruby like API interface for creating different prompts.
TTY::Reader forges its own path to provide features necessary for building line editing in terminal applications!
Features
- Pure Ruby
- Reading single keypress
- Line editing
- Reading multiline input
- Ability to register for keystroke events
- Track input history
- No global state
- Works on Linux, OS X, FreeBSD and Windows
- Supports Ruby versions
>= 2.0.0& JRuby
Installation
Add this line to your application's Gemfile:
gem "tty-reader"
And then execute:
$ bundle
Or install it yourself as:
$ gem install tty-reader
Usage
In just a few lines you can recreate IRB prompt.
Initialize the reader:
reader = TTY::Reader.new
Then register to listen for key events, in this case listen for Ctrl-X or Esc keys to exit:
reader.on(:keyctrl_x, :keyescape) do
puts "Exiting..."
exit
end
Finally, keep asking user for line input with a => as a prompt:
loop do
reader.read_line("=> ")
end
API
2.1 read_keypress
To read a single key stroke from the user use read_char or read_keypress:
reader.read_char
reader.read_keypress
reader.read_keypress(nonblock: true)
2.2 read_line
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.
For example, to read a single line terminated by a new line character use read_line like so:
reader.read_line
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:
reader.read_line(raw: false)
Any non-interpreted characters received are written back to terminal, however you can stop this by using :echo option set to false:
reader.read_line(echo: false)
You can also provide a line prefix displayed before input by passing it as a first argument:
reader.read_line(">> ")
# >>
To pre-populate the line content for editing use :value option:
reader.read_line("> ", value: "edit me")
# > edit me
2.3 read_multiline
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.
For example, to read more than one line terminated by Ctrl+d or Ctrl+z use read_multiline:
reader.read_multiline
# => [ "line1", "line2", ... ]
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:
reader.read_line(raw: false)
You can also provide a line prefix displayed before input by passing a string as a first argument:
reader.read_multiline(">> ")
2.4 on
You can register to listen on a key pressed events. This can be done by calling on with a event name(s):
reader.on(:keypress) { |event| .... }
or listen for multiple events:
reader.on(:keyctrl_x, :keyescape) { |event| ... }
The KeyEvent object is yielded to a block whenever a particular key event fires. The event responds to:
key- key pressedvalue- value of the key pressedline- the content of the currently edited line, empty otherwise
The value returns the actual key pressed and the line the content for the currently edited line or is empty.
The key is an object that responds to following messages:
name- the name of the event such as :up, :down, letter or digitmeta- true if event is non-standard key associatedshift- true if shift has been pressed with the keyctrl- true if ctrl has been pressed with the key
For example, to add listen to vim like navigation keys, one would do the following:
reader.on(:keypress) do |event|
if event.value == "j"
...
end
if event.value == "k"
...
end
end
You can subscribe to more than one event:
reader.on(:keypress) { |event| ... }
.on(:keydown) { |event| ... }
2.5 subscribe
You can subscribe any object to listen for the emitted key events using the subscribe message. The listener would need to implement a method for every event it wishes to receive.
For example, if a MyListener class wishes to only listen for keypress event:
class MyListener
def keypress(event)
...
end
end
Then subscribing is done:
reader.subscribe(MyListener.new)
Alternatively, subscribe allows you to listen to events only for the duration of block execution like so:
reader.subscribe(MyListener) do
...
end
2.6 unsubscribe
You can unsubscribe any object from listening to the key events using the unsubscribe message:
reader.unsubscribe(my_listener)
2.7 trigger
The signature for triggering key events is trigger(event, args...). The first argument is a key event name followed by any number of actual values related to the event being triggered.
For example, to trigger :keydown event do:
reader.trigger(:keydown)
To add vim bindings for line editing you could discern between alphanumeric inputs like so:
reader.on(:keypress) do |event|
if event.value == "j"
reader.trigger(:keydown)
end
if evevnt.value == "k"
reader.trigger(:keyup)
end
end
2.8 supported events
The available key events for character input are:
:keypress:keyenter:keyreturn:keytab:keybackspace:keyspace:keyescape:keydelete:keyalpha:keynum
The navigation related key events are:
:keydown:keyup:keyleft:keyright:keyhome:keyend:keyclear
The specific ctrl key events:
:keyctrl_a:keyctrl_b- ...
:keyctrl_z
The key events for functional keys f* are:
:keyf1:keyf2- ...
:keyf24
3. Configuration
3.1. :interrupt
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:
:signal- sends interrupt signal:exit- exists with status code:noop- skips handler- custom proc
For example, to send interrupt signal do:
reader = TTY::Reader.new(interrupt: :signal)
3.2. :track_history
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:
reader = TTY::Reader.new(track_history: false)
3.3. :history_cycle
This option determines whether the history buffer allows for infinite navigation. By default it is set to false. You can change this:
reader = TTY::Reader.new(history_cycle: true)
3.4. :history_duplicates
This option controls whether duplicate lines are stored in history. By default set to false. You can change this:
reader = TTY::Reader.new(history_duplicates: true)
3.5. :history_exclude
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:
reader = TTY::Reader.new(history_exclude: ->(line) { ... })
3.6. :history_size
By default, the history buffer can store up to 512 lines. This can be changed with the :history_size configuration:
reader = TTY::Reader.new(history_size: 2048)
Development
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.
Contributing
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 code of conduct.
- Clone the project on GitHub
- Create a feature branch
- Submit a Pull Request
Important notes:
- 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.
- The tests must be be idempotent. Any test run should produce the same result when run over and over.
- 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.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the TTY::Reader project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
Copyright
Copyright (c) 2017 Piotr Murach. See LICENSE for further details.
Owner metadata
- Name: Piotr Murach
- Login: piotrmurach
- Email:
- Kind: user
- Description: Tender loving command line.
- Website: https://piotrmurach.com
- Location: Sheffield / Olsztyn
- Twitter: piotr_murach
- Company:
- Icon url: https://avatars.githubusercontent.com/u/444312?v=4
- Repositories: 89
- Last ynced at: 2025-11-23T03:03:05.684Z
- Profile URL: https://github.com/piotrmurach
GitHub Events
Total
- Issues event: 2
- Watch event: 8
- Issue comment event: 3
- Pull request event: 1
- Fork event: 1
Last Year
- Issues event: 1
- Watch event: 6
- Issue comment event: 1
Committers metadata
Last synced: 7 days ago
Total Commits: 228
Total Committers: 7
Avg Commits per committer: 32.571
Development Distribution Score (DDS): 0.031
Commits in past year: 0
Committers in past year: 0
Avg Commits per committer in past year: 0.0
Development Distribution Score (DDS) in past year: 0.0
| Name | Commits | |
|---|---|---|
| Piotr Murach | p****h@g****m | 221 |
| Samuel Williams | s****s@o****z | 2 |
| Mark Allen | m****n@g****m | 1 |
| Katelyn Schiesser | k****r@g****m | 1 |
| Josh Bodah | j****h | 1 |
| Joe Eli McIlvain | j****c@g****m | 1 |
| Charles Pence | c****s@c****t | 1 |
Committer domains:
Issue and Pull Request metadata
Last synced: 7 days ago
Total issues: 18
Total pull requests: 17
Average time to close issues: 2 months
Average time to close pull requests: about 2 months
Total issue authors: 17
Total pull request authors: 14
Average comments per issue: 3.83
Average comments per pull request: 2.29
Merged pull request: 7
Bot issues: 0
Bot pull requests: 0
Past year issues: 2
Past year pull requests: 0
Past year average time to close issues: N/A
Past year average time to close pull requests: N/A
Past year issue authors: 2
Past year pull request authors: 0
Past year average comments per issue: 0.0
Past year average comments per pull request: 0
Past year merged pull request: 0
Past year bot issues: 0
Past year bot pull requests: 0
Top Issue Authors
- piotrmurach (2)
- jemc (1)
- cpence (1)
- DannyBen (1)
- Kris-LIBIS (1)
- mmitchellg5 (1)
- pjvleeuwen (1)
- 64kramsystem (1)
- doriantaylor (1)
- mmrwoods (1)
- ddoherty03 (1)
- mattbrictson (1)
- thewyzard44 (1)
- jeremie-stripe (1)
- wrzasa (1)
Top Pull Request Authors
- ioquatix (2)
- qd3v (2)
- zzyzwicz (2)
- jbodah (1)
- kmayer (1)
- ColonelPanicks (1)
- 64kramsystem (1)
- jemc (1)
- eikes (1)
- slowbro (1)
- TSMMark (1)
- doriantaylor (1)
- cpence (1)
- Ranhiru (1)
Top Issue Labels
- enhancement (4)
- bug (3)
- help wanted (1)
Top Pull Request Labels
Package metadata
- Total packages: 4
-
Total downloads:
- rubygems: 144,115,266 total
- Total docker downloads: 965,283,614
- Total dependent packages: 25 (may contain duplicates)
- Total dependent repositories: 3,188 (may contain duplicates)
- Total versions: 29
- Total maintainers: 1
gem.coop: tty-reader
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.
- Homepage: https://ttytoolkit.org
- Documentation: http://www.rubydoc.info/gems/tty-reader/
- Licenses: MIT
- Latest release: 0.9.0 (published about 5 years ago)
- Last Synced: 2025-12-09T06:03:14.173Z (3 days ago)
- Versions: 9
- Dependent Packages: 0
- Dependent Repositories: 0
- Downloads: 72,111,488 Total
- Docker Downloads: 482,641,807
-
Rankings:
- Dependent repos count: 0.0%
- Dependent packages count: 0.0%
- Average: 0.153%
- Docker downloads count: 0.211%
- Downloads: 0.402%
- Maintainers (1)
rubygems.org: tty-reader
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.
- Homepage: https://ttytoolkit.org
- Documentation: http://www.rubydoc.info/gems/tty-reader/
- Licenses: MIT
- Latest release: 0.9.0 (published about 5 years ago)
- Last Synced: 2025-12-07T18:02:26.020Z (4 days ago)
- Versions: 9
- Dependent Packages: 24
- Dependent Repositories: 3,188
- Downloads: 72,003,778 Total
- Docker Downloads: 482,641,807
-
Rankings:
- Docker downloads count: 0.26%
- Dependent repos count: 0.555%
- Downloads: 0.579%
- Dependent packages count: 1.167%
- Average: 2.64%
- Stargazers count: 5.904%
- Forks count: 7.373%
- Maintainers (1)
proxy.golang.org: github.com/piotrmurach/tty-reader
- Homepage:
- Documentation: https://pkg.go.dev/github.com/piotrmurach/tty-reader#section-documentation
- Licenses: mit
- Latest release: v0.9.0 (published about 5 years ago)
- Last Synced: 2025-12-07T18:02:27.029Z (4 days ago)
- Versions: 9
- Dependent Packages: 0
- Dependent Repositories: 0
-
Rankings:
- Stargazers count: 4.753%
- Forks count: 5.307%
- Average: 7.609%
- Dependent packages count: 9.576%
- Dependent repos count: 10.802%
conda-forge.org: rb-tty-reader
- Homepage: https://rubygems.org/gems/tty-reader
- Licenses: MIT
- Latest release: 0.7.0 (published about 6 years ago)
- Last Synced: 2025-12-07T18:02:39.325Z (4 days ago)
- Versions: 2
- Dependent Packages: 1
- Dependent Repositories: 0
-
Rankings:
- Dependent packages count: 28.82%
- Stargazers count: 32.014%
- Average: 33.042%
- Dependent repos count: 34.025%
- Forks count: 37.31%
Dependencies
- benchmark-ips ~> 2.7.2 development
- coveralls_reborn ~> 0.21.0 development
- rspec-benchmark ~> 0.6 development
- simplecov ~> 0.21.0 development
- yard ~> 0.9 development
- yardstick ~> 0.9.9 development
- rake >= 0 development
- rspec >= 3.0 development
- tty-cursor ~> 0.7
- tty-screen ~> 0.8
- wisper ~> 2.0
- actions/checkout v2 composite
- ruby/setup-ruby v1 composite
Score: 27.464345529659646