2021-10-11 11:42:47 +00:00
|
|
|
local M = {}
|
|
|
|
|
|
|
|
local require = require('lualine_require').require
|
2022-01-02 11:38:39 +00:00
|
|
|
local utils = require('lualine.utils.utils')
|
2021-10-11 11:42:47 +00:00
|
|
|
|
2021-04-11 08:20:41 +00:00
|
|
|
-- vars
|
2021-10-11 11:42:47 +00:00
|
|
|
local current_git_branch = ''
|
|
|
|
local current_git_dir = ''
|
|
|
|
local branch_cache = {} -- stores last known branch for a buffer
|
|
|
|
local active_bufnr = '0'
|
2021-01-20 10:19:10 +00:00
|
|
|
-- os specific path separator
|
2021-10-11 11:42:47 +00:00
|
|
|
local sep = package.config:sub(1, 1)
|
2021-04-11 08:20:41 +00:00
|
|
|
-- event watcher to watch head file
|
2021-10-28 15:22:15 +00:00
|
|
|
-- Use file watch for non Windows and poll for Windows.
|
|
|
|
-- Windows doesn't like file watch for some reason.
|
2021-10-11 11:42:47 +00:00
|
|
|
local file_changed = sep ~= '\\' and vim.loop.new_fs_event() or vim.loop.new_fs_poll()
|
|
|
|
local git_dir_cache = {} -- Stores git paths that we already know of
|
|
|
|
|
2021-10-28 15:22:15 +00:00
|
|
|
---sets git_branch variable to branch name or commit hash if not on branch
|
2021-10-12 14:04:47 +00:00
|
|
|
---@param head_file string full path of .git/HEAD file
|
2021-10-11 11:42:47 +00:00
|
|
|
local function get_git_head(head_file)
|
|
|
|
local f_head = io.open(head_file)
|
|
|
|
if f_head then
|
|
|
|
local HEAD = f_head:read()
|
|
|
|
f_head:close()
|
2022-01-02 11:38:39 +00:00
|
|
|
local branch = HEAD:match('ref: refs/heads/(.+)$')
|
2021-10-11 11:42:47 +00:00
|
|
|
if branch then
|
|
|
|
current_git_branch = branch
|
|
|
|
else
|
|
|
|
current_git_branch = HEAD:sub(1, 6)
|
|
|
|
end
|
2021-04-11 08:20:41 +00:00
|
|
|
end
|
2021-10-11 11:42:47 +00:00
|
|
|
return nil
|
2021-04-11 08:20:41 +00:00
|
|
|
end
|
|
|
|
|
2021-10-28 15:22:15 +00:00
|
|
|
---updates the current value of git_branch and sets up file watch on HEAD file
|
2021-10-11 11:42:47 +00:00
|
|
|
local function update_branch()
|
2022-01-04 13:17:16 +00:00
|
|
|
active_bufnr = tostring(vim.api.nvim_get_current_buf())
|
2021-10-11 11:42:47 +00:00
|
|
|
file_changed:stop()
|
|
|
|
local git_dir = current_git_dir
|
|
|
|
if git_dir and #git_dir > 0 then
|
|
|
|
local head_file = git_dir .. sep .. 'HEAD'
|
|
|
|
get_git_head(head_file)
|
|
|
|
file_changed:start(
|
|
|
|
head_file,
|
|
|
|
sep ~= '\\' and {} or 1000,
|
|
|
|
vim.schedule_wrap(function()
|
|
|
|
-- reset file-watch
|
|
|
|
update_branch()
|
|
|
|
end)
|
|
|
|
)
|
|
|
|
else
|
|
|
|
-- set to '' when git dir was not found
|
|
|
|
current_git_branch = ''
|
2021-09-03 18:28:20 +00:00
|
|
|
end
|
2022-01-04 13:17:16 +00:00
|
|
|
branch_cache[vim.api.nvim_get_current_buf()] = current_git_branch
|
2021-08-08 16:03:58 +00:00
|
|
|
end
|
2021-01-20 10:19:10 +00:00
|
|
|
|
2023-10-18 04:49:27 +00:00
|
|
|
---updates the current value of current_git_branch and sets up file watch on HEAD file if value changed
|
|
|
|
local function update_current_git_dir(git_dir)
|
|
|
|
if current_git_dir ~= git_dir then
|
|
|
|
current_git_dir = git_dir
|
|
|
|
update_branch()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-10-12 14:04:47 +00:00
|
|
|
---returns full path to git directory for dir_path or current directory
|
|
|
|
---@param dir_path string|nil
|
2023-10-18 04:49:27 +00:00
|
|
|
---@return string|nil
|
2021-10-11 11:42:47 +00:00
|
|
|
function M.find_git_dir(dir_path)
|
2023-10-18 04:49:27 +00:00
|
|
|
local git_dir = vim.env.GIT_DIR
|
|
|
|
if git_dir then
|
|
|
|
update_current_git_dir(git_dir)
|
|
|
|
return git_dir
|
|
|
|
end
|
|
|
|
|
2021-01-20 10:19:10 +00:00
|
|
|
-- get file dir so we can search from that dir
|
2022-01-02 11:38:39 +00:00
|
|
|
local file_dir = dir_path or vim.fn.expand('%:p:h')
|
2021-08-09 15:09:29 +00:00
|
|
|
local root_dir = file_dir
|
2021-08-03 09:28:05 +00:00
|
|
|
-- Search upward for .git file or folder
|
2021-09-03 18:28:20 +00:00
|
|
|
while root_dir do
|
2021-08-09 15:09:29 +00:00
|
|
|
if git_dir_cache[root_dir] then
|
|
|
|
git_dir = git_dir_cache[root_dir]
|
|
|
|
break
|
|
|
|
end
|
2021-10-11 11:42:47 +00:00
|
|
|
local git_path = root_dir .. sep .. '.git'
|
2021-08-03 09:28:05 +00:00
|
|
|
local git_file_stat = vim.loop.fs_stat(git_path)
|
2021-09-03 18:28:20 +00:00
|
|
|
if git_file_stat then
|
2021-08-03 09:28:05 +00:00
|
|
|
if git_file_stat.type == 'directory' then
|
|
|
|
git_dir = git_path
|
|
|
|
elseif git_file_stat.type == 'file' then
|
2021-08-25 06:07:00 +00:00
|
|
|
-- separate git-dir or submodule is used
|
|
|
|
local file = io.open(git_path)
|
2021-12-25 10:13:39 +00:00
|
|
|
if file then
|
|
|
|
git_dir = file:read()
|
2022-01-02 11:38:39 +00:00
|
|
|
git_dir = git_dir and git_dir:match('gitdir: (.+)$')
|
2021-12-25 10:13:39 +00:00
|
|
|
file:close()
|
|
|
|
end
|
2021-08-25 06:07:00 +00:00
|
|
|
-- submodule / relative file path
|
2022-01-02 11:38:39 +00:00
|
|
|
if git_dir and git_dir:sub(1, 1) ~= sep and not git_dir:match('^%a:.*$') then
|
|
|
|
git_dir = git_path:match('(.*).git') .. git_dir
|
2021-08-25 06:07:00 +00:00
|
|
|
end
|
2021-08-03 09:28:05 +00:00
|
|
|
end
|
2021-08-25 06:18:47 +00:00
|
|
|
if git_dir then
|
2021-10-11 11:42:47 +00:00
|
|
|
local head_file_stat = vim.loop.fs_stat(git_dir .. sep .. 'HEAD')
|
2021-08-25 06:18:47 +00:00
|
|
|
if head_file_stat and head_file_stat.type == 'file' then
|
|
|
|
break
|
2021-09-03 18:28:20 +00:00
|
|
|
else
|
|
|
|
git_dir = nil
|
|
|
|
end
|
2021-08-25 06:18:47 +00:00
|
|
|
end
|
2021-08-03 09:28:05 +00:00
|
|
|
end
|
2021-10-11 11:42:47 +00:00
|
|
|
root_dir = root_dir:match('(.*)' .. sep .. '.-')
|
2021-08-03 09:28:05 +00:00
|
|
|
end
|
|
|
|
|
2021-08-09 15:09:29 +00:00
|
|
|
git_dir_cache[file_dir] = git_dir
|
2023-10-18 04:49:27 +00:00
|
|
|
if dir_path == nil then
|
|
|
|
update_current_git_dir(git_dir)
|
2021-08-09 15:09:29 +00:00
|
|
|
end
|
2021-01-20 10:19:10 +00:00
|
|
|
return git_dir
|
|
|
|
end
|
|
|
|
|
2021-10-28 15:22:15 +00:00
|
|
|
---initializes git_branch module
|
2021-10-11 11:42:47 +00:00
|
|
|
function M.init()
|
|
|
|
-- run watch head on load so branch is present when component is loaded
|
|
|
|
M.find_git_dir()
|
|
|
|
-- update branch state of BufEnter as different Buffer may be on different repos
|
|
|
|
utils.define_autocmd('BufEnter', "lua require'lualine.components.branch.git_branch'.find_git_dir()")
|
2021-01-20 10:19:10 +00:00
|
|
|
end
|
2021-10-11 11:42:47 +00:00
|
|
|
function M.get_branch(bufnr)
|
|
|
|
if vim.g.actual_curbuf ~= nil and active_bufnr ~= vim.g.actual_curbuf then
|
2021-10-22 13:10:33 +00:00
|
|
|
-- Workaround for https://github.com/nvim-lualine/lualine.nvim/issues/286
|
2021-10-11 11:42:47 +00:00
|
|
|
-- See upstream issue https://github.com/neovim/neovim/issues/15300
|
|
|
|
-- Diff is out of sync re sync it.
|
|
|
|
M.find_git_dir()
|
|
|
|
end
|
|
|
|
if bufnr then
|
|
|
|
return branch_cache[bufnr] or ''
|
2021-01-20 10:19:10 +00:00
|
|
|
end
|
2021-10-11 11:42:47 +00:00
|
|
|
return current_git_branch
|
2021-01-20 10:19:10 +00:00
|
|
|
end
|
2021-01-04 00:38:01 +00:00
|
|
|
|
2021-09-25 17:15:42 +00:00
|
|
|
return M
|