#!/usr/bin/perl # vim: sts=4 sw=4 ts=4 expandtab: =pod =head1 NAME git-id =head1 SYNOPSIS git-id =head1 DESCRIPTION Runs git-status and prepends numeric ids to filenames. =head1 OPTIONS =over 4 =item -h Show this help message =item -s =item --column =item -u(no|normal|all) =item --color=(always|auto|never) These options are similar to git-status'. =back =head1 SEE ALSO git-number(1), git-list(1) =cut use strict; use warnings; use Cwd; my $red = "\e[31m"; my $normal = "\e[0m"; my $git_dir = `git rev-parse --git-dir`; chomp $git_dir; my $gitids = "$git_dir/gitids.txt"; my $color = 'always'; my $STATUS_DEFAULT = 0; my $STATUS_SHORT = 1; my $status_style = $STATUS_DEFAULT; my $status_opt = ''; my $untracked_in_columns = 0; while (scalar @ARGV && $ARGV[0] =~ /^-/) { my $option = shift @ARGV; last if $option eq '--'; if ($option =~ /--color=(always|auto|never)/) { $color = $1; if ($color =~ /never/) { $red = $normal = ''; } } elsif ($option eq '--short') { $status_style = $STATUS_SHORT; } elsif ($option =~ m{^-u(no|normal|all)$}) { $status_opt .= " $option"; } elsif ($option =~ /^--column/) { if ($option eq '--column=never' || ($option =~ /--column(=auto)?$/ && ! -t STDOUT)) { $untracked_in_columns = 0; } else { $untracked_in_columns = 1; } $status_opt .= " $option"; } else { print "Unknown option: $option\n"; exit 1; } } if (! $untracked_in_columns) { $status_opt .= " --column=never"; } my @status_option_for = ( '', '--short' ); my $status_format = $status_option_for[$status_style]; my $git_cmd = "git -c color.status=$color status $status_opt $status_format " . join(' ', @ARGV); open my $git_status, "$git_cmd|" or die "Error: $!"; open my $cache, ">$gitids" or die "Error: $!"; # Headers print $cache "cwd: " . getcwd . "\n"; print $cache "status-format: $status_format\n"; print $cache "\n"; my $seen_untracked = 0; my @untracked; my $c = 1; while (my $line = <$git_status>) { if ($line =~ /Untracked files:/) { $seen_untracked = 1; } if ($status_style == $STATUS_DEFAULT) { if ($seen_untracked && $line =~ /\t/ && $untracked_in_columns) { push @untracked, $line; last; } if ($line =~ /#\t/) { $line =~ s/#\t/#$c\t/; $c += 1; } elsif ($line =~ /\t/) { $line =~ s/\t/$c\t/; $c += 1; } } elsif ($status_style == $STATUS_SHORT) { if ($line !~ /^#/) { $line =~ s/^/$c /; $c += 1; } } show_and_cache($line); } if ($untracked_in_columns) { my $seen_files = 0; my @the_rest; while (my $line = <$git_status>) { if ($line =~ /\t/) { $seen_files = 1; push @untracked, $line; } else { push @the_rest, $line; } } my $rows = @untracked; foreach my $line (@untracked) { my $id = $c; $line =~ s/([\t ])(\S)/add_number(\$id, $1, $2, $rows)/ge; $line =~ s/^ +//; show_and_cache($line); $c += 1; } print join "", @the_rest; } close $git_status; close $cache; exit 0; sub show_and_cache { my ($line) = @_; my $tocache = $line; $tocache =~ s/{(\d+)}[\t ]{1,2}/\n$1\t/g; $line =~ s/{(\d+)}/$1/g; print $line; $tocache =~ s/\e\[(\d*(;\d*)*)m//g; if ($untracked_in_columns) { $tocache =~ s/\s*\n/\n/gms; # Trailing spaces from columnar formatting } print $cache $tocache; } sub add_number { my ($nref, $space, $first_char, $incr) = @_; my $num = $$nref; if ($num < 10 && $space eq ' ') { $num = "{$num} "; } else { $num = "{$num}"; } my $str = "$normal$num$space$red$first_char"; $$nref += $incr; return $str; }