From 89cba7056edb1daed90aa5a0a532f53d5999ca38 Mon Sep 17 00:00:00 2001 From: Carlos Gutierrez Date: Mon, 12 Jan 2026 18:59:46 -0500 Subject: [PATCH] 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 --- .gitignore | 4 + lua/cargdev/core/dashboard_config.lua | 66 ++++ .../core/function/performance_monitor.lua | 112 +++++++ lua/cargdev/core/keymaps/lsp.lua | 18 +- lua/cargdev/core/options.lua | 54 +++ lua/cargdev/plugins/alpha.lua | 83 +---- lua/cargdev/plugins/avante.lua | 32 +- lua/cargdev/plugins/bufferline.lua | 314 +++++++++++++++++- lua/cargdev/plugins/codetyper.lua | 7 +- lua/cargdev/plugins/fzf-lua.lua | 39 +++ lua/cargdev/plugins/indent-blankline.lua | 70 +++- lua/cargdev/plugins/lsp/mason.lua | 16 +- lua/cargdev/plugins/lualine.lua | 172 ++++++---- lua/cargdev/plugins/noice.lua | 235 +++++++++++-- 14 files changed, 998 insertions(+), 224 deletions(-) create mode 100644 lua/cargdev/core/dashboard_config.lua create mode 100644 lua/cargdev/core/function/performance_monitor.lua create mode 100644 lua/cargdev/plugins/fzf-lua.lua diff --git a/.gitignore b/.gitignore index 5c19abf..03bd2d8 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,7 @@ session.vim # Local configuration overrides local.lua + +# Codetyper.nvim - AI coding partner files +*.coder.* +.coder/ diff --git a/lua/cargdev/core/dashboard_config.lua b/lua/cargdev/core/dashboard_config.lua new file mode 100644 index 0000000..b396187 --- /dev/null +++ b/lua/cargdev/core/dashboard_config.lua @@ -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("^:", "") .. "" + table.insert(buttons, dashboard.button(item.key, item.icon .. " " .. item.desc, cmd)) + end + return buttons +end + +return M diff --git a/lua/cargdev/core/function/performance_monitor.lua b/lua/cargdev/core/function/performance_monitor.lua new file mode 100644 index 0000000..560c337 --- /dev/null +++ b/lua/cargdev/core/function/performance_monitor.lua @@ -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 diff --git a/lua/cargdev/core/keymaps/lsp.lua b/lua/cargdev/core/keymaps/lsp.lua index 49ddaaf..d800276 100644 --- a/lua/cargdev/core/keymaps/lsp.lua +++ b/lua/cargdev/core/keymaps/lsp.lua @@ -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", "lua require('snacks.picker').lsp_definitions()", { desc = "Go to definition" }) -keymap.set("n", "gi", "lua require('snacks.picker').lsp_implementations()", { desc = "Go to implementation" }) -keymap.set("n", "gr", "lua require('snacks.picker').lsp_references()", { desc = "Show references" }) -keymap.set("n", "gt", "lua require('snacks.picker').lsp_type_definitions()", { desc = "Go to type definition" }) +keymap.set("n", "gd", "FzfLua lsp_definitions", { desc = "Go to definition" }) +keymap.set("n", "gi", "FzfLua lsp_implementations", { desc = "Go to implementation" }) +keymap.set("n", "gr", "FzfLua lsp_references", { desc = "Show references" }) +keymap.set("n", "gt", "FzfLua lsp_typedefs", { desc = "Go to type definition" }) -- Symbol search -keymap.set("n", "ds", "lua require('snacks.picker').lsp_document_symbols()", { desc = "Document symbols" }) -keymap.set("n", "ws", "lua require('snacks.picker').lsp_workspace_symbols()", { desc = "Workspace symbols" }) +keymap.set("n", "ds", "FzfLua lsp_document_symbols", { desc = "Document symbols" }) +keymap.set("n", "ws", "FzfLua lsp_workspace_symbols", { desc = "Workspace symbols" }) -- Code actions and documentation -keymap.set("n", "ca", "lua vim.lsp.buf.code_action()", { desc = "Code actions" }) +keymap.set("n", "ca", "FzfLua lsp_code_actions", { desc = "Code actions" }) keymap.set("n", "rn", "lua vim.lsp.buf.rename()", { desc = "Rename" }) keymap.set("n", "K", "lua vim.lsp.buf.hover()", { desc = "Hover documentation" }) -- Diagnostics -keymap.set("n", "D", "lua require('snacks.picker').diagnostics()", { desc = "Show diagnostics" }) +keymap.set("n", "D", "FzfLua diagnostics_workspace", { desc = "Show diagnostics" }) keymap.set("n", "dd", "lua vim.diagnostic.open_float()", { desc = "Line diagnostics" }) keymap.set("n", "[d", "lua vim.diagnostic.goto_prev()", { desc = "Previous diagnostic" }) keymap.set("n", "]d", "lua vim.diagnostic.goto_next()", { desc = "Next diagnostic" }) \ No newline at end of file diff --git a/lua/cargdev/core/options.lua b/lua/cargdev/core/options.lua index 4cba0f8..98fa91f 100644 --- a/lua/cargdev/core/options.lua +++ b/lua/cargdev/core/options.lua @@ -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 }) diff --git a/lua/cargdev/plugins/alpha.lua b/lua/cargdev/plugins/alpha.lua index 67d7e7c..c9076fd 100644 --- a/lua/cargdev/plugins/alpha.lua +++ b/lua/cargdev/plugins/alpha.lua @@ -1,56 +1,24 @@ return { "goolord/alpha-nvim", event = "VimEnter", - enabled = true, + enabled = false, -- Replaced by Snacks dashboard config = function() local alpha = require("alpha") local dashboard = require("alpha.themes.dashboard") + local config = require("cargdev.core.dashboard_config") - -- 🚀 Set header - dashboard.section.header.val = { - " ██████╗ █████╗ ██████╗ ██████╗ ██████╗ ███████╗██╗ ██╗ ", - " █╔════╝██╔══██╗██╔══██╗██╔════╝ ██╔══██╗██╔════╝██║ ██║ ", - " █║ ███████║██████╔╝██║ ███╗██║ ██║█████╗ ██║ ██║ ", - " █║ ██╔══██║██╔══██╗██║ ██║██║ ██║██╔══╝ ╚██╗ ██╔╝ ", - " ██████╗██║ ██║██║ ██║╚██████╔╝██████╔╝███████╗ ╚████╔╝ ", - " ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═══╝ ", - " ", - " ", - " ███╗ ██╗███████╗ ██████╗ ██╗ ██╗██╗███╗ ███╗ ", - " ████╗ ██║██╔════╝██╔═══██╗██║ ██║██║████╗ ████║ ", - " ██╔██╗ ██║█████╗ ██║ ██║██║ ██║██║██╔████╔██╗ ", - " ██║╚██╗██║██╔══╝ ██║ ██║╚██╗ ██╔╝██║██║╚██╔╝██║ ", - " ██║ ╚████║███████╗╚██████╔╝ ╚████╔╝ ██║██║ ╚═╝ ██║ ", - " ╚═╝ ╚═══╝╚══════╝ ╚═════╝ ╚═══╝ ╚═╝╚═╝ ╚═╝ ", - " ", - " ", - " 🚀 Welcome to CarGDev Neovim - Customize Your Flow! 🚀 ", - } + -- Set header from shared config + dashboard.section.header.val = config.header - -- 📂 Set menu with improved icons and performance tools - dashboard.section.buttons.val = { - dashboard.button("f", "🔎 Find File (Safe)", "Telescope find_files"), - dashboard.button("n", "📄 New File", "ene"), - dashboard.button("g", "📝 Find Text", "Telescope live_grep"), - dashboard.button("r", "📚 Recent Files", "Telescope oldfiles"), - dashboard.button("t", "🌳 File Tree", "NvimTreeToggle"), - dashboard.button("c", "⚙️ Config", "e ~/.config/nvim/init.lua"), - dashboard.button("L", "🦥 Lazy", "Lazy"), - dashboard.button("p", "📊 Performance", "lua require('cargdev.core.function.performance_monitor').check_performance()"), - dashboard.button("l", "🔧 LSP Health", "lua require('cargdev.core.function.performance_monitor').check_lsp_health()"), - dashboard.button("s", "🧩 Sudoku", "Sudoku"), - dashboard.button("e", "💻 LeetCode", "Leet"), - dashboard.button("m", "🔨 Mason", "Mason"), - dashboard.button("q", "🚪 Quit", "qa"), - } + -- Set menu from shared config + dashboard.section.buttons.val = config.get_alpha_buttons(dashboard) - -- 🎯 Function to center text within a width + -- Footer with fortune local function center_text(text, width) local padding = math.floor((width - #text) / 2) return padding > 0 and string.rep(" ", padding) .. text or text end - -- 📌 Function to wrap text at a specific width local function wrap_text(text, width) local wrapped_lines = {} for line in text:gmatch("[^\n]+") do @@ -64,48 +32,19 @@ return { return wrapped_lines end - -- 🖥 Set viewport width (adjust if necessary) local viewport_width = 50 - - -- 📝 Get a fortune quote and wrap it local handle = io.popen("fortune") - local quote = handle and handle:read("*a") or "💻 Code, Create, Conquer with CarGDev 🚀" - if handle then - handle:close() - end + local quote = handle and handle:read("*a") or "Code, Create, Conquer with CarGDev" + if handle then handle:close() end local wrapped_quote = wrap_text(quote:gsub("\n", " "), viewport_width) - -- 📝 Set the footer content with added spacing - dashboard.section.footer.val = { - "", - center_text("🔧 CarGDev - Innovating with Neovim! 🔧", viewport_width), - "", - } - - -- Add wrapped quote below separator + dashboard.section.footer.val = { "", center_text("CarGDev - Innovating with Neovim!", viewport_width), "" } for _, line in ipairs(wrapped_quote) do table.insert(dashboard.section.footer.val, line) end - -- Add branding line at the bottom - table.insert(dashboard.section.footer.val, "") - table.insert( - dashboard.section.footer.val, - center_text("🎯 Stay productive & code with passion! 🚀", viewport_width) - ) - table.insert(dashboard.section.footer.val, "") - - -- 🌈 Apply modern styling - dashboard.opts.opts = { - position = "center", - hl = "Statement", - spacing = 2, - } - - -- 🚀 Load dashboard config + dashboard.opts.opts = { position = "center", hl = "Statement", spacing = 2 } alpha.setup(dashboard.opts) - - -- 🔥 Disable folding on alpha buffer vim.cmd([[autocmd FileType alpha setlocal nofoldenable]]) end, } diff --git a/lua/cargdev/plugins/avante.lua b/lua/cargdev/plugins/avante.lua index 2c5141c..f100d03 100644 --- a/lua/cargdev/plugins/avante.lua +++ b/lua/cargdev/plugins/avante.lua @@ -54,21 +54,31 @@ return { "stevearc/dressing.nvim", -- Load after dressing to override it }, config = function() + local dashboard_config = require("cargdev.core.dashboard_config") require("snacks").setup({ -- Enable all snacks modules bigfile = { enabled = true }, - dashboard = { - enabled = false, -- Disabled: using alpha-nvim for CARGDEV branding + dashboard = { + enabled = true, + width = 60, + row = nil, + col = nil, + pane_gap = 4, + autokeys = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + preset = { + keys = dashboard_config.get_snacks_keys(), + header = dashboard_config.get_header_string(), + }, + sections = { + { section = "header" }, + { padding = 1 }, + { section = "keys", gap = 1, padding = 1 }, + { section = "startup" }, + }, }, explorer = { enabled = true }, - image = { + image = { enabled = true, - -- Auto-detect terminal (will try: kitty, wezterm, ghostty in order) - -- If none found, image rendering will be disabled with warnings - -- Note: LaTeX and Mermaid features require external tools: - -- - LaTeX: tectonic or pdflatex - -- - Mermaid: mmdc (Mermaid CLI) - -- These warnings are informational and won't prevent basic image rendering terminal = nil, -- nil = auto-detect }, input = { enabled = true }, @@ -81,9 +91,9 @@ return { statuscolumn = { enabled = true }, terminal = { enabled = true }, toggle = { enabled = true }, - words = { + words = { enabled = true, - lsp = { enabled = false }, -- Disable LSP to prevent crashes + lsp = { enabled = false }, hl = { enabled = true }, }, }) diff --git a/lua/cargdev/plugins/bufferline.lua b/lua/cargdev/plugins/bufferline.lua index dc083b4..d97a0bd 100644 --- a/lua/cargdev/plugins/bufferline.lua +++ b/lua/cargdev/plugins/bufferline.lua @@ -1,11 +1,313 @@ return { "akinsho/bufferline.nvim", dependencies = { "nvim-tree/nvim-web-devicons" }, - version = "*", - opts = { - options = { - mode = "tabs", - }, - }, + event = "VeryLazy", + config = function() + local bufferline = require("bufferline") + + bufferline.setup({ + options = { + mode = "buffers", + style_preset = bufferline.style_preset.minimal, + themable = true, + numbers = "none", + close_command = "bdelete! %d", + right_mouse_command = "bdelete! %d", + left_mouse_command = "buffer %d", + middle_mouse_command = nil, + indicator = { + icon = "▎", + style = "icon", + }, + buffer_close_icon = "󰅖", + modified_icon = "●", + close_icon = "", + left_trunc_marker = "", + right_trunc_marker = "", + max_name_length = 30, + max_prefix_length = 30, + truncate_names = true, + tab_size = 21, + diagnostics = "nvim_lsp", + diagnostics_update_in_insert = false, + diagnostics_indicator = function(count, level, _, _) + local icon = level:match("error") and " " or " " + return " " .. icon .. count + end, + color_icons = true, + show_buffer_icons = true, + show_buffer_close_icons = true, + show_close_icon = true, + show_tab_indicators = true, + show_duplicate_prefix = true, + persist_buffer_sort = true, + separator_style = "thin", + enforce_regular_tabs = false, + always_show_bufferline = true, + hover = { + enabled = true, + delay = 200, + reveal = { "close" }, + }, + offsets = { + { + filetype = "NvimTree", + text = " File Explorer", + text_align = "center", + separator = true, + highlight = "Directory", + }, + }, + }, + highlights = { + fill = { + bg = "#16161e", + }, + background = { + fg = "#565f89", + bg = "#16161e", + }, + tab = { + fg = "#565f89", + bg = "#16161e", + }, + tab_selected = { + fg = "#c0caf5", + bg = "#1a1b26", + }, + tab_separator = { + fg = "#16161e", + bg = "#16161e", + }, + tab_separator_selected = { + fg = "#1a1b26", + bg = "#1a1b26", + }, + buffer_visible = { + fg = "#565f89", + bg = "#16161e", + }, + buffer_selected = { + fg = "#c0caf5", + bg = "#1a1b26", + bold = true, + italic = false, + }, + numbers = { + fg = "#565f89", + bg = "#16161e", + }, + numbers_visible = { + fg = "#565f89", + bg = "#16161e", + }, + numbers_selected = { + fg = "#c0caf5", + bg = "#1a1b26", + bold = true, + italic = false, + }, + diagnostic = { + fg = "#565f89", + bg = "#16161e", + }, + diagnostic_visible = { + fg = "#565f89", + bg = "#16161e", + }, + diagnostic_selected = { + fg = "#c0caf5", + bg = "#1a1b26", + bold = true, + italic = false, + }, + hint = { + fg = "#1abc9c", + bg = "#16161e", + }, + hint_visible = { + fg = "#1abc9c", + bg = "#16161e", + }, + hint_selected = { + fg = "#1abc9c", + bg = "#1a1b26", + bold = true, + italic = false, + }, + hint_diagnostic = { + fg = "#1abc9c", + bg = "#16161e", + }, + hint_diagnostic_visible = { + fg = "#1abc9c", + bg = "#16161e", + }, + hint_diagnostic_selected = { + fg = "#1abc9c", + bg = "#1a1b26", + bold = true, + italic = false, + }, + info = { + fg = "#0db9d7", + bg = "#16161e", + }, + info_visible = { + fg = "#0db9d7", + bg = "#16161e", + }, + info_selected = { + fg = "#0db9d7", + bg = "#1a1b26", + bold = true, + italic = false, + }, + info_diagnostic = { + fg = "#0db9d7", + bg = "#16161e", + }, + info_diagnostic_visible = { + fg = "#0db9d7", + bg = "#16161e", + }, + info_diagnostic_selected = { + fg = "#0db9d7", + bg = "#1a1b26", + bold = true, + italic = false, + }, + warning = { + fg = "#e0af68", + bg = "#16161e", + }, + warning_visible = { + fg = "#e0af68", + bg = "#16161e", + }, + warning_selected = { + fg = "#e0af68", + bg = "#1a1b26", + bold = true, + italic = false, + }, + warning_diagnostic = { + fg = "#e0af68", + bg = "#16161e", + }, + warning_diagnostic_visible = { + fg = "#e0af68", + bg = "#16161e", + }, + warning_diagnostic_selected = { + fg = "#e0af68", + bg = "#1a1b26", + bold = true, + italic = false, + }, + error = { + fg = "#f7768e", + bg = "#16161e", + }, + error_visible = { + fg = "#f7768e", + bg = "#16161e", + }, + error_selected = { + fg = "#f7768e", + bg = "#1a1b26", + bold = true, + italic = false, + }, + error_diagnostic = { + fg = "#f7768e", + bg = "#16161e", + }, + error_diagnostic_visible = { + fg = "#f7768e", + bg = "#16161e", + }, + error_diagnostic_selected = { + fg = "#f7768e", + bg = "#1a1b26", + bold = true, + italic = false, + }, + modified = { + fg = "#e0af68", + bg = "#16161e", + }, + modified_visible = { + fg = "#e0af68", + bg = "#16161e", + }, + modified_selected = { + fg = "#e0af68", + bg = "#1a1b26", + }, + duplicate_selected = { + fg = "#c0caf5", + bg = "#1a1b26", + italic = true, + }, + duplicate_visible = { + fg = "#565f89", + bg = "#16161e", + italic = true, + }, + duplicate = { + fg = "#565f89", + bg = "#16161e", + italic = true, + }, + separator_selected = { + fg = "#16161e", + bg = "#1a1b26", + }, + separator_visible = { + fg = "#16161e", + bg = "#16161e", + }, + separator = { + fg = "#16161e", + bg = "#16161e", + }, + indicator_selected = { + fg = "#7aa2f7", + bg = "#1a1b26", + }, + indicator_visible = { + fg = "#16161e", + bg = "#16161e", + }, + pick_selected = { + fg = "#f7768e", + bg = "#1a1b26", + bold = true, + italic = false, + }, + pick_visible = { + fg = "#f7768e", + bg = "#16161e", + bold = true, + italic = false, + }, + pick = { + fg = "#f7768e", + bg = "#16161e", + bold = true, + italic = false, + }, + offset_separator = { + fg = "#16161e", + bg = "#16161e", + }, + trunc_marker = { + fg = "#565f89", + bg = "#16161e", + }, + }, + }) + end, } diff --git a/lua/cargdev/plugins/codetyper.lua b/lua/cargdev/plugins/codetyper.lua index 5663fcb..a29c77f 100644 --- a/lua/cargdev/plugins/codetyper.lua +++ b/lua/cargdev/plugins/codetyper.lua @@ -1,5 +1,7 @@ return { - "CarGDev/codetyper.nvim", + -- Codetyper.nvim - AI-powered coding partner + -- Local development version + dir = "/Volumes/Carlos_SSD/Documents/projects/nvim.plugins/codetyper.nvim", name = "codetyper.nvim", lazy = false, -- Load on startup to create .coder folder priority = 100, -- Load early @@ -44,7 +46,7 @@ return { provider = "ollama", ollama = { host = "http://localhost:11434", - model = "qwen3-coder:30b", + model = "deepseek-coder:6.7b", }, }, window = { @@ -59,6 +61,7 @@ return { }, auto_gitignore = true, auto_open_ask = false, -- Always open Ask panel on startup + agent_mode = false, }) end, } diff --git a/lua/cargdev/plugins/fzf-lua.lua b/lua/cargdev/plugins/fzf-lua.lua new file mode 100644 index 0000000..54b711c --- /dev/null +++ b/lua/cargdev/plugins/fzf-lua.lua @@ -0,0 +1,39 @@ +return { + "ibhagwan/fzf-lua", + dependencies = { "nvim-tree/nvim-web-devicons" }, + config = function() + local fzf = require("fzf-lua") + fzf.setup({ + "default", + winopts = { + height = 0.85, + width = 0.80, + row = 0.35, + col = 0.50, + border = "rounded", + preview = { + layout = "flex", + flip_columns = 120, + scrollbar = "float", + }, + }, + keymap = { + builtin = { + [""] = "preview-page-down", + [""] = "preview-page-up", + }, + fzf = { + ["ctrl-q"] = "select-all+accept", + }, + }, + lsp = { + async_or_timeout = 5000, + jump_to_single_result = true, + ignore_current_line = true, + }, + diagnostics = { + severity_limit = vim.diagnostic.severity.HINT, + }, + }) + end, +} diff --git a/lua/cargdev/plugins/indent-blankline.lua b/lua/cargdev/plugins/indent-blankline.lua index ddaa680..fee47ad 100644 --- a/lua/cargdev/plugins/indent-blankline.lua +++ b/lua/cargdev/plugins/indent-blankline.lua @@ -2,17 +2,61 @@ return { "lukas-reineke/indent-blankline.nvim", event = { "BufReadPre", "BufNewFile" }, main = "ibl", - opts = { - indent = { - char = "┊", - }, - exclude = { - filetypes = { "help", "alpha", "dashboard", "neo-tree", "Trouble", "lazy", "mason" }, - buftypes = { "terminal", "nofile", "quickfix", "prompt" }, - }, - scope = { - enabled = false - }, - }, -} + config = function() + local hooks = require("ibl.hooks") + -- Rainbow indent colors (subtle) + hooks.register(hooks.type.HIGHLIGHT_SETUP, function() + vim.api.nvim_set_hl(0, "IblIndent", { fg = "#292e42" }) + vim.api.nvim_set_hl(0, "IblScope", { fg = "#7aa2f7" }) + vim.api.nvim_set_hl(0, "RainbowRed", { fg = "#3b3052" }) + vim.api.nvim_set_hl(0, "RainbowYellow", { fg = "#3b3939" }) + vim.api.nvim_set_hl(0, "RainbowBlue", { fg = "#2a3a52" }) + vim.api.nvim_set_hl(0, "RainbowOrange", { fg = "#3b3339" }) + vim.api.nvim_set_hl(0, "RainbowGreen", { fg = "#2a3b39" }) + vim.api.nvim_set_hl(0, "RainbowViolet", { fg = "#3a2a52" }) + vim.api.nvim_set_hl(0, "RainbowCyan", { fg = "#2a3b4a" }) + end) + + require("ibl").setup({ + indent = { + char = "│", + tab_char = "│", + highlight = "IblIndent", + }, + scope = { + enabled = true, + show_start = false, + show_end = false, + highlight = "IblScope", + include = { + node_type = { + ["*"] = { "return_statement", "table_constructor" }, + lua = { "return_statement", "table_constructor", "function", "if_statement" }, + python = { "function_definition", "class_definition", "if_statement", "for_statement" }, + javascript = { "function_declaration", "arrow_function", "if_statement", "for_statement" }, + typescript = { "function_declaration", "arrow_function", "if_statement", "for_statement" }, + }, + }, + }, + exclude = { + filetypes = { + "help", + "alpha", + "dashboard", + "snacks_dashboard", + "neo-tree", + "NvimTree", + "Trouble", + "trouble", + "lazy", + "mason", + "notify", + "toggleterm", + "lazyterm", + }, + buftypes = { "terminal", "nofile", "quickfix", "prompt" }, + }, + }) + end, +} diff --git a/lua/cargdev/plugins/lsp/mason.lua b/lua/cargdev/plugins/lsp/mason.lua index d277385..30f896e 100644 --- a/lua/cargdev/plugins/lsp/mason.lua +++ b/lua/cargdev/plugins/lsp/mason.lua @@ -27,17 +27,19 @@ return { mason_lspconfig.setup({ -- list of servers for mason to install ensure_installed = { - "ts_ls", - "html", "cssls", - "tailwindcss", - "svelte", - "lua_ls", - "graphql", "emmet_ls", + "eslint", + "gopls", + "graphql", + "html", + "jdtls", + "lua_ls", "prismals", "pyright", - "jdtls", + "svelte", + "tailwindcss", + "ts_ls", }, }) diff --git a/lua/cargdev/plugins/lualine.lua b/lua/cargdev/plugins/lualine.lua index 14657f7..a499f04 100644 --- a/lua/cargdev/plugins/lualine.lua +++ b/lua/cargdev/plugins/lualine.lua @@ -3,114 +3,150 @@ return { dependencies = { "nvim-tree/nvim-web-devicons" }, config = function() local lualine = require("lualine") - local lazy_status = require("lazy.status") -- to configure lazy pending updates count + local lazy_status = require("lazy.status") + -- Rainbow colors similar to p10k-rainbow local colors = { - blue = "#65D1FF", - green = "#3EFFDC", - violet = "#FF61EF", - yellow = "#FFDA7B", - red = "#FF4A4A", - fg = "#c3ccdc", - bg = "#112638", - inactive_bg = "#2c3043", + blue = "#61afef", + cyan = "#56b6c2", + green = "#98c379", + magenta = "#c678dd", + orange = "#d19a66", + red = "#e06c75", + yellow = "#e5c07b", + fg = "#abb2bf", + bg = "#282c34", + bg_dark = "#21252b", + white = "#ffffff", + black = "#000000", } - local my_lualine_theme = { + -- P10k rainbow style theme with solid backgrounds + local theme = { normal = { - a = { bg = colors.blue, fg = colors.bg, gui = "bold" }, - b = { bg = colors.bg, fg = colors.fg }, - c = { bg = colors.bg, fg = colors.fg }, + a = { bg = colors.blue, fg = colors.black, gui = "bold" }, + b = { bg = colors.bg, fg = colors.blue }, + c = { bg = colors.bg_dark, fg = colors.fg }, + z = { bg = colors.blue, fg = colors.black, gui = "bold" }, }, insert = { - a = { bg = colors.green, fg = colors.bg, gui = "bold" }, - b = { bg = colors.bg, fg = colors.fg }, - c = { bg = colors.bg, fg = colors.fg }, + a = { bg = colors.green, fg = colors.black, gui = "bold" }, + b = { bg = colors.bg, fg = colors.green }, + c = { bg = colors.bg_dark, fg = colors.fg }, + z = { bg = colors.green, fg = colors.black, gui = "bold" }, }, visual = { - a = { bg = colors.violet, fg = colors.bg, gui = "bold" }, - b = { bg = colors.bg, fg = colors.fg }, - c = { bg = colors.bg, fg = colors.fg }, + a = { bg = colors.magenta, fg = colors.black, gui = "bold" }, + b = { bg = colors.bg, fg = colors.magenta }, + c = { bg = colors.bg_dark, fg = colors.fg }, + z = { bg = colors.magenta, fg = colors.black, gui = "bold" }, }, command = { - a = { bg = colors.yellow, fg = colors.bg, gui = "bold" }, - b = { bg = colors.bg, fg = colors.fg }, - c = { bg = colors.bg, fg = colors.fg }, + a = { bg = colors.yellow, fg = colors.black, gui = "bold" }, + b = { bg = colors.bg, fg = colors.yellow }, + c = { bg = colors.bg_dark, fg = colors.fg }, + z = { bg = colors.yellow, fg = colors.black, gui = "bold" }, }, replace = { - a = { bg = colors.red, fg = colors.bg, gui = "bold" }, - b = { bg = colors.bg, fg = colors.fg }, - c = { bg = colors.bg, fg = colors.fg }, + a = { bg = colors.red, fg = colors.black, gui = "bold" }, + b = { bg = colors.bg, fg = colors.red }, + c = { bg = colors.bg_dark, fg = colors.fg }, + z = { bg = colors.red, fg = colors.black, gui = "bold" }, }, inactive = { - a = { bg = colors.inactive_bg, fg = colors.semilightgray, gui = "bold" }, - b = { bg = colors.inactive_bg, fg = colors.semilightgray }, - c = { bg = colors.inactive_bg, fg = colors.semilightgray }, + a = { bg = colors.bg_dark, fg = colors.fg }, + b = { bg = colors.bg_dark, fg = colors.fg }, + c = { bg = colors.bg_dark, fg = colors.fg }, }, } - -- Custom word counter function - local function word_count() - -- Skip for very large files to avoid performance issues - local line_count = vim.api.nvim_buf_line_count(0) - if line_count > 10000 then + -- LSP client name + local function lsp_client() + local clients = vim.lsp.get_clients({ bufnr = 0 }) + if #clients == 0 then return "" end - - local words = 0 - - -- Get all lines at once for better performance - local all_lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) - - for _, line in ipairs(all_lines) do - if line and #line > 0 then - -- Count words (non-whitespace sequences) - for _ in line:gmatch("%S+") do - words = words + 1 - end - end + local names = {} + for _, client in ipairs(clients) do + table.insert(names, client.name) end - - -- Format: show only word count - return string.format("%d words", words) + return " " .. table.concat(names, ", ") end - -- configure lualine with modified theme lualine.setup({ options = { - theme = my_lualine_theme, + theme = theme, + globalstatus = true, + -- Powerline angled separators like p10k + component_separators = { left = "", right = "" }, + section_separators = { left = "", right = "" }, + disabled_filetypes = { + statusline = { "dashboard", "alpha", "snacks_dashboard" }, + }, }, sections = { - lualine_a = { "mode" }, - lualine_b = { "branch", "diff", "diagnostics" }, - lualine_c = { "filename" }, + lualine_a = { + { "mode", icon = "" }, + }, + lualine_b = { + { "branch", icon = "" }, + { + "diff", + symbols = { added = " ", modified = " ", removed = " " }, + colored = true, + diff_color = { + added = { fg = colors.green }, + modified = { fg = colors.yellow }, + removed = { fg = colors.red }, + }, + }, + }, + lualine_c = { + { + "diagnostics", + symbols = { error = " ", warn = " ", info = " ", hint = "󰌵 " }, + diagnostics_color = { + error = { fg = colors.red }, + warn = { fg = colors.yellow }, + info = { fg = colors.cyan }, + hint = { fg = colors.green }, + }, + }, + { "filetype", icon_only = true, separator = "", padding = { left = 1, right = 0 } }, + { "filename", path = 1, symbols = { modified = " ●", readonly = " ", unnamed = "󰜥 " } }, + }, lualine_x = { { lazy_status.updates, cond = lazy_status.has_updates, - color = { fg = "#ff9e64" }, + color = { fg = colors.orange, bg = colors.bg_dark }, }, - { "encoding" }, - { "fileformat" }, - { "filetype" }, + { lsp_client, color = { fg = colors.cyan, bg = colors.bg_dark } }, + }, + lualine_y = { + { "encoding", icon = "" }, + { "fileformat", icons_enabled = true }, + { "filetype", colored = true, icon_only = false }, }, - lualine_y = { "progress" }, lualine_z = { - { - word_count, - color = { fg = colors.fg }, - }, - { "location" }, + { "progress", icon = "󰦨" }, + { "location", icon = "" }, }, }, inactive_sections = { - lualine_a = { "filename" }, + lualine_a = {}, lualine_b = {}, - lualine_c = {}, - lualine_x = {}, + lualine_c = { { "filename", path = 1 } }, + lualine_x = { "location" }, lualine_y = {}, - lualine_z = { "location" }, + lualine_z = {}, }, + extensions = { "nvim-tree", "lazy", "fzf", "trouble", "quickfix" }, }) + + -- Ensure statusline has solid background + vim.opt.laststatus = 3 + vim.api.nvim_set_hl(0, "StatusLine", { bg = colors.bg_dark }) + vim.api.nvim_set_hl(0, "StatusLineNC", { bg = colors.bg_dark }) end, } diff --git a/lua/cargdev/plugins/noice.lua b/lua/cargdev/plugins/noice.lua index 5a86f9c..4dde799 100644 --- a/lua/cargdev/plugins/noice.lua +++ b/lua/cargdev/plugins/noice.lua @@ -6,71 +6,234 @@ return { "rcarriga/nvim-notify", }, config = function() + require("notify").setup({ + background_colour = "#1a1b26", + fps = 60, + icons = { + DEBUG = "", + ERROR = "", + INFO = "", + TRACE = "✎", + WARN = "", + }, + level = 2, + minimum_width = 50, + render = "wrapped-compact", + stages = "fade_in_slide_out", + timeout = 3000, + top_down = true, + }) + require("noice").setup({ cmdline = { enabled = true, view = "cmdline_popup", + opts = {}, format = { - cmdline = { icon = ">" }, - search_down = { icon = "🔍 " }, - search_up = { icon = "🔍 " }, - filter = { icon = "$" }, - lua = { icon = "" }, - help = { icon = "?" }, + cmdline = { pattern = "^:", icon = "", lang = "vim" }, + search_down = { kind = "search", pattern = "^/", icon = " ", lang = "regex" }, + search_up = { kind = "search", pattern = "^%?", icon = " ", lang = "regex" }, + filter = { pattern = "^:%s*!", icon = "$", lang = "bash" }, + lua = { pattern = { "^:%s*lua%s+", "^:%s*lua%s*=%s*", "^:%s*=%s*" }, icon = "", lang = "lua" }, + help = { pattern = "^:%s*he?l?p?%s+", icon = "󰋖" }, + input = { view = "cmdline_input", icon = "󰥻 " }, }, }, messages = { enabled = true, - view = "mini", -- Mini popup for messages - view_error = "mini", -- Ensure errors also use mini - view_warn = "mini", + view = "notify", + view_error = "notify", + view_warn = "notify", view_history = "messages", view_search = "virtualtext", }, popupmenu = { enabled = true, backend = "nui", + kind_icons = {}, + }, + redirect = { + view = "popup", + filter = { event = "msg_show" }, + }, + commands = { + history = { + view = "split", + opts = { enter = true, format = "details" }, + filter = { + any = { + { event = "notify" }, + { error = true }, + { warning = true }, + { event = "msg_show", kind = { "" } }, + { event = "lsp", kind = "message" }, + }, + }, + }, + last = { + view = "popup", + opts = { enter = true, format = "details" }, + filter = { + any = { + { event = "notify" }, + { error = true }, + { warning = true }, + { event = "msg_show", kind = { "" } }, + { event = "lsp", kind = "message" }, + }, + }, + filter_opts = { count = 1 }, + }, + errors = { + view = "popup", + opts = { enter = true, format = "details" }, + filter = { error = true }, + filter_opts = { reverse = true }, + }, + }, + notify = { + enabled = true, + view = "notify", }, lsp = { progress = { - enabled = false, + enabled = true, + format = "lsp_progress", + format_done = "lsp_progress_done", + throttle = 1000 / 30, + view = "mini", + }, + override = { + ["vim.lsp.util.convert_input_to_markdown_lines"] = true, + ["vim.lsp.util.stylize_markdown"] = true, + ["cmp.entry.get_documentation"] = true, + }, + hover = { + enabled = true, + silent = false, + view = nil, + opts = {}, + }, + signature = { + enabled = true, + auto_open = { + enabled = true, + trigger = true, + luasnip = true, + throttle = 50, + }, + view = nil, + opts = {}, }, message = { enabled = true, - view = "mini", -- Show LSP messages in mini popup + view = "notify", + opts = {}, + }, + documentation = { + view = "hover", + opts = { + lang = "markdown", + replace = true, + render = "plain", + format = { "{message}" }, + win_options = { concealcursor = "n", conceallevel = 3 }, + }, }, }, - views = { - mini = { - position = { - row = "100%", -- Place it at the bottom of the screen - col = "50%", -- Center it horizontally - }, - border = { - style = "rounded", - }, - win_options = { - winblend = 10, -- Slight transparency - }, - max_height = 2, -- Small window size - max_width = 60, + markdown = { + hover = { + ["|(%S-)|"] = vim.cmd.help, + ["%[.-%]%((%S-)%)"] = require("noice.util").open, }, - notify = { - position = { - row = "100%", -- Bottom of the screen - col = "50%", - }, - win_options = { - winblend = 10, - }, - max_height = 2, - max_width = 60, + highlights = { + ["|%S-|"] = "@text.reference", + ["@%S+"] = "@parameter", + ["^%s*(Parameters:)"] = "@text.title", + ["^%s*(Return:)"] = "@text.title", + ["^%s*(See also:)"] = "@text.title", + ["{%S-}"] = "@parameter", }, }, + health = { + checker = true, + }, + smart_move = { + enabled = true, + excluded_filetypes = { "cmp_menu", "cmp_docs", "notify" }, + }, presets = { bottom_search = false, command_palette = true, - long_message_to_split = false, + long_message_to_split = true, + inc_rename = false, + lsp_doc_border = true, + }, + throttle = 1000 / 30, + views = { + cmdline_popup = { + position = { + row = "50%", + col = "50%", + }, + size = { + width = 60, + height = "auto", + }, + border = { + style = "rounded", + padding = { 0, 1 }, + }, + win_options = { + winhighlight = { + Normal = "NormalFloat", + FloatBorder = "FloatBorder", + }, + }, + }, + popupmenu = { + relative = "editor", + position = { + row = "55%", + col = "50%", + }, + size = { + width = 60, + height = 10, + }, + border = { + style = "rounded", + padding = { 0, 1 }, + }, + win_options = { + winhighlight = { + Normal = "NormalFloat", + FloatBorder = "FloatBorder", + }, + }, + }, + mini = { + win_options = { + winblend = 0, + }, + }, + }, + routes = { + { + filter = { + event = "msg_show", + kind = "", + find = "written", + }, + opts = { skip = true }, + }, + { + filter = { + event = "msg_show", + kind = "search_count", + }, + opts = { skip = true }, + }, }, }) end,