2023-09-28 15:34:01 +03:00
# A feature-rich line editor - powering Nushell
2021-07-17 02:40:38 +03:00
2022-01-27 17:43:24 +03:00
![GitHub ](https://img.shields.io/github/license/nushell/reedline )
2021-07-18 21:05:54 +03:00
[![Crates.io ](https://img.shields.io/crates/v/reedline )](https://crates.io/crates/reedline)
[![docs.rs ](https://img.shields.io/docsrs/reedline )](https://docs.rs/reedline/)
2022-12-21 15:00:50 +03:00
![GitHub Workflow Status ](https://img.shields.io/github/actions/workflow/status/nushell/reedline/ci.yml?branch=main )
2023-09-15 12:15:02 +03:00
[![codecov ](https://codecov.io/gh/nushell/reedline/graph/badge.svg?token=NUTC465WOL )](https://codecov.io/gh/nushell/reedline)
2021-07-18 21:05:54 +03:00
[![Discord ](https://img.shields.io/discord/601130461678272522.svg?logo=discord )](https://discord.gg/NtAbbGn)
2021-07-17 02:40:38 +03:00
2021-09-23 22:40:32 +03:00
## Introduction
2022-03-17 01:39:08 +03:00
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 ](https://github.com/nushell/nushell ) (starting with `v0.60` ) striving to provide a pleasant interactive experience.
## Outline
- [Examples ](#examples )
2022-08-22 11:06:33 +03:00
- [Basic example ](#basic-example )
- [Integrate with custom keybindings ](#integrate-with-custom-keybindings )
- [Integrate with `History` ](#integrate-with-history )
- [Integrate with custom syntax `Highlighter` ](#integrate-with-custom-syntax-highlighter )
- [Integrate with custom tab completion ](#integrate-with-custom-tab-completion )
- [Integrate with `Hinter` for fish-style history autosuggestions ](#integrate-with-hinter-for-fish-style-history-autosuggestions )
- [Integrate with custom line completion `Validator` ](#integrate-with-custom-line-completion-validator )
- [Use custom `EditMode` ](#use-custom-editmode )
2022-09-18 15:17:34 +03:00
- [Crate features ](#crate-features )
2022-08-22 11:06:33 +03:00
- [Are we prompt yet? (Development status) ](#are-we-prompt-yet-development-status )
2022-03-17 01:39:08 +03:00
- [Contributing ](./CONTRIBUTING.md )
- [Alternatives ](#alternatives )
2021-09-23 22:40:32 +03:00
## Examples
2022-03-17 01:39:08 +03:00
For the full documentation visit < https: / / docs . rs / reedline > . The examples should highlight how you enable the most important features or which traits can be implemented for language-specific behavior.
2021-09-23 22:40:32 +03:00
### Basic example
2021-07-17 02:40:38 +03:00
```rust,no_run
// Create a default reedline object to handle user input
use reedline::{DefaultPrompt, Reedline, Signal};
2022-10-17 00:20:35 +03:00
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);
2021-05-04 13:12:08 +03:00
}
}
}
2021-06-15 02:03:57 +03:00
```
2021-07-18 21:05:54 +03:00
2022-03-17 01:39:08 +03:00
### Integrate with custom keybindings
2021-06-15 02:03:57 +03:00
2022-05-02 15:23:01 +03:00
```rust
2021-06-15 02:03:57 +03:00
// Configure reedline with custom keybindings
2021-07-17 02:40:38 +03:00
//Cargo.toml
2022-10-17 00:20:35 +03:00
// [dependencies]
// crossterm = "*"
2021-07-17 02:40:38 +03:00
use {
crossterm::event::{KeyCode, KeyModifiers},
2022-10-17 00:20:35 +03:00
reedline::{default_emacs_keybindings, EditCommand, Reedline, Emacs, ReedlineEvent},
2021-07-17 02:40:38 +03:00
};
let mut keybindings = default_emacs_keybindings();
2021-06-15 02:03:57 +03:00
keybindings.add_binding(
2022-10-17 00:20:35 +03:00
KeyModifiers::ALT,
KeyCode::Char('m'),
ReedlineEvent::Edit(vec![EditCommand::BackspaceWord]),
2021-06-15 02:03:57 +03:00
);
2022-10-17 00:20:35 +03:00
let edit_mode = Box::new(Emacs::new(keybindings));
2021-06-15 02:03:57 +03:00
2022-10-17 00:20:35 +03:00
let mut line_editor = Reedline::create().with_edit_mode(edit_mode);
2021-07-17 02:40:38 +03:00
```
2022-08-22 11:06:33 +03:00
### Integrate with `History`
2021-07-17 02:40:38 +03:00
```rust,no_run
// 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())
2022-01-27 17:43:24 +03:00
.expect("Error configuring history with file"),
2021-07-17 02:40:38 +03:00
);
2022-04-01 00:32:31 +03:00
let mut line_editor = Reedline::create()
.with_history(history);
2021-07-17 02:40:38 +03:00
```
2022-03-17 01:39:08 +03:00
### Integrate with custom syntax `Highlighter`
2021-07-17 02:40:38 +03:00
2022-05-02 15:23:01 +03:00
```rust
2021-07-17 02:40:38 +03:00
// Create a reedline object with highlighter support
2022-01-02 22:26:30 +03:00
use reedline::{ExampleHighlighter, Reedline};
2021-06-15 02:03:57 +03:00
2021-07-17 02:40:38 +03:00
let commands = vec![
"test".into(),
"hello world".into(),
"hello world reedline".into(),
2021-07-18 21:05:54 +03:00
"this is the reedline crate".into(),
2021-07-17 02:40:38 +03:00
];
let mut line_editor =
2022-04-01 00:32:31 +03:00
Reedline::create().with_highlighter(Box::new(ExampleHighlighter::new(commands)));
2021-06-15 02:03:57 +03:00
```
2022-01-27 17:43:24 +03:00
### Integrate with custom tab completion
2021-06-15 02:03:57 +03:00
2022-05-02 15:23:01 +03:00
```rust
2021-07-17 02:40:38 +03:00
// Create a reedline object with tab completions support
2021-06-15 02:03:57 +03:00
2022-10-17 00:41:57 +03:00
use reedline::{default_emacs_keybindings, ColumnarMenu, DefaultCompleter, Emacs, KeyCode, KeyModifiers, Reedline, ReedlineEvent, ReedlineMenu};
2021-07-17 02:40:38 +03:00
let commands = vec![
"test".into(),
"hello world".into(),
"hello world reedline".into(),
2021-07-18 21:05:54 +03:00
"this is the reedline crate".into(),
2021-07-17 02:40:38 +03:00
];
let completer = Box::new(DefaultCompleter::new_with_wordlen(commands.clone(), 2));
2022-02-24 22:41:45 +03:00
// Use the interactive menu to select options from the completer
2022-05-02 15:23:01 +03:00
let completion_menu = Box::new(ColumnarMenu::default().with_name("completion_menu"));
2022-10-17 00:41:57 +03:00
// 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,
]),
);
2021-07-17 02:40:38 +03:00
2022-10-17 00:41:57 +03:00
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);
2021-07-17 02:40:38 +03:00
```
2021-06-15 02:03:57 +03:00
2022-03-17 01:39:08 +03:00
### Integrate with `Hinter` for fish-style history autosuggestions
2021-07-17 02:40:38 +03:00
2022-05-02 15:23:01 +03:00
```rust
2021-07-18 21:05:54 +03:00
// Create a reedline object with in-line hint support
2021-07-17 02:40:38 +03:00
//Cargo.toml
2022-01-27 17:43:24 +03:00
// [dependencies]
// nu-ansi-term = "*"
2021-07-17 02:40:38 +03:00
use {
nu_ansi_term::{Color, Style},
2022-01-20 21:25:40 +03:00
reedline::{DefaultHinter, Reedline},
2021-07-17 02:40:38 +03:00
};
2022-04-01 00:32:31 +03:00
let mut line_editor = Reedline::create().with_hinter(Box::new(
2021-07-17 02:40:38 +03:00
DefaultHinter::default()
.with_style(Style::new().italic().fg(Color::LightGray)),
));
```
2022-03-17 01:39:08 +03:00
### Integrate with custom line completion `Validator`
2021-09-23 22:40:32 +03:00
2022-05-02 15:23:01 +03:00
```rust
2021-09-23 22:40:32 +03:00
// Create a reedline object with line completion validation support
use reedline::{DefaultValidator, Reedline};
let validator = Box::new(DefaultValidator);
2022-04-01 00:32:31 +03:00
let mut line_editor = Reedline::create().with_validator(validator);
2021-09-23 22:40:32 +03:00
```
2022-05-02 15:23:01 +03:00
### Use custom `EditMode`
2021-07-17 02:40:38 +03:00
2022-05-02 15:23:01 +03:00
```rust
2021-07-17 02:40:38 +03:00
// Create a reedline object with custom edit mode
2022-05-02 15:23:01 +03:00
// This can define a keybinding setting or enable vi-emulation
2021-07-17 02:40:38 +03:00
2022-05-02 15:23:01 +03:00
use reedline::{
default_vi_insert_keybindings, default_vi_normal_keybindings, EditMode, Reedline, Vi,
};
2021-07-17 02:40:38 +03:00
2022-05-02 15:23:01 +03:00
let mut line_editor = Reedline::create().with_edit_mode(Box::new(Vi::new(
default_vi_insert_keybindings(),
default_vi_normal_keybindings(),
)));
2021-05-04 13:12:08 +03:00
```
2022-09-18 15:17:34 +03:00
## Crate features
- `clipboard` : Enable support to use the `SystemClipboard` . Enabling this feature will return a `SystemClipboard` instead of a local clipboard when calling `get_default_clipboard()` .
- `bashisms` : Enable support for special text sequences that recall components from the history. e.g. `!!` and `!$` . For use in shells like `bash` or [`nushell` ](https://nushell.sh ).
- `sqlite` : Provides the `SqliteBackedHistory` to store richer information in the history. Statically links the required sqlite version.
- `sqlite-dynlib` : Alternative to the feature `sqlite` . Will not statically link. Requires `sqlite >= 3.38` to link dynamically!
- `external_printer` : **Experimental:** Thread-safe `ExternalPrinter` handle to print lines from concurrently running threads.
2021-05-04 13:12:08 +03:00
## Are we prompt yet? (Development status)
2022-05-23 16:25:03 +03:00
Reedline has now all the basic features to become the primary line editor for [nushell](https://github.com/nushell/nushell
2022-03-17 01:39:08 +03:00
)
- 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 multiple 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 ](https://github.com/nushell/reedline/issues/63 ) or hop on the `#reedline` channel of the [nushell discord ](https://discordapp.com/invite/NtAbbGn ).
2021-05-04 13:12:08 +03:00
2022-03-17 01:39:08 +03:00
### Development history
2021-05-04 13:12:08 +03:00
2022-04-11 18:58:36 +03:00
If you want to follow along with the history of how reedline got started, you can watch the [recordings ](https://youtube.com/playlist?list=PLP2yfE2-FXdQw0I6O4YdIX_mzBeF5TDdv ) of [JT ](https://github.com/jntrnr )'s [live-coding streams ](https://www.twitch.tv/jntrnr ).
2021-07-18 21:05:54 +03:00
2022-03-17 01:39:08 +03:00
[Playlist: Creating a line editor in Rust ](https://youtube.com/playlist?list=PLP2yfE2-FXdQw0I6O4YdIX_mzBeF5TDdv )
2021-05-04 13:12:08 +03:00
### Alternatives
2021-06-14 09:35:40 +03:00
For currently more mature Rust line editing check out:
2021-05-04 13:12:08 +03:00
2021-06-14 09:35:40 +03:00
- [rustyline ](https://crates.io/crates/rustyline )