#!/bin/sh # Color diff output, for human consumption # License: LGPLv2 # Author: # http://www.pixelbeat.org/ # Notes: # If 2 parameters are passed, then they are passed to # the `diff -Naru` command first. Otherwise the parameters # (or stdin) are assumed to be diff format and are colourised. # # VIM can be useful for viewing diffs also: # diff -Naru a b | vim -R - # vim -R a-b.diff # Changes: # V0.1, 12 Feb 2008, Initial release # V0.2, 18 Feb 2008, Use tput rather than hardcoding escape sequences. # V0.3, 24 Apr 2008, Support Mac OS X # V0.4, 30 Apr 2008, P@draigBrady.com # Use $PAGER if set # Manfred Schwarb # Support `diff -c` format fully. # Pointed out issues with less -EF options. # Suggested to use the less -S option. # V0.5, 18 Jun 2009, P@draigBrady.com # Delineate each file level item with highlight. # Simplify expressions by using '&' in replacement. # Use 't' after all matches for consistency and speed. # less -K reportedly not available on older Mac OS X less -K -Ff /dev/null !2 >/dev/null && global CTRL_C_EXITS := '"-K'" global RED := '1'; global GREEN := '2'; global BLUE := '4'; global BRIGHT := ''1;'' proc tputc { global bright := $1; global colour := $2 test $bright && tput bold tput setaf $colour } global DEL := $[tputc $BRIGHT $RED] global ADD := $[tputc $BRIGHT $GREEN] global CHG := $[tputc $BRIGHT $BLUE] global FIL := $[tput smso] #highlight file level items global RST := $[tput sgr0] if test "$Argc" -eq "2" { diff -Naru @Argv } else { cat @Argv } | sed " s/^\*\{3\}.*\*\{4\}/$CHG&$RST/;t s/^-\{3\}.*-\{4\}/$CHG&$RST/;t s/^@.*/$CHG&$RST/;t s/^[0-9].*/$CHG&$RST/;t s/^!.*/$CHG&$RST/;t s/^-.*/$DEL&$RST/;t s/^<.*/$DEL&$RST/;t s/^\*.*/$ADD&$RST/;t s/^\+.*/$ADD&$RST/;t s/^>.*/$ADD&$RST/;t s/^Only in.*/$FIL&$RST/;t s/^Index: .*/$FIL&$RST/;t s/^diff .*/$FIL&$RST/;t " | $(PAGER:-less -QRS $CTRL_C_EXITS) # could use less -EFX also, but for large files or lots of scrolling, this # is a lot more obtrusive on the terminal as the [de]init codes not used. (CommandList children: [ (AndOr children: [ (SimpleCommand words: [{(less)} {(-K)} {(-Ff)} {(/dev/null)}] redirects: [(Redir op_id:Redir_Great fd:2 arg_word:{(/dev/null)} spids:[95])] ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:CTRL_C_EXITS) op:Equal rhs:{(DQ (-K))} spids:[100])] spids: [100] ) ] op_id: Op_DAmp ) (Sentence child: (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:RED) op:Equal rhs:{(1)} spids:[106])] spids: [106] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:GREEN) op:Equal rhs:{(2)} spids:[110])] spids: [110] ) terminator: ) (Sentence child: (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:BLUE) op:Equal rhs:{(4)} spids:[114])] spids: [114] ) terminator: ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:BRIGHT) op:Equal rhs:{(SQ <"1;">)} spids:[118])] spids: [118] ) (FuncDef name: tputc body: (BraceGroup children: [ (Sentence child: (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:bright) op: Equal rhs: {($ VSub_Number "$1")} spids: [131] ) ] spids: [131] ) terminator: ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:colour) op: Equal rhs: {($ VSub_Number "$2")} spids: [135] ) ] spids: [135] ) (AndOr children: [ (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$bright"))} {(Lit_Other "]")}) (C {(tput)} {(bold)}) ] op_id: Op_DAmp ) (C {(tput)} {(setaf)} {($ VSub_Name "$colour")}) ] spids: [128] ) spids: [124 127] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:DEL) op: Equal rhs: { (DQ (CommandSubPart command_list: (CommandList children: [(C {(tputc)} {($ VSub_Name "$BRIGHT")} {($ VSub_Name "$RED")})] ) left_token: spids: [165 171] ) ) } spids: [163] ) ] spids: [163] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:ADD) op: Equal rhs: { (DQ (CommandSubPart command_list: (CommandList children: [(C {(tputc)} {($ VSub_Name "$BRIGHT")} {($ VSub_Name "$GREEN")})] ) left_token: spids: [176 182] ) ) } spids: [174] ) ] spids: [174] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:CHG) op: Equal rhs: { (DQ (CommandSubPart command_list: (CommandList children: [(C {(tputc)} {($ VSub_Name "$BRIGHT")} {($ VSub_Name "$BLUE")})] ) left_token: spids: [187 193] ) ) } spids: [185] ) ] spids: [185] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:FIL) op: Equal rhs: { (DQ (CommandSubPart command_list: (CommandList children:[(C {(tput)} {(smso)})]) left_token: spids: [198 202] ) ) } spids: [196] ) ] spids: [196] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:RST) op: Equal rhs: { (DQ (CommandSubPart command_list: (CommandList children:[(C {(tput)} {(sgr0)})]) left_token: spids: [210 214] ) ) } spids: [208] ) ] spids: [208] ) (Pipeline children: [ (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Pound "$#"))} {(-eq)} {(DQ (2))} {(Lit_Other "]")}) terminator: ) ] action: [(C {(diff)} {(-Naru)} {(DQ ($ VSub_At "$@"))})] spids: [-1 235] ) ] else_action: [(C {(cat)} {(DQ ($ VSub_At "$@"))})] spids: [246 255] ) (C {(sed)} { (DQ ("\n") ("s/^") (EscapedLiteralPart token:) (EscapedLiteralPart token:) (3) (EscapedLiteralPart token:) (".*") (EscapedLiteralPart token:) (EscapedLiteralPart token:) (4) (EscapedLiteralPart token:) (/) ($ VSub_Name "$CHG") ("&") ($ VSub_Name "$RST") ("/;t\n") (" s/^-") (EscapedLiteralPart token:) (3) (EscapedLiteralPart token:) (".*-") (EscapedLiteralPart token:) (4) (EscapedLiteralPart token:) (/) ($ VSub_Name "$CHG") ("&") ($ VSub_Name "$RST") ("/;t\n") (" s/^@.*/") ($ VSub_Name "$CHG") ("&") ($ VSub_Name "$RST") ("/;t\n") (" s/^[0-9].*/") ($ VSub_Name "$CHG") ("&") ($ VSub_Name "$RST") ("/;t\n") (" s/^!.*/") ($ VSub_Name "$CHG") ("&") ($ VSub_Name "$RST") ("/;t\n") ("\n") (" s/^-.*/") ($ VSub_Name "$DEL") ("&") ($ VSub_Name "$RST") ("/;t\n") (" s/^<.*/") ($ VSub_Name "$DEL") ("&") ($ VSub_Name "$RST") ("/;t\n") ("\n") (" s/^") (EscapedLiteralPart token:) (".*/") ($ VSub_Name "$ADD") ("&") ($ VSub_Name "$RST") ("/;t\n") (" s/^") (EscapedLiteralPart token:) (".*/") ($ VSub_Name "$ADD") ("&") ($ VSub_Name "$RST") ("/;t\n") (" s/^>.*/") ($ VSub_Name "$ADD") ("&") ($ VSub_Name "$RST") ("/;t\n") ("\n") (" s/^Only in.*/") ($ VSub_Name "$FIL") ("&") ($ VSub_Name "$RST") ("/;t\n") (" s/^Index: .*/") ($ VSub_Name "$FIL") ("&") ($ VSub_Name "$RST") ("/;t\n") (" s/^diff .*/") ($ VSub_Name "$FIL") ("&") ($ VSub_Name "$RST") ("/;t\n") ) } ) (C { (BracedVarSub token: suffix_op: (StringUnary op_id: VTest_ColonHyphen arg_word: {("less -QRS ") ($ VSub_Name "$CTRL_C_EXITS")} ) spids: [357 362] ) } ) ] negated: False ) ] )