diff --git a/src/bin/relish.rs b/src/bin/relish.rs index 1268382..1226843 100644 --- a/src/bin/relish.rs +++ b/src/bin/relish.rs @@ -42,7 +42,7 @@ use { Reedline, Signal, Prompt, PromptEditMode, PromptHistorySearch, PromptHistorySearchStatus, Completer, Suggestion, Span, KeyModifiers, KeyCode, ReedlineEvent, Keybindings, - ColumnarMenu, Emacs, ReedlineMenu, + ColumnarMenu, Emacs, ReedlineMenu, Validator, ValidationResult, default_emacs_keybindings, }, nu_ansi_term::{Color, Style}, @@ -61,6 +61,8 @@ pub struct CustomPrompt(String, String, String); #[derive(Clone)] pub struct CustomCompleter(Vec); +pub struct CustomValidator; + impl Prompt for CustomPrompt { fn render_prompt_left(&self) -> Cow { { @@ -221,6 +223,51 @@ impl Completer for CustomCompleter { } } +impl Validator for CustomValidator { + fn validate(&self, line: &str) -> ValidationResult { + if incomplete_brackets(line) { + ValidationResult::Incomplete + } else { + ValidationResult::Complete + } + } +} + +fn incomplete_brackets(line: &str) -> bool { + let mut balance: Vec = Vec::new(); + let mut within_string: Option = None; + + for c in line.chars() { + match c { + c if ['"', '`', '\''].contains(&c) => { + match within_string { + Some(w) if c == w => { + balance.pop(); + within_string = None + } + Some(_) => {}, + None => { + balance.push(c); + within_string = Some(c) + }, + } + }, + + '(' if within_string.is_none() => balance.push(')'), + + ')' => if let Some(last) = balance.last() { + if last == &c { + balance.pop(); + } + }, + + _ => {} + } + } + + !balance.is_empty() +} + fn add_menu_keybindings(keybindings: &mut Keybindings) { keybindings.add_binding( KeyModifiers::NONE, @@ -313,7 +360,7 @@ fn main() { rl = rl.with_hinter(Box::new( DefaultHinter::default() .with_style(Style::new().italic().fg(Color::LightGray)), - )).with_validator(Box::new(DefaultValidator)); + )).with_validator(Box::new(CustomValidator)); let mut xdimension: u16 = 0; let mut ydimension: u16 = 0;