Skip to content

Commit b8d97d0

Browse files
jnarebgitster
authored andcommitted
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>
1 parent b560707 commit b8d97d0

File tree

1 file changed

+57
-16
lines changed

1 file changed

+57
-16
lines changed

gitweb/gitweb.perl

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -848,32 +848,73 @@ sub project_in_list {
848848
## ----------------------------------------------------------------------
849849
## HTML aware string manipulation
850850

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.
851855
sub chop_str {
852856
my $str = shift;
853857
my $len = shift;
854858
my $add_len = shift || 10;
859+
my $where = shift || 'right'; # 'left' | 'center' | 'right'
855860

856861
# allow only $len chars, but don't cut a word if it would fit in $add_len
857862
# 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";
864908
}
865-
return "$body$tail";
866909
}
867910

868911
# takes the same arguments as chop_str, but also wraps a <span> around the
869912
# result with a title attribute if it does get chopped. Additionally, the
870913
# string is HTML-escaped.
871914
sub chop_and_escape_str {
872-
my $str = shift;
873-
my $len = shift;
874-
my $add_len = shift || 10;
915+
my ($str) = @_;
875916

876-
my $chopped = chop_str($str, $len, $add_len);
917+
my $chopped = chop_str(@_);
877918
if ($chopped eq $str) {
878919
return esc_html($chopped);
879920
} else {
@@ -3791,11 +3832,11 @@ sub git_search_grep_body {
37913832
foreach my $line (@$comment) {
37923833
if ($line =~ m/^(.*)($search_regexp)(.*)$/i) {
37933834
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');
37993840

38003841
$lead = esc_html($lead);
38013842
$match = esc_html($match);

0 commit comments

Comments
 (0)