From a081bcffbeb0401930c2c3c43cf562c5f1d8f5f1 Mon Sep 17 00:00:00 2001 From: Steve Beaulac Date: Thu, 2 Apr 2026 13:48:26 -0400 Subject: [PATCH] chore(nvim): moving plugins around --- config/nvim/lua/plugins/ai.lua | 865 ++++++++++++++++++ config/nvim/lua/plugins/ft.lua | 1 - config/nvim/lua/plugins/ide.lua | 1363 +++++++++++------------------ config/nvim/lua/plugins/init.lua | 278 ------ config/nvim/lua/plugins/tools.lua | 37 +- config/nvim/lua/plugins/ui.lua | 16 +- 6 files changed, 1386 insertions(+), 1174 deletions(-) create mode 100644 config/nvim/lua/plugins/ai.lua diff --git a/config/nvim/lua/plugins/ai.lua b/config/nvim/lua/plugins/ai.lua new file mode 100644 index 0000000..9f67658 --- /dev/null +++ b/config/nvim/lua/plugins/ai.lua @@ -0,0 +1,865 @@ +return { + { + "Davidyz/VectorCode", + version = "*", + build = "uv tool upgrade vectorcode", -- This helps keeping the CLI up-to-date + -- build = "pipx upgrade vectorcode", -- If you used pipx to install the CLI + dependencies = { "nvim-lua/plenary.nvim" }, + }, + { + "olimorris/codecompanion.nvim", + version = "^18.0.0", + opts = {}, + dependencies = { + "nvim-lua/plenary.nvim", + "nvim-treesitter/nvim-treesitter", + "franco-ruggeri/codecompanion-spinner.nvim", + "ravitemer/codecompanion-history.nvim", + "cairijun/codecompanion-agentskills.nvim", + "ttgrules/cc-adapter-copilot-cli-acp", + }, + event = "VeryLazy", + keys = { + { "rct", "CodeCompanionChat Toggle", mode = {'n', 'v'}, { noremap = true, silent = true }, desc = "CC Toggle" }, + { "rca", "CodeCompanionActions", mode = { 'n', 'v' }, { noremap = true, silent = true }, desc = "CC Action" }, + { "rce", "CodeCompanion Explain", mode = { 'n' }, desc = "CC Explain" }, + { "rcf", "CodeCompanion Fix code", mode = { 'n' }, desc = "CC fix" }, + { "rcc", "CodeCompanionChat Add", mode = { 'v' }, { noremap = true, silent = true }, desc = "CC Add" }, + { 'rcr', 'CodeCompanion Code Review', mode = { 'v' }, desc = 'Code Review' }, + { 'rco', 'CodeCompanion Optimize Performance', mode = { 'v' }, desc = 'Optimize Code' }, + { 'rce', 'CodeCompanion Explain Code', mode = { 'v' }, desc = 'Explain Code' }, + { 'rcg', 'CodeCompanion Generate Tests', mode = { 'v' }, desc = 'Generate Tests' }, + { 'rcd', 'CodeCompanion Debug Analysis', mode = { 'v' }, desc = 'Debug Analysis' }, + }, + config = function() + local function get_abacus_key() + local handle = io.popen("pass show abacus.ai-api") + if not handle then return "" end + local result = handle:read("*a") + handle:close() + -- Remove trailing newline that 'pass' often adds + return result:gsub("%s+", "") + end + + local codecompanion = require("codecompanion") + codecompanion.setup({ + adapters = { + http = { + opts = { + show_presets = true, + show_model_choices = true, + }, + -- openai = function() + -- return require("codecompanion.adapters").extend("openai", { + -- env = { api_key = "cmd:pass show api.openai.com" } + -- }) + -- end, + openrouter = function() + return require("codecompanion.adapters").extend("openai_compatible", { + env = { + url = "https://openrouter.ai/api", + api_key = "OPENROUTER_API_KEY", + chat_url = "/v1/chat/completions", + }, + schema = { + model = { + default = "anthropic/claude-3.7-sonnet", + }, + }, + }) + end, + abacus = function() + return require("codecompanion.adapters").extend("openai_compatible", { + name = "abacus", + formatted_name = "Abacus.AI", + env = { + url = "https://routellm.abacus.ai/v1", + -- IMPORTANT: include /v1 in the base url + api_key = get_abacus_key(), + chat_url = "/chat/completions" + }, + headers = { + ["Content-Type"] = "application/json", + ["Authorization"] = "Bearer ${api_key}", + }, + schema = { + model = { + order = 1, + mapping = "parameters", + type = "enum", + desc = "The model to use for chat completions.", + default = "route-llm", + choices = { + -- Routing Model + ["route-llm"] = { opts = { desc = "Intelligent routing to best model" } }, + + -- OpenAI Models + ["gpt-5.2"] = { opts = { has_vision = true } }, + ["gpt-5.1"] = { opts = { has_vision = true } }, + ["gpt-5.1-chat-latest"] = { opts = { has_vision = true } }, + ["gpt-5"] = { opts = { has_vision = true } }, + ["gpt-5-mini"] = { opts = { has_vision = true } }, + ["gpt-5-nano"] = { opts = { has_vision = true } }, + ["gpt-4o"] = { opts = { has_vision = true } }, + ["gpt-4o-mini"] = { opts = { has_vision = true } }, + ["o4-mini"] = { opts = { can_reason = true } }, + ["o3"] = { opts = { can_reason = true } }, + ["o3-pro"] = { opts = { can_reason = true } }, + + -- Anthropic Models + ["claude-4-5-sonnet"] = { opts = { has_vision = true } }, + ["claude-4-5-haiku"] = { opts = { has_vision = true } }, + ["claude-4-5-opus"] = { opts = { has_vision = true } }, + ["claude-3-opus"] = { opts = { has_vision = true } }, + + -- Google Models + ["gemini-3-pro"] = { opts = { has_vision = true } }, + ["gemini-3-flash"] = { opts = { has_vision = true } }, + ["gemini-2.5-pro"] = { opts = { has_vision = true } }, + ["gemini-2.5-flash"] = { opts = { has_vision = true } }, + + -- xAI Models + ["grok-4-1-fast"] = {}, + ["grok-4"] = {}, + ["grok-code-fast-1"] = {}, + + -- Meta Models + ["llama-4-Maverick-17B"] = {}, + ["llama-3.1-405B"] = {}, + ["llama-3.1-70B"] = {}, + + -- DeepSeek Models + ["deepseek-v3.2"] = {}, + ["deepseek-v3.1-Terminus"] = {}, + ["deepseek-R1"] = { opts = { can_reason = true } }, + + -- Qwen Models + ["qwen-3-Max"] = {}, + ["qwen3-coder-480b-a35b-instruct"] = {}, + ["qwen-3-32B"] = {}, + ["qwq-32B"] = { opts = { can_reason = true } }, + }, + }, + temperature = { + order = 2, + mapping = "parameters", + type = "number", + optional = true, + default = 1.0, + desc = "Controls randomness of output (0-2).", + validate = function(n) + return n >= 0 and n <= 2, "Must be between 0 and 2" + end, + }, + max_tokens = { + order = 3, + mapping = "parameters", + type = "integer", + optional = true, + default = nil, + desc = "Maximum tokens to generate.", + validate = function(n) + return n > 0, "Must be greater than 0" + end, + }, + top_p = { + order = 4, + mapping = "parameters", + type = "number", + optional = true, + default = 1.0, + desc = "Nucleus sampling parameter (0-1).", + validate = function(n) + return n >= 0 and n <= 1, "Must be between 0 and 1" + end, + }, + }, + }) + end, + ollama = function() + return require("codecompanion.adapters").extend("ollama", { + env = { + url = "http://129.100.33.66:11434", + }, + schema = { + model = { + default = "qwen3.5", -- change to whatever you pulled + }, + }, + }) + end, + copilot = function() + return require("codecompanion.adapters").extend("copilot", { + schema = { + model = { + default = "gpt-5-mini", -- Consistent model choice + }, + max_tokens = { + default = 16284, + } + } + }) + end, + }, + acp = { + opts = { + show_presets = true, + }, + copilot_cli = function() + return require("codecompanion.adapters").extend("copilot_cli", {}) + end, + codex = function() + return require("codecompanion.adapters").extend("codex", { + commands = { + default = { "codex-acp" }, + }, + schema = { + model = { + default = "github-copilot/gpt-5.2-codex", + }, + }, + defaults = { + timeout = 20000, + auth_method = "chatgpt", -- "openai-api-key"|"codex-api-key"|"chatgpt" + }, + }) + end, + opencode = function() + return require("codecompanion.adapters").extend("codex", { + commands = { + default = { "opencode", "acp" }, + }, + schema = { + model = { + default = "github-copilot/gpt-5.2-codex", + }, + }, + defaults = { + timeout = 20000, + auth_method = "chatgpt", -- "openai-api-key"|"codex-api-key"|"chatgpt" + }, + }) + end, + }, + }, + rules = { + opts = { + chat = { + enabled = true, + autoload = { "default" } + }, + }, + }, + opts = { + send_code = true, + log_level = "WARN", -- Change to DEBUG for troubleshooting + language = "English", + -- NEW: Performance improvements + job_start_delay = 500, -- Reduced from default 1500ms + submit_delay = 1000, -- Reduced from default 2000ms + }, + extensions = { + spinner = {}, + -- ddgr_search = { + -- opts = { + -- require_approval_before = false, + -- }, + -- }, + agentskills = { + opts = { + { "~/Documents/ai-skills", recursive = true }, + }, + }, + -- vectorcode = { lazy = true }, + history = { + lazy = true, + enabled = true, + opts = { + keymap = "ghf", + save_chat_keymap = "ghs", + picker = "snacks", + dir_to_save = vim.env.HOME .. "/Documents/ai-history", + title_generation_opts = { + adapter = "copilot", + model = "gpt-5-mini", + }, + summary = { + create_summary_keymap = "ghc", + browse_summaries_keymap = "ghb", + }, + }, + }, + -- mcphub = { + -- callback = "mcphub.extensions.codecompanion", + -- opts = { + -- make_vars = true, + -- make_slash_commands = true, + -- show_result_in_chat = true, + -- }, + -- }, + }, + interactions = { + chat = { + variables = { + project = { + callback = function() + -- Get project files structure + local files = vim.fn.systemlist("fd . -type f") + return table.concat(files, "\n") + end, + description = "Share project structure" + } + }, + tools = { + opts = { + auto_submit_errors = true, -- Send any errors to the LLM automatically? + auto_submit_success = true, -- Send any successful output to the LLM automatically? + system_prompt = { + enabled = true, + replace_main_system_prompt = false, + }, + default_tools = { + "file_search", + "read_file", + "cmd_runner", + -- "ddgr_search", + }, + }, + ["fetch_enhanced"] = { + callback = function(url, options) + options = options or {} + local max_length = options.max_length or 200000 -- 200KB default + local timeout = options.timeout or 60 + + -- Use curl for better control + local cmd = string.format( + 'curl -L -s --max-time %d --user-agent "CodeCompanion-Neovim" "%s"', + timeout, + url + ) + + local handle = io.popen(cmd) + if not handle then + return nil, "Failed to execute curl" + end + + local result = handle:read("*a") + local success = handle:close() + + if not success then + return nil, "Curl command failed" + end + + -- Truncate if too long + if #result > max_length then + result = result:sub(1, max_length) .. "\n[... truncated at " .. max_length .. " characters ...]" + end + + return result + end, + opts = { + requires_approval = false, + } + }, + ["fetch_unlimited"] = { + description = "Fetch a data from the web", + callback = function(url, options) + options = options or {} + + -- Use a local proxy service or direct system calls + local temp_file = vim.fn.tempname() + local cmd = string.format( + 'wget --timeout=60 --tries=3 --output-document="%s" "%s" 2>/dev/null && cat "%s" && rm "%s"', + temp_file, url, temp_file, temp_file + ) + + local handle = io.popen(cmd) + if not handle then + return nil, "Failed to fetch URL" + end + + local result = handle:read("*a") + handle:close() + + -- Optional: Process and clean the content + -- Remove excessive whitespace, clean HTML if needed + -- result = result:gsub("%s+", " "):gsub("^\s+", ""):gsub("%s+$", "") + + return result + end, + opts = { + requires_approval = false, + description = "Fetch web content with unlimited size" + } + }, + ["fetch"] = { + description = "Fetch a webpage in a markdown format", + callback = function(url, options) + local cmd = string.format( + 'reader -o -i none %s 2>/dev/null', + url + ) + local handle = io.popen(cmd) + if not handle then + return nil, "Failed to fetch URL" + end + + local result = handle:read("*a") + handle:close() + + return result + end, + }, + -- ["mcp"] = { -- Name this tool whatever you like + -- -- Callback provides the necessary functions to CodeCompanion + -- callback = function() + -- return require("mcphub.extensions.codecompanion") + -- end, + -- opts = { + -- -- If true, CodeCompanion will ask for approval before executing the MCP tool call + -- requires_approval = true, + -- -- Optional: Pass parameters like temperature to the underlying LLM if the chat strategy supports it + -- temperature = 0.7 + -- } + -- }, + groups = { + ['plan'] = { + description = "Planning my project and codes with enhanced web access", + prompt = "Using all the ${tools} at your disposal including enhanced web fetching. Analyze the codes and use it to help me with my query. You have access to unlimited web content fetching.", + tools = { + "fetch", -- Backup unlimited fetch + "file_search", + "grep_search", + "list_code_usages", + "next_edit_suggestion", + "read_file", + "cmd_runner", + }, + opts = { + collapse_tools = true, + -- Override default fetch behavior for this group + tool_config = { + fetch_enhanced = { + max_length = 500000, -- 500KB for planning tasks + chunk_processing = true, + }, + }, + }, + }, + ['research'] = { + description = "Deep research with unlimited web access", + prompt = "You are a research assistant with unlimited web access. Using the ${tools} fetch and analyze large documents, research papers, and comprehensive web content.", + tools = { + "fetch", + "fetch_enhanced", + "file_search", + "read_file", + }, + opts = { + collapse_tools = false, + }, + }, + -- NEW: Add development group for coding tasks + ['dev'] = { + description = "Full-stack development with all necessary tools", + prompt = "You are an expert full-stack developer. Use ${tools} to understand, modify, and test code. Always gather context before making changes.", + tools = { + "file_search", + "grep_search", + "fetch", + "list_code_usages", + "read_file", + "insert_edit_into_file", + "cmd_runner", + "next_edit_suggestion", + }, + opts = { + collapse_tools = true, + }, + }, + }, + }, + slash_commands = { + ["buffer"] = { opts = { provider = "snacks" } }, -- snacks + ["file"] = { opts = { provider = "snacks" } }, -- snackes + ['git_files'] = { + description = 'List git files', + ---@param chat CodeCompanion.Chat + callback = function(chat) + local handle = io.popen 'git ls-files' + if handle ~= nil then + local result = handle:read '*a' + handle:close() + chat:add_reference({ content = result }, 'git', '') + return vim.notify('Git files added to the chat.') + else + return vim.notify('No git files available', vim.log.levels.INFO, { title = 'CodeCompanion' }) + end + end, + opts = { + contains_code = false, + }, + }, + -- NEW: Add helpful workspace command + ["workspace"] = { + description = "Add workspace context", + callback = function(chat) + local cwd = vim.fn.getcwd() + local workspace_info = string.format("Working directory: %s", cwd) + + -- Get project type + local files = vim.fn.glob(cwd .. "/*", false, true) + for _, file in ipairs(files) do + local basename = vim.fn.fnamemodify(file, ":t") + if basename == "package.json" then + workspace_info = workspace_info .. "\nProject type: Node.js/JavaScript" + break + elseif basename == "Cargo.toml" then + workspace_info = workspace_info .. "\nProject type: Rust" + break + elseif basename == "go.mod" then + workspace_info = workspace_info .. "\nProject type: Go" + break + end + end + + chat:add_reference({ content = workspace_info }, 'workspace', '') + return vim.notify('Workspace context added.') + end, + opts = { + contains_code = false, + }, + }, + }, + -- adapter = { name = "abacus", model = "route-llm" }, + -- adapter = { name = "opencode", model = "github-copilot/gpt-5.2-codex" }, + adapter = { name = "copilot", model = "gpt-5-mini" }, + }, + inline = { + -- adapter = { name = "abacus", model = "route-llm" }, + adapter = { name = "copilot", model = "gpt-5.1-codex-mini" }, + }, + cmd = { + adapter = { name = "copilot", model = "gpt-5-mini" }, + }, + background = { + adapter = { name = "copilot", model = "gpt-5-mini" }, + }, + }, + prompt_library = { + markdown = { + dirs = { + vim.fn.getcwd() .. "/.prompts", + "~/.agents/prompts", + }, + }, + ["Code Review"] = { + interaction = "chat", + description = "Review the selected code for improvements", + opts = { + mapping = "rpc", + modes = { "v" }, + adapter = { + name = "copilot", + model = "chatgpt-5.1-codex", + }, + }, + prompts = { + { + role = "system", + content = "You are an expert code reviewer. Analyze the code for: 1) Logic errors 2) Performance issues 3) Security vulnerabilities 4) Best practices 5) Code clarity and maintainability. Provide specific, actionable feedback.", + }, + { + role = "user", + content = function(context) + local code = require("codecompanion.helpers.actions").get_code(context.start_line, context.end_line) + return "Please review this code:\n\n```" .. context.filetype .. "\n" .. code .. "\n```" + end, + }, + }, + cc_keywords = { "review", "critique", "smell", "security", "vulnerability", "best practice", "maintainab" }, + cc_threshold = 2, + }, + ["Optimize Performance"] = { + interaction = "chat", + description = "Get performance optimization suggestions", + opts = { + mapping = "rpo", + modes = { "v" }, + adapter = { + name = "copilot", + model = "chatgpt-5.2-codex", + }, + }, + prompts = { + { + role = "system", + content = "You are a performance optimization expert. Focus on: 1) Time complexity improvements 2) Space efficiency 3) Algorithm optimization 4) Framework-specific optimizations 5) Caching strategies.", + }, + { + role = "user", + content = function(context) + local code = require("codecompanion.helpers.actions").get_code(context.start_line, context.end_line) + return "How can I optimize the performance of this code?\n\n```" .. context.filetype .. "\n" .. code .. "\n```" + end, + }, + }, + cc_keywords = { "optimize", "performance", "slow", "latency", "throughput", "memory", "alloc" }, + }, + ["Debug Analysis"] = { + interaction = "chat", + description = "Analyze and debug problematic code", + opts = { + mapping = "rpd", + modes = { "v" }, + + adapter = { + name = "copilot", + model = "chatgpt-5.2-codex", + }, + }, + prompts = { + { + role = "system", + content = [[You are a debugging expert. Analyze code for: + 1. Potential bugs and issues + 2. Logic errors + 3. Runtime errors + 4. Common pitfalls + 5. Debugging strategies. + 6. Provide specific solutions.]], + }, + { + role = "user", + content = function(context) + local code = require("codecompanion.helpers.actions").get_code(context.start_line, context.end_line) + return fmt( + [[Help me debug this code from buffer %d and identify potential issues: + + ```%s + %s + ```]], + context.bufnr, + context.filetype, + code + ) + end, + opts = { + contains_code = true, + } + }, + }, + cc_keyword = { "bug", "debug", "error", "exception", "crash", "stacktrace", "broken", "issue" }, + }, + ["Architecture Review"] = { + interaction = "chat", + description = "Review architectural patterns and design", + opts = { + mapping = "rpa", + modes = { "v" }, + + adapter = { + name = "copilot", + model = "chatgpt-5.2-codex", + }, + }, + prompts = { + { + role = "system", + content = "You are a software architect. Review code for: 1) Design patterns usage 2) SOLID principles 3) Separation of concerns 4) Scalability considerations 5) Maintainability. Suggest architectural improvements.", + }, + { + role = "user", + content = function(context) + local code = require("codecompanion.helpers.actions").get_code(context.start_line, context.end_line) + return fmt( + [[Please review the architecture and design of this code from buffer %d: + + ```%s + %s + ```]], + context.bufnr, + context.filetype, + code + ) + end, + opts = { + contains_code = true, + } + }, + }, + cc_keywords = { "architecture", "design", "pattern", "solid", "scalab", "maintainab", "refactor" }, + }, + }, + display = { + action_palette = { + provider = "snacks", + opts = { + show_default_actions = true, + show_default_prompt_library = true, + } + }, + chat = { + show_settings = false, + render_headers = false, + icons = { + chat_context = "📎️", + }, + fold_context = true, + -- NEW: Better chat window configuration + window = { + layout = "vertical", + width = 0.45, + height = 0.8, + border = "rounded", -- Better visual + }, + auto_scroll = false, + start_in_insert_mode = false, -- More convenient + } + } + }) + end + }, + { + "carlos-algms/agentic.nvim", + opts = { + -- Available by default: "claude-agent-acp" | "gemini-acp" | "codex-acp" | "opencode-acp" | "cursor-acp" | "auggie-acp" | "mistral-vibe-acp" + provider = "opencode-acp", -- setting the name here is all you need to get started + keymaps = { + -- Keybindings for ALL buffers in the widget (chat, prompt, code, files) + widget = { + close = "q", -- String for a single keybinding + change_mode = { + { + "", + mode = { "i", "n", "v" }, -- Specify modes for this keybinding + }, + }, + switch_provider = "ras", -- Switch ACP provider + switch_model = "ram", -- Switch model + }, + + -- Keybindings for the prompt buffer only + prompt = { + submit = { + "", -- Normal mode, just Enter + { + "", + mode = { "n", "v", "i" }, + }, + }, + + paste_image = { + { + "p", + mode = { "n" }, + }, + { + "", -- Same as Claude-code in insert mode + mode = { "i" }, + } + }, + }, + + -- Keybindings for diff preview navigation + diff_preview = { + next_hunk = "]c", + prev_hunk = "[c", + }, + }, + }, + -- these are just suggested keymaps; customize as desired + keys = { + { + "rat", + function() require("agentic").toggle() end, + mode = { "n", "v", "i" }, + desc = "Toggle Agentic Chat" + }, + { + "", + function() require("agentic").add_selection_or_file_to_context() end, + mode = { "n", "v" }, + desc = "Add file or selection to Agentic to Context" + }, + { + "ran", + function() require("agentic").new_session() end, + mode = { "n", "v", "i" }, + desc = "New Agentic Session" + }, + { + "r", -- ai Restore + function() + require("agentic").restore_session() + end, + desc = "Agentic Restore session", + silent = true, + mode = { "n", "v", "i" }, + }, + { + "rad", -- ai Diagnostics + function() + require("agentic").add_current_line_diagnostics() + end, + desc = "Add current line diagnostic to Agentic", + mode = { "n" }, + }, + { + "raD", -- ai all Diagnostics + function() + require("agentic").add_buffer_diagnostics() + end, + desc = "Add all buffer diagnostics to Agentic", + mode = { "n" }, + }, + }, + }, + { + "zbirenbaum/copilot.lua", + dependencies = { + "copilotlsp-nvim/copilot-lsp", + config = function() + vim.g.copilot_nes_debounce = 500 + end, + }, + cmd = "Copilot", + event = "InsertEnter", + config = function() + require('copilot').setup({ + nes = { + enabled = false, + keymap = { + accept_and_goto = "", + accept = false, + dismiss = "", + }, + }, + panel = { + enabled = false, + }, + }) + end, + }, + { + "PhantomYdn/fabric-ai.nvim", + cmd = { "Fabric" }, + opts = { + -- Default configuration (all optional) + fabric_path = "fabric-ai", -- Path to Fabric CLI + patterns_path = nil, -- Custom patterns dir (auto-detect if nil) + timeout = 300000, -- Command timeout in ms (5 minutes) + window = { + width = 0.8, -- 80% of editor width + height = 0.8, -- 80% of editor height + border = "rounded", + }, + }, + keys = { + -- fabric-ai.nvim doesn't have default keymappings + { "fa", ":'<,'>Fabric", mode = "v", desc = "Fabric AI" }, + { "fa", ":Fabric", mode = "n", desc = "Fabric AI" }, + { "fu", ":Fabric url", mode = "n", desc = "Fabric URL" }, + }, + }, +} diff --git a/config/nvim/lua/plugins/ft.lua b/config/nvim/lua/plugins/ft.lua index 5ea80ee..52b7e16 100644 --- a/config/nvim/lua/plugins/ft.lua +++ b/config/nvim/lua/plugins/ft.lua @@ -1,5 +1,4 @@ return { - { "mfussenegger/nvim-ansible", lazy = true, diff --git a/config/nvim/lua/plugins/ide.lua b/config/nvim/lua/plugins/ide.lua index 20bc11d..aae9579 100644 --- a/config/nvim/lua/plugins/ide.lua +++ b/config/nvim/lua/plugins/ide.lua @@ -1,867 +1,290 @@ return { { - "Davidyz/VectorCode", - version = "*", - build = "uv tool upgrade vectorcode", -- This helps keeping the CLI up-to-date - -- build = "pipx upgrade vectorcode", -- If you used pipx to install the CLI - dependencies = { "nvim-lua/plenary.nvim" }, - }, - { 'j-hui/fidget.nvim', lazy = true }, - { - "olimorris/codecompanion.nvim", - version = "^18.0.0", - opts = {}, - dependencies = { - "nvim-lua/plenary.nvim", - "nvim-treesitter/nvim-treesitter", - "franco-ruggeri/codecompanion-spinner.nvim", - "ravitemer/codecompanion-history.nvim", - "cairijun/codecompanion-agentskills.nvim", - "ttgrules/cc-adapter-copilot-cli-acp", - }, - event = "VeryLazy", - keys = { - { "rct", "CodeCompanionChat Toggle", mode = {'n', 'v'}, { noremap = true, silent = true }, desc = "CC Toggle" }, - { "rca", "CodeCompanionActions", mode = { 'n', 'v' }, { noremap = true, silent = true }, desc = "CC Action" }, - { "rce", "CodeCompanion Explain", mode = { 'n' }, desc = "CC Explain" }, - { "rcf", "CodeCompanion Fix code", mode = { 'n' }, desc = "CC fix" }, - { "rcc", "CodeCompanionChat Add", mode = { 'v' }, { noremap = true, silent = true }, desc = "CC Add" }, - { 'rcr', 'CodeCompanion Code Review', mode = { 'v' }, desc = 'Code Review' }, - { 'rco', 'CodeCompanion Optimize Performance', mode = { 'v' }, desc = 'Optimize Code' }, - { 'rce', 'CodeCompanion Explain Code', mode = { 'v' }, desc = 'Explain Code' }, - { 'rcg', 'CodeCompanion Generate Tests', mode = { 'v' }, desc = 'Generate Tests' }, - { 'rcd', 'CodeCompanion Debug Analysis', mode = { 'v' }, desc = 'Debug Analysis' }, - }, - config = function() - local function get_abacus_key() - local handle = io.popen("pass show abacus.ai-api") - if not handle then return "" end - local result = handle:read("*a") - handle:close() - -- Remove trailing newline that 'pass' often adds - return result:gsub("%s+", "") - end - - local codecompanion = require("codecompanion") - codecompanion.setup({ - adapters = { - http = { - opts = { - show_presets = true, - show_model_choices = true, - }, - -- openai = function() - -- return require("codecompanion.adapters").extend("openai", { - -- env = { api_key = "cmd:pass show api.openai.com" } - -- }) - -- end, - openrouter = function() - return require("codecompanion.adapters").extend("openai_compatible", { - env = { - url = "https://openrouter.ai/api", - api_key = "OPENROUTER_API_KEY", - chat_url = "/v1/chat/completions", - }, - schema = { - model = { - default = "anthropic/claude-3.7-sonnet", - }, - }, - }) - end, - abacus = function() - return require("codecompanion.adapters").extend("openai_compatible", { - name = "abacus", - formatted_name = "Abacus.AI", - env = { - url = "https://routellm.abacus.ai/v1", - -- IMPORTANT: include /v1 in the base url - api_key = get_abacus_key(), - chat_url = "/chat/completions" - }, - headers = { - ["Content-Type"] = "application/json", - ["Authorization"] = "Bearer ${api_key}", - }, - schema = { - model = { - order = 1, - mapping = "parameters", - type = "enum", - desc = "The model to use for chat completions.", - default = "route-llm", - choices = { - -- Routing Model - ["route-llm"] = { opts = { desc = "Intelligent routing to best model" } }, - - -- OpenAI Models - ["gpt-5.2"] = { opts = { has_vision = true } }, - ["gpt-5.1"] = { opts = { has_vision = true } }, - ["gpt-5.1-chat-latest"] = { opts = { has_vision = true } }, - ["gpt-5"] = { opts = { has_vision = true } }, - ["gpt-5-mini"] = { opts = { has_vision = true } }, - ["gpt-5-nano"] = { opts = { has_vision = true } }, - ["gpt-4o"] = { opts = { has_vision = true } }, - ["gpt-4o-mini"] = { opts = { has_vision = true } }, - ["o4-mini"] = { opts = { can_reason = true } }, - ["o3"] = { opts = { can_reason = true } }, - ["o3-pro"] = { opts = { can_reason = true } }, - - -- Anthropic Models - ["claude-4-5-sonnet"] = { opts = { has_vision = true } }, - ["claude-4-5-haiku"] = { opts = { has_vision = true } }, - ["claude-4-5-opus"] = { opts = { has_vision = true } }, - ["claude-3-opus"] = { opts = { has_vision = true } }, - - -- Google Models - ["gemini-3-pro"] = { opts = { has_vision = true } }, - ["gemini-3-flash"] = { opts = { has_vision = true } }, - ["gemini-2.5-pro"] = { opts = { has_vision = true } }, - ["gemini-2.5-flash"] = { opts = { has_vision = true } }, - - -- xAI Models - ["grok-4-1-fast"] = {}, - ["grok-4"] = {}, - ["grok-code-fast-1"] = {}, - - -- Meta Models - ["llama-4-Maverick-17B"] = {}, - ["llama-3.1-405B"] = {}, - ["llama-3.1-70B"] = {}, - - -- DeepSeek Models - ["deepseek-v3.2"] = {}, - ["deepseek-v3.1-Terminus"] = {}, - ["deepseek-R1"] = { opts = { can_reason = true } }, - - -- Qwen Models - ["qwen-3-Max"] = {}, - ["qwen3-coder-480b-a35b-instruct"] = {}, - ["qwen-3-32B"] = {}, - ["qwq-32B"] = { opts = { can_reason = true } }, - }, - }, - temperature = { - order = 2, - mapping = "parameters", - type = "number", - optional = true, - default = 1.0, - desc = "Controls randomness of output (0-2).", - validate = function(n) - return n >= 0 and n <= 2, "Must be between 0 and 2" - end, - }, - max_tokens = { - order = 3, - mapping = "parameters", - type = "integer", - optional = true, - default = nil, - desc = "Maximum tokens to generate.", - validate = function(n) - return n > 0, "Must be greater than 0" - end, - }, - top_p = { - order = 4, - mapping = "parameters", - type = "number", - optional = true, - default = 1.0, - desc = "Nucleus sampling parameter (0-1).", - validate = function(n) - return n >= 0 and n <= 1, "Must be between 0 and 1" - end, - }, - }, - }) - end, - ollama = function() - return require("codecompanion.adapters").extend("ollama", { - env = { - url = "http://129.100.33.66:11434", - }, - schema = { - model = { - default = "qwen3.5", -- change to whatever you pulled - }, - }, - }) - end, - copilot = function() - return require("codecompanion.adapters").extend("copilot", { - schema = { - model = { - default = "gpt-5-mini", -- Consistent model choice - }, - max_tokens = { - default = 16284, - } - } - }) - end, - }, - acp = { - opts = { - show_presets = true, - }, - copilot_cli = function() - return require("codecompanion.adapters").extend("copilot_cli", {}) - end, - codex = function() - return require("codecompanion.adapters").extend("codex", { - commands = { - default = { "codex-acp" }, - }, - schema = { - model = { - default = "github-copilot/gpt-5.2-codex", - }, - }, - defaults = { - timeout = 20000, - auth_method = "chatgpt", -- "openai-api-key"|"codex-api-key"|"chatgpt" - }, - }) - end, - opencode = function() - return require("codecompanion.adapters").extend("codex", { - commands = { - default = { "opencode", "acp" }, - }, - schema = { - model = { - default = "github-copilot/gpt-5.2-codex", - }, - }, - defaults = { - timeout = 20000, - auth_method = "chatgpt", -- "openai-api-key"|"codex-api-key"|"chatgpt" - }, - }) - end, - }, - }, - rules = { - opts = { - chat = { - enabled = true, - autoload = { "default" } - }, - }, - }, - opts = { - send_code = true, - log_level = "WARN", -- Change to DEBUG for troubleshooting - language = "English", - -- NEW: Performance improvements - job_start_delay = 500, -- Reduced from default 1500ms - submit_delay = 1000, -- Reduced from default 2000ms - }, - extensions = { - spinner = {}, - -- ddgr_search = { - -- opts = { - -- require_approval_before = false, - -- }, - -- }, - agentskills = { - opts = { - { "~/Documents/ai-skills", recursive = true }, - }, - }, - -- vectorcode = { lazy = true }, - history = { - lazy = true, - enabled = true, - opts = { - keymap = "ghf", - save_chat_keymap = "ghs", - picker = "snacks", - dir_to_save = vim.env.HOME .. "/Documents/ai-history", - title_generation_opts = { - adapter = "copilot", - model = "gpt-5-mini", - }, - summary = { - create_summary_keymap = "ghc", - browse_summaries_keymap = "ghb", - }, - }, - }, - -- mcphub = { - -- callback = "mcphub.extensions.codecompanion", - -- opts = { - -- make_vars = true, - -- make_slash_commands = true, - -- show_result_in_chat = true, - -- }, - -- }, - }, - interactions = { - chat = { - variables = { - project = { - callback = function() - -- Get project files structure - local files = vim.fn.systemlist("fd . -type f") - return table.concat(files, "\n") - end, - description = "Share project structure" - } - }, - tools = { - opts = { - auto_submit_errors = true, -- Send any errors to the LLM automatically? - auto_submit_success = true, -- Send any successful output to the LLM automatically? - system_prompt = { - enabled = true, - replace_main_system_prompt = false, - }, - default_tools = { - "file_search", - "read_file", - "cmd_runner", - -- "ddgr_search", - }, - }, - ["fetch_enhanced"] = { - callback = function(url, options) - options = options or {} - local max_length = options.max_length or 200000 -- 200KB default - local timeout = options.timeout or 60 - - -- Use curl for better control - local cmd = string.format( - 'curl -L -s --max-time %d --user-agent "CodeCompanion-Neovim" "%s"', - timeout, - url - ) - - local handle = io.popen(cmd) - if not handle then - return nil, "Failed to execute curl" - end - - local result = handle:read("*a") - local success = handle:close() - - if not success then - return nil, "Curl command failed" - end - - -- Truncate if too long - if #result > max_length then - result = result:sub(1, max_length) .. "\n[... truncated at " .. max_length .. " characters ...]" - end - - return result - end, - opts = { - requires_approval = false, - } - }, - ["fetch_unlimited"] = { - description = "Fetch a data from the web", - callback = function(url, options) - options = options or {} - - -- Use a local proxy service or direct system calls - local temp_file = vim.fn.tempname() - local cmd = string.format( - 'wget --timeout=60 --tries=3 --output-document="%s" "%s" 2>/dev/null && cat "%s" && rm "%s"', - temp_file, url, temp_file, temp_file - ) - - local handle = io.popen(cmd) - if not handle then - return nil, "Failed to fetch URL" - end - - local result = handle:read("*a") - handle:close() - - -- Optional: Process and clean the content - -- Remove excessive whitespace, clean HTML if needed - -- result = result:gsub("%s+", " "):gsub("^\s+", ""):gsub("%s+$", "") - - return result - end, - opts = { - requires_approval = false, - description = "Fetch web content with unlimited size" - } - }, - ["fetch"] = { - description = "Fetch a webpage in a markdown format", - callback = function(url, options) - local cmd = string.format( - 'reader -o -i none %s 2>/dev/null', - url - ) - local handle = io.popen(cmd) - if not handle then - return nil, "Failed to fetch URL" - end - - local result = handle:read("*a") - handle:close() - - return result - end, - }, - -- ["mcp"] = { -- Name this tool whatever you like - -- -- Callback provides the necessary functions to CodeCompanion - -- callback = function() - -- return require("mcphub.extensions.codecompanion") - -- end, - -- opts = { - -- -- If true, CodeCompanion will ask for approval before executing the MCP tool call - -- requires_approval = true, - -- -- Optional: Pass parameters like temperature to the underlying LLM if the chat strategy supports it - -- temperature = 0.7 - -- } - -- }, - groups = { - ['plan'] = { - description = "Planning my project and codes with enhanced web access", - prompt = "Using all the ${tools} at your disposal including enhanced web fetching. Analyze the codes and use it to help me with my query. You have access to unlimited web content fetching.", - tools = { - "fetch", -- Backup unlimited fetch - "file_search", - "grep_search", - "list_code_usages", - "next_edit_suggestion", - "read_file", - "cmd_runner", - }, - opts = { - collapse_tools = true, - -- Override default fetch behavior for this group - tool_config = { - fetch_enhanced = { - max_length = 500000, -- 500KB for planning tasks - chunk_processing = true, - }, - }, - }, - }, - ['research'] = { - description = "Deep research with unlimited web access", - prompt = "You are a research assistant with unlimited web access. Using the ${tools} fetch and analyze large documents, research papers, and comprehensive web content.", - tools = { - "fetch", - "fetch_enhanced", - "file_search", - "read_file", - }, - opts = { - collapse_tools = false, - }, - }, - -- NEW: Add development group for coding tasks - ['dev'] = { - description = "Full-stack development with all necessary tools", - prompt = "You are an expert full-stack developer. Use ${tools} to understand, modify, and test code. Always gather context before making changes.", - tools = { - "file_search", - "grep_search", - "fetch", - "list_code_usages", - "read_file", - "insert_edit_into_file", - "cmd_runner", - "next_edit_suggestion", - }, - opts = { - collapse_tools = true, - }, - }, - }, - }, - slash_commands = { - ["buffer"] = { opts = { provider = "snacks" } }, -- snacks - ["file"] = { opts = { provider = "snacks" } }, -- snackes - ['git_files'] = { - description = 'List git files', - ---@param chat CodeCompanion.Chat - callback = function(chat) - local handle = io.popen 'git ls-files' - if handle ~= nil then - local result = handle:read '*a' - handle:close() - chat:add_reference({ content = result }, 'git', '') - return vim.notify('Git files added to the chat.') - else - return vim.notify('No git files available', vim.log.levels.INFO, { title = 'CodeCompanion' }) - end - end, - opts = { - contains_code = false, - }, - }, - -- NEW: Add helpful workspace command - ["workspace"] = { - description = "Add workspace context", - callback = function(chat) - local cwd = vim.fn.getcwd() - local workspace_info = string.format("Working directory: %s", cwd) - - -- Get project type - local files = vim.fn.glob(cwd .. "/*", false, true) - for _, file in ipairs(files) do - local basename = vim.fn.fnamemodify(file, ":t") - if basename == "package.json" then - workspace_info = workspace_info .. "\nProject type: Node.js/JavaScript" - break - elseif basename == "Cargo.toml" then - workspace_info = workspace_info .. "\nProject type: Rust" - break - elseif basename == "go.mod" then - workspace_info = workspace_info .. "\nProject type: Go" - break - end - end - - chat:add_reference({ content = workspace_info }, 'workspace', '') - return vim.notify('Workspace context added.') - end, - opts = { - contains_code = false, - }, - }, - }, - -- adapter = { name = "abacus", model = "route-llm" }, - -- adapter = { name = "opencode", model = "github-copilot/gpt-5.2-codex" }, - adapter = { name = "copilot", model = "gpt-5-mini" }, - }, - inline = { - -- adapter = { name = "abacus", model = "route-llm" }, - adapter = { name = "copilot", model = "gpt-5.1-codex-mini" }, - }, - cmd = { - adapter = { name = "copilot", model = "gpt-5-mini" }, - }, - background = { - adapter = { name = "copilot", model = "gpt-5-mini" }, - }, - }, - prompt_library = { - markdown = { - dirs = { - vim.fn.getcwd() .. "/.prompts", - "~/.agents/prompts", - }, - }, - ["Code Review"] = { - interaction = "chat", - description = "Review the selected code for improvements", - opts = { - mapping = "rpc", - modes = { "v" }, - adapter = { - name = "copilot", - model = "chatgpt-5.1-codex", - }, - }, - prompts = { - { - role = "system", - content = "You are an expert code reviewer. Analyze the code for: 1) Logic errors 2) Performance issues 3) Security vulnerabilities 4) Best practices 5) Code clarity and maintainability. Provide specific, actionable feedback.", - }, - { - role = "user", - content = function(context) - local code = require("codecompanion.helpers.actions").get_code(context.start_line, context.end_line) - return "Please review this code:\n\n```" .. context.filetype .. "\n" .. code .. "\n```" - end, - }, - }, - cc_keywords = { "review", "critique", "smell", "security", "vulnerability", "best practice", "maintainab" }, - cc_threshold = 2, - }, - ["Optimize Performance"] = { - interaction = "chat", - description = "Get performance optimization suggestions", - opts = { - mapping = "rpo", - modes = { "v" }, - adapter = { - name = "copilot", - model = "chatgpt-5.2-codex", - }, - }, - prompts = { - { - role = "system", - content = "You are a performance optimization expert. Focus on: 1) Time complexity improvements 2) Space efficiency 3) Algorithm optimization 4) Framework-specific optimizations 5) Caching strategies.", - }, - { - role = "user", - content = function(context) - local code = require("codecompanion.helpers.actions").get_code(context.start_line, context.end_line) - return "How can I optimize the performance of this code?\n\n```" .. context.filetype .. "\n" .. code .. "\n```" - end, - }, - }, - cc_keywords = { "optimize", "performance", "slow", "latency", "throughput", "memory", "alloc" }, - }, - ["Debug Analysis"] = { - interaction = "chat", - description = "Analyze and debug problematic code", - opts = { - mapping = "rpd", - modes = { "v" }, - - adapter = { - name = "copilot", - model = "chatgpt-5.2-codex", - }, - }, - prompts = { - { - role = "system", - content = [[You are a debugging expert. Analyze code for: - 1. Potential bugs and issues - 2. Logic errors - 3. Runtime errors - 4. Common pitfalls - 5. Debugging strategies. - 6. Provide specific solutions.]], - }, - { - role = "user", - content = function(context) - local code = require("codecompanion.helpers.actions").get_code(context.start_line, context.end_line) - return fmt( - [[Help me debug this code from buffer %d and identify potential issues: - - ```%s - %s - ```]], - context.bufnr, - context.filetype, - code - ) - end, - opts = { - contains_code = true, - } - }, - }, - cc_keyword = { "bug", "debug", "error", "exception", "crash", "stacktrace", "broken", "issue" }, - }, - ["Architecture Review"] = { - interaction = "chat", - description = "Review architectural patterns and design", - opts = { - mapping = "rpa", - modes = { "v" }, - - adapter = { - name = "copilot", - model = "chatgpt-5.2-codex", - }, - }, - prompts = { - { - role = "system", - content = "You are a software architect. Review code for: 1) Design patterns usage 2) SOLID principles 3) Separation of concerns 4) Scalability considerations 5) Maintainability. Suggest architectural improvements.", - }, - { - role = "user", - content = function(context) - local code = require("codecompanion.helpers.actions").get_code(context.start_line, context.end_line) - return fmt( - [[Please review the architecture and design of this code from buffer %d: - - ```%s - %s - ```]], - context.bufnr, - context.filetype, - code - ) - end, - opts = { - contains_code = true, - } - }, - }, - cc_keywords = { "architecture", "design", "pattern", "solid", "scalab", "maintainab", "refactor" }, - }, - }, - display = { - action_palette = { - provider = "snacks", - opts = { - show_default_actions = true, - show_default_prompt_library = true, - } - }, - chat = { - show_settings = false, - render_headers = false, - icons = { - chat_context = "📎️", - }, - fold_context = true, - -- NEW: Better chat window configuration - window = { - layout = "vertical", - width = 0.45, - height = 0.8, - border = "rounded", -- Better visual - }, - auto_scroll = false, - start_in_insert_mode = false, -- More convenient - } - } - }) - end - }, - { - "carlos-algms/agentic.nvim", + "folke/snacks.nvim", + priority = 1000, + lazy = false, + ---@type snacks.Config opts = { - -- Available by default: "claude-agent-acp" | "gemini-acp" | "codex-acp" | "opencode-acp" | "cursor-acp" | "auggie-acp" | "mistral-vibe-acp" - provider = "opencode-acp", -- setting the name here is all you need to get started - keymaps = { - -- Keybindings for ALL buffers in the widget (chat, prompt, code, files) - widget = { - close = "q", -- String for a single keybinding - change_mode = { - { - "", - mode = { "i", "n", "v" }, -- Specify modes for this keybinding - }, - }, - switch_provider = "ras", -- Switch ACP provider - switch_model = "ram", -- Switch model + animate = { + enabled = false, + duration = { step = 1, total = 1 }, + easing = "linear", + }, + bigfile = { enabled = true }, + dashboard = { enabled = false }, + explorer = { enabled = false }, + image = { + enabled = true, + inline = false, + scale = 3, -- nil | 1 (default) | 2 | 3 | ... + doc = { + inline = true, + enabled = true, + max_width = nil, + max_height = nil, + conceal = true, }, - - -- Keybindings for the prompt buffer only - prompt = { - submit = { - "", -- Normal mode, just Enter - { - "", - mode = { "n", "v", "i" }, - }, - }, - - paste_image = { - { - "p", - mode = { "n" }, - }, - { - "", -- Same as Claude-code in insert mode - mode = { "i" }, - } - }, + math = { + enabled = true, + } + }, + terminal = { + bo = { + filetype = "snacks_terminal", }, - - -- Keybindings for diff preview navigation - diff_preview = { - next_hunk = "]c", - prev_hunk = "[c", + win = { style = "terminal" }, + wo = {}, + keys = { + q = "hide", + gf = function(self) + local f = vim.fn.findfile(vim.fn.expand(""), "**") + if f == "" then + Snacks.notify.warn("No file under cursor") + else + self:hide() + vim.schedule(function() + vim.cmd("e " .. f) + end) + end + end, + term_normal = { + "", + function(self) + self.esc_timer = self.esc_timer or (vim.uv or vim.loop).new_timer() + if self.esc_timer:is_active() then + self.esc_timer:stop() + vim.cmd("stopinsert") + else + self.esc_timer:start(250, 0, function() end) + return "" + end + end, + mode = "t", + expr = true, + desc = "Double escape to normal mode", + }, }, }, + indent = { enabled = false }, + notifier = { + enabled = true, + timeout = 1000, + }, + picker = { + enabled = true, + layout = { preset = "ivy", layout = { position = "bottom" } }, + frecency = true, + history_bonus = true, + projects = { + dev = { "~/Projects", }, + }, + win = { + input = { + keys = { + [''] = { 'layout_right', mode = { 'i', 'n' } }, + }, + }, + }, + sources = { + files = { + -- add a custom action + actions = { + create_if_missing = function(picker, item) + -- When typing in the input, item may be nil. + -- We'll use the input text as the intended file path. + local input = picker.input and picker.input:get() or "" + if input == "" then return end + + -- Make it relative to picker cwd if it’s not absolute + local cwd = picker.opts.cwd or vim.loop.cwd() + local path = input + if not path:match("^/") and not path:match("^%a:[/\\]") then + path = cwd .. "/" .. path + end + + -- Normalize path (optional) + path = vim.fn.fnamemodify(path, ":p") + + -- If file exists, just open it + if vim.loop.fs_stat(path) then + picker:close() + vim.cmd.edit(path) + return + end + + -- Ensure parent dirs exist (optional but nice) + vim.fn.mkdir(vim.fn.fnamemodify(path, ":h"), "p") + + -- Open a new buffer at that path (creates buffer even if file missing) + picker:close() + vim.cmd.edit(path) + -- At this point buffer is new + unnamed-on-disk until you :w + end, + }, + + -- bind the action to a key in the picker UI + win = { + input = { + keys = { + [""] = { "create_if_missing", mode = { "i", "n" }, desc = "Create file from input" }, + }, + }, + list = { + keys = { + [""] = { "create_if_missing", mode = { "n" }, desc = "Create file from input" }, + }, + }, + }, + }, + }, + }, + scope = { enabled = false }, + scratch = { + ft = "markdown", + }, + statuscolumn = { enabled = true }, + styles = { + notification = { + -- wo = { wrap = true } -- Wrap notifications + } + } }, - -- these are just suggested keymaps; customize as desired keys = { + -- Org Search + { "o/", function() Snacks.picker.grep({dirs = { os.getenv("HOME") .. "/Documents/notes" }}) end, desc = "Search Org Files" }, + -- { "o/", function() Snacks.picker.files({ cwd = os.getenv("HOME") .. "/Documents/notes" }) end, desc = "Find Document" }, + -- Top Pickers & Explorer + { "", function() Snacks.picker.smart() end, desc = "Smart Find Files" }, + { "j", function() Snacks.picker.files({args = { "--no-require-git" }}) end, desc = "Find Files" }, + { ",", function() Snacks.picker.buffers() end, desc = "Buffers" }, + { "/", function() Snacks.picker.grep() end, desc = "Grep" }, + { ":", function() Snacks.picker.command_history() end, desc = "Command History" }, + { "n", function() Snacks.picker.notifications() end, desc = "Notification History" }, + { "i", function() Snacks.picker.lsp_symbols() end, desc = "Symbols" }, + { "I", function() Snacks.picker.lsp_workspace_symbols() end, desc = "LSP Workspace Symbols" }, + -- { "e", function() Snacks.explorer() end, desc = "File Explorer" }, + -- find + { "fb", function() Snacks.picker.buffers() end, desc = "Buffers" }, + { "fc", function() Snacks.picker.files({ cwd = vim.fn.stdpath("config") }) end, desc = "Find Config File" }, + { "ff", function() Snacks.picker.files() end, desc = "Find Files" }, + { "fg", function() Snacks.picker.git_files() end, desc = "Find Git Files" }, + { "fp", function() Snacks.picker.projects() end, desc = "Projects" }, + { "fr", function() Snacks.picker.recent() end, desc = "Recent" }, + -- git + { "gb", function() Snacks.picker.git_branches() end, desc = "Git Branches" }, + { "gl", function() Snacks.picker.git_log() end, desc = "Git Log" }, + { "gL", function() Snacks.picker.git_log_line() end, desc = "Git Log Line" }, + { "gs", function() Snacks.picker.git_status() end, desc = "Git Status" }, + { "gS", function() Snacks.picker.git_stash() end, desc = "Git Stash" }, + { "gd", function() Snacks.picker.git_diff() end, desc = "Git Diff (Hunks)" }, + { "gf", function() Snacks.picker.git_log_file() end, desc = "Git Log File" }, + -- Grep + { "sb", function() Snacks.picker.lines() end, desc = "Buffer Lines" }, + { "sB", function() Snacks.picker.grep_buffers() end, desc = "Grep Open Buffers" }, + { "sg", function() Snacks.picker.grep() end, desc = "Grep" }, + { "sw", function() Snacks.picker.grep_word() end, desc = "Visual selection or word", mode = { "n", "x" } }, + -- search + { 's"', function() Snacks.picker.registers() end, desc = "Registers" }, + { 's/', function() Snacks.picker.search_history() end, desc = "Search History" }, + { "sa", function() Snacks.picker.autocmds() end, desc = "Autocmds" }, + { "sb", function() Snacks.picker.lines() end, desc = "Buffer Lines" }, + { "sc", function() Snacks.picker.command_history() end, desc = "Command History" }, + { "sC", function() Snacks.picker.commands() end, desc = "Commands" }, + { "sd", function() Snacks.picker.diagnostics() end, desc = "Diagnostics" }, + { "sD", function() Snacks.picker.diagnostics_buffer() end, desc = "Buffer Diagnostics" }, + { "sh", function() Snacks.picker.help() end, desc = "Help Pages" }, + { "sH", function() Snacks.picker.highlights() end, desc = "Highlights" }, + { "si", function() Snacks.picker.icons() end, desc = "Icons" }, + { "sj", function() Snacks.picker.jumps() end, desc = "Jumps" }, + { "sk", function() Snacks.picker.keymaps() end, desc = "Keymaps" }, + { "sl", function() Snacks.picker.loclist() end, desc = "Location List" }, + { "sm", function() Snacks.picker.marks() end, desc = "Marks" }, + { "sM", function() Snacks.picker.man() end, desc = "Man Pages" }, + { "sp", function() Snacks.picker.lazy() end, desc = "Search for Plugin Spec" }, + { "sq", function() Snacks.picker.qflist() end, desc = "Quickfix List" }, + { "sR", function() Snacks.picker.resume() end, desc = "Resume" }, + { "su", function() Snacks.picker.undo() end, desc = "Undo History" }, + { "sz", function() Snacks.picker.zoxide() end, desc = "Zoxide" }, + { "uC", function() Snacks.picker.colorschemes() end, desc = "Colorschemes" }, + -- LSP + { "gd", function() Snacks.picker.lsp_definitions() end, desc = "Goto Definition" }, + { "gD", function() Snacks.picker.lsp_declarations() end, desc = "Goto Declaration" }, + { "grr", function() Snacks.picker.lsp_references() end, nowait = true, desc = "References" }, + { "gri", function() Snacks.picker.lsp_implementations() end, desc = "Goto Implementation" }, + { "gy", function() Snacks.picker.lsp_type_definitions() end, desc = "Goto T[y]pe Definition" }, + { "ss", function() Snacks.picker.lsp_symbols() end, desc = "LSP Symbols" }, + { "sS", function() Snacks.picker.lsp_workspace_symbols() end, desc = "LSP Workspace Symbols" }, + -- Other + { "Z", function() Snacks.zen() end, desc = "Toggle Zen Mode" }, + { "z", function() Snacks.zen.zoom() end, desc = "Toggle Zoom" }, + { ".", function() Snacks.scratch() end, desc = "Toggle Scratch Buffer" }, + { "S", function() Snacks.scratch.select() end, desc = "Select Scratch Buffer" }, + -- { "n", function() Snacks.notifier.show_history() end, desc = "Notification History" }, + { "bd", function() Snacks.bufdelete() end, desc = "Delete Buffer" }, + { "bR", function() Snacks.rename.rename_file() end, desc = "Rename File" }, + { "gB", function() Snacks.gitbrowse() end, desc = "Git Browse", mode = { "n", "v" } }, + { "gg", function() Snacks.lazygit() end, desc = "Lazygit" }, + { "un", function() Snacks.notifier.hide() end, desc = "Dismiss All Notifications" }, + { "", function() Snacks.terminal.toggle() end, desc = "Toggle Terminal", mode = { "n", "t" } }, + -- { "", "", desc = "Exit Terminal Mode", mode = { "t" } }, + { "]]", function() Snacks.words.jump(vim.v.count1) end, desc = "Next Reference", mode = { "n", "t" } }, + { "[[", function() Snacks.words.jump(-vim.v.count1) end, desc = "Prev Reference", mode = { "n", "t" } }, { - "rat", - function() require("agentic").toggle() end, - mode = { "n", "v", "i" }, - desc = "Toggle Agentic Chat" - }, - { - "", - function() require("agentic").add_selection_or_file_to_context() end, - mode = { "n", "v" }, - desc = "Add file or selection to Agentic to Context" - }, - { - "ran", - function() require("agentic").new_session() end, - mode = { "n", "v", "i" }, - desc = "New Agentic Session" - }, - { - "r", -- ai Restore + "xN", + desc = "Neovim News", function() - require("agentic").restore_session() + Snacks.win({ + file = vim.api.nvim_get_runtime_file("doc/news.txt", false)[1], + width = 0.6, + height = 0.6, + wo = { + spell = false, + wrap = false, + signcolumn = "yes", + statuscolumn = " ", + conceallevel = 3, + }, + }) end, - desc = "Agentic Restore session", - silent = true, - mode = { "n", "v", "i" }, - }, - { - "rad", -- ai Diagnostics - function() - require("agentic").add_current_line_diagnostics() - end, - desc = "Add current line diagnostic to Agentic", - mode = { "n" }, - }, - { - "raD", -- ai all Diagnostics - function() - require("agentic").add_buffer_diagnostics() - end, - desc = "Add all buffer diagnostics to Agentic", - mode = { "n" }, - }, + } }, - }, - { - "zbirenbaum/copilot.lua", - dependencies = { - "copilotlsp-nvim/copilot-lsp", - config = function() - vim.g.copilot_nes_debounce = 500 - end, - }, - cmd = "Copilot", - event = "InsertEnter", - config = function() - require('copilot').setup({ - nes = { - enabled = false, - keymap = { - accept_and_goto = "", - accept = false, - dismiss = "", - }, - }, - panel = { - enabled = false, - }, + init = function() + vim.api.nvim_create_autocmd("User", { + pattern = "VeryLazy", + callback = function() + -- Setup some globals for debugging (lazy-loaded) + _G.dd = function(...) + Snacks.debug.inspect(...) + end + _G.bt = function() + Snacks.debug.backtrace() + end + vim.print = _G.dd -- Override print to use snacks for `:=` command + + -- Create some toggle mappings + Snacks.toggle.option("spell", { name = "Spelling" }):map("us") + Snacks.toggle.option("wrap", { name = "Wrap" }):map("uw") + Snacks.toggle.option("relativenumber", { name = "Relative Number" }):map("uL") + Snacks.toggle.diagnostics():map("ud") + Snacks.toggle.line_number():map("ul") + Snacks.toggle.option("conceallevel", { off = 0, on = vim.o.conceallevel > 0 and vim.o.conceallevel or 2 }):map("uc") + Snacks.toggle.treesitter():map("uT") + Snacks.toggle.option("background", { off = "light", on = "dark", name = "Dark Background" }):map("ub") + Snacks.toggle.inlay_hints():map("uh") + Snacks.toggle.indent():map("ug") + Snacks.toggle.dim():map("uD") + end, }) end, }, { - "PhantomYdn/fabric-ai.nvim", - cmd = { "Fabric" }, - opts = { - -- Default configuration (all optional) - fabric_path = "fabric-ai", -- Path to Fabric CLI - patterns_path = nil, -- Custom patterns dir (auto-detect if nil) - timeout = 300000, -- Command timeout in ms (5 minutes) - window = { - width = 0.8, -- 80% of editor width - height = 0.8, -- 80% of editor height - border = "rounded", - }, - }, + "folke/todo-comments.nvim", + lazy = true, keys = { - -- fabric-ai.nvim doesn't have default keymappings - { "fa", ":'<,'>Fabric", mode = "v", desc = "Fabric AI" }, - { "fa", ":Fabric", mode = "n", desc = "Fabric AI" }, - { "fu", ":Fabric url", mode = "n", desc = "Fabric URL" }, + { "st", function() Snacks.picker.todo_comments() end, desc = "Todo" }, + { "sT", function() Snacks.picker.todo_comments({ keywords = { "TODO", "FIX", "FIXME", "NOTE" } }) end, desc = "Todo/Fix/Fixme/Note" }, }, + opts = {}, }, { 'L3MON4D3/LuaSnip', @@ -1607,15 +1030,6 @@ return { enabled = true, opts = { mode = "cursor", max_lines = 3 }, }, - { - "folke/todo-comments.nvim", - lazy = true, - keys = { - { "st", function() Snacks.picker.todo_comments() end, desc = "Todo" }, - { "sT", function() Snacks.picker.todo_comments({ keywords = { "TODO", "FIX", "FIXME", "NOTE" } }) end, desc = "Todo/Fix/Fixme/Note" }, - }, - opts = {}, - }, { "mbbill/undotree", lazy = true, @@ -1623,5 +1037,246 @@ return { { 'uu', vim.cmd.UndotreeToggle, desc = 'Format buffer' } }, }, + { + 'Civitasv/cmake-tools.nvim', + lazy = true, + config = function () + local osys = require("cmake-tools.osys") + require("cmake-tools").setup { + cmake_command = "cmake", -- this is used to specify cmake command path + ctest_command = "ctest", -- this is used to specify ctest command path + cmake_use_preset = true, + cmake_regenerate_on_save = true, -- auto generate when save CMakeLists.txt + cmake_generate_options = { "-DCMAKE_EXPORT_COMPILE_COMMANDS=1" }, -- this will be passed when invoke `CMakeGenerate` + cmake_build_options = {}, -- this will be passed when invoke `CMakeBuild` + -- support macro expansion: + -- ${kit} + -- ${kitGenerator} + -- ${variant:xx} + cmake_build_directory = function() + if osys.iswin32 then + return "out\\${variant:buildType}" + end + return "out/${variant:buildType}" + end, -- this is used to specify generate directory for cmake, allows macro expansion, can be a string or a function returning the string, relative to cwd. + cmake_soft_link_compile_commands = true, -- this will automatically make a soft link from compile commands file to project root dir + cmake_compile_commands_from_lsp = false, -- this will automatically set compile commands file location using lsp, to use it, please set `cmake_soft_link_compile_commands` to false + cmake_kits_path = nil, -- this is used to specify global cmake kits path, see CMakeKits for detailed usage + cmake_variants_message = { + short = { show = true }, -- whether to show short message + long = { show = true, max_length = 40 }, -- whether to show long message + }, + cmake_dap_configuration = { -- debug settings for cmake + name = "cpp", + type = "codelldb", + request = "launch", + stopOnEntry = false, + runInTerminal = true, + console = "integratedTerminal", + }, + cmake_executor = { -- executor to use + name = "quickfix", -- name of the executor + opts = {}, -- the options the executor will get, possible values depend on the executor type. See `default_opts` for possible values. + default_opts = { -- a list of default and possible values for executors + quickfix = { + show = "always", -- "always", "only_on_error" + position = "belowright", -- "vertical", "horizontal", "leftabove", "aboveleft", "rightbelow", "belowright", "topleft", "botright", use `:h vertical` for example to see help on them + size = 10, + encoding = "utf-8", -- if encoding is not "utf-8", it will be converted to "utf-8" using `vim.fn.iconv` + auto_close_when_success = true, -- typically, you can use it with the "always" option; it will auto-close the quickfix buffer if the execution is successful. + }, + toggleterm = { + direction = "float", -- 'vertical' | 'horizontal' | 'tab' | 'float' + close_on_exit = false, -- whether close the terminal when exit + auto_scroll = true, -- whether auto scroll to the bottom + singleton = true, -- single instance, autocloses the opened one, if present + }, + overseer = { + new_task_opts = { + strategy = { + "toggleterm", + direction = "horizontal", + autos_croll = true, + quit_on_exit = "success" + } + }, -- options to pass into the `overseer.new_task` command + on_new_task = function(task) + require("overseer").open( + { enter = false, direction = "right" } + ) + end, -- a function that gets overseer.Task when it is created, before calling `task:start` + }, + terminal = { + name = "Main Terminal", + prefix_name = "[CMakeTools]: ", -- This must be included and must be unique, otherwise the terminals will not work. Do not use a simple spacebar " ", or any generic name + split_direction = "horizontal", -- "horizontal", "vertical" + split_size = 11, + + -- Window handling + single_terminal_per_instance = true, -- Single viewport, multiple windows + single_terminal_per_tab = true, -- Single viewport per tab + keep_terminal_static_location = true, -- Static location of the viewport if avialable + auto_resize = true, -- Resize the terminal if it already exists + + -- Running Tasks + start_insert = false, -- If you want to enter terminal with :startinsert upon using :CMakeRun + focus = false, -- Focus on terminal when cmake task is launched. + do_not_add_newline = false, -- Do not hit enter on the command inserted when using :CMakeRun, allowing a chance to review or modify the command before hitting enter. + }, -- terminal executor uses the values in cmake_terminal + }, + }, + cmake_runner = { -- runner to use + name = "terminal", -- name of the runner + opts = {}, -- the options the runner will get, possible values depend on the runner type. See `default_opts` for possible values. + default_opts = { -- a list of default and possible values for runners + quickfix = { + show = "always", -- "always", "only_on_error" + position = "belowright", -- "bottom", "top" + size = 10, + encoding = "utf-8", + auto_close_when_success = true, -- typically, you can use it with the "always" option; it will auto-close the quickfix buffer if the execution is successful. + }, + toggleterm = { + direction = "float", -- 'vertical' | 'horizontal' | 'tab' | 'float' + close_on_exit = false, -- whether close the terminal when exit + auto_scroll = true, -- whether auto scroll to the bottom + singleton = true, -- single instance, autocloses the opened one, if present + }, + overseer = { + new_task_opts = { + strategy = { + "toggleterm", + direction = "horizontal", + autos_croll = true, + quit_on_exit = "success" + } + }, -- options to pass into the `overseer.new_task` command + on_new_task = function(task) + end, -- a function that gets overseer.Task when it is created, before calling `task:start` + }, + terminal = { + name = "Main Terminal", + prefix_name = "[CMakeTools]: ", -- This must be included and must be unique, otherwise the terminals will not work. Do not use a simple spacebar " ", or any generic name + split_direction = "horizontal", -- "horizontal", "vertical" + split_size = 11, + + -- Window handling + single_terminal_per_instance = true, -- Single viewport, multiple windows + single_terminal_per_tab = true, -- Single viewport per tab + keep_terminal_static_location = true, -- Static location of the viewport if avialable + auto_resize = true, -- Resize the terminal if it already exists + + -- Running Tasks + start_insert = false, -- If you want to enter terminal with :startinsert upon using :CMakeRun + focus = false, -- Focus on terminal when cmake task is launched. + do_not_add_newline = false, -- Do not hit enter on the command inserted when using :CMakeRun, allowing a chance to review or modify the command before hitting enter. + }, + }, + }, + cmake_notifications = { + runner = { enabled = true }, + executor = { enabled = true }, + spinner = { "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" }, -- icons used for progress display + refresh_rate_ms = 100, -- how often to iterate icons + }, + cmake_virtual_text_support = true, -- Show the target related to current file using virtual text (at right corner) + } + end, + }, + { + "folke/persistence.nvim", + event = "BufReadPre", + opts = { options = { "buffers", "curdir", "tabpages", "winsize", "help", "globals", "skiprtp" } }, + -- stylua: ignore + keys = { + { "xr", function() require("persistence").load() end, desc = "Restore Session" }, + { "xs", function() require("persistence").save() end, desc = "Save Session" }, + { "xl", function() require("persistence").load({ last = true }) end, desc = "Restore Last Session" }, + { "xd", function() require("persistence").stop() end, desc = "Don't Save Current Session" }, + }, + }, + + { + "otavioschwanck/arrow.nvim", + dependencies = { + { + "nvim-tree/nvim-web-devicons" + }, + -- or if using `mini.icons` + -- { "echasnovski/mini.icons" }, + }, + opts = { + show_icons = true, + leader_key = ';', -- Recommended to be a single key + buffer_leader_key = ';', -- Per Buffer Mappings + } + }, + { + "nvim-pack/nvim-spectre", + lazy = true, + cmd = { "Spectre" }, + keys = { + { "sr", function() require("spectre").open() end, desc = "Replace in files (Spectre)" }, + }, + opts = { + open_cmd = "noswapfile vnew", + highlight = { + search = "SpectreSearch", + replace = "SpectreReplace", + }, + mapping = { + ["send_to_qf"] = { + map = "", + cmd = "lua require('spectre.actions').send_to_qf()", + desc = "send all items to quickfix", + }, + }, + } + }, + { + 'stevearc/overseer.nvim', + keys = { + { "xo", "OverseerOpen", desc = "Open Overseer" }, + { "to", "OverseerToggle", desc = "Overseer Toggle" }, + { "", "OverseerRun", desc = "Run Overseer" }, + { "", "OverseerToggle", desc = "Overseer Toggle" }, + }, + config = function() + require("overseer").setup({ + templates = { "builtin", "user" }, + component_aliases = { + default = { + { 'display_duration', detail_level = 2 }, + 'on_output_summarize', + 'on_exit_set_status', + 'on_result_diagnostics_quickfix', + 'on_complete_notify', + { "on_complete_dispose", require_view = { "SUCCESS", "FAILURE" } }, + }, + default_vscode = { + 'default', + 'on_result_diagnostics', + 'on_result_diagnostics_quickfix', + 'on_complete_notify', + }, + } + }) + -- local pm = require("overseer.template.vscode.problem_matcher") + -- pm.register_problem_matcher("$rustc", { + -- fileLocation = { "autoDetect", "${cwd}" }, + -- pattern = { + -- --regexp = "^(.*?)-->\\s+(.*?):(\\d+):(\\d+)$", + -- -- vim_regexp = "\\v^(.*?)-->\\s+(.*?):(\\d+):(\\d+)$", + -- regexp = "^\\s+-->\\s*([^:]*):(\\d+):(\\d+)$", + -- vim_regexp = "\\v^\\s+-->\\s*([^:]*):(\\d+):(\\d+)$", + -- file = 1, + -- line = 2, + -- column = 3, + -- } + -- }) + + end, + }, + } diff --git a/config/nvim/lua/plugins/init.lua b/config/nvim/lua/plugins/init.lua index 91e9d7f..39aacf8 100644 --- a/config/nvim/lua/plugins/init.lua +++ b/config/nvim/lua/plugins/init.lua @@ -131,282 +131,4 @@ return { require('mini.sessions').setup() end, }, - { - "folke/snacks.nvim", - priority = 1000, - lazy = false, - ---@type snacks.Config - opts = { - animate = { - enabled = false, - duration = { step = 1, total = 1 }, - easing = "linear", - }, - bigfile = { enabled = true }, - dashboard = { enabled = false }, - explorer = { enabled = false }, - image = { - enabled = true, - inline = false, - scale = 3, -- nil | 1 (default) | 2 | 3 | ... - doc = { - inline = true, - enabled = true, - max_width = nil, - max_height = nil, - conceal = true, - }, - math = { - enabled = true, - } - }, - terminal = { - bo = { - filetype = "snacks_terminal", - }, - win = { style = "terminal" }, - wo = {}, - keys = { - q = "hide", - gf = function(self) - local f = vim.fn.findfile(vim.fn.expand(""), "**") - if f == "" then - Snacks.notify.warn("No file under cursor") - else - self:hide() - vim.schedule(function() - vim.cmd("e " .. f) - end) - end - end, - term_normal = { - "", - function(self) - self.esc_timer = self.esc_timer or (vim.uv or vim.loop).new_timer() - if self.esc_timer:is_active() then - self.esc_timer:stop() - vim.cmd("stopinsert") - else - self.esc_timer:start(250, 0, function() end) - return "" - end - end, - mode = "t", - expr = true, - desc = "Double escape to normal mode", - }, - }, - }, - indent = { enabled = false }, - notifier = { - enabled = true, - timeout = 1000, - }, - picker = { - enabled = true, - layout = { preset = "ivy", layout = { position = "bottom" } }, - frecency = true, - history_bonus = true, - projects = { - dev = { "~/Projects", }, - }, - win = { - input = { - keys = { - [''] = { 'layout_right', mode = { 'i', 'n' } }, - }, - }, - }, - sources = { - files = { - -- add a custom action - actions = { - create_if_missing = function(picker, item) - -- When typing in the input, item may be nil. - -- We'll use the input text as the intended file path. - local input = picker.input and picker.input:get() or "" - if input == "" then return end - - -- Make it relative to picker cwd if it’s not absolute - local cwd = picker.opts.cwd or vim.loop.cwd() - local path = input - if not path:match("^/") and not path:match("^%a:[/\\]") then - path = cwd .. "/" .. path - end - - -- Normalize path (optional) - path = vim.fn.fnamemodify(path, ":p") - - -- If file exists, just open it - if vim.loop.fs_stat(path) then - picker:close() - vim.cmd.edit(path) - return - end - - -- Ensure parent dirs exist (optional but nice) - vim.fn.mkdir(vim.fn.fnamemodify(path, ":h"), "p") - - -- Open a new buffer at that path (creates buffer even if file missing) - picker:close() - vim.cmd.edit(path) - -- At this point buffer is new + unnamed-on-disk until you :w - end, - }, - - -- bind the action to a key in the picker UI - win = { - input = { - keys = { - [""] = { "create_if_missing", mode = { "i", "n" }, desc = "Create file from input" }, - }, - }, - list = { - keys = { - [""] = { "create_if_missing", mode = { "n" }, desc = "Create file from input" }, - }, - }, - }, - }, - }, - }, - scope = { enabled = false }, - scratch = { - ft = "markdown", - }, - statuscolumn = { enabled = true }, - styles = { - notification = { - -- wo = { wrap = true } -- Wrap notifications - } - } - }, - keys = { - -- Org Search - { "o/", function() Snacks.picker.grep({dirs = { os.getenv("HOME") .. "/Documents/notes" }}) end, desc = "Search Org Files" }, - -- { "o/", function() Snacks.picker.files({ cwd = os.getenv("HOME") .. "/Documents/notes" }) end, desc = "Find Document" }, - -- Top Pickers & Explorer - { "", function() Snacks.picker.smart() end, desc = "Smart Find Files" }, - { "j", function() Snacks.picker.files({args = { "--no-require-git" }}) end, desc = "Find Files" }, - { ",", function() Snacks.picker.buffers() end, desc = "Buffers" }, - { "/", function() Snacks.picker.grep() end, desc = "Grep" }, - { ":", function() Snacks.picker.command_history() end, desc = "Command History" }, - { "n", function() Snacks.picker.notifications() end, desc = "Notification History" }, - { "i", function() Snacks.picker.lsp_symbols() end, desc = "Symbols" }, - { "I", function() Snacks.picker.lsp_workspace_symbols() end, desc = "LSP Workspace Symbols" }, - -- { "e", function() Snacks.explorer() end, desc = "File Explorer" }, - -- find - { "fb", function() Snacks.picker.buffers() end, desc = "Buffers" }, - { "fc", function() Snacks.picker.files({ cwd = vim.fn.stdpath("config") }) end, desc = "Find Config File" }, - { "ff", function() Snacks.picker.files() end, desc = "Find Files" }, - { "fg", function() Snacks.picker.git_files() end, desc = "Find Git Files" }, - { "fp", function() Snacks.picker.projects() end, desc = "Projects" }, - { "fr", function() Snacks.picker.recent() end, desc = "Recent" }, - -- git - { "gb", function() Snacks.picker.git_branches() end, desc = "Git Branches" }, - { "gl", function() Snacks.picker.git_log() end, desc = "Git Log" }, - { "gL", function() Snacks.picker.git_log_line() end, desc = "Git Log Line" }, - { "gs", function() Snacks.picker.git_status() end, desc = "Git Status" }, - { "gS", function() Snacks.picker.git_stash() end, desc = "Git Stash" }, - { "gd", function() Snacks.picker.git_diff() end, desc = "Git Diff (Hunks)" }, - { "gf", function() Snacks.picker.git_log_file() end, desc = "Git Log File" }, - -- Grep - { "sb", function() Snacks.picker.lines() end, desc = "Buffer Lines" }, - { "sB", function() Snacks.picker.grep_buffers() end, desc = "Grep Open Buffers" }, - { "sg", function() Snacks.picker.grep() end, desc = "Grep" }, - { "sw", function() Snacks.picker.grep_word() end, desc = "Visual selection or word", mode = { "n", "x" } }, - -- search - { 's"', function() Snacks.picker.registers() end, desc = "Registers" }, - { 's/', function() Snacks.picker.search_history() end, desc = "Search History" }, - { "sa", function() Snacks.picker.autocmds() end, desc = "Autocmds" }, - { "sb", function() Snacks.picker.lines() end, desc = "Buffer Lines" }, - { "sc", function() Snacks.picker.command_history() end, desc = "Command History" }, - { "sC", function() Snacks.picker.commands() end, desc = "Commands" }, - { "sd", function() Snacks.picker.diagnostics() end, desc = "Diagnostics" }, - { "sD", function() Snacks.picker.diagnostics_buffer() end, desc = "Buffer Diagnostics" }, - { "sh", function() Snacks.picker.help() end, desc = "Help Pages" }, - { "sH", function() Snacks.picker.highlights() end, desc = "Highlights" }, - { "si", function() Snacks.picker.icons() end, desc = "Icons" }, - { "sj", function() Snacks.picker.jumps() end, desc = "Jumps" }, - { "sk", function() Snacks.picker.keymaps() end, desc = "Keymaps" }, - { "sl", function() Snacks.picker.loclist() end, desc = "Location List" }, - { "sm", function() Snacks.picker.marks() end, desc = "Marks" }, - { "sM", function() Snacks.picker.man() end, desc = "Man Pages" }, - { "sp", function() Snacks.picker.lazy() end, desc = "Search for Plugin Spec" }, - { "sq", function() Snacks.picker.qflist() end, desc = "Quickfix List" }, - { "sR", function() Snacks.picker.resume() end, desc = "Resume" }, - { "su", function() Snacks.picker.undo() end, desc = "Undo History" }, - { "sz", function() Snacks.picker.zoxide() end, desc = "Zoxide" }, - { "uC", function() Snacks.picker.colorschemes() end, desc = "Colorschemes" }, - -- LSP - { "gd", function() Snacks.picker.lsp_definitions() end, desc = "Goto Definition" }, - { "gD", function() Snacks.picker.lsp_declarations() end, desc = "Goto Declaration" }, - { "grr", function() Snacks.picker.lsp_references() end, nowait = true, desc = "References" }, - { "gri", function() Snacks.picker.lsp_implementations() end, desc = "Goto Implementation" }, - { "gy", function() Snacks.picker.lsp_type_definitions() end, desc = "Goto T[y]pe Definition" }, - { "ss", function() Snacks.picker.lsp_symbols() end, desc = "LSP Symbols" }, - { "sS", function() Snacks.picker.lsp_workspace_symbols() end, desc = "LSP Workspace Symbols" }, - -- Other - { "Z", function() Snacks.zen() end, desc = "Toggle Zen Mode" }, - { "z", function() Snacks.zen.zoom() end, desc = "Toggle Zoom" }, - { ".", function() Snacks.scratch() end, desc = "Toggle Scratch Buffer" }, - { "S", function() Snacks.scratch.select() end, desc = "Select Scratch Buffer" }, - -- { "n", function() Snacks.notifier.show_history() end, desc = "Notification History" }, - { "bd", function() Snacks.bufdelete() end, desc = "Delete Buffer" }, - { "bR", function() Snacks.rename.rename_file() end, desc = "Rename File" }, - { "gB", function() Snacks.gitbrowse() end, desc = "Git Browse", mode = { "n", "v" } }, - { "gg", function() Snacks.lazygit() end, desc = "Lazygit" }, - { "un", function() Snacks.notifier.hide() end, desc = "Dismiss All Notifications" }, - { "", function() Snacks.terminal.toggle() end, desc = "Toggle Terminal", mode = { "n", "t" } }, - -- { "", "", desc = "Exit Terminal Mode", mode = { "t" } }, - { "]]", function() Snacks.words.jump(vim.v.count1) end, desc = "Next Reference", mode = { "n", "t" } }, - { "[[", function() Snacks.words.jump(-vim.v.count1) end, desc = "Prev Reference", mode = { "n", "t" } }, - { - "xN", - desc = "Neovim News", - function() - Snacks.win({ - file = vim.api.nvim_get_runtime_file("doc/news.txt", false)[1], - width = 0.6, - height = 0.6, - wo = { - spell = false, - wrap = false, - signcolumn = "yes", - statuscolumn = " ", - conceallevel = 3, - }, - }) - end, - } - }, - init = function() - vim.api.nvim_create_autocmd("User", { - pattern = "VeryLazy", - callback = function() - -- Setup some globals for debugging (lazy-loaded) - _G.dd = function(...) - Snacks.debug.inspect(...) - end - _G.bt = function() - Snacks.debug.backtrace() - end - vim.print = _G.dd -- Override print to use snacks for `:=` command - - -- Create some toggle mappings - Snacks.toggle.option("spell", { name = "Spelling" }):map("us") - Snacks.toggle.option("wrap", { name = "Wrap" }):map("uw") - Snacks.toggle.option("relativenumber", { name = "Relative Number" }):map("uL") - Snacks.toggle.diagnostics():map("ud") - Snacks.toggle.line_number():map("ul") - Snacks.toggle.option("conceallevel", { off = 0, on = vim.o.conceallevel > 0 and vim.o.conceallevel or 2 }):map("uc") - Snacks.toggle.treesitter():map("uT") - Snacks.toggle.option("background", { off = "light", on = "dark", name = "Dark Background" }):map("ub") - Snacks.toggle.inlay_hints():map("uh") - Snacks.toggle.indent():map("ug") - Snacks.toggle.dim():map("uD") - end, - }) - end, - }, } diff --git a/config/nvim/lua/plugins/tools.lua b/config/nvim/lua/plugins/tools.lua index 134c8e7..41bb612 100644 --- a/config/nvim/lua/plugins/tools.lua +++ b/config/nvim/lua/plugins/tools.lua @@ -1,4 +1,5 @@ return { + { 'Civitasv/cmake-tools.nvim', lazy = true, @@ -268,35 +269,19 @@ return { end, }, { - 'stevearc/quicker.nvim', - event = "FileType qf", - ---@module "quicker" - ---@type quicker.SetupOptions - opts = {}, - }, - { - "saxon1964/neovim-tips", - version = "*", -- Only update on tagged releases - lazy = false, -- Load on startup (recommended for daily tip feature) + "otavioschwanck/arrow.nvim", dependencies = { - "MunifTanjim/nui.nvim", - -- OPTIONAL: Choose your preferred markdown renderer (or omit for raw markdown) - "MeanderingProgrammer/render-markdown.nvim", -- Clean rendering - -- OR: "OXY2DEV/markview.nvim", -- Rich rendering with advanced features + { + "nvim-tree/nvim-web-devicons" + }, + -- or if using `mini.icons` + -- { "echasnovski/mini.icons" }, }, opts = { - -- OPTIONAL: Location of user defined tips (default value shown below) - user_file = vim.fn.stdpath("config") .. "/neovim_tips/user_tips.md", - -- OPTIONAL: Prefix for user tips to avoid conflicts (default: "[User] ") - user_tip_prefix = "[User] ", - -- OPTIONAL: Show warnings when user tips conflict with builtin (default: true) - warn_on_conflicts = true, - -- OPTIONAL: Daily tip mode (default: 1) - -- 0 = off, 1 = once per day, 2 = every startup - daily_tip = 1, - -- OPTIONAL: Bookmark symbol (default: "🌟 ") - bookmark_symbol = "🌟 ", - }, + show_icons = true, + leader_key = ';', -- Recommended to be a single key + buffer_leader_key = ';', -- Per Buffer Mappings + } }, { "nvim-pack/nvim-spectre", diff --git a/config/nvim/lua/plugins/ui.lua b/config/nvim/lua/plugins/ui.lua index bc3e47c..73eb1de 100644 --- a/config/nvim/lua/plugins/ui.lua +++ b/config/nvim/lua/plugins/ui.lua @@ -1,19 +1,5 @@ return { - { - "otavioschwanck/arrow.nvim", - dependencies = { - { - "nvim-tree/nvim-web-devicons" - }, - -- or if using `mini.icons` - -- { "echasnovski/mini.icons" }, - }, - opts = { - show_icons = true, - leader_key = ';', -- Recommended to be a single key - buffer_leader_key = ';', -- Per Buffer Mappings - } - }, + { 'j-hui/fidget.nvim', lazy = true }, { "utilyre/barbecue.nvim", dependencies = {