dotfiles/nvim/.config/nvim/after/plugin/statusline.lua

288 lines
7.4 KiB
Lua
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local fn = vim.fn
local api = vim.api
local gstatus = { ahead = 0, behind = 0 }
local update_gstatus = 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()
end
if _G.Gstatus_timer == nil then
_G.Gstatus_timer = vim.loop.new_timer()
else
_G.Gstatus_timer:stop()
end
_G.Gstatus_timer:start(0, 2000, vim.schedule_wrap(update_gstatus))
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)
M.trunc_width = setmetatable({
git_status = 60,
filename = 140,
}, {
__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.set_active = function(self)
return table.concat {
self:get_filename(),
self:get_git_status(),
self:git_ahead_behind_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"
})