From: Tor Arvid Lund Date: Fri, 22 Oct 2010 14:40:38 GMT Subject: Re: [PATCH] git-gui: apply color information from git diff output Message-ID: In-Reply-To: <87pqv2ttjx.fsf_-_@fox.patthoyts.tk> On Fri, Oct 22, 2010 at 12:10 PM, Pat Thoyts wrote: > This patch extracts the ANSI color sequences from git diff output and > applies these to the diff view window. This ensures that the gui view > makes use of the current git configuration for whitespace display. > > ANSI codes may include attributes, foreground and background in a single > sequence. Handle this and support bold and reverse attributes. Ignore > all other attributes. > > Suggested-by: Tor Arvid Lund > Suggested-by: Junio C Hamano > Signed-off-by: Pat Thoyts > --- Tested-by: Tor Arvid Lund It seems to work well for me. I'm just using the default (unset) core.whitespace settings, so space-before-tab and blank-at-eol both show up with red background, just like in the console. -Tor Arvid- > Kevin Ballard writes: > >>On Oct 21, 2010, at 8:22 AM, Pat Thoyts wrote: >> >>> +    while {[regexp -indices -start $start "\033\\\[(\\d+)?m" $line match code]} { >> >>Git currently doesn't emit combined escapes (e.g. \e[0;31m to reset and then turn on red text), but I can imagine it being enhanced to do this in the future. I would recommend handling it here if you can. >> >>-Kevin Ballard > > It turns out that such sequences will be generated by git if the user > configures the color.diff.whitespace (eg: bold cyan magenta). This patch > handles these cases. I don't see any point trying to handle blink. I > could add underline but I don't see that being so appropriate for a > GUI. It seems more like something that is configured for a monochrome > terminal. > >  git-gui.sh   |   10 +++++++++- >  lib/diff.tcl |   34 +++++++++++++++++++++++++++++++++- >  2 files changed, 42 insertions(+), 2 deletions(-) > > diff --git a/git-gui.sh b/git-gui.sh > index 1ccaba1..1fb0254 100755 > --- a/git-gui.sh > +++ b/git-gui.sh > @@ -3322,8 +3322,16 @@ pack $ui_diff -side left -fill both -expand 1 >  pack .vpane.lower.diff.header -side top -fill x >  pack .vpane.lower.diff.body -side bottom -fill both -expand 1 > > +foreach {n c} {0 black 1 red4 2 green4 3 yellow4 4 blue4 5 magenta4 6 cyan4 7 grey60} { > +       $ui_diff tag configure clr4$n -background $c > +       $ui_diff tag configure clri4$n -foreground $c > +       $ui_diff tag configure clr3$n -foreground $c > +       $ui_diff tag configure clri3$n -background $c > +} > +$ui_diff tag configure clr1 -font font_diffbold > + >  $ui_diff tag conf d_cr -elide true > -$ui_diff tag conf d_@ -foreground blue -font font_diffbold > +$ui_diff tag conf d_@ -font font_diffbold >  $ui_diff tag conf d_+ -foreground {#00a000} >  $ui_diff tag conf d_- -foreground red > > diff --git a/lib/diff.tcl b/lib/diff.tcl > index c628750..dcf0711 100644 > --- a/lib/diff.tcl > +++ b/lib/diff.tcl > @@ -294,7 +294,7 @@ proc start_show_diff {cont_info {add_opts {}}} { >        } > >        lappend cmd -p > -       lappend cmd --no-color > +       lappend cmd --color >        if {$repo_config(gui.diffcontext) >= 1} { >                lappend cmd "-U$repo_config(gui.diffcontext)" >        } > @@ -332,6 +332,23 @@ proc start_show_diff {cont_info {add_opts {}}} { >        fileevent $fd readable [list read_diff $fd $cont_info] >  } > > +proc parse_color_line {line} { > +       set start 0 > +       set result "" > +       set markup [list] > +       set regexp {\033\[((?:\d+;)*\d+)?m} > +       while {[regexp -indices -start $start $regexp $line match code]} { > +               foreach {begin end} $match break > +               append result [string range $line $start [expr {$begin - 1}]] > +               lappend markup [string length $result] \ > +                       [eval [linsert $code 0 string range $line]] > +               set start [incr end] > +       } > +       append result [string range $line $start end] > +       if {[llength $markup] < 4} {set markup {}} > +       return [list $result $markup] > +} > + >  proc read_diff {fd cont_info} { >        global ui_diff diff_active is_submodule_diff >        global is_3way_diff is_conflict_diff current_diff_header > @@ -340,6 +357,9 @@ proc read_diff {fd cont_info} { > >        $ui_diff conf -state normal >        while {[gets $fd line] >= 0} { > +               foreach {line markup} [parse_color_line $line] break > +               set line [string map {\033 ^} $line] > + >                # -- Cleanup uninteresting diff header lines. >                # >                if {$::current_diff_inheader} { > @@ -434,11 +454,23 @@ proc read_diff {fd cont_info} { >                        } >                        } >                } > +               set mark [$ui_diff index "end - 1 line linestart"] >                $ui_diff insert end $line $tags >                if {[string index $line end] eq "\r"} { >                        $ui_diff tag add d_cr {end - 2c} >                } >                $ui_diff insert end "\n" $tags > + > +               foreach {posbegin colbegin posend colend} $markup { > +                       set prefix clr > +                       foreach style [split $colbegin ";"] { > +                               if {$style eq "7"} {append prefix i; continue} > +                               if {$style < 30 || $style > 47} {continue} > +                               set a "$mark linestart + $posbegin chars" > +                               set b "$mark linestart + $posend chars" > +                               catch {$ui_diff tag add $prefix$style $a $b} > +                       } > +               } >        } >        $ui_diff conf -state disabled > > -- > 1.7.3.1.msysgit.0 > > >