diff --git a/configuration.nix b/configuration.nix index dee5001f..2995fee8 100644 --- a/configuration.nix +++ b/configuration.nix @@ -248,6 +248,7 @@ isMaximal: { cmp.enable = isMaximal; }; codecompanion-nvim.enable = false; + avante-nvim.enable = isMaximal; }; session = { diff --git a/docs/release-notes/rl-0.8.md b/docs/release-notes/rl-0.8.md index 385eb548..eb9e1f74 100644 --- a/docs/release-notes/rl-0.8.md +++ b/docs/release-notes/rl-0.8.md @@ -370,7 +370,10 @@ [aionoid](https://github.com/aionoid): +[avante-nvim]: https://github.com/yetone/avante.nvim + - Fix [render-markdown.nvim] file_types option type to list, to accept merging. +- Add [avante.nvim] plugin under `vim.assistant.avante-nvim`. [poz](https://poz.pet): diff --git a/flake/avante-nvim/default.nix b/flake/avante-nvim/default.nix new file mode 100644 index 00000000..c048c4f8 --- /dev/null +++ b/flake/avante-nvim/default.nix @@ -0,0 +1,65 @@ +{ + nix-update-script, + openssl, + pkg-config, + rustPlatform, + stdenv, + vimPlugins, + vimUtils, + makeWrapper, + pkgs, + version, + src, + pins, +}: let + inherit version src; + avante-nvim-lib = rustPlatform.buildRustPackage { + pname = "avante-nvim-lib"; + inherit version src; + + useFetchCargoVendor = true; + cargoHash = "sha256-pmnMoNdaIR0i+4kwW3cf01vDQo39QakTCEG9AXA86ck="; + + nativeBuildInputs = [ + pkg-config + makeWrapper + pkgs.perl + ]; + + buildInputs = [ + openssl + ]; + + buildFeatures = ["luajit"]; + + checkFlags = [ + # Disabled because they access the network. + "--skip=test_hf" + "--skip=test_public_url" + "--skip=test_roundtrip" + "--skip=test_fetch_md" + ]; + }; +in + vimUtils.buildVimPlugin { + pname = "avante-nvim"; + inherit version src; + + postInstall = let + ext = stdenv.hostPlatform.extensions.sharedLibrary; + in '' + mkdir -p $out/build + ln -s ${avante-nvim-lib}/lib/libavante_repo_map${ext} $out/build/avante_repo_map${ext} + ln -s ${avante-nvim-lib}/lib/libavante_templates${ext} $out/build/avante_templates${ext} + ln -s ${avante-nvim-lib}/lib/libavante_tokenizers${ext} $out/build/avante_tokenizers${ext} + ln -s ${avante-nvim-lib}/lib/libavante_html2md${ext} $out/build/avante_html2md${ext} + ''; + + nvimSkipModules = [ + # Requires setup with corresponding provider + "avante.providers.azure" + "avante.providers.copilot" + "avante.providers.vertex_claude" + "avante.providers.ollama" + ]; + } diff --git a/flake/packages.nix b/flake/packages.nix index d6afbbf8..5161b34f 100644 --- a/flake/packages.nix +++ b/flake/packages.nix @@ -1,4 +1,8 @@ -{inputs, ...} @ args: { +{ + inputs, + self, + ... +} @ args: { perSystem = { config, pkgs, @@ -14,6 +18,18 @@ in { packages = { blink-cmp = pkgs.callPackage ./blink {}; + avante-nvim = let + pin = self.pins.avante-nvim; + in + pkgs.callPackage ./avante-nvim { + version = pin.branch; + src = pkgs.fetchFromGitHub { + inherit (pin.repository) owner repo; + rev = pin.revision; + sha256 = pin.hash; + }; + pins = self.pins; + }; inherit (docs.manual) htmlOpenTool; # Documentation diff --git a/modules/plugins/assistant/avante/avante-nvim.nix b/modules/plugins/assistant/avante/avante-nvim.nix new file mode 100644 index 00000000..7d52fab8 --- /dev/null +++ b/modules/plugins/assistant/avante/avante-nvim.nix @@ -0,0 +1,325 @@ +{lib, ...}: let + inherit (lib.options) mkOption mkEnableOption literalMD; + inherit (lib.types) int str enum nullOr attrs bool; + inherit (lib.nvim.types) mkPluginSetupOption; +in { + options.vim.assistant = { + avante-nvim = { + enable = mkEnableOption "complementary Neovim plugin for avante.nvim"; + setupOpts = mkPluginSetupOption "avante-nvim" { + provider = mkOption { + type = nullOr str; + default = null; + description = "The provider used in Aider mode or in the planning phase of Cursor Planning Mode."; + }; + + vendors = mkOption { + type = nullOr attrs; + default = null; + description = "Define Your Custom providers."; + example = literalMD '' + ```nix + ollama = { + __inherited_from = "openai"; + api_key_name = ""; + endpoint = "http://127.0.0.1:11434/v1"; + model = "qwen2.5u-coder:7b"; + max_tokens = 4096; + disable_tools = true; + }; + ollama_ds = { + __inherited_from = "openai"; + api_key_name = ""; + endpoint = "http://127.0.0.1:11434/v1"; + model = "deepseek-r1u:7b"; + max_tokens = 4096; + disable_tools = true; + }; + ``` + ''; + }; + + auto_suggestions_provider = mkOption { + type = str; + default = "claude"; + description = '' + Since auto-suggestions are a high-frequency operation and therefore expensive, + currently designating it as `copilot` provider is dangerous because: + https://github.com/yetone/avante.nvim/issues/1048 + Of course, you can reduce the request frequency by increasing `suggestion.debounce`. + ''; + }; + + cursor_applying_provider = mkOption { + type = nullOr str; + default = null; + description = '' + The provider used in the applying phase of Cursor Planning Mode, defaults to `nil`, + Config.provider will be used as the provider for the applying phase when `nil`. + ''; + }; + + dual_boost = { + enabled = mkEnableOption "dual_boost mode."; + + first_provider = mkOption { + type = str; + default = "openai"; + description = "The first provider to generate response."; + }; + + second_provider = mkOption { + type = str; + default = "claude"; + description = "The second provider to generate response."; + }; + + prompt = mkOption { + type = str; + default = '' + Based on the two reference outputs below, generate a response that incorporates + elements from both but reflects your own judgment and unique perspective. + Do not provide any explanation, just give the response directly. Reference Output 1: + [{{provider1_output}}], Reference Output 2: [{{provider2_output}}''; + description = "The prompt to generate response based on the two reference outputs."; + }; + + timeout = mkOption { + type = int; + default = 60000; + description = "Timeout in milliseconds."; + }; + }; + + behaviour = { + auto_suggestions = + mkEnableOption "auto suggestions."; + + auto_set_highlight_group = + mkEnableOption "automatically set the highlight group for the current line." + // { + default = true; + }; + + auto_set_keymaps = + mkEnableOption "automatically set the keymap for the current line." + // { + default = true; + }; + + auto_apply_diff_after_generation = + mkEnableOption "automatically apply diff after LLM response."; + + support_paste_from_clipboard = mkEnableOption '' + pasting image from clipboard. + This will be determined automatically based whether img-clip is available or not. + ''; + + minimize_diff = + mkEnableOption "remove unchanged lines when applying a code block." + // { + default = true; + }; + + enable_token_counting = + mkEnableOption "token counting." + // { + default = true; + }; + + enable_cursor_planning_mode = + mkEnableOption "Cursor Planning Mode."; + + enable_claude_text_editor_tool_mode = + mkEnableOption "Claude Text Editor Tool Mode."; + }; + + mappings = { + diff = mkOption { + type = nullOr attrs; + default = null; + description = "Define or override the default keymaps for diff."; + }; + + suggestion = mkOption { + type = nullOr attrs; + default = null; + description = "Define or override the default keymaps for suggestion actions."; + }; + + jump = mkOption { + type = nullOr attrs; + default = null; + description = "Define or override the default keymaps for jump actions."; + }; + + submit = mkOption { + type = nullOr attrs; + default = null; + description = "Define or override the default keymaps for submit actions."; + }; + + cancel = mkOption { + type = nullOr attrs; + default = null; + description = "Define or override the default keymaps for cancel actions."; + }; + + sidebar = mkOption { + type = nullOr attrs; + default = null; + description = "Define or override the default keymaps for sidebar actions."; + }; + }; + + hints.enabled = + mkEnableOption "" + // { + default = true; + description = '' + Whether to enable hints. + ''; + }; + + windows = { + position = mkOption { + type = enum ["right" "left" "top" "bottom"]; + default = "right"; + description = "The position of the sidebar."; + }; + + wrap = + mkEnableOption "" + // { + default = true; + description = '' + similar to vim.o.wrap. + ''; + }; + + width = mkOption { + type = int; + default = 30; + description = "Default % based on available width."; + }; + + sidebar_header = { + enabled = mkOption { + type = bool; + default = true; + description = "enable/disable the header."; + }; + + align = mkOption { + type = enum ["right" "center" "left"]; + default = "center"; + description = "Position of the title."; + }; + + rounded = mkOption { + type = bool; + default = true; + description = "Enable rounded sidebar header"; + }; + }; + + input = { + prefix = mkOption { + type = str; + default = "> "; + description = "The prefix used on the user input."; + }; + + height = mkOption { + type = int; + default = 8; + description = '' + Height of the input window in vertical layout. + ''; + }; + }; + + edit = { + border = mkOption { + type = str; + default = "rounded"; + description = "The border type on the edit window."; + }; + + start_insert = mkOption { + type = bool; + default = true; + description = '' + Start insert mode when opening the edit window. + ''; + }; + }; + + ask = { + floating = mkOption { + type = bool; + default = false; + description = '' + Open the 'AvanteAsk' prompt in a floating window. + ''; + }; + + start_insert = mkOption { + type = bool; + default = true; + description = '' + Start insert mode when opening the ask window. + ''; + }; + + border = mkOption { + type = str; + default = "rounded"; + description = "The border type on the ask window."; + }; + + focus_on_apply = mkOption { + type = enum ["ours" "theirs"]; + default = "ours"; + description = "Which diff to focus after applying."; + }; + }; + }; + + diff = { + autojump = + mkEnableOption "" + // { + default = true; + description = "Automatically jumps to the next change."; + }; + + override_timeoutlen = mkOption { + type = int; + default = 500; + example = -1; + description = '' + Override the 'timeoutlen' setting while hovering over a diff (see {command}`:help timeoutlen`). + Helps to avoid entering operator-pending mode with diff mappings starting with `c`. + Disable by setting to -1. + ''; + }; + }; + + suggestion = { + debounce = mkOption { + type = int; + default = 600; + description = "Suggestion debounce in milliseconds."; + }; + + throttle = mkOption { + type = int; + default = 600; + description = "Suggestion throttle in milliseconds."; + }; + }; + }; + }; + }; +} diff --git a/modules/plugins/assistant/avante/config.nix b/modules/plugins/assistant/avante/config.nix new file mode 100644 index 00000000..e140de89 --- /dev/null +++ b/modules/plugins/assistant/avante/config.nix @@ -0,0 +1,41 @@ +{ + config, + lib, + ... +}: let + inherit (lib.modules) mkIf; + inherit (lib.lists) optionals; + + cfg = config.vim.assistant.avante-nvim; +in { + config = mkIf cfg.enable { + vim = { + startPlugins = + [ + "nvim-treesitter" + "plenary-nvim" + "dressing-nvim" + "nui-nvim" + ] + ++ (optionals config.vim.mini.pick.enable ["mini-pick"]) + ++ (optionals config.vim.telescope.enable ["telescope"]) + ++ (optionals config.vim.autocomplete.nvim-cmp.enable ["nvim-cmp"]) + ++ (optionals config.vim.fzf-lua.enable ["fzf-lua"]) + ++ (optionals config.vim.visuals.nvim-web-devicons.enable ["nvim-web-devicons"]) + ++ (optionals config.vim.utility.images.img-clip.enable ["img-clip"]); + + lazy.plugins = { + avante-nvim = { + package = "avante-nvim"; + setupModule = "avante"; + inherit (cfg) setupOpts; + event = ["DeferredUIEnter"]; + }; + }; + + treesitter.enable = true; + + languages.markdown.extensions.render-markdown-nvim.setupOpts.file_types = lib.mkAfter ["Avante"]; + }; + }; +} diff --git a/modules/plugins/assistant/avante/default.nix b/modules/plugins/assistant/avante/default.nix new file mode 100644 index 00000000..c8ab1a1c --- /dev/null +++ b/modules/plugins/assistant/avante/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./config.nix + ./avante-nvim.nix + ]; +} diff --git a/modules/plugins/assistant/default.nix b/modules/plugins/assistant/default.nix index 697d54f6..ab50ea4f 100644 --- a/modules/plugins/assistant/default.nix +++ b/modules/plugins/assistant/default.nix @@ -3,5 +3,6 @@ ./chatgpt ./copilot ./codecompanion + ./avante ]; } diff --git a/modules/wrapper/build/config.nix b/modules/wrapper/build/config.nix index dd22bed8..585e9839 100644 --- a/modules/wrapper/build/config.nix +++ b/modules/wrapper/build/config.nix @@ -48,7 +48,7 @@ doCheck = false; }; - inherit (inputs.self.packages.${pkgs.stdenv.system}) blink-cmp; + inherit (inputs.self.packages.${pkgs.stdenv.system}) blink-cmp avante-nvim; }; buildConfigPlugins = plugins: diff --git a/modules/wrapper/rc/options.nix b/modules/wrapper/rc/options.nix index 02729401..028d903e 100644 --- a/modules/wrapper/rc/options.nix +++ b/modules/wrapper/rc/options.nix @@ -11,7 +11,7 @@ in { description = '' [official documentation]: https://neovim.io/doc/user/lua.html#vim.loader.enable() - Whethere to enable the experimental Lua module loader to speed up the start + Whether to enable the experimental Lua module loader to speed up the start up process. If `true`, this will enable the experimental Lua module loader which: diff --git a/npins/sources.json b/npins/sources.json index 846b1c48..d07e0484 100644 --- a/npins/sources.json +++ b/npins/sources.json @@ -26,6 +26,19 @@ "url": "https://github.com/goolord/alpha-nvim/archive/a35468cd72645dbd52c0624ceead5f301c566dff.tar.gz", "hash": "0c1jkhxamfn2md7m1r5b2wpxa26y90b98yzjwf68m3fymalvkn5h" }, + "avante-nvim": { + "type": "Git", + "repository": { + "type": "GitHub", + "owner": "yetone", + "repo": "avante.nvim" + }, + "branch": "main", + "submodules": false, + "revision": "f9aa75459d403d9e963ef2647c9791e0dfc9e5f9", + "url": "https://github.com/yetone/avante.nvim/archive/f9aa75459d403d9e963ef2647c9791e0dfc9e5f9.tar.gz", + "hash": "1qgdxapmw24zkx3d4cwv6f459p2a6dw7pvx7sa3650px2n75bb31" + }, "base16": { "type": "Git", "repository": {