Subject: Re: [PATCH] sideband: color lines with keyword only

From: Jonathan Nieder <[email-masked]>
Date: Mon, 3 Dec 2018 15:23:53 -0800

Hi,

Stefan Beller wrote:

> When bf1a11f0a1 (sideband: highlight keywords in remote sideband output,
> 2018-08-07) was introduced, it was carefully considered which strings
> would be highlighted. However 59a255aef0 (sideband: do not read beyond
> the end of input, 2018-08-18) brought in a regression that the original
> did not test for. A line containing only the keyword and nothing else
> ("SUCCESS") should still be colored.
>
> Signed-off-by: Stefan Beller <[email-masked]>
> ---
>  sideband.c                          | 5 +++--
>  t/t5409-colorize-remote-messages.sh | 2 ++
>  2 files changed, 5 insertions(+), 2 deletions(-)

Thanks for writing this.

I was curious about what versions of Gerrit this is designed to
support (or in other words whether it's a bug fix or a feature).
Looking at examples like [1], it seems that Gerrit historically always
used "ERROR:" so the 59a255aef0 logic would work for it.  More
recently, [2] (ReceiveCommits: add a "SUCCESS" marker for successful
change updates, 2018-08-21) put SUCCESS on a line of its own.  That
puts this squarely in the new-feature category.

"success" on its own line is even less likely to be a false positive
than "success" followed by punctuation (for example a period marking
the end of a sentence).  So I like this change.

[1] https://gerrit-review.googlesource.com/c/gerrit/+/22361
[2] https://gerrit-review.googlesource.com/c/gerrit/+/193570

> diff --git a/sideband.c b/sideband.c
> index 368647acf8..7c3d33d3f8 100644
> --- a/sideband.c
> +++ b/sideband.c
> @@ -87,7 +87,7 @@ static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n)
>  		struct keyword_entry *p = keywords + i;
>  		int len = strlen(p->keyword);
>  
> -		if (n <= len)
> +		if (n < len)
>  			continue;

In the old code, we would escape early if 'n == len', but we didn't
need to.  If 'n == len', then

	src[len] == '\0'
	src .. &src[len-1] is a valid buffer to read from

so the strncasecmp and strbuf_add operations used in this function are
valid.  Good.

>  		/*
>  		 * Match case insensitively, so we colorize output from existing
> @@ -95,7 +95,8 @@ static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n)
>  		 * messages. We only highlight the word precisely, so
>  		 * "successful" stays uncolored.
>  		 */
> -		if (!strncasecmp(p->keyword, src, len) && !isalnum(src[len])) {
> +		if (!strncasecmp(p->keyword, src, len) &&
> +		    (len == n || !isalnum(src[len]))) {

Our custom isalnum treats '\0' as not alphanumeric (sane_ctype[0] ==
GIT_CNTRL) so this part of the patch is unnecessary.  That said, it's
good for clarity and defensive programming.

>  			strbuf_addstr(dest, p->color);
>  			strbuf_add(dest, src, len);
>  			strbuf_addstr(dest, GIT_COLOR_RESET);
> diff --git a/t/t5409-colorize-remote-messages.sh b/t/t5409-colorize-remote-messages.sh
> index f81b6813c0..2a8c449661 100755
> --- a/t/t5409-colorize-remote-messages.sh
> +++ b/t/t5409-colorize-remote-messages.sh
> @@ -17,6 +17,7 @@ test_expect_success 'setup' '
>  	echo " " "error: leading space"
>  	echo "    "
>  	echo Err
> +	echo SUCCESS
>  	exit 0
>  	EOF
>  	echo 1 >file &&
> @@ -35,6 +36,7 @@ test_expect_success 'keywords' '
>  	grep "<BOLD;RED>error<RESET>: error" decoded &&
>  	grep "<YELLOW>hint<RESET>:" decoded &&
>  	grep "<BOLD;GREEN>success<RESET>:" decoded &&
> +	grep "<BOLD;GREEN>SUCCESS<RESET>" decoded &&
>  	grep "<BOLD;YELLOW>warning<RESET>:" decoded
>  '

Nice tests.

The "hinting: not highlighted" example shows that we aren't
introducing false positives here, so the coverage seems sufficient.
It might be nice to include a line

	echo ERROR:

as well to match another idiom that Gerrit sometimes uses.

Reviewed-by: Jonathan Nieder <[email-masked]>

Thanks again for a pleasant read.