class GitHelpers::GitDiff
Constants
- NoNewLine
Attributes
output[R]
Public Class Methods
new(diff,**opts)
click to toggle source
# File lib/git_helpers/diff.rb, line 31 def initialize(diff,**opts) @diff=diff #Assume diff is a line iterator ['gitdiff'.each_line] @current=0 @mode=:unknown @opts=opts @opts[:color]=@opts.fetch(:color,true) #modes: #- unknown (temp mode) #- commit #- meta #- submodule_header #- submodule #- diff_header #- hunk @colors={meta: [:bold]} end
output(gdiff, **opts)
click to toggle source
# File lib/git_helpers/diff.rb, line 18 def self.output(gdiff, **opts) if gdiff.respond_to?(:each_line) enum=gdiff.each_line else enum=gdiff.each end self.new(enum, **opts).output end
Public Instance Methods
change_mode(nmode)
click to toggle source
# File lib/git_helpers/diff.rb, line 66 def change_mode(nmode) @start_mode=true send :"end_#{@mode}" unless @mode==:unknown @mode=nmode send :"new_#{@mode}" unless @mode==:unknown end
detect_delete()
click to toggle source
# File lib/git_helpers/diff.rb, line 198 def detect_delete if m=@line.match(/^deleted file mode\s+(.*)/) @file[:old_perm]=m[1] @file[:mode]=:delete return true end false end
detect_diff_header()
click to toggle source
# File lib/git_helpers/diff.rb, line 245 def detect_diff_header if @start_mode if m=@line.chomp.match(/^diff\s--git\s(.*)\s(.*)/) @file[:old_name]=get_file_name(m[1]) @file[:name]=get_file_name(m[2]) elsif m=@line.match(/^diff\s--(?:cc|combined)\s(.*)/) @file[:name]=get_file_name(m[1]) end true end end
detect_end_diff_header()
click to toggle source
# File lib/git_helpers/diff.rb, line 89 def detect_end_diff_header @line =~ /^\+\+\+\s/ end
detect_end_hunk()
click to toggle source
# File lib/git_helpers/diff.rb, line 96 def detect_end_hunk @hunk[:lines_seen].each_with_index.all? { |v,i| v==@hunk[:lines][i].first } end
detect_filename()
click to toggle source
# File lib/git_helpers/diff.rb, line 164 def detect_filename if m=@line.match(/^---\s(.*)/) @file[:old_name]=get_file_name(m[1]) return true end if m=@line.match(/^\+\+\+\s(.*)/) @file[:name]=get_file_name(m[1]) return true end false end
detect_index()
click to toggle source
# File lib/git_helpers/diff.rb, line 188 def detect_index if m=@line.match(/^index\s+(.*)\.\.(.*)/) @file[:oldhash]=m[1].split(',') @file[:hash],perm=m[2].split @file[:perm]||=perm return true end false end
detect_new_commit()
click to toggle source
# File lib/git_helpers/diff.rb, line 317 def detect_new_commit @line=~/^commit\b/ end
detect_new_diff_header()
click to toggle source
# File lib/git_helpers/diff.rb, line 86 def detect_new_diff_header @line =~ /^diff\s/ end
detect_new_hunk()
click to toggle source
# File lib/git_helpers/diff.rb, line 93 def detect_new_hunk @line.match(/^@@+\s.*\s@@/) end
detect_new_submodule_header()
click to toggle source
# File lib/git_helpers/diff.rb, line 273 def detect_new_submodule_header if m=@line.chomp.match(/^Submodule\s(.*)\s(.*)/) subname=m[1]; return not(@submodule && @submodule[:name]==subname) end false end
detect_newfile()
click to toggle source
# File lib/git_helpers/diff.rb, line 207 def detect_newfile if m=@line.match(/^new file mode\s+(.*)/) @file[:new_perm]=m[1] @file[:mode]=:new return true end false end
detect_perm()
click to toggle source
# File lib/git_helpers/diff.rb, line 176 def detect_perm if m=@line.match(/^old mode\s+(.*)/) @file[:old_perm]=m[1] return true end if m=@line.match(/^new mode\s+(.*)/) @file[:new_perm]=m[1] return true end false end
detect_rename_copy()
click to toggle source
# File lib/git_helpers/diff.rb, line 216 def detect_rename_copy if m=@line.match(/^similarity index\s+(.*)/) @file[:similarity]=m[1] return true end if m=@line.match(/^dissimilarity index\s+(.*)/) @file[:mode]=:rewrite @file[:dissimilarity]=m[1] return true end #if we have a rename with 100% similarity, there won't be any hunks so #we need to detect the filenames there if m=@line.match(/^(?:rename|copy) from\s+(.*)/) @file[:old_name]=m[1] end if m=@line.match(/^(?:rename|copy) to\s+(.*)/) @file[:name]=m[1] end if m=@line.match(/^rename\s+(.*)/) @file[:mode]=:rename return true end if m=@line.match(/^copy\s+(.*)/) @file[:mode]=:copy return true end false end
each(&b)
click to toggle source
# File lib/git_helpers/diff.rb, line 387 def each(&b) parse.each(&b) end
end_commit()
click to toggle source
# File lib/git_helpers/diff.rb, line 74 def end_commit; end
end_diff_header()
click to toggle source
# File lib/git_helpers/diff.rb, line 84 def end_diff_header; end
end_hunk()
click to toggle source
# File lib/git_helpers/diff.rb, line 78 def end_hunk; end
end_meta()
click to toggle source
# File lib/git_helpers/diff.rb, line 76 def end_meta; end
end_submodule()
click to toggle source
# File lib/git_helpers/diff.rb, line 82 def end_submodule; end
end_submodule_header()
click to toggle source
# File lib/git_helpers/diff.rb, line 80 def end_submodule_header; end
get_file_name(file)
click to toggle source
# File lib/git_helpers/diff.rb, line 159 def get_file_name(file) #remove prefix (todo handle the no-prefix option) file.gsub(/^[abciow12]\//,'') end
handle_commit()
click to toggle source
# File lib/git_helpers/diff.rb, line 321 def handle_commit if m=@line.match(/^(\w+):\s(.*)/) @commit[m[1]]=m[2] handle_line else @start_mode ? handle_line : reparse(:unknown) end end
handle_diff_header()
click to toggle source
# File lib/git_helpers/diff.rb, line 258 def handle_diff_header if detect_diff_header elsif detect_filename elsif detect_perm elsif detect_index elsif detect_delete elsif detect_newfile elsif detect_rename_copy else return reparse(:unknown) end next_mode(:unknown) if detect_end_diff_header handle_line end
handle_hunk()
click to toggle source
# File lib/git_helpers/diff.rb, line 128 def handle_hunk if @start_mode parse_hunk_header else #'The 'No new line at end of file' is sort of part of the hunk, but #is not considerer in the hunkheader unless @line == NoNewLine #we need to wait for a NoNewLine to be sure we are at the end of the hunk return reparse(:unknown) if detect_end_hunk linemodes=@line[0...@hunk[:n]-1] newline=true #the line is on the new file unless there is a '-' somewhere if linemodes=~/-/ newline=false else @hunk[:lines_seen][0]+=1 end (1...@hunk[:n]).each do |i| linemode=linemodes[i-1] case linemode when '-' @hunk[:lines_seen][i]+=1 when ' ' @hunk[:lines_seen][i]+=1 if newline end end end end handle_line end
handle_line()
click to toggle source
# File lib/git_helpers/diff.rb, line 335 def handle_line end
handle_meta()
click to toggle source
# File lib/git_helpers/diff.rb, line 100 def handle_meta handle_line end
handle_submodule()
click to toggle source
# File lib/git_helpers/diff.rb, line 310 def handle_submodule #we have lines indicating new commits #they always end by a new line except when followed by another submodule return reparse(:unknown) if !submodule_line handle_line end
handle_submodule_header()
click to toggle source
# File lib/git_helpers/diff.rb, line 281 def handle_submodule_header if m=@line.chomp.match(/^Submodule\s(\S*)\s(.*)/) subname=m[1] if @submodule[:name] #we may be dealing with a new submodule #require 'pry'; binding.pry return reparse(:submodule_header) if subname != @submodule[:name] else @submodule[:name]=m[1] end subinfo=m[2] if subinfo == "contains untracked content" @submodule[:untracked]=true elsif subinfo == "contains modified content" @submodule[:modified]=true else (@submodule[:info]||="") << subinfo next_mode(:submodule) if subinfo =~ /^.......\.\.\.?........*:$/ end handle_line else return reparse(:unknown) end end
new_commit()
click to toggle source
# File lib/git_helpers/diff.rb, line 73 def new_commit; @commit={}; end
new_diff_header()
click to toggle source
# File lib/git_helpers/diff.rb, line 83 def new_diff_header; @file={mode: :modify} end
new_hunk()
click to toggle source
# File lib/git_helpers/diff.rb, line 77 def new_hunk; end
new_meta()
click to toggle source
# File lib/git_helpers/diff.rb, line 75 def new_meta; end
new_submodule()
click to toggle source
# File lib/git_helpers/diff.rb, line 81 def new_submodule; end
new_submodule_header()
click to toggle source
# File lib/git_helpers/diff.rb, line 79 def new_submodule_header; @submodule={}; end
next_mode(nmode)
click to toggle source
# File lib/git_helpers/diff.rb, line 58 def next_mode(nmode) @next_mode=nmode end
output_line(l)
click to toggle source
# File lib/git_helpers/diff.rb, line 48 def output_line(l) @output << l.chomp+"\n" end
output_lines(lines)
click to toggle source
# File lib/git_helpers/diff.rb, line 51 def output_lines(lines) lines.each {|l| output_line l} end
parse() { || ... }
click to toggle source
# File lib/git_helpers/diff.rb, line 375 def parse Enumerator.new do |y| @output=y @diff.each do |line| prepare_new_line(line) parse_line yield if block_given? end change_mode(:unknown) #to trigger the last end_* hook end end
parse_hunk_header()
click to toggle source
# File lib/git_helpers/diff.rb, line 104 def parse_hunk_header m=@line.match(/^@@+\s(.*)\s@@\s*(.*)/) hunks=m[1] @hunk={lines: []} @hunk[:header]=m[2] filenumber=0 hunks.split.each do |hunk| hunkmode=hunk[0] hunk=hunk[1..-1] line,length=hunk.split(',').map(&:to_i) #handle hunks of the form @@ -1 +0,0 @@ length,line=line,length unless length case hunkmode when '-' filenumber+=1 @hunk[:lines][filenumber]=[length,line] when '+' @hunk[:lines][0]=[length,line] end end @hunk[:n]=@hunk[:lines].length @hunk[:lines_seen]=Array.new(@hunk[:n],0) end
parse_line()
click to toggle source
# File lib/git_helpers/diff.rb, line 339 def parse_line case @mode when :unknown, :meta if detect_new_hunk return reparse(:hunk) elsif detect_new_diff_header return reparse(:diff_header) elsif detect_new_submodule_header return reparse(:submodule_header) elsif detect_new_commit return reparse(:commit) else change_mode(:meta) if @mode==:unknown handle_meta end when :commit handle_commit when :submodule_header handle_submodule_header when :submodule handle_submodule when :diff_header handle_diff_header #=> mode=unknown if we detect we are not a diff header anymore when :hunk handle_hunk #=> mode=unknown at end of hunk end end
prepare_new_line(line)
click to toggle source
# File lib/git_helpers/diff.rb, line 369 def prepare_new_line(line) @orig_line=line @line=@orig_line.uncolor update_mode end
reparse(nmode)
click to toggle source
# File lib/git_helpers/diff.rb, line 330 def reparse(nmode) change_mode(nmode) parse_line end
submodule_line()
click to toggle source
# File lib/git_helpers/diff.rb, line 306 def submodule_line @line=~/^ [><] / end
update_mode()
click to toggle source
# File lib/git_helpers/diff.rb, line 61 def update_mode @start_mode=false @next_mode && change_mode(@next_mode) @next_mode=nil end