git_helpers 0.1.0 → 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ChangeLog.md +99 -2
- data/LICENSE.txt +1 -1
- data/Rakefile +7 -10
- data/bin/diff-fancy.rb +1 -0
- data/bin/gitstatus.old.rb +349 -0
- data/bin/gitstatus.rb +74 -305
- data/lib/git_helpers.rb +24 -330
- data/lib/git_helpers/branch.rb +216 -0
- data/lib/git_helpers/branch_infos.rb +178 -0
- data/lib/git_helpers/diff.rb +701 -0
- data/lib/git_helpers/extra_helpers.rb +24 -220
- data/lib/git_helpers/git_dir.rb +176 -0
- data/lib/git_helpers/raw_helpers.rb +105 -0
- data/lib/git_helpers/stats.rb +183 -0
- data/lib/git_helpers/status.rb +404 -0
- data/lib/git_helpers/submodules.rb +32 -0
- data/lib/git_helpers/version.rb +1 -1
- metadata +13 -3
- data/bin/diff-fancy.rb +0 -699
@@ -0,0 +1,32 @@
|
|
1
|
+
module GitHelpers
|
2
|
+
module GitSubmodules
|
3
|
+
def foreach(commited: true, modified: true, untracked: true, recursive: false, &b)
|
4
|
+
r=[]
|
5
|
+
st=status
|
6
|
+
st[:paths].each do |k,v|
|
7
|
+
sub=v[:submodule]
|
8
|
+
if sub
|
9
|
+
sub_commited=v[:sub_commited]
|
10
|
+
sub_modified=v[:sub_modified]
|
11
|
+
sub_untracked=v[:sub_untracked]
|
12
|
+
if (commited && sub_commited or modified && sub_modified or untracked && sub_untracked)
|
13
|
+
b.call(k, v) if b
|
14
|
+
r << k
|
15
|
+
end
|
16
|
+
|
17
|
+
if recursive
|
18
|
+
# Dir.chdir(k) do
|
19
|
+
# rec=GitDir.new.foreach(commited: commited, modified: modified, untracked: untracked, recursive: true, &b)
|
20
|
+
# r+=rec
|
21
|
+
# end
|
22
|
+
GitDir.new(k).with_dir do |g|
|
23
|
+
rec=g.foreach(commited: commited, modified: modified, untracked: untracked, recursive: true, &b)
|
24
|
+
r+=rec.map {|sub| g.reldir+sub}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
r
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/git_helpers/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git_helpers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.2'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Damien Robert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-02-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: shell_helpers
|
@@ -126,6 +126,7 @@ description: Add status line 'gitstatus.rb' and diff enhancement 'diff-fancy.rb'
|
|
126
126
|
email: Damien.Olivier.Robert+gems@gmail.com
|
127
127
|
executables:
|
128
128
|
- diff-fancy.rb
|
129
|
+
- gitstatus.old.rb
|
129
130
|
- gitstatus.rb
|
130
131
|
extensions: []
|
131
132
|
extra_rdoc_files:
|
@@ -142,12 +143,21 @@ files:
|
|
142
143
|
- README.md
|
143
144
|
- Rakefile
|
144
145
|
- bin/diff-fancy.rb
|
146
|
+
- bin/gitstatus.old.rb
|
145
147
|
- bin/gitstatus.rb
|
146
148
|
- fixtures/git-diff.diff
|
147
149
|
- gemspec.yml
|
148
150
|
- git_helpers.gemspec
|
149
151
|
- lib/git_helpers.rb
|
152
|
+
- lib/git_helpers/branch.rb
|
153
|
+
- lib/git_helpers/branch_infos.rb
|
154
|
+
- lib/git_helpers/diff.rb
|
150
155
|
- lib/git_helpers/extra_helpers.rb
|
156
|
+
- lib/git_helpers/git_dir.rb
|
157
|
+
- lib/git_helpers/raw_helpers.rb
|
158
|
+
- lib/git_helpers/stats.rb
|
159
|
+
- lib/git_helpers/status.rb
|
160
|
+
- lib/git_helpers/submodules.rb
|
151
161
|
- lib/git_helpers/version.rb
|
152
162
|
- test/helper.rb
|
153
163
|
- test/test_git_helpers.rb
|
@@ -171,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
171
181
|
- !ruby/object:Gem::Version
|
172
182
|
version: '0'
|
173
183
|
requirements: []
|
174
|
-
rubygems_version: 3.
|
184
|
+
rubygems_version: 3.1.2
|
175
185
|
signing_key:
|
176
186
|
specification_version: 4
|
177
187
|
summary: Git helpers utilities
|
data/bin/diff-fancy.rb
DELETED
@@ -1,699 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# Inspired by diff-so-fancy; wrapper around diff-highlight
|
3
|
-
# https://github.com/stevemao/diff-so-fancy
|
4
|
-
# [commit: 0ea7c129420c57ec0384a704325e27c41f8f450d,
|
5
|
-
# last commit checked: 3adf0114da99643ec53a16253a3d6f42390e4c19 (2017-04-04)]
|
6
|
-
#TODO: use git-config
|
7
|
-
#TODO: work with 'git log -p --graph'
|
8
|
-
|
9
|
-
require "simplecolor"
|
10
|
-
SimpleColor.mix_in_string
|
11
|
-
begin
|
12
|
-
require "shell_helpers"
|
13
|
-
rescue LoadError
|
14
|
-
end
|
15
|
-
|
16
|
-
class GitDiff
|
17
|
-
def self.output(gdiff, **opts)
|
18
|
-
if gdiff.respond_to?(:each_line)
|
19
|
-
enum=gdiff.each_line
|
20
|
-
else
|
21
|
-
enum=gdiff.each
|
22
|
-
end
|
23
|
-
self.new(enum, **opts).output
|
24
|
-
end
|
25
|
-
|
26
|
-
attr_reader :output
|
27
|
-
include Enumerable
|
28
|
-
NoNewLine="\\n"
|
29
|
-
|
30
|
-
def initialize(diff,**opts)
|
31
|
-
@diff=diff #Assume diff is a line iterator ['gitdiff'.each_line]
|
32
|
-
@current=0
|
33
|
-
@mode=:unknown
|
34
|
-
@opts=opts
|
35
|
-
@opts[:color]=@opts.fetch(:color,true)
|
36
|
-
#modes:
|
37
|
-
#- unknown (temp mode)
|
38
|
-
#- commit
|
39
|
-
#- meta
|
40
|
-
#- submodule_header
|
41
|
-
#- submodule
|
42
|
-
#- diff_header
|
43
|
-
#- hunk
|
44
|
-
@colors={meta: [:bold]}
|
45
|
-
end
|
46
|
-
|
47
|
-
def output_line(l)
|
48
|
-
@output << l.chomp+"\n"
|
49
|
-
end
|
50
|
-
def output_lines(lines)
|
51
|
-
lines.each {|l| output_line l}
|
52
|
-
end
|
53
|
-
def output
|
54
|
-
each {|l| puts l}
|
55
|
-
end
|
56
|
-
|
57
|
-
def next_mode(nmode)
|
58
|
-
@next_mode=nmode
|
59
|
-
end
|
60
|
-
def update_mode
|
61
|
-
@start_mode=false
|
62
|
-
@next_mode && change_mode(@next_mode)
|
63
|
-
@next_mode=nil
|
64
|
-
end
|
65
|
-
def change_mode(nmode)
|
66
|
-
@start_mode=true
|
67
|
-
send :"end_#{@mode}" unless @mode==:unknown
|
68
|
-
@mode=nmode
|
69
|
-
send :"new_#{@mode}" unless @mode==:unknown
|
70
|
-
end
|
71
|
-
|
72
|
-
def new_commit; @commit={}; end
|
73
|
-
def end_commit; end
|
74
|
-
def new_meta; end
|
75
|
-
def end_meta; end
|
76
|
-
def new_hunk; end
|
77
|
-
def end_hunk; end
|
78
|
-
def new_submodule_header; @submodule={}; end
|
79
|
-
def end_submodule_header; end
|
80
|
-
def new_submodule; end
|
81
|
-
def end_submodule; end
|
82
|
-
def new_diff_header; @file={mode: :modify} end
|
83
|
-
def end_diff_header; end
|
84
|
-
|
85
|
-
def detect_new_diff_header
|
86
|
-
@line =~ /^diff\s/
|
87
|
-
end
|
88
|
-
def detect_end_diff_header
|
89
|
-
@line =~ /^\+\+\+\s/
|
90
|
-
end
|
91
|
-
|
92
|
-
def detect_new_hunk
|
93
|
-
@line.match(/^@@+\s.*\s@@/)
|
94
|
-
end
|
95
|
-
def detect_end_hunk
|
96
|
-
@hunk[:lines_seen].each_with_index.all? { |v,i| v==@hunk[:lines][i].first }
|
97
|
-
end
|
98
|
-
|
99
|
-
def handle_meta
|
100
|
-
handle_line
|
101
|
-
end
|
102
|
-
|
103
|
-
def parse_hunk_header
|
104
|
-
m=@line.match(/^@@+\s(.*)\s@@\s*(.*)/)
|
105
|
-
hunks=m[1]
|
106
|
-
@hunk={lines: []}
|
107
|
-
@hunk[:header]=m[2]
|
108
|
-
filenumber=0
|
109
|
-
hunks.split.each do |hunk|
|
110
|
-
hunkmode=hunk[0]
|
111
|
-
hunk=hunk[1..-1]
|
112
|
-
line,length=hunk.split(',').map(&:to_i)
|
113
|
-
#handle hunks of the form @@ -1 +0,0 @@
|
114
|
-
length,line=line,length unless length
|
115
|
-
case hunkmode
|
116
|
-
when '-'
|
117
|
-
filenumber+=1
|
118
|
-
@hunk[:lines][filenumber]=[length,line]
|
119
|
-
when '+'
|
120
|
-
@hunk[:lines][0]=[length,line]
|
121
|
-
end
|
122
|
-
end
|
123
|
-
@hunk[:n]=@hunk[:lines].length
|
124
|
-
@hunk[:lines_seen]=Array.new(@hunk[:n],0)
|
125
|
-
end
|
126
|
-
|
127
|
-
def handle_hunk
|
128
|
-
if @start_mode
|
129
|
-
parse_hunk_header
|
130
|
-
else
|
131
|
-
#'The 'No new line at end of file' is sort of part of the hunk, but
|
132
|
-
#is not considerer in the hunkheader
|
133
|
-
unless @line == NoNewLine
|
134
|
-
#we need to wait for a NoNewLine to be sure we are at the end of the hunk
|
135
|
-
return reparse(:unknown) if detect_end_hunk
|
136
|
-
linemodes=@line[0...@hunk[:n]-1]
|
137
|
-
newline=true
|
138
|
-
#the line is on the new file unless there is a '-' somewhere
|
139
|
-
if linemodes=~/-/
|
140
|
-
newline=false
|
141
|
-
else
|
142
|
-
@hunk[:lines_seen][0]+=1
|
143
|
-
end
|
144
|
-
(1...@hunk[:n]).each do |i|
|
145
|
-
linemode=linemodes[i-1]
|
146
|
-
case linemode
|
147
|
-
when '-'
|
148
|
-
@hunk[:lines_seen][i]+=1
|
149
|
-
when ' '
|
150
|
-
@hunk[:lines_seen][i]+=1 if newline
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
handle_line
|
156
|
-
end
|
157
|
-
|
158
|
-
def get_file_name(file)
|
159
|
-
#remove prefix (todo handle the no-prefix option)
|
160
|
-
file.gsub(/^[abciow12]\//,'')
|
161
|
-
end
|
162
|
-
|
163
|
-
def detect_filename
|
164
|
-
if m=@line.match(/^---\s(.*)/)
|
165
|
-
@file[:old_name]=get_file_name(m[1])
|
166
|
-
return true
|
167
|
-
end
|
168
|
-
if m=@line.match(/^\+\+\+\s(.*)/)
|
169
|
-
@file[:name]=get_file_name(m[1])
|
170
|
-
return true
|
171
|
-
end
|
172
|
-
false
|
173
|
-
end
|
174
|
-
|
175
|
-
def detect_perm
|
176
|
-
if m=@line.match(/^old mode\s+(.*)/)
|
177
|
-
@file[:old_perm]=m[1]
|
178
|
-
return true
|
179
|
-
end
|
180
|
-
if m=@line.match(/^new mode\s+(.*)/)
|
181
|
-
@file[:new_perm]=m[1]
|
182
|
-
return true
|
183
|
-
end
|
184
|
-
false
|
185
|
-
end
|
186
|
-
|
187
|
-
def detect_index
|
188
|
-
if m=@line.match(/^index\s+(.*)\.\.(.*)/)
|
189
|
-
@file[:oldhash]=m[1].split(',')
|
190
|
-
@file[:hash],perm=m[2].split
|
191
|
-
@file[:perm]||=perm
|
192
|
-
return true
|
193
|
-
end
|
194
|
-
false
|
195
|
-
end
|
196
|
-
|
197
|
-
def detect_delete
|
198
|
-
if m=@line.match(/^deleted file mode\s+(.*)/)
|
199
|
-
@file[:old_perm]=m[1]
|
200
|
-
@file[:mode]=:delete
|
201
|
-
return true
|
202
|
-
end
|
203
|
-
false
|
204
|
-
end
|
205
|
-
|
206
|
-
def detect_newfile
|
207
|
-
if m=@line.match(/^new file mode\s+(.*)/)
|
208
|
-
@file[:new_perm]=m[1]
|
209
|
-
@file[:mode]=:new
|
210
|
-
return true
|
211
|
-
end
|
212
|
-
false
|
213
|
-
end
|
214
|
-
|
215
|
-
def detect_rename_copy
|
216
|
-
if m=@line.match(/^similarity index\s+(.*)/)
|
217
|
-
@file[:similarity]=m[1]
|
218
|
-
return true
|
219
|
-
end
|
220
|
-
if m=@line.match(/^dissimilarity index\s+(.*)/)
|
221
|
-
@file[:mode]=:rewrite
|
222
|
-
@file[:dissimilarity]=m[1]
|
223
|
-
return true
|
224
|
-
end
|
225
|
-
#if we have a rename with 100% similarity, there won't be any hunks so
|
226
|
-
#we need to detect the filenames there
|
227
|
-
if m=@line.match(/^(?:rename|copy) from\s+(.*)/)
|
228
|
-
@file[:old_name]=m[1]
|
229
|
-
end
|
230
|
-
if m=@line.match(/^(?:rename|copy) to\s+(.*)/)
|
231
|
-
@file[:name]=m[1]
|
232
|
-
end
|
233
|
-
if m=@line.match(/^rename\s+(.*)/)
|
234
|
-
@file[:mode]=:rename
|
235
|
-
return true
|
236
|
-
end
|
237
|
-
if m=@line.match(/^copy\s+(.*)/)
|
238
|
-
@file[:mode]=:copy
|
239
|
-
return true
|
240
|
-
end
|
241
|
-
false
|
242
|
-
end
|
243
|
-
|
244
|
-
def detect_diff_header
|
245
|
-
if @start_mode
|
246
|
-
if m=@line.chomp.match(/^diff\s--git\s(.*)\s(.*)/)
|
247
|
-
@file[:old_name]=get_file_name(m[1])
|
248
|
-
@file[:name]=get_file_name(m[2])
|
249
|
-
elsif
|
250
|
-
m=@line.match(/^diff\s--(?:cc|combined)\s(.*)/)
|
251
|
-
@file[:name]=get_file_name(m[1])
|
252
|
-
end
|
253
|
-
true
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
def handle_diff_header
|
258
|
-
if detect_diff_header
|
259
|
-
elsif detect_filename
|
260
|
-
elsif detect_perm
|
261
|
-
elsif detect_index
|
262
|
-
elsif detect_delete
|
263
|
-
elsif detect_newfile
|
264
|
-
elsif detect_rename_copy
|
265
|
-
else
|
266
|
-
return reparse(:unknown)
|
267
|
-
end
|
268
|
-
next_mode(:unknown) if detect_end_diff_header
|
269
|
-
handle_line
|
270
|
-
end
|
271
|
-
|
272
|
-
def detect_new_submodule_header
|
273
|
-
if m=@line.chomp.match(/^Submodule\s(.*)\s(.*)/)
|
274
|
-
subname=m[1];
|
275
|
-
return not(@submodule && @submodule[:name]==subname)
|
276
|
-
end
|
277
|
-
false
|
278
|
-
end
|
279
|
-
|
280
|
-
def handle_submodule_header
|
281
|
-
if m=@line.chomp.match(/^Submodule\s(\S*)\s(.*)/)
|
282
|
-
subname=m[1]
|
283
|
-
if @submodule[:name]
|
284
|
-
#we may be dealing with a new submodule
|
285
|
-
#require 'pry'; binding.pry
|
286
|
-
return reparse(:submodule_header) if subname != @submodule[:name]
|
287
|
-
else
|
288
|
-
@submodule[:name]=m[1]
|
289
|
-
end
|
290
|
-
subinfo=m[2]
|
291
|
-
if subinfo == "contains untracked content"
|
292
|
-
@submodule[:untracked]=true
|
293
|
-
elsif subinfo == "contains modified content"
|
294
|
-
@submodule[:modified]=true
|
295
|
-
else
|
296
|
-
(@submodule[:info]||="") << subinfo
|
297
|
-
next_mode(:submodule) if subinfo =~ /^.......\.\.\.?........*:$/
|
298
|
-
end
|
299
|
-
handle_line
|
300
|
-
else
|
301
|
-
return reparse(:unknown)
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
|
-
def submodule_line
|
306
|
-
@line=~/^ [><] /
|
307
|
-
end
|
308
|
-
|
309
|
-
def handle_submodule
|
310
|
-
#we have lines indicating new commits
|
311
|
-
#they always end by a new line except when followed by another submodule
|
312
|
-
return reparse(:unknown) if !submodule_line
|
313
|
-
handle_line
|
314
|
-
end
|
315
|
-
|
316
|
-
def detect_new_commit
|
317
|
-
@line=~/^commit\b/
|
318
|
-
end
|
319
|
-
|
320
|
-
def handle_commit
|
321
|
-
if m=@line.match(/^(\w+):\s(.*)/)
|
322
|
-
@commit[m[1]]=m[2]
|
323
|
-
handle_line
|
324
|
-
else
|
325
|
-
@start_mode ? handle_line : reparse(:unknown)
|
326
|
-
end
|
327
|
-
end
|
328
|
-
|
329
|
-
def reparse(nmode)
|
330
|
-
change_mode(nmode)
|
331
|
-
parse_line
|
332
|
-
end
|
333
|
-
|
334
|
-
def handle_line
|
335
|
-
end
|
336
|
-
|
337
|
-
|
338
|
-
def parse_line
|
339
|
-
case @mode
|
340
|
-
when :unknown, :meta
|
341
|
-
if detect_new_hunk
|
342
|
-
return reparse(:hunk)
|
343
|
-
elsif detect_new_diff_header
|
344
|
-
return reparse(:diff_header)
|
345
|
-
elsif detect_new_submodule_header
|
346
|
-
return reparse(:submodule_header)
|
347
|
-
elsif detect_new_commit
|
348
|
-
return reparse(:commit)
|
349
|
-
else
|
350
|
-
change_mode(:meta) if @mode==:unknown
|
351
|
-
handle_meta
|
352
|
-
end
|
353
|
-
when :commit
|
354
|
-
handle_commit
|
355
|
-
when :submodule_header
|
356
|
-
handle_submodule_header
|
357
|
-
when :submodule
|
358
|
-
handle_submodule
|
359
|
-
when :diff_header
|
360
|
-
handle_diff_header
|
361
|
-
#=> mode=unknown if we detect we are not a diff header anymore
|
362
|
-
when :hunk
|
363
|
-
handle_hunk
|
364
|
-
#=> mode=unknown at end of hunk
|
365
|
-
end
|
366
|
-
end
|
367
|
-
|
368
|
-
def prepare_new_line(line)
|
369
|
-
@orig_line=line
|
370
|
-
@line=@orig_line.uncolor
|
371
|
-
update_mode
|
372
|
-
end
|
373
|
-
|
374
|
-
def parse
|
375
|
-
Enumerator.new do |y|
|
376
|
-
@output=y
|
377
|
-
@diff.each do |line|
|
378
|
-
prepare_new_line(line)
|
379
|
-
parse_line
|
380
|
-
yield if block_given?
|
381
|
-
end
|
382
|
-
change_mode(:unknown) #to trigger the last end_* hook
|
383
|
-
end
|
384
|
-
end
|
385
|
-
|
386
|
-
def each(&b)
|
387
|
-
parse.each(&b)
|
388
|
-
end
|
389
|
-
end
|
390
|
-
|
391
|
-
class GitDiffDebug < GitDiff
|
392
|
-
def initialize(*args,&b)
|
393
|
-
super
|
394
|
-
@cols=`tput cols`.to_i
|
395
|
-
end
|
396
|
-
|
397
|
-
def center(msg)
|
398
|
-
msg.center(@cols,'─')
|
399
|
-
end
|
400
|
-
|
401
|
-
def handle_line
|
402
|
-
super
|
403
|
-
output_line "#{@mode}: #{@orig_line}"
|
404
|
-
#p @hunk if @mode==:hunk
|
405
|
-
end
|
406
|
-
|
407
|
-
%i(commit meta diff_header hunk submodule_header submodule).each do |meth|
|
408
|
-
define_method(:"new_#{meth}") do |*a,&b|
|
409
|
-
super(*a,&b)
|
410
|
-
output_line(center("New #{meth}"))
|
411
|
-
end
|
412
|
-
define_method(:"end_#{meth}") do |*a,&b|
|
413
|
-
super(*a,&b)
|
414
|
-
output_line(center("End #{meth}"))
|
415
|
-
end
|
416
|
-
end
|
417
|
-
end
|
418
|
-
|
419
|
-
#stolen from diff-highlight git contrib script
|
420
|
-
class GitDiffHighlight < GitDiff
|
421
|
-
def new_hunk
|
422
|
-
super
|
423
|
-
@accumulator=[[],[]]
|
424
|
-
end
|
425
|
-
def end_hunk
|
426
|
-
super
|
427
|
-
show_hunk
|
428
|
-
end
|
429
|
-
|
430
|
-
def highlight_pair(old,new)
|
431
|
-
oldc=SimpleColor.color_entities(old).each_with_index
|
432
|
-
newc=SimpleColor.color_entities(new).each_with_index
|
433
|
-
seen_pm=false
|
434
|
-
#find common prefix
|
435
|
-
loop do
|
436
|
-
a=oldc.grep {|c| ! SimpleColor.color?(c)}
|
437
|
-
b=newc.grep {|c| ! SimpleColor.color?(c)}
|
438
|
-
if !seen_pm and a=="-" and b=="+"
|
439
|
-
seen_pm=true
|
440
|
-
elsif a==b
|
441
|
-
else
|
442
|
-
last
|
443
|
-
end
|
444
|
-
#rescue StopIteration
|
445
|
-
end
|
446
|
-
end
|
447
|
-
|
448
|
-
def show_hunk
|
449
|
-
old,new=@accumulator
|
450
|
-
if old.length != new.length
|
451
|
-
output_lines(old+new)
|
452
|
-
else
|
453
|
-
newhunk=[]
|
454
|
-
(0...old.length).each do |i|
|
455
|
-
oldi,newi=highlight_pair(old[i],new[i])
|
456
|
-
output_line oldi
|
457
|
-
newhunk << newi
|
458
|
-
end
|
459
|
-
output_lines(newhunk)
|
460
|
-
end
|
461
|
-
end
|
462
|
-
|
463
|
-
def handle_line
|
464
|
-
if @mode == :hunk && @hunk[:n]==2
|
465
|
-
linemode=@line[0]
|
466
|
-
case linemode
|
467
|
-
when "-"
|
468
|
-
@accumulator[0] << @orig_line
|
469
|
-
when "+"
|
470
|
-
@accumulator[1] << @orig_line
|
471
|
-
else
|
472
|
-
show_hunk
|
473
|
-
@accumulator=[[],[]]
|
474
|
-
output_line @orig_line
|
475
|
-
end
|
476
|
-
else
|
477
|
-
output_line @orig_line
|
478
|
-
end
|
479
|
-
end
|
480
|
-
end
|
481
|
-
|
482
|
-
class GitFancyDiff < GitDiff
|
483
|
-
|
484
|
-
def initialize(*args,&b)
|
485
|
-
super
|
486
|
-
#when run inside a pager I get one more column so the line overflow
|
487
|
-
#I don't know why
|
488
|
-
cols=`tput cols`.to_i
|
489
|
-
cols==0 && cols=80 #if TERM is not defined `tput cols` returns ''
|
490
|
-
@cols=cols-1
|
491
|
-
end
|
492
|
-
|
493
|
-
def hline
|
494
|
-
'─'*@cols
|
495
|
-
end
|
496
|
-
def hhline
|
497
|
-
#'⬛'*@cols
|
498
|
-
#"━"*@cols
|
499
|
-
"═"*@cols
|
500
|
-
end
|
501
|
-
|
502
|
-
def short_perm_mode(m, prefix: '+')
|
503
|
-
case m
|
504
|
-
when "040000"
|
505
|
-
prefix+"d" #directory
|
506
|
-
when "100644"
|
507
|
-
"" #file
|
508
|
-
when "100755"
|
509
|
-
prefix+"x" #executable
|
510
|
-
when "120000"
|
511
|
-
prefix+"l" #symlink
|
512
|
-
when "160000"
|
513
|
-
prefix+"g" #gitlink
|
514
|
-
end
|
515
|
-
end
|
516
|
-
def perm_mode(m, prefix: ' ')
|
517
|
-
case m
|
518
|
-
when "040000"
|
519
|
-
prefix+"directory"
|
520
|
-
when "100644"
|
521
|
-
"" #file
|
522
|
-
when "100755"
|
523
|
-
prefix+"executable"
|
524
|
-
when "120000"
|
525
|
-
prefix+"symlink"
|
526
|
-
when "160000"
|
527
|
-
prefix+"gitlink"
|
528
|
-
end
|
529
|
-
end
|
530
|
-
|
531
|
-
def diff_header_summary
|
532
|
-
r=case @file[:mode]
|
533
|
-
when :modify
|
534
|
-
"modified: #{@file[:name]}"
|
535
|
-
when :rewrite
|
536
|
-
"rewrote: #{@file[:name]} (dissimilarity: #{@file[:dissimilarity]})"
|
537
|
-
when :new
|
538
|
-
"added#{perm_mode(@file[:new_perm])}: #{@file[:name]}"
|
539
|
-
when :delete
|
540
|
-
"deleted#{perm_mode(@file[:old_perm])}: #{@file[:old_name]}"
|
541
|
-
when :rename
|
542
|
-
"renamed: #{@file[:old_name]} to #{@file[:name]} (similarity: #{@file[:similarity]})"
|
543
|
-
when :copy
|
544
|
-
"copied: #{@file[:old_name]} to #{@file[:name]} (similarity: #{@file[:similarity]})"
|
545
|
-
end
|
546
|
-
r<<" [#{short_perm_mode(@file[:old_perm],prefix:'-')}#{short_perm_mode(@file[:new_perm])}]" if @file[:old_perm] && @file[:new_perm]
|
547
|
-
r
|
548
|
-
end
|
549
|
-
|
550
|
-
def meta_colorize(l)
|
551
|
-
if @opts[:color]
|
552
|
-
l.color(*@colors[:meta])
|
553
|
-
else
|
554
|
-
l
|
555
|
-
end
|
556
|
-
end
|
557
|
-
|
558
|
-
def new_diff_header
|
559
|
-
super
|
560
|
-
output_line meta_colorize(hline)
|
561
|
-
end
|
562
|
-
|
563
|
-
def end_diff_header
|
564
|
-
super
|
565
|
-
output_line meta_colorize(diff_header_summary)
|
566
|
-
output_line meta_colorize(hline)
|
567
|
-
end
|
568
|
-
|
569
|
-
def submodule_header_summary
|
570
|
-
r="Submodule #{@submodule[:name]}"
|
571
|
-
extra=[@submodule[:modified] && "modified", @submodule[:untracked] && "untracked"].compact.join("+")
|
572
|
-
r<<" [#{extra}]" unless extra.empty?
|
573
|
-
r << " #{@submodule[:info]}" if @submodule[:info]
|
574
|
-
r
|
575
|
-
end
|
576
|
-
|
577
|
-
def new_submodule_header
|
578
|
-
super
|
579
|
-
output_line meta_colorize(hline)
|
580
|
-
end
|
581
|
-
|
582
|
-
def end_submodule_header
|
583
|
-
super
|
584
|
-
output_line meta_colorize(submodule_header_summary)
|
585
|
-
output_line meta_colorize(hline)
|
586
|
-
end
|
587
|
-
|
588
|
-
def nonewline_clean
|
589
|
-
@mode==:hunk && @file && (@file[:perm]=="120000" or @file[:old_perm]=="120000" or @file[:new_perm]=="120000") && @line==NoNewLine
|
590
|
-
end
|
591
|
-
|
592
|
-
def new_commit
|
593
|
-
super
|
594
|
-
output_line meta_colorize(hhline)
|
595
|
-
end
|
596
|
-
def end_commit
|
597
|
-
super
|
598
|
-
output_line meta_colorize(hhline)
|
599
|
-
end
|
600
|
-
|
601
|
-
def clean_hunk_col
|
602
|
-
if @opts[:color] && @mode==:hunk && !@start_mode && @hunk[:n]==2
|
603
|
-
bcolor,ecolor,line=SimpleColor.current_colors(@orig_line)
|
604
|
-
m=line.scrub.match(/^([+-])?(.*)/)
|
605
|
-
mode=m[1]
|
606
|
-
cline=m[2]
|
607
|
-
if mode && cline !~ /[^[:space:]]/ #detect blank line
|
608
|
-
output_line SimpleColor.color(bcolor.to_s + (cline.empty? ? " ": cline)+ecolor.to_s,:inverse)
|
609
|
-
else
|
610
|
-
cline.sub!(/^\s/,'') unless mode #strip one blank character
|
611
|
-
output_line bcolor.to_s+cline+ecolor.to_s
|
612
|
-
end
|
613
|
-
true
|
614
|
-
end
|
615
|
-
end
|
616
|
-
|
617
|
-
def hunk_header
|
618
|
-
if @mode==:hunk && @start_mode
|
619
|
-
if @hunk[:lines][0][1] && @hunk[:lines][0][1] != 0
|
620
|
-
header="#{@file[:name]}:#{@hunk[:lines][0][1]}"
|
621
|
-
output_line @orig_line.sub(/(@@+\s)(.*)(\s@@+)/,"\\1#{header}\\3")
|
622
|
-
end
|
623
|
-
true
|
624
|
-
end
|
625
|
-
end
|
626
|
-
|
627
|
-
def binary_file_differ
|
628
|
-
@file and (@file[:mode]==:new && @line =~ %r{^Binary files /dev/null and ./#{@file[:name]} differ$} or
|
629
|
-
@file[:mode]==:delete && @line =~ %r{^Binary files ./#{@file[:old_name]} and /dev/null differ$})
|
630
|
-
end
|
631
|
-
|
632
|
-
def handle_line
|
633
|
-
super
|
634
|
-
#:diff_header and submodule_header are handled at end_*
|
635
|
-
case @mode
|
636
|
-
when :meta
|
637
|
-
if binary_file_differ
|
638
|
-
else output_line @orig_line
|
639
|
-
end
|
640
|
-
when :hunk
|
641
|
-
if hunk_header
|
642
|
-
elsif nonewline_clean
|
643
|
-
elsif clean_hunk_col
|
644
|
-
else output_line @orig_line
|
645
|
-
end
|
646
|
-
when :submodule,:commit
|
647
|
-
output_line @orig_line
|
648
|
-
end
|
649
|
-
end
|
650
|
-
end
|
651
|
-
|
652
|
-
if __FILE__ == $0
|
653
|
-
require 'optparse'
|
654
|
-
|
655
|
-
@opts={pager: true, diff_highlight: true, color: true, debug: false}
|
656
|
-
optparse = OptionParser.new do |opt|
|
657
|
-
opt.banner = "fancy git diff"
|
658
|
-
opt.on("--[no-]pager", "launch the pager [true]") do |v|
|
659
|
-
@opts[:pager]=v
|
660
|
-
end
|
661
|
-
opt.on("--[no-]highlight", "run the diff through diff-highlight [true]") do |v|
|
662
|
-
@opts[:diff_highlight]=v
|
663
|
-
end
|
664
|
-
opt.on("--[no-]color", "color output [true]") do |v|
|
665
|
-
@opts[:color]=v
|
666
|
-
end
|
667
|
-
opt.on("--raw", "Only parse diff headers") do |v|
|
668
|
-
@opts[:color]=false
|
669
|
-
@opts[:pager]=false
|
670
|
-
@opts[:diff_highlight]=false
|
671
|
-
end
|
672
|
-
opt.on("--[no-]debug", "Debug mode") do |v|
|
673
|
-
@opts[:debug]=v
|
674
|
-
end
|
675
|
-
end
|
676
|
-
optparse.parse!
|
677
|
-
@opts[:pager]=false unless Module.const_defined?('ShellHelpers')
|
678
|
-
@opts[:pager] && ShellHelpers.run_pager #("--pattern '^(Date|added|deleted|modified): '")
|
679
|
-
|
680
|
-
diff_highlight=ENV['DIFF_HIGHLIGHT']||"#{File.dirname(__FILE__)}/contrib/diff-highlight"
|
681
|
-
|
682
|
-
args=ARGF
|
683
|
-
if @opts[:debug]
|
684
|
-
GitDiffDebug.new(args,**@opts).output
|
685
|
-
elsif @opts[:diff_highlight]
|
686
|
-
IO.popen(diff_highlight,'r+') do |f|
|
687
|
-
Thread.new do
|
688
|
-
args.each_line do |l|
|
689
|
-
f.write(l)
|
690
|
-
end
|
691
|
-
f.close_write
|
692
|
-
end
|
693
|
-
GitFancyDiff.new(f,**@opts).output
|
694
|
-
end
|
695
|
-
else
|
696
|
-
#diff=GitDiffHighlight.new(args,**@opts).parse
|
697
|
-
GitFancyDiff.new(args,**@opts).output
|
698
|
-
end
|
699
|
-
end
|