How to make Git display diffs in the terminal with code syntax highlight, like what GitHub does? I mean not only with green for addition and red for deletion, but also with code syntax highlighting.
Syntax highlighting determines the color and style of source code displayed in the Visual Studio Code editor. It is responsible for colorizing keywords like if or for in JavaScript differently than strings and comments and variable names.
If you really want to spruce up your code blocks, you can denote a specific language for syntax highlighting, by typing the name of the language you want the code block to expect right after the first three backticks beginning your code block.
Just add ```diff on start, and ``` on end.
I recently wrote a tool that does this: https://github.com/dandavison/delta
It's possible to write a git diff driver that passes the files through Pygments' pygmentize
tool.
First, define a pygmentize
wrapper with your preferred pygmentize settings (formatter / style / filters) in ~/bin/pygmentize-term
:
#!/bin/sh
exec pygmentize -f terminal256 -O bg=dark,style=trac "$@"
Then, define a generic "diff with syntax highlighting" program in ~/bin/hldiff
:
#!/bin/bash
set -euo pipefail
# Diff two files with syntax highlighting using pygmentize.
# pygmentize-term should be a pygmentize wrapper with your preferred
# pygmentize settings (formatter / style / filters)
function prepare() {
local fn=$1
# Work around https://bitbucket.org/birkenfeld/pygments-main/issues/1437
if [[ "$fn" == /dev/null ]]
then
return
fi
local lexer
lexer=$(pygmentize -N "$fn")
#printf "Detected lexer of %q as %q\n" "$fn" "$lexer" 1>&2
if [[ "$lexer" == text ]]
then
expand "$fn" | pygmentize-term -g
else
expand "$fn" | pygmentize-term -l "$lexer"
fi
}
# Use colordiff (instead of diff --color=always) solely because it
# produces consistent formatting on a per-line basis, saving us from
# having to keep track of state across lines
diff=(colordiff --color=yes)
for arg in "$@"
do
if [[ $arg == -* ]]
then
diff+=("$arg")
else
exec {fd}< <(prepare "$arg")
diff+=(/dev/fd/$fd)
fi
done
sed=(
sed
# replace "all attributes off" (used by Pygmentize to turn off
# bold) with "normal intensity"
-e 's/\x1b\[00m/\x1b[22m/g'
# Replace colordiff's foreground colors with some dark background
# colors. You can customize them here.
-e 's/^\x1b\[0;36m/\x1b[0;36;48;5;23m/' # cyan
-e 's/^\x1b\[0;31m/\x1b[0;31;48;5;52m/' # red
-e 's/^\x1b\[0;32m/\x1b[0;32;48;5;22m/' # green
# Extend background color across the entire terminal window width
-e 's/\x1b\[0;0m$/\x1b\[K\x1b[0m/'
)
"${diff[@]}" | "${sed[@]}"
The above can be used instead of diff
to get a diff of two files with syntax highlighting.
To get git to use it, define a git diff driver wrapper for the above in ~/bin/git-hldiff-driver
:
#!/bin/bash
set -euo pipefail
# Program suitable for GIT_EXTERNAL_DIFF, which will syntax-highlight differences.
hldiff -u "$2" "$5" || true
You can now set GIT_EXTERNAL_DIFF
to the above wrapper script to get git to show diffs with syntax highlighting:
$ GIT_EXTERNAL_DIFF=~/bin/git-hldiff-driver git diff
To get git show
to use it, you need to specify the --ext-diff
switch:
$ GIT_EXTERNAL_DIFF=~/bin/git-hldiff-driver git show --ext-diff
Note that by default git show
will send its output through a pager (less
), which will cause the background color to not be displayed quite properly, so also add --no-pager
to prevent that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With