From f8aa7f6c8a632546b4cb234abf0030a39be52eed Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Wed, 26 Aug 2020 21:41:36 +0200 Subject: Add `diff_options` to parse Git diff options In order to accept Git diff options on the command line, we need a way to extract these from args. Add a function to parse diff options. These were sourced from: https://github.com/git/git/blob/675a4aaf3b226c0089108221b96559e0baae5de9/Documentation/diff-options.txt The function loops through the input arguments and extracts all diff options and their values. Still needs some work to integrate it into `git-sugdiff`, but it currently works as advertised. --- src/bin/git-sugdiff.rs | 3 + src/diff_options.rs | 380 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 3 files changed, 384 insertions(+) create mode 100644 src/diff_options.rs diff --git a/src/bin/git-sugdiff.rs b/src/bin/git-sugdiff.rs index 6c96a27..6b95239 100644 --- a/src/bin/git-sugdiff.rs +++ b/src/bin/git-sugdiff.rs @@ -27,6 +27,9 @@ use github_suggestion_cli::config::Config; fn main() { let args: Vec<_> = env::args().collect(); + // TODO: Shift all diff options from args, then pass them to Config::get(). + // Add diff options to Command call below. + let config = match Config::get( &args, "usage: git sugdiff [options] ...", diff --git a/src/diff_options.rs b/src/diff_options.rs new file mode 100644 index 0000000..587e214 --- /dev/null +++ b/src/diff_options.rs @@ -0,0 +1,380 @@ +// Copyright (c) 2020 Teddy Wing +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + + +static FLAGS: [&'static str; 59] = [ + "-p", + "--no-stat", + "-p", + "-u", + "--patch", + "-s", + "--no-patch", + "--raw", + "--patch-with-raw", + "-t", + "--indent-heuristic", + "--no-indent-heuristic", + "--minimal", + "--patience", + "--histogram", + "--compact-summary", + "--numstat", + "--shortstat", + "--cumulative", + "--summary", + "--patch-with-stat", + "-z", + "--name-only", + "--name-status", + "--no-color", + "--no-color-moved", + "--no-color-moved-ws", + "--no-renames", + "--rename-empty", + "--no-rename-empty", + "--check", + "--full-index", + "--binary", + "--find-copies-harder", + "-D", + "--irreversible-delete", + "--pickaxe-all", + "--pickaxe-regex", + "-R", + "--no-relative", + "-a", + "--text", + "--ignore-cr-at-eol", + "--ignore-space-at-eol", + "-b", + "--ignore-space-change", + "-w", + "--ignore-all-space", + "--ignore-blank-lines", + "-W", + "--function-context", + "--exit-code", + "--quiet", + "--ext-diff", + "--no-ext-diff", + "--textconv", + "--no-textconv", + "--no-prefix", + "--ita-invisible-in-index", +]; + +// static OPTIONS: [&'static str; 21] = [ +// "-U", +// "--unified=", +// "--output=", +// "--output-indicator-new=", +// "--output-indicator-old=", +// "--output-indicator-context=", +// "--anchored=", +// "--diff-algorithm={patience|minimal|histogram|myers}", +// "--stat[=[,[,]]]", +// "-X[]", +// "--dirstat[=]", +// "--dirstat-by-file[=...]", +// "--submodule[=]", +// "--color[=]", +// "--color-moved[=]", +// "--color-moved-ws=", +// "--word-diff[=]", +// "--word-diff-regex=", +// "--color-words[=]", +// "--ws-error-highlight=", +// "--abbrev[=]", +// "-B[][/]", +// "--break-rewrites[=[][/]]", +// "-M[]", +// "--find-renames[=]", +// "-C[]", +// "--find-copies[=]", +// "-l", +// "--diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]]", +// "-S", +// "-G", +// "--find-object=", +// "-O", +// "--relative[=]", +// "--inter-hunk-context=", +// "--ignore-submodules[=]", +// "--src-prefix=", +// "--dst-prefix=", +// "--line-prefix=", +// ]; + +static ARG_OPTIONS: [&'static str; 20] = [ + "-U", + "--unified", + "--output", + "--output-indicator-new", + "--output-indicator-old", + "--output-indicator-context", + "--anchored", + "--diff-algorithm", + "--color-moved-ws", + "--word-diff-regex", + "--ws-error-highlight", + "-l", + "-S", + "-G", + "--find-object", + "-O", + "--inter-hunk-context", + "--src-prefix", + "--dst-prefix", + "--line-prefix", +]; + +static OPT_OPTIONS: [&'static str; 19] = [ + "--stat", + "-X", + "--dirstat", + "--dirstat-by-file", + "--submodule", + "--color", + "--color-moved", + "--word-diff", + "--color-words", + "--abbrev", + "-B", + "--break-rewrites", + "-M", + "--find-renames", + "-C", + "--find-copies", + "--diff-filter", + "--relative", + "--ignore-submodules", +]; + + +// pub fn parse(args: &[String]) -> &[String] { +pub fn parse(args: &[String]) -> Vec<&String> { + let mut found_args = Vec::new(); + let mut add_next_arg = false; + + for arg in args { + let find_arg_prefix = arg.find('-'); + + if add_next_arg + && ( + find_arg_prefix.is_none() + || find_arg_prefix != Some(0) + ) + { + found_args.push(arg); + + add_next_arg = false; + + continue; + } + + for flag in FLAGS.iter() { + if arg.starts_with(flag) { + found_args.push(arg); + } + } + + // TODO: check for "=" and get next arg + // '=' + // if no equals, then add next arg + for option in &ARG_OPTIONS { + if arg.starts_with(option) { + found_args.push(arg); + + // if arg doesn't have an = after it + // if i < arg.len() { + // let char_after_option = arg.get(option.len()); + // if char_after_option.is_some() + // && char_after_option.unwrap() == '=' { + + let (_option, rest) = arg.split_at(option.len()); + + dbg!(arg); + dbg!(arg.len()); + dbg!(option); + dbg!(option.len()); + dbg!(rest.find('=').is_none()); + // if arg.len() > option.len() + // && rest.find('=').is_none() { + if rest.find('=').is_none() { + add_next_arg = true; + } + } + } + + // check '=' + // If no equals, add next arg if it doesn't begin with '-' + for option in &OPT_OPTIONS { + if arg.starts_with(option) { + found_args.push(arg); + + let (_option, rest) = arg.split_at(option.len()); + + if rest.find('=').is_none() { + add_next_arg = true; + } + } + } + } + + found_args +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_extracts_diff_options() { + let args = vec![ + "--github-token".to_owned(), + "MY_TOKEN".to_owned(), + "--diff-filter=A".to_owned(), + "-D".to_owned(), + "--color".to_owned(), + "always".to_owned(), + "-U5".to_owned(), + "--patience".to_owned(), + "--ws-error-highlight".to_owned(), + "old,new".to_owned(), + "--no-rename-empty".to_owned(), + "--stat=50".to_owned(), + "-M90%".to_owned(), + "--relative".to_owned(), + ]; + + let options = parse(&args); + + assert_eq!(options, vec![ + "--diff-filter=A", + "-D", + "--color", + "always", + "-U5", + "--patience", + "--ws-error-highlight", + "old,new", + "--no-rename-empty", + "--stat=50", + "-M90%", + "--relative", + ]); + } +} + +// -p +// --no-stat +// -p +// -u +// --patch +// -s +// --no-patch +// -U +// --unified= +// --output= +// --output-indicator-new= +// --output-indicator-old= +// --output-indicator-context= +// --raw +// --patch-with-raw +// -t +// --indent-heuristic +// --no-indent-heuristic +// --minimal +// --patience +// --histogram +// --anchored= +// --diff-algorithm={patience|minimal|histogram|myers} +// --stat[=[,[,]]] +// --compact-summary +// --numstat +// --shortstat +// -X[] +// --dirstat[=] +// --cumulative +// --dirstat-by-file[=...] +// --summary +// --patch-with-stat +// -z +// --name-only +// --name-status +// --submodule[=] +// --color[=] +// --no-color +// --color-moved[=] +// --no-color-moved +// --color-moved-ws= +// --no-color-moved-ws +// --word-diff[=] +// --word-diff-regex= +// --color-words[=] +// --no-renames +// --[no-]rename-empty +// --check +// --ws-error-highlight= +// --full-index +// --binary +// --abbrev[=] +// -B[][/] +// --break-rewrites[=[][/]] +// -M[] +// --find-renames[=] +// -C[] +// --find-copies[=] +// --find-copies-harder +// -D +// --irreversible-delete +// -l +// --diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]] +// -S +// -G +// -S"frotz\(nitfol" --pickaxe-regex` will not (because the number of +// --find-object= +// --pickaxe-all +// --pickaxe-regex +// -O +// -R +// --relative[=] +// --no-relative +// -a +// --text +// --ignore-cr-at-eol +// --ignore-space-at-eol +// -b +// --ignore-space-change +// -w +// --ignore-all-space +// --ignore-blank-lines +// --inter-hunk-context= +// -W +// --function-context +// --exit-code +// --quiet +// --ext-diff +// --no-ext-diff +// --textconv +// --no-textconv +// --ignore-submodules[=] +// --src-prefix= +// --dst-prefix= +// --no-prefix +// --line-prefix= +// --ita-invisible-in-index diff --git a/src/lib.rs b/src/lib.rs index 314d130..fa31028 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ #![warn(rust_2018_idioms)] pub mod config; +pub mod diff_options; pub mod error; mod arg; -- cgit v1.2.3