summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2020-06-01 10:14:28 +0200
committerCanop <cano.petrole@gmail.com>2020-06-01 10:14:28 +0200
commitf9a75313b16378e61b64ee36c3bd829397642032 (patch)
tree6f15446a49da49e7228537ba5acf7c4a5fbf8601 /src
parent928365ae4bf4370b6bed57de1488d347fc5cc644 (diff)
[WIP] refactoring for new pattern syntax
Diffstat (limited to 'src')
-rw-r--r--src/app/state.rs24
-rw-r--r--src/browser/browser_state.rs38
-rw-r--r--src/command/command.rs14
-rw-r--r--src/command/mod.rs2
-rw-r--r--src/command/parts.rs91
-rw-r--r--src/command/pattern_parts.rs24
-rw-r--r--src/command/sequence.rs8
-rw-r--r--src/errors.rs9
-rw-r--r--src/pattern/pattern.rs17
-rw-r--r--src/pattern/regex_patterns.rs10
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 });
}
}
}