diff --git a/src/params.rs b/src/params.rs index a3cdfe6..88feb47 100644 --- a/src/params.rs +++ b/src/params.rs @@ -49,13 +49,10 @@ pub fn parse_params>(opts: I) -> Result\d+)$").unwrap(); - let context_re = - Regex::new(r"^(-[cC](?\d*)|--context(=(?\d*))?|-(?\d+)c)$").unwrap(); - let unified_re = - Regex::new(r"^(-[uU](?\d*)|--unified(=(?\d*))?|-(?\d+)u)$").unwrap(); while let Some(param) = opts.next() { + let next_param = opts.peek(); if param == "--" { break; } @@ -111,73 +108,43 @@ pub fn parse_params>(opts: I) -> Result().unwrap()); - } - if param == "-C" { - let next_param = opts.peek(); - if next_param.is_some() { - let next_value = next_param - .unwrap() - .to_string_lossy() - .as_ref() - .parse::(); - if next_value.is_ok() { - context_count = Some(next_value.unwrap()); + match match_context_diff_params(¶m, next_param, format) { + Ok(DiffStyleMatch { + is_match, + context_count, + next_param_consumed, + }) => { + if is_match { + format = Some(Format::Context); + if context_count.is_some() { + context = context_count; + } + if next_param_consumed { opts.next(); - } else { - return Err(format!( - "invalid context length '{}'", - next_param.unwrap().to_string_lossy() - )); } + continue; } } - continue; + Err(error) => return Err(error), } - if unified_re.is_match(param.to_string_lossy().as_ref()) { - if format.is_some() && format != Some(Format::Unified) { - return Err("Conflicting output style options".to_string()); - } - format = Some(Format::Unified); - let captures = unified_re.captures(param.to_str().unwrap()).unwrap(); - let num = captures - .name("num1") - .or(captures.name("num2")) - .or(captures.name("num3")); - if num.is_some() && !num.unwrap().as_str().is_empty() { - context_count = Some(num.unwrap().as_str().parse::().unwrap()); - } - if param == "-U" { - let next_param = opts.peek(); - if next_param.is_some() { - let next_value = next_param - .unwrap() - .to_string_lossy() - .as_ref() - .parse::(); - if next_value.is_ok() { - context_count = Some(next_value.unwrap()); + match match_unified_diff_params(¶m, next_param, format) { + Ok(DiffStyleMatch { + is_match, + context_count, + next_param_consumed, + }) => { + if is_match { + format = Some(Format::Unified); + if context_count.is_some() { + context = context_count; + } + if next_param_consumed { opts.next(); - } else { - return Err(format!( - "invalid context length '{}'", - next_param.unwrap().to_string_lossy() - )); } + continue; } } - continue; + Err(error) => return Err(error), } if param.to_string_lossy().starts_with('-') { return Err(format!("Unknown option: {:?}", param)); @@ -205,12 +172,110 @@ pub fn parse_params>(opts: I) -> Result ", exe.to_string_lossy())); }; params.format = format.unwrap_or(Format::default()); - if context_count.is_some() { - params.context_count = context_count.unwrap(); + if let Some(context_count) = context { + params.context_count = context_count; } Ok(params) } +struct DiffStyleMatch { + is_match: bool, + context_count: Option, + next_param_consumed: bool, +} + +fn match_context_diff_params( + param: &OsString, + next_param: Option<&OsString>, + format: Option, +) -> Result { + const CONTEXT_RE: &str = r"^(-[cC](?\d*)|--context(=(?\d*))?|-(?\d+)c)$"; + let regex = Regex::new(CONTEXT_RE).unwrap(); + let is_match = regex.is_match(param.to_string_lossy().as_ref()); + let mut context_count = None; + let mut next_param_consumed = false; + if is_match { + if format.is_some() && format != Some(Format::Context) { + return Err("Conflicting output style options".to_string()); + } + let captures = regex.captures(param.to_str().unwrap()).unwrap(); + let num = captures + .name("num1") + .or(captures.name("num2")) + .or(captures.name("num3")); + if let Some(numvalue) = num { + if !numvalue.as_str().is_empty() { + context_count = Some(numvalue.as_str().parse::().unwrap()); + } + } + if param == "-C" && next_param.is_some() { + match next_param.unwrap().to_string_lossy().parse::() { + Ok(context_size) => { + context_count = Some(context_size); + next_param_consumed = true; + } + Err(_) => { + return Err(format!( + "invalid context length '{}'", + next_param.unwrap().to_string_lossy() + )) + } + } + } + } + Ok(DiffStyleMatch { + is_match, + context_count, + next_param_consumed, + }) +} + +fn match_unified_diff_params( + param: &OsString, + next_param: Option<&OsString>, + format: Option, +) -> Result { + const UNIFIED_RE: &str = r"^(-[uU](?\d*)|--unified(=(?\d*))?|-(?\d+)u)$"; + let regex = Regex::new(UNIFIED_RE).unwrap(); + let is_match = regex.is_match(param.to_string_lossy().as_ref()); + let mut context_count = None; + let mut next_param_consumed = false; + if is_match { + if format.is_some() && format != Some(Format::Unified) { + return Err("Conflicting output style options".to_string()); + } + let captures = regex.captures(param.to_str().unwrap()).unwrap(); + let num = captures + .name("num1") + .or(captures.name("num2")) + .or(captures.name("num3")); + if let Some(numvalue) = num { + if !numvalue.as_str().is_empty() { + context_count = Some(numvalue.as_str().parse::().unwrap()); + } + } + if param == "-U" && next_param.is_some() { + match next_param.unwrap().to_string_lossy().parse::() { + Ok(context_size) => { + context_count = Some(context_size); + next_param_consumed = true; + } + Err(_) => { + return Err(format!( + "invalid context length '{}'", + next_param.unwrap().to_string_lossy() + )) + } + } + } + } + Ok(DiffStyleMatch { + is_match, + context_count, + next_param_consumed, + }) +} + #[cfg(test)] mod tests { use super::*;