@matheusbsbs / matheus-bagliano / commits / b8d97d07fd
Fork 0

gitweb: Better cutting matched string and its context

Improve look of commit search output ('search' view) by better cutting of matched string and its context in match info, as suggested by Junio. For example, if you are looking for "very long search string" in the following line: Could somebody test this with very long search string, and see how you would now see: ...this with <<very long ... string>>, and see... instead of: Could som... <<very long search...>>, and see... (where <<something>> denotes emphasized / colored fragment; matched fragment to be more exact). For this feature, support for fourth [optional] parameter to chop_str subroutine was added. This fourth parameter is used to denote where to cut string to make it shorter. chop_str can now cut at the beginning (from the _left_ side of the string), in the middle (_center_ of the string), or at the end (from the _right_ side of the string); cutting from right is the default: chop_str(somestring, len, slop, 'left') -> ' ...string' chop_str(somestring, len, slop, 'center') -> 'som ... ing' chop_str(somestring, len, slop, 'right') -> 'somestr... ' If you want to use default slop (default additional length), use undef as value for third parameter to chop_str. While at it, return from chop_str early if given string is so short that chop_str couldn't shorten it. Simplify also regexp used by chop_str. Make ellipsis (dots) stick to shortened fragment for cutting at ends, to better see which part got shortened. Simplify passing all arguments to chop_str in chop_and_escape_str subroutine. This was needed to pass additional options to chop_str. Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jakub Narebski committed Feb 25, 2008 at 21:07 UTC b8d97d07fd5025232cae74cfc9a555abd9ac390e
1 file changed +57 -16
gitweb/gitweb.perl
+57 -16
@@ -848,32 +848,73 @@ sub project_in_list {
848 ## ----------------------------------------------------------------------
849 ## HTML aware string manipulation
850
851 +# Try to chop given string on a word boundary between position
852 +# $len and $len+$add_len. If there is no word boundary there,
853 +# chop at $len+$add_len. Do not chop if chopped part plus ellipsis
854 +# (marking chopped part) would be longer than given string.
855 sub chop_str {
856 my $str = shift;
857 my $len = shift;
858 my $add_len = shift || 10;
859 + my $where = shift || 'right'; # 'left' | 'center' | 'right'
860
861 # allow only $len chars, but don't cut a word if it would fit in $add_len
862 # if it doesn't fit, cut it if it's still longer than the dots we would add
858 - $str =~ m/^(.{0,$len}[^ \/\-_:\.@]{0,$add_len})(.*)/;
859 - my $body = $1;
860 - my $tail = $2;
861 - if (length($tail) > 4) {
862 - $tail = " ...";
863 - $body =~ s/&[^;]*$//; # remove chopped character entities
863 + # remove chopped character entities entirely
864 +
865 + # when chopping in the middle, distribute $len into left and right part
866 + # return early if chopping wouldn't make string shorter
867 + if ($where eq 'center') {
868 + return $str if ($len + 5 >= length($str)); # filler is length 5
869 + $len = int($len/2);
870 + } else {
871 + return $str if ($len + 4 >= length($str)); # filler is length 4
872 + }
873 +
874 + # regexps: ending and beginning with word part up to $add_len
875 + my $endre = qr/.{$len}\w{0,$add_len}/;
876 + my $begre = qr/\w{0,$add_len}.{$len}/;
877 +
878 + if ($where eq 'left') {
879 + $str =~ m/^(.*?)($begre)$/;
880 + my ($lead, $body) = ($1, $2);
881 + if (length($lead) > 4) {
882 + $body =~ s/^[^;]*;// if ($lead =~ m/&[^;]*$/);
883 + $lead = " ...";
884 + }
885 + return "$lead$body";
886 +
887 + } elsif ($where eq 'center') {
888 + $str =~ m/^($endre)(.*)$/;
889 + my ($left, $str) = ($1, $2);
890 + $str =~ m/^(.*?)($begre)$/;
891 + my ($mid, $right) = ($1, $2);
892 + if (length($mid) > 5) {
893 + $left =~ s/&[^;]*$//;
894 + $right =~ s/^[^;]*;// if ($mid =~ m/&[^;]*$/);
895 + $mid = " ... ";
896 + }
897 + return "$left$mid$right";
898 +
899 + } else {
900 + $str =~ m/^($endre)(.*)$/;
901 + my $body = $1;
902 + my $tail = $2;
903 + if (length($tail) > 4) {
904 + $body =~ s/&[^;]*$//;
905 + $tail = "... ";
906 + }
907 + return "$body$tail";
908 }
865 - return "$body$tail";
909 }
910
911 # takes the same arguments as chop_str, but also wraps a <span> around the
912 # result with a title attribute if it does get chopped. Additionally, the
913 # string is HTML-escaped.
914 sub chop_and_escape_str {
872 - my $str = shift;
873 - my $len = shift;
874 - my $add_len = shift || 10;
915 + my ($str) = @_;
916
876 - my $chopped = chop_str($str, $len, $add_len);
917 + my $chopped = chop_str(@_);
918 if ($chopped eq $str) {
919 return esc_html($chopped);
920 } else {
@@ -3791,11 +3832,11 @@ sub git_search_grep_body {
3832 foreach my $line (@$comment) {
3833 if ($line =~ m/^(.*)($search_regexp)(.*)$/i) {
3834 my ($lead, $match, $trail) = ($1, $2, $3);
3794 - $match = chop_str($match, 70, 5); # in case match is very long
3795 - my $contextlen = int((80 - length($match))/2); # for the remainder
3796 - $contextlen = 30 if ($contextlen > 30); # but not too much
3797 - $lead = chop_str($lead, $contextlen, 10);
3798 - $trail = chop_str($trail, $contextlen, 10);
3835 + $match = chop_str($match, 70, 5, 'center');
3836 + my $contextlen = int((80 - length($match))/2);
3837 + $contextlen = 30 if ($contextlen > 30);
3838 + $lead = chop_str($lead, $contextlen, 10, 'left');
3839 + $trail = chop_str($trail, $contextlen, 10, 'right');
3840
3841 $lead = esc_html($lead);
3842 $match = esc_html($match);