-
Notifications
You must be signed in to change notification settings - Fork 178
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #492 from gwenn/conditional_binding2
Conditional binding
- Loading branch information
Showing
11 changed files
with
534 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
use smallvec::smallvec; | ||
use std::borrow::Cow::{self, Borrowed, Owned}; | ||
|
||
use rustyline::highlight::Highlighter; | ||
use rustyline::hint::{Hinter, HistoryHinter}; | ||
use rustyline::{ | ||
Cmd, ConditionalEventHandler, Context, Editor, Event, EventContext, EventHandler, KeyEvent, | ||
RepeatCount, | ||
}; | ||
use rustyline_derive::{Completer, Helper, Validator}; | ||
|
||
#[derive(Completer, Helper, Validator)] | ||
struct MyHelper(HistoryHinter); | ||
|
||
impl Hinter for MyHelper { | ||
type Hint = String; | ||
|
||
fn hint(&self, line: &str, pos: usize, ctx: &Context<'_>) -> Option<String> { | ||
self.0.hint(line, pos, ctx) | ||
} | ||
} | ||
|
||
impl Highlighter for MyHelper { | ||
fn highlight_prompt<'b, 's: 'b, 'p: 'b>( | ||
&'s self, | ||
prompt: &'p str, | ||
default: bool, | ||
) -> Cow<'b, str> { | ||
if default { | ||
Owned(format!("\x1b[1;32m{}\x1b[m", prompt)) | ||
} else { | ||
Borrowed(prompt) | ||
} | ||
} | ||
|
||
fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> { | ||
Owned(format!("\x1b[1m{}\x1b[m", hint)) | ||
} | ||
} | ||
|
||
#[derive(Clone)] | ||
struct CompleteHintHandler; | ||
impl ConditionalEventHandler for CompleteHintHandler { | ||
fn handle(&self, evt: &Event, _: RepeatCount, _: bool, ctx: &EventContext) -> Option<Cmd> { | ||
if !ctx.has_hint() { | ||
return None; // default | ||
} | ||
if let Some(k) = evt.get(0) { | ||
#[allow(clippy::if_same_then_else)] | ||
if *k == KeyEvent::ctrl('E') { | ||
Some(Cmd::CompleteHint) | ||
} else if *k == KeyEvent::alt('f') && ctx.line().len() == ctx.pos() { | ||
Some(Cmd::CompleteHint) // TODO give access to hint | ||
} else { | ||
None | ||
} | ||
} else { | ||
unreachable!() | ||
} | ||
} | ||
} | ||
|
||
struct TabEventHandler; | ||
impl ConditionalEventHandler for TabEventHandler { | ||
fn handle(&self, evt: &Event, n: RepeatCount, _: bool, ctx: &EventContext) -> Option<Cmd> { | ||
debug_assert_eq!(*evt, Event::from(KeyEvent::from('\t'))); | ||
if ctx.line()[..ctx.pos()] | ||
.chars() | ||
.rev() | ||
.next() | ||
.filter(|c| c.is_whitespace()) | ||
.is_some() | ||
{ | ||
Some(Cmd::SelfInsert(n, '\t')) | ||
} else { | ||
None // default complete | ||
} | ||
} | ||
} | ||
|
||
fn main() { | ||
let mut rl = Editor::<MyHelper>::new(); | ||
rl.set_helper(Some(MyHelper(HistoryHinter {}))); | ||
|
||
let ceh = Box::new(CompleteHintHandler); | ||
rl.bind_sequence(KeyEvent::ctrl('E'), EventHandler::Conditional(ceh.clone())); | ||
rl.bind_sequence(KeyEvent::alt('f'), EventHandler::Conditional(ceh)); | ||
rl.bind_sequence( | ||
KeyEvent::from('\t'), | ||
EventHandler::Conditional(Box::new(TabEventHandler)), | ||
); | ||
rl.bind_sequence( | ||
Event::KeySeq(smallvec![KeyEvent::ctrl('X'), KeyEvent::ctrl('E')]), | ||
EventHandler::Simple(Cmd::Suspend), // TODO external editor | ||
); | ||
|
||
loop { | ||
let readline = rl.readline("> "); | ||
match readline { | ||
Ok(line) => { | ||
rl.add_history_entry(line.as_str()); | ||
println!("Line: {}", line); | ||
} | ||
Err(err) => { | ||
println!("Error: {:?}", err); | ||
break; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
use rustyline::{ | ||
Cmd, ConditionalEventHandler, Editor, Event, EventContext, EventHandler, KeyCode, KeyEvent, | ||
Modifiers, RepeatCount, | ||
}; | ||
|
||
struct FilteringEventHandler; | ||
impl ConditionalEventHandler for FilteringEventHandler { | ||
fn handle(&self, evt: &Event, _: RepeatCount, _: bool, _: &EventContext) -> Option<Cmd> { | ||
if let Some(KeyEvent(KeyCode::Char(c), m)) = evt.get(0) { | ||
if m.contains(Modifiers::CTRL) || m.contains(Modifiers::ALT) || c.is_ascii_digit() { | ||
None | ||
} else { | ||
Some(Cmd::Noop) // filter out invalid input | ||
} | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
|
||
fn main() { | ||
let mut rl = Editor::<()>::new(); | ||
|
||
rl.bind_sequence( | ||
Event::Any, | ||
EventHandler::Conditional(Box::new(FilteringEventHandler)), | ||
); | ||
|
||
loop { | ||
let readline = rl.readline("> "); | ||
match readline { | ||
Ok(line) => { | ||
println!("Num: {}", line); | ||
} | ||
Err(err) => { | ||
println!("Error: {:?}", err); | ||
break; | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.