summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Davison <dandavison7@gmail.com>2021-11-27 16:39:54 -0500
committerDan Davison <dandavison7@gmail.com>2021-11-29 08:41:24 -0500
commit67df50c8a8f8f1068a5bfbc02aa2ac38e601cd75 (patch)
tree3243c23dd341e21a788faf74dd72a9a7d1cdf4c5
parent1c9be71dd97329085c76adc655306857029c1a4a (diff)
Refactor: parse command line
-rw-r--r--src/handlers/git_show_file.rs4
-rw-r--r--src/handlers/grep.rs10
-rw-r--r--src/utils/process.rs118
3 files changed, 79 insertions, 53 deletions
diff --git a/src/handlers/git_show_file.rs b/src/handlers/git_show_file.rs
index 2a4998ca..d5eeb512 100644
--- a/src/handlers/git_show_file.rs
+++ b/src/handlers/git_show_file.rs
@@ -9,11 +9,11 @@ impl<'a> StateMachine<'a> {
self.painter.emit()?;
let mut handled_line = false;
if matches!(self.state, State::Unknown) {
- if let Some(process::CallingProcess::GitShow(extension)) =
+ if let Some(process::CallingProcess::GitShow(_, extension)) =
process::calling_process().as_deref()
{
self.state = State::GitShowFile;
- self.painter.set_syntax(Some(extension));
+ self.painter.set_syntax(extension.as_deref());
self.painter.set_highlighter();
} else {
return Ok(handled_line);
diff --git a/src/handlers/grep.rs b/src/handlers/grep.rs
index 25f4b8a1..e5c004ff 100644
--- a/src/handlers/grep.rs
+++ b/src/handlers/grep.rs
@@ -244,8 +244,9 @@ fn get_code_style_sections<'b>(
fn make_output_config() -> GrepOutputConfig {
match process::calling_process().as_deref() {
- Some(process::CallingProcess::GitGrep((longs, shorts)))
- if shorts.contains("-W") || longs.contains("--function-context") =>
+ Some(process::CallingProcess::GitGrep(command_line))
+ if command_line.short_options.contains("-W")
+ || command_line.long_options.contains("--function-context") =>
{
// --function-context is in effect: i.e. the entire function is
// being displayed. In that case we don't render the first line as a
@@ -261,8 +262,9 @@ fn make_output_config() -> GrepOutputConfig {
pad_line_number: true,
}
}
- Some(process::CallingProcess::GitGrep((longs, shorts)))
- if shorts.contains("-p") || longs.contains("--show-function") =>
+ Some(process::CallingProcess::GitGrep(command_line))
+ if command_line.short_options.contains("-p")
+ || command_line.long_options.contains("--show-function") =>
{
// --show-function is in effect, i.e. the function header is being
// displayed, along with matches within the function. Therefore we
diff --git a/src/utils/process.rs b/src/utils/process.rs
index 85edba78..e8060cf3 100644
--- a/src/utils/process.rs
+++ b/src/utils/process.rs
@@ -7,9 +7,16 @@ use lazy_static::lazy_static;
#[derive(Clone, Debug, PartialEq)]
pub enum CallingProcess {
- GitShow(String), // (extension)
- GitGrep((HashSet<String>, HashSet<String>)), // ((long_options, short_options))
- OtherGrep, // rg, grep, ag, ack, etc
+ GitShow(CommandLine, Option<String>), // element 2 is file extension
+ GitGrep(CommandLine),
+ OtherGrep, // rg, grep, ag, ack, etc
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct CommandLine {
+ pub long_options: HashSet<String>,
+ pub short_options: HashSet<String>,
+ last_arg: Option<String>,
}
pub fn calling_process() -> Option<Cow<'static, CallingProcess>> {
@@ -87,16 +94,21 @@ pub fn describe_calling_process(args: &[String]) -> ProcessArgs<CallingProcess>
let mut args = args.skip_while(|s| *s != "grep" && *s != "show");
match args.next() {
Some("grep") => {
- ProcessArgs::Args(CallingProcess::GitGrep(parse_command_option_keys(args)))
+ ProcessArgs::Args(CallingProcess::GitGrep(parse_command_line(args)))
}
Some("show") => {
- if let Some(extension) = get_git_show_file_extension(args) {
- ProcessArgs::Args(CallingProcess::GitShow(extension.to_string()))
+ let command_line = parse_command_line(args);
+ let extension = if let Some(last_arg) = &command_line.last_arg {
+ match last_arg.split_once(':') {
+ Some((_, suffix)) => {
+ suffix.split('.').last().map(|s| s.to_string())
+ }
+ None => None,
+ }
} else {
- // It's git show, but we failed to determine the
- // file extension. Don't look at any more processes.
- ProcessArgs::ArgError
- }
+ None
+ };
+ ProcessArgs::Args(CallingProcess::GitShow(command_line, extension))
}
_ => {
// It's git, but not a subcommand that we parse. Don't
@@ -128,18 +140,6 @@ pub fn describe_calling_process(args: &[String]) -> ProcessArgs<CallingProcess>
}
}
-fn get_git_show_file_extension<'a>(args: impl Iterator<Item = &'a str>) -> Option<&'a str> {
- if let Some(last_arg) = skip_uninteresting_args(args, "".split(' ')).last() {
- // E.g. "HEAD~1:Makefile" or "775c3b8:./src/delta.rs"
- match last_arg.split_once(':') {
- Some((_, suffix)) => suffix.split('.').last(),
- None => None,
- }
- } else {
- None
- }
-}
-
fn is_git_binary(git: &str) -> bool {
// Ignore case, for e.g. NTFS or APFS file systems
Path::new(git)
@@ -184,22 +184,28 @@ where
// Given `--aa val -bc -d val e f -- ...` return
// ({"--aa"}, {"-b", "-c", "-d"})
-fn parse_command_option_keys<'a>(
- args: impl Iterator<Item = &'a str>,
-) -> (HashSet<String>, HashSet<String>) {
- let mut longs = HashSet::new();
- let mut shorts = HashSet::new();
+fn parse_command_line<'a>(args: impl Iterator<Item = &'a str>) -> CommandLine {
+ let mut long_options = HashSet::new();
+ let mut short_options = HashSet::new();
+ let mut last_arg = None;
for s in args {
if s == "--" {
break;
} else if s.starts_with("--") {
- longs.insert(s.split('=').next().unwrap().to_owned());
+ long_options.insert(s.split('=').next().unwrap().to_owned());
} else if let Some(suffix) = s.strip_prefix('-') {
- shorts.extend(suffix.chars().map(|c| format!("-{}", c)));
+ short_options.extend(suffix.chars().map(|c| format!("-{}", c)));
+ } else {
+ last_arg = Some(s);
}
}
- (longs, shorts)
+
+ CommandLine {
+ long_options,
+ short_options,
+ last_arg: last_arg.map(|s| s.to_string()),
+ }
}
struct ProcInfo {
@@ -437,6 +443,7 @@ where
#[cfg(test)]
pub mod tests {
+
use super::*;
use itertools::Itertools;
@@ -672,6 +679,10 @@ pub mod tests {
}
}
+ fn set(arg1: &[&str]) -> HashSet<String> {
+ arg1.iter().map(|&s| s.to_owned()).collect()
+ }
+
#[test]
fn test_process_testing() {
{
@@ -877,6 +888,11 @@ pub mod tests {
None
);
+ let empty_command_line = CommandLine {
+ long_options: [].into(),
+ short_options: [].into(),
+ last_arg: Some("hello.txt".to_string()),
+ };
let parent = MockProcInfo::with(&[
(2, 100, "-shell", None),
(3, 100, "git grep pattern hello.txt", Some(2)),
@@ -884,7 +900,7 @@ pub mod tests {
]);
assert_eq!(
calling_process_cmdline(parent, describe_calling_process),
- Some(CallingProcess::GitGrep(([].into(), [].into())))
+ Some(CallingProcess::GitGrep(empty_command_line.clone()))
);
let parent = MockProcInfo::with(&[
@@ -894,7 +910,7 @@ pub mod tests {
]);
assert_eq!(
calling_process_cmdline(parent, describe_calling_process),
- Some(CallingProcess::GitGrep(([].into(), [].into())))
+ Some(CallingProcess::GitGrep(empty_command_line.clone()))
);
for grep_command in &[
@@ -914,17 +930,14 @@ pub mod tests {
);
}
- fn set(arg1: &[&str]) -> HashSet<String> {
- arg1.iter().map(|&s| s.to_owned()).collect()
- }
-
let git_grep_command =
"git grep -ab --function-context -n --show-function -W --foo=val pattern hello.txt";
- let expected_result = Some(CallingProcess::GitGrep((
- set(&["--function-context", "--show-function", "--foo"]),
- set(&["-a", "-b", "-n", "-W"]),
- )));
+ let expected_result = Some(CallingProcess::GitGrep(CommandLine {
+ long_options: set(&["--function-context", "--show-function", "--foo"]),
+ short_options: set(&["-a", "-b", "-n", "-W"]),
+ last_arg: Some("hello.txt".to_string()),
+ }));
let parent = MockProcInfo::with(&[
(2, 100, "-shell", None),
@@ -951,10 +964,16 @@ pub mod tests {
#[test]
fn test_describe_calling_process_git_show() {
for (command, expected_extension) in [
- ("/usr/local/bin/git show 775c3b84:./src/hello.rs", "rs"),
- ("/usr/local/bin/git show HEAD~1:Makefile", "Makefile"),
(
- "git -c x.y=z show --abbrev-commit 775c3b84:./src/hello.bye.R",
+ "/usr/local/bin/git show --abbrev-commit -w 775c3b84:./src/hello.rs",
+ "rs",
+ ),
+ (
+ "/usr/local/bin/git show --abbrev-commit -w HEAD~1:Makefile",
+ "Makefile",
+ ),
+ (
+ "git -c x.y=z show --abbrev-commit -w 775c3b84:./src/hello.bye.R",
"R",
),
] {
@@ -963,10 +982,15 @@ pub mod tests {
(3, 100, command, Some(2)),
(4, 100, "delta", Some(3)),
]);
- assert_eq!(
- calling_process_cmdline(parent, describe_calling_process),
- Some(CallingProcess::GitShow(expected_extension.to_string())),
- );
+ if let Some(CallingProcess::GitShow(cmd_line, ext)) =
+ calling_process_cmdline(parent, describe_calling_process)
+ {
+ assert_eq!(cmd_line.long_options, set(&["--abbrev-commit"]));
+ assert_eq!(cmd_line.short_options, set(&["-w"]));
+ assert_eq!(ext, Some(expected_extension.to_string()));
+ } else {
+ assert!(false);
+ }
}
}