Mirror of https://gitlab.redox-os.org/redox-os/termion


Termion logo

Build Status Latest Version Documentation Examples Changelog Tutorial

Termion is a pure Rust, bindless library for low-level handling, manipulating and reading information about terminals. This provides a full-featured alternative to Termbox.

Termion aims to be simple and yet expressive. It is bindless, meaning that it is not a front-end to some other library (e.g., ncurses or termbox), but a standalone library directly talking to the TTY.

Termion is quite convenient, due to its complete coverage of essential TTY features, providing one consistent API. Termion is rather low-level containing only abstraction aligned with what actually happens behind the scenes. For something more high-level, refer to inquirer-rs, which uses Termion as backend.

Termion generates escapes and API calls for the user. This makes it a whole lot cleaner to use escapes.

Supports Redox, Mac OS X, BSD, and Linux (or, in general, ANSI terminals).

A note on stability

This crate is stable.


termion = "*"

0.1.0 to 1.0.0 guide

This sample table gives an idea of how to go about converting to the new major version of Termion.

0.1.0 1.0.0
use termion::IntoRawMode use termion::raw::IntoRawMode
use termion::TermRead use termion::input::TermRead
stdout.color(color::Red); write!(stdout, "{}", color::Fg(color::Red));
stdout.color_bg(color::Red); write!(stdout, "{}", color::Bg(color::Red));
stdout.goto(x, y); write!(stdout, "{}", cursor::Goto(x, y));
color::rgb(r, g, b); color::Rgb(r, g, b) (truecolor)
x.with_mouse() MouseTerminal::from(x)


  • Raw mode.
  • TrueColor.
  • 256-color mode.
  • Cursor movement.
  • Text formatting.
  • Console size.
  • TTY-only stream.
  • Control sequences.
  • Termios control.
  • Password input.
  • Redox support.
  • Safe isatty wrapper.
  • Panic-free error handling.
  • Special keys events (modifiers, special keys, etc.).
  • Allocation-free.
  • Asynchronous key events.
  • Mouse input.
  • Carefully tested.
  • Detailed documentation on every item.

and much more.


Style and colors.

extern crate termion;

use termion::{color, style};

use std::io;

fn main() {
    println!("{}Red", color::Fg(color::Red));
    println!("{}Blue", color::Fg(color::Blue));
    println!("{}Blue'n'Bold{}", style::Bold, style::Reset);
    println!("{}Just plain italic", style::Italic);

Moving the cursor

extern crate termion;

fn main() {
    print!("{}{}Stuff", termion::clear::All, termion::cursor::Goto(1, 1));


extern crate termion;

use termion::event::{Key, Event, MouseEvent};
use termion::input::{TermRead, MouseTerminal};
use termion::raw::IntoRawMode;
use std::io::{Write, stdout, stdin};

fn main() {
    let stdin = stdin();
    let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap());

    write!(stdout, "{}{}q to exit. Click, click, click!", termion::clear::All, termion::cursor::Goto(1, 1)).unwrap();

    for c in stdin.events() {
        let evt = c.unwrap();
        match evt {
            Event::Key(Key::Char('q')) => break,
            Event::Mouse(me) => {
                match me {
                    MouseEvent::Press(_, x, y) => {
                        write!(stdout, "{}x", termion::cursor::Goto(x, y)).unwrap();
                    _ => (),
            _ => {}

Read a password

extern crate termion;

use termion::input::TermRead;
use std::io::{Write, stdout, stdin};

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let stdin = stdin();
    let mut stdin = stdin.lock();

    stdout.write_all(b"password: ").unwrap();

    let pass = stdin.read_passwd(&mut stdout);

    if let Ok(Some(pass)) = pass {
    } else {


See examples/, and the documentation, which can be rendered using cargo doc.

For a more complete example, see a minesweeper implementation, that I made for Redox using termion.



  • modify Keys and Events to detect Esc key presses

    modify Keys and Events to detect Esc key presses

    The strategy used here is to read two bytes at a time, going on the assumption that escape sequences will consist of multi byte reads and solitary Esc key presses will consist of single byte reads.

    Tests had to be modified to account for these new multi byte reads by including dummy bytes when a single byte was previously expected.

    Fixes ticki/termion#43

    opened by iamcodemaker 11
  • Add explicit lifetime parameters to reader iterator trait, allows use of &mut instead of move

    Add explicit lifetime parameters to reader iterator trait, allows use of &mut instead of move

    So that the input reader iterators can be used in places where a move is not possible and where constantly reinstantiating is not feasible. This change was prompted by needing to work with keyboard input inside of a main loop of a program, without being able to use the normal (synchronous) loop because it blocks. I had tried calling async_stdin() on every loop iteration, but in addition to being probably quite expensive, that function panics every now and again because sometimes stdin isn't available, and an Error is unwrapped in get_tty(). I don't think this changes the external-facing API at all, simply allows a slightly looser use of the main stream because &mut is more flexible than a move.

    needs discussion 
    opened by mhintz 9
  • Reduce amount of unwraps

    Reduce amount of unwraps

    Things have done to achieve that:

    • Introducing an error_chain-ish custom error type, convertable from all other ones used in src/event.rs and src/cursor.rs.
    • Replacing .unwrap()s in src/event.rs and src/cursor.rs by explicit error return values.
    • Modifying public interfaces which is mentioned below.
    • Refactoring and fixing formatting.

    Changes that can be considered as regressions:

    • Using custom error type instead of std::io::Error may add memory and likely but little CPU overhead, though compiler could possibly pull some null-pointer optimizations to completely remove the said overhead. This is also useful for end-users that want to filter the specific error which is hard with io::Error::new(/* whatever io::ErrorKind variant here */, "custom error message").
    • Breaking changes in the public cursor::DetectCursorPos trait: cursor_pos method now returns error::Result<(u16, u16)> instead of io::Result<(u16, u16)>.

    Possible improvement ideas, their pros and cons:

    • Switch completely to error_chain - this introduces the backtrace dependency which may not be suitable for platforms that don't support it, and as a result, makes the error::Error type consume more memory - which was the primary reason to not to use that crate from the beginning. On the other hand, improved maintainability and readability.
    • If the breaking change above is accepted, use error::Error and error::Result throughout the crate, not just in src/event.rs and src/cursor.rs, for better interoperability and consistency (if make a breaking change anyway, do it correctly). If not, then convert everything back to io::Error and io::Result which is fine, but in this case custom errors do need heap allocation. And of course, no plans to go back to .unwrap()s (the fewer unexpected panics, the better).
    opened by hcpl 6
  • added cursor position detection

    added cursor position detection

    This solves #85 in a similar fashion as the color amount detection: the cursor module now provides a trait that adds a cursor_pos() method to an instance of Write.

    It also corrects that previous implementation somewhat by making the CONTROL_SEQUENCE_TIMEOUT a member of the raw module and implementing DetectColors for any instance of Write rather than just RawTerminal (MouseTerminal for instance works as well).

    opened by IGI-111 6
  • Add travis integration

    Add travis integration

    This configures travis to build and test termion on the stable, beta and nightly branches.

    I updated the rainbow example to work on stable (removed the step_by feature), which admittedly isn't as pretty. Possible solutions are:

    • Wait for step_by to be stable before integrating travis
    • Add conditional to only compile rainbow example on nightly
    • Use manual multiplications for now, and update back to step_by once it is stable
    opened by gyscos 6
  • Add `UnknownCSI` event type

    Add `UnknownCSI` event type

    When a CSI sequence is not parsed by termion, return a special UnknownCSI event including the byte sequence, allowing applications using termion to do their own parsing.

    opened by gyscos 6
  • Move system specific features into sys module

    Move system specific features into sys module

    This organizes the system specific code into two modules, redox and unix. Tests are moved when necessary to the root, so they can be run on both modules. Termios is implemented for raw mode on Redox.

    opened by jackpot51 5
  • Show cursor before exiting

    Show cursor before exiting

    If the cursor is hidden when the terminal is dropped, the controlling process (most likely a shell) won't display a cursor. By sending a show cursor escape code, we guarantee that the cursor is restored prior to shutdown.

    opened by jmacdonald 5
  • add illumos support

    add illumos support

    Everything pretty much works on illumos as-is, except for two issues:

    • We do not currently have a system implementation of cfmakeraw(); see illumos bug 1060. There is, however, a compatibility implementation in the libc crate so we use that here.
    • It seems like we're using tcsetattr() in set_terminal_attr() with a literal 0 for the actions argument; this appears to correspond to TCSANOW on Linux systems. On illumos, this constant has a different value, so we should use the symbol from the libc crate here.
    opened by jclulow 4
  • Eliminated unwraps to avoid panics

    Eliminated unwraps to avoid panics

    Problem: With the MouseTerminal, press mouse and drag the pointer outside of the terminal window and fiddle with it a lot => panic:

    thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', libcore/option.rs:345:21
    stack backtrace:
       0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
                 at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
       1: std::sys_common::backtrace::print
                 at libstd/sys_common/backtrace.rs:71
                 at libstd/sys_common/backtrace.rs:59
       2: std::panicking::default_hook::{{closure}}
                 at libstd/panicking.rs:211
       3: std::panicking::default_hook
                 at libstd/panicking.rs:227
       4: std::panicking::rust_panic_with_hook
                 at libstd/panicking.rs:511
       5: std::panicking::continue_panic_fmt
                 at libstd/panicking.rs:426
       6: rust_begin_unwind
                 at libstd/panicking.rs:337
       7: core::panicking::panic_fmt
                 at libcore/panicking.rs:92
       8: core::panicking::panic
                 at libcore/panicking.rs:53
       9: <core::option::Option<T>>::unwrap
                 at /checkout/src/libcore/macros.rs:20
      10: termion::event::parse_csi::{{closure}}
                 at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/termion-1.5.1/src/event.rs:161
      11: termion::event::parse_csi
                 at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/termion-1.5.1/src/event.rs:166
      12: termion::event::parse_event
                 at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/termion-1.5.1/src/event.rs:118
      13: termion::input::parse_event
                 at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/termion-1.5.1/src/input.rs:99
      14: <termion::input::EventsAndRaw<R> as core::iter::iterator::Iterator>::next
                 at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/termion-1.5.1/src/input.rs:77
      15: <termion::input::Events<R> as core::iter::iterator::Iterator>::next
                 at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/termion-1.5.1/src/input.rs:38
      16: two::ui::grinui::GrinUI::process
                 at src/ui/grinui.rs:59
      17: two::ui::grinui::GrinUI::react_once
                 at src/ui/grinui.rs:54
      18: two::ui::grin::Grin::wait
                 at src/ui/grin.rs:63
      19: two::main::{{closure}}
                 at src/main.rs:23
      20: <core::result::Result<T, E>>::and_then
                 at /checkout/src/libcore/result.rs:621
      21: two::main
                 at src/main.rs:22
      22: std::rt::lang_start::{{closure}}
                 at /checkout/src/libstd/rt.rs:74
      23: std::panicking::try::do_call
                 at libstd/rt.rs:59
                 at libstd/panicking.rs:310
      24: __rust_maybe_catch_panic
                 at libpanic_unwind/lib.rs:105
      25: std::rt::lang_start_internal
                 at libstd/panicking.rs:289
                 at libstd/panic.rs:392
                 at libstd/rt.rs:58
      26: std::rt::lang_start
                 at /checkout/src/libstd/rt.rs:74
      27: main
      28: __libc_start_main
      29: _start

    To help others trying to crack on event issues I've added some logging. Feel free to remove that if not welcome. I'm still thinking what to do with the lone ESC event:

    2019-01-27T19:11:34+01:00 - DEBUG - Event: Mouse(Press(Left, 4, 47)) 2019-01-27T19:11:34+01:00 - DEBUG - Event: Mouse(Press(Left, 1, 47)) 2019-01-27T19:11:34+01:00 - DEBUG - Event: lone ESC 2019-01-27T19:11:34+01:00 - DEBUG - Event: Key(Char('[')) 2019-01-27T19:11:34+01:00 - DEBUG - Leftover: 77 2019-01-27T19:11:34+01:00 - DEBUG - Event: Key(Char('M')) 2019-01-27T19:11:34+01:00 - DEBUG - Event: Key(Char('@')) 2019-01-27T19:11:34+01:00 - DEBUG - Leftover: 33 2019-01-27T19:11:34+01:00 - DEBUG - Event: Key(Char('!')) 2019-01-27T19:11:34+01:00 - DEBUG - Event: Key(Char('O')) 2019-01-27T19:11:34+01:00 - DEBUG - Event: Mouse(Press(Left, 1, 48)) 2019-01-27T19:11:34+01:00 - DEBUG - Event: Mouse(Press(Left, 1, 49))

    opened by jocutajar 4
  • Remove unused import of std::ascii::AsciiExt

    Remove unused import of std::ascii::AsciiExt

    The import of std::ascii::AsciiExt in src/event.rs is unused. Remove it.

    warning: unused import: std::ascii::AsciiExt --> src/event.rs:4:5 | 4 | use std::ascii::AsciiExt; | ^^^^^^^^^^^^^^^^^^^^ | = note: #[warn(unused_imports)] on by default

    opened by d-e-s-o 3
Redox OS
A Rust Operating System
Redox OS
Basic vim-like editor for Redox-OS

red red is an editor based on vim written in Rust. Goal of this project is to provide a basic command-line editor, much like nano. Targeted for Redox.

null 1 Mar 5, 2022
A CLI command to parse kustomize build result and notify it to GitLab

ksnotify A CLI command to parse kustomize build result and notify it to GitLab Caution This repository is under development status. What ksnotify does

null 7 Jan 2, 2023
Check the reproducibility status of your Arch Linux packages (read-only mirror)

arch-repro-status A CLI tool for querying the reproducibility status of the Arch Linux packages using data from a rebuilderd instance such as reproduc

Arch Linux 12 Nov 16, 2022
A library that creates a terminal-like window with feature-packed drawing of text and easy input handling. MIRROR.

BearLibTerminal provides a pseudoterminal window with a grid of character cells and a simple yet powerful API for flexible textual output and uncompli

Tommy Ettinger 43 Oct 31, 2022
By mirroring traffic to and from your machine, mirrord surrounds your local service with a mirror image of its cloud environment.

mirrord lets you easily mirror traffic from your Kubernetes cluster to your development environment. It comes as both Visual Studio Code extension and

MetalBear 2.1k Jan 3, 2023
A fast, efficient osu! beatmap mirror written in asynchronous Rust

A fast, efficient osu! beatmap mirror written in asynchronous Rust. Supports cheesegull, aswell as osu!api v2 formats.

James 4 Oct 28, 2022
An implementation of a mirror SponsorBlock server in Rust.

sponsorblock-mirror This is a Rust-based mirror of the SponsorBlock API. It also uses sb-mirror for mirroring the CSV dumps via rsync. Instances spons

Team Piped 38 Feb 11, 2023
A mirror of lib.rs/main

Lib.rs (Crates.rs) Lib.rs is a fast, lightweight index of Rust libraries and applications. Crates published to crates.io will automatically show up on

Max Bruce 3 Aug 4, 2023
Video Management System. Mirror of Codeberg.

Screenshots | Changelog | Codeberg | Matrix Overview Full resolution live view with sub 2 second delay 24/7 recording to custom database TFlite object

null 44 Nov 14, 2023
A simple cli to clone projects and fetch all projects in a GitHub org..

stupid-git A simple cli to clone projects and update all projects. get all repository from GitHub clone all pull all with git stash Usage create sgit.

Fengda Huang 5 Sep 15, 2022
A tool to format codeblocks inside markdown and org documents.

cbfmt (codeblock format) A tool to format codeblocks inside markdown, org, and restructuredtext documents. It iterates over all codeblocks, and format

Lukas Reineke 126 May 26, 2023
this-week-in-neovim.org official webapp repository

This Week In Neovim This repository holds the source code of https://this-week-in-neovim.org. Architecture How does it run in production Automatic upd

Dimitri Sabadie 189 Jun 23, 2023
Code examples for https://www.poor.dev/blog/terminal-anatomy/

This repository contains examples from the Anatomy of a Terminal Emulator blog post. Each folder contains a separate example and can be run separately

Aram Drevekenin 28 Dec 7, 2022
☃️ Learning Rust with AoC 2021 🎄https://adventofcode.com/2021/

?? Andrei's 2021 Advent of Code ?? Learning Goals Rust basics (vectors, arrays, math, etc.) Rust basic CLI Rust linear algebra and ndarrays (e.g., htt

Andrei Bârsan 1 Feb 2, 2022
A wrapper around the code action dump from https://mcdiamondfire.com.

DiamondFire Action Dump for Rust A wrapper around the code action dump from https://mcdiamondfire.com. This currently only provides schema types for u

null 3 Sep 17, 2022
Rust port of https://github.com/hunar4321/life_code with some fun features.

Smarticles A Rust port of Brainxyz's Artificial Life simulator with some fun features. A simple program to simulate primitive Artificial Life using si

Chevy Ray Johnston 15 Dec 24, 2022

Advent of Code 2022 This repository contains my solutions for Advent of Code 2022. Goal is readable, simple and mostly clean. Each day is solved in it

Guillaume P. 3 Dec 15, 2022
Simple Secure Static (HTTPS) File Server with embedded certificate

Secure Static File Server Static Files HTTPs server with self signed embedded certificate Installation Install using cargo: cargo install ssfs Or buil

0xor0ne 21 Apr 20, 2023
ARCHIVED -- moved into the main Embassy repo at https://github.com/embassy-rs/embassy

ARCHIVED - moved into the main Embassy repo https://github.com/embassy-rs/embassy cyw43 WIP driver for the CYW43439 wifi chip, used in the Raspberry P

null 245 Jun 27, 2023