diff options
author | Canop <cano.petrole@gmail.com> | 2020-06-01 10:14:28 +0200 |
---|---|---|
committer | Canop <cano.petrole@gmail.com> | 2020-06-01 10:14:28 +0200 |
commit | f9a75313b16378e61b64ee36c3bd829397642032 (patch) | |
tree | 6f15446a49da49e7228537ba5acf7c4a5fbf8601 /src | |
parent | 928365ae4bf4370b6bed57de1488d347fc5cc644 (diff) |
[WIP] refactoring for new pattern syntax
Diffstat (limited to 'src')
-rw-r--r-- | src/app/state.rs | 24 | ||||
-rw-r--r-- | src/browser/browser_state.rs | 38 | ||||
-rw-r--r-- | src/command/command.rs | 14 | ||||
-rw-r--r-- | src/command/mod.rs | 2 | ||||
-rw-r--r-- | src/command/parts.rs | 91 | ||||
-rw-r--r-- | src/command/pattern_parts.rs | 24 | ||||
-rw-r--r-- | src/command/sequence.rs | 8 | ||||
-rw-r--r-- | src/errors.rs | 9 | ||||
-rw-r--r-- | src/pattern/pattern.rs | 17 | ||||
-rw-r--r-- | src/pattern/regex_patterns.rs | 10 |
10 files changed, 135 insertions, 102 deletions
diff --git a/src/app/state.rs b/src/app/state.rs index 1c75c1d..254e970 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -5,6 +5,7 @@ use { display::{Areas, Screen, W}, errors::ProgramError, flag::Flag, + pattern::Pattern, selection_type::SelectionType, skin::PanelSkin, task_sync::Dam, @@ -40,18 +41,9 @@ pub trait AppState { Ok(AppStateCmdResult::Keep) } - fn on_fuzzy_pattern_edit( + fn on_pattern( &mut self, - _pat: &str, - _con: &AppContext, - ) -> Result<AppStateCmdResult, ProgramError> { - Ok(AppStateCmdResult::Keep) - } - - fn on_regex_pattern_edit( - &mut self, - _pat: &str, - _flags: &str, + _pat: Pattern, _con: &AppContext, ) -> Result<AppStateCmdResult, ProgramError> { Ok(AppStateCmdResult::Keep) @@ -89,8 +81,14 @@ pub trait AppState { match cmd { Command::Click(x, y) => self.on_click(*x, *y, screen, con), Command::DoubleClick(x, y) => self.on_double_click(*x, *y, screen, con), - Command::FuzzyPatternEdit(pat) => self.on_fuzzy_pattern_edit(pat, con), - Command::RegexEdit(pat, flags) => self.on_regex_pattern_edit(pat, flags, con), + Command::PatternEdit(parts) => { + match Pattern::from_parts(parts, con) { + Ok(pattern) => self.on_pattern(pattern, con), + Err(e) => Ok(AppStateCmdResult::DisplayError(format!("{}", e))), + } + } + // Command::FuzzyPatternEdit(pat) => self.on_fuzzy_pattern_edit(pat, con), + // Command::RegexEdit(pat, flags) => self.on_regex_pattern_edit(pat, flags, con), Command::VerbTrigger { index, input_invocation, diff --git a/src/browser/browser_state.rs b/src/browser/browser_state.rs index 0426b58..c06ab01 100644 --- a/src/browser/browser_state.rs +++ b/src/browser/browser_state.rs @@ -265,10 +265,7 @@ impl AppState for BrowserState { con: &AppContext, ) -> Status { match cmd { - Command::FuzzyPatternEdit(s) if !s.is_empty() => { - Status::new(self.normal_status_message(true), false) - } - Command::RegexEdit(s, _) if !s.is_empty() => { + Command::PatternEdit(_) => { Status::new(self.normal_status_message(true), false) } Command::VerbEdit(invocation) => { @@ -344,40 +341,19 @@ impl AppState for BrowserState { } } - fn on_fuzzy_pattern_edit( + + fn on_pattern( &mut self, - pat: &str, + pat: Pattern, _con: &AppContext, ) -> Result<AppStateCmdResult, ProgramError> { - match pat.len() { - 0 => { - self.filtered_tree = None; - } - _ => { - self.pending_pattern = Pattern::fuzzy(pat); - } + if !pat.is_some() { + self.filtered_tree = None; } + self.pending_pattern = pat; Ok(AppStateCmdResult::Keep) } - fn on_regex_pattern_edit( - &mut self, - pat: &str, - flags: &str, - _con: &AppContext, - ) -> Result<AppStateCmdResult, ProgramError> { - Ok(match Pattern::regex(pat, flags) { - Ok(regex_pattern) => { - self.pending_pattern = regex_pattern; - AppStateCmdResult::Keep - } - Err(e) => { - // FIXME details - AppStateCmdResult::DisplayError(format!("{}", e)) - } - }) - } - fn on_internal( &mut self, internal_exec: &InternalExecution, diff --git a/src/command/command.rs b/src/command/command.rs index 3255a3a..1da90c6 100644 --- a/src/command/command.rs +++ b/src/command/command.rs @@ -39,10 +39,7 @@ pub enum Command { }, /// a pattern being edited - FuzzyPatternEdit(String), - - /// a regex being edited (core & flags) - RegexEdit(String, String), + PatternEdit(PatternParts), /// a mouse click Click(u16, u16), @@ -76,14 +73,9 @@ impl Command { input_invocation: None, } } else if let Some(pattern) = &cp.pattern { - let pattern = String::from(pattern.as_str()); - if let Some(regex_flags) = &cp.regex_flags { - Self::RegexEdit(pattern, String::from(regex_flags.as_str())) - } else { - Self::FuzzyPatternEdit(String::from(pattern.as_str())) - } + Self::PatternEdit(pattern.clone()) } else { - Self::FuzzyPatternEdit(String::from("")) + Self::PatternEdit(PatternParts::default()) } } diff --git a/src/command/mod.rs b/src/command/mod.rs index 19c5e19..85ba99e 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -1,6 +1,7 @@ mod command; mod completion; mod event; +mod pattern_parts; mod parts; mod sequence; mod trigger_type; @@ -10,6 +11,7 @@ pub use { completion::Completions, event::PanelInput, parts::CommandParts, + pattern_parts::PatternParts, sequence::parse_command_sequence, trigger_type::TriggerType, }; diff --git a/src/command/parts.rs b/src/command/parts.rs index 6fffbe2..c27e704 100644 --- a/src/command/parts.rs +++ b/src/command/parts.rs @@ -1,23 +1,20 @@ use { + super::PatternParts, crate::verb::VerbInvocation, std::fmt, }; /// An intermediate parsed representation of the raw string -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct CommandParts { - pub pattern: Option<String>, // either a fuzzy pattern or the core of a regex - pub regex_flags: Option<String>, // may be Some("") if user asked for a regex but specified no flag + pub pattern: Option<PatternParts>, // pub verb_invocation: Option<VerbInvocation>, // may be empty if user typed the separator but no char after } impl fmt::Display for CommandParts { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(pattern) = &self.pattern { - write!(f, "{}", pattern)?; - if let Some(flags) = &self.regex_flags { - write!(f, "/{}", flags)?; - } + pattern.fmt(f)?; } if let Some(invocation) = &self.verb_invocation { write!(f, "{}", invocation)?; @@ -31,7 +28,6 @@ impl CommandParts { pub fn new() -> CommandParts { CommandParts { pattern: None, - regex_flags: None, verb_invocation: None, } } @@ -41,9 +37,9 @@ impl CommandParts { let c = regex!( r"(?x) ^ - (?P<slash_before>/)? + (?:(?P<search_mode>\w*)/)? (?P<pattern>[^\s/:]+)? - (?:/(?P<regex_flags>\w*))? + (?:/(?P<pattern_flags>\w*))? (?:[\s:]+(?P<verb_invocation>.*))? $ " @@ -51,21 +47,19 @@ impl CommandParts { .captures(raw); if let Some(c) = c { if let Some(pattern) = c.name("pattern") { - cp.pattern = Some(String::from(pattern.as_str())); - if let Some(rxf) = c.name("regex_flags") { - cp.regex_flags = Some(String::from(rxf.as_str())); - } else if c.name("slash_before").is_some() { - cp.regex_flags = Some("".into()); - } + cp.pattern = Some(PatternParts { + mode: c.name("search_mode").map(|c| c.as_str().to_string()), + pattern: pattern.as_str().to_string(), + flags: c.name("pattern_flags").map(|c| c.as_str().to_string()), + }); } if let Some(verb) = c.name("verb_invocation") { cp.verb_invocation = Some(VerbInvocation::from(verb.as_str())); } } else { // Non matching pattterns include "///" - // We decide the whole is a fuzzy search pattern, in this case - // (this will change when we release the new input syntax) - cp.pattern = Some(String::from(raw)); + // We decide the whole is a search pattern, in this case + cp.pattern = Some(PatternParts::default()) } cp } @@ -73,24 +67,19 @@ impl CommandParts { /// split an input into its two possible parts, the pattern /// and the verb invocation. Each part, when defined, is /// suitable to create a command on its own. - pub fn split(raw: &str) -> (Option<String>, Option<String>) { - let captures = regex!( - r"(?x) - ^ - (?P<pattern_part>/?[^\s/:]+/?\w*)? - (?P<verb_part>[\s:]+(.+))? - $ - " - ) - .captures(raw) - .unwrap(); // all parts optional : always captures + pub fn split(mut self) -> (Option<CommandParts>, Option<CommandParts>) { ( - captures - .name("pattern_part") - .map(|c| c.as_str().to_string()), - captures.name("verb_part").map(|c| c.as_str().to_string()), + self.pattern.take().map(|p| CommandParts { + pattern: Some(p), + verb_invocation: None, + }), + self.verb_invocation.take().map(|inv| CommandParts { + pattern: None, + verb_invocation: Some(inv), + }), ) } + } impl Default for CommandParts { @@ -98,3 +87,37 @@ impl Default for CommandParts { CommandParts::new() } } + +#[cfg(test)] +mod command_parsing_tests { + use super::*; + fn check( + raw: &str, + search_mode: Option<&str>, + pattern: Option<&str>, + pattern_flags: Option<&str>, + verb_invocation: Option<&str>, + ) { + println!("checking {:?}", raw); + let left = CommandParts::from(raw); + let right = CommandParts { + search_mode: search_mode.map(|c| c.to_string()), + pattern: pattern.map(|c| c.to_string()), + pattern_flags: pattern_flags.map(|c| c.to_string()), + verb_invocation: verb_invocation.map(|s| VerbInvocation::from(s)), + }; + assert_eq!(left, right); + } + #[test] + fn test_command_parsing() { + check("pat", None, Some("pat"), None, None); + check("pat ", None, Some("pat"), None, Some("")); + check(" verb arg1 arg2", None, None, None, Some("verb arg1 arg2")); + check(" verb ", None, None, None, Some("verb ")); + check("pat verb ", None, Some("pat"), None, Some("verb ")); + check("/pat/i verb ", Some(""), Some("pat"), Some("i"), Some("verb ")); + check("/pat/:verb ", Some(""), Some("pat"), Some(""), Some("verb ")); + check("/pat", Some(""), Some("pat"), None, None); + check("p/pat", Some("p"), Some("pat"), None, None); + } +} diff --git a/src/command/pattern_parts.rs b/src/command/pattern_parts.rs new file mode 100644 index 0000000..2b993bf --- /dev/null +++ b/src/command/pattern_parts.rs @@ -0,0 +1,24 @@ +use { + std::fmt, +}; + +/// An intermediate parsed representation of the raw string +#[derive(Debug, Clone, PartialEq, Default)] +pub struct PatternParts { + pub mode: Option<String>, // may be Some("") if the user typed `/pat` + pub pattern: String, // either a fuzzy pattern or the core of a regex + pub flags: Option<String>, // may be Some("") if user asked for a regex but specified no flag +} + +impl fmt::Display for PatternParts { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(mode) = &self.mode { + write!(f, "{}/", mode)?; + } + write!(f, "{}", self.pattern)?; + if let Some(flags) = &self.flags { + write!(f, "/{}", flags)?; + } + Ok(()) + } +} diff --git a/src/command/sequence.rs b/src/command/sequence.rs index 1ffefb8..78ebf57 100644 --- a/src/command/sequence.rs +++ b/src/command/sequence.rs @@ -33,14 +33,15 @@ pub fn parse_command_sequence<'a>( // we need to build a command for each part so // that the search is effectively done before // the verb invocation - let (pattern, verb_invocation) = CommandParts::split(input); + let raw_parts = CommandParts::from(input); + let (pattern, verb_invocation) = raw_parts.split(); if let Some(pattern) = pattern { debug!("adding pattern: {:?}", pattern); - commands.push((input, Command::from_raw(pattern, false))); + commands.push((input, Command::from_parts(&pattern, false))); } if let Some(verb_invocation) = verb_invocation { debug!("adding verb_invocation: {:?}", verb_invocation); - let command = Command::from_raw(verb_invocation, true); + let command = Command::from_parts(&verb_invocation, true); if let Command::VerbInvocate(invocation) = &command { // we check that the verb exists to avoid running a sequence // of actions with some missing @@ -63,3 +64,4 @@ pub fn parse_command_sequence<'a>( } Ok(commands) } + diff --git a/src/errors.rs b/src/errors.rs index 02dd50d..950cd8e 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -36,13 +36,12 @@ custom_error! {pub ConfError UnexpectedInternalArg { invocation: String} = "unexpected argument for internal: {}", } -// error which can be raised when parsing a regex the -// user typed -custom_error! {pub RegexError - Parsing {source: regex::Error} = @{ +// error which can be raised when parsing a pattern the user typed +custom_error! {pub PatternError + InvalidRegex {source: regex::Error} = @{ format!("Invalid Regular Expression: {}", source.to_string().lines().last().unwrap_or("")) }, - UnknownFlag {bad: char} = "Unknown regular expression flag: {:?}", + UnknownRegexFlag {bad: char} = "Unknown regular expression flag: {:?}", } custom_error! {pub InvalidSkinError diff --git a/src/pattern/pattern.rs b/src/pattern/pattern.rs index 8b47549..f548503 100644 --- a/src/pattern/pattern.rs +++ b/src/pattern/pattern.rs @@ -5,7 +5,11 @@ use { super::{FuzzyPattern, RegexPattern}, - crate::errors::RegexError, + crate::{ + app::AppContext, + command::PatternParts, + errors::PatternError, + }, std::{fmt, mem}, }; @@ -27,12 +31,21 @@ impl fmt::Display for Pattern { } impl Pattern { + pub fn from_parts(parts: &PatternParts, con: &AppContext) -> Result<Pattern, PatternError> { + if parts.pattern.is_empty() { + Ok(Self::None) + } else if let Some(flags) = &parts.flags { + Self::regex(&parts.pattern, flags) + } else { + Ok(Self::fuzzy(&parts.pattern)) + } + } /// create a new fuzzy pattern pub fn fuzzy(pat: &str) -> Pattern { Pattern::Fuzzy(FuzzyPattern::from(pat)) } /// try to create a regex pattern - pub fn regex(pat: &str, flags: &str) -> Result<Pattern, RegexError> { + pub fn regex(pat: &str, flags: &str) -> Result<Pattern, PatternError> { Ok(Pattern::Regex(RegexPattern::from(pat, flags)?)) } pub fn find(&self, candidate: &str) -> Option<Match> { diff --git a/src/pattern/regex_patterns.rs b/src/pattern/regex_patterns.rs index 3f703aa..6398816 100644 --- a/src/pattern/regex_patterns.rs +++ b/src/pattern/regex_patterns.rs @@ -1,6 +1,10 @@ //! a filename filtering pattern using a regular expression -use {crate::errors::RegexError, regex, std::fmt}; +use { + crate::errors::PatternError, + regex, + std::fmt, +}; #[derive(Debug, Clone)] pub struct RegexPattern { @@ -15,7 +19,7 @@ impl fmt::Display for RegexPattern { } impl RegexPattern { - pub fn from(pat: &str, flags: &str) -> Result<RegexPattern, RegexError> { + pub fn from(pat: &str, flags: &str) -> Result<RegexPattern, PatternError> { let mut builder = regex::RegexBuilder::new(pat); for c in flags.chars() { match c { @@ -26,7 +30,7 @@ impl RegexPattern { builder.swap_greed(true); } _ => { - return Err(RegexError::UnknownFlag { bad: c }); + return Err(PatternError::UnknownRegexFlag { bad: c }); } } } |