Class: Snaptoken::Diff

Inherits:
Object
  • Object
show all
Defined in:
lib/snaptoken/diff.rb

Defined Under Namespace

Classes: HTMLLineByLine

Constant Summary collapse

SYNTAX_HIGHLIGHTER =
HTMLLineByLine.new(Rouge::Formatters::HTML.new)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(filename = nil, is_new_file = false, lines = []) ⇒ Diff



4
5
6
7
8
9
# File 'lib/snaptoken/diff.rb', line 4

def initialize(filename = nil, is_new_file = false, lines = [])
  @filename = filename
  @is_new_file = is_new_file
  @lines = lines
  @syntax_highlighted = false
end

Instance Attribute Details

#filenameObject

Returns the value of attribute filename.



2
3
4
# File 'lib/snaptoken/diff.rb', line 2

def filename
  @filename
end

#is_new_fileObject

Returns the value of attribute is_new_file.



2
3
4
# File 'lib/snaptoken/diff.rb', line 2

def is_new_file
  @is_new_file
end

#linesObject

Returns the value of attribute lines.



2
3
4
# File 'lib/snaptoken/diff.rb', line 2

def lines
  @lines
end

#syntax_highlightedObject

Returns the value of attribute syntax_highlighted.



2
3
4
# File 'lib/snaptoken/diff.rb', line 2

def syntax_highlighted
  @syntax_highlighted
end

Class Method Details

.parse(git_diff) ⇒ Object

Parse a git diff and return an array of Diff objects, one for each file in the git diff.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/snaptoken/diff.rb', line 54

def self.parse(git_diff)
  in_diff = false
  old_line_num = nil
  new_line_num = nil
  cur_diff = nil
  diffs = []

  git_diff.lines.each do |line|
    if line =~ /^diff --git (\S+) (\S+)$/
      filename = $2.split("/")[1..-1].join("/")
      cur_diff = Snaptoken::Diff.new(filename)
      diffs << cur_diff
      in_diff = false
    elsif !in_diff && line.start_with?('new file')
      cur_diff.is_new_file = true
    elsif line =~ /^@@ -(\d+)(,\d+)? \+(\d+)(,\d+)? @@/
      # TODO: somehow preserve function name that comes to the right of the @@ header?
      in_diff = true
      old_line_num = $1.to_i
      new_line_num = $3.to_i
    elsif in_diff && line[0] == '\\'
      # Ignore "\ No newline at end of file".
    elsif in_diff && [' ', '|', '+', '-'].include?(line[0])
      case line[0]
      when ' ', '|'
        type = :unchanged
        line_nums = [old_line_num, new_line_num]
        old_line_num += 1
        new_line_num += 1
      when '+'
        type = :added
        line_nums = [nil, new_line_num]
        new_line_num += 1
      when '-'
        type = :removed
        line_nums = [old_line_num, nil]
        old_line_num += 1
      end

      cur_diff << Snaptoken::DiffLine.new(type, line[1..-1], line_nums)
    else
      in_diff = false
    end
  end

  diffs
end

Instance Method Details

#<<(diff_line) ⇒ Object

Append a DiffLine to the Diff.



24
25
26
27
28
29
30
# File 'lib/snaptoken/diff.rb', line 24

def <<(diff_line)
  unless diff_line.is_a? Snaptoken::DiffLine
    raise ArgumentError, "expected a DiffLine"
  end
  @lines << diff_line
  self
end

#cloneObject



11
12
13
14
15
# File 'lib/snaptoken/diff.rb', line 11

def clone
  diff = Snaptoken::Diff.new(@filename.dup, @is_new_file, @lines.map(&:clone))
  diff.syntax_highlighted = @syntax_highlighted
  diff
end

#clone_emptyObject



17
18
19
20
21
# File 'lib/snaptoken/diff.rb', line 17

def clone_empty
  diff = Snaptoken::Diff.new(@filename.dup, @is_new_file, [])
  diff.syntax_highlighted = @syntax_highlighted
  diff
end

#syntax_highlight!Object



119
120
121
122
123
124
125
126
127
# File 'lib/snaptoken/diff.rb', line 119

def syntax_highlight!
  return if @syntax_highlighted
  code = @lines.map(&:source).join("\n") + "\n"
  lexer = Rouge::Lexer.guess(filename: @filename, source: code)
  SYNTAX_HIGHLIGHTER.format(lexer.lex(code)).lines.each.with_index do |line_hl, idx|
    @lines[idx].source = line_hl
  end
  @syntax_highlighted = true
end

#to_patch(options = {}) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/snaptoken/diff.rb', line 32

def to_patch(options = {})
  patch = "diff --git a/#{@filename} b/#{@filename}\n"
  if @is_new_file
    patch += "new file mode 100644\n"
    patch += "--- /dev/null\n"
  else
    patch += "--- a/#{@filename}\n"
  end
  patch += "+++ b/#{@filename}\n"

  find_hunks.each do |hunk|
    patch += hunk_header(hunk)
    hunk.each do |line|
      patch += line.to_patch(options)
    end
  end

  patch
end