git-id 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #!/usr/bin/perl
  2. # vim: sts=4 sw=4 ts=4 expandtab:
  3. =pod
  4. =head1 NAME
  5. git-id
  6. =head1 SYNOPSIS
  7. git-id
  8. =head1 DESCRIPTION
  9. Runs git-status and prepends numeric ids to filenames.
  10. =head1 OPTIONS
  11. =over 4
  12. =item -h
  13. Show this help message
  14. =item -s
  15. =item --column
  16. =item -u(no|normal|all)
  17. =item --color=(always|auto|never)
  18. These options are similar to git-status'.
  19. =back
  20. =head1 SEE ALSO
  21. git-number(1), git-list(1)
  22. =cut
  23. use strict;
  24. use warnings;
  25. use Cwd;
  26. my $red = "\e[31m";
  27. my $normal = "\e[0m";
  28. my $git_dir = `git rev-parse --git-dir`;
  29. chomp $git_dir;
  30. my $gitids = "$git_dir/gitids.txt";
  31. my $color = 'always';
  32. my $STATUS_DEFAULT = 0;
  33. my $STATUS_SHORT = 1;
  34. my $status_style = $STATUS_DEFAULT;
  35. my $status_opt = '';
  36. my $untracked_in_columns = 0;
  37. while (scalar @ARGV && $ARGV[0] =~ /^-/) {
  38. my $option = shift @ARGV;
  39. last if $option eq '--';
  40. if ($option =~ /--color=(always|auto|never)/) {
  41. $color = $1;
  42. if ($color =~ /never/) {
  43. $red = $normal = '';
  44. }
  45. } elsif ($option eq '--short') {
  46. $status_style = $STATUS_SHORT;
  47. } elsif ($option =~ m{^-u(no|normal|all)$}) {
  48. $status_opt .= " $option";
  49. } elsif ($option =~ /^--column/) {
  50. if ($option eq '--column=never' || ($option =~ /--column(=auto)?$/ && ! -t STDOUT)) {
  51. $untracked_in_columns = 0;
  52. } else {
  53. $untracked_in_columns = 1;
  54. }
  55. $status_opt .= " $option";
  56. } else {
  57. print "Unknown option: $option\n";
  58. exit 1;
  59. }
  60. }
  61. if (! $untracked_in_columns) {
  62. $status_opt .= " --column=never";
  63. }
  64. my @status_option_for = ( '', '--short' );
  65. my $status_format = $status_option_for[$status_style];
  66. my $git_cmd = "git -c color.status=$color status $status_opt $status_format "
  67. . join(' ', @ARGV);
  68. open my $git_status, "$git_cmd|"
  69. or die "Error: $!";
  70. open my $cache, ">$gitids"
  71. or die "Error: $!";
  72. # Headers
  73. print $cache "cwd: " . getcwd . "\n";
  74. print $cache "status-format: $status_format\n";
  75. print $cache "\n";
  76. my $seen_untracked = 0;
  77. my @untracked;
  78. my $c = 1;
  79. while (my $line = <$git_status>) {
  80. if ($line =~ /Untracked files:/) {
  81. $seen_untracked = 1;
  82. }
  83. if ($status_style == $STATUS_DEFAULT) {
  84. if ($seen_untracked && $line =~ /\t/ && $untracked_in_columns) {
  85. push @untracked, $line;
  86. last;
  87. }
  88. if ($line =~ /#\t/) {
  89. $line =~ s/#\t/#$c\t/;
  90. $c += 1;
  91. } elsif ($line =~ /\t/) {
  92. $line =~ s/\t/$c\t/;
  93. $c += 1;
  94. }
  95. } elsif ($status_style == $STATUS_SHORT) {
  96. if ($line !~ /^#/) {
  97. $line =~ s/^/$c /;
  98. $c += 1;
  99. }
  100. }
  101. show_and_cache($line);
  102. }
  103. if ($untracked_in_columns) {
  104. my $seen_files = 0;
  105. my @the_rest;
  106. while (my $line = <$git_status>) {
  107. if ($line =~ /\t/) {
  108. $seen_files = 1;
  109. push @untracked, $line;
  110. } else {
  111. push @the_rest, $line;
  112. }
  113. }
  114. my $rows = @untracked;
  115. foreach my $line (@untracked) {
  116. my $id = $c;
  117. $line =~ s/([\t ])(\S)/add_number(\$id, $1, $2, $rows)/ge;
  118. $line =~ s/^ +//;
  119. show_and_cache($line);
  120. $c += 1;
  121. }
  122. print join "", @the_rest;
  123. }
  124. close $git_status;
  125. close $cache;
  126. exit 0;
  127. sub show_and_cache {
  128. my ($line) = @_;
  129. my $tocache = $line;
  130. $tocache =~ s/{(\d+)}[\t ]{1,2}/\n$1\t/g;
  131. $line =~ s/{(\d+)}/$1/g;
  132. print $line;
  133. $tocache =~ s/\e\[(\d*(;\d*)*)m//g;
  134. if ($untracked_in_columns) {
  135. $tocache =~ s/\s*\n/\n/gms; # Trailing spaces from columnar formatting
  136. }
  137. print $cache $tocache;
  138. }
  139. sub add_number {
  140. my ($nref, $space, $first_char, $incr) = @_;
  141. my $num = $$nref;
  142. if ($num < 10 && $space eq ' ') {
  143. $num = "{$num} ";
  144. } else {
  145. $num = "{$num}";
  146. }
  147. my $str = "$normal$num$space$red$first_char";
  148. $$nref += $incr;
  149. return $str;
  150. }