386 lines
12 KiB
Lua
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
|
|
}
|