Module: GitCrecord::Diff

Defined in:
lib/git_crecord/diff.rb,
lib/git_crecord/diff/file.rb,
lib/git_crecord/diff/hunk.rb,
lib/git_crecord/diff/line.rb,
lib/git_crecord/diff/difference.rb

Defined Under Namespace

Classes: Difference, File, Hunk, Line, PseudoLine

Class Method Summary collapse

Class Method Details

.file_encoding(filename) ⇒ Object



66
67
68
# File 'lib/git_crecord/diff.rb', line 66

def self.file_encoding(filename)
  `file --mime-encoding #{filename}`.split(': ', 2)[1].chomp
end

.file_lines(filename) ⇒ Object



70
71
72
73
74
75
# File 'lib/git_crecord/diff.rb', line 70

def self.file_lines(filename)
  encoding = file_encoding(filename)
  return [[], 'binary'] if encoding == 'binary'

  [::File.open(filename, "r:#{encoding}", &:readlines), nil]
end

.file_start?(line) ⇒ Boolean

Returns:

  • (Boolean)


21
22
23
# File 'lib/git_crecord/diff.rb', line 21

def self.file_start?(line)
  line.start_with?('diff')
end

.hunk_start?(line) ⇒ Boolean

Returns:

  • (Boolean)


25
26
27
# File 'lib/git_crecord/diff.rb', line 25

def self.hunk_start?(line)
  line.start_with?('@@')
end

.parse(diff, reverse = false) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/git_crecord/diff.rb', line 7

def self.parse(diff, reverse = false)
  files = []
  enum = diff.lines.each
  loop do
    line = enum.next
    line.chomp!
    next files << parse_file_head(line, enum, reverse) if file_start?(line)
    next files[-1] << line if hunk_start?(line)

    files[-1].add_hunk_line(line)
  end
  files
end

.parse_file_head(line, enum, reverse) ⇒ Object



29
30
31
32
33
34
35
36
37
# File 'lib/git_crecord/diff.rb', line 29

def self.parse_file_head(line, enum, reverse)
  index_line = enum.next # index ... or new ...
  is_new_file = index_line.start_with?('new')
  enum.next if is_new_file
  enum.next # --- ...
  enum.next # +++ ...
  type = is_new_file ? :untracked : :modified
  File.new(*parse_filenames(line), type: type, reverse: reverse)
end

.parse_filenames(line) ⇒ Object



39
40
41
# File 'lib/git_crecord/diff.rb', line 39

def self.parse_filenames(line)
  line.match(%r{a/(.*) b/(.*)$})[1..2]
end

.untracked_dir(path) ⇒ Object



60
61
62
63
64
# File 'lib/git_crecord/diff.rb', line 60

def self.untracked_dir(path)
  Dir.glob(::File.join(path, '**/*')).map do |filename|
    untracked_file(filename) unless ::File.directory?(filename)
  end
end

.untracked_file(filename) ⇒ Object



50
51
52
53
54
55
56
57
58
# File 'lib/git_crecord/diff.rb', line 50

def self.untracked_file(filename)
  File.new(filename, filename, type: :untracked).tap do |file|
    lines, err = file_lines(filename)
    file << "@@ -0,0 +1,#{lines.size} @@"
    file.subs[0].subs << PseudoLine.new(err) if lines.empty?
    lines.each { |line| file.add_hunk_line("+#{line.chomp}") }
    file.selected = false
  end
end

.untracked_files(git_status) ⇒ Object



43
44
45
46
47
48
# File 'lib/git_crecord/diff.rb', line 43

def self.untracked_files(git_status)
  git_status.lines.select { |l| l.start_with?('??') }.flat_map do |path|
    path = path.chomp[3..-1]
    ::File.directory?(path) ? untracked_dir(path) : untracked_file(path)
  end.compact
end