diff --git a/lua/core/init.lua b/lua/core/init.lua index 8e089d5..51bde5c 100644 --- a/lua/core/init.lua +++ b/lua/core/init.lua @@ -16,3 +16,6 @@ autocmd("BufUnload", { vim.opt.laststatus = 3 end, }) + +-- load statusline +vim.opt.statusline = "%!v:lua.require'ui.statusline'.run()" diff --git a/lua/core/utils.lua b/lua/core/utils.lua index 244fc90..76e0a19 100644 --- a/lua/core/utils.lua +++ b/lua/core/utils.lua @@ -1,15 +1,17 @@ local M = {} +local api = vim.api +local fn = vim.fn local merge_tb = vim.tbl_deep_extend M.close_buffer = function(force) if vim.bo.buftype == "terminal" then - vim.api.nvim_win_hide(0) + api.nvim_win_hide(0) return end - local fileExists = vim.fn.filereadable(vim.fn.expand "%p") - local modified = vim.api.nvim_buf_get_option(vim.fn.bufnr(), "modified") + local fileExists = fn.filereadable(fn.expand "%p") + local modified = api.nvim_buf_get_option(fn.bufnr(), "modified") -- if file doesnt exist & its modified if fileExists == 0 and modified then @@ -20,7 +22,7 @@ M.close_buffer = function(force) force = force or not vim.bo.buflisted or vim.bo.buftype == "nofile" -- if not force, change to prev buf and then close current - local close_cmd = force and ":bd!" or ":bp | bd" .. vim.fn.bufnr() + local close_cmd = force and ":bd!" or ":bp | bd" .. fn.bufnr() vim.cmd(close_cmd) end diff --git a/lua/plugins/configs/gps.lua b/lua/plugins/configs/gps.lua index 23799d7..920f218 100644 --- a/lua/plugins/configs/gps.lua +++ b/lua/plugins/configs/gps.lua @@ -9,36 +9,30 @@ local icons = require "plugins.configs.lspkind_icons" local options = { icons = { - ["class-name"] = "%#CmpItemKindClass#" .. icons.Class .. "%*" .. " ", - ["function-name"] = "%#CmpItemKindFunction#" .. icons.Function .. "%*" .. " ", - ["method-name"] = "%#CmpItemKindMethod#" .. icons.Method .. "%*" .. " ", - ["container-name"] = "%#CmpItemKindProperty#" .. icons.Object .. "%*" .. " ", - ["tag-name"] = "%#CmpItemKindKeyword#" .. icons.Tag .. "%*" .. " ", - ["mapping-name"] = "%#CmpItemKindProperty#" .. icons.Object .. "%*" .. " ", - ["sequence-name"] = "%CmpItemKindProperty#" .. icons.Array .. "%*" .. " ", - ["null-name"] = "%CmpItemKindField#" .. icons.Field .. "%*" .. " ", - ["boolean-name"] = "%CmpItemKindValue#" .. icons.Boolean .. "%*" .. " ", - ["integer-name"] = "%CmpItemKindValue#" .. icons.Number .. "%*" .. " ", - ["float-name"] = "%CmpItemKindValue#" .. icons.Number .. "%*" .. " ", - ["string-name"] = "%CmpItemKindValue#" .. icons.String .. "%*" .. " ", - ["array-name"] = "%CmpItemKindProperty#" .. icons.Array .. "%*" .. " ", - ["object-name"] = "%CmpItemKindProperty#" .. icons.Object .. "%*" .. " ", - ["number-name"] = "%CmpItemKindValue#" .. icons.Number .. "%*" .. " ", - ["table-name"] = "%CmpItemKindProperty#" .. icons.Table .. "%*" .. " ", - ["date-name"] = "%CmpItemKindValue#" .. icons.Calendar .. "%*" .. " ", - ["date-time-name"] = "%CmpItemKindValue#" .. icons.Table .. "%*" .. " ", - ["inline-table-name"] = "%CmpItemKindProperty#" .. icons.Calendar .. "%*" .. " ", - ["time-name"] = "%CmpItemKindValue#" .. icons.Watch .. "%*" .. " ", - ["module-name"] = "%CmpItemKindModule#" .. icons.Module .. "%*" .. " ", - }, - - ["lua"] = { - icons = { - ["container-name"] = "%#CmpItemKindProperty#" .. icons.Table .. "%*" .. " ", - ["mapping-name"] = "%#CmpItemKindProperty#" .. icons.Table .. "%*" .. " ", - ["object-name"] = "%CmpItemKindProperty#" .. icons.Table .. "%*" .. " ", - }, + ["class-name"] = "%#GpsItemKindClass#" .. icons.Class .. "%*" .. " ", + ["function-name"] = "%#GpsItemKindFunction#" .. icons.Function .. "%*" .. " ", + ["method-name"] = "%#GpsItemKindMethod#" .. icons.Method .. "%*" .. " ", + ["container-name"] = "%#GpsItemKindProperty#" .. icons.Object .. "%*" .. " ", + ["tag-name"] = "%#GpsItemKindKeyword#" .. icons.Tag .. "%*" .. " ", + ["mapping-name"] = "%#GpsItemKindProperty#" .. icons.Object .. "%*" .. " ", + ["sequence-name"] = "%GpsItemKindProperty#" .. icons.Array .. "%*" .. " ", + ["null-name"] = "%GpsItemKindField#" .. icons.Field .. "%*" .. " ", + ["boolean-name"] = "%GpsItemKindValue#" .. icons.Boolean .. "%*" .. " ", + ["integer-name"] = "%GpsItemKindValue#" .. icons.Number .. "%*" .. " ", + ["float-name"] = "%GpsItemKindValue#" .. icons.Number .. "%*" .. " ", + ["string-name"] = "%GpsItemKindValue#" .. icons.String .. "%*" .. " ", + ["array-name"] = "%GpsItemKindProperty#" .. icons.Array .. "%*" .. " ", + ["object-name"] = "%GpsItemKindProperty#" .. icons.Object .. "%*" .. " ", + ["number-name"] = "%GpsItemKindValue#" .. icons.Number .. "%*" .. " ", + ["table-name"] = "%GpsItemKindProperty#" .. icons.Table .. "%*" .. " ", + ["date-name"] = "%GpsItemKindValue#" .. icons.Calendar .. "%*" .. " ", + ["date-time-name"] = "%GpsItemKindValue#" .. icons.Table .. "%*" .. " ", + ["inline-table-name"] = "%GpsItemKindProperty#" .. icons.Calendar .. "%*" .. " ", + ["time-name"] = "%GpsItemKindValue#" .. icons.Watch .. "%*" .. " ", + ["module-name"] = "%GpsItemKindModule#" .. icons.Module .. "%*" .. " ", }, } +options = require("core.utils").load_override(options, "SmiteshP/nvim-gps") + gps.setup(options) diff --git a/lua/plugins/configs/icons.lua b/lua/plugins/configs/icons.lua index c3f3ba0..bccc134 100644 --- a/lua/plugins/configs/icons.lua +++ b/lua/plugins/configs/icons.lua @@ -6,6 +6,11 @@ end local options = { override = { + default_icon = { + icon = "", + name = "Default", + }, + c = { icon = "", name = "c", diff --git a/lua/plugins/configs/statusline.lua b/lua/plugins/configs/statusline.lua deleted file mode 100644 index 6bdea53..0000000 --- a/lua/plugins/configs/statusline.lua +++ /dev/null @@ -1,447 +0,0 @@ -local present, feline = pcall(require, "feline") -local fn = vim.fn - -local function get_color(group, attr) - return fn.synIDattr(fn.synIDtrans(fn.hlID(group)), attr) -end - -if not present then - return -end - -local options = { - lsp = require "feline.providers.lsp", - lsp_severity = vim.diagnostic.severity, -} - -options.icons = { - mode_icon = "  ", - position_icon = " ", - empty_file = " Empty ", - dir = " ", - clock = " ", -} - -options.icon_styles = { - - -- mix of slant + round - default = { - left = "", - right = " ", - }, - - round = { - left = "", - right = "", - }, - - block = { - left = "█", - right = "█", - }, - - arrow = { - left = "", - right = "", - }, -} - -local statusline_opt = require("core.utils").load_config().plugins.options.statusline.separator_style -options.separator_style = options.icon_styles[statusline_opt] - -options.mode_icon = { - provider = options.icons.mode_icon, - - hl = function() - return { - fg = get_color("Feline", "bg#"), - bg = get_color(options.mode_hlgroups[fn.mode()][2], "fg#"), - } - end, - - right_sep = { - str = options.separator_style.right, - hl = function() - return { - fg = get_color(options.mode_hlgroups[fn.mode()][2], "fg#"), - bg = get_color("Feline_EmptySpace", "fg#"), - } - end, - }, -} - --- MODES - -options.mode_hlgroups = { - ["n"] = { "Normal", "Feline_NormalMode" }, - ["no"] = { "N-PENDING", "Feline_NormalMode" }, - ["i"] = { "INSERT", "Feline_InsertMode" }, - ["ic"] = { "INSERT", "Feline_InsertMode" }, - ["t"] = { "TERMINAL", "Feline_TerminalMode" }, - ["v"] = { "VISUAL", "Feline_VisualMode" }, - ["V"] = { "V-LINE", "Feline_VisualMode" }, - [""] = { "V-BLOCK", "Feline_VisualMode" }, - ["R"] = { "REPLACE", "Feline_ReplaceMode" }, - ["Rv"] = { "V-REPLACE", "Feline_ReplaceMode" }, - ["s"] = { "SELECT", "Feline_SelectMode" }, - ["S"] = { "S-LINE", "Feline_SelectMode" }, - [""] = { "S-BLOCK", "Feline_SelectMode" }, - ["c"] = { "COMMAND", "Feline_CommandMode" }, - ["cv"] = { "COMMAND", "Feline_CommandMode" }, - ["ce"] = { "COMMAND", "Feline_CommandMode" }, - ["r"] = { "PROMPT", "Feline_ConfirmMode" }, - ["rm"] = { "MORE", "Feline_ConfirmMode" }, - ["r?"] = { "CONFIRM", "Feline_ConfirmMode" }, - ["!"] = { "SHELL", "Feline_TerminalMode" }, -} - -options.vi_mode = { - provider = function() - return " " .. options.mode_hlgroups[fn.mode()][1] .. " " - end, - - hl = function() - return options.mode_hlgroups[fn.mode()][2] - end, - - right_sep = { - str = options.separator_style.right, - hl = function() - return { - fg = get_color("Feline_EmptySpace", "bg#"), - bg = get_color("Feline_nvim_gps", "bg#"), - } - end, - }, -} - -options.cwd = { - -- icon - left_sep = { - str = " " .. options.icons.dir, - hl = "FelineCwd", - }, - - -- dirname - provider = function() - local dir_name = fn.fnamemodify(fn.getcwd(), ":t") - return " " .. dir_name .. " " - end, - - hl = "FelineCwd", -} - --- lsp -options.diagnostic = { - error = { - provider = "diagnostic_errors", - enabled = function() - return options.lsp.diagnostics_exist(options.lsp_severity.ERROR) - end, - - hl = "Feline_lspError", - icon = "  ", - }, - - warning = { - provider = "diagnostic_warnings", - enabled = function() - return options.lsp.diagnostics_exist(options.lsp_severity.WARN) - end, - - hl = "Feline_lspWarning", - icon = "  ", - }, - - hint = { - provider = "diagnostic_hints", - enabled = function() - return options.lsp.diagnostics_exist(options.lsp_severity.HINT) - end, - hl = "Feline_LspHints", - icon = "  ", - }, - - info = { - provider = "diagnostic_info", - enabled = function() - return options.lsp.diagnostics_exist(options.lsp_severity.INFO) - end, - hl = "Feline_LspInfo", - icon = "  ", - }, -} - -options.lsp_status = { - provider = function() - if next(vim.lsp.buf_get_clients()) ~= nil then - local lsp_name = vim.lsp.get_active_clients()[1].name - - return "  LSP ~ " .. lsp_name .. " " - else - return "" - end - end, - - hl = "Feline_LspIcon", -} - -options.lsp_progress = { - provider = function() - local Lsp = vim.lsp.util.get_progress_messages()[1] - - if not Lsp then - return "" - end - - local msg = Lsp.message or "" - local percentage = Lsp.percentage or 0 - local title = Lsp.title or "" - local spinners = { "", "" } - - local ms = vim.loop.hrtime() / 1000000 - local frame = math.floor(ms / 120) % #spinners - - return string.format(" %%<%s %s %s (%s%%%%) ", spinners[frame + 1], title, msg, percentage) - end, - - hl = "Feline_LspProgress", -} - --- Git - -options.diff = { - add = { - provider = "git_diff_added", - hl = "Feline_diffIcons", - icon = "  ", - }, - - change = { - provider = "git_diff_changed", - hl = "Feline_diffIcons", - icon = "  ", - }, - - remove = { - provider = "git_diff_removed", - hl = "Feline_diffIcons", - icon = "  ", - }, -} - -options.git_branch = { - provider = "git_branch", - hl = "Feline_diffIcons", - icon = "  ", - - right_sep = { - str = " ", - hl = "Feline_diffIcons", - }, -} - -options.file_info = { - left_sep = { - str = options.separator_style.left, - hl = "Feline_file_info_sep", - }, - - -- file icon - provider = function() - local filename = fn.expand "%:t" - local extension = fn.expand "%:e" - - if filename == "" then - return options.icons.empty_file - end - - local icon = require("nvim-web-devicons").get_icon(filename, extension) - - if icon == nil then - icon = " " - else - icon = icon .. " " - end - - return icon - end, - - hl = "Feline_file_info", - - -- file name - right_sep = { - str = function() - local filename = fn.expand "%:t" - return " " .. fn.fnamemodify(filename, ":r") .. " " - end, - - hl = function() - return { - fg = get_color("Feline_file_info", "bg#"), - bg = get_color("Feline_file_info", "fg#"), - } - end, - }, -} - -options.nvim_gps = { - provider = function() - -- nvim-gps loads at cursorMoved so need to handle this - local gps_loaded, gps = pcall(require, "nvim-gps") - - if not gps_loaded then - return - end - - return " " .. gps.get_location() - end, - - enabled = function() - local gps_loaded, gps = pcall(require, "nvim-gps") - - if not gps_loaded then - return false - end - - return gps.is_available() - end, - - hl = "Feline_nvim_gps", -} - -options.separator_left = { - provider = options.separator_style.right, - hl = "Feline_EmptySpace", -} - -options.separator_right = { - provider = options.separator_style.left, - hl = "Feline_EmptySpace", -} - -options.separator_right_file = { - provider = options.separator_style.left, - hl = function() - return { - fg = get_color("Feline_EmptySpace", "fg#"), - bg = get_color("Feline_nvim_gps", "bg#"), - } - end, -} - -options.time = { - left_sep = { - str = options.separator_style.left, - hl = function() - return { - fg = get_color("Feline_time", "fg#"), - bg = get_color("Feline_EmptySpace", "fg#"), - } - end, - }, - - icon = { - str = options.icons.clock, - hl = function() - return { - fg = get_color("Feline_time", "bg#"), - bg = get_color("Feline_time", "fg#"), - } - end, - }, - - provider = function() - return " " .. fn.strftime "%H:%M" .. " " - end, - - hl = "Feline_time", -} - -options.current_line = { - - left_sep = { - str = options.separator_style.left, - hl = "Feline_PositionSeparator", - }, - - icon = { - str = options.icons.position_icon, - hl = "Feline_PositionIcon", - }, - - provider = function() - local current_line = fn.line "." - local total_line = fn.line "$" - - if current_line == 1 then - return " Top " - elseif current_line == fn.line "$" then - return " Bot " - end - local result, _ = math.modf((current_line / total_line) * 100) - return " " .. result .. "%% " - end, - - hl = "Feline_CurrentLine", -} - -options = require("core.utils").load_override(options, "feline-nvim/feline.nvim") - -local function add_table(tbl, inject) - if inject then - table.insert(tbl, inject) - end -end - --- components are divided in 3 sections -options.left = {} -options.middle = {} -options.right = {} - --- left -add_table(options.left, options.mode_icon) -add_table(options.left, options.separator_left) -add_table(options.left, options.vi_mode) -add_table(options.left, options.cwd) - --- lsp -add_table(options.left, options.lsp_status) -add_table(options.left, options.diagnostic.error) -add_table(options.left, options.diagnostic.warning) -add_table(options.left, options.diagnostic.hint) -add_table(options.left, options.diagnostic.info) - -add_table(options.middle, options.lsp_progress) -add_table(options.middle, options.nvim_gps) - --- git diffs -add_table(options.right, options.diff.add) -add_table(options.right, options.diff.change) -add_table(options.right, options.diff.remove) -add_table(options.right, options.git_branch) - -add_table(options.right, options.separator_right_file) -add_table(options.right, options.file_info) - -add_table(options.right, options.separator_right) -add_table(options.right, options.time) -add_table(options.right, options.separator_right) -add_table(options.right, options.current_line) - --- Initialize the components table -options.components = { active = {} } - -options.components.active[1] = options.left -options.components.active[2] = options.middle -options.components.active[3] = options.right - -options.theme = { - fg = get_color("Feline", "fg#"), - bg = get_color("Feline", "bg#"), -} - -feline.setup { - theme = options.theme, - components = options.components, -} diff --git a/lua/plugins/init.lua b/lua/plugins/init.lua index 6a82e17..7add238 100644 --- a/lua/plugins/init.lua +++ b/lua/plugins/init.lua @@ -17,6 +17,7 @@ local plugins = { }, ["NvChad/nvterm"] = { + module = "nvterm", config = function() require "plugins.configs.nvterm" end, @@ -29,13 +30,6 @@ local plugins = { end, }, - ["feline-nvim/feline.nvim"] = { - after = "nvim-web-devicons", - config = function() - require "plugins.configs.statusline" - end, - }, - ["SmiteshP/nvim-gps"] = { event = "CursorMoved", config = function() diff --git a/lua/ui/statusline.lua b/lua/ui/statusline.lua new file mode 100644 index 0000000..a0ca5cf --- /dev/null +++ b/lua/ui/statusline.lua @@ -0,0 +1,186 @@ +local fn = vim.fn + +local sep_style = { + default = { + left = "", + right = " ", + }, + + round = { + left = "", + right = "", + }, + + block = { + left = "█", + right = "█", + }, +} + +local user_sep_style = require("core.utils").load_config().plugins.options.statusline.separator_style +local sep_l = sep_style[user_sep_style]["left"] +local sep_r = sep_style[user_sep_style]["right"] + +local width_below = function(text, thresh) + return vim.o.columns / #text >= thresh +end + +local modes = { + ["n"] = { "NORMAL", "St_NormalMode" }, + ["no"] = { "N-PENDING", "St_NormalMode" }, + ["i"] = { "INSERT", "St_InsertMode" }, + ["ic"] = { "INSERT", "St_InsertMode" }, + ["t"] = { "TERMINAL", "St_TerminalMode" }, + ["nt"] = { "NTERMINAL", "St_NTerminalMode" }, + ["v"] = { "VISUAL", "St_VisualMode" }, + ["V"] = { "V-LINE", "St_VisualMode" }, + [""] = { "V-BLOCK", "St_VisualMode" }, + ["R"] = { "REPLACE", "St_ReplaceMode" }, + ["Rv"] = { "V-REPLACE", "St_ReplaceMode" }, + ["s"] = { "SELECT", "St_SelectMode" }, + ["S"] = { "S-LINE", "St_SelectMode" }, + [""] = { "S-BLOCK", "St_SelectMode" }, + ["c"] = { "COMMAND", "St_CommandMode" }, + ["cv"] = { "COMMAND", "St_CommandMode" }, + ["ce"] = { "COMMAND", "St_CommandMode" }, + ["r"] = { "PROMPT", "St_ConfirmMode" }, + ["rm"] = { "MORE", "St_ConfirmMode" }, + ["r?"] = { "CONFIRM", "St_ConfirmMode" }, + ["!"] = { "SHELL", "St_TerminalMode" }, +} + +local M = {} + +M.mode = function() + local m = vim.api.nvim_get_mode().mode + local current_mode = "%#" .. modes[m][2] .. "#" .. "  " .. modes[m][1] + local mode_sep1 = "%#" .. modes[m][2] .. "Sep" .. "#" .. sep_r + + return current_mode .. mode_sep1 .. "%#ST_EmptySpace#" .. sep_r +end + +M.fileInfo = function() + local icon = "" + local filename = fn.fnamemodify(fn.expand "%:t", ":r") + local extension = fn.expand "%:e" + + if filename == "" then + icon = icon .. "  Empty " + else + filename = " " .. filename .. " " + end + + local ft_icon = require("nvim-web-devicons").get_icon(filename, extension) + icon = (ft_icon ~= nil and " " .. ft_icon) or icon + + return "%#St_file_info#" .. icon .. filename .. "%#St_file_sep#" .. sep_r +end + +M.gps = function() + local gps_present, gps = pcall(require, "nvim-gps") + return gps_present and gps.is_available() and gps.get_location() or "" +end + +M.git = function() + if not vim.b.gitsigns_head or vim.b.gitsigns_git_status then + return "" + end + + local git_status = vim.b.gitsigns_status_dict + + local added = (git_status.added and git_status.added ~= 0) and ("  " .. git_status.added) or "" + local changed = (git_status.changed and git_status.changed ~= 0) and ("  " .. git_status.changed) or "" + local removed = (git_status.removed and git_status.removed ~= 0) and ("  " .. git_status.removed) or "" + local branch_name = "  " .. git_status.head .. " " + local git_info = branch_name .. added .. changed .. removed + + return "%#St_gitIcons#" .. git_info +end + +-- LSP STUFF +M.LSP_progress = function() + local Lsp = vim.lsp.util.get_progress_messages()[1] + + if not Lsp then + return "" + end + + local msg = Lsp.message or "" + local percentage = Lsp.percentage or 0 + local title = Lsp.title or "" + local spinners = { "", "" } + local ms = vim.loop.hrtime() / 1000000 + local frame = math.floor(ms / 120) % #spinners + local content = string.format(" %%<%s %s %s (%s%%%%) ", spinners[frame + 1], title, msg, percentage) + + return width_below(content, 5.3) and ("%#St_LspProgress#" .. content) or "" +end + +M.LSP_Diagnostics = function() + if not #vim.diagnostic.get(0) then + return "" + end + + local errors = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.ERROR }) + local warnings = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.WARN }) + local hints = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.HINT }) + local info = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.INFO }) + + errors = (errors and errors > 0) and ("%#St_lspError#" .. " " .. errors .. " ") or "" + warnings = (warnings and warnings > 0) and ("%#St_lspWarning#" .. " " .. warnings .. " ") or "" + hints = (hints and hints > 0) and ("%#St_lspHints#" .. "ﯧ " .. hints .. " ") or "" + info = (info and info > 0) and ("%#St_lspInfo#" .. " " .. info .. " ") or "" + + return errors .. warnings .. hints .. info +end + +M.LSP_status = function() + local lsp_attached = next(vim.lsp.buf_get_clients()) ~= nil + local content = lsp_attached and "  LSP ~ " .. vim.lsp.get_active_clients()[1].name .. " " or false + return content and width_below(content, 5.3) and ("%#St_LspStatus#" .. content) or "" +end + +M.cwd = function() + local left_sep = "%#ST_EmptySpace2#" .. sep_l .. "%#St_cwd_sep#" .. sep_l + local dir_icon = "%#St_cwd_icon#" .. " " + local dir_name = "%#St_cwd_text#" .. " " .. fn.fnamemodify(fn.getcwd(), ":t") .. " " + + return left_sep .. dir_icon .. dir_name +end + +M.cursor_position = function() + local left_sep = "%#ST_EmptySpace#" .. sep_l .. "%#St_pos_sep#" .. sep_l + local icon = "%#St_pos_icon#" .. " " + + local current_line = fn.line "." + local total_line = fn.line "$" + local text = math.modf((current_line / total_line) * 100) .. tostring "%%" + + if current_line == 1 then + text = "Top " + elseif current_line == total_line then + text = "Bot " + end + + return left_sep .. icon .. "%#St_pos_text#" .. " " .. text +end + +M.run = function() + return table.concat { + M.mode(), + M.fileInfo(), + M.git(), + + "%=", + M.LSP_progress(), + M.gps(), + "%=", + + M.LSP_Diagnostics(), + M.LSP_status(), + M.cwd(), + M.cursor_position(), + } +end + +return M