Skip to content

Commit 6f8d23a

Browse files
committed
Initial commit
0 parents  commit 6f8d23a

File tree

5 files changed

+254
-0
lines changed

5 files changed

+254
-0
lines changed

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
git-diff-syntax-highlight
2+
=========================
3+
4+
Utilities to include syntax highlighting in the terminal, for git diffs and other commands.
5+
This is a patched version of https://gist.github.com/skanev/0eeb943e3111a1df55fd
6+
which fixes rare bugs I've encountered in that gist.
7+
8+
This is configured to highlight ruby, C, C++, Clojure, CSS, ERB, Go, Java, JavaScript, JSON, PHP, Lua, Python, SASS, SCSS, SQL, XML, and YAML files.
9+
10+
Known Issues
11+
------------
12+
13+
- RVM can break this when switching to a different ruby version.
14+
- Highlighting using background colors is poorly handled and result in code that are hard to read.
15+
This may be fixable by ensuring some minimum contrast when generating color codes.
16+
- At the time of writing, there is no support for Markdown in `coderay`, which this depends on
17+
18+
Dependencies
19+
------------
20+
21+
This requires that `term-ansicolor` and `coderay` be installed, and that ruby be set up.
22+
23+
```
24+
gem install --user term-ansicolor coderay
25+
```
26+
27+
Colorizing Git diffs
28+
--------------------
29+
30+
31+
Add the following to .gitconfig.
32+
33+
The `simple-log`, `simple-diff`, and `simple-show` aliases are provided because syntax highlighting is slow for projects with long histories,
34+
and because changes in rvm paths can break diffs completely.
35+
36+
```
37+
[core]
38+
pager = /path/to/git-diff-syntax-highlight.rb | less
39+
```
40+
41+
42+
The `git-simple-*` scripts are found in [./bin](./bin).
43+
After adding those to a directory the shell's `$PATH`, you probably also want to create aliases for the original diffs.
44+
45+
```
46+
[alias]
47+
simple-log = !git-simple-log
48+
simple-diff = !git-simple-diff
49+
simple-show = !git-simple-show
50+
```

bin/git-simple-diff

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/sh
2+
# Installation:
3+
# git config --global alias.simple-diff '!git-simple-diff'
4+
git --no-pager diff -p --color "$@" | less -R -F -X

bin/git-simple-log

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/sh
2+
# Installation:
3+
# git config --global alias.simple-log '!git-simple-log'
4+
git --no-pager log -p --color "$@" | less -R -F -X

bin/git-simple-show

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/sh
2+
# Installation:
3+
# git config --global alias.simple-show '!git-simple-show'
4+
git --no-pager show -p --color "$@" | less -R -F -X

git-diff-syntax-highlight.rb

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
#!/usr/bin/ruby
2+
# Source: https://gist.github.com/skanev/0eeb943e3111a1df55fd
3+
# This hardcodes the path to ruby to avoid interference from rvm
4+
#
5+
# Usage: add the following to .gitconfig
6+
#
7+
# [core]
8+
# pager = /path/to/git-diff-syntax-highlight.rb | less
9+
#
10+
# Dependencies:
11+
# gem install --user term-ansicolor coderay
12+
require 'coderay'
13+
require 'term/ansicolor'
14+
require 'optparse'
15+
16+
# --- Adjusting colors -------------------------------------------------------
17+
18+
RGB = Term::ANSIColor::RGBTriple
19+
Attribute = Term::ANSIColor::Attribute
20+
Color = Term::ANSIColor
21+
22+
GREEN = RGB.new(0, 256, 0)
23+
RED = RGB.new(256, 0, 0)
24+
GRAY = RGB.new(180, 180, 180)
25+
26+
ADJUSTMENTS = {}
27+
GRADIENTS = {}
28+
29+
def adjust(text, target, gradient = 8)
30+
open = adjust_seq("\e[37m", target, gradient)
31+
adjusted = text.chomp.gsub(/\e\[[0-9;]+m/) { |seq| adjust_seq(seq, target, gradient) }
32+
33+
"#{open}#{adjusted}"
34+
end
35+
36+
def adjust_seq(seq, target, level)
37+
key = [seq, target]
38+
39+
ADJUSTMENTS[key] ||=
40+
begin
41+
escapes = []
42+
43+
seq[/\d+(;\d+)*/].split(';').map(&:to_i).each do |number|
44+
case number
45+
when 0 then escapes << ["\e[0m", gradient_to(255, target, level)]
46+
when 1 then escapes << "\e[1m"
47+
when 4 then escapes << "\e[4m"
48+
when 30..37 then escapes << gradient_to(number - 30, target, level)
49+
when 40..47 then escapes << gradient_to(number - 30, target, level, :background)
50+
else escapes << seq
51+
end
52+
end
53+
54+
escapes.join('')
55+
end
56+
end
57+
58+
59+
def gradient_to(num, target, level, background = false)
60+
key = [num, target, background]
61+
62+
GRADIENTS[key] ||=
63+
begin
64+
triple = triple(num)
65+
target = triple.gradient_to(target)[level]
66+
html = target.html
67+
method = background ? "on_#{html}" : html
68+
69+
Attribute[method].apply
70+
end
71+
end
72+
73+
def triple(num)
74+
Attribute[num].to_rgb_triple
75+
end
76+
77+
# --- Parsing git diffs ------------------------------------------------------
78+
79+
FORMATS = {
80+
'Gemfile' => :ruby,
81+
'rb' => :ruby,
82+
'c' => :c,
83+
'h' => :c,
84+
'cpp' => :cpp,
85+
'cxx' => :cpp,
86+
'hpp' => :cpp,
87+
'clj' => :clojure,
88+
'css' => :css,
89+
'erb' => :erb,
90+
'go' => :go,
91+
'java' => :java,
92+
'js' => :javascript,
93+
'json' => :json,
94+
'php' => :php,
95+
'html' => :php,
96+
'lua' => :lua,
97+
'py' => :python,
98+
'sass' => :sass,
99+
'scss' => :scss,
100+
'sql' => :sql,
101+
'xml' => :xml,
102+
'yml' => :yaml,
103+
'yaml' => :yaml,
104+
}
105+
106+
CACHED_OBJECTS = {}
107+
108+
def show(sha, path)
109+
return [] if sha =~ /^0+$/
110+
111+
cached = CACHED_OBJECTS.delete sha
112+
return cached if cached
113+
114+
format = FORMATS[path[/(\w+)$/, 1]]
115+
code = `git show #{sha} 2> /dev/null`
116+
code = File.read(path) if code.empty?
117+
code = CodeRay.scan(code, format).terminal if format
118+
CACHED_OBJECTS[sha] = code.lines
119+
end
120+
121+
def process(options)
122+
new = nil
123+
old = nil
124+
remaining = nil
125+
old_file = nil
126+
new_file = nil
127+
old_hash = nil
128+
new_hash = nil
129+
130+
while gets
131+
stripped = $_.gsub(/(\e\[[0-9;]*m)*/, '')
132+
case stripped
133+
when /^index (\w+)..(\w+)/
134+
old_hash = $1
135+
new_hash = $2
136+
puts $_
137+
# @@ -1,4 +1,4 @@
138+
when /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/
139+
old_start, old_length = $1.to_i - 1, ($2 || 1).to_i
140+
new_start, new_length = $3.to_i - 1, ($4 || 1).to_i
141+
142+
remaining = old_length + new_length
143+
puts $_
144+
when /^\+\+\+ (.*)$/
145+
new_file = $1.sub(/^[ab]\//, '')
146+
old = show old_hash, old_file
147+
new = show new_hash, new_file
148+
puts $_
149+
when /^--- (.*)$/
150+
old_file = $1.sub(/^[ab]\//, '')
151+
puts $_
152+
when /^ /
153+
if remaining.nil? || remaining <= 0
154+
puts $_
155+
next
156+
elsif options[:highlight]
157+
puts adjust(" #{new[new_start]}", GRAY, 10)
158+
else
159+
puts $_
160+
end
161+
162+
remaining -= 2
163+
old_start += 1
164+
new_start += 1
165+
when /^\+/
166+
puts adjust("+#{new[new_start]}", GREEN)
167+
new_start += 1
168+
remaining -= 1
169+
when /^-/
170+
puts adjust("-#{old[old_start]}", RED)
171+
old_start += 1
172+
remaining -= 1
173+
else
174+
puts $_
175+
end
176+
end
177+
end
178+
179+
options = {}
180+
OptionParser.new do |opts|
181+
opts.banner = "Usage: #{File.basename(__FILE__)} [options]"
182+
183+
opts.on("-h", "--[no-]highlight", "Highlight all the code") do |v|
184+
options[:highlight] = v
185+
end
186+
end.parse!
187+
188+
begin
189+
process(options)
190+
rescue Errno::EPIPE
191+
exit 0
192+
end

0 commit comments

Comments
 (0)