feat(ui): modernize nvim with fzf-lua, snacks dashboard, and p10k-style statusline
- Replace Snacks picker with fzf-lua for LSP navigation (gd, gr, gi, gt) - Add fzf-lua plugin with LSP-optimized settings - Fix Mason inconsistencies (add eslint, gopls to ensure_installed) - Replace alpha-nvim with Snacks dashboard (shared config) - Create dashboard_config.lua for DRY dashboard settings - Modernize lualine with p10k-rainbow style and solid backgrounds - Enhance bufferline with LSP diagnostics and modern styling - Update noice with centered cmdline/search and modern icons - Add global rounded borders for floating windows - Improve indent-blankline with scope highlighting - Add return-to-dashboard on last buffer close - Create performance_monitor module Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
66
lua/cargdev/core/dashboard_config.lua
Normal file
66
lua/cargdev/core/dashboard_config.lua
Normal file
@@ -0,0 +1,66 @@
|
||||
-- Shared dashboard configuration for alpha-nvim and snacks.dashboard
|
||||
local M = {}
|
||||
|
||||
M.header = {
|
||||
" ██████╗ █████╗ ██████╗ ██████╗ ██████╗ ███████╗██╗ ██╗ ",
|
||||
" █╔════╝██╔══██╗██╔══██╗██╔════╝ ██╔══██╗██╔════╝██║ ██║ ",
|
||||
" █║ ███████║██████╔╝██║ ███╗██║ ██║█████╗ ██║ ██║ ",
|
||||
" █║ ██╔══██║██╔══██╗██║ ██║██║ ██║██╔══╝ ╚██╗ ██╔╝ ",
|
||||
" ██████╗██║ ██║██║ ██║╚██████╔╝██████╔╝███████╗ ╚████╔╝ ",
|
||||
" ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═══╝ ",
|
||||
" ",
|
||||
" ███╗ ██╗███████╗ ██████╗ ██╗ ██╗██╗███╗ ███╗ ",
|
||||
" ████╗ ██║██╔════╝██╔═══██╗██║ ██║██║████╗ ████║ ",
|
||||
" ██╔██╗ ██║█████╗ ██║ ██║██║ ██║██║██╔████╔██║ ",
|
||||
" ██║╚██╗██║██╔══╝ ██║ ██║╚██╗ ██╔╝██║██║╚██╔╝██║ ",
|
||||
" ██║ ╚████║███████╗╚██████╔╝ ╚████╔╝ ██║██║ ╚═╝ ██║ ",
|
||||
" ╚═╝ ╚═══╝╚══════╝ ╚═════╝ ╚═══╝ ╚═╝╚═╝ ╚═╝ ",
|
||||
}
|
||||
|
||||
-- Menu items (single column)
|
||||
M.menu_items = {
|
||||
{ key = "f", icon = " ", desc = "Find File", action = ":FzfLua files" },
|
||||
{ key = "n", icon = " ", desc = "New File", action = ":ene | startinsert" },
|
||||
{ key = "g", icon = " ", desc = "Find Text", action = ":FzfLua live_grep" },
|
||||
{ key = "r", icon = " ", desc = "Recent Files", action = ":FzfLua oldfiles" },
|
||||
{ key = "t", icon = " ", desc = "File Tree", action = ":NvimTreeToggle" },
|
||||
{ key = "L", icon = " ", desc = "Lazy", action = ":Lazy" },
|
||||
{ key = "m", icon = " ", desc = "Mason", action = ":Mason" },
|
||||
{ key = "q", icon = " ", desc = "Quit", action = ":qa" },
|
||||
}
|
||||
|
||||
-- Get header as string (for snacks)
|
||||
function M.get_header_string()
|
||||
return table.concat(M.header, "\n")
|
||||
end
|
||||
|
||||
-- Helper to convert menu items to snacks format
|
||||
local function to_snacks_keys(items)
|
||||
local keys = {}
|
||||
for _, item in ipairs(items) do
|
||||
table.insert(keys, {
|
||||
icon = item.icon,
|
||||
key = item.key,
|
||||
desc = item.desc,
|
||||
action = item.action,
|
||||
})
|
||||
end
|
||||
return keys
|
||||
end
|
||||
|
||||
-- Get snacks dashboard keys format
|
||||
function M.get_snacks_keys()
|
||||
return to_snacks_keys(M.menu_items)
|
||||
end
|
||||
|
||||
-- Get alpha buttons (requires alpha dashboard module)
|
||||
function M.get_alpha_buttons(dashboard)
|
||||
local buttons = {}
|
||||
for _, item in ipairs(M.menu_items) do
|
||||
local cmd = item.action:gsub("^:", "<cmd>") .. "<CR>"
|
||||
table.insert(buttons, dashboard.button(item.key, item.icon .. " " .. item.desc, cmd))
|
||||
end
|
||||
return buttons
|
||||
end
|
||||
|
||||
return M
|
||||
112
lua/cargdev/core/function/performance_monitor.lua
Normal file
112
lua/cargdev/core/function/performance_monitor.lua
Normal file
@@ -0,0 +1,112 @@
|
||||
local M = {}
|
||||
|
||||
-- Check overall Neovim performance
|
||||
function M.check_performance()
|
||||
local stats = {}
|
||||
|
||||
-- Startup time
|
||||
stats.startup = vim.fn.reltimefloat(vim.fn.reltime(vim.g.start_time or vim.fn.reltime()))
|
||||
|
||||
-- Memory usage
|
||||
local mem = collectgarbage("count")
|
||||
stats.memory_kb = math.floor(mem)
|
||||
stats.memory_mb = string.format("%.2f", mem / 1024)
|
||||
|
||||
-- Buffer count
|
||||
stats.buffers = #vim.fn.getbufinfo({ buflisted = 1 })
|
||||
|
||||
-- Loaded plugins (lazy.nvim)
|
||||
local lazy_ok, lazy = pcall(require, "lazy")
|
||||
if lazy_ok then
|
||||
local lazy_stats = lazy.stats()
|
||||
stats.plugins_loaded = lazy_stats.loaded
|
||||
stats.plugins_total = lazy_stats.count
|
||||
stats.startup_ms = string.format("%.2f", lazy_stats.startuptime)
|
||||
end
|
||||
|
||||
-- Active LSP clients
|
||||
stats.lsp_clients = #vim.lsp.get_clients()
|
||||
|
||||
-- Display results
|
||||
local lines = {
|
||||
"Performance Stats",
|
||||
string.rep("-", 40),
|
||||
string.format("Memory Usage: %s MB (%d KB)", stats.memory_mb, stats.memory_kb),
|
||||
string.format("Open Buffers: %d", stats.buffers),
|
||||
string.format("Active LSP Clients: %d", stats.lsp_clients),
|
||||
}
|
||||
|
||||
if stats.plugins_loaded then
|
||||
table.insert(lines, string.format("Plugins: %d/%d loaded", stats.plugins_loaded, stats.plugins_total))
|
||||
table.insert(lines, string.format("Startup Time: %s ms", stats.startup_ms))
|
||||
end
|
||||
|
||||
vim.notify(table.concat(lines, "\n"), vim.log.levels.INFO, { title = "Performance" })
|
||||
end
|
||||
|
||||
-- Check LSP health for current buffer
|
||||
function M.check_lsp_health()
|
||||
local clients = vim.lsp.get_clients({ bufnr = 0 })
|
||||
|
||||
if #clients == 0 then
|
||||
vim.notify("No LSP clients attached to this buffer", vim.log.levels.WARN, { title = "LSP Health" })
|
||||
return
|
||||
end
|
||||
|
||||
local lines = {
|
||||
"LSP Health Report",
|
||||
string.rep("-", 40),
|
||||
}
|
||||
|
||||
for _, client in ipairs(clients) do
|
||||
table.insert(lines, "")
|
||||
table.insert(lines, string.format("Client: %s (id: %d)", client.name, client.id))
|
||||
table.insert(lines, string.format(" Root: %s", client.config.root_dir or "N/A"))
|
||||
|
||||
-- Check capabilities
|
||||
local caps = {}
|
||||
if client.server_capabilities.completionProvider then
|
||||
table.insert(caps, "completion")
|
||||
end
|
||||
if client.server_capabilities.hoverProvider then
|
||||
table.insert(caps, "hover")
|
||||
end
|
||||
if client.server_capabilities.definitionProvider then
|
||||
table.insert(caps, "definition")
|
||||
end
|
||||
if client.server_capabilities.referencesProvider then
|
||||
table.insert(caps, "references")
|
||||
end
|
||||
if client.server_capabilities.documentFormattingProvider then
|
||||
table.insert(caps, "formatting")
|
||||
end
|
||||
if client.server_capabilities.codeActionProvider then
|
||||
table.insert(caps, "code_actions")
|
||||
end
|
||||
|
||||
table.insert(lines, string.format(" Capabilities: %s", table.concat(caps, ", ")))
|
||||
end
|
||||
|
||||
-- Diagnostics summary
|
||||
local diagnostics = vim.diagnostic.get(0)
|
||||
local counts = { errors = 0, warnings = 0, hints = 0, info = 0 }
|
||||
for _, d in ipairs(diagnostics) do
|
||||
if d.severity == vim.diagnostic.severity.ERROR then
|
||||
counts.errors = counts.errors + 1
|
||||
elseif d.severity == vim.diagnostic.severity.WARN then
|
||||
counts.warnings = counts.warnings + 1
|
||||
elseif d.severity == vim.diagnostic.severity.HINT then
|
||||
counts.hints = counts.hints + 1
|
||||
elseif d.severity == vim.diagnostic.severity.INFO then
|
||||
counts.info = counts.info + 1
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(lines, "")
|
||||
table.insert(lines, string.format("Diagnostics: %d errors, %d warnings, %d hints, %d info",
|
||||
counts.errors, counts.warnings, counts.hints, counts.info))
|
||||
|
||||
vim.notify(table.concat(lines, "\n"), vim.log.levels.INFO, { title = "LSP Health" })
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -2,26 +2,26 @@
|
||||
local keymap = vim.keymap
|
||||
|
||||
-- =============================================================================
|
||||
-- LSP NAVIGATION (FUNCTION NAVIGATION)
|
||||
-- LSP NAVIGATION (FUNCTION NAVIGATION) - Using fzf-lua
|
||||
-- =============================================================================
|
||||
|
||||
-- Primary LSP navigation
|
||||
keymap.set("n", "gd", "<cmd>lua require('snacks.picker').lsp_definitions()<cr>", { desc = "Go to definition" })
|
||||
keymap.set("n", "gi", "<cmd>lua require('snacks.picker').lsp_implementations()<cr>", { desc = "Go to implementation" })
|
||||
keymap.set("n", "gr", "<cmd>lua require('snacks.picker').lsp_references()<cr>", { desc = "Show references" })
|
||||
keymap.set("n", "gt", "<cmd>lua require('snacks.picker').lsp_type_definitions()<cr>", { desc = "Go to type definition" })
|
||||
keymap.set("n", "gd", "<cmd>FzfLua lsp_definitions<cr>", { desc = "Go to definition" })
|
||||
keymap.set("n", "gi", "<cmd>FzfLua lsp_implementations<cr>", { desc = "Go to implementation" })
|
||||
keymap.set("n", "gr", "<cmd>FzfLua lsp_references<cr>", { desc = "Show references" })
|
||||
keymap.set("n", "gt", "<cmd>FzfLua lsp_typedefs<cr>", { desc = "Go to type definition" })
|
||||
|
||||
-- Symbol search
|
||||
keymap.set("n", "<leader>ds", "<cmd>lua require('snacks.picker').lsp_document_symbols()<cr>", { desc = "Document symbols" })
|
||||
keymap.set("n", "<leader>ws", "<cmd>lua require('snacks.picker').lsp_workspace_symbols()<cr>", { desc = "Workspace symbols" })
|
||||
keymap.set("n", "<leader>ds", "<cmd>FzfLua lsp_document_symbols<cr>", { desc = "Document symbols" })
|
||||
keymap.set("n", "<leader>ws", "<cmd>FzfLua lsp_workspace_symbols<cr>", { desc = "Workspace symbols" })
|
||||
|
||||
-- Code actions and documentation
|
||||
keymap.set("n", "<leader>ca", "<cmd>lua vim.lsp.buf.code_action()<cr>", { desc = "Code actions" })
|
||||
keymap.set("n", "<leader>ca", "<cmd>FzfLua lsp_code_actions<cr>", { desc = "Code actions" })
|
||||
keymap.set("n", "<leader>rn", "<cmd>lua vim.lsp.buf.rename()<cr>", { desc = "Rename" })
|
||||
keymap.set("n", "K", "<cmd>lua vim.lsp.buf.hover()<cr>", { desc = "Hover documentation" })
|
||||
|
||||
-- Diagnostics
|
||||
keymap.set("n", "<leader>D", "<cmd>lua require('snacks.picker').diagnostics()<cr>", { desc = "Show diagnostics" })
|
||||
keymap.set("n", "<leader>D", "<cmd>FzfLua diagnostics_workspace<cr>", { desc = "Show diagnostics" })
|
||||
keymap.set("n", "<leader>dd", "<cmd>lua vim.diagnostic.open_float()<cr>", { desc = "Line diagnostics" })
|
||||
keymap.set("n", "[d", "<cmd>lua vim.diagnostic.goto_prev()<cr>", { desc = "Previous diagnostic" })
|
||||
keymap.set("n", "]d", "<cmd>lua vim.diagnostic.goto_next()<cr>", { desc = "Next diagnostic" })
|
||||
@@ -242,3 +242,57 @@ vim.api.nvim_create_autocmd("FileType", {
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- =============================================================================
|
||||
-- RETURN TO DASHBOARD ON LAST BUFFER CLOSE
|
||||
-- =============================================================================
|
||||
|
||||
-- When closing the last buffer, return to dashboard instead of quitting
|
||||
vim.api.nvim_create_autocmd("BufDelete", {
|
||||
callback = function()
|
||||
local bufs = vim.tbl_filter(function(b)
|
||||
return vim.api.nvim_buf_is_valid(b)
|
||||
and vim.bo[b].buflisted
|
||||
and vim.api.nvim_buf_get_name(b) ~= ""
|
||||
end, vim.api.nvim_list_bufs())
|
||||
|
||||
-- If this is the last listed buffer, open dashboard
|
||||
if #bufs <= 1 then
|
||||
vim.schedule(function()
|
||||
local ok, snacks = pcall(require, "snacks")
|
||||
if ok and snacks.dashboard then
|
||||
snacks.dashboard()
|
||||
end
|
||||
end)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- =============================================================================
|
||||
-- MODERN UI: GLOBAL ROUNDED BORDERS
|
||||
-- =============================================================================
|
||||
|
||||
-- Rounded border style for all floating windows
|
||||
local border = "rounded"
|
||||
|
||||
-- Override default floating window border
|
||||
vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { border = border })
|
||||
vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, { border = border })
|
||||
|
||||
-- Diagnostic floating window border
|
||||
vim.diagnostic.config({
|
||||
float = {
|
||||
border = border,
|
||||
source = "always",
|
||||
header = "",
|
||||
prefix = "",
|
||||
},
|
||||
})
|
||||
|
||||
-- Set global float border highlight
|
||||
vim.api.nvim_set_hl(0, "FloatBorder", { fg = "#7aa2f7", bg = "NONE" })
|
||||
vim.api.nvim_set_hl(0, "NormalFloat", { bg = "#1a1b26" })
|
||||
|
||||
-- Modern cursor line (subtle highlight)
|
||||
vim.api.nvim_set_hl(0, "CursorLine", { bg = "#292e42" })
|
||||
vim.api.nvim_set_hl(0, "CursorLineNr", { fg = "#7aa2f7", bold = true })
|
||||
|
||||
Reference in New Issue
Block a user