gitweb: Highlight matched part of shortened project description

Previous commit make gitweb use esc_html_match_hl() to mark match in the _whole_ description of a project when searching projects. This commit makes gitweb highlight match in _shortened_ description, based on match in whole description, using esc_html_match_hl_chopped() subroutine. If match is in removed (chopped) part, even partially, then trailing "... " is highlighted. Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jakub Narebski committed Feb 27, 2012 at 02:55 UTC e607b79fb14f2196f7ea46d2115f21c548972e78
1 file changed +47 -5
gitweb/gitweb.perl
+47 -5
@@ -1742,20 +1742,61 @@ sub esc_html_hl_regions {
1742 return $out;
1743 }
1744
1745 -# highlight match (if any), and escape HTML
1746 -sub esc_html_match_hl {
1745 +# return positions of beginning and end of each match
1746 +sub matchpos_list {
1747 my ($str, $regexp) = @_;
1748 - return esc_html($str) unless defined $regexp;
1748 + return unless (defined $str && defined $regexp);
1749
1750 my @matches;
1751 while ($str =~ /$regexp/g) {
1752 push @matches, [$-[0], $+[0]];
1753 }
1754 + return @matches;
1755 +}
1756 +
1757 +# highlight match (if any), and escape HTML
1758 +sub esc_html_match_hl {
1759 + my ($str, $regexp) = @_;
1760 + return esc_html($str) unless defined $regexp;
1761 +
1762 + my @matches = matchpos_list($str, $regexp);
1763 return esc_html($str) unless @matches;
1764
1765 return esc_html_hl_regions($str, 'match', @matches);
1766 }
1767
1768 +
1769 +# highlight match (if any) of shortened string, and escape HTML
1770 +sub esc_html_match_hl_chopped {
1771 + my ($str, $chopped, $regexp) = @_;
1772 + return esc_html_match_hl($str, $regexp) unless defined $chopped;
1773 +
1774 + my @matches = matchpos_list($str, $regexp);
1775 + return esc_html($chopped) unless @matches;
1776 +
1777 + # filter matches so that we mark chopped string
1778 + my $tail = "... "; # see chop_str
1779 + unless ($chopped =~ s/\Q$tail\E$//) {
1780 + $tail = '';
1781 + }
1782 + my $chop_len = length($chopped);
1783 + my $tail_len = length($tail);
1784 + my @filtered;
1785 +
1786 + for my $m (@matches) {
1787 + if ($m->[0] > $chop_len) {
1788 + push @filtered, [ $chop_len, $chop_len + $tail_len ] if ($tail_len > 0);
1789 + last;
1790 + } elsif ($m->[1] > $chop_len) {
1791 + push @filtered, [ $m->[0], $chop_len + $tail_len ];
1792 + last;
1793 + }
1794 + push @filtered, $m;
1795 + }
1796 +
1797 + return esc_html_hl_regions($chopped . $tail, 'match', @filtered);
1798 +}
1799 +
1800 ## ----------------------------------------------------------------------
1801 ## functions returning short strings
1802
@@ -5405,9 +5446,10 @@ sub git_project_list_rows {
5446 "</td>\n" .
5447 "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
5448 -class => "list",
5408 - $search_regexp ? () : -title => $pr->{'descr_long'}},
5449 + -title => $pr->{'descr_long'}},
5450 $search_regexp
5410 - ? esc_html_match_hl($pr->{'descr_long'}, $search_regexp)
5451 + ? esc_html_match_hl_chopped($pr->{'descr_long'},
5452 + $pr->{'descr'}, $search_regexp)
5453 : esc_html($pr->{'descr'})) .
5454 "</td>\n" .
5455 "<td><i>" . chop_and_escape_str($pr->{'owner'}, 15) . "</i></td>\n";