diff --git a/lua/core/options.lua b/lua/core/options.lua index ed149c4af..b620249b1 100644 --- a/lua/core/options.lua +++ b/lua/core/options.lua @@ -17,7 +17,7 @@ local function load_options() breakat = [[\ \ ;:,!?]], breakindentopt = "shift:2,min:20", clipboard = "unnamedplus", - cmdheight = 2, -- 0, 1, 2 + cmdheight = 1, -- 0, 1, 2 cmdwinheight = 5, complete = ".,w,b,k", completeopt = "menuone,noselect", diff --git a/lua/modules/configs/completion/formatting.lua b/lua/modules/configs/completion/formatting.lua index f1586dd11..3e0b9a507 100644 --- a/lua/modules/configs/completion/formatting.lua +++ b/lua/modules/configs/completion/formatting.lua @@ -35,7 +35,7 @@ end, { nargs = 1, complete = "filetype" }) function M.enable_format_on_save(is_configured) local opts = { pattern = "*", timeout = 1000 } - vim.api.nvim_create_augroup("format_on_save", {}) + vim.api.nvim_create_augroup("format_on_save", { clear = true }) vim.api.nvim_create_autocmd("BufWritePre", { group = "format_on_save", pattern = opts.pattern, diff --git a/lua/modules/configs/completion/lspsaga.lua b/lua/modules/configs/completion/lspsaga.lua index feb371ef6..42cc4a146 100644 --- a/lua/modules/configs/completion/lspsaga.lua +++ b/lua/modules/configs/completion/lspsaga.lua @@ -108,7 +108,7 @@ return function() }, }, symbol_in_winbar = { - enable = false, + enable = true, separator = " " .. icons.ui.Separator, hide_keyword = true, show_file = false, diff --git a/lua/modules/configs/ui/bufferline.lua b/lua/modules/configs/ui/bufferline.lua index 68f76f426..7ceabab57 100644 --- a/lua/modules/configs/ui/bufferline.lua +++ b/lua/modules/configs/ui/bufferline.lua @@ -8,7 +8,7 @@ return function() buffer_close_icon = icons.ui.Close, left_trunc_marker = icons.ui.Left, right_trunc_marker = icons.ui.Right, - max_name_length = 14, + max_name_length = 20, max_prefix_length = 13, tab_size = 20, color_icons = true, @@ -29,13 +29,13 @@ return function() filetype = "NvimTree", text = "File Explorer", text_align = "center", - padding = 1, + padding = 0, }, { filetype = "lspsagaoutline", text = "Lspsaga Outline", text_align = "center", - padding = 1, + padding = 0, }, }, }, diff --git a/lua/modules/configs/ui/catppuccin.lua b/lua/modules/configs/ui/catppuccin.lua index a95d1c78d..3c2e0bb5c 100644 --- a/lua/modules/configs/ui/catppuccin.lua +++ b/lua/modules/configs/ui/catppuccin.lua @@ -128,6 +128,13 @@ return function() bg = transparent_background and cp.none or cp.mantle, }, + -- For lspsaga.nvim + OutlineNormal = { bg = transparent_background and cp.none or cp.mantle }, + OutlineWinSeparator = { + bg = transparent_background and cp.none or cp.base, + fg = transparent_background and cp.surface1 or cp.base, + }, + -- For fidget FidgetTask = { bg = cp.none, fg = cp.surface2 }, FidgetTitle = { fg = cp.blue, style = { "bold" } }, @@ -172,7 +179,7 @@ return function() bg = transparent_background and cp.none or cp.mantle, }, TelescopeSelection = { - fg = cp.green, + fg = transparent_background and cp.subtext0 or cp.text, bg = transparent_background and cp.none or cp.surface0, }, TelescopeResultsDiffAdd = { fg = cp.green }, diff --git a/lua/modules/configs/ui/lualine.lua b/lua/modules/configs/ui/lualine.lua index 0d6a3096c..d80a716d2 100644 --- a/lua/modules/configs/ui/lualine.lua +++ b/lua/modules/configs/ui/lualine.lua @@ -2,61 +2,49 @@ return function() local colors = require("modules.utils").get_palette() local icons = { diagnostics = require("modules.utils.icons").get("diagnostics", true), + git = require("modules.utils.icons").get("git", true), + git_nosep = require("modules.utils.icons").get("git"), misc = require("modules.utils.icons").get("misc", true), ui = require("modules.utils.icons").get("ui", true), } - local function escape_status() - local ok, m = pcall(require, "better_escape") - return ok and m.waiting and icons.misc.EscapeST or "" - end + local function custom_theme() + vim.api.nvim_create_autocmd("ColorScheme", { + group = vim.api.nvim_create_augroup("LualineColorScheme", { clear = true }), + callback = function() + require("lualine").setup({ options = { theme = custom_theme() } }) + end, + }) - local _cache = { context = "", bufnr = -1 } - local function lspsaga_symbols() - local exclude = { - ["terminal"] = true, - ["toggleterm"] = true, - ["prompt"] = true, - ["NvimTree"] = true, - ["help"] = true, + colors = require("modules.utils").get_palette() + local universal_bg = require("core.settings").transparent_background and "NONE" or colors.mantle + return { + normal = { + a = { fg = colors.lavender, bg = colors.surface0, gui = "bold" }, + b = { fg = colors.text, bg = universal_bg }, + c = { fg = colors.text, bg = universal_bg }, + }, + command = { + a = { fg = colors.peach, bg = colors.surface0, gui = "bold" }, + }, + insert = { + a = { fg = colors.green, bg = colors.surface0, gui = "bold" }, + }, + visual = { + a = { fg = colors.flamingo, bg = colors.surface0, gui = "bold" }, + }, + terminal = { + a = { fg = colors.teal, bg = colors.surface0, gui = "bold" }, + }, + replace = { + a = { fg = colors.red, bg = colors.surface0, gui = "bold" }, + }, + inactive = { + a = { fg = colors.subtext0, bg = universal_bg, gui = "bold" }, + b = { fg = colors.subtext0, bg = universal_bg }, + c = { fg = colors.subtext0, bg = universal_bg }, + }, } - if vim.api.nvim_win_get_config(0).zindex or exclude[vim.bo.filetype] then - return "" -- Excluded filetypes - else - local currbuf = vim.api.nvim_get_current_buf() - local ok, lspsaga = pcall(require, "lspsaga.symbolwinbar") - if ok and lspsaga:get_winbar() ~= nil then - _cache.context = lspsaga:get_winbar() - _cache.bufnr = currbuf - elseif _cache.bufnr ~= currbuf then - _cache.context = "" -- Reset [invalid] cache (usually from another buffer) - end - - return _cache.context - end - end - - local function diff_source() - local gitsigns = vim.b.gitsigns_status_dict - if gitsigns then - return { - added = gitsigns.added, - modified = gitsigns.changed, - removed = gitsigns.removed, - } - end - end - - local function get_cwd() - local cwd = vim.fn.getcwd() - local is_windows = require("core.global").is_windows - if not is_windows then - local home = require("core.global").home - if cwd:find(home, 1, true) == 1 then - cwd = "~" .. cwd:sub(#home + 1) - end - end - return icons.ui.RootFolderOpened .. cwd end local mini_sections = { @@ -76,48 +64,239 @@ return function() filetypes = { "DiffviewFiles" }, } - local function python_venv() - local function env_cleanup(venv) - if string.find(venv, "/") then - local final_venv = venv - for w in venv:gmatch("([^/]+)") do - final_venv = w - end - venv = final_venv - end - return venv - end + local conditionals = { + has_enough_room = function() + return vim.o.columns > 100 + end, + has_comp_before = function() + return vim.bo.filetype ~= "" + end, + has_git = function() + local filepath = vim.fn.expand("%:p:h") + local gitdir = vim.fn.finddir(".git", filepath .. ";") + return gitdir and #gitdir > 0 and #gitdir < #filepath + end, + } - if vim.bo.filetype == "python" then - local venv = os.getenv("CONDA_DEFAULT_ENV") - if venv then - return string.format("%s", env_cleanup(venv)) + ---@class lualine_hlgrp + ---@field fg string + ---@field bg string + ---@field gui string? + local utils = { + force_centering = function() + return "%=" + end, + abbreviate_path = function(path) + local home = require("core.global").home + if path:find(home, 1, true) == 1 then + path = "~" .. path:sub(#home + 1) end - venv = os.getenv("VIRTUAL_ENV") - if venv then - return string.format("%s", env_cleanup(venv)) + return path + end, + ---Generate `color` for any component + ---@param fg string @Foreground hl group + ---@param gen_bg boolean @Generate guibg from hl group |StatusLine|? + ---@param special_nobg boolean @Disable guibg for transparent backgrounds? + ---@param bg string? @Background hl group + ---@param gui string? @GUI highlight arguments + ---@return fun():lualine_hlgrp + gen_hl = function(fg, gen_bg, special_nobg, bg, gui) + return function() + local guifg = colors[fg] + local guibg = gen_bg and require("modules.utils").hl_to_rgb("StatusLine", true, colors.mantle) + or colors[bg] + local nobg = special_nobg and require("core.settings").transparent_background + return { + fg = guifg and guifg or colors.none, + bg = (guibg and not nobg) and guibg or colors.none, + gui = gui and gui or nil, + } end + end, + } + + local function diff_source() + local gitsigns = vim.b.gitsigns_status_dict + if gitsigns then + return { + added = gitsigns.added, + modified = gitsigns.changed, + removed = gitsigns.removed, + } end - return "" end + local components = { + separator = { -- use as section separators + function() + return "│" + end, + padding = 0, + color = utils.gen_hl("surface1", true, true), + }, + + file_status = { + function() + local function is_new_file() + local filename = vim.fn.expand("%") + return filename ~= "" and vim.bo.buftype == "" and vim.fn.filereadable(filename) == 0 + end + + local symbols = {} + if vim.bo.modified then + table.insert(symbols, "[+]") + end + if vim.bo.modifiable == false then + table.insert(symbols, "[-]") + end + if vim.bo.readonly == true then + table.insert(symbols, "[RO]") + end + if is_new_file() then + table.insert(symbols, "[New]") + end + return #symbols > 0 and table.concat(symbols, "") or "" + end, + padding = { left = -1, right = 1 }, + cond = conditionals.has_comp_before, + }, + + lsp = { + function() + local buf_ft = vim.api.nvim_buf_get_option(0, "filetype") + local clients = vim.lsp.get_active_clients() + local lsp_lists = {} + local available_servers = {} + if next(clients) == nil then + return icons.misc.NoActiveLsp -- No server available + end + for _, client in ipairs(clients) do + local filetypes = client.config.filetypes + local client_name = client.name + if filetypes and vim.fn.index(filetypes, buf_ft) ~= -1 then + -- Avoid adding servers that already exists. + if not lsp_lists[client_name] then + lsp_lists[client_name] = true + table.insert(available_servers, client_name) + end + end + end + return next(available_servers) == nil and icons.misc.NoActiveLsp + or string.format("%s[%s]", icons.misc.LspAvailable, table.concat(available_servers, ", ")) + end, + color = utils.gen_hl("blue", true, true, nil, "bold"), + cond = conditionals.has_enough_room, + }, + + python_venv = { + function() + local function env_cleanup(venv) + if string.find(venv, "/") then + local final_venv = venv + for w in venv:gmatch("([^/]+)") do + final_venv = w + end + venv = final_venv + end + return venv + end + + if vim.api.nvim_buf_get_option(0, "filetype") == "python" then + local venv = os.getenv("CONDA_DEFAULT_ENV") + if venv then + return string.format("%s", env_cleanup(venv)) + end + venv = os.getenv("VIRTUAL_ENV") + if venv then + return string.format("%s", env_cleanup(venv)) + end + end + return "" + end, + color = utils.gen_hl("green", true, true), + cond = conditionals.has_enough_room, + }, + + tabwidth = { + function() + return icons.ui.Tab .. vim.api.nvim_buf_get_option(0, "shiftwidth") + end, + padding = 1, + }, + + cwd = { + function() + return icons.ui.FolderWithHeart .. utils.abbreviate_path(vim.fs.normalize(vim.fn.getcwd())) + end, + color = utils.gen_hl("subtext0", true, true, nil, "bold"), + }, + + file_location = { + function() + local cursorline = vim.fn.line(".") + local cursorcol = vim.fn.virtcol(".") + local filelines = vim.fn.line("$") + local position + if cursorline == 1 then + position = "Top" + elseif cursorline == filelines then + position = "Bot" + else + position = string.format("%2d%%%%", math.floor(cursorline / filelines * 100)) + end + return string.format("%s · %3d:%-2d", position, cursorline, cursorcol) + end, + }, + } + require("lualine").setup({ options = { icons_enabled = true, - theme = "catppuccin", - disabled_filetypes = {}, - component_separators = "|", - section_separators = { left = "", right = "" }, + theme = custom_theme(), + disabled_filetypes = { statusline = { "alpha" } }, + component_separators = "", + section_separators = { left = "", right = "" }, }, sections = { - lualine_a = { { "mode" } }, - lualine_b = { { "branch" }, { "diff", source = diff_source } }, - lualine_c = { lspsaga_symbols }, - lualine_x = { - { escape_status }, + lualine_a = { "mode" }, + lualine_b = { + { + "filetype", + colored = true, + icon_only = false, + icon = { align = "left" }, + }, + components.file_status, + vim.tbl_deep_extend("force", components.separator, { + cond = function() + return conditionals.has_git() and conditionals.has_comp_before() + end, + }), + }, + lualine_c = { + { + "branch", + icon = icons.git_nosep.Branch, + color = utils.gen_hl("subtext0", true, true, nil, "bold"), + }, + { + "diff", + symbols = { + added = icons.git.Add, + modified = icons.git.Mod_alt, + removed = icons.git.Remove, + }, + source = diff_source, + colored = false, + color = utils.gen_hl("subtext0", true, true), + padding = { right = 1 }, + }, + + { utils.force_centering }, { "diagnostics", sources = { "nvim_diagnostic" }, + sections = { "error", "warn", "info", "hint" }, symbols = { error = icons.diagnostics.Error, warn = icons.diagnostics.Warning, @@ -125,23 +304,32 @@ return function() hint = icons.diagnostics.Hint_alt, }, }, - { get_cwd }, + components.lsp, }, - lualine_y = { - { "filetype", colored = true, icon_only = true }, - { python_venv }, - { "encoding" }, + lualine_x = { + { + "encoding", + fmt = string.upper, + padding = { left = 1 }, + cond = conditionals.has_enough_room, + }, { "fileformat", - icons_enabled = true, symbols = { unix = "LF", dos = "CRLF", - mac = "CR", + mac = "CR", -- Legacy macOS }, + padding = { left = 1 }, }, + components.tabwidth, + }, + lualine_y = { + components.separator, + components.python_venv, + components.cwd, }, - lualine_z = { "progress", "location" }, + lualine_z = { components.file_location }, }, inactive_sections = { lualine_a = {}, @@ -162,10 +350,4 @@ return function() diffview, }, }) - - -- Properly set background color for lspsaga - local winbar_bg = require("modules.utils").hl_to_rgb("StatusLine", true, colors.mantle) - for _, hlGroup in pairs(require("lspsaga.lspkind").get_kind_group()) do - require("modules.utils").extend_hl(hlGroup, { bg = winbar_bg }) - end end diff --git a/lua/modules/plugins/completion.lua b/lua/modules/plugins/completion.lua index 241a2b7dc..b8371390b 100644 --- a/lua/modules/plugins/completion.lua +++ b/lua/modules/plugins/completion.lua @@ -5,15 +5,17 @@ completion["neovim/nvim-lspconfig"] = { event = { "BufReadPost", "BufAdd", "BufNewFile" }, config = require("completion.lsp"), dependencies = { - { "ray-x/lsp_signature.nvim" }, { "williamboman/mason.nvim" }, { "williamboman/mason-lspconfig.nvim" }, - { - "nvimdev/lspsaga.nvim", - config = require("completion.lspsaga"), - }, + { "ray-x/lsp_signature.nvim" }, }, } +completion["nvimdev/lspsaga.nvim"] = { + lazy = true, + event = "LspAttach", + config = require("completion.lspsaga"), + dependencies = { "nvim-tree/nvim-web-devicons" }, +} completion["jose-elias-alvarez/null-ls.nvim"] = { lazy = true, event = { "CursorHold", "CursorHoldI" }, diff --git a/lua/modules/utils/icons.lua b/lua/modules/utils/icons.lua index 365143e4f..1bbe7dfb2 100644 --- a/lua/modules/utils/icons.lua +++ b/lua/modules/utils/icons.lua @@ -94,6 +94,7 @@ local data = { Fire = "", Folder = "", FolderOpen = "", + FolderWithHeart = "󱃪", Gear = "", History = "󰄉", Incoming = "󰏷", @@ -125,6 +126,7 @@ local data = { Sort = "", Spell = "󰓆", Symlink = "", + Tab = "", Table = "", Telescope = "", }, @@ -147,12 +149,14 @@ local data = { EscapeST = "", Gavel = "", Glass = "󰂖", + NoActiveLsp = "󱚧", PyEnv = "󰌠", Squirrel = "", Tag = "", Tree = "", Watch = "", Lego = "", + LspAvailable = "󱜙", Vbar = "│", Add = "+", Added = "",