You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

530 lines
11 KiB
Lua

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