Sanchayan Maity
0265000a4f
Use the same timer loop for updating LSP progress in status line which we use for updating git ahead, behind status.
309 lines
7.8 KiB
Lua
309 lines
7.8 KiB
Lua
local fn = vim.fn
|
||
local api = vim.api
|
||
|
||
local lsp_status = ""
|
||
local gstatus = { ahead = 0, behind = 0 }
|
||
|
||
local update_status = function()
|
||
local Job = require 'plenary.job'
|
||
Job:new({
|
||
command = 'git',
|
||
args = { 'rev-list', '--left-right', '--count', 'HEAD...@{upstream}' },
|
||
on_exit = function(exit_job, _)
|
||
local res = exit_job:result()[1]
|
||
if type(res) ~= 'string' then
|
||
gstatus = { ahead = 0, behind = 0 };
|
||
return
|
||
end
|
||
local ok, ahead, behind = pcall(string.match, res, "(%d+)%s*(%d+)")
|
||
if not ok then
|
||
ahead, behind = 0, 0
|
||
end
|
||
gstatus = { ahead = ahead, behind = behind }
|
||
end,
|
||
}):start()
|
||
|
||
if vim.lsp.status then
|
||
lsp_status = vim.lsp.status()
|
||
end
|
||
end
|
||
|
||
if _G.Gstatus_timer == nil then
|
||
_G.Gstatus_timer = vim.uv.new_timer()
|
||
_G.Gstatus_timer:start(0, 1000, vim.schedule_wrap(update_status))
|
||
else
|
||
_G.Gstatus_timer:stop()
|
||
end
|
||
|
||
local M = {}
|
||
|
||
local colors = {
|
||
line_bg = '#21242b',
|
||
bg = '#000000',
|
||
fg = '#dobfa1',
|
||
yellow = '#fabd2f',
|
||
cyan = '#008080',
|
||
darkblue = '#081633',
|
||
green = '#afd700',
|
||
orange = '#FF8800',
|
||
purple = '#5d4d7a',
|
||
magenta = '#c678dd',
|
||
blue = '#51afef',
|
||
red = '#ec5f67'
|
||
}
|
||
|
||
local function highlight(group, fg, bg)
|
||
api.nvim_set_hl(0, group, { fg = fg, bg = bg })
|
||
end
|
||
|
||
highlight("Window" , colors.red , colors.bg)
|
||
highlight("Mode" , colors.green , colors.bg)
|
||
highlight("Filename" , colors.blue , colors.bg)
|
||
highlight("Fileformat" , colors.purple , colors.bg)
|
||
|
||
highlight("GitBranch" , colors.orange , colors.bg)
|
||
highlight("GitStatus" , colors.magenta, colors.bg)
|
||
highlight("DiffAdded" , colors.green , colors.bg)
|
||
highlight("DiffChanged" , colors.orange , colors.bg)
|
||
highlight("DiffRemoved" , colors.red , colors.bg)
|
||
|
||
highlight("DiagnosticsE", colors.red , colors.bg)
|
||
highlight("DiagnosticsW", colors.yellow , colors.bg)
|
||
highlight("DiagnosticsI", colors.cyan , colors.bg)
|
||
highlight("DiagnosticsH", colors.orange , colors.bg)
|
||
|
||
highlight("Location" , colors.yellow , colors.bg)
|
||
highlight("Progress" , colors.magenta, colors.bg)
|
||
highlight("WinbarFile" , colors.magenta, colors.bg)
|
||
highlight("LspProgress" , colors.orange , colors.bg)
|
||
|
||
M.trunc_width = setmetatable({
|
||
filename = 140,
|
||
git_status = 60,
|
||
lsp_status = 80,
|
||
}, {
|
||
__index = function()
|
||
return 80
|
||
end,
|
||
})
|
||
|
||
M.is_truncated = function(_, width)
|
||
return api.nvim_win_get_width(0) < width
|
||
end
|
||
|
||
M.get_window_number = function()
|
||
return string.format(" %s%d", "%#Window#", api.nvim_win_get_number(0))
|
||
end
|
||
|
||
M.modes = setmetatable({
|
||
["n" ] = "N" ,
|
||
["no"] = "N·P",
|
||
["v" ] = "V" ,
|
||
["V" ] = "V·L",
|
||
[""] = "V·B", -- this is not ^V, but it's , they're different
|
||
["s" ] = "S" ,
|
||
["S" ] = "S·L",
|
||
[""] = "S·B", -- same with this one, it's not ^S but it's
|
||
["i" ] = "I" ,
|
||
["ic"] = "I" ,
|
||
["R" ] = "R" ,
|
||
["Rv"] = "V·R",
|
||
["c" ] = "C" ,
|
||
["cv"] = "V·E",
|
||
["ce"] = "E" ,
|
||
["r" ] = "P" ,
|
||
["rm"] = "RM" ,
|
||
["r?"] = "C" ,
|
||
["!" ] = "S" ,
|
||
["t" ] = "T" ,
|
||
}, {
|
||
__index = function()
|
||
return "U"
|
||
end,
|
||
})
|
||
|
||
M.get_current_mode = function(self)
|
||
local current_mode = api.nvim_get_mode().mode
|
||
return string.format(" %s%s", "%#Mode#", self.modes[current_mode])
|
||
end
|
||
|
||
M.get_git_branch = function(self)
|
||
if self:is_truncated(self.trunc_width.git_status) then
|
||
return ""
|
||
end
|
||
|
||
return string.format(" %s %s", "%#GitBranch#", fn.FugitiveHead())
|
||
end
|
||
|
||
M.get_git_status = function(self)
|
||
local signs = vim.b.gitsigns_status_dict
|
||
or { head = "", added = 0, changed = 0, removed = 0 }
|
||
local is_head_empty = signs.head ~= ""
|
||
|
||
return is_head_empty
|
||
and string.format(
|
||
" %s+%s %s~%s %s-%s",
|
||
"%#DiffAdded#",
|
||
signs.added or 0,
|
||
"%#DiffChanged#",
|
||
signs.changed or 0,
|
||
"%#DiffRemoved#",
|
||
signs.removed or 0
|
||
)
|
||
or ""
|
||
end
|
||
|
||
M.get_filename = function()
|
||
local filetype = vim.bo.filetype
|
||
local special_ft = { 'diff', 'fugitive', 'git', 'qf' }
|
||
for _, v in pairs(special_ft) do
|
||
if v == filetype then
|
||
return string.format(" %s%s", "%#Filename#", filetype)
|
||
end
|
||
end
|
||
|
||
return string.format(" %s%s", "%#Filename#", '%t%m%r')
|
||
end
|
||
|
||
M.get_fileformat = function()
|
||
return string.format("%s%s", "%#Fileformat#", vim.o.fileformat):lower()
|
||
end
|
||
|
||
M.diagnostic_status = function()
|
||
local diagnostic = ''
|
||
|
||
local num_errors = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.ERROR })
|
||
if num_errors > 0 then
|
||
diagnostic = string.format("%s%s%d", diagnostic, ' %#DiagnosticsE#E:', num_errors)
|
||
end
|
||
|
||
local num_warnings = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.WARN })
|
||
if num_warnings > 0 then
|
||
diagnostic = string.format("%s%s%d", diagnostic, ' %#DiagnosticsW#W:', num_warnings)
|
||
end
|
||
|
||
local num_infos = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.INFO })
|
||
if num_infos > 0 then
|
||
diagnostic = string.format("%s%s%d", diagnostic, ' %#DiagnosticsI#I:', num_infos)
|
||
end
|
||
|
||
local num_hints = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.HINT })
|
||
if num_hints > 0 then
|
||
diagnostic = string.format("%s%s%d", diagnostic, ' %#DiagnosticsH#H:', num_hints)
|
||
end
|
||
|
||
return diagnostic
|
||
end
|
||
|
||
M.get_line_col = function()
|
||
return string.format(" %s%s", "%#Location#", "%l:%c")
|
||
end
|
||
|
||
M.progress = function()
|
||
return string.format(" %s%s", "%#Progress#", "%3p%% ")
|
||
end
|
||
|
||
M.git_ahead_behind_status = function()
|
||
return
|
||
vim.b.gitsigns_status_dict
|
||
and
|
||
string.format(" %s%s%d%s%d", '%#GitStatus#', ' ', gstatus.behind, ' ', gstatus.ahead)
|
||
or ""
|
||
end
|
||
|
||
M.get_lsp_status = function(self)
|
||
local trunc_width = self.trunc_width.lsp_status
|
||
if self:is_truncated(trunc_width) then
|
||
return ""
|
||
end
|
||
|
||
if vim.lsp.status then
|
||
return string.format(" %s%s", '%#LspProgress#', string.sub(lsp_status, 1, trunc_width))
|
||
end
|
||
|
||
return ""
|
||
end
|
||
|
||
M.set_active = function(self)
|
||
return table.concat {
|
||
self:get_filename(),
|
||
self:get_git_status(),
|
||
self:git_ahead_behind_status(),
|
||
"%=",
|
||
self:get_lsp_status(),
|
||
self:diagnostic_status(),
|
||
self:get_line_col(),
|
||
self:progress(),
|
||
}
|
||
end
|
||
|
||
M.set_inactive = function(self)
|
||
return table.concat {
|
||
"%#Window#",
|
||
-- Putting this in a function like the others seems to not work. And takes
|
||
-- the window number of the active window. Same for filename.
|
||
" %{winnr()}",
|
||
self:get_git_branch(),
|
||
"%=",
|
||
self:get_fileformat(),
|
||
self:get_line_col(),
|
||
self:progress(),
|
||
}
|
||
end
|
||
|
||
_G.Statusline = setmetatable(M, {
|
||
__call = function(self, mode)
|
||
return self["set_" .. mode](self)
|
||
end,
|
||
})
|
||
|
||
local status_id = api.nvim_create_augroup("Statusline", {clear = true})
|
||
local hide_status_id = api.nvim_create_augroup("HideStatusline", {clear = true})
|
||
|
||
api.nvim_create_autocmd({"WinEnter", "BufEnter"}, {
|
||
group = status_id,
|
||
pattern = "*",
|
||
command = "setlocal statusline=%!v:lua.Statusline('active')"
|
||
})
|
||
api.nvim_create_autocmd({"WinLeave" , "BufLeave"}, {
|
||
group = status_id,
|
||
pattern = "*",
|
||
command = "setlocal statusline=%!v:lua.Statusline('inactive')"
|
||
})
|
||
api.nvim_create_autocmd({"BufWinEnter", "BufFilePost"}, {
|
||
group = status_id,
|
||
callback = function()
|
||
-- Skip floating windows
|
||
-- Idea taken from https://github.com/itchyny/lightline.vim/pull/552
|
||
if api.nvim_win_get_config(0).relative ~= '' then
|
||
return
|
||
end
|
||
|
||
local winbar_filetype_exclude = {
|
||
"diff",
|
||
"fugitive",
|
||
"git",
|
||
"help",
|
||
"packer",
|
||
"qf"
|
||
}
|
||
|
||
if vim.tbl_contains(winbar_filetype_exclude, vim.bo.filetype) then
|
||
vim.opt_local.winbar = nil
|
||
return
|
||
end
|
||
|
||
vim.opt_local.winbar = string.format(" %s%s", "%#WinbarFile#", '%f%m%r')
|
||
end,
|
||
})
|
||
api.nvim_create_autocmd({"TermOpen", "TermEnter"}, {
|
||
group = hide_status_id,
|
||
pattern = "*",
|
||
command = "set laststatus=0 noshowmode noruler"
|
||
})
|
||
api.nvim_create_autocmd({"TermLeave"}, {
|
||
group = hide_status_id,
|
||
pattern = "*",
|
||
command = "set laststatus=2 showmode ruler"
|
||
})
|