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;
}
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::{default_emacs_keybindings, ColumnarMenu, DefaultCompleter, Emacs, KeyCode, KeyModifiers, Reedline, ReedlineEvent, ReedlineMenu, MenuBuilder};
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"));
// Set up the required keybindings
let mut keybindings = default_emacs_keybindings();
keybindings.add_binding(
KeyModifiers::NONE,
KeyCode::Tab,
ReedlineEvent::UntilFound(vec![
ReedlineEvent::Menu("completion_menu".to_string()),
ReedlineEvent::MenuNext,
]),
);
let edit_mode = Box::new(Emacs::new(keybindings));
let mut line_editor = Reedline::create()
.with_completer(completer)
.with_menu(ReedlineMenu::EngineCompleter(completion_menu))
.with_edit_mode(edit_mode);
§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)),
));
§Integrate with custom line completion Validator
// Create a reedline object with line completion validation support
use reedline::{DefaultValidator, Reedline};
let validator = Box::new(DefaultValidator);
let mut line_editor = Reedline::create().with_validator(validator);
§Use custom EditMode
// Create a reedline object with custom edit mode
// This can define a keybinding setting or enable vi-emulation
use reedline::{
default_vi_insert_keybindings, default_vi_normal_keybindings, EditMode, Reedline, Vi,
};
let mut line_editor = Reedline::create().with_edit_mode(Box::new(Vi::new(
default_vi_insert_keybindings(),
default_vi_normal_keybindings(),
)));
§Crate features
clipboard
: Enable support to use theSystemClipboard
. Enabling this feature will return aSystemClipboard
instead of a local clipboard when callingget_default_clipboard()
.bashisms
: Enable support for special text sequences that recall components from the history. e.g.!!
and!$
. For use in shells likebash
ornushell
.sqlite
: Provides theSqliteBackedHistory
to store richer information in the history. Statically links the required sqlite version.sqlite-dynlib
: Alternative to the featuresqlite
. Will not statically link. Requiressqlite >= 3.38
to link dynamically!external_printer
: Experimental: Thread-safeExternalPrinter
handle to print lines from concurrently running threads.
§Are we prompt yet? (Development status)
Reedline 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§
- menu_
functions - Collection of common functions that can be used to create menus
Structs§
- Columnar
Menu - Menu to present suggestions in a columnar fashion It presents a description of the suggestion if available
- Cursor
Config - Maps cursor shapes to each edit mode (emacs, vi normal & vi insert).
If any of the fields is
None
, the cursor won’t get changed by Reedline for that mode. - CwdAware
Hinter - A hinter that uses the completions or the history to show a hint to the user
- Default
Completer - A default completer that can detect keywords
- Default
Hinter - A hinter that uses the completions or the history to show a hint to the user
- Default
Prompt - Simple
Prompt
displaying a configurable left and a right prompt. For more fine-tuned configuration, implement thePrompt
trait. For the default configuration, useDefaultPrompt::default()
- Default
Validator - A default validator which checks for mismatched quotes and brackets
- Description
Menu - Completion menu definition
- Editor
- Stateful editor executing changes to the underlying
LineBuffer
- Emacs
- This parses the incoming Events like a emacs style-editor
- Example
Highlighter - A simple, example highlighter that shows how to highlight keywords
- External
Printer - An ExternalPrinter allows to print messages of text while editing a line. The message is printed as a new line, the line-edit will continue below the output.
- File
Backed History - Stateful history that allows up/down-arrow browsing with an internal cursor.
- History
Item - Represents one run command with some optional additional context
- History
Item Id - Unique ID for the
HistoryItem
. More recent items have higher ids than older ones. - History
Session Id - Unique ID for the session in which reedline was run to disambiguate different sessions
- IdeMenu
- Menu to present suggestions like similar to Ide completion menus
- KeyModifiers
- Represents key modifiers (shift, control, alt, etc.).
- Keybindings
- Main definition of editor keybindings
- Line
Buffer - In memory representation of the entered line(s) including a cursor position to facilitate cursor based editing.
- List
Menu - Struct to store the menu style Context menu definition
- Menu
Text Style - Struct to store the menu style
- Painter
- Implementation of the output to the terminal
- Prompt
History Search - A representation of the history search
- Reedline
- Line editor engine
- Reedline
Error - separate struct to not expose anything to the public (for now)
- Reedline
RawEvent - A wrapper for crossterm::event::Event.
- Search
Filter - Defines additional filters for querying the
History
- Search
Query - Query for search in the potentially rich
History
- Simple
Match Highlighter - Highlight all matches for a given search string in a line
- Span
- A span of source code, with positions in bytes
- Sqlite
Backed History - A history that stores the values to an SQLite database. In addition to storing the command, the history can store an additional arbitrary HistoryEntryContext, to add information such as a timestamp, running directory, result…
- Styled
Text - A representation of a buffer with styling, used for doing syntax highlighting
- Suggestion
- Suggestion returned by the Completer
- Vi
- This parses incoming input
Event
s like a Vi-Style editor
Enums§
- Color
- Represents a color.
- Command
Line Search - Ways to search for a particular command line in the
History
- Default
Prompt Segment - A struct to control the appearance of the left or right prompt in a
DefaultPrompt
- Description
Mode - The direction of the description box
- Edit
Command - Editing actions which can be mapped to key bindings.
- History
Navigation Query - Browsing modes for a
History
- KeyCode
- Represents a key.
- Menu
Event - Defines all possible events that could happen with a menu.
- Prompt
Edit Mode - Modes that the prompt can be in
- Prompt
History Search Status - The current success/failure of the history search
- Prompt
ViMode - The vi-specific modes that the prompt can be in
- Reedline
Error Variants - non-public (for now)
- Reedline
Event - Reedline supported actions.
- Reedline
Menu - Allowed menus in Reedline
- Search
Direction - Defines how to traverse the history when executing a
SearchQuery
- Signal
- Valid ways how
Reedline::read_line()
can return - Undo
Behavior - Every line change should come with an
UndoBehavior
tag, which can be used to calculate how the change should be reflected on the undo stack - Validation
Result - Whether or not the validation shows the input was complete
Constants§
- HISTORY_
SIZE - Default size of the
FileBackedHistory
used when callingFileBackedHistory::default()
Traits§
- Completer
- A trait that defines how to convert some text and a position to a list of potential completions in that position. The text could be a part of the whole line, and the position is the index of the end of the text in the original line.
- Edit
Mode - Define the style of parsing for the edit events Available default options:
- Highlighter
- 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 - Hinter
- 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
- History
- Represents a history file or database
Data could be stored e.g. in a plain text file, in a
JSONL
file, in aSQLite
database - Menu
- Trait that defines how a menu will be printed by the painter
- Menu
Builder - Common builder for all menus
- Prompt
- API to provide a custom prompt.
- Validator
- The syntax validation trait. Implementers of this trait will check to see if the current input is incomplete and spans multiple lines
Functions§
- default_
emacs_ keybindings - Returns the current default emacs keybindings
- default_
vi_ insert_ keybindings - Default Vi insert keybindings
- default_
vi_ normal_ keybindings - Default Vi normal keybindings
- get_
reedline_ default_ keybindings - Get the default keybindings and return a
Vec<(String, String, String, String)>
where String 1 ismode
, String 2 iskey_modifiers
, String 3 iskey_code
, and Sting 4 isevent
- get_
reedline_ edit_ commands - Return a
Vec<String>
of the ReedlineEditCommand
s - get_
reedline_ keybinding_ modifiers - Return a
Vec
of the Reedline Keybinding Modifiers - get_
reedline_ keycodes - Return a
Vec<String>
of the ReedlineKeyCode
s - get_
reedline_ prompt_ edit_ modes - Return a
Vec<String>
of the ReedlinePromptEditMode
s - get_
reedline_ reedline_ events - Return a
Vec<String>
of the ReedlineReedlineEvent
s - kitty_
protocol_ available - Return if the terminal supports the kitty keyboard enhancement protocol
Type Aliases§
- Result
- Standard
std::result::Result
, withReedlineError
as the error variant