blob: 1047719b9ffe0b7973a181fee2115e2396af28a3 [file] [view]
# line-editor
`line-editor` is a lightweight line-editing library for Fuchsia. It provides
single-line and multi-line terminal line editing, history management, tab
completion, inline hints with ANSI colors, and VT100 terminal escape sequence
keybindings.
## Features
- **Binary String API**: Works natively with `bstr::BString` and `bstr::BStr`
without requiring UTF-8 validation.
- **Generic Stream Support**: Operates on any `std::io::Read` and
`std::io::Write` streams, standard I/O (`stdin`/`stdout`), or pipe handles.
- **History Management**: In-memory history with deduplication and maximum entry
bounds. Callers can manually record history entries using `editor.add_history(...)`.
- **Tab Completion**: Register custom completion handlers (`CompletionHandler`
or closures) for tab autocompletion.
- **Inline Hints**: Register custom hint callbacks (`HintHandler`) with
optional ANSI foreground colors (`Color`) and bold formatting.
- **Single-Line & Multi-Line Modes**: Supports horizontal scrolling single-line
mode as well as automatic multi-line wrapping.
- **VT100 & Emacs Keybindings**:
- `Ctrl-A` / `Home`: Move to start of line
- `Ctrl-E` / `End`: Move to end of line
- `Ctrl-B` / `Left Arrow`: Move cursor left
- `Ctrl-F` / `Right Arrow`: Move cursor right
- `Ctrl-P` / `Up Arrow`: Navigate back in history
- `Ctrl-N` / `Down Arrow`: Navigate forward in history
- `Ctrl-K`: Kill text to end of line
- `Ctrl-U`: Clear entire line
- `Ctrl-W`: Delete previous word
- `Ctrl-T`: Transpose characters
- `Ctrl-L`: Clear screen
- `Ctrl-C`: Interrupt (`ReadlineError::Interrupted`)
- `Ctrl-D`: EOF on empty line (`ReadlineError::Eof`) or delete character
## Usage
### Simple Standalone Readline
```rust
use line_editor::readline;
fn main() -> Result<(), line_editor::ReadlineError> {
let line = readline("prompt> ")?;
println!("Entered: {}", line);
Ok(())
}
```
### Advanced Usage with `Editor`
```rust
use bstr::{BStr, BString};
use line_editor::{Color, Config, Editor, Hint, ReadlineError};
fn main() -> Result<(), ReadlineError> {
let mut editor = Editor::with_config(Config {
max_history_len: 100,
multiline_mode: true,
max_line_len: 4096,
..Default::default()
});
// Register a completion handler
editor.set_completion_handler(|line: &BStr| {
if line.starts_with(b"h") {
vec![BString::from("hello"), BString::from("help")]
} else {
vec![]
}
});
// Register a hint handler
editor.set_hint_handler(|line: &BStr| {
if line == b"hello" {
Some(Hint::new(" world").with_color(Color::Green).with_bold(true))
} else {
None
}
});
// Read lines from stdin/stdout in an interactive loop
while let Ok(line) = editor.readline("app> ") {
if !line.is_empty() {
// Record non-empty lines in history
editor.add_history(&line);
}
println!("Read line: {}", line);
}
Ok(())
}
```
### Managing History
You can access and modify the editor's history directly via `editor.history()`
and `editor.history_mut()`:
```rust
use line_editor::Editor;
let mut editor = Editor::new();
editor.add_history("first command");
editor.add_history("second command");
println!("History count: {}", editor.history().len());
for entry in editor.history().entries() {
println!(" {}", entry);
}
// Clear all history entries
editor.history_mut().clear();
```
### Reading from Custom Streams
```rust
use line_editor::{Editor, OperatingMode};
fn read_from_stream(mut reader: impl std::io::Read, mut writer: impl std::io::Write) {
let mut editor = Editor::new();
let line = editor.readline_from(
&mut reader,
&mut writer,
OperatingMode::Interactive,
"stream> ",
);
}
```
## Testing
Run unit tests with `fx`:
```bash
fx test line-editor-tests
```