aboutsummaryrefslogtreecommitdiff
path: root/common/nvim/lua/plugins/heirline.lua
diff options
context:
space:
mode:
authorsrdusr <trevorgray@srdusr.com>2025-09-24 02:56:53 +0200
committersrdusr <trevorgray@srdusr.com>2025-09-24 02:56:53 +0200
commit0f6cee92221dc517bd756083e260dd9373851b82 (patch)
treec6d929fa5832d17a2d1fe3c85744bae7621ed447 /common/nvim/lua/plugins/heirline.lua
parent3cf613ec7c90ab4933728b0f19e49b0c955c17bb (diff)
downloaddotfiles-0f6cee92221dc517bd756083e260dd9373851b82.tar.gz
dotfiles-0f6cee92221dc517bd756083e260dd9373851b82.zip
Moved files to common/
Diffstat (limited to 'common/nvim/lua/plugins/heirline.lua')
-rwxr-xr-xcommon/nvim/lua/plugins/heirline.lua1497
1 files changed, 0 insertions, 1497 deletions
diff --git a/common/nvim/lua/plugins/heirline.lua b/common/nvim/lua/plugins/heirline.lua
deleted file mode 100755
index a4c2fc3..0000000
--- a/common/nvim/lua/plugins/heirline.lua
+++ /dev/null
@@ -1,1497 +0,0 @@
-local M = {}
-
--- Safe require function to handle missing dependencies
-local function safe_require(module)
- local ok, result = pcall(require, module)
- return ok and result or nil
-end
-
--- These will be initialized in M.setup()
-local heirline = nil
-local conditions = {}
-local utils = {}
-local colors = {}
-
-function M.setup()
- heirline = safe_require("heirline")
- if not heirline then
- return
- end
-
- -- Initialize conditions and utils after heirline is loaded
- conditions = require("heirline.conditions") or {}
- utils = require("heirline.utils") or {}
-
-
- -- Initialize colors after safe_fg is defined
- colors = {
- bg = "NONE",
- nobg = "NONE",
- white = "#f8f8f2",
- black = "#000000",
- darkgray = "#23232e",
- gray = "#2d2b3a",
- lightgray = "#d6d3ea",
- pink = "#f92672",
- green = "#50fa7b",
- blue = "#39BAE6",
- yellow = "#f1fa8c",
- orange = "#ffb86c",
- purple = "#BF40BF",
- violet = "#7F00FF",
- red = "#ff5555",
- cyan = "#66d9eC",
- --diag = {
- -- warn = safe_fg("DiagnosticSignWarn", "#ffb86c"),
- -- error = safe_fg("DiagnosticSignError", "#ff5555"),
- -- hint = safe_fg("DiagnosticSignHint", "#50fa7b"),
- -- info = safe_fg("DiagnosticSignInfo", "#66d9eC"),
- --},
- diag = {
- warn = utils.get_highlight("DiagnosticSignWarn").fg,
- error = utils.get_highlight("DiagnosticSignError").fg,
- hint = utils.get_highlight("DiagnosticSignHint").fg,
- info = utils.get_highlight("DiagnosticSignInfo").fg,
- },
- git = {
- active = "#f34f29",
- del = "#ff5555",
- add = "#50fa7b",
- change = "#ae81ff",
- },
- }
-
- -- Only load colors if heirline is available
- if heirline.load_colors then
- local ok, err = pcall(heirline.load_colors, colors)
- if not ok then
- vim.notify("Failed to load Heirline colors: " .. tostring(err), vim.log.levels.ERROR)
- end
- end
-
- local function get_icon(icon, fallback)
- -- Check if we have Nerd Fonts available
- local has_nerd_fonts = vim.g.statusline_has_nerd_fonts
- if has_nerd_fonts == nil then
- -- Cache the result to avoid repeated checks
- if vim.fn.has('unix') == 1 and vim.fn.executable('fc-list') == 1 then
- local handle = io.popen('fc-list | grep -i nerd')
- local result = handle:read('*a')
- handle:close()
- has_nerd_fonts = result ~= ""
- else
- -- On non-Unix systems or if fc-list isn't available, assume no Nerd Fonts
- has_nerd_fonts = false
- end
- vim.g.statusline_has_nerd_fonts = has_nerd_fonts
- end
-
- -- Return the appropriate string based on font availability
- local result = has_nerd_fonts and icon or (fallback or '')
- -- Trim any whitespace to prevent layout issues
- return vim.trim(result)
- end
-
- -- Define all components after colors and utils are initialized
-
- --local Signs = {
- -- Error = "✘",
- -- Warn = "",
- -- Hint = "◉",
- -- Info = "",
- --}
- local Icons = {
- Signs = {
- Error = "✘",
- Warn = "",
- Hint = "◉",
- Info = "",
- LSP = get_icon("⚙️", "LSP"),
- },
- ---- LSP/Debug
- Error = get_icon("✘", "E"),
- Warn = get_icon("", "W"),
- Hint = get_icon("◉", "H"),--
- Info = get_icon("ℹ", "I"),
- --LSP = get_icon("⚙️", "LSP"),
-
- -- Diagnostic
- Diagnostic = {
- error = get_icon("✘", "E"),
- warn = get_icon("", "W"),
- hint = get_icon("", "H"),
- info = get_icon("ℹ", "I"),
- },
-
-
---local GitIcons = {
--- added = "✚", -- plus in diff style
--- modified = "", -- nf-oct-diff_modified
--- removed = "", -- nf-oct-diff_removed
---}
---added = "", -- nf-oct-diff_added
---modified = "", -- nf-oct-diff_modified
---removed = "", -- nf-oct-diff_removed
---local GitIcons = {
--- added = "", -- nf-fa-plus_square
--- modified = "", -- nf-fa-file_text_o
--- removed = "", -- nf-fa-minus_square
---}
- -- Git
- Git = {
- branch = get_icon(" ", "⎇ "),
- added = get_icon("+ ", "+"),
- removed = get_icon("- ", "-"),
- modified = get_icon("~ ", "~"),
- renamed = get_icon("", "r"),
- untracked = get_icon("", "?"),
- ignored = get_icon("", "."),
- },
-
- -- UI Elements
- UI = {
- left_separator = get_icon("", ""),
- right_separator = get_icon("", ""),
- thin_separator = get_icon("▏", "|"),
- ellipsis = get_icon("…", "..."),
- arrow_left = get_icon("◀", "<"),
- arrow_right = get_icon("▶", ">"),
- close = get_icon("✕", "x"),
- big_close = get_icon(" ", "x "),
- modified = get_icon(" + ", "*"),
- readonly = get_icon("", "RO"),
- lock = get_icon("", "[L]"),
- clock = get_icon("🕒", "[TIME]"),
- buffer = get_icon("", "[BUF]"),
- tab = get_icon("", "[TAB]"),
- search = get_icon("🔍", "[SEARCH]"),
- spell = get_icon("暈", "[SPELL]"),
- whitespace = get_icon("␣", "[WS]"),
- newline = get_icon("↵", "[NL]"),
- indent = get_icon("▏", "|"),
- fold = get_icon("", ">"),
- fold_open = get_icon("", "v"),
- fold_closed = get_icon("", ">"),
- },
-
- -- File types
- File = {
- default = get_icon("", "[F]"),
- directory = get_icon("", "[D]"),
- symlink = get_icon("", "[L]"),
- executable = get_icon("", "[X]"),
- image = get_icon("", "[IMG]"),
- archive = get_icon("", "[ARC]"),
- audio = get_icon("", "[AUD]"),
- video = get_icon("", "[VID]"),
- document = get_icon("", "[DOC]"),
- config = get_icon("", "[CFG]"),
- code = get_icon("", "[CODE]"),
- terminal = get_icon("", "[TERM]"),
- },
-
- -- File format indicators
- Format = {
- unix = get_icon("", "[UNIX]"),
- dos = get_icon("", "[DOS]"),
- mac = get_icon("", "[MAC]"),
- },
-
- -- Version control
- VCS = {
- branch = get_icon("", "[BR]"),
- git = get_icon("", "[GIT]"),
- github = get_icon("", "[GH]"),
- gitlab = get_icon("", "[GL]"),
- bitbucket = get_icon("", "[BB]"),
- },
-
- -- Programming languages
- Lang = {
- lua = get_icon("", "[LUA]"),
- python = get_icon("", "[PY]"),
- javascript = get_icon("", "[JS]"),
- typescript = get_icon("", "[TS]"),
- html = get_icon("", "[HTML]"),
- css = get_icon("", "[CSS]"),
- json = get_icon("", "[JSON]"),
- markdown = get_icon("", "[MD]"),
- docker = get_icon("", "[DKR]"),
- rust = get_icon("", "[RS]"),
- go = get_icon("", "[GO]"),
- java = get_icon("", "[JAVA]"),
- c = get_icon("", "[C]"),
- cpp = get_icon("", "[C++]"),
- ruby = get_icon("", "[RB]"),
- php = get_icon("", "[PHP]"),
- haskell = get_icon("", "[HS]"),
- scala = get_icon("", "[SCALA]"),
- elixir = get_icon("", "[EXS]"),
- clojure = get_icon("", "[CLJ]"),
- },
-
- -- UI Indicators
- Indicator = {
- error = get_icon("✘", "[E]"),
- warning = get_icon("⚠", "[W]"),
- info = get_icon("ℹ", "[I]"),
- hint = get_icon("", "[H]"),
- success = get_icon("✓", "[OK]"),
- question = get_icon("?", "[?]"),
- star = get_icon("★", "[*]"),
- heart = get_icon("❤", "<3"),
- lightning = get_icon("⚡", "[!]"),
- check = get_icon("✓", "[√]"),
- cross = get_icon("✗", "[x]"),
- plus = get_icon("+", "[+]"),
- recording = get_icon(" ", "q")
- },
-
- -- File operations
- FileOp = {
- new = get_icon("", "[NEW]"),
- save = get_icon("💾", "[SAVE]"),
- open = get_icon("📂", "[OPEN]"),
- close = get_icon("✕", "[X]"),
- undo = get_icon("↩", "[UNDO]"),
- redo = get_icon("↪", "[REDO]"),
- cut = get_icon("✂", "[CUT]"),
- copy = get_icon("⎘", "[COPY]"),
- paste = get_icon("📋", "[PASTE]"),
- search = get_icon("🔍", "[FIND]"),
- replace = get_icon("🔄", "[REPLACE]"),
- },
-
- -- Navigation
- Nav = {
- left = get_icon("←", "[<]"),
- right = get_icon("→", "[>]"),
- up = get_icon("↑", "[^]"),
- down = get_icon("↓", "[v]"),
- first = get_icon("⏮", "[<<]"),
- last = get_icon("⏭", "[>>]"),
- prev = get_icon("◀", "[<]"),
- next = get_icon("▶", "[>]"),
- back = get_icon("↩", "[B]"),
- forward = get_icon("↪", "[F]"),
- },
-
- -- Editor states
- State = {
- insert = get_icon("", "[INS]"),
- normal = get_icon("🚀", "[NOR]"),
- visual = get_icon("👁", "[VIS]"),
- replace = get_icon("🔄", "[REP]"),
- command = get_icon("", "[CMD]"),
- terminal = get_icon("", "[TERM]"),
- select = get_icon("🔍", "[SEL]"),
- },
-
- -- Common symbols
- Symbol = {
- dot = get_icon("•", "•"),
- bullet = get_icon("•", "•"),
- middle_dot = get_icon("·", "·"),
- ellipsis = get_icon("…", "..."),
- check = get_icon("✓", "[OK]"),
- cross = get_icon("✗", "[X]"),
- arrow_right = get_icon(" ", "->"),
- arrow_left = get_icon(" ", "<-"),
- double_arrow_right = get_icon("»", ">>"),
- double_arrow_left = get_icon("«", "<<"),
- chevron_right = get_icon("›", ">"),
- chevron_left = get_icon("‹", "<"),
- },
-
- -- Document symbols
- DocSymbol = {
- class = get_icon("", "[C]"),
- function_icon = get_icon("", "[F]"),
- method = get_icon("", "[M]"),
- property = get_icon("", "[P]"),
- field = get_icon("ﰠ", "[F]"),
- constructor = get_icon("", "[C]"),
- enum = get_icon("", "[E]"),
- interface = get_icon("", "[I]"),
- variable = get_icon("", "[V]"),
- constant = get_icon("", "[C]"),
- string = get_icon("", "[S]"),
- number = get_icon("", "[N]"),
- boolean = get_icon("◩", "[B]"),
- array = get_icon("", "[A]"),
- object = get_icon("⦿", "[O]"),
- key = get_icon("🔑", "[K]"),
- null = get_icon("NULL", "Ø"),
- enum_member = get_icon("", "[E]"),
- struct = get_icon("פּ", "[S]"),
- event = get_icon("", "[E]"),
- operator = get_icon("", "[O]"),
- type_parameter = get_icon("", "[T]"),
- },
- }
- local Align = { provider = "%=", hl = { bg = colors.bg } }
- local Space = { provider = " ", hl = { bg = colors.bg } }
- local Tab = { provider = " " }
- local LeftSpace = { provider = "" }
- local RightSpace = { provider = "" }
-
- local ViMode = {
- init = function(self)
- self.mode = vim.fn.mode(1)
- -- Store the initial mode
- self.prev_mode = self.mode
-
- -- Set up autocommand to force redraw on mode change
- vim.api.nvim_create_autocmd("ModeChanged", {
- pattern = "*:*",
- callback = function()
- -- Only redraw if the mode actually changed
- local current_mode = vim.fn.mode(1)
- if current_mode ~= self.prev_mode then
- self.prev_mode = current_mode
- vim.schedule(function()
- vim.cmd("redrawstatus")
- end)
- end
- end,
- })
- end,
- static = {
- mode_names = {
- n = " NORMAL ",
- no = "PENDING ",
- nov = " N? ",
- noV = " N? ",
- ["no\22"] = " N? ",
- niI = " Ni ",
- niR = " Nr ",
- niV = " Nv ",
- nt = "TERMINAL",
- v = " VISUAL ",
- vs = " Vs ",
- V = " V·LINE ",
- ["\22"] = "V·BLOCK ",
- ["\22s"] = "V·BLOCK ",
- s = " SELECT ",
- S = " S·LINE ",
- ["\19"] = "S·BLOCK ",
- i = " INSERT ",
- ix = "insert x",
- ic = "insert c",
- R = "REPLACE ",
- Rc = " Rc ",
- Rx = " Rx ",
- Rv = "V·REPLACE ",
- Rvc = " Rv ",
- Rvx = " Rv ",
- c = "COMMAND ",
- cv = " VIM EX ",
- ce = " EX ",
- r = " PROMPT ",
- rm = " MORE ",
- ["r?"] = "CONFIRM ",
- ["!"] = " SHELL ",
- t = "TERMINAL",
- },
- },
- provider = function(self)
- return " %2(" .. self.mode_names[self.mode] .. "%) "
- end,
- hl = function(self)
- return { fg = "colors.black", bg = self.mode_color, bold = true }
- end,
- update = {
- "ModeChanged",
- "VimEnter",
- "BufEnter",
- "WinEnter",
- "TabEnter",
- pattern = "*:*",
- callback = vim.schedule_wrap(function()
- vim.cmd("redrawstatus")
- end),
- },
- }
-
- -- LSP
- local LSPActive = {
- condition = function()
- local ok, _ = pcall(function()
- local buf = vim.api.nvim_get_current_buf()
- return #vim.lsp.get_clients({ bufnr = buf }) > 0
- end)
- return ok or false
- end,
- update = { "LspAttach", "LspDetach", "BufEnter" },
- provider = function()
- local ok, result = pcall(function()
- local buf = vim.api.nvim_get_current_buf()
- if not vim.api.nvim_buf_is_valid(buf) then return "" end
-
- local clients = vim.lsp.get_clients({ bufnr = buf })
- if not clients or #clients == 0 then return "" end
-
- local client_names = {}
- for _, client in ipairs(clients) do
- if client and client.name and client.name ~= "null-ls" then
- table.insert(client_names, client.name)
- end
- end
-
- if #client_names > 0 then
- return Icons.Signs.LSP .. " " .. table.concat(client_names, "/") .. " "
- end
-
- return ""
- end)
-
- if not ok then
- vim.schedule(function()
- vim.notify_once("Error in LSPActive provider: " .. tostring(result), vim.log.levels.DEBUG)
- end)
- return ""
- end
-
- return result or ""
- end,
- hl = { fg = "lightgray", bold = false },
- }
-
- local Navic = {
- condition = function()
- local ok, navic = pcall(require, "nvim-navic")
- return ok and navic.is_available()
- end,
- static = {
- type_hl = {
- File = "Directory",
- Module = "@include",
- Namespace = "@namespace",
- Package = "@include",
- Class = "@structure",
- Method = "@method",
- Property = "@property",
- Field = "@field",
- Constructor = "@constructor",
- Enum = "@field",
- Interface = "@type",
- Function = "@function",
- Variable = "@variable",
- Constant = "@constant",
- String = "@string",
- Number = "@number",
- Boolean = "@boolean",
- Array = "@field",
- Object = "@type",
- Key = "@keyword",
- Null = "@comment",
- EnumMember = "@field",
- Struct = "@structure",
- Event = "@keyword",
- Operator = "@operator",
- TypeParameter = "@type",
- },
- enc = function(line, col, winnr)
- return bit.bor(bit.lshift(line, 16), bit.lshift(col, 6), winnr)
- end,
- dec = function(c)
- local line = bit.rshift(c, 16)
- local col = bit.band(bit.rshift(c, 6), 1023)
- local winnr = bit.band(c, 63)
- return line, col, winnr
- end,
- },
- init = function(self)
- local data = require("nvim-navic").get_data() or {}
- local children = {}
- for i, d in ipairs(data) do
- local pos = self.enc(d.scope.start.line, d.scope.start.character, self.winnr)
- local child = {
- {
- provider = d.icon,
- hl = self.type_hl[d.type],
- },
- {
- provider = d.name:gsub("%%", "%%%%"):gsub("%s*->%s*", ""),
- on_click = {
- minwid = pos,
- callback = function(_, minwid)
- local line, col, winnr = self.dec(minwid)
- vim.api.nvim_win_set_cursor(vim.fn.win_getid(winnr), { line, col })
- end,
- name = "heirline_navic",
- },
- },
- }
- if #data > 1 and i < #data then
- table.insert(child, {
- provider = " > ",
- hl = { fg = "bright_fg" },
- })
- end
- table.insert(children, child)
- end
- self.child = self:new(children, 1)
- end,
- provider = function(self)
- return self.child:eval()
- end,
- hl = { fg = "gray" },
- update = "CursorMoved",
- }
-
- -- Diagnostics
- local Diagnostics = {
- condition = conditions.has_diagnostics,
- static = {
- error_icon = Icons.Error,
- warn_icon = Icons.Warn,
- info_icon = Icons.Info,
- hint_icon = Icons.Hint,
- },
- 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)
- return self.errors > 0 and (self.error_icon .. " " .. self.errors .. " ")
- end,
- hl = { fg = colors.diag.error, bg = colors.bg },
- },
- {
- provider = function(self)
- return self.warnings > 0 and (self.warn_icon .. " " .. self.warnings .. " ")
- end,
- hl = { fg = colors.diag.warn, bg = colors.bg },
- },
- {
- provider = function(self)
- return self.info > 0 and (self.info_icon .. " " .. self.info .. " ")
- end,
- hl = { fg = colors.diag.info, bg = colors.bg },
- },
- {
- provider = function(self)
- return self.hints > 0 and (self.hint_icon .. " " .. self.hints .. " ")
- end,
- hl = { fg = colors.diag.hint, bg = colors.bg },
- },
- on_click = {
- callback = function()
- local ok, _ = pcall(require, "trouble")
- if ok then
- require("trouble").toggle({ mode = "document_diagnostics" })
- else
- vim.diagnostic.setqflist()
- end
- end,
- name = "heirline_diagnostics",
- },
- }
-
- -- Git
- local Git = {
- condition = conditions.is_git_repo,
- init = function(self)
- self.status_dict = vim.b.gitsigns_status_dict or {}
- self.has_changes = (self.status_dict.added or 0) ~= 0 or
- (self.status_dict.removed or 0) ~= 0 or
- (self.status_dict.changed or 0) ~= 0
- end,
- {
- provider = function()
- return " " .. Icons.Git.branch .. " "
- end,
- hl = { fg = colors.git.active, bg = colors.bg },
- },
- {
- provider = function(self)
- return self.status_dict.head or ""
- end,
- hl = { fg = colors.white, bg = colors.bg },
- },
- {
- condition = function(self)
- return self.has_changes
- end,
- provider = "",
- },
- {
- provider = function(self)
- local count = self.status_dict.added or 0
- return count > 0 and (" " .. Icons.Git.added .. count) or ""
- end,
- hl = { fg = colors.git.add, bg = colors.bg },
- },
- {
- provider = function(self)
- local count = self.status_dict.removed or 0
- return count > 0 and (" " .. Icons.Git.removed .. count) or ""
- end,
- hl = { fg = colors.git.del, bg = colors.bg },
- },
- {
- provider = function(self)
- local count = self.status_dict.changed or 0
- return count > 0 and (" " .. Icons.Git.modified .. count) or ""
- end,
- hl = { fg = colors.git.change, bg = colors.bg },
- },
- on_click = {
- callback = function()
- vim.defer_fn(function()
- vim.cmd("Lazygit")
- end, 100)
- end,
- name = "heirline_git",
- },
- }
-
- -- FileNameBlock: FileIcon, FileName and friends
- local FileNameBlock = {
- init = function(self)
- self.filename = vim.api.nvim_buf_get_name(0)
- end,
- hl = { bg = colors.bg },
- }
-
- local FileIcon = {
- init = function(self)
- local filename = self.filename or vim.api.nvim_buf_get_name(0)
- local extension = vim.fn.fnamemodify(filename, ":e")
-
- local has_nerd_fonts = vim.g.statusline_has_nerd_fonts
- if has_nerd_fonts == nil then
- if vim.fn.has('unix') == 1 and vim.fn.executable('fc-list') == 1 then
- local handle = io.popen('fc-list | grep -i nerd')
- local result = handle:read('*a')
- handle:close()
- has_nerd_fonts = result ~= ""
- else
- has_nerd_fonts = false
- end
- vim.g.statusline_has_nerd_fonts = has_nerd_fonts
- end
-
- local icon, icon_color
- if has_nerd_fonts then
- icon, icon_color = require("nvim-web-devicons").get_icon_color(filename, extension, { default = true })
- end
-
- if vim.fn.isdirectory(filename) == 1 then
- self.icon = has_nerd_fonts and Icons.File.directory or "[DIR]"
- self.icon_color = colors.blue
- else
- if has_nerd_fonts and icon then
- self.icon = icon .. " "
- self.icon_color = icon_color or colors.blue
- else
- if extension == "" then
- self.icon = Icons.File.default
- else
- local file_icon = Icons.File[extension:lower()] or Icons.File.default
- if type(file_icon) == "table" then
- self.icon = file_icon[1] or Icons.File.default
- else
- self.icon = file_icon
- end
- end
- self.icon_color = colors.blue
- end
- end
- end,
- provider = function(self)
- return self.icon
- end,
- hl = function(self)
- return { fg = self.icon_color, bold = true }
- end,
- }
-
- local FileName = {
- provider = function(self)
- local filename = vim.fn.fnamemodify(self.filename, ":.")
- if filename == "" then
- return "No Name"
- end
- if not conditions.width_percent_below(#filename, 0.25) then
- filename = vim.fn.pathshorten(filename)
- end
- return filename
- end,
- hl = { fg = colors.white, bold = false, bg = colors.bg },
- }
-
- local FileFlags = {
- {
- provider = function()
- if vim.bo.modified then
- return " +"
- end
- end,
- hl = { fg = colors.green, bg = colors.bg },
- },
- {
- provider = function()
- if not vim.bo.modifiable or vim.bo.readonly then
- return " " .. Icons.UI.lock
- end
- end,
- hl = { fg = colors.orange, bold = true, bg = colors.bg },
- },
- }
-
- local FileNameModifier = {
- hl = function()
- if vim.bo.modified then
- return { fg = colors.green, bold = false, force = true }
- end
- end,
- }
-
- -- FileType, FileEncoding and FileFormat
- local FileType = {
- provider = function()
- return vim.bo.filetype
- end,
- hl = { fg = colors.white, bold = false, bg = colors.bg },
- }
-
- local FileEncoding = {
- Space,
- provider = function()
- local enc = (vim.bo.fenc ~= "" and vim.bo.fenc) or vim.o.enc
- return enc:lower()
- end,
- hl = { bg = colors.bg, bold = false },
- }
-
- local FileFormat = {
- provider = function()
- local fmt = vim.bo.fileformat
- return fmt ~= "unix" and fmt:lower() or ""
- end,
- hl = { fg = utils.get_highlight("Statusline").fg, bold = true, bg = colors.bg },
- }
-
- local FileSize = {
- provider = function()
- local suffix = { "b", "k", "M", "G", "T", "P", "E" }
- local filename = vim.api.nvim_buf_get_name(0)
- local fsize = vim.fn.getfsize(filename)
- fsize = (fsize < 0 and 0) or fsize
- if fsize < 1024 then
- return fsize .. suffix[1]
- end
- local i = math.floor((math.log(fsize) / math.log(1024)))
- return string.format("%.2g%s", fsize / math.pow(1024, i), suffix[i + 1])
- end,
- hl = { fg = utils.get_highlight("Statusline").fg, bold = true, bg = colors.bg },
- }
-
- local FileLastModified = {
- provider = function()
- local filename = vim.api.nvim_buf_get_name(0)
- local ftime = vim.fn.getftime(filename)
- return (ftime > 0) and os.date("%c", ftime) or ""
- end,
- hl = { fg = utils.get_highlight("Statusline").fg, bold = true, bg = colors.bg },
- }
-
- local Spell = {
- condition = function()
- return vim.wo.spell
- end,
- provider = function()
- return " " .. Icons.Indicator.spell .. " "
- end,
- hl = { bold = true, fg = colors.yellow },
- }
-
- local HelpFileName = {
- condition = function()
- return vim.bo.filetype == "help"
- end,
- provider = function()
- local filename = vim.api.nvim_buf_get_name(0)
- return vim.fn.fnamemodify(filename, ":t")
- end,
- hl = { fg = colors.blue },
- }
-
- local SearchCount = {
- condition = function()
- return vim.v.hlsearch ~= 0 and vim.o.cmdheight == 0
- end,
- init = function(self)
- local ok, search = pcall(vim.fn.searchcount, { recompute = 1, maxcount = -1 })
- if ok and search.total then
- self.search = search
- end
- end,
- provider = function(self)
- local search = self.search or { current = 0, total = 0, maxcount = 0 }
- return string.format("[%d/%d]", search.current, math.min(search.total, search.maxcount))
- end,
- update = { "CursorMoved", "CursorMovedI", "SearchWrapped" },
- }
-
- local MacroRec = {
- condition = function()
- return vim.fn.reg_recording() ~= "" and vim.o.cmdheight == 0
- end,
- provider = function()
- return Icons.Indicator.recording .. " "
- end,
- hl = { fg = "orange", bold = true },
- utils.surround({ "[", "]" }, nil, {
- provider = function()
- return vim.fn.reg_recording()
- end,
- hl = { fg = "green", bold = true },
- }),
- update = {
- "RecordingEnter",
- "RecordingLeave",
- callback = vim.schedule_wrap(function()
- vim.cmd("redrawstatus")
- end),
- },
- }
-
- local ShowCmd = {
- condition = function()
- return vim.o.cmdheight == 0
- end,
- provider = ":%3.5(%S%)",
- update = { "CmdlineChanged" },
- }
-
- local cursor_location = {
- { provider = "%1(%4l:%-3(%c%)%) %*", hl = { fg = colors.black, bold = true } },
- }
-
- local Ruler = { cursor_location }
-
- local WordCount = {
- condition = function()
- return conditions.buffer_matches({
- filetype = {
- "markdown",
- "txt",
- "vimwiki",
- },
- })
- end,
- Space,
- {
- provider = function()
- local ok, wordcount = pcall(vim.fn.wordcount)
- return ok and wordcount.words and ("W:%d"):format(wordcount.words) or ""
- end,
- update = { "CursorMoved", "CursorMovedI", "InsertEnter", "TextChanged", "TextChangedI" },
- },
- }
-
- local WorkDir = {
- init = function(self)
- local is_local = vim.fn.haslocaldir(0) == 1
- self.icon = (is_local and "l" or "g") .. " " .. Icons.File.directory
- local cwd = vim.fn.getcwd(0)
- self.cwd = vim.fn.fnamemodify(cwd, ":~")
- end,
- hl = { fg = colors.blue, bold = true },
- on_click = {
- callback = function()
- vim.cmd("Telescope find_files cwd=" .. vim.fn.getcwd(0))
- end,
- name = "heirline_workdir",
- },
- flexible = 1,
- {
- provider = function(self)
- local trail = self.cwd:sub(-1) == "/" and "" or "/"
- return self.icon .. " " .. self.cwd .. trail .. " "
- end,
- },
- {
- provider = function(self)
- local cwd = vim.fn.pathshorten(self.cwd)
- local trail = self.cwd:sub(-1) == "/" and "" or "/"
- return self.icon .. " " .. cwd .. trail .. " "
- end,
- },
- {
- provider = function(self)
- return self.icon .. " "
- end,
- },
- }
-
- -- Build FileNameBlock
- FileNameBlock = utils.insert(
- FileNameBlock,
- FileIcon,
- utils.insert(FileNameModifier, FileName),
- unpack(FileFlags),
- { provider = "%<" }
- )
-
- local FileInfoBlock = {
- init = function(self)
- self.filename = vim.api.nvim_buf_get_name(0)
- end,
- }
-
- FileInfoBlock = utils.insert(
- FileInfoBlock,
- Space,
- FileIcon,
- FileType,
- { provider = "%<" }
- )
-
- -- Create surrounded components with proper mode color functions
- LeftSpace = utils.surround({ "", Icons.UI.right_separator }, function(self)
- return self:mode_color()
- end, { LeftSpace, hl = { fg = utils.get_highlight("statusline").bg, force = true } })
-
- RightSpace = utils.surround({ Icons.UI.left_separator, "" }, function(self)
- return self:mode_color()
- end, { RightSpace, hl = { fg = utils.get_highlight("statusline").bg, force = true } })
-
- LSPActive = utils.surround({ "", "" }, function(self)
- return self:mode_color()
- end, { Space, LSPActive, hl = { bg = colors.darkgray, force = true } })
-
- FileInfoBlock = utils.surround({ "", "" }, function(self)
- return self:mode_color()
- end, { FileInfoBlock, Space, hl = { bg = colors.black, force = true } })
-
- ViMode = utils.surround({ "", "" }, function(self)
- return self:mode_color()
- end, { ViMode, hl = { fg = colors.black, force = true } })
-
- Ruler = utils.surround({ "", "" }, function(self)
- return self:mode_color()
- end, { Ruler, hl = { fg = colors.black, force = true } })
-
- -- Statusline sections - FIXED: Removed duplicate LeftSpace from right section
- local left = {
- { RightSpace, hl = { bg = colors.nobg, force = true } },
- { ViMode, hl = { bg = utils.get_highlight("statusline").bg, bold = false } },
- { LeftSpace, hl = { bg = colors.nobg, force = true } },
- { Space, hl = { bg = colors.nobg, force = true } },
- { FileNameBlock, hl = { bg = colors.nobg, force = true } },
- { Space, hl = { bg = colors.nobg, force = true } },
- { Git, hl = { bg = colors.nobg, force = true } },
- }
-
- local middle = {
- { Align, hl = { bg = colors.nobg, force = true } },
- { Align, hl = { bg = colors.nobg, force = true } },
- }
-
- -- FIXED: Right section now has proper sequence without duplicate LeftSpace
- local right = {
- { Diagnostics, hl = { bg = colors.nobg, force = true } },
- { Space, hl = { bg = colors.nobg, force = true } },
- { LSPActive, hl = { bg = colors.nobg, force = true } },
- { Space, hl = { bg = colors.nobg, force = true } },
- { FileInfoBlock, hl = { bg = colors.nobg, force = true } },
- { RightSpace, hl = { bg = colors.nobg, force = true } },
- { Ruler, hl = { fg = utils.get_highlight("statusline").bg, bold = false } },
- { LeftSpace, hl = { bg = colors.nobg, force = true } },
- }
-
- local sections = { left, middle, right }
- local DefaultStatusline = { sections }
-
- -- Special statuslines for inactive/special buffers
- local specialleft = {
- { RightSpace, hl = { bg = colors.nobg, force = true } },
- { ViMode, hl = { bg = utils.get_highlight("statusline").bg, bold = false } },
- { LeftSpace, hl = { bg = colors.nobg, force = true } },
- }
-
- local specialmiddle = {
- { Align, hl = { bg = colors.nobg, force = true } },
- { Align, hl = { bg = colors.nobg, force = true } },
- }
-
- local specialright = {
- { RightSpace, hl = { bg = colors.nobg, force = true } },
- { Ruler, hl = { fg = utils.get_highlight("statusline").bg, bold = false } },
- { LeftSpace, hl = { bg = colors.nobg, force = true } },
- }
-
- local specialsections = { specialleft, specialmiddle, specialright }
-
- local InactiveStatusline = {
- condition = conditions.is_not_active,
- specialsections,
- }
-
- local SpecialStatusline = {
- condition = function()
- return conditions.buffer_matches({
- buftype = { "nofile", "prompt", "help", "quickfix" },
- filetype = { "^git.*", "fugitive", "dashboard" },
- })
- end,
- specialsections,
- }
-
- local TerminalStatusline = {
- condition = function()
- return conditions.buffer_matches({ buftype = { "terminal" } })
- end,
- specialsections,
- }
-
- -- FIXED: Main StatusLine with better mode handling
- local StatusLine = {
- static = {
- mode_colors = {
- n = colors.blue,
- no = colors.blue,
- nov = colors.blue,
- noV = colors.blue,
- ["no\22"] = colors.blue,
- niI = colors.blue,
- niR = colors.blue,
- niV = colors.blue,
- nt = colors.blue,
- v = colors.purple,
- vs = colors.purple,
- V = colors.purple,
- ["\22"] = colors.purple,
- ["\22s"] = colors.purple,
- s = colors.purple,
- S = colors.purple,
- ["\19"] = colors.purple,
- i = colors.green,
- ix = colors.green,
- ic = colors.green,
- R = colors.red,
- Rc = colors.red,
- Rx = colors.red,
- Rv = colors.red,
- Rvc = colors.red,
- Rvx = colors.red,
- c = colors.orange,
- cv = colors.orange,
- ce = colors.orange,
- r = colors.red,
- rm = colors.red,
- ["r?"] = colors.red,
- ["!"] = colors.orange,
- t = colors.orange,
- },
- mode_color = function(self)
- -- FIXED: Always get current mode to ensure updates
- local mode = vim.fn.mode()
- return self.mode_colors[mode] or colors.blue
- end,
- },
- -- FIXED: Add update triggers to ensure statusline refreshes properly
- update = {
- "ModeChanged",
- "BufEnter",
- "WinEnter",
- "WinLeave",
- "BufWinEnter",
- "CmdlineLeave",
- callback = vim.schedule_wrap(function()
- vim.cmd("redrawstatus")
- end),
- },
- fallthrough = false,
- SpecialStatusline,
- TerminalStatusline,
- InactiveStatusline,
- DefaultStatusline,
- }
-
- -- WinBar components
- local WinbarFileNameBlock = {
- init = function(self)
- self.filename = vim.api.nvim_buf_get_name(0)
- end,
- hl = { bg = colors.bg },
- }
-
- local WinbarFileName = {
- provider = function(self)
- local filename = vim.fn.fnamemodify(self.filename, ":.")
- if filename == "" then
- return "No Name"
- end
- if not conditions.width_percent_below(#filename, 0.25) then
- filename = vim.fn.pathshorten(filename)
- end
- return filename
- end,
- hl = { fg = colors.gray, bold = false, bg = colors.bg },
- }
-
- WinbarFileNameBlock = utils.insert(
- WinbarFileNameBlock,
- FileIcon,
- utils.insert(WinbarFileName),
- unpack(FileFlags),
- { provider = "%<" }
- )
-
- vim.api.nvim_create_autocmd("User", {
- pattern = "HeirlineInitWinbar",
- callback = function(args)
- local buf = args.buf
- local buftype = vim.tbl_contains({ "prompt", "nofile", "help", "quickfix" }, vim.bo[buf].buftype)
- local filetype = vim.tbl_contains({ "gitcommit", "fugitive" }, vim.bo[buf].filetype)
- if buftype or filetype then
- vim.opt_local.winbar = nil
- end
- end,
- })
-
- local On_click = {
- minwid = function()
- return vim.api.nvim_get_current_win()
- end,
- callback = function(_, minwid)
- local winid = minwid
- local buf = vim.api.nvim_win_get_buf(winid)
- end,
- }
-
- local CloseButton = {
- condition = function(self)
- return not vim.bo.modified
- end,
- update = { "WinNew", "WinClosed", "BufEnter" },
- { provider = " " },
- {
- provider = Icons.UI.close,
- hl = { fg = "gray" },
- On_click = {
- minwid = function()
- return vim.api.nvim_get_current_win()
- end,
- callback = function(_, minwid)
- vim.api.nvim_win_close(minwid, true)
- end,
- name = "heirline_winbar_close_button",
- },
- },
- }
-
- local Center = {
- fallthrough = false,
- {
- condition = function()
- return conditions.buffer_matches({
- buftype = { "terminal", "nofile", "prompt", "help", "quickfix" },
- filetype = { "dap-ui", "NvimTree", "^git.*", "fugitive", "dashboard" },
- })
- end,
- init = function()
- vim.opt_local.winbar = nil
- end,
- },
- {
- condition = function()
- return conditions.buffer_matches({ buftype = { "terminal" } })
- end,
- FileType,
- Space,
- },
- {
- condition = function()
- return not conditions.is_active()
- end,
- utils.surround({ "", "" }, colors.nobg, { WinbarFileNameBlock }),
- },
- utils.surround({ "", "" }, colors.nobg, { FileNameBlock }),
- }
-
- local WinBar = { Space, Center }
-
- -- Tabline components
- local TablineFileIcon = {
- init = function(self)
- local filename = self.filename
- local extension = vim.fn.fnamemodify(filename, ":e")
-
- local has_nerd_fonts = vim.g.statusline_has_nerd_fonts
- if has_nerd_fonts == nil then
- if vim.fn.has('unix') == 1 and vim.fn.executable('fc-list') == 1 then
- local handle = io.popen('fc-list | grep -i nerd')
- local result = handle:read('*a')
- handle:close()
- has_nerd_fonts = result ~= ""
- else
- has_nerd_fonts = false
- end
- vim.g.statusline_has_nerd_fonts = has_nerd_fonts
- end
-
- if has_nerd_fonts then
- self.icon, self.icon_color = require("nvim-web-devicons").get_icon_color(filename, extension, { default = true })
- else
- self.icon = ""
- self.icon_color = colors.blue
-
- if vim.fn.isdirectory(filename) == 1 then
- self.icon = "[DIR]"
- else
- local file_icon = Icons.File[extension:lower()] or Icons.File.default
- if type(file_icon) == "table" then
- self.icon = file_icon[1] or Icons.File.default
- else
- self.icon = file_icon
- end
- end
- end
-
- if self.icon ~= "" then
- self.icon = self.icon .. " "
- end
- end,
- provider = function(self)
- return self.icon or ""
- end,
- hl = function(self)
- return { fg = self.icon_color or colors.blue }
- end,
- }
-
- local TablineFileName = {
- provider = function(self)
- local filename = vim.fn.fnamemodify(self.filename, ":t")
- if filename == "" then
- return "[No Name]"
- end
- return filename
- end,
- }
-
- local TablineFileFlags = {
- {
- condition = function(self)
- return vim.api.nvim_buf_get_option(self.bufnr, "modified")
- end,
- provider = "%X " .. Icons.Indicator.plus .. " %X",
- hl = { fg = "green" },
- },
- {
- condition = function(self)
- return not vim.api.nvim_buf_get_option(self.bufnr, "modifiable") or vim.api.nvim_buf_get_option(self.bufnr, "readonly")
- end,
- provider = function()
- if vim.bo.readonly then
- return " " .. Icons.UI.lock
- end
- return ""
- end,
- hl = { fg = "orange" },
- },
- }
-
- local TablineFileNameBlock = {
- init = function(self)
- self.filename = vim.api.nvim_buf_get_name(self.bufnr)
- end,
- hl = function(self)
- if self.is_active then
- return "TabLineSel"
- else
- return "TabLineFill"
- end
- end,
- on_click = {
- callback = function(_, minwid, _, button)
- if button == "m" then
- vim.api.nvim_buf_delete(minwid, { force = false })
- else
- vim.api.nvim_win_set_buf(0, minwid)
- end
- end,
- minwid = function(self)
- return self.bufnr
- end,
- name = "heirline_tabline_buffer_callback",
- },
- TablineFileIcon,
- TablineFileName,
- TablineFileFlags,
- }
-
- local TablineCloseButton = {
- condition = function(self)
- return not vim.api.nvim_buf_get_option(self.bufnr, "modified")
- end,
- { provider = " " },
- {
- provider = "" .. Icons.UI.close .. " %X",
- hl = { fg = colors.red },
- on_click = {
- callback = function(_, minwid)
- vim.api.nvim_buf_delete(minwid, { force = false })
- end,
- minwid = function(self)
- return self.bufnr
- end,
- name = "heirline_tabline_close_buffer_callback",
- },
- },
- }
-
- local TablineBufferBlock = utils.surround({ "", "" }, function(self)
- if self.is_active then
- return utils.get_highlight("TabLineSel").bg
- else
- return utils.get_highlight("TabLineFill").bg
- end
- end, { Tab, TablineFileNameBlock, TablineCloseButton })
-
- local BufferLine = utils.make_buflist(
- TablineBufferBlock,
- { provider = Icons.Symbol.arrow_left, hl = { fg = colors.gray } },
- { provider = Icons.Symbol.arrow_right, hl = { fg = colors.gray } }
- )
-
- local Tabpage = {
- provider = function(self)
- return "%" .. self.tabnr .. "T " .. self.tabnr .. " %T"
- end,
- hl = function(self)
- return self.is_active and "TabLineSel" or "TabLineFill"
- end,
- }
-
- local TabpageClose = {
- provider = "%999X " .. Icons.UI.close .. " %X",
- hl = { fg = colors.red, bg = colors.bg },
- }
-
- local TabPages = {
- condition = function()
- return #vim.api.nvim_list_tabpages() >= 2
- end,
- { provider = "%=" },
- utils.make_tablist(Tabpage),
- TabpageClose,
- }
-
- local TabLineOffset = {
- condition = function(self)
- local win = vim.api.nvim_tabpage_list_wins(0)[1]
- local bufnr = vim.api.nvim_win_get_buf(win)
- self.winid = win
-
- if vim.api.nvim_buf_get_option(bufnr, "filetype") == "NvimTree" then
- self.title = "NvimTree"
- return true
- end
- end,
- provider = function(self)
- local title = self.title
- local width = vim.api.nvim_win_get_width(self.winid)
- local pad = math.ceil((width - #title) / 2)
- return string.rep(" ", pad) .. title .. string.rep(" ", pad)
- end,
- hl = { fg = colors.white, bg = "#333842", bold = true },
- }
-
- local TabLine = {
- TabLineOffset,
- BufferLine,
- TabPages,
- }
-
- -- Buffer navigation functions
- local function get_bufs()
- return vim.tbl_filter(function(bufnr)
- return vim.api.nvim_buf_is_loaded(bufnr) and vim.bo[bufnr].buflisted
- end, vim.api.nvim_list_bufs())
- end
-
- local function goto_buf(index)
- local bufs = get_bufs()
- if index > #bufs then
- index = #bufs
- end
- vim.api.nvim_win_set_buf(0, bufs[index])
- end
-
- local function add_key(key, index)
- vim.keymap.set("n", "<A-" .. key .. ">", function()
- goto_buf(index)
- end, { noremap = true, silent = true })
- end
-
- for i = 1, 9 do
- add_key(i, i)
- end
- add_key("0", 10)
-
- vim.o.showtabline = 2
- vim.cmd([[au FileType * if index(['wipe', 'delete', 'unload'], &bufhidden) >= 0 | set nobuflisted | endif]])
-
- -- FIXED: Add proper autocmds for better statusline updates
- local augroup = vim.api.nvim_create_augroup("HeirlineStatusline", { clear = true })
-
- -- Force statusline refresh on mode changes and buffer events
- vim.api.nvim_create_autocmd({
- "ModeChanged",
- "BufEnter",
- "BufWinEnter",
- "WinEnter",
- "WinLeave",
- "CmdlineLeave",
- "TermEnter",
- "TermLeave"
- }, {
- group = augroup,
- callback = function()
- vim.schedule(function()
- if vim.o.laststatus > 0 then
- vim.cmd("redrawstatus!")
- end
- end)
- end,
- })
-
- -- Final heirline setup
- heirline.setup({
- statusline = StatusLine,
- winbar = WinBar,
- tabline = TabLine,
- opts = {
- disable_winbar_cb = function(args)
- local buf = args.buf
- if not vim.api.nvim_buf_is_valid(buf) then
- return true
- end
-
- local buftype = vim.tbl_contains(
- { "prompt", "nofile", "help", "quickfix" },
- vim.bo[buf].buftype
- )
- local filetype = vim.tbl_contains(
- { "gitcommit", "fugitive" },
- vim.bo[buf].filetype
- )
- return buftype or filetype
- end,
- }
- })
-
-end
-
-return M