class Thicket::Log

Constants

LOG_PARSE_REGEX

Public Class Methods

new(options) click to toggle source
# File lib/thicket/log.rb, line 10
def initialize(options)
  @options = options
  @count_parsed = 0
end

Public Instance Methods

print() click to toggle source

Gets a printable version of the log for purposes of printing to a terminal. This effectively builds the final printable log to display to the user.

Private Instance Methods

git_executable() click to toggle source

The path to the git executable. Honors the passed in command line option, and falls back to just “git”.

# File lib/thicket/log.rb, line 184
def git_executable
  @options[:git_binary] || "git"
end
git_log_command() click to toggle source

The command string which gets the raw git log input straight from git. Includes all formatting and color escape codes.

# File lib/thicket/log.rb, line 173
def git_log_command
  format = "%C(yellow)%h %Cgreen%aI %Cblue{%an}%Cred%d %Creset%s"
  cmd = +"#{git_executable} log --oneline --decorate --color " \
  "--graph --pretty=format:'#{format}'"
  cmd << " --all" if @options[:all]

  cmd
end
git_working_directory() click to toggle source

The directory which represents the git project that we want to retreive logs for. Uses the command line option if it was provided, and falls back to the current working directory otherwise.

# File lib/thicket/log.rb, line 191
def git_working_directory
  @options[:project_directory] || Dir.pwd
end
process_author_name(author, line) click to toggle source

Takes an input log string and commit author, and moves it from the normal position in the string to a right-justified location.

# File lib/thicket/log.rb, line 133
def process_author_name(author, line)
  line.sub!("\e[34m{#{author}}\e[31m ", "")
  total_length = strip_color(line).length
  over = (total_length + author.length + 1) - terminal_width
  line = line[0...-over] if over > 0

  total_length = strip_color(line).length
  spaces_needed = terminal_width - total_length - author.length - 2
  if spaces_needed < 0
    line = +"#{line[0...-spaces_needed - 5]}...  "
  else
    line << " \e[30m"
    line << @padding_char * spaces_needed
    line << " \e[m"
  end

  line << "\e[34m#{author}\e[m"
end
process_date_time(time_string, line, have_refs) click to toggle source

Takes an input log string and a commit date/time and replaces it in the log string with a formatted version.

# File lib/thicket/log.rb, line 55
def process_date_time(time_string, line, have_refs)
  seconds_ago = Time.now - Time.iso8601(time_string)
  measure = TimeMeasure.measures.find { |m| m.threshold < seconds_ago }
  quantity = (seconds_ago / measure.length).floor
  to_sub = +"#{quantity}#{measure.abbreviation}".rjust(3)
  to_sub << "\e[31m" if have_refs # add color if we have refs in this line

  line.sub(time_string, to_sub)
end
process_git_log_line(line) click to toggle source

Takes a single line of raw, colored git log output and manipulates it into the desired format.

# File lib/thicket/log.rb, line 39
def process_git_log_line(line)
  @padding_char = @padding_char == " " ? "-" : " "

  line.match(LOG_PARSE_REGEX) do |matcher|
    line = process_date_time(matcher[1], line, matcher[3])
    line = process_refs(matcher[3], line) if matcher[3] && @options[:consolidate_refs]
    line = process_message_prefix(matcher[4], line) if @options[:color_prefixes]
    line = process_author_name(matcher[2], line)
    @count_parsed += 1
  end

  line
end
process_message_prefix(message, line) click to toggle source

Takes an input log string and commit message, finds commit messages prefixes, and darkens them.

# File lib/thicket/log.rb, line 121
def process_message_prefix(message, line)
  prefix_regex = %r{^(?=.*[0-9])([A-Z\d-]+?[: \/])}
  message.match(prefix_regex) do |matcher|
    prefix = matcher[1]
    return line.sub(/([^\/])#{prefix}/, "\\1\e[30m#{prefix}\e[m")
  end

  line
end
process_refs(refs, line) click to toggle source

Takes an input log string and a refs list, and formats the refs list in a more consolidated way.

# File lib/thicket/log.rb, line 67
def process_refs(refs, line)
  original_refs = refs
  main_remote = @options[:main_remote] || "origin"
  refs = strip_color(refs).split(",").map(&:strip)
  tags = []

  head_ref_index = refs.find_index { |r| r.start_with?("HEAD -> ") }

  refs_to_delete = []
  refs.each do |r|
    refs_to_delete << r if r == "#{main_remote}/HEAD"
    next if r.start_with?("#{main_remote}/")

    ref_without_head = r.sub("HEAD -> ", "")
    branch = "#{main_remote}/#{ref_without_head}"
    if refs.include?(branch)
      refs_to_delete << branch
      r << "#"
    end

    if r.start_with?("tag:")
      tag = r
      tag.slice!("tag: ")

      refs_to_delete << r
      tags << tag
    end
  end

  refs[head_ref_index].sub!("HEAD -> ", "@") if head_ref_index
  refs.delete_if { |r| refs_to_delete.include? r }

  refs = if refs.any?
           "(#{refs.join(", ")})"
         else
           ""
         end

  substitute = if tags.any?
                 tags = "\e[35m[#{tags.join(", ")}]\e[0m"
                 if refs.empty?
                   tags
                 else
                   "#{refs} #{tags}"
                 end
               else
                 refs
               end

  line.sub("(#{original_refs})", substitute)
end
strip_color(string) click to toggle source

Strips ANSI color escape codes from a string. Colorize's String#uncolorize would be used, but it seems to only remove escape codes which match a strict pattern, which git log's colored output doesn't follow.

# File lib/thicket/log.rb, line 156
def strip_color(string)
  color_escape_regex = /\e\[([;\d]+)?m/
  string.gsub(color_escape_regex, "").chomp
end
terminal_width() click to toggle source

Gets the width of the terminal window in columns. Memoizes the result to avoid more shell calls, and because the terminal size won't be changing during the execution of this script.

# File lib/thicket/log.rb, line 164
def terminal_width
  @terminal_width ||= `tput cols`.to_i
rescue Errno::ENOENT
  puts "Failed to determine terminal column width."
  exit
end