git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[REPLACEMENT PATCH] Highlight keyboard shortcuts in git-add--interactive

From
Wincent Colaiuta <win@wincent.com>
Date
Dec 1, 2007, 14:29 UTC
Message-ID
<1196519351-86280-1-git-send-email-win@wincent.com>
In-Reply-To
<697AB37F-784D-4374-A290-0E6290712B29@wincent.com>

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 an anchored regex search 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>
---
I will go now and crawl under a rock.
 git-add--interactive.perl |  110 ++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 100 insertions(+), 10 deletions(-)
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index fb1e92a..0e358b5 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -44,7 +44,6 @@ my $status_fmt = '%12s %12s %s';
 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?
@@ -122,8 +121,6 @@ sub list_modified {
 		}
 		push @return, +{
 			VALUE => $_,
-			PRINT => (sprintf $status_fmt,
-				  $it->{INDEX}, $it->{FILE}, $_),
 			%$it,
 		};
 	}
@@ -159,10 +156,95 @@ 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];
+		}
+		elsif ((ref $print) eq 'HASH') {
+			$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;
+}
+
+# filters out prefixes which have special meaning to list_and_choose()
+sub is_valid_prefix {
+	my $prefix = shift;
+	return (defined $prefix) &&
+	    !($prefix =~ /[\s,]/) && # separators
+	    !($prefix =~ /^-/) &&    # deselection
+	    !($prefix =~ /^\d+/) &&  # selection
+	    ($prefix ne '*');        # "all" wildcard
+}
+
+# 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 $remainder unless defined $prefix;
+	return is_valid_prefix($prefix) ?
+	    "[$prefix]$remainder" :
+	    "$prefix$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) {
@@ -177,13 +259,21 @@ sub list_and_choose {
 		for ($i = 0; $i < @stuff; $i++) {
 			my $chosen = $chosen[$i] ? '*' : ' ';
 			my $print = $stuff[$i];
-			if (ref $print) {
-				if ((ref $print) eq 'ARRAY') {
-					$print = $print->[0];
-				}
-				else {
-					$print = $print->{PRINT};
-				}
+			my $ref = ref $print;
+			my $highlighted = highlight_prefix(@{$prefixes[$i]})
+			    if @prefixes;
+			if ($ref eq 'ARRAY') {
+				$print = $highlighted || $print->[0];
+			}
+			elsif ($ref eq 'HASH') {
+				my $value = $highlighted || $print->{VALUE};
+				$print = sprintf($status_fmt,
+				    $print->{INDEX},
+				    $print->{FILE},
+				    $value);
+			}
+			else {
+				$print = $highlighted || $print;
 			}
 			printf("%s%2d: %s", $chosen, $i+1, $print);
 			if (($opts->{LIST_FLAT}) &&
-- 
1.5.3.6.953.gdffc
Previous: Wincent ColaiutaNext: Wincent Colaiuta
Message 14 of 17 in “Highlight keyboard shortcuts in git-add--interactive”
  1. Highlight keyboard shortcuts in git-add--interactiveWincent Colaiuta, Nov 21, 2007
  2. Matthieu MoyNov 21, 2007
  3. Jeff KingNov 21, 2007
  4. Dan ZwellNov 21, 2007
  5. Junio C HamanoNov 28, 2007
  6. Wincent ColaiutaNov 29, 2007
  7. Highlight keyboard shortcuts in git-add--interactiveWincent Colaiuta, Nov 29, 2007
  8. Jeff KingNov 29, 2007
  9. Junio C HamanoDec 1, 2007
  10. Wincent ColaiutaDec 1, 2007
  11. 1/2 Highlight keyboard shortcuts in git-add--interactiveWincent Colaiuta, Dec 1, 2007
  12. 2/2 Teach git-add--interactive to highlight untracked file prefixesWincent Colaiuta, Dec 1, 2007
  13. Wincent ColaiutaDec 1, 2007
  14. Highlight keyboard shortcuts in git-add--interactiveWincent Colaiuta, Dec 1, 2007
  15. Wincent ColaiutaDec 2, 2007
  16. Junio C HamanoDec 2, 2007
  17. Wincent ColaiutaDec 3, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.