Files
yadm/.config/nvim/lua/plugins/line.lua
2025-04-23 01:37:19 +02:00

386 lines
12 KiB
Lua

return {
"rebelot/heirline.nvim",
config = function()
local conditions = require("heirline.conditions")
local heirline = require('heirline')
local utils = require("heirline.utils")
local Space = { provider = " " }
local colors = {
bg = utils.get_highlight("Normal").bg,
fg = utils.get_highlight("Normal").fg,
bright_bg = utils.get_highlight("Normal").bg,
bright_fg = utils.get_highlight("Normal").fg,
red = utils.get_highlight("DiagnosticError").fg,
dark_red = utils.get_highlight("DiffDelete").bg,
green = utils.get_highlight("String").fg,
blue = utils.get_highlight("Function").fg,
gray = utils.get_highlight("NonText").fg,
orange = utils.get_highlight("Constant").fg,
purple = utils.get_highlight("Statement").fg,
cyan = utils.get_highlight("Special").fg,
diag_warn = utils.get_highlight("DiagnosticWarn").fg,
diag_error = utils.get_highlight("DiagnosticError").fg,
diag_hint = utils.get_highlight("DiagnosticHint").fg,
diag_info = utils.get_highlight("DiagnosticInfo").fg,
git_del = utils.get_highlight("diffDeleted").fg,
git_add = utils.get_highlight("diffAdded").fg,
git_change = utils.get_highlight("diffChanged").fg,
}
heirline.load_colors(colors)
-- --------------------------------------------------------------
local ViMode = {
-- get vim current mode, this information will be required by the provider
-- and the highlight functions, so we compute it only once per component
-- evaluation and store it as a component attribute
init = function(self)
self.mode = vim.fn.mode(1) -- :h mode()
-- execute this only once, this is required if you want the ViMode
-- component to be updated on operator pending mode
if not self.once then
vim.api.nvim_create_autocmd("ModeChanged", {
pattern = "*:*o",
command = 'redrawstatus'
})
self.once = true
end
end,
-- Now we define some dictionaries to map the output of mode() to the
-- corresponding string and color. We can put these into `static` to compute
-- them at initialisation time.
static = {
mode_names = { -- change the strings if you like it vvvvverbose!
n = "N",
no = "N?",
nov = "N?",
noV = "N?",
["no\22"] = "N?",
niI = "Ni",
niR = "Nr",
niV = "Nv",
nt = "Nt",
v = "V",
vs = "Vs",
V = "V_",
Vs = "Vs",
["\22"] = "^V",
["\22s"] = "^V",
s = "S",
S = "S_",
["\19"] = "^S",
i = "I",
ic = "Ic",
ix = "Ix",
R = "R",
Rc = "Rc",
Rx = "Rx",
Rv = "Rv",
Rvc = "Rv",
Rvx = "Rv",
c = "C",
cv = "Ex",
r = "...",
rm = "M",
["r?"] = "?",
["!"] = "!",
t = "T",
},
mode_colors = {
n = "red",
i = "green",
v = "cyan",
V = "cyan",
["\22"] = "cyan",
c = "orange",
s = "purple",
S = "purple",
["\19"] = "purple",
R = "orange",
r = "orange",
["!"] = "red",
t = "red",
}
},
-- We can now access the value of mode() that, by now, would have been
-- computed by `init()` and use it to index our strings dictionary.
-- note how `static` fields become just regular attributes once the
-- component is instantiated.
-- To be extra meticulous, we can also add some vim statusline syntax to
-- control the padding and make sure our string is always at least 2
-- characters long. Plus a nice Icon.
provider = function(self)
return "%1(" .. self.mode_names[self.mode] .. "%)"
end,
-- Same goes for the highlight. Now the foreground will change according to the current mode.
hl = function(self)
local mode = self.mode:sub(1, 1) -- get only the first mode character
return { fg = self.mode_colors[mode], bold = true, }
end,
-- Re-evaluate the component only on ModeChanged event!
-- This is not required in any way, but it's there, and it's a small
-- performance improvement.
update = {
"ModeChanged",
},
}
-- --------------------------------------------------------------
local FileNameBlock = {
-- let's first set up some attributes needed by this component and it's children
init = function(self)
self.filename = vim.api.nvim_buf_get_name(0)
end,
}
-- We can now define some children separately and add them later
local FileIcon = {
init = function(self)
local filename = self.filename
local extension = vim.fn.fnamemodify(filename, ":e")
self.icon, self.icon_color = require("nvim-web-devicons").get_icon_color(filename, extension,
{ default = true })
end,
provider = function(self)
return self.icon and (self.icon .. " ")
end,
hl = function(self)
return { fg = self.icon_color }
end
}
local FileName = {
provider = function(self)
-- first, trim the pattern relative to the current directory. For other
-- options, see :h filename-modifiers
local filename = vim.fn.fnamemodify(self.filename, ":.")
if filename == "" then return "[No Name]" end
-- now, if the filename would occupy more than 1/4th of the available
-- space, we trim the file path to its initials
-- See Flexible Components section below for dynamic truncation
if not conditions.width_percent_below(#filename, 0.5) then
filename = vim.fn.pathshorten(filename)
end
return filename
end,
hl = { fg = utils.get_highlight("Directory").fg },
}
local FileFlags = {
{
condition = function()
return vim.bo.modified
end,
provider = "[+]",
hl = { fg = "green" },
},
{
condition = function()
return not vim.bo.modifiable or vim.bo.readonly
end,
provider = "",
hl = { fg = "orange" },
},
}
-- Now, let's say that we want the filename color to change if the buffer is
-- modified. Of course, we could do that directly using the FileName.hl field,
-- but we'll see how easy it is to alter existing components using a "modifier"
-- component
local FileNameModifier = {
hl = function()
if vim.bo.modified then
-- use `force` because we need to override the child's hl foreground
return { fg = "cyan", bold = true, force = true }
end
end,
}
-- let's add the children to our FileNameBlock component
FileNameBlock = utils.insert(FileNameBlock,
FileIcon,
utils.insert(FileNameModifier, FileName), -- a new table where FileName is a child of FileNameModifier
FileFlags,
{ provider = '%<' } -- this means that the statusline is cut here when there's not enough space
)
-- --------------------------------------------------------------
-- We're getting minimalists here!
local Ruler = {
-- %l = current line number
-- %L = number of lines in the buffer
-- %c = column number
-- %P = percentage through file of displayed window
provider = "%7(%l/%3L%):%2c %P",
}
-- --------------------------------------------------------------
local LSPActive = {
condition = conditions.lsp_attached,
update = { 'LspAttach', 'LspDetach' },
-- You can keep it simple,
-- provider = " [LSP]",
-- Or complicate things a bit and get the servers names
provider = function()
local names = {}
for i, server in pairs(vim.lsp.get_clients({ bufnr = 0 })) do
table.insert(names, server.name)
end
return "" .. table.concat(names, ",")
end,
hl = { fg = "green", bold = true },
}
local LSPMessages = {
provider = vim.lsp.status(),
hl = { fg = "gray" },
}
-- --------------------------------------------------------------
local Diagnostics = {
condition = conditions.has_diagnostics,
static = {
-- these require something...
error_icon = "",
warn_icon = "",
info_icon = "",
hint_icon = "",
},
init = function(self)
self.errors = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.ERROR })
self.warnings = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.WARN })
self.hints = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.HINT })
self.info = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.INFO })
end,
update = { "DiagnosticChanged", "BufEnter" },
{
provider = function(self)
-- 0 is just another output, we can decide to print it or not!
return self.errors > 0 and (self.error_icon .. self.errors .. " ")
end,
hl = { fg = "diag_error" },
},
{
provider = function(self)
return self.warnings > 0 and (self.warn_icon .. self.warnings .. " ")
end,
hl = { fg = "diag_warn" },
},
{
provider = function(self)
return self.info > 0 and (self.info_icon .. self.info .. " ")
end,
hl = { fg = "diag_info" },
},
{
provider = function(self)
return self.hints > 0 and (self.hint_icon .. self.hints)
end,
hl = { fg = "diag_hint" },
},
}
-- --------------------------------------------------------------
local DAPMessages = {
condition = function()
local session = require("dap").session()
return session ~= nil
end,
provider = function()
return "" .. require("dap").status()
end,
hl = "Debug"
-- see Click-it! section for clickable actions
}
-- --------------------------------------------------------------
local WorkDir = {
provider = function()
local icon = (vim.fn.haslocaldir(0) == 1 and "l" or "g") .. " " .. ""
local cwd = vim.fn.getcwd(0)
cwd = vim.fn.fnamemodify(cwd, ":~")
if not conditions.width_percent_below(#cwd, 0.25) then
cwd = vim.fn.pathshorten(cwd)
end
local trail = cwd:sub(-1) == '/' and '' or "/"
return icon .. cwd .. trail
end,
hl = { fg = "blue", bold = true },
}
-- --------------------------------------------------------------
local Align = { provider = "%=" }
-- ViMode = utils.surround({ "", "" }, "bright_bg", { ViMode })
local DefaultStatusline = {
ViMode, Space, FileNameBlock, Space, Align,
Align, DAPMessages,
LSPActive, Space, Diagnostics, Space, LSPMessages, Space, Ruler
}
local FileType = {
provider = function()
return string.upper(vim.bo.filetype)
end,
hl = { fg = utils.get_highlight("Type").fg, bold = true },
}
--
local InactiveStatusline = {
condition = conditions.is_not_active,
FileNameBlock,
Align,
}
local SpecialStatusline = {
condition = function()
return conditions.buffer_matches({
buftype = { "nofile", "prompt", "help", "quickfix" },
filetype = { "^git.*", "fugitive" },
})
end,
FileType,
Space,
Align
}
local StatusLine = {
hl = function()
if conditions.is_active() then
return "StatusLine"
else
return "StatusLineNC"
end
end,
-- the first statusline with no condition, or which condition returns true is used.
-- think of it as a switch case with breaks to stop fallthrough.
fallthrough = false,
SpecialStatusline,
InactiveStatusline,
DefaultStatusline,
colors = colors
}
local Winbar = { { provider = "»" }, Space }
local TabLine = {}
-- local StatusColumn = {}
heirline.setup({
statusline = StatusLine,
-- winbar = Winbar,
tabline = TabLine,
-- statuscolumn = StatusColumn
opts = {
colors = colors
}
})
end,
enabled = false
}