Search code examples
linuxbashcomparediff

Highlight direct code change (diff, vimdiff, meld)


In a diff the changes are marked in red and green per line. Is there a way to mark the text changes within the line?

That would be a comparison with diff:

diff \
    <(printf "same\nsame-colored changed-bold-colored same-colored\nsame") \
    <(printf "same\nsame-colored CHANGED-BOLD-COLORED same-colored\nsame") 

I would like an output like vimdiff or meld. Only very simple and output directly in the terminal.

Like this output for example:

red='\033[0;31m'; redDark='\033[7;31m'; green='\033[0;32m'; greenDark='\033[7;32m'; noColor='\033[0m'
printf "${red}same-colored ${redDark}changed-bold-colored${red} same-colored${noColor}\n"
printf "${green}same-colored ${greenDark}changed-bold-colored${green} same-colored${noColor}\n"

enter image description here

Is this possible without much effort?


Solution

  • This doesn't produce the output you asked for but it's output may give you the information you need:

    git diff -U0 --no-index --word-diff=color --word-diff-regex=. file1 file2
    

    You do not need to be in a git repo to use that command.

    Here's the same command run 3 times with the output displayed in different ways to make sure it can be seen here:

    enter image description here

    $ git diff -U0 --no-index --word-diff=color --word-diff-regex=. \
        <(printf "same\nsame-colored changed-bold-colored same-colored\nsame") \
        <(printf "same\nsame-colored CHANGED-BOLD-COLORED same-colored\nsame")
    diff --git a/dev/fd/63 b/dev/fd/62
    --- a/dev/fd/63
    +++ b/dev/fd/62
    @@ -2 +2 @@ same
    same-colored changedCHANGED-boldBOLD-coloredCOLORED same-colored
    $
    

    $ git diff -U0 --no-index --word-diff=color --word-diff-regex=. \
        <(printf "same\nsame-colored changed-bold-colored same-colored\nsame") \
        <(printf "same\nsame-colored CHANGED-BOLD-COLORED same-colored\nsame") \
            | cat -A
    ^[[1mdiff --git a/dev/fd/63 b/dev/fd/62^[[m$
    ^[[1m--- a/dev/fd/63^[[m$
    ^[[1m+++ b/dev/fd/62^[[m$
    ^[[36m@@ -2 +2 @@^[[m ^[[msame^[[m$
    same-colored ^[[31mchanged^[[m^[[32mCHANGED^[[m-^[[31mbold^[[m^[[32mBOLD^[[m-^[[31mcolored^[[m^[[32mCOLORED^[[m same-colored$
    $
    

    If you have the kind of problems using process substitution with git diff as described by the OP in comments below or like this:

    $ git diff -U0 --no-index --word-diff=color --word-diff-regex=. \
        <(printf "same\nsame-colored changed-bold-colored same-colored\nsame") \
        <(printf "same\nsame-colored CHANGED-BOLD-COLORED same-colored\nsame" )
    error: Could not access '/proc/2063/fd/63'
    

    then you could write a command like this to ensure that git diff always gets regular files to operate on:

    $ cat $HOME/bin/colordiff
    #!/usr/bin/env bash
    
    tmpDir=$(mktemp -d)  || exit 1
    trap 'rm -rf "$tmpDir"; exit' EXIT
    
    tmpFiles=()
    for file; do
        tmpFile="$tmpDir/$file"
        mkdir -p -- "$tmpDir/${file%/*}"
        cp -- "$file" "$tmpFile"
        tmpFiles+=( "$tmpFile" )
    done
    
    git diff -U0 --no-index --word-diff=color --word-diff-regex=. "${tmpFiles[@]}"
    

    which you'd then call as:

    $ colordiff \
        <(printf "same\nsame-colored changed-bold-colored same-colored\nsame") \
        <(printf "same\nsame-colored CHANGED-BOLD-COLORED same-colored\nsame")
    diff --git a/C:/Some/Path/Temp/tmp.E5Pv4qtlnH/dev/fd/63 b/C:/Some/Path/Temp/tmp.E5Pv4qtlnH/dev/fd/62
    index 078906c..275fedd 100644
    --- a/C:/Some/Path/Temp/tmp.E5Pv4qtlnH/dev/fd/63
    +++ b/C:/Some/Path/Temp/tmp.E5Pv4qtlnH/dev/fd/62
    @@ -2 +2 @@ same
    same-colored changedCHANGED-boldBOLD-coloredCOLORED same-colored