local M = {} local C = require("catppuccin.palettes").get_palette() local lsp = require("feline.providers.lsp") local navic = require("nvim-navic") local assets = { left_separator = "", right_separator = "", mode_icon = "", dir = "", file = "", lsp = { server = "", error = "", warning = "", info = "", hint = "", }, git = { branch = "", added = "", changed = "", removed = "", }, } local sett = { text = C.surface0, bkg = C.surface0, diffs = C.mauve, extras = C.overlay1, curr_file = C.maroon, curr_dir = C.flamingo, show_modified = false, } if require("catppuccin").options.transparent_background then sett.bkg = "NONE" end local mode_colors = { ["n"] = { "NORMAL", C.lavender }, ["no"] = { "N-PENDING", C.lavender }, ["i"] = { "INSERT", C.green }, ["ic"] = { "INSERT", C.green }, ["t"] = { "TERMINAL", C.green }, ["v"] = { "VISUAL", C.flamingo }, ["V"] = { "V-LINE", C.flamingo }, [""] = { "V-BLOCK", C.flamingo }, ["R"] = { "REPLACE", C.maroon }, ["Rv"] = { "V-REPLACE", C.maroon }, ["s"] = { "SELECT", C.maroon }, ["S"] = { "S-LINE", C.maroon }, [""] = { "S-BLOCK", C.maroon }, ["c"] = { "COMMAND", C.peach }, ["cv"] = { "COMMAND", C.peach }, ["ce"] = { "COMMAND", C.peach }, ["r"] = { "PROMPT", C.teal }, ["rm"] = { "MORE", C.teal }, ["r?"] = { "CONFIRM", C.mauve }, ["!"] = { "SHELL", C.green }, } function M.setup(opts) if opts then opts.assets = opts.assets or {} opts.sett = opts.sett or {} opts.mode_colors = opts.mode_colors or {} else opts = {} end assets = vim.tbl_deep_extend("force", assets, opts.assets) sett = vim.tbl_deep_extend("force", sett, opts.sett) mode_colors = vim.tbl_deep_extend("force", mode_colors, opts.mode_colors) end function M.get() local shortline = false local components = { active = { {}, {}, {} }, -- left, center, right inactive = { {} }, } local function is_enabled(min_width) if shortline then return true end return vim.api.nvim_win_get_width(0) > min_width end -- global components local invi_sep = { str = " ", hl = { fg = sett.bkg, bg = sett.bkg, }, } -- helpers local function has_git_head() return vim.b.gitsigns_head ~= nil end local function any_git_changes() local gst = vim.b.gitsigns_status_dict -- git stats if gst then if gst["added"] and gst["added"] > 0 or gst["removed"] and gst["removed"] > 0 or gst["changed"] and gst["changed"] > 0 then return true end end return false end -- #################### STATUSLINE -> -- ######## Left -- Current vi mode ------> local vi_mode_hl = function() return { fg = sett.text, bg = mode_colors[vim.fn.mode()][2], style = "bold", } end components.active[1][1] = { provider = " " .. assets.mode_icon .. " ", hl = function() return { fg = sett.text, bg = mode_colors[vim.fn.mode()][2], } end, } -- there is a dilema: we need to hide Diffs if ther is no git info. We can do that, but this will -- leave the right_separator colored with purple, and since we can't change the color conditonally -- then the solution is to create two right_separators: one with a mauve sett.bkg and the other one normal -- sett.bkg; both have the same fg (vi mode). The mauve one appears if there is git info, else the one with -- the normal sett.bkg appears. Fixed :) components.active[1][2] = { provider = assets.right_separator, hl = function() return { fg = mode_colors[vim.fn.mode()][2], bg = sett.bkg, } end, enabled = function() return not any_git_changes() and not has_git_head() end, } components.active[1][3] = { provider = assets.right_separator, hl = function() return { fg = mode_colors[vim.fn.mode()][2], bg = sett.diffs, } end, enabled = function() return any_git_changes() end, } components.active[1][4] = { provider = assets.right_separator, hl = function() return { fg = mode_colors[vim.fn.mode()][2], bg = C.maroon, } end, enabled = function() return not any_git_changes() and has_git_head() end, } -- Current vi mode ------> -- Diffs ------> components.active[1][5] = { provider = "git_diff_added", hl = { fg = sett.text, bg = sett.diffs, }, icon = " " .. assets.git.added .. " ", } components.active[1][6] = { provider = "git_diff_changed", hl = { fg = sett.text, bg = sett.diffs, }, icon = " " .. assets.git.changed .. " ", } components.active[1][7] = { provider = "git_diff_removed", hl = { fg = sett.text, bg = sett.diffs, }, icon = " " .. assets.git.removed .. " ", } components.active[1][8] = { provider = assets.right_separator, hl = { fg = sett.diffs, bg = C.maroon, }, enabled = function() return any_git_changes() end, } -- Diffs ------> -- Git Branch & Breadcrumbs ------> components.active[1][9] = { provider = " ", hl = { fg = C.maroon, bg = C.maroon, }, enabled = function() return has_git_head() end, } components.active[1][10] = { provider = "git_branch", enabled = is_enabled(70), hl = { fg = sett.text, bg = C.maroon, }, icon = assets.git.branch .. " ", } components.active[1][11] = { provider = " ", hl = { fg = sett.bkg, bg = C.maroon, }, enabled = function() return has_git_head() end, } components.active[1][12] = { provider = assets.right_separator, hl = { fg = C.maroon, bg = sett.bkg, }, enabled = function() return has_git_head() end, } components.active[1][13] = { provider = function() return " " .. navic.get_location() end, enabled = function() return navic.is_available() end, hl = { fg = sett.text, bg = sett.bkg, }, } components.active[1][14] = { provider = " ", hl = { fg = sett.bkg, bg = sett.bkg, }, enabled = function() return not navic.is_available() end, } -- Git Branch & Breadcrumbs ------> -- ######## Left -- ######## Center function map(arr, func) local new_arr = {} for i, v in ipairs(arr) do new_arr[i] = func(v) end return new_arr end -- Diagnostics ------> -- workspace loader components.active[2][1] = { provider = function() local Lsp = vim.lsp.util.get_progress_messages()[1] if Lsp then local msg = Lsp.message or "" local percentage = Lsp.percentage if not percentage then return "" end local title = Lsp.title or "" local spinners = { "", "", "", } local success_icon = { "", "", "", } local ms = vim.loop.hrtime() / 1000000 local frame = math.floor(ms / 120) % #spinners if percentage >= 70 then return string.format(" %%<%s %s %s (%s%%%%) ", success_icon[frame + 1], title, msg, percentage) end return string.format(" %%<%s %s %s (%s%%%%) ", spinners[frame + 1], title, msg, percentage) end return "" end, enabled = is_enabled(80), hl = { fg = C.rosewater, bg = sett.bkg, }, } -- general diagnostics (errors, warnings. info and hints) components.active[2][2] = { provider = "diagnostic_errors", enabled = function() return lsp.diagnostics_exist(vim.diagnostic.severity.ERROR) end, hl = { fg = C.red, bg = sett.bkg, }, icon = " " .. assets.lsp.error .. " ", } components.active[2][3] = { provider = "diagnostic_warnings", enabled = function() return lsp.diagnostics_exist(vim.diagnostic.severity.WARN) end, hl = { fg = C.yellow, bg = sett.bkg, }, icon = " " .. assets.lsp.warning .. " ", } components.active[2][4] = { provider = "diagnostic_info", enabled = function() return lsp.diagnostics_exist(vim.diagnostic.severity.INFO) end, hl = { fg = C.sky, bg = sett.bkg, }, icon = " " .. assets.lsp.info .. " ", } components.active[2][5] = { provider = "diagnostic_hints", enabled = function() return lsp.diagnostics_exist(vim.diagnostic.severity.HINT) end, hl = { fg = C.rosewater, bg = sett.bkg, }, icon = " " .. assets.lsp.hint .. " ", } -- Diagnostics ------> -- ######## Center -- ######## Right components.active[3][1] = { provider = function() local current_line = vim.fn.line(".") local total_line = vim.fn.line("$") if current_line == 1 then return "Top" elseif current_line == vim.fn.line("$") then return "Bot" end local result, _ = math.modf((current_line / total_line) * 100) return result .. "%%" end, -- enabled = shortline or function(winid) -- return vim.api.nvim_win_get_width(winid) > 90 -- end, hl = { fg = sett.extras, bg = sett.bkg, }, right_sep = invi_sep, } -- position components.active[3][2] = { provider = "position", -- enabled = shortline or function(winid) -- return vim.api.nvim_win_get_width(winid) > 90 -- end, hl = { fg = sett.extras, bg = sett.bkg, }, right_sep = invi_sep, } -- macro components.active[3][3] = { provider = "macro", enabled = function() return vim.api.nvim_get_option("cmdheight") == 0 end, hl = { fg = sett.extras, bg = sett.bkg, }, right_sep = invi_sep, } -- search count components.active[3][4] = { provider = "search_count", enabled = function() return vim.api.nvim_get_option("cmdheight") == 0 end, hl = { fg = sett.extras, bg = sett.bkg, }, right_sep = invi_sep, } components.active[3][5] = { provider = function() local filename = vim.fn.expand("%:t") local extension = vim.fn.expand("%:e") local present, icons = pcall(require, "nvim-web-devicons") local icon = present and icons.get_icon(filename, extension) or assets.file return (sett.show_modified and "%m" or "") .. " " .. icon .. " " .. filename .. " " end, enabled = is_enabled(70), hl = { fg = sett.text, bg = sett.curr_file, }, left_sep = { str = assets.left_separator, hl = { fg = sett.curr_file, bg = sett.bkg, }, }, } -- components.active[3][6] = { -- provider = function() -- local dir_name = vim.fn.fnamemodify(vim.fn.getcwd(), ":t") -- return " " .. assets.dir .. " " .. dir_name .. " " -- end, -- enabled = is_enabled(80), -- hl = { -- fg = sett.text, -- bg = sett.curr_dir, -- }, -- left_sep = { -- str = assets.left_separator, -- hl = { -- fg = sett.curr_dir, -- bg = sett.curr_file, -- }, -- }, -- } -- ######## Right -- Inanctive components components.inactive[1][1] = { provider = function() return " " .. string.upper(vim.bo.ft) .. " " end, hl = { fg = C.overlay2, bg = C.mantle, }, } return components end return M