Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- require 'shellwords'
- class Blamify
- PORCELAIN_COMMIT_HASH_RE = /^(?<hash>\h{40})\s/
- PORCELAIN_LINE_RE = /^\t(?<line>.*)$/
- COLORS = (237..255).to_a # Greyscale gradient
- def initialize(filename)
- @filename = filename
- end
- def print(output = $stdout)
- committer_times = blames.map { |blame| blame[:committer_time].to_i }
- min_time = committer_times.min
- max_time = committer_times.max
- timespan = max_time - min_time
- mid_time = min_time + timespan / 2
- blames.each do |blame|
- committer_time = blame[:committer_time].to_i
- offset = committer_time - min_time
- Time.at(committer_time)
- color = color_at(offset / timespan.to_f)
- author = blame.fetch(:author, "")
- output.puts format("\e[38;5;%dm%-14s: %s\e[0m", color, author[0, 14], blame[:line])
- end
- end
- private
- def color_at(x)
- x = 0 if x.nan?
- x = [[x, 0.0].max, 1.0].min # Clamp to (0.0, 1.0)
- COLORS[(x * COLORS.size.pred).floor]
- end
- def blames
- @blames ||= load_blames
- end
- def load_blames
- blame_data = {}
- load_porcelain.lines.each_with_object([]) do |line, blames|
- case line
- when PORCELAIN_COMMIT_HASH_RE
- blame_data[:commit] = $~[:hash]
- when PORCELAIN_LINE_RE
- blames << blame_data.merge(line: $~[:line])
- else # Key/value
- key, value = line.chomp.split(' ', 2)
- key.tr!('-', '_')
- blame_data[key.to_sym] = value
- end
- end
- end
- def load_porcelain
- `#{ Shellwords.shelljoin(['git', 'blame', '-p', @filename]) }`
- end
- end
- if file = ARGV.first
- dir = File.dirname(File.expand_path(file))
- Dir.chdir(dir) do
- Blamify.new(File.basename(file)).print
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement