GNU bug report logs - #26572
problem with "diff --color": escape sequences shouldn't span multiple lines

Previous Next

Package: diffutils;

Reported by: <ian_bruce <at> mail.ru>

Date: Thu, 20 Apr 2017 00:54:01 UTC

Severity: normal

To reply to this bug, email your comments to 26572 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-diffutils <at> gnu.org:
bug#26572; Package diffutils. (Thu, 20 Apr 2017 00:54:01 GMT) Full text and rfc822 format available.

Acknowledgement sent to <ian_bruce <at> mail.ru>:
New bug report received and forwarded. Copy sent to bug-diffutils <at> gnu.org. (Thu, 20 Apr 2017 00:54:01 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: <ian_bruce <at> mail.ru>
To: bug-diffutils <at> gnu.org
Subject: problem with "diff --color": escape sequences shouldn't span
 multiple lines
Date: Wed, 19 Apr 2017 17:39:36 -0700
It appears that when "diff --color" wants to colourize a multi-line
block of text, it outputs ANSI escape sequences only at the beginning
and end of the block. However, it would be preferable if the escape
sequences were repeated at the beginning and end of each separate line.

Although this might seem inefficient, the current behavior causes bad
interactions with other software. For example, with GNU "less":

    diff --color=always -u file.c~ file.c | less -R

Only the first line of a multi-line difference gets coloured. See bug
#294, which is marked as "probably will not fix":

    With the -R flag, less only honors coloring within a single line. If
    a color extends across a newline, the color is reset at the start of
    the next line.

    The performance cost of implementing multi-line coloring is
    excessive. For example, when jumping to the end of the file using
    the G command, less could no longer just seek to the end of the
    file, but would need to read and parse any color sequences in the
    entire file.

http://www.greenwoodsoftware.com/less/bugs.html

In any situation where the output of "diff --color" is subjected to
further processing, colour-escaped text which spans multiple lines will
cause a problem, if either the first or last line of the block is
somehow removed or hidden, as with "less". The solution is to repeat the
escape sequences before and after each newline:

    <COLOUR-ESCAPE-IN>first  line of block<COLOUR-ESCAPE-OUT>\n
    <COLOUR-ESCAPE-IN>second line of block<COLOUR-ESCAPE-OUT>\n
    <COLOUR-ESCAPE-IN>third  line of block<COLOUR-ESCAPE-OUT>\n

Please consider making this small behavior change, so that
"diff --color" will be useful in situations other than direct output to
the terminal (as is clearly intended by the existence of the
"--color=always" option).


-- Ian Bruce




Information forwarded to bug-diffutils <at> gnu.org:
bug#26572; Package diffutils. (Thu, 20 Apr 2017 12:28:01 GMT) Full text and rfc822 format available.

Message #8 received at 26572 <at> debbugs.gnu.org (full text, mbox):

From: <ian_bruce <at> mail.ru>
To: 26572 <at> debbugs.gnu.org
Subject: Re: problem with "diff --color": escape sequences shouldn't span
 multiple lines
Date: Thu, 20 Apr 2017 05:27:02 -0700
[Message part 1 (text/plain, inline)]
On Wed, 19 Apr 2017 17:39:36 -0700
<ian_bruce <at> mail.ru> wrote:

> In any situation where the output of "diff --color" is subjected to
> further processing, colour-escaped text which spans multiple lines
> will cause a problem, if either the first or last line of the block is
> somehow removed or hidden, as with "less". The solution is to repeat
> the escape sequences before and after each newline:
> 
>     <COLOUR-ESCAPE-IN>first  line of block<COLOUR-ESCAPE-OUT>\n
>     <COLOUR-ESCAPE-IN>second line of block<COLOUR-ESCAPE-OUT>\n
>     <COLOUR-ESCAPE-IN>third  line of block<COLOUR-ESCAPE-OUT>\n

For now, this works much better than "diff --color":

    cdiff() 
    { 
      diff "$@" |
        sed -e '/^\(---\|+++\)/s/.*/\c[\[1m&\c[\[0m/' \
            -e      '/^[@0-9]/s/.*/\c[\[36m&\c[\[0m/' \
            -e        '/^[-<]/s/.*/\c[\[31m&\c[\[0m/' \
            -e        '/^[+>]/s/.*/\c[\[32m&\c[\[0m/'
    }

    cdiff -u file.c~ file.c | less -R

The attached images illustrate the differences in output:

    diff --color=always -u file.c~ file.c | less   # diff-color-less.png

    cdiff               -u file.c~ file.c | less   # diff-sed-less.png

It seems like the problem would be solved completely, if the output of
"diff --color" was changed to this form.


-- Ian Bruce
[diff-color-less.png (image/png, attachment)]
[diff-sed-less.png (image/png, attachment)]

This bug report was last modified 8 years and 58 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.