chore: optimize readline multiline

This commit is contained in:
sigoden 2023-03-12 07:54:18 +08:00
parent 4aab872ee1
commit 0ed0ad1fd2
3 changed files with 66 additions and 4 deletions

View File

@ -1,11 +1,13 @@
use super::{highlighter::ReplHighlighter, prompt::ReplPrompt, REPL_COMMANDS}; use super::{
highlighter::ReplHighlighter, prompt::ReplPrompt, validator::ReplValidator, REPL_COMMANDS,
};
use crate::config::{Config, SharedConfig}; use crate::config::{Config, SharedConfig};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use reedline::{ use reedline::{
default_emacs_keybindings, ColumnarMenu, DefaultCompleter, DefaultValidator, Emacs, default_emacs_keybindings, ColumnarMenu, DefaultCompleter, Emacs, FileBackedHistory, KeyCode,
FileBackedHistory, KeyCode, KeyModifiers, Keybindings, Reedline, ReedlineEvent, ReedlineMenu, KeyModifiers, Keybindings, Reedline, ReedlineEvent, ReedlineMenu,
}; };
const MENU_NAME: &str = "completion_menu"; const MENU_NAME: &str = "completion_menu";
@ -36,7 +38,7 @@ impl Repl {
.with_edit_mode(edit_mode) .with_edit_mode(edit_mode)
.with_quick_completions(true) .with_quick_completions(true)
.with_partial_completions(true) .with_partial_completions(true)
.with_validator(Box::new(DefaultValidator)) .with_validator(Box::new(ReplValidator))
.with_ansi_colors(true); .with_ansi_colors(true);
let prompt = ReplPrompt::new(config); let prompt = ReplPrompt::new(config);
Ok(Self { editor, prompt }) Ok(Self { editor, prompt })

View File

@ -3,6 +3,7 @@ mod handler;
mod highlighter; mod highlighter;
mod init; mod init;
mod prompt; mod prompt;
mod validator;
pub use self::abort::*; pub use self::abort::*;
pub use self::handler::*; pub use self::handler::*;

59
src/repl/validator.rs Normal file
View File

@ -0,0 +1,59 @@
use reedline::{ValidationResult, Validator};
/// A default validator which checks for mismatched quotes and brackets
pub struct ReplValidator;
impl Validator for ReplValidator {
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<char> = Vec::new();
let mut symbol = None;
for c in line.chars() {
match symbol {
Some(s) => match (s, c) {
('{', '}') | ('(', ')') => {
balance.pop();
}
_ if s == c => {
balance.push(c);
}
_ => {}
},
None => match c {
'{' | '(' => {
balance.push(c);
symbol = Some(c)
}
_ => {}
},
}
}
!balance.is_empty()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_incomplete_brackets() {
assert!(incomplete_brackets("{"));
assert!(incomplete_brackets("("));
assert!(!incomplete_brackets("{}"));
assert!(!incomplete_brackets("()"));
assert!(!incomplete_brackets("{ab\nc}"));
assert!(!incomplete_brackets("(ab\nc)"));
assert!(!incomplete_brackets("{[}"));
assert!(!incomplete_brackets("{{{{{}}}}}"));
assert!(incomplete_brackets("{{}"));
}
}