Convert Figma logo to code with AI

kkawakam logorustyline

Readline Implementation in Rust

1,526
176
1,526
118

Top Related Projects

10,830

Build terminal user interfaces and dashboards using Rust

Cross platform terminal library rust

44,121

☄🌌️ The minimal, blazing-fast, and infinitely customizable prompt for any shell!

3,966

Terminal based "The Matrix" like implementation

Quick Overview

Rustyline is a readline implementation in Rust, inspired by Python's readline. It provides line editing functionality with history and completion support, making it useful for building command-line interfaces and interactive shells in Rust applications.

Pros

  • Written in pure Rust, offering memory safety and performance benefits
  • Supports cross-platform functionality (Windows, macOS, Linux)
  • Provides customizable key bindings and completion behavior
  • Actively maintained with regular updates and improvements

Cons

  • May have a steeper learning curve compared to simpler input libraries
  • Documentation could be more comprehensive for advanced use cases
  • Limited to command-line applications, not suitable for GUI environments
  • Some features may not be as mature as long-standing C libraries like GNU Readline

Code Examples

  1. Basic usage:
use rustyline::error::ReadlineError;
use rustyline::Editor;

fn main() {
    let mut rl = Editor::<()>::new();
    loop {
        let readline = rl.readline(">> ");
        match readline {
            Ok(line) => {
                println!("Line: {}", line);
                rl.add_history_entry(line.as_str());
            },
            Err(ReadlineError::Interrupted) => {
                println!("CTRL-C");
                break
            },
            Err(ReadlineError::Eof) => {
                println!("CTRL-D");
                break
            },
            Err(err) => {
                println!("Error: {:?}", err);
                break
            }
        }
    }
}
  1. Using custom completion:
use rustyline::completion::{Completer, Pair};
use rustyline::Context;
use rustyline::Editor;

struct MyCompleter;

impl Completer for MyCompleter {
    type Candidate = Pair;

    fn complete(&self, line: &str, pos: usize, _ctx: &Context<'_>) -> Result<(usize, Vec<Pair>), ReadlineError> {
        let commands = vec!["help", "quit", "list"];
        let matches: Vec<Pair> = commands
            .iter()
            .filter(|cmd| cmd.starts_with(line))
            .map(|cmd| Pair {
                display: cmd.to_string(),
                replacement: cmd.to_string(),
            })
            .collect();
        Ok((0, matches))
    }
}

fn main() {
    let mut rl = Editor::new();
    rl.set_completer(Some(MyCompleter));
    // ... rest of the code
}
  1. Customizing key bindings:
use rustyline::config::Config;
use rustyline::Editor;
use rustyline::KeyEvent;
use rustyline::KeyCode;
use rustyline::Modifiers;

fn main() {
    let config = Config::builder()
        .keyseq_timeout(0)
        .edit_mode(rustyline::EditMode::Emacs)
        .build();
    let mut rl = Editor::with_config(config);
    
    rl.bind_sequence(KeyEvent(KeyCode::Char('f'), Modifiers::CTRL), rustyline::Cmd::ForwardChar);
    rl.bind_sequence(KeyEvent(KeyCode::Char('b'), Modifiers::CTRL), rustyline::Cmd::BackwardChar);
    
    // ... rest of the code
}

Getting Started

To use Rustyline in your Rust project, add the following to your Cargo.toml:

[dependencies]
rustyline = "10.0.0"

Then, in your Rust code:

use rustyline::error::ReadlineError;
use rustyline::Editor;

fn main() {
    let mut rl = Editor::<()>::new();
    if rl.readline(">> ").is_ok() {
        println!("It works!");
    }
}

This basic example sets up Rustyline and prompts the user for input.

Competitor Comparisons

10,830

Build terminal user interfaces and dashboards using Rust

Pros of tui-rs

  • Offers a comprehensive framework for building complex terminal user interfaces
  • Supports advanced features like custom widgets and layouts
  • Provides a more flexible and powerful approach to TUI development

Cons of tui-rs

  • Steeper learning curve compared to Rustyline's simpler API
  • Requires more code and setup for basic input scenarios
  • May be overkill for simple command-line applications

Code Comparison

Rustyline (basic input):

use rustyline::Editor;

let mut rl = Editor::<()>::new();
let readline = rl.readline(">> ");
match readline {
    Ok(line) => println!("Line: {}", line),
    Err(_) => println!("Error"),
}

tui-rs (basic input):

use tui::{backend::CrosstermBackend, Terminal};
use crossterm::{event::{self, Event, KeyCode}};

let mut terminal = Terminal::new(CrosstermBackend::new(std::io::stdout()))?;
terminal.draw(|f| {
    // Draw UI components
})?;
if let Event::Key(key) = event::read()? {
    if key.code == KeyCode::Char('q') {
        break;
    }
}

The code comparison demonstrates that tui-rs requires more setup and boilerplate for basic input scenarios, while Rustyline provides a simpler API for command-line input. However, tui-rs offers greater flexibility and power for building complex terminal interfaces.

Cross platform terminal library rust

Pros of crossterm

  • More comprehensive terminal manipulation capabilities, including cursor movement, colors, and styles
  • Cross-platform support for Windows, macOS, and Linux
  • Active development with frequent updates and improvements

Cons of crossterm

  • Steeper learning curve due to more extensive API
  • May be overkill for simple line editing tasks
  • Requires more setup and configuration for basic functionality

Code comparison

rustyline:

use rustyline::Editor;

let mut rl = Editor::<()>::new();
let readline = rl.readline(">> ");
match readline {
    Ok(line) => println!("Line: {}", line),
    Err(_) => println!("Error"),
}

crossterm:

use crossterm::{execute, cursor, terminal, Result};
use std::io::{stdout, Write};

fn main() -> Result<()> {
    execute!(stdout(), terminal::Clear(terminal::ClearType::All))?;
    execute!(stdout(), cursor::MoveTo(0, 0))?;
    print!(">> ");
    stdout().flush()?;
    Ok(())
}

While rustyline focuses on providing a simple line editing experience, crossterm offers more extensive terminal control capabilities. rustyline is easier to use for basic input scenarios, while crossterm provides greater flexibility for complex terminal applications at the cost of increased complexity.

44,121

☄🌌️ The minimal, blazing-fast, and infinitely customizable prompt for any shell!

Pros of Starship

  • More feature-rich and customizable prompt system
  • Actively maintained with frequent updates
  • Supports a wide range of programming languages and tools

Cons of Starship

  • Larger project scope, potentially more complex to contribute to
  • May have higher system resource usage due to its extensive features

Code Comparison

Rustyline (basic readline implementation):

use rustyline::error::ReadlineError;
use rustyline::Editor;

fn main() {
    let mut rl = Editor::<()>::new();
    loop {
        let readline = rl.readline(">> ");
        match readline {
            Ok(line) => println!("Line: {}", line),
            Err(ReadlineError::Interrupted) => break,
            Err(ReadlineError::Eof) => break,
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
    }
}

Starship (prompt configuration):

[character]
success_symbol = "[➜](bold green)"
error_symbol = "[✗](bold red)"

[git_branch]
symbol = "🌱 "
truncation_length = 4
truncation_symbol = ""

[package]
symbol = "📦 "

[nodejs]
symbol = "⬢ "

While Rustyline focuses on providing a readline implementation, Starship offers a highly customizable prompt system with support for various programming environments and tools. Rustyline may be more suitable for simpler command-line applications, while Starship is designed for enhancing terminal productivity across multiple shells and platforms.

3,966

Terminal based "The Matrix" like implementation

Pros of cmatrix

  • Visual appeal: Creates an eye-catching Matrix-like animation in the terminal
  • Lightweight: Minimal system resources required for operation
  • Customizable: Offers various color options and animation speeds

Cons of cmatrix

  • Limited functionality: Primarily a visual effect without practical use cases
  • Less versatile: Focused on a single animation style, unlike Rustyline's broad input handling capabilities

Code Comparison

cmatrix (C):

for (j = 0; j <= LINES; j++) {
    for (i = 0; i <= COLS - 1; i += 2) {
        move(j, i);
        if (matrix[i][j].val == 1) {
            attrset(COLOR_PAIR(matrix[i][j].color));
            addch(matrix[i][j].ascii);
        }
    }
}

Rustyline (Rust):

pub fn readline(&mut self, prompt: &str) -> Result<String> {
    let mut cmd = EditCommand::BeginningOfLine;
    let mut line = String::new();
    self.move_cursor_to_end();
    self.refresh_line()?;
    loop {
        match self.next_cmd(prompt, &mut cmd)? {
            // ... (command handling logic)
        }
    }
}

The code snippets highlight the different focus areas of each project. cmatrix deals with terminal graphics and animation, while Rustyline handles complex input processing and line editing functionality.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

RustyLine

Build Status dependency status Docs

Readline implementation in Rust that is based on Antirez' Linenoise

Supported Platforms

  • Unix (tested on FreeBSD, Linux and macOS)
  • Windows
    • cmd.exe
    • Powershell

Note:

  • Powershell ISE is not supported, check issue #56
  • Mintty (Cygwin/MinGW) is not supported
  • Highlighting / Colors are not supported on Windows < Windows 10 except with ConEmu and ColorMode::Forced.

Example

use rustyline::error::ReadlineError;
use rustyline::{DefaultEditor, Result};

fn main() -> Result<()> {
    // `()` can be used when no completer is required
    let mut rl = DefaultEditor::new()?;
    #[cfg(feature = "with-file-history")]
    if rl.load_history("history.txt").is_err() {
        println!("No previous history.");
    }
    loop {
        let readline = rl.readline(">> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(line.as_str());
                println!("Line: {}", line);
            },
            Err(ReadlineError::Interrupted) => {
                println!("CTRL-C");
                break
            },
            Err(ReadlineError::Eof) => {
                println!("CTRL-D");
                break
            },
            Err(err) => {
                println!("Error: {:?}", err);
                break
            }
        }
    }
    #[cfg(feature = "with-file-history")]
    rl.save_history("history.txt");
    Ok(())
}

crates.io

You can use this package in your project by adding the following to your Cargo.toml:

[dependencies]
rustyline = "14.0.0"

Features

  • Unicode (UTF-8) (linenoise supports only ASCII)
  • Word completion (linenoise supports only line completion)
  • Filename completion
  • History search (Searching for Commands in the History)
  • Kill ring (Killing Commands)
  • Multi line support (line wrapping)
  • Word commands
  • Hints

Actions

For all modes:

KeystrokeAction
HomeMove cursor to the beginning of line
EndMove cursor to end of line
LeftMove cursor one character left
RightMove cursor one character right
Ctrl-CInterrupt/Cancel edition
Ctrl-D, Del(if line is not empty) Delete character under cursor
Ctrl-D(if line is empty) End of File
Ctrl-J, Ctrl-M, EnterFinish the line entry
Ctrl-RReverse Search history (Ctrl-S forward, Ctrl-G cancel)
Ctrl-TTranspose previous character with current character
Ctrl-UDelete from start of line to cursor
Ctrl-VInsert any special character without performing its associated action (#65)
Ctrl-WDelete word leading up to cursor (using white space as a word boundary)
Ctrl-YPaste from Yank buffer
Ctrl-ZSuspend (Unix only)
Ctrl-_Undo

Emacs mode (default mode)

KeystrokeAction
Ctrl-A, HomeMove cursor to the beginning of line
Ctrl-B, LeftMove cursor one character left
Ctrl-E, EndMove cursor to end of line
Ctrl-F, RightMove cursor one character right
Ctrl-H, BackspaceDelete character before cursor
Ctrl-I, TabNext completion
Ctrl-KDelete from cursor to end of line
Ctrl-LClear screen
Ctrl-N, DownNext match from history
Ctrl-P, UpPrevious match from history
Ctrl-X Ctrl-UUndo
Ctrl-YPaste from Yank buffer (Meta-Y to paste next yank instead)
Meta-<Move to first entry in history
Meta->Move to last entry in history
Meta-B, Alt-LeftMove cursor to previous word
Meta-CCapitalize the current word
Meta-DDelete forwards one word
Meta-F, Alt-RightMove cursor to next word
Meta-LLower-case the next word
Meta-TTranspose words
Meta-UUpper-case the next word
Meta-YSee Ctrl-Y
Meta-BackspaceKill from the start of the current word, or, if between words, to the start of the previous word
Meta-0, 1, ..., -Specify the digit to the argument. – starts a negative argument.

Readline Emacs Editing Mode Cheat Sheet

vi command mode

KeystrokeAction
$, EndMove cursor to end of line
.Redo the last text modification
;Redo the last character finding command
,Redo the last character finding command in opposite direction
0, HomeMove cursor to the beginning of line
^Move to the first non-blank character of line
aInsert after cursor
AInsert at the end of line
bMove one word or token left
BMove one non-blank word left
cChange text of a movement command
CChange text to the end of line (equivalent to c$)
dDelete text of a movement command
D, Ctrl-KDelete to the end of the line
eMove to the end of the current word
EMove to the end of the current non-blank word
fMove right to the next occurrence of char
FMove left to the previous occurrence of char
h, Ctrl-H, BackspaceMove one character left
l, SpaceMove one character right
Ctrl-LClear screen
iInsert before cursor
IInsert at the beginning of line
+, j, Ctrl-NMove forward one command in history
-, k, Ctrl-PMove backward one command in history
pInsert the yanked text at the cursor (paste)
PInsert the yanked text before the cursor
rReplaces a single character under the cursor (without leaving command mode)
sDelete a single character under the cursor and enter input mode
SChange current line (equivalent to 0c$)
tMove right to the next occurrence of char, then one char backward
TMove left to the previous occurrence of char, then one char forward
uUndo
wMove one word or token right
WMove one non-blank word right
xDelete a single character under the cursor
XDelete a character before the cursor
yYank a movement into buffer (copy)

vi insert mode

KeystrokeAction
Ctrl-H, BackspaceDelete character before cursor
Ctrl-I, TabNext completion
EscSwitch to command mode

Readline vi Editing Mode Cheat Sheet

Terminal codes (ANSI/VT100)

Wine

$ cargo run --example example --target 'x86_64-pc-windows-gnu'
...
Error: Io(Error { repr: Os { code: 6, message: "Invalid handle." } })
$ wineconsole --backend=curses target/x86_64-pc-windows-gnu/debug/examples/example.exe
...

Terminal checks

$ # current settings of all terminal attributes:
$ stty -a
$ # key bindings:
$ bind -p
$ # print out a terminfo description:
$ infocmp

Similar projects

LibraryLangOSTermUnicodeHistoryCompletionKeymapKill RingUndoColorsHint/Auto suggest
go-promptGoUx/winANSIYesYesanyEmacs/progNoNoYesYes
HaskelineHaskellUx/WinAnyYesYesanyEmacs/vi/confYesYes??
isoclineCUx/WinANSIYesYesanyEmacsNoYesYesYes
linefeedRustUx/WinAnyYesanyEmacs/confYesNo?No
linenoiseCUxANSINoYesonly lineEmacsNoNoUxYes
LinerRustUxANSINo inc searchonly wordEmacs/vi/progNoYesUxHistory based
prompt_toolkitPythonUx/WinANSIYesYesanyEmacs/vi/confYesYesUx/WinYes
reedlineRustUx/WinANSIYesYesanyEmacs/vi/bindNoYesUx/WinYes
replxxC/C++Ux/WinANSIYesYesonly lineEmacsYesNoUx/WinYes
RustylineRustUx/WinANSIYesYesanyEmacs/vi/bindYesYesUx/Win 10+Yes
termwizRustUx/WinAny?YesanyEmacsNoNoUx/WinNo

Multi line support

This is a very simple feature that simply causes lines that are longer than the current terminal width to be displayed on the next visual line instead of horizontally scrolling as more characters are typed. Currently, this feature is always enabled and there is no configuration option to disable it.

This feature does not allow the end user to hit a special key sequence and enter a mode where hitting the return key will cause a literal newline to be added to the input buffer.

The way to achieve multi-line editing is to implement the Validator trait.