Sanchayan Maity
f3736630c0
signs.add/change/delete can be nil for a file not yet being tracked
with git. This was broken in 703d23c
.
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 is_git = fn.FugitiveHead() ~= ""
|
||
local signs = vim.b.minidiff_summary or { add = 0, change = 0, delete = 0 }
|
||
|
||
return is_git
|
||
and string.format(
|
||
" %s+%s %s~%s %s-%s",
|
||
"%#DiffAdded#",
|
||
signs.add or 0,
|
||
"%#DiffChanged#",
|
||
signs.change or 0,
|
||
"%#DiffRemoved#",
|
||
signs.delete 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()
|
||
local is_git = fn.FugitiveHead() ~= ""
|
||
|
||
return
|
||
is_git
|
||
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"
|
||
})
|