Newer
Older
dotfiles / .config / lite-xl / plugins / gitblame / gitblame.lua
local core = require "core"
local config = require "core.config"

local gitblame = {}

local blame_pattern = "%w+[ (_.%w]+[ ]+%d+[-]?%d+[-]?%d+[ ]?%d+[:]?%d+[:]?%d+[ ]+[+-]?%d+"
local hash_pattern = "[0-9a-f]+"
-- local username_pattern = "[ _.%w]+"
local opening_bracket_pattern = "[ (]*"
local datetime_pattern = "%d+[-]?%d+[-]?%d+[ ]?%d+[:]?%d+[:]?%d+[ ]+[+-]?%d+"

local not_commited_yet_hash = "00000000"

local not_git_repo_message = "fatal: not a git repository"

local function exec(cmd)
    local proc = process.start(cmd)

    if proc then

        local output = ""

        while true do
            local rdbuf = proc:read_stdout()
            if not rdbuf then
                break
            else
                output = output .. rdbuf
            end
        end

        return output
    end

    return nil
end

local function log_data(var_name, var_value)
  if config.plugins.gitblame.debug then
    if var_value ~= nil then
      if type(var_value) == 'table' then
        core.try(function (var)
            local data = table.concat(var, " ")
            core.log("[GITBLAME] " .. var_name .. " : " .. data)
          end, var_value
        )
      else
        core.try(
          function (name, value)
            core.log("[GITBLAME] " .. name .. " : " .. value)
          end, var_name, var_value
        )
      end
    else
      core.try(
        function (name)
          core.log("[GITBLAME] " .. name .. " : nil")
        end, var_name
      )
    end
  end
end

local function get_commit_message(commit_hash)
  local git_command = {config.plugins.gitblame.git_executable, "show", "--no-color", "--pretty=format:%s", "--no-patch", commit_hash}

  log_data("get_commit_message.git_command", git_command)

  local result = exec(git_command)
  if result ~= nil then
    local length = result:len()

    if length ~= nil then
      if length > config.plugins.gitblame.max_commit_message_length then
        result = result:sub(0, config.plugins.gitblame.max_commit_message_length) .. "..."
      end
    end
  end

  return result
end

local function truncate_blame_text(blame_text)
  local _, first_index = blame_text:find(hash_pattern)

  local last_index, _ = blame_text:find(datetime_pattern)

  return blame_text:sub(first_index+1, last_index-1)
end

function gitblame.get_blame_text(active_view)
  if active_view ~= nil then
    local abs_filename = active_view.doc.abs_filename
    local line, _ = active_view.doc:get_selection()

    local git_command = {config.plugins.gitblame.git_executable, "blame", "-L", line .. "," .. line, abs_filename}

    log_data("get_blame_text.git_command", git_command)

    local git_output = exec(git_command)

    log_data("git_output", git_output)

    local blame_text = git_output:match(blame_pattern)

    log_data("blame_text", blame_text)

    if blame_text == nil then
      local a, _ = git_output:find(not_git_repo_message)

      if a ~= nil then
        return "Not a git repository"
      end

      return nil
    end

    local commit_hash = blame_text:match(hash_pattern)

    log_data("commit_hash", commit_hash)

    if commit_hash == nil then
      return nil
    end

    if commit_hash == not_commited_yet_hash then
      return "Not Committed Yet"
    end

    local datetime = blame_text:match(datetime_pattern)

    log_data("datetime", datetime)

    blame_text = truncate_blame_text(blame_text)

    log_data("truncated_blame_text", blame_text)

    local _, username_start_index = blame_text:find(opening_bracket_pattern)

    local username = blame_text:sub(username_start_index+1, blame_text:len() - 1)

    log_data("username", username)

    local commit_message = get_commit_message(commit_hash)

    local result = commit_hash .. ' | ' .. "(" .. username .. ") " .. datetime .. ' | ' ..  commit_message

    log_data("result", result)

    return result
  end
end

return gitblame