git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCHv3 1/4] gitweb: Introduce esc_html_match_hl and esc_html_hl_regions

From
Jakub Narebski <jnareb@gmail.com>
Date
Feb 27, 2012, 01:55 UTC
Message-ID
<1330307722-25351-2-git-send-email-jnareb@gmail.com>
In-Reply-To
<1330307722-25351-1-git-send-email-jnareb@gmail.com>

The esc_html_match_hl() subroutine added in this commit will be used to highlight *all* matches of given regexp, using 'match' class. Ultimately it is to be used in all match highlighting, starting with project search, which does not have it yet.

It uses the esc_html_hl_regions() subroutine, which is meant to highlight in a given string a list of regions (given as a list of [ beg, end ] pairs of positions in string), using HTML <span> element with given class. It could probably be used in other places that do highlighting of part of ready line, like highlighting of changes in a diff (diff refinement highlighting).

Implementation and enhancement notes:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Currently esc_html_hl_regions() subroutine doesn't accept any
  parameters, like esc_html() does.  We might want for example to
  pass  nbsp=>1  to it.
  It can easily be done with the following code:
    my %opts = grep { ref($_) ne "ARRAY" } @sel;
    @sel     = grep { ref($_) eq "ARRAY" } @sel;
  This allow adding parameters after or before regions, e.g.:
    esc_html_hl_regions("foo bar", "mark", [ 0, 3 ], -nbsp => 1);
* esc_html_hl_regions() escapes like esc_html(); if we wanted to
  highlight with esc_path(), we could pass subroutine reference
  to now named esc_gen_hl_regions().
    esc_html_hl_regions("foo bar", "mark", \&esc_path, [ 0, 3 ]);
  Note that this way we can handle -nbsp=>1 case automatically,
  e.g.
    esc_html_hl_regions("foo bar", "mark",
                        sub { esc_html(@_, -nbsp=>1) },
                        [ 0, 3 ]);
* Alternate solution for highlighting region of a string would be to
  use the idea that strings are to be HTML-escaped, and references to
  scalars are HTML (like in the idea for generic committags).
  This would require modifying gitweb code or esc_html to get list of
  fragments, e.g.:
    esc_html(\'<span class="mark">', 'foo', \'</span>', ' bar',
             { -nbsp => 1 });
  or
    esc_html([\'<span class="mark">', 'foo', \'</span>', ' bar'],
             -nbsp=>1);
  esc_html_match_hl() could be then simple wrapper around "match
  formatter", e.g.
    esc_html([ render_match_hl($str, $regexp) ], -nbsp=>1);
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
This commit is here mainly for the notes in the commit message,
otherwise it could have been squashed with the next commit.  Having
it as a separate commit might help with reviewing.
Changes from v2 (patch was not present in v1):
* Patch includes esc_html_match_hl() subroutine (the interface), and
  not only the esc_html_hl_regions() "engine".
* Slightly expanded "Implementation and enhancement notes" section in
  the commit message.
* Added not about possible future use of esc_html_hl_regions()
  in commit message
 gitweb/gitweb.perl |   41 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 41 insertions(+), 0 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 4ceb1a6..b790f67 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1715,6 +1715,47 @@ sub chop_and_escape_str {
 	}
 }
 
+# Highlight selected fragments of string, using given CSS class,
+# and escape HTML.  It is assumed that fragments do not overlap.
+# Regions are passed as list of pairs (array references).
+#
+# Example: esc_html_hl_regions("foobar", "mark", [ 0, 3 ]) returns
+# '<span class="mark">foo</span>bar'
+sub esc_html_hl_regions {
+	my ($str, $css_class, @sel) = @_;
+	return esc_html($str) unless @sel;
+
+	my $out = '';
+	my $pos = 0;
+
+	for my $s (@sel) {
+		$out .= esc_html(substr($str, $pos, $s->[0] - $pos))
+			if ($s->[0] - $pos > 0);
+		$out .= $cgi->span({-class => $css_class},
+		                   esc_html(substr($str, $s->[0], $s->[1] - $s->[0])));
+
+		$pos = $s->[1];
+	}
+	$out .= esc_html(substr($str, $pos))
+		if ($pos < length($str));
+
+	return $out;
+}
+
+# highlight match (if any), and escape HTML
+sub esc_html_match_hl {
+	my ($str, $regexp) = @_;
+	return esc_html($str) unless defined $regexp;
+
+	my @matches;
+	while ($str =~ /$regexp/g) {
+		push @matches, [$-[0], $+[0]];
+	}
+	return esc_html($str) unless @matches;
+
+	return esc_html_hl_regions($str, 'match', @matches);
+}
+
 ## ----------------------------------------------------------------------
 ## functions returning short strings
 
-- 
1.7.9
Previous: Jakub NarebskiNext: Jakub Narebski
Message 2 of 5 in “[PATCHv3 0/4] gitweb: Match highlighting in project search”
  1. Jakub NarebskiFeb 27, 2012
  2. 1/4 gitweb: Introduce esc_html_match_hl and esc_html_hl_regionsJakub Narebski, Feb 27, 2012
  3. 2/4 gitweb: Highlight matched part of project name when searching projectsJakub Narebski, Feb 27, 2012
  4. 3/4 gitweb: Highlight matched part of project description when searching projectsJakub Narebski, Feb 27, 2012
  5. 4/4 gitweb: Highlight matched part of shortened project descriptionJakub Narebski, Feb 27, 2012

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.