>From 9096652a71666920ae8d59dd4317d536ba974d5b Mon Sep 17 00:00:00 2001 From: Aarni Koskela <a...@iki.fi> Date: Tue, 2 Dec 2014 13:56:15 +0200 Subject: [PATCH] git-add--interactive: allow list (un)selection by regular expression
Teach `list_and_choose` to allow `/regexp` and `-/regexp` syntax to select items based on regular expression match. This feature works in all list menus in `git-add--interactive`, and is not limited to file menus only. For instance, in file lists, `/\.c$` will select all files whose extension is `.c`. In option menus, such as the main menu, `/pa` could be used to choose the `patch` option. Signed-off-by: Aarni Koskela <a...@iki.fi> --- Thank you for the insightful comments, Junio, and sorry for the confusion regarding email-patch formatting. Hoping I get it right this time. > Usually the responsibility to ensure correctness lies on the person who > proposes a change, not those who relies on the continued correct operation > of the existing code. You're of course absolutely right. My point was that I can't think of an use case where one would need to otherwise have "/" or "-/" as the first characters of input in a list_and_choose situation, but someone else might. > [...] but is this about the selection that happens after showing you a > list of filenames to choose from? I clarified this in the commit message. Selection by regexp works in all list_and_choose situations, including the main menu of `git add -i`, hence "option". Regarding the unchoose quantifier -- yes, silly me. And regarding error checking for the regular expression, you're right -- the program promptly blew up when entering an invalid regexp. I incorporated your suggestion for error checking, with the addition of using the `error_msg` sub for colorized error reporting. Best regards, Aarni Koskela git-add--interactive.perl | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/git-add--interactive.perl b/git-add--interactive.perl index 1fadd69..28e4c2d 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -483,6 +483,8 @@ sub is_valid_prefix { !($prefix =~ /[\s,]/) && # separators !($prefix =~ /^-/) && # deselection !($prefix =~ /^\d+/) && # selection + !($prefix =~ /^\//) && # regexp selection + !($prefix =~ /^-\//) && # regexp unselection ($prefix ne '*') && # "all" wildcard ($prefix ne '?'); # prompt help } @@ -585,6 +587,50 @@ sub list_and_choose { prompt_help_cmd(); next TOPLOOP; } + if ($line =~ /^(-)?\/(.+)$/) { + # The first capture group ("-") being missing means "choose" is + # requested. If the first group exists at all, "unchoose" is + # requested. + my $choose = !(defined $1); + + # Validate the regular expression and complain if compilation failed. + my $re = eval { qr/$2/ }; + if (!$re) { + error_msg "Invalid regular expression:\n $@\n"; + next TOPLOOP; + } + + my $found = 0; + for ($i = 0; $i < @stuff; $i++) { + my $val = $stuff[$i]; + + # Figure out the display value for $val. + # Some lists passed to list_and_choose contain + # items other than strings; in order to match + # regexps against them, we need to extract the + # displayed string. The logic here is approximately + # equivalent to the display logic above. + + my $ref = ref $val; + if ($ref eq 'ARRAY') { + $val = $val->[0]; + } + elsif ($ref eq 'HASH') { + $val = $val->{VALUE}; + } + + # Match the string value against the regexp, + # then act accordingly. + + if ($val =~ $re) { + $chosen[$i] = $choose; + $found = $found || $choose; + last if $choose && $opts->{SINGLETON}; + } + } + last if $found && ($opts->{IMMEDIATE}); + next TOPLOOP; + } for my $choice (split(/[\s,]+/, $line)) { my $choose = 1; my ($bottom, $top); @@ -635,6 +681,7 @@ sub singleton_prompt_help_cmd { Prompt help: 1 - select a numbered item foo - select item based on unique prefix +/regexp - select item based on regular expression - (empty) select nothing EOF } @@ -648,6 +695,8 @@ Prompt help: foo - select item based on unique prefix -... - unselect specified items * - choose all items +/regexp - select items based on regular expression +-/regexp - unselect items based on regular expression - (empty) finish selecting EOF } -- 1.9.2.msysgit.0 -----Original Message----- From: Junio C Hamano [mailto:gits...@pobox.com] Sent: 1. joulukuuta 2014 18:28 To: Aarni Koskela Cc: git@vger.kernel.org; a...@iki.fi Subject: Re: [PATCH] git add -i: allow list (un)selection by regexp Aarni Koskela <aarni.kosk...@andersinnovations.com> writes: > Hello! > > This patch makes it possible to select or unselect files in `git add > -i` by regular expression instead of unique prefix only. > > The command syntax is `/foo` for selection and `-/foo` for unselection. > I don't think the syntax will conflict with any existing use cases, > but feel free to prove me wrong. Usually the responsibility to ensure correctness lies on the person who proposes a change, not those who relies on the continued correct operation of the existing code. > I'm not a Perl programmer, but I've tried to follow the style of the > existing code as much as possible. :) > > Note I'm currently not on the mailing list, so please cc. > > Best regards, > > Aarni Koskela All of the above do not belong to the commit log message. Please have these commentaries after the three-dash line you have under your Signed-off-by line. > > From 53c12d9c9928dc93a57595e92d785ecc0b245390 Mon Sep 17 00:00:00 2001 > From: Aarni Koskela <a...@iki.fi> > Date: Mon, 1 Dec 2014 11:06:10 +0200 > Subject: [PATCH] git-add--interactive: allow list (un)selection by > regular expression Remove these four lines when sending out a patch in the e-mail. > Teach `list_and_choose` to allow `/regexp` and `-/regexp` syntax to > select items based on regular expression match. > > For instance, `/jpg$` will select all options whose display name ends > with `jpg`. It has been a long time since I wrote this code, but is this about the selection that happens after showing you a list of filenames to choose from? "all options" together with "jpg" made me go "Huh? Does any of our command have jpeg related options? We are not in the image processing business". Perhaps s/all options/all files/ or something. > Signed-off-by: Aarni Koskela <a...@iki.fi> > --- > git-add--interactive.perl | 27 +++++++++++++++++++++++++++ > 1 file changed, 27 insertions(+) > > diff --git a/git-add--interactive.perl b/git-add--interactive.perl > index 1fadd69..34cc603 100755 > --- a/git-add--interactive.perl > +++ b/git-add--interactive.perl > @@ -483,6 +483,8 @@ sub is_valid_prefix { > !($prefix =~ /[\s,]/) && # separators > !($prefix =~ /^-/) && # deselection > !($prefix =~ /^\d+/) && # selection > + !($prefix =~ /^\//) && # regexp selection > + !($prefix =~ /^-\//) && # regexp unselection > ($prefix ne '*') && # "all" wildcard > ($prefix ne '?'); # prompt help > } > @@ -585,6 +587,28 @@ sub list_and_choose { > prompt_help_cmd(); > next TOPLOOP; > } > + if ($line =~ /^(-)*\/(.+)$/) { You want zero or one '-', not zero or arbitrary large number of '-', as a sign to unchoose. (-)? instead of (-)*, perhaps? > + my $choose = !($1 && $1 eq '-'); The first $1 is an attempt to catch non-negative case where it is "undef"; it might be more explicit this way? my $choose = !(defined $1); > + my $re = $2; Mental note. $re is an end-user supplied random string that may or may not be a valid regular expression. > + my $found = 0; > + for ($i = 0; $i < @stuff; $i++) { > + my $val = $stuff[$i]; > + my $ref = ref $val; > + if ($ref eq 'ARRAY') { > + $val = $val->[0]; > + } > + elsif ($ref eq 'HASH') { > + $val = $val->{VALUE}; > + } > + if ($val =~ /$re/) { ... which makes me wonder what happens when $re is a bogus regular expression here. Does the program die? Does the user get an error message about bad regexp and the condition to this if expression is false? Something else? Perhaps validating and catching regexp errors early like this might be sufficient: my $re = eval { qr/$2/ }; if (!$re) { print STDERR "$@\n"; next TOPLOOP; } Thanks. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html