Skip to content

Commit

Permalink
Highlight keyboard shortcuts in git-add--interactive
Browse files Browse the repository at this point in the history
The user interface provided by the command loop in git-add--interactive
gives the impression that subcommands can only be launched by entering
an integer identifier from 1 through 8.

A "hidden" feature is that any string can be entered, and a regex search
anchored at the beginning of the string is used to find the uniquely
matching option.

This patch makes this feature a little more obvious by highlighting the
first character of each subcommand (for example "patch" is displayed as
"[p]atch").

A new function is added to detect the shortest unique prefix and this
is used to decide what to highlight. Highlighting is also applied when
choosing files.

In the case where the common prefix may be unreasonably large
highlighting is omitted; in this patch the soft limit (above which the
highlighting will be omitted for a particular item) is 0 (in other words,
there is no soft limit) and the hard limit (above which highlighting will
be omitted for all items) is 3, but this can be tweaked.

The actual highlighting is done by the highlight_prefix function, which
will enable us to implement ANSI color code-based highlighting (most
likely using underline or boldface) in the future.

Signed-off-by: Wincent Colaiuta <win@wincent.com>
Acked-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Wincent Colaiuta authored and Junio C Hamano committed Nov 30, 2007
1 parent 280e50c commit 14cb503
Showing 1 changed file with 82 additions and 5 deletions.
87 changes: 82 additions & 5 deletions git-add--interactive.perl
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ sub list_untracked {
my $status_head = sprintf($status_fmt, 'staged', 'unstaged', 'path');

# Returns list of hashes, contents of each of which are:
# PRINT: print message
# VALUE: pathname
# BINARY: is a binary path
# INDEX: is index different from HEAD?
Expand Down Expand Up @@ -133,8 +132,6 @@ sub list_modified {
}
push @return, +{
VALUE => $_,
PRINT => (sprintf $status_fmt,
$it->{INDEX}, $it->{FILE}, $_),
%$it,
};
}
Expand Down Expand Up @@ -170,10 +167,82 @@ sub find_unique {
return $found;
}

# inserts string into trie and updates count for each character
sub update_trie {
my ($trie, $string) = @_;
foreach (split //, $string) {
$trie = $trie->{$_} ||= {COUNT => 0};
$trie->{COUNT}++;
}
}

# returns an array of tuples (prefix, remainder)
sub find_unique_prefixes {
my @stuff = @_;
my @return = ();

# any single prefix exceeding the soft limit is omitted
# if any prefix exceeds the hard limit all are omitted
# 0 indicates no limit
my $soft_limit = 0;
my $hard_limit = 3;

# build a trie modelling all possible options
my %trie;
foreach my $print (@stuff) {
if ((ref $print) eq 'ARRAY') {
$print = $print->[0];
}
else {
$print = $print->{VALUE};
}
update_trie(\%trie, $print);
push @return, $print;
}

# use the trie to find the unique prefixes
for (my $i = 0; $i < @return; $i++) {
my $ret = $return[$i];
my @letters = split //, $ret;
my %search = %trie;
my ($prefix, $remainder);
my $j;
for ($j = 0; $j < @letters; $j++) {
my $letter = $letters[$j];
if ($search{$letter}{COUNT} == 1) {
$prefix = substr $ret, 0, $j + 1;
$remainder = substr $ret, $j + 1;
last;
}
else {
my $prefix = substr $ret, 0, $j;
return ()
if ($hard_limit && $j + 1 > $hard_limit);
}
%search = %{$search{$letter}};
}
if ($soft_limit && $j + 1 > $soft_limit) {
$prefix = undef;
$remainder = $ret;
}
$return[$i] = [$prefix, $remainder];
}
return @return;
}

# given a prefix/remainder tuple return a string with the prefix highlighted
# for now use square brackets; later might use ANSI colors (underline, bold)
sub highlight_prefix {
my $prefix = shift;
my $remainder = shift;
return (defined $prefix) ? "[$prefix]$remainder" : $remainder;
}

sub list_and_choose {
my ($opts, @stuff) = @_;
my (@chosen, @return);
my $i;
my @prefixes = find_unique_prefixes(@stuff) unless $opts->{LIST_ONLY};

TOPLOOP:
while (1) {
Expand All @@ -190,10 +259,18 @@ sub list_and_choose {
my $print = $stuff[$i];
if (ref $print) {
if ((ref $print) eq 'ARRAY') {
$print = $print->[0];
$print = @prefixes ?
highlight_prefix(@{$prefixes[$i]}) :
$print->[0];
}
else {
$print = $print->{PRINT};
my $value = @prefixes ?
highlight_prefix(@{$prefixes[$i]}) :
$print->{VALUE};
$print = sprintf($status_fmt,
$print->{INDEX},
$print->{FILE},
$value);
}
}
printf("%s%2d: %s", $chosen, $i+1, $print);
Expand Down

0 comments on commit 14cb503

Please sign in to comment.