Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mutable Helper in functions #809

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ required-features = ["custom-bindings", "derive"]
name = "input_multiline"
required-features = ["custom-bindings", "derive"]
[[example]]
name = "bracket_parser"
required-features = ["derive"]
[[example]]
name = "input_validation"
required-features = ["derive"]
[[example]]
Expand Down
127 changes: 127 additions & 0 deletions examples/bracket_parser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use std::borrow::Cow;

use rustyline::highlight::Highlighter;
use rustyline::parse::{InputEdit, Parser};
use rustyline::validate::{ValidationContext, ValidationResult, Validator};
use rustyline::{Completer, Hinter};
use rustyline::{Editor, Helper, Result};

/// [Yellow, Cyan, BrightMagenta]
const BRACKET_COLORS: [u8; 3] = [33, 36, 95];
/// Red
const INVALID_COLOR: u8 = 31;
#[derive(Completer, Hinter)]
struct BarcketHelper {
bracket_level: i32,
color_indexs: Vec<(usize, u8)>,
/// re-render only when input just changed
/// not render after cursor moving
need_render: bool,
}

impl Helper for BarcketHelper {}

impl Parser for BarcketHelper {
/// Set `need_render = true`
///
/// Parse input once, update the parsed bracker results into `BarcketHelper` itself.
fn parse(&mut self, line: &str, _change: InputEdit) {
self.need_render = true;
let btyes = line.as_bytes();
self.bracket_level = (0..line.len()).fold(0, |level, pos| {
let c = btyes[pos];
if c == b'(' {
level + 1
} else if c == b')' {
level - 1
} else {
level
}
});
let mut level = 0;
self.color_indexs = (0..line.len())
.filter_map(|pos| {
let c = btyes[pos];
if c == b'(' {
let color = if self.bracket_level <= level {
TryInto::<usize>::try_into(level).map_or(INVALID_COLOR, |level| {
BRACKET_COLORS[level % BRACKET_COLORS.len()]
})
} else {
INVALID_COLOR
};
level += 1;
Some((pos, color))
} else if c == b')' {
level -= 1;
let color = TryInto::<usize>::try_into(level).map_or(INVALID_COLOR, |level| {
BRACKET_COLORS[level % BRACKET_COLORS.len()]
});
Some((pos, color))
} else {
None
}
})
.collect();
}
}

impl Validator for BarcketHelper {
/// Use the parsed bracker results to validate
fn validate(&mut self, _ctx: &mut ValidationContext) -> Result<ValidationResult> {
if self.bracket_level > 0 {
Ok(ValidationResult::Incomplete)
} else if self.bracket_level < 0 {
Ok(ValidationResult::Invalid(Some(format!(
" - excess {} close bracket",
-self.bracket_level
))))
} else {
Ok(ValidationResult::Valid(None))
}
}
}

impl Highlighter for BarcketHelper {
/// use `need_render` to decide whether to highlight again
fn highlight_char(&mut self, _line: &str, _pos: usize, _forced: bool) -> bool {
self.need_render
}
/// Set `need_render = false`
///
/// Use the parsed bracker results to highlight
fn highlight<'l>(&mut self, line: &'l str, _pos: usize) -> Cow<'l, str> {
self.need_render = false;
if self.color_indexs.is_empty() {
Cow::Borrowed(&line)
} else {
let mut out = String::new();
let mut last_idx = 0;
for (pos, color) in &self.color_indexs {
out += &format!(
"{}\x1b[1;{}m{}\x1b[m",
&line[last_idx..(*pos)],
color,
&line[(*pos)..=(*pos)],
);
last_idx = *pos + 1;
}
out += &line[last_idx..];
Cow::Owned(out)
}
}
}

fn main() -> Result<()> {
let h = BarcketHelper {
bracket_level: 0,
color_indexs: Vec::new(),
need_render: true,
};
let mut rl = Editor::new()?;
rl.set_helper(Some(h));
let input = rl.readline(">> ")?;
println!("Input: {input}");

Ok(())
}
8 changes: 4 additions & 4 deletions examples/custom_key_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ use rustyline::{
Cmd, ConditionalEventHandler, Editor, Event, EventContext, EventHandler, KeyEvent, RepeatCount,
Result,
};
use rustyline::{Completer, Helper, Hinter, Validator};
use rustyline::{Completer, Helper, Hinter, Parser, Validator};

#[derive(Completer, Helper, Hinter, Validator)]
#[derive(Completer, Helper, Hinter, Parser, Validator)]
struct MyHelper(#[rustyline(Hinter)] HistoryHinter);

impl Highlighter for MyHelper {
fn highlight_prompt<'b, 's: 'b, 'p: 'b>(
&'s self,
&'s mut self,
prompt: &'p str,
default: bool,
) -> Cow<'b, str> {
Expand All @@ -25,7 +25,7 @@ impl Highlighter for MyHelper {
}
}

fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
fn highlight_hint<'h>(&mut self, hint: &'h str) -> Cow<'h, str> {
Owned(format!("\x1b[1m{hint}\x1b[m"))
}
}
Expand Down
6 changes: 3 additions & 3 deletions examples/diy_hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use std::collections::HashSet;
use rustyline::hint::{Hint, Hinter};
use rustyline::history::DefaultHistory;
use rustyline::Context;
use rustyline::{Completer, Helper, Highlighter, Validator};
use rustyline::{Completer, Helper, Highlighter, Parser, Validator};
use rustyline::{Editor, Result};

#[derive(Completer, Helper, Validator, Highlighter)]
#[derive(Completer, Helper, Highlighter, Parser, Validator)]
struct DIYHinter {
// It's simple example of rustyline, for more efficient, please use ** radix trie **
hints: HashSet<CommandHint>,
Expand Down Expand Up @@ -52,7 +52,7 @@ impl CommandHint {
impl Hinter for DIYHinter {
type Hint = CommandHint;

fn hint(&self, line: &str, pos: usize, _ctx: &Context<'_>) -> Option<CommandHint> {
fn hint(&mut self, line: &str, pos: usize, _ctx: &Context<'_>) -> Option<CommandHint> {
if line.is_empty() || pos < line.len() {
return None;
}
Expand Down
12 changes: 6 additions & 6 deletions examples/example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use rustyline::highlight::{Highlighter, MatchingBracketHighlighter};
use rustyline::hint::HistoryHinter;
use rustyline::validate::MatchingBracketValidator;
use rustyline::{Cmd, CompletionType, Config, EditMode, Editor, KeyEvent};
use rustyline::{Completer, Helper, Hinter, Validator};
use rustyline::{Completer, Helper, Hinter, Parser, Validator};

#[derive(Helper, Completer, Hinter, Validator)]
#[derive(Completer, Helper, Hinter, Parser, Validator)]
struct MyHelper {
#[rustyline(Completer)]
completer: FilenameCompleter,
Expand All @@ -22,7 +22,7 @@ struct MyHelper {

impl Highlighter for MyHelper {
fn highlight_prompt<'b, 's: 'b, 'p: 'b>(
&'s self,
&'s mut self,
prompt: &'p str,
default: bool,
) -> Cow<'b, str> {
Expand All @@ -33,15 +33,15 @@ impl Highlighter for MyHelper {
}
}

fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
fn highlight_hint<'h>(&mut self, hint: &'h str) -> Cow<'h, str> {
Owned("\x1b[1m".to_owned() + hint + "\x1b[m")
}

fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> {
fn highlight<'l>(&mut self, line: &'l str, pos: usize) -> Cow<'l, str> {
self.highlighter.highlight(line, pos)
}

fn highlight_char(&self, line: &str, pos: usize, forced: bool) -> bool {
fn highlight_char(&mut self, line: &str, pos: usize, forced: bool) -> bool {
self.highlighter.highlight_char(line, pos, forced)
}
}
Expand Down
4 changes: 2 additions & 2 deletions examples/input_multiline.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use rustyline::highlight::MatchingBracketHighlighter;
use rustyline::validate::MatchingBracketValidator;
use rustyline::{Cmd, Editor, EventHandler, KeyCode, KeyEvent, Modifiers, Result};
use rustyline::{Completer, Helper, Highlighter, Hinter, Validator};
use rustyline::{Completer, Helper, Highlighter, Hinter, Parser, Validator};

#[derive(Completer, Helper, Highlighter, Hinter, Validator)]
#[derive(Completer, Helper, Highlighter, Hinter, Parser, Validator)]
struct InputValidator {
#[rustyline(Validator)]
brackets: MatchingBracketValidator,
Expand Down
6 changes: 3 additions & 3 deletions examples/input_validation.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use rustyline::validate::{ValidationContext, ValidationResult, Validator};
use rustyline::{Completer, Helper, Highlighter, Hinter};
use rustyline::{Completer, Helper, Highlighter, Hinter, Parser};
use rustyline::{Editor, Result};

#[derive(Completer, Helper, Highlighter, Hinter)]
#[derive(Completer, Helper, Highlighter, Hinter, Parser)]
struct InputValidator {}

impl Validator for InputValidator {
fn validate(&self, ctx: &mut ValidationContext) -> Result<ValidationResult> {
fn validate(&mut self, ctx: &mut ValidationContext) -> Result<ValidationResult> {
use ValidationResult::{Incomplete, Invalid, Valid};
let input = ctx.input();
let result = if !input.starts_with("SELECT") {
Expand Down
8 changes: 4 additions & 4 deletions examples/read_password.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ use std::borrow::Cow::{self, Borrowed, Owned};
use rustyline::config::Configurer;
use rustyline::highlight::Highlighter;
use rustyline::{ColorMode, Editor, Result};
use rustyline::{Completer, Helper, Hinter, Validator};
use rustyline::{Completer, Helper, Hinter, Parser, Validator};

#[derive(Completer, Helper, Hinter, Validator)]
#[derive(Completer, Helper, Hinter, Parser, Validator)]
struct MaskingHighlighter {
masking: bool,
}

impl Highlighter for MaskingHighlighter {
fn highlight<'l>(&self, line: &'l str, _pos: usize) -> Cow<'l, str> {
fn highlight<'l>(&mut self, line: &'l str, _pos: usize) -> Cow<'l, str> {
use unicode_width::UnicodeWidthStr;
if self.masking {
Owned(" ".repeat(line.width()))
Expand All @@ -20,7 +20,7 @@ impl Highlighter for MaskingHighlighter {
}
}

fn highlight_char(&self, _line: &str, _pos: usize, _forced: bool) -> bool {
fn highlight_char(&mut self, _line: &str, _pos: usize, _forced: bool) -> bool {
self.masking
}
}
Expand Down
Loading