diff --git a/lua/lualine/async.lua b/lua/lualine/async.lua deleted file mode 100644 index fba27f6..0000000 --- a/lua/lualine/async.lua +++ /dev/null @@ -1,75 +0,0 @@ -local M = {} - -function M:new(args) - args = args or {} - for index, arg in pairs(args) do - self[index] = arg - end - setmetatable(args, self) - self.__index = self - return args -end - -local function close_pipe(pipe) - if pipe ~= nil and not pipe:is_closing() then - pipe:close() - end -end - -function M.close_all() - close_pipe(M.stdin) - close_pipe(M.stderr) - close_pipe(M.stdout) - close_pipe(M.handle) -end - -function M.init_options() - local options = {} - local args = vim.fn.split(M.cmd, ' ') - M.stdin = vim.loop.new_pipe(false) - M.stdout = vim.loop.new_pipe(false) - M.stderr = vim.loop.new_pipe(false) - options.command = table.remove(args, 1) - options.args = args - options.stdio = { - M.stdin, - M.stdout, - M.stderr - } - if M.cwd then - options.cwd = M.cwd - end - if M.env then - options.env = M.env - end - if M.detach then - options.detach = M.detach - end - return options -end - -function M.start() - local options = M.init_options() - M.handle = vim.loop.spawn(options.command, options, vim.schedule_wrap(M.stop)) - if M.on_stdout then - M.stdout:read_start(vim.schedule_wrap(M.on_stdout)) - end - if M.on_stderr then - M.stderr:read_start(vim.schedule_wrap(M.on_stderr)) - end -end - -function M.stop(code, signal) - if M.on_exit then - M.on_exit(code, signal) - end - if M.on_stdout then - M.stdout:read_stop() - end - if M.on_stderr then - M.stderr:read_stop() - end - M.close_all() -end - -return M diff --git a/lua/lualine/components/branch.lua b/lua/lualine/components/branch.lua index a687137..b589dbe 100644 --- a/lua/lualine/components/branch.lua +++ b/lua/lualine/components/branch.lua @@ -1,34 +1,65 @@ -local async = require('lualine.async') - local git_branch -local get_git_branch = async:new({ - cmd = 'git branch --show-current', - on_stdout = function(_, data) - if data then - git_branch = data:gsub('\n', '') - end - end, - on_stderr = function (_, data) - if data then - if data:find("fatal: not a git repository") then - git_branch = '' - end - end - end, -}) +-- os specific path separator +local sep = package.config:sub(1,1) -local timer = vim.loop.new_timer() -timer:start(0, 1000, vim.schedule_wrap(function() - local cur_dir = vim.fn.getcwd() - local buffer_working_directory = vim.fn.expand("%:p:h") - local status, _ = pcall(vim.api.nvim_set_current_dir, buffer_working_directory) - if status == true then - get_git_branch:start() - vim.api.nvim_set_current_dir(cur_dir) +-- returns full path to git directory for current directory +local function find_git_dir() + -- get file dir so we can search from that dir + local file_dir = vim.fn.expand('%:p:h') .. ';' + -- find .git/ folder genaral case + local git_dir = vim.fn.finddir('.git', file_dir) + -- find .git file in case of submodules or any other case git dir is in + -- any other place than .git/ + local git_file = vim.fn.findfile('.git', file_dir) + -- for some weird reason findfile gives relative path so expand it to fullpath + if #git_file > 0 then git_file = vim.fn.fnamemodify(git_file, ':p') end + if #git_file > #git_dir then + -- separate git-dir or submodule is used + local file = io.open(git_file) + git_dir = file:read() + git_dir = git_dir:match("gitdir: (.+)$") + file:close() + -- submodule / relative file path + if git_dir:sub(1,1) ~= sep and not git_dir:match('^%a:.*$') then + git_dir = git_file:match('(.*).git')..git_dir + end end -end)) + return git_dir +end +-- sets git_branch veriable to branch name or commit hash if not on branch +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() + local branch = HEAD:match('ref: refs/heads/(.+)$') + if branch then git_branch = branch + else git_branch = HEAD:sub(1,6) end + end + return nil +end + +-- event watcher to watch head file +local file_changed = vim.loop.new_fs_event() +local function watch_head() + file_changed:stop() + local git_dir = find_git_dir() + if #git_dir > 0 then + local head_file = git_dir..sep..'HEAD' + get_git_head(head_file) + file_changed:start(head_file, {}, vim.schedule_wrap(function() + -- reset file-watch + watch_head() + end)) + else + -- set to nil when git dir was not found + git_branch = nil + end +end + +-- returns the git_branch value to be shown on statusline local function branch() if not git_branch or #git_branch == 0 then return '' end local ok,devicons = pcall(require,'nvim-web-devicons') @@ -47,4 +78,12 @@ local function branch() return git_branch end +-- run watch head on load so branch is present when component is loaded +watch_head() + +-- TODO Don't export as a global function +_G.lualine_branch_update = watch_head +-- update branch state of BufEnter as different Buffer may be on different repos +vim.cmd[[autocmd BufEnter * call v:lua.lualine_branch_update()]] + return branch