diff --git a/lua/config/keymaps.lua b/lua/config/keymaps.lua index ea91492..05b7542 100644 --- a/lua/config/keymaps.lua +++ b/lua/config/keymaps.lua @@ -57,12 +57,31 @@ map("n", "", ":m '>+1gv=gv", { desc = "Move selection down" }) map("n", "", ":m '<-2gv=gv", { desc = "Move selection up" }) -- ───────────────────────────────────────────────────────────────────────────── --- AI (Avante) +-- AI (OpenCode) -- ───────────────────────────────────────────────────────────────────────────── -map("n", "aa", "AvanteAsk", { desc = "AI Ask" }) -map("v", "aa", "AvanteAsk", { desc = "AI Ask (selection)" }) -map("n", "ac", "AvanteChat", { desc = "AI Chat" }) -map("n", "at", "AvanteToggle", { desc = "AI Toggle" }) +map({ "n", "x" }, "aa", function() + require("opencode").ask("@this: ", { submit = true }) +end, { desc = "AI Ask" }) +map({ "n", "x" }, "ax", function() + require("opencode").select() +end, { desc = "AI Ask (selection)" }) +map({ "n", "t" }, "at", function() + require("opencode").toggle() +end, { desc = "AI Toggle" }) + +map({ "n", "x" }, "go", function() + return require("opencode").operator("@this ") +end, { desc = "Add range to AI chat", expr = true }) +map("n", "goo", function() + return require("opencode").operator("@this ") .. "_" +end, { desc = "Add line to AI chat", expr = true }) + +map("n", "", function() + require("opencode").command("sesion.half.page.up") +end, { desc = "Scroll AI chat up" }) +map("n", "", function() + require("opencode").command("session.half.page.down") +end, { desc = "Scroll AI chat down" }) -- ───────────────────────────────────────────────────────────────────────────── -- Database (vim-dadbod) diff --git a/lua/plugins/ai.lua b/lua/plugins/ai.lua index 9c69d18..c31ea32 100644 --- a/lua/plugins/ai.lua +++ b/lua/plugins/ai.lua @@ -1,209 +1,65 @@ --- AI Chat Integration using avante.nvim --- Supports: Anthropic Claude, OpenAI, Google Gemini, Copilot, and more --- API keys via environment variables: --- ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY --- Or scoped: AVANTE_ANTHROPIC_API_KEY, AVANTE_OPENAI_API_KEY, etc. --- --- Switch provider at runtime with: :AvanteSwitchProvider claude|openai|gemini|copilot|ollama - return { { - "yetone/avante.nvim", - version = false, -- Never set to "*" - build = "make", + "nickyvandyke/opencode.nvim", + version = "v0.10.1", dependencies = { - "nvim-treesitter/nvim-treesitter", - "stevearc/dressing.nvim", - "nvim-lua/plenary.nvim", - "MunifTanjim/nui.nvim", - "nvim-tree/nvim-web-devicons", { - -- Image support (optional) - "HakonHarnes/img-clip.nvim", - event = "VeryLazy", + ---@module "snacks" + "folke/snacks.nvim", + optional = true, opts = { - default = { - embed_image_as_base64 = false, - prompt_for_file_name = false, - drag_and_drop = { - insert_mode = true, + input = {}, -- Enhances `ask()` + picker = { -- Enhances `select()` + actions = { + opencode_send = function(...) + return require("opencode").snacks_picker_send(...) + end, + }, + win = { + input = { + keys = { + [""] = { "opencode_send", mode = { "n", "i" } }, + }, + }, }, }, }, }, - { - -- Markdown rendering in Avante - "MeanderingProgrammer/render-markdown.nvim", - opts = { - file_types = { "markdown", "Avante" }, - }, - ft = { "markdown", "Avante" }, - }, }, - cmd = { - "AvanteAsk", - "AvanteChat", - "AvanteToggle", - "AvanteEdit", - "AvanteRefresh", - "AvanteBuild", - "AvanteSwitchProvider", - "AvanteShowRepoMap", - "AvanteClear", - "AvanteFocus", - }, - ---@module 'avante' - ---@type avante.Config - opts = { - -- Default provider (switch with :AvanteProvider command) - -- Options: "claude", "openai", "azure", "gemini", "copilot", "cohere" - provider = "openai", + config = function() + local opencode_cmd = "opencode --port" + ---@type snacks.terminal.Opts + local snacks_terminal_opts = { + win = { + position = "right", + enter = false, + on_win = function(win) + -- Set up keymaps and cleanup for an arbitary terminal + require("opencode.terminal").setup(win.win) + end, + }, + } - -- Provider configurations - providers = { - claude = { - endpoint = "https://api.anthropic.com", - model = "claude-sonnet-4-5-20250929", - timeout = 30000, - extra_request_body = { - temperature = 0.75, - max_tokens = 20480, - }, + ---@type opencode.Opts + vim.g.opencode_opts = { + -- Specific configuration around opencode + server = { + start = function() + require("snacks.terminal").open(opencode_cmd, snacks_terminal_opts) + end, + stop = function() + require("snacks.terminal").get(opencode_cmd, snacks_terminal_opts):close() + end, + toggle = function() + require("snacks.terminal").toggle(opencode_cmd, snacks_terminal_opts) + end, }, - openai = { - endpoint = "https://api.openai.com/v1", - model = "gpt-4o-mini", - timeout = 30000, - extra_request_body = { - temperature = 0.75, - max_completion_tokens = 16384, - }, - }, - azure = { - endpoint = "", -- e.g., "https://.openai.azure.com" - deployment = "", -- Azure deployment name - api_version = "2024-12-01-preview", - timeout = 30000, - extra_request_body = { - temperature = 0.75, - max_completion_tokens = 16384, - }, - }, - gemini = { - endpoint = "https://generativelanguage.googleapis.com/v1beta/models", - model = "gemini-2.0-flash", - timeout = 30000, - extra_request_body = { - generationConfig = { - temperature = 0.75, - }, - }, - }, - copilot = { - endpoint = "https://api.githubcopilot.com", - model = "gpt-4o-2024-08-06", - timeout = 30000, - extra_request_body = { - temperature = 0.75, - max_tokens = 20480, - }, - }, - -- Custom provider example for Ollama (local models) - -- Uncomment and configure if using local LLMs - -- ollama = { - -- __inherited_from = "openai", - -- endpoint = "http://localhost:11434/v1", - -- model = "llama3.2", - -- api_key_name = "", - -- }, - }, - - -- Behavior settings - behaviour = { - auto_suggestions = false, -- Set true for copilot-like suggestions - auto_set_highlight_group = true, - auto_set_keymaps = true, - auto_apply_diff_after_generation = false, - support_paste_from_clipboard = false, - minimize_diff = true, - enable_token_counting = true, - }, - - -- Mappings - mappings = { - diff = { - ours = "co", - theirs = "ct", - all_theirs = "ca", - both = "cb", - cursor = "cc", - next = "]x", - prev = "[x", - }, - suggestion = { - accept = "", - next = "", - prev = "", - dismiss = "", - }, - jump = { - next = "]]", - prev = "[[", - }, - submit = { - normal = "", - insert = "", - }, - sidebar = { - apply_all = "A", - apply_cursor = "a", - switch_windows = "", - reverse_switch_windows = "", - }, - }, - - -- Hints shown in the UI - hints = { enabled = true }, - - -- Window configuration - windows = { - position = "right", - wrap = true, - width = 30, - sidebar_header = { + lsp = { enabled = true, - align = "center", - rounded = true, }, - input = { - prefix = "> ", - height = 8, - }, - edit = { - border = "rounded", - start_insert = true, - }, - ask = { - floating = false, - start_insert = true, - border = "rounded", - }, - }, + } - -- Highlight groups - highlights = { - diff = { - current = "DiffText", - incoming = "DiffAdd", - }, - }, - - -- Diff settings - diff = { - autojump = true, - list_opener = "copen", - override_timeoutlen = 500, - }, - }, + vim.o.autoreload = true -- Required for `opts.events.reload` + end, }, }