Expand description

reedline \|/

A readline replacement written in Rust

Reedline is a project to create a line editor (like bash’s readline or zsh’s zle) that supports many of the modern conveniences of CLIs, including syntax highlighting, completions, multiline support, Unicode support, and more. It is currently primarily developed as the interactive editor for nushell (starting with v0.60) striving to provide a pleasant interactive experience.

Basic example

// Create a default reedline object to handle user input

use reedline::{DefaultPrompt, Reedline, Signal};

 let mut line_editor = Reedline::create();
 let prompt = DefaultPrompt::default();

 loop {
     let sig = line_editor.read_line(&prompt);
     match sig {
         Ok(Signal::Success(buffer)) => {
             println!("We processed: {}", buffer);
         }
         Ok(Signal::CtrlD) | Ok(Signal::CtrlC) => {
             println!("\nAborted!");
             break;
         }
         Ok(Signal::CtrlL) => {
             line_editor.clear_screen();
         }
         x => {
             println!("Event: {:?}", x);
         }
     }
 }

Integrate with custom keybindings

// Configure reedline with custom keybindings

//Cargo.toml
//    [dependencies]
//    crossterm = "*"

use {
  crossterm::event::{KeyCode, KeyModifiers},
  reedline::{default_emacs_keybindings, EditCommand, Reedline, Emacs, ReedlineEvent},
};

let mut keybindings = default_emacs_keybindings();
keybindings.add_binding(
    KeyModifiers::ALT,
    KeyCode::Char('m'),
    ReedlineEvent::Edit(vec![EditCommand::BackspaceWord]),
);
let edit_mode = Box::new(Emacs::new(keybindings));

let mut line_editor = Reedline::create().with_edit_mode(edit_mode);

Integrate with History

// Create a reedline object with history support, including history size limits

use reedline::{FileBackedHistory, Reedline};

let history = Box::new(
    FileBackedHistory::with_file(5, "history.txt".into())
        .expect("Error configuring history with file"),
);
let mut line_editor = Reedline::create()
    .with_history(history);

Integrate with custom syntax Highlighter

// Create a reedline object with highlighter support

use reedline::{ExampleHighlighter, Reedline};

let commands = vec![
  "test".into(),
  "hello world".into(),
  "hello world reedline".into(),
  "this is the reedline crate".into(),
];
let mut line_editor =
Reedline::create().with_highlighter(Box::new(ExampleHighlighter::new(commands)));

Integrate with custom tab completion

// Create a reedline object with tab completions support

use reedline::{ColumnarMenu, DefaultCompleter, Reedline, ReedlineMenu};

let commands = vec![
  "test".into(),
  "hello world".into(),
  "hello world reedline".into(),
  "this is the reedline crate".into(),
];
let completer = Box::new(DefaultCompleter::new_with_wordlen(commands.clone(), 2));
// Use the interactive menu to select options from the completer
let completion_menu = Box::new(ColumnarMenu::default().with_name("completion_menu"));

let mut line_editor =
Reedline::create().with_completer(completer).with_menu(ReedlineMenu::EngineCompleter(completion_menu));

Integrate with Hinter for fish-style history autosuggestions

// Create a reedline object with in-line hint support

//Cargo.toml
//    [dependencies]
//    nu-ansi-term = "*"

use {
  nu_ansi_term::{Color, Style},
  reedline::{DefaultHinter, Reedline},
};


let mut line_editor = Reedline::create().with_hinter(Box::new(
  DefaultHinter::default()
  .with_style(Style::new().italic().fg(Color::LightGray)),
));

Are we prompt yet? (Development status)

Nushell has now all the basic features to become the primary line editor for nushell

  • General editing functionality, that should feel familiar coming from other shells (e.g. bash, fish, zsh).
  • Configurable keybindings (emacs-style bindings and basic vi-style).
  • Configurable prompt
  • Content-aware syntax highlighting.
  • Autocompletion (With graphical selection menu or simple cycling inline).
  • History with interactive search options (optionally persists to file, can support multilple sessions accessing the same file)
  • Fish-style history autosuggestion hints
  • Undo support.
  • Clipboard integration
  • Line completeness validation for seamless entry of multiline command sequences.

Areas for future improvements

  • Support for Unicode beyond simple left-to-right scripts
  • Easier keybinding configuration
  • Support for more advanced vi commands
  • Visual selection
  • Smooth experience if completion or prompt content takes long to compute
  • Support for a concurrent output stream from background tasks to be displayed, while the input prompt is active. (“Full duplex” mode)

For more ideas check out the feature discussion or hop on the #reedline channel of the nushell discord.

Development history

If you want to follow along with the history how reedline got started, you can watch the recordings of JT’s live-coding streams.

Playlist: Creating a line editor in Rust

Alternatives

For currently more mature Rust line editing check out:

Modules

Collection of common functions that can be used to create menus

Structs

Menu to present suggestions in a columnar fashion It presents a description of the suggestion if available

A default completer that can detect keywords

A hinter that use the completions or the history to show a hint to the user

Simple two-line Prompt displaying the current working directory and the time above the entry line.

A default validator which checks for mismatched quotes and brackets

This parses the incoming Events like a emacs style-editor

A simple, example highlighter that shows how to highlight keywords

Stateful history that allows up/down-arrow browsing with an internal cursor.

Main definition of editor keybindings

In memory representation of the entered line(s) including a cursor position to facilitate cursor based editing.

Struct to store the menu style Context menu definition

Struct to store the menu style

Implementation of the output to the terminal

A representation of the history search

Line editor engine

Highlight all matches for a given search string in a line

A span of source code, with positions in bytes

A representation of a buffer with styling, used for doing syntax highlighting

Suggestion returned by the Completer

This parses incoming input Events like a Vi-Style editor

Enums

Editing actions which can be mapped to key bindings.

Browsing modes for a History

Defines all possible events that could happen with a menu.

Modes that the prompt can be in

The current success/failure of the history search

The vi-specific modes that the prompt can be in

Reedline supported actions.

Allowed menus in Reedline

Valid ways how Reedline::read_line() can return

Specifies how the (previously executed) operation should be treated in the Undo stack.

Whether or not the validation shows the input was complete

Constants

Default size of the FileBackedHistory used when calling FileBackedHistory::default()

Traits

A trait that defines how to convert a line and position to a list of potential completions in that position.

Define the style of parsing for the edit events Available default options:

The syntax highlighting trait. Implementers of this trait will take in the current string and then return a StyledText object, which represents the contents of the original line as styled strings

A trait that’s responsible for returning the hint for the current line and position Hints are often shown in-line as part of the buffer, showing the user text they can accept or ignore

Interface of a history datastructure that supports stateful navigation via HistoryNavigationQuery.

Trait that defines how a menu will be printed by the painter

API to provide a custom prompt.

The syntax validation trait. Implementers of this trait will check to see if the current input is incomplete and spans multiple lines

Functions

Returns the current default emacs keybindings

Default Vi insert keybindings

Default Vi normal keybindings

Get the default keybindings and return a Vec<(String, String, String, String)> where String 1 is mode, String 2 is key_modifiers, String 3 is key_code, and Sting 4 is event

Return a Vec<String> of the Reedline EditCommands

Return a Vec of the Reedline Keybinding Modifiers

Return a Vec<String> of the Reedline KeyCodes

Return a Vec<String> of the Reedline PromptEditModes

Return a Vec<String> of the Reedline ReedlineEvents