reedline/examples/ide_completions.rs
maxomatic458 c8a52a85f1
menu refactor (#723)
* get correct cursor pos when menu indicator contains newline

* add tests

* fix cursor pos in multiline prompt

* make description mode enum public

* add doc comment

* respect windows newline in update_values

* Revert "respect windows newline in update_values"

This reverts commit 070d600545.

* add complete_with_base_ranges to Completer

* add builder for correct_cursor_pos

* add config options to completion examples

* add style to ide menu

* run fmt

* start menu refactor

* Revert "start menu refactor"

This reverts commit 62726f29be.

* start menu refactor

* fix ci

* use MenuSettings struct

* add test case for unix newline

* more tests

* fix newline replace

* add explicit panic to stay backwards compatible

* fix ci

* Update columnar_menu.rs

Co-authored-by: Yash Thakur <45539777+ysthakur@users.noreply.github.com>

---------

Co-authored-by: Yash Thakur <45539777+ysthakur@users.noreply.github.com>
2024-01-28 08:01:16 -08:00

132 lines
4.5 KiB
Rust

// Create a reedline object with tab completions support
// cargo run --example completions
//
// "t" [Tab] will allow you to select the completions "test" and "this is the reedline crate"
// [Enter] to select the chosen alternative
use reedline::{
default_emacs_keybindings, DefaultCompleter, DefaultPrompt, DescriptionMode, EditCommand,
Emacs, IdeMenu, KeyCode, KeyModifiers, Keybindings, MenuBuilder, Reedline, ReedlineEvent,
ReedlineMenu, Signal,
};
use std::io;
fn add_menu_keybindings(keybindings: &mut Keybindings) {
keybindings.add_binding(
KeyModifiers::NONE,
KeyCode::Tab,
ReedlineEvent::UntilFound(vec![
ReedlineEvent::Menu("completion_menu".to_string()),
ReedlineEvent::MenuNext,
]),
);
keybindings.add_binding(
KeyModifiers::ALT,
KeyCode::Enter,
ReedlineEvent::Edit(vec![EditCommand::InsertNewline]),
);
}
fn main() -> io::Result<()> {
// Min width of the completion box, including the border
let min_completion_width: u16 = 0;
// Max width of the completion box, including the border
let max_completion_width: u16 = 50;
// Max height of the completion box, including the border
let max_completion_height = u16::MAX;
// Padding inside of the completion box (on the left and right side)
let padding: u16 = 0;
// Whether to draw the default border around the completion box
let border: bool = false;
// Offset of the cursor from the top left corner of the completion box
// By default the top left corner is below the cursor
let cursor_offset: i16 = 0;
// How the description should be aligned
let description_mode: DescriptionMode = DescriptionMode::PreferRight;
// Min width of the description box, including the border
let min_description_width: u16 = 0;
// Max width of the description box, including the border
let max_description_width: u16 = 50;
// Distance between the completion and the description box
let description_offset: u16 = 1;
// If true, the cursor pos will be corrected, so the suggestions match up with the typed text
// ```text
// C:\> str
// str join
// str trim
// str split
// ```
// If a border is being used
let correct_cursor_pos: bool = false;
let commands = vec![
"test".into(),
"clear".into(),
"exit".into(),
"history 1".into(),
"history 2".into(),
"logout".into(),
"login".into(),
"hello world".into(),
"hello world reedline".into(),
"hello world something".into(),
"hello world another".into(),
"hello world 1".into(),
"hello world 2".into(),
"hello another very large option for hello word that will force one column".into(),
"this is the reedline crate".into(),
"abaaabas".into(),
"abaaacas".into(),
"ababac".into(),
"abacaxyc".into(),
"abadarabc".into(),
];
let completer = Box::new(DefaultCompleter::new_with_wordlen(commands, 2));
// Use the interactive menu to select options from the completer
let mut ide_menu = IdeMenu::default()
.with_name("completion_menu")
.with_min_completion_width(min_completion_width)
.with_max_completion_width(max_completion_width)
.with_max_completion_height(max_completion_height)
.with_padding(padding)
.with_cursor_offset(cursor_offset)
.with_description_mode(description_mode)
.with_min_description_width(min_description_width)
.with_max_description_width(max_description_width)
.with_description_offset(description_offset)
.with_correct_cursor_pos(correct_cursor_pos);
if border {
ide_menu = ide_menu.with_default_border();
}
let completion_menu = Box::new(ide_menu);
let mut keybindings = default_emacs_keybindings();
add_menu_keybindings(&mut keybindings);
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);
let prompt = DefaultPrompt::default();
loop {
let sig = line_editor.read_line(&prompt)?;
match sig {
Signal::Success(buffer) => {
println!("We processed: {buffer}");
}
Signal::CtrlD | Signal::CtrlC => {
println!("\nAborted!");
break Ok(());
}
}
}
}