Skip to content

Commit 6759f95

Browse files
committed
Merge branch 'jn/gitweb-hilite-regions'
* jn/gitweb-hilite-regions: gitweb: Highlight matched part of shortened project description gitweb: Highlight matched part of project description when searching projects gitweb: Highlight matched part of project name when searching projects gitweb: Introduce esc_html_match_hl and esc_html_hl_regions
2 parents 250f0a0 + e607b79 commit 6759f95

File tree

1 file changed

+92
-3
lines changed

1 file changed

+92
-3
lines changed

gitweb/gitweb.perl

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,88 @@ sub chop_and_escape_str {
17241724
}
17251725
}
17261726

1727+
# Highlight selected fragments of string, using given CSS class,
1728+
# and escape HTML. It is assumed that fragments do not overlap.
1729+
# Regions are passed as list of pairs (array references).
1730+
#
1731+
# Example: esc_html_hl_regions("foobar", "mark", [ 0, 3 ]) returns
1732+
# '<span class="mark">foo</span>bar'
1733+
sub esc_html_hl_regions {
1734+
my ($str, $css_class, @sel) = @_;
1735+
return esc_html($str) unless @sel;
1736+
1737+
my $out = '';
1738+
my $pos = 0;
1739+
1740+
for my $s (@sel) {
1741+
$out .= esc_html(substr($str, $pos, $s->[0] - $pos))
1742+
if ($s->[0] - $pos > 0);
1743+
$out .= $cgi->span({-class => $css_class},
1744+
esc_html(substr($str, $s->[0], $s->[1] - $s->[0])));
1745+
1746+
$pos = $s->[1];
1747+
}
1748+
$out .= esc_html(substr($str, $pos))
1749+
if ($pos < length($str));
1750+
1751+
return $out;
1752+
}
1753+
1754+
# return positions of beginning and end of each match
1755+
sub matchpos_list {
1756+
my ($str, $regexp) = @_;
1757+
return unless (defined $str && defined $regexp);
1758+
1759+
my @matches;
1760+
while ($str =~ /$regexp/g) {
1761+
push @matches, [$-[0], $+[0]];
1762+
}
1763+
return @matches;
1764+
}
1765+
1766+
# highlight match (if any), and escape HTML
1767+
sub esc_html_match_hl {
1768+
my ($str, $regexp) = @_;
1769+
return esc_html($str) unless defined $regexp;
1770+
1771+
my @matches = matchpos_list($str, $regexp);
1772+
return esc_html($str) unless @matches;
1773+
1774+
return esc_html_hl_regions($str, 'match', @matches);
1775+
}
1776+
1777+
1778+
# highlight match (if any) of shortened string, and escape HTML
1779+
sub esc_html_match_hl_chopped {
1780+
my ($str, $chopped, $regexp) = @_;
1781+
return esc_html_match_hl($str, $regexp) unless defined $chopped;
1782+
1783+
my @matches = matchpos_list($str, $regexp);
1784+
return esc_html($chopped) unless @matches;
1785+
1786+
# filter matches so that we mark chopped string
1787+
my $tail = "... "; # see chop_str
1788+
unless ($chopped =~ s/\Q$tail\E$//) {
1789+
$tail = '';
1790+
}
1791+
my $chop_len = length($chopped);
1792+
my $tail_len = length($tail);
1793+
my @filtered;
1794+
1795+
for my $m (@matches) {
1796+
if ($m->[0] > $chop_len) {
1797+
push @filtered, [ $chop_len, $chop_len + $tail_len ] if ($tail_len > 0);
1798+
last;
1799+
} elsif ($m->[1] > $chop_len) {
1800+
push @filtered, [ $m->[0], $chop_len + $tail_len ];
1801+
last;
1802+
}
1803+
push @filtered, $m;
1804+
}
1805+
1806+
return esc_html_hl_regions($chopped . $tail, 'match', @filtered);
1807+
}
1808+
17271809
## ----------------------------------------------------------------------
17281810
## functions returning short strings
17291811

@@ -5368,10 +5450,17 @@ sub git_project_list_rows {
53685450
print "</td>\n";
53695451
}
53705452
print "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
5371-
-class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
5453+
-class => "list"},
5454+
esc_html_match_hl($pr->{'path'}, $search_regexp)) .
5455+
"</td>\n" .
53725456
"<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"),
5373-
-class => "list", -title => $pr->{'descr_long'}},
5374-
esc_html($pr->{'descr'})) . "</td>\n" .
5457+
-class => "list",
5458+
-title => $pr->{'descr_long'}},
5459+
$search_regexp
5460+
? esc_html_match_hl_chopped($pr->{'descr_long'},
5461+
$pr->{'descr'}, $search_regexp)
5462+
: esc_html($pr->{'descr'})) .
5463+
"</td>\n" .
53755464
"<td><i>" . chop_and_escape_str($pr->{'owner'}, 15) . "</i></td>\n";
53765465
print "<td class=\"". age_class($pr->{'age'}) . "\">" .
53775466
(defined $pr->{'age_string'} ? $pr->{'age_string'} : "No commits") . "</td>\n" .

0 commit comments

Comments
 (0)