Showing preview only (1,618K chars total). Download the full file or copy to clipboard to get everything.
Repository: yetone/avante.nvim
Branch: main
Commit: 348be57354a8
Files: 215
Total size: 1.5 MB
Directory structure:
gitextract_wdvhrp8a/
├── .cargo/
│ └── config.toml
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ └── feature_request.yml
│ └── workflows/
│ ├── close-stale-issues-and-prs.yaml
│ ├── lua.yaml
│ ├── pre-commit.yaml
│ ├── release.yaml
│ └── rust.yaml
├── .gitignore
├── .luacheckrc
├── .pre-commit-config.yaml
├── Build.ps1
├── Cargo.toml
├── LICENSE
├── Makefile
├── README.md
├── README_zh.md
├── autoload/
│ └── avante.vim
├── build.sh
├── crates/
│ ├── avante-html2md/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ ├── avante-repo-map/
│ │ ├── Cargo.toml
│ │ ├── queries/
│ │ │ ├── tree-sitter-c-defs.scm
│ │ │ ├── tree-sitter-c-sharp-defs.scm
│ │ │ ├── tree-sitter-cpp-defs.scm
│ │ │ ├── tree-sitter-elixir-defs.scm
│ │ │ ├── tree-sitter-go-defs.scm
│ │ │ ├── tree-sitter-java-defs.scm
│ │ │ ├── tree-sitter-javascript-defs.scm
│ │ │ ├── tree-sitter-lua-defs.scm
│ │ │ ├── tree-sitter-php-defs.scm
│ │ │ ├── tree-sitter-python-defs.scm
│ │ │ ├── tree-sitter-ruby-defs.scm
│ │ │ ├── tree-sitter-rust-defs.scm
│ │ │ ├── tree-sitter-scala-defs.scm
│ │ │ ├── tree-sitter-swift-defs.scm
│ │ │ ├── tree-sitter-typescript-defs.scm
│ │ │ └── tree-sitter-zig-defs.scm
│ │ └── src/
│ │ └── lib.rs
│ ├── avante-templates/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ └── avante-tokenizers/
│ ├── Cargo.toml
│ ├── README.md
│ └── src/
│ └── lib.rs
├── lua/
│ ├── avante/
│ │ ├── api.lua
│ │ ├── auth/
│ │ │ └── pkce.lua
│ │ ├── clipboard.lua
│ │ ├── config.lua
│ │ ├── diff.lua
│ │ ├── extensions/
│ │ │ ├── init.lua
│ │ │ └── nvim_tree.lua
│ │ ├── file_selector.lua
│ │ ├── health.lua
│ │ ├── highlights.lua
│ │ ├── history/
│ │ │ ├── helpers.lua
│ │ │ ├── init.lua
│ │ │ ├── message.lua
│ │ │ └── render.lua
│ │ ├── history_selector.lua
│ │ ├── html2md.lua
│ │ ├── init.lua
│ │ ├── libs/
│ │ │ ├── ReAct_parser.lua
│ │ │ ├── ReAct_parser2.lua
│ │ │ ├── acp_client.lua
│ │ │ ├── jsonparser.lua
│ │ │ └── xmlparser.lua
│ │ ├── llm.lua
│ │ ├── llm_tools/
│ │ │ ├── attempt_completion.lua
│ │ │ ├── base.lua
│ │ │ ├── bash.lua
│ │ │ ├── create.lua
│ │ │ ├── delete_tool_use_messages.lua
│ │ │ ├── dispatch_agent.lua
│ │ │ ├── edit_file.lua
│ │ │ ├── get_diagnostics.lua
│ │ │ ├── glob.lua
│ │ │ ├── grep.lua
│ │ │ ├── helpers.lua
│ │ │ ├── init.lua
│ │ │ ├── insert.lua
│ │ │ ├── ls.lua
│ │ │ ├── read_todos.lua
│ │ │ ├── replace_in_file.lua
│ │ │ ├── str_replace.lua
│ │ │ ├── think.lua
│ │ │ ├── undo_edit.lua
│ │ │ ├── view.lua
│ │ │ ├── write_to_file.lua
│ │ │ └── write_todos.lua
│ │ ├── model_selector.lua
│ │ ├── path.lua
│ │ ├── providers/
│ │ │ ├── azure.lua
│ │ │ ├── bedrock/
│ │ │ │ └── claude.lua
│ │ │ ├── bedrock.lua
│ │ │ ├── claude.lua
│ │ │ ├── cohere.lua
│ │ │ ├── copilot.lua
│ │ │ ├── gemini.lua
│ │ │ ├── init.lua
│ │ │ ├── ollama.lua
│ │ │ ├── openai.lua
│ │ │ ├── vertex.lua
│ │ │ ├── vertex_claude.lua
│ │ │ └── watsonx_code_assistant.lua
│ │ ├── rag_service.lua
│ │ ├── range.lua
│ │ ├── repo_map.lua
│ │ ├── selection.lua
│ │ ├── selection_result.lua
│ │ ├── sidebar.lua
│ │ ├── suggestion.lua
│ │ ├── templates/
│ │ │ ├── _context.avanterules
│ │ │ ├── _diagnostics.avanterules
│ │ │ ├── _environments.avanterules
│ │ │ ├── _gpt4-1-agentic.avanterules
│ │ │ ├── _memory.avanterules
│ │ │ ├── _project.avanterules
│ │ │ ├── _task-guidelines.avanterules
│ │ │ ├── _tools-guidelines.avanterules
│ │ │ ├── agentic.avanterules
│ │ │ ├── base.avanterules
│ │ │ ├── editing.avanterules
│ │ │ ├── legacy.avanterules
│ │ │ └── suggesting.avanterules
│ │ ├── tokenizers.lua
│ │ ├── types.lua
│ │ ├── ui/
│ │ │ ├── acp_confirm_adapter.lua
│ │ │ ├── button_group_line.lua
│ │ │ ├── confirm.lua
│ │ │ ├── input/
│ │ │ │ ├── init.lua
│ │ │ │ └── providers/
│ │ │ │ ├── dressing.lua
│ │ │ │ ├── native.lua
│ │ │ │ └── snacks.lua
│ │ │ ├── line.lua
│ │ │ ├── prompt_input.lua
│ │ │ └── selector/
│ │ │ ├── init.lua
│ │ │ └── providers/
│ │ │ ├── fzf_lua.lua
│ │ │ ├── mini_pick.lua
│ │ │ ├── native.lua
│ │ │ ├── snacks.lua
│ │ │ └── telescope.lua
│ │ └── utils/
│ │ ├── diff2search_replace.lua
│ │ ├── environment.lua
│ │ ├── file.lua
│ │ ├── init.lua
│ │ ├── logo.lua
│ │ ├── lru_cache.lua
│ │ ├── lsp.lua
│ │ ├── path.lua
│ │ ├── platform.lua
│ │ ├── promptLogger.lua
│ │ ├── prompts.lua
│ │ ├── root.lua
│ │ ├── streaming_json_parser.lua
│ │ ├── test.lua
│ │ └── tokens.lua
│ ├── avante_lib.lua
│ └── cmp_avante/
│ ├── commands.lua
│ ├── mentions.lua
│ └── shortcuts.lua
├── luarc.json.template
├── plugin/
│ └── avante.lua
├── py/
│ └── rag-service/
│ ├── Dockerfile
│ ├── README.md
│ ├── gitconfig
│ ├── requirements.txt
│ ├── run.sh
│ ├── shell.nix
│ └── src/
│ ├── libs/
│ │ ├── __init__.py
│ │ ├── configs.py
│ │ ├── db.py
│ │ ├── logger.py
│ │ └── utils.py
│ ├── main.py
│ ├── models/
│ │ ├── __init__.py
│ │ ├── indexing_history.py
│ │ └── resource.py
│ ├── providers/
│ │ ├── __init__.py
│ │ ├── dashscope.py
│ │ ├── factory.py
│ │ ├── ollama.py
│ │ ├── openai.py
│ │ └── openrouter.py
│ └── services/
│ ├── __init__.py
│ ├── indexing_history.py
│ └── resource.py
├── pyrightconfig.json
├── ruff.toml
├── scripts/
│ ├── lua-typecheck.sh
│ ├── run-luatest.sh
│ └── setup-deps.sh
├── stylua.toml
├── syntax/
│ └── jinja.vim
└── tests/
├── data/
│ ├── claude_token_error_response.json
│ └── claude_token_response.json
├── libs/
│ ├── acp_client_spec.lua
│ └── jsonparser_spec.lua
├── llm_spec.lua
├── llm_tools/
│ └── helpers_spec.lua
├── llm_tools_spec.lua
├── providers/
│ ├── bedrock_spec.lua
│ ├── claude_spec.lua
│ └── watsonx_code_assistant_spec.lua
├── rag_service_spec.lua
├── ui/
│ └── acp_confirm_adapter_spec.lua
└── utils/
├── file_spec.lua
├── fix_diff_spec.lua
├── get_parent_path_spec.lua
├── init_spec.lua
├── join_paths_spec.lua
├── make_relative_path_spec.lua
└── streaming_json_parser_spec.lua
================================================
FILE CONTENTS
================================================
================================================
FILE: .cargo/config.toml
================================================
[target.x86_64-apple-darwin]
rustflags = ["-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup"]
[target.aarch64-apple-darwin]
rustflags = ["-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup"]
[target.x86_64-unknown-linux-musl]
rustflags = ["-C", "target-feature=-crt-static"]
================================================
FILE: .editorconfig
================================================
; https://editorconfig.org/
root = true
[*]
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
tab_width = 8
[{Makefile,**/Makefile}]
indent_style = tab
indent_size = 8
================================================
FILE: .gitattributes
================================================
* text=auto eol=lf
**/*.lock linguist-generated=true
*.avanterules linguist-language=jinja
syntax/jinja.vim linguist-vendored
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: 🐛 Bug Report
description: Create a bug report to help us improve Avante
title: 'bug: '
labels: ['bug']
body:
- type: markdown
id: issue-already-exists
attributes:
value: |
Please search to see if an issue already exists for the bug you encountered.
See [Searching Issues and Pull Requests](https://docs.github.com/en/search-github/searching-on-github/searching-issues-and-pull-requests) for how to use the GitHub search bar and filters.
- type: textarea
id: describe-the-bug
validations:
required: true
attributes:
label: Describe the bug
description: Please provide a clear and concise description about the problem you ran into.
placeholder: This happened when I ...
- type: textarea
id: to-reproduce
validations:
required: false
attributes:
label: To reproduce
description: |
Please provide a code sample or a code snippet to reproduce said problem. If you have code snippets, error messages, or a stack trace please also provide them here.
**IMPORTANT**: make sure to use [code tags](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) to correctly format your code. Screenshots are helpful but don't use them for code snippets as they don't allow others to copy-and-paste your code.
placeholder: |
Give a minimal config to reproduce the issue.
- type: textarea
id: expected-behavior
validations:
required: false
attributes:
label: Expected behavior
description: 'A clear and concise description of what you would expect to happen.'
- type: textarea
id: how-to-install
validations:
required: true
attributes:
label: Installation method
description: |
Please share your installation method with us.
value: |
Use lazy.nvim:
```lua
{
"yetone/avante.nvim",
event = "VeryLazy",
lazy = false,
version = false, -- set this if you want to always pull the latest change
opts = {
-- add any opts here
},
-- if you want to build from source then do `make BUILD_FROM_SOURCE=true`
build = "make",
-- build = "powershell -ExecutionPolicy Bypass -File Build.ps1 -BuildFromSource false" -- for windows
dependencies = {
"nvim-lua/plenary.nvim",
"MunifTanjim/nui.nvim",
},
}
```
- type: textarea
id: environment-info
attributes:
label: Environment
description: |
Please share your environment with us, including your neovim version using `nvim -v` and `uname -a`.
placeholder: |
neovim version: ...
distribution (if any): ...
platform: ...
validations:
required: true
- type: textarea
attributes:
label: Repro
description: Minimal `init.lua` to reproduce this issue. Save as `repro.lua` and run with `nvim -u repro.lua`
value: |
vim.env.LAZY_STDPATH = ".repro"
load(vim.fn.system("curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua"))()
require("lazy.minit").repro({
spec = {
-- add any other plugins here
},
})
render: lua
validations:
required: false
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
version: 2.1
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
name: 🚀 Feature Request
description: Submit a proposal/request for new Avante feature.
title: 'feature: '
labels: ['new-feature', 'enhancement']
body:
- type: textarea
id: feature-request
validations:
required: true
attributes:
label: Feature request
description: |
A clear and concise description of the feature request.
placeholder: |
I would like it if...
- type: textarea
id: motivation
validations:
required: false
attributes:
label: Motivation
description: |
Please outline the motivation for this feature request. Is your feature request related to a problem? e.g., I'm always frustrated when [...].
If this is related to another issue, please link here too.
If you have a current workaround, please also provide it here.
placeholder: |
This feature would solve ...
- type: textarea
id: other
attributes:
label: Other
description: |
Is there any way that you could help, e.g. by submitting a PR?
placeholder: |
I would love to contribute ...
================================================
FILE: .github/workflows/close-stale-issues-and-prs.yaml
================================================
name: 'Close stale issues and PRs'
on:
schedule:
- cron: '30 1 * * *'
permissions:
contents: write # only for delete-branch option
issues: write
pull-requests: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
stale-pr-message: 'This PR is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 10 days.'
close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.'
close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity.'
days-before-issue-stale: 30
days-before-pr-stale: 14
days-before-issue-close: 5
days-before-pr-close: 10
================================================
FILE: .github/workflows/lua.yaml
================================================
name: Lua CI
on:
push:
branches:
- main
paths:
- "**/*.lua"
- .github/workflows/lua.yaml
pull_request:
branches:
- main
paths:
- "**/*.lua"
- .github/workflows/lua.yaml
jobs:
# reference from: https://github.com/nvim-lua/plenary.nvim/blob/2d9b06177a975543726ce5c73fca176cedbffe9d/.github/workflows/default.yml#L6C3-L43C20
run_tests:
name: unit tests
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
rev: v0.10.0
steps:
- uses: actions/checkout@v6
- id: todays-date
run: echo "date=$(date +%F)" >> "$GITHUB_OUTPUT"
- name: Restore cache for today's nightly.
id: cache-neovim
uses: actions/cache@v4
with:
path: _neovim
key: ${{ runner.os }}-${{ matrix.rev }}-${{ steps.todays-date.outputs.date }}
- name: Download neovim ${{ matrix.rev }}
env:
GH_TOKEN: ${{ github.token }}
NEOVIM_VERSION: ${{ matrix.rev }}
if: steps.cache-neovim.outputs.cache-hit != 'true'
run: |
mkdir -p _neovim
gh release download \
--output - \
--pattern nvim-linux64.tar.gz \
--repo neovim/neovim \
"$NEOVIM_VERSION" | tar xvz --strip-components 1 --directory _neovim
- name: Prepare
run: |
sudo apt-get update
sudo apt-get install -y ripgrep
sudo apt-get install -y silversearcher-ag
echo "${PWD}/_neovim/bin" >> "$GITHUB_PATH"
echo VIM="${PWD}/_neovim/share/nvim/runtime" >> "$GITHUB_ENV"
- name: Run tests
run: |
nvim --version
make luatest
typecheck:
name: Typecheck
runs-on: ubuntu-latest
strategy:
matrix:
nvim_version: [ stable ]
luals_version: [ 3.13.6 ]
steps:
- uses: actions/checkout@v6
- uses: rhysd/action-setup-vim@v1
with:
neovim: true
version: ${{ matrix.nvim_version }}
- name: Typecheck
env:
VIMRUNTIME: /home/runner/nvim-${{ matrix.nvim_version }}/share/nvim/runtime
run: |
make lua-typecheck
================================================
FILE: .github/workflows/pre-commit.yaml
================================================
name: pre-commit
on:
pull_request:
types: [labeled, opened, reopened, synchronize]
push:
branches: [main, test-me-*]
jobs:
pre-commit:
if: "github.event.action != 'labeled' || github.event.label.name == 'pre-commit ci run'"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: gh pr edit ${{ github.event.number }} --remove-label 'pre-commit ci run'
if: github.event.action == 'labeled' && github.event.label.name == 'pre-commit ci run'
env:
GH_TOKEN: ${{ github.token }}
- uses: actions/setup-python@v3
with:
python-version: '3.11'
- name: Install uv
uses: astral-sh/setup-uv@v5
- run: |
uv venv
source .venv/bin/activate
uv pip install -r py/rag-service/requirements.txt
- uses: leafo/gh-actions-lua@v11
- uses: leafo/gh-actions-luarocks@v5
- run: luarocks install luacheck
- name: Install stylua from crates.io
uses: baptiste0928/cargo-install@v3
with:
crate: stylua
args: --features lua54
- uses: pre-commit/action@v3.0.1
- uses: pre-commit-ci/lite-action@v1.1.0
if: always()
================================================
FILE: .github/workflows/release.yaml
================================================
name: Release
on:
push:
tags: [v\d+\.\d+\.\d+]
permissions:
contents: write
packages: write
env:
CARGO_TERM_COLOR: always
jobs:
create-release:
permissions:
contents: write
runs-on: ubuntu-24.04
outputs:
release_id: ${{ steps.create-release.outputs.id }}
release_upload_url: ${{ steps.create-release.outputs.upload_url }}
release_body: "${{ steps.tag.outputs.message }}"
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4
- name: Get version
id: get_version
uses: battila7/get-version-action@d97fbc34ceb64d1f5d95f4dfd6dce33521ccccf5 # ratchet:battila7/get-version-action@v2
- name: Get tag message
id: tag
run: |
git fetch --depth=1 origin +refs/tags/*:refs/tags/*
echo "message<<EOF" >> $GITHUB_OUTPUT
echo "$(git tag -l --format='%(contents)' ${{ steps.get_version.outputs.version }})" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Create Release
id: create-release
uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5 # ratchet:ncipollo/release-action@v1
with:
draft: true
name: "avante-libs ${{ steps.get_version.outputs.version }}"
tag: ${{ steps.get_version.outputs.version }}
body: "${{ steps.tag.outputs.message }}"
releases-matrix:
needs: [create-release]
strategy:
fail-fast: false
matrix:
feature: [lua51, luajit]
config:
- os: ubuntu-24.04-arm
os_name: linux
arch: aarch64
rust_target: aarch64-unknown-linux-gnu
docker_platform: linux/aarch64
container: quay.io/pypa/manylinux2014_aarch64
- os: ubuntu-latest
os_name: linux
arch: x86_64
rust_target: x86_64-unknown-linux-gnu
docker_platform: linux/amd64
container: quay.io/pypa/manylinux2014_x86_64 # for glibc 2.17
- os: macos-13
os_name: darwin
arch: x86_64
rust_target: x86_64-apple-darwin
- os: macos-latest
os_name: darwin
arch: aarch64
rust_target: aarch64-apple-darwin
- os: windows-latest
os_name: windows
arch: x86_64
rust_target: x86_64-pc-windows-msvc
- os: windows-latest
os_name: windows
arch: aarch64
rust_target: aarch64-pc-windows-msvc
runs-on: ${{ matrix.config.os }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4
- uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # ratchet:Swatinem/rust-cache@v2
if: ${{ matrix.config.container == null }}
- uses: dtolnay/rust-toolchain@7b1c307e0dcbda6122208f10795a713336a9b35a # ratchet:dtolnay/rust-toolchain@master
if: ${{ matrix.config.container == null }}
with:
targets: ${{ matrix.config.rust_target }}
toolchain: "1.85.0"
- name: Build all crates
if: ${{ matrix.config.container == null }}
run: |
cargo build --release --features ${{ matrix.feature }}
- name: Build all crates with glibc 2.17 # for glibc 2.17
if: ${{ matrix.config.container != null }}
run: |
# sudo apt-get install -y qemu qemu-user-static
docker run \
--rm \
-v $(pwd):/workspace \
-w /workspace \
--platform ${{ matrix.config.docker_platform }} \
${{ matrix.config.container }} \
bash -c "yum install -y perl-IPC-Cmd openssl-devel && curl --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal && . /root/.cargo/env && cargo build --release --features ${{ matrix.feature }}"
- name: Handle binaries
if: ${{ matrix.config.os_name != 'windows' }}
shell: bash
run: |
mkdir -p results
if [ "${{ matrix.config.os_name }}" == "linux" ]; then
EXT="so"
else
EXT="dylib"
fi
cp target/release/libavante_templates.$EXT results/avante_templates.$EXT
cp target/release/libavante_tokenizers.$EXT results/avante_tokenizers.$EXT
cp target/release/libavante_repo_map.$EXT results/avante_repo_map.$EXT
cp target/release/libavante_html2md.$EXT results/avante_html2md.$EXT
cd results
tar zcvf avante_lib-${{ matrix.config.os_name }}-${{ matrix.config.arch }}-${{ matrix.feature }}.tar.gz *.${EXT}
- name: Handle binaries (Windows)
if: ${{ matrix.config.os_name == 'windows' }}
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path results
Copy-Item -Path "target\release\avante_templates.dll" -Destination "results\avante_templates.dll"
Copy-Item -Path "target\release\avante_tokenizers.dll" -Destination "results\avante_tokenizers.dll"
Copy-Item -Path "target\release\avante_repo_map.dll" -Destination "results\avante_repo_map.dll"
Copy-Item -Path "target\release\avante_html2md.dll" -Destination "results\avante_html2md.dll"
Set-Location -Path results
$dllFiles = Get-ChildItem -Filter "*.dll" | Select-Object -ExpandProperty Name
Compress-Archive -Path $dllFiles -DestinationPath "avante_lib-${{ matrix.config.os_name }}-${{ matrix.config.arch }}-${{ matrix.feature }}.zip"
- name: Upload Release Asset
uses: shogo82148/actions-upload-release-asset@8482bd769644976d847e96fb4b9354228885e7b4 # ratchet:shogo82148/actions-upload-release-asset@v1
if: ${{ matrix.config.os_name != 'windows' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ASSET_NAME: avante_lib-${{ matrix.config.os_name }}-${{ matrix.config.arch }}-${{ matrix.feature }}.tar.gz
with:
upload_url: ${{ needs.create-release.outputs.release_upload_url }}
asset_path: ./results/avante_lib-${{ matrix.config.os_name }}-${{ matrix.config.arch }}-${{ matrix.feature }}.tar.gz
- name: Upload Release Asset (Windows)
uses: shogo82148/actions-upload-release-asset@8482bd769644976d847e96fb4b9354228885e7b4 # ratchet:shogo82148/actions-upload-release-asset@v1
if: ${{ matrix.config.os_name == 'windows' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ASSET_NAME: avante_lib-${{ matrix.config.os_name }}-${{ matrix.config.arch }}-${{ matrix.feature }}.zip
with:
upload_url: ${{ needs.create-release.outputs.release_upload_url }}
asset_path: ./results/avante_lib-${{ matrix.config.os_name }}-${{ matrix.config.arch }}-${{ matrix.feature }}.zip
publish-release:
permissions:
contents: write
runs-on: ubuntu-24.04
needs: [create-release, releases-matrix]
steps:
- name: publish release
id: publish-release
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # ratchet:actions/github-script@v6
env:
release_id: ${{ needs.create-release.outputs.release_id }}
with:
script: |
github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: process.env.release_id,
draft: false,
prerelease: false
})
================================================
FILE: .github/workflows/rust.yaml
================================================
name: Rust CI
on:
push:
branches:
- main
paths:
- "crates/**/*"
- "Cargo.lock"
- "Cargo.toml"
pull_request:
branches:
- main
paths:
- "crates/**/*"
- "Cargo.lock"
- "Cargo.toml"
jobs:
tests:
name: Run Rust tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # ratchet:actions/checkout@v4
- uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # ratchet:Swatinem/rust-cache@v2
- uses: dtolnay/rust-toolchain@7b1c307e0dcbda6122208f10795a713336a9b35a # ratchet:dtolnay/rust-toolchain@master
with:
toolchain: stable
components: clippy, rustfmt
- name: Run rust tests
run: cargo test --features luajit
================================================
FILE: .gitignore
================================================
*.so
# Lua compiled files
*.lua~
*.luac
.venv
__pycache__/
# Neovim plugin specific files
plugin/packer_compiled.lua
# OS generated files
.DS_Store
Thumbs.db
# Editor/IDE generated files
*.swp
*.swo
*~
.vscode/
.idea/
# Dependency manager generated directories
/lua_modules/
/.luarocks/
# Log files
*.log
# Temporary files
tmp/
temp/
# Environment variable files (if you use .env file to store API keys)
.env
.envrc
# If you use any build tools, you might need to ignore build output directories
build/
dist/
# If you use any test frameworks, you might need to ignore test coverage reports
coverage/
# If you use documentation generation tools, you might need to ignore generated docs
doc/
# If you have any personal configuration files, you should ignore them too
config.personal.lua
target
================================================
FILE: .luacheckrc
================================================
-- Rerun tests only if their modification time changed.
cache = true
-- Glorious list of warnings: https://luacheck.readthedocs.io/en/stable/warnings.html
ignore = {
'211',
'631',
'212', -- Unused argument, In the case of callback function, _arg_name is easier to understand than _, so this option is set to off.
'411', -- Redefining a local variable.
'412', -- Redefining an argument.
'422', -- Shadowing an argument
'431', -- Shadowing a variable
'122', -- Indirectly setting a readonly global
}
-- Global objects defined by the C code
read_globals = {
'vim',
'Snacks',
}
================================================
FILE: .pre-commit-config.yaml
================================================
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-ast # 检查Python语法错误
- id: debug-statements # 检查是否有debug语句
- id: check-added-large-files
- id: check-merge-conflict
- repo: https://github.com/JohnnyMorganz/StyLua
rev: v2.0.2
hooks:
- id: stylua-system # or stylua-system / stylua-github
files: \.lua$
- repo: https://github.com/Calinou/pre-commit-luacheck
rev: v1.0.0
hooks:
- id: luacheck
- repo: https://github.com/doublify/pre-commit-rust
rev: v1.0
hooks:
- id: fmt
files: \.rs$
- id: cargo-check
args: ['--features', 'luajit']
files: \.rs$
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.9
hooks:
# 运行 Ruff linter
- id: ruff
args: [--fix]
# 运行 Ruff formatter
- id: ruff-format
- repo: https://github.com/RobertCraigie/pyright-python
rev: v1.1.395
hooks:
- id: pyright
additional_dependencies:
- "types-setuptools"
- "types-requests"
================================================
FILE: Build.ps1
================================================
param (
[string]$Version = "luajit",
[string]$BuildFromSource = "false"
)
$Build = [System.Convert]::ToBoolean($BuildFromSource)
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
$BuildDir = "build"
$REPO_OWNER = "yetone"
$REPO_NAME = "avante.nvim"
function Build-FromSource($feature) {
if (-not (Test-Path $BuildDir)) {
New-Item -ItemType Directory -Path $BuildDir | Out-Null
}
cargo build --release --features=$feature
$SCRIPT_DIR = $PSScriptRoot
$targetTokenizerFile = "avante_tokenizers.dll"
$targetTemplatesFile = "avante_templates.dll"
$targetRepoMapFile = "avante_repo_map.dll"
Copy-Item (Join-Path $SCRIPT_DIR "target\release\avante_tokenizers.dll") (Join-Path $BuildDir $targetTokenizerFile)
Copy-Item (Join-Path $SCRIPT_DIR "target\release\avante_templates.dll") (Join-Path $BuildDir $targetTemplatesFile)
Copy-Item (Join-Path $SCRIPT_DIR "target\release\avante_repo_map.dll") (Join-Path $BuildDir $targetRepoMapFile)
Remove-Item -Recurse -Force "target"
}
function Test-Command($cmdname) {
return $null -ne (Get-Command $cmdname -ErrorAction SilentlyContinue)
}
function Test-GHAuth {
try {
$null = gh api user
return $true
} catch {
return $false
}
}
function Download-Prebuilt($feature, $tag) {
$SCRIPT_DIR = $PSScriptRoot
# Set the target directory to clone the artifact
$TARGET_DIR = Join-Path $SCRIPT_DIR "build"
# Set the platform to Windows
$PLATFORM = "windows"
$ARCH = "x86_64"
if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") {
$ARCH = "aarch64"
}
# Set the Lua version (lua51 or luajit)
$LUA_VERSION = if ($feature) { $feature } else { "luajit" }
# Set the artifact name pattern
$ARTIFACT_NAME_PATTERN = "avante_lib-$PLATFORM-$ARCH-$LUA_VERSION"
$TempFile = Get-Item ([System.IO.Path]::GetTempFilename()) | Rename-Item -NewName { $_.Name + ".zip" } -PassThru
if ((Test-Command "gh") -and (Test-GHAuth)) {
write-host "Using GitHub CLI to download artifacts..."
gh release download $latestTag --repo "$REPO_OWNER/$REPO_NAME" --pattern "*$ARTIFACT_NAME_PATTERN*" --output $TempFile --clobber
} else {
# Get the artifact download URL
$RELEASE = Invoke-RestMethod -Uri "https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/releases/tags/$tag"
$ARTIFACT_URL = $RELEASE.assets | Where-Object { $_.name -like "*$ARTIFACT_NAME_PATTERN*" } | Select-Object -ExpandProperty browser_download_url
# Download and extract the artifact
Invoke-WebRequest -Uri $ARTIFACT_URL -OutFile $TempFile
}
# Create target directory if it doesn't exist
if (-not (Test-Path $TARGET_DIR)) {
New-Item -ItemType Directory -Path $TARGET_DIR | Out-Null
}
Expand-Archive -Path $TempFile -DestinationPath $TARGET_DIR -Force
Remove-Item $TempFile
}
function Main {
Set-Location $PSScriptRoot
if ($Build) {
Write-Host "Building for $Version..."
Build-FromSource $Version
} else {
$latestTag = git describe --tags --abbrev=0 2>&1 | Where-Object { $_ -ne $null }
$builtTag = if (Test-Path "build/.tag") {
Get-Content "build/.tag"
} else {
$null
}
function Save-Tag($tag) {
$tag | Set-Content "build/.tag"
}
if ($latestTag -eq $builtTag -and $latestTag) {
Write-Host "Local build is up to date. No download needed."
} elseif ($latestTag -ne $builtTag -and $latestTag) {
Write-Host "Downloading prebuilt binaries $latestTag for $Version..."
Download-Prebuilt $Version $latestTag
Save-Tag $latestTag
} else {
cargo build --release --features=$Version
Get-ChildItem -Path "target/release/avante_*.dll" | ForEach-Object {
Copy-Item $_.FullName "build/$($_.Name)"
}
Save-Tag $latestTag
}
}
Write-Host "Completed!"
}
# Run the main function
Main
================================================
FILE: Cargo.toml
================================================
[workspace]
members = ["crates/*"]
resolver = "2"
[workspace.package]
edition = "2021"
rust-version = "1.80"
license = "Apache-2.0"
version = "0.1.0"
[workspace.dependencies]
avante-tokenizers = { path = "crates/avante-tokenizers" }
avante-templates = { path = "crates/avante-templates" }
avante-repo-map = { path = "crates/avante-repo-map" }
avante-html2md = { path = "crates/avante-html2md" }
minijinja = { version = "2.4.0", features = [
"loader",
"json",
"fuel",
"unicode",
"speedups",
"custom_syntax",
"loop_controls",
] }
mlua = { version = "0.10.0", features = ["module", "serialize"] }
tiktoken-rs = { version = "0.6.0" }
tokenizers = { version = "0.20.0", features = [
"esaxx_fast",
"http",
"unstable_wasm",
"onig",
], default-features = false }
serde = { version = "1.0.209", features = ["derive"] }
[workspace.lints.rust]
unsafe_code = "warn"
unreachable_pub = "warn"
[workspace.lints.clippy]
pedantic = { level = "warn", priority = -2 }
# Allowed pedantic lints
char_lit_as_u8 = "allow"
collapsible_else_if = "allow"
collapsible_if = "allow"
implicit_hasher = "allow"
map_unwrap_or = "allow"
match_same_arms = "allow"
missing_errors_doc = "allow"
missing_panics_doc = "allow"
module_name_repetitions = "allow"
must_use_candidate = "allow"
similar_names = "allow"
too_many_lines = "allow"
too_many_arguments = "allow"
# Disallowed restriction lints
print_stdout = "warn"
print_stderr = "warn"
dbg_macro = "warn"
empty_drop = "warn"
empty_structs_with_brackets = "warn"
exit = "warn"
get_unwrap = "warn"
rc_buffer = "warn"
rc_mutex = "warn"
rest_pat_in_fully_bound_structs = "warn"
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Makefile
================================================
UNAME := $(shell uname)
ARCH := $(shell uname -m)
ifeq ($(UNAME), Linux)
OS := linux
EXT := so
else ifeq ($(UNAME), Darwin)
OS := macOS
EXT := dylib
else
$(error Unsupported operating system: $(UNAME))
endif
LUA_VERSIONS := luajit lua51
BUILD_DIR := build
BUILD_FROM_SOURCE ?= false
TARGET_LIBRARY ?= all
RAG_SERVICE_VERSION ?= 0.0.11
RAG_SERVICE_IMAGE := quay.io/yetoneful/avante-rag-service:$(RAG_SERVICE_VERSION)
all: luajit
define make_definitions
ifeq ($(BUILD_FROM_SOURCE),true)
ifeq ($(TARGET_LIBRARY), all)
$1: $(BUILD_DIR)/libAvanteTokenizers-$1.$(EXT) $(BUILD_DIR)/libAvanteTemplates-$1.$(EXT) $(BUILD_DIR)/libAvanteRepoMap-$1.$(EXT) $(BUILD_DIR)/libAvanteHtml2md-$1.$(EXT)
else ifeq ($(TARGET_LIBRARY), tokenizers)
$1: $(BUILD_DIR)/libAvanteTokenizers-$1.$(EXT)
else ifeq ($(TARGET_LIBRARY), templates)
$1: $(BUILD_DIR)/libAvanteTemplates-$1.$(EXT)
else ifeq ($(TARGET_LIBRARY), repo-map)
$1: $(BUILD_DIR)/libAvanteRepoMap-$1.$(EXT)
else ifeq ($(TARGET_LIBRARY), html2md)
$1: $(BUILD_DIR)/libAvanteHtml2md-$1.$(EXT)
else
$$(error TARGET_LIBRARY must be one of all, tokenizers, templates, repo-map, html2md)
endif
else
$1:
LUA_VERSION=$1 bash ./build.sh
endif
endef
$(foreach lua_version,$(LUA_VERSIONS),$(eval $(call make_definitions,$(lua_version))))
define build_package
$1-$2:
cargo build --release --features=$1 -p avante-$2
cp target/release/libavante_$(shell echo $2 | tr - _).$(EXT) $(BUILD_DIR)/avante_$(shell echo $2 | tr - _).$(EXT)
endef
define build_targets
$(BUILD_DIR)/libAvanteTokenizers-$1.$(EXT): $(BUILD_DIR) $1-tokenizers
$(BUILD_DIR)/libAvanteTemplates-$1.$(EXT): $(BUILD_DIR) $1-templates
$(BUILD_DIR)/libAvanteRepoMap-$1.$(EXT): $(BUILD_DIR) $1-repo-map
$(BUILD_DIR)/libAvanteHtml2md-$1.$(EXT): $(BUILD_DIR) $1-html2md
endef
$(foreach lua_version,$(LUA_VERSIONS),$(eval $(call build_package,$(lua_version),tokenizers)))
$(foreach lua_version,$(LUA_VERSIONS),$(eval $(call build_package,$(lua_version),templates)))
$(foreach lua_version,$(LUA_VERSIONS),$(eval $(call build_package,$(lua_version),repo-map)))
$(foreach lua_version,$(LUA_VERSIONS),$(eval $(call build_package,$(lua_version),html2md)))
$(foreach lua_version,$(LUA_VERSIONS),$(eval $(call build_targets,$(lua_version))))
$(BUILD_DIR):
@mkdir -p $(BUILD_DIR)
clean:
@rm -rf $(BUILD_DIR)
luacheck:
@luacheck `find \( -path './target' -prune \) -o -name "*.lua" -print` --codes
luastylecheck:
@stylua --check lua/ plugin/ tests/
stylefix:
@stylua lua/ plugin/
.PHONY: ruststylecheck
ruststylecheck:
@rustup component add rustfmt 2> /dev/null
@cargo fmt --all -- --check
.PHONY: rustlint
rustlint:
@rustup component add clippy 2> /dev/null
@cargo clippy -F luajit --all -- -F clippy::dbg-macro -D warnings
.PHONY: rusttest
rusttest:
@cargo test --features luajit
.PHONY: luatest
luatest:
@./scripts/run-luatest.sh
.PHONY: lint
lint: luacheck luastylecheck ruststylecheck rustlint
.PHONY: lua-typecheck
lua-typecheck:
@./scripts/lua-typecheck.sh
.PHONY: build-image
build-image:
docker build --platform=linux/amd64 -t $(RAG_SERVICE_IMAGE) -f py/rag-service/Dockerfile py/rag-service
.PHONY: push-image
push-image: build-image
docker push $(RAG_SERVICE_IMAGE)
================================================
FILE: README.md
================================================
<div align="center">
<img alt="logo" width="120" src="https://github.com/user-attachments/assets/2e2f2a58-2b28-4d11-afd1-87b65612b2de" />
<h1>avante.nvim</h1>
</div>
<p align="center">
<a href="https://neovim.io/" target="_blank"><img src="https://img.shields.io/static/v1?style=flat-square&label=Neovim&message=v0.10%2b&logo=neovim&labelColor=282828&logoColor=8faa80&color=414b32" alt="Neovim: v0.10+" /></a>
<a href="https://github.com/yetone/avante.nvim/actions/workflows/lua.yaml" target="_blank"><img src="https://img.shields.io/github/actions/workflow/status/yetone/avante.nvim/lua.yaml?style=flat-square&logo=lua&logoColor=c7c7c7&label=Lua+CI&labelColor=1E40AF&color=347D39&event=push" alt="Lua CI status" /></a>
<a href="https://github.com/yetone/avante.nvim/actions/workflows/rust.yaml" target="_blank"><img src="https://img.shields.io/github/actions/workflow/status/yetone/avante.nvim/rust.yaml?style=flat-square&logo=rust&logoColor=ffffff&label=Rust+CI&labelColor=BC826A&color=347D39&event=push" alt="Rust CI status" /></a>
<a href="https://github.com/yetone/avante.nvim/actions/workflows/pre-commit.yaml" target="_blank"><img src="https://img.shields.io/github/actions/workflow/status/yetone/avante.nvim/pre-commit.yaml?style=flat-square&logo=pre-commit&logoColor=ffffff&label=pre-commit&labelColor=FAAF3F&color=347D39&event=push" alt="pre-commit status" /></a>
<a href="https://discord.gg/QfnEFEdSjz" target="_blank"><img src="https://img.shields.io/discord/1302530866362323016?style=flat-square&logo=discord&label=Discord&logoColor=ffffff&labelColor=7376CF&color=268165" alt="Discord" /></a>
<a href="https://dotfyle.com/plugins/yetone/avante.nvim"><img src="https://dotfyle.com/plugins/yetone/avante.nvim/shield?style=flat-square" /></a>
</p>
**avante.nvim** is a Neovim plugin designed to emulate the behaviour of the [Cursor](https://www.cursor.com) AI IDE. It provides users with AI-driven code suggestions and the ability to apply these recommendations directly to their source files with minimal effort.
[查看中文版](README_zh.md)
> [!NOTE]
>
> 🥰 This project is undergoing rapid iterations, and many exciting features will be added successively. Stay tuned!
<https://github.com/user-attachments/assets/510e6270-b6cf-459d-9a2f-15b397d1fe53>
<https://github.com/user-attachments/assets/86140bfd-08b4-483d-a887-1b701d9e37dd>
## Sponsorship ❤️
If you like this project, please consider supporting me on Patreon, as it helps me to continue maintaining and improving it:
[Sponsor me](https://patreon.com/yetone)
## Features
- **AI-Powered Code Assistance**: Interact with AI to ask questions about your current code file and receive intelligent suggestions for improvement or modification.
- **One-Click Application**: Quickly apply the AI's suggested changes to your source code with a single command, streamlining the editing process and saving time.
- **Project-Specific Instruction Files**: Customize AI behavior by adding a markdown file (`avante.md` by default) in the project root. This file is automatically referenced during workspace changes. You can also configure a custom file name for tailored project instructions.
## Avante Zen Mode
Due to the prevalence of claude code, it is clear that this is an era of Coding Agent CLIs. As a result, there are many arguments like: in the Vibe Coding era, editors are no longer needed; you only need to use the CLI in the terminal. But have people realized that for more than half a century, Terminal-based Editors have solved and standardized the biggest problem with Terminal-based applications — that is, the awkward TUI interactions! No matter how much these Coding Agent CLIs optimize their UI/UX, their UI/UX will always be a subset of Terminal-based Editors (Vim, Emacs)! They cannot achieve Vim’s elegant action + text objects abstraction (imagine how you usually edit large multi-line prompts in an Agent CLI), nor can they leverage thousands of mature Vim/Neovim plugins to help optimize TUI UI/UX—such as easymotions and so on. Moreover, when they want to view or modify code, they often have to jump into other applications which forcibly interrupts the UI/UX experience.
Therefore, Avante’s Zen Mode was born! It looks like a Vibe Coding Agent CLI but it is completely Neovim underneath. So you can use your muscle-memory Vim operations and those rich and mature Neovim plugins on it. At the same time, by leveraging [ACP](https://github.com/yetone/avante.nvim#acp-support) it has all capabilities of claude code / gemini-cli / codex! Why not enjoy both?
Now all you need to do is alias this command to avante; then every time you simply type avante just like using claude code and enter Avante’s Zen Mode!
```bash
alias avante='nvim -c "lua vim.defer_fn(function()require(\"avante.api\").zen_mode()end, 100)"'
```
The effect is as follows:
<img alt="Avante Zen Mode" src="https://github.com/user-attachments/assets/60880f65-af55-4e4c-a565-23bb63e19251" />
## Project instructions with avante.md
<details>
<summary>
The `avante.md` file allows you to provide project-specific context and instructions to the ai. this file should be placed in your project root and will be automatically referenced during all interactions with avante.
</summary>
### Best practices for avante.md
to get the most out of your project instruction file, consider following this structure:
#### Your role
define the ai's persona and expertise level for your project:
```markdown
### your role
you are an expert senior software engineer specializing in [technology stack]. you have deep knowledge of [specific frameworks/tools] and understand best practices for [domain/industry]. you write clean, maintainable, and well-documented code. you prioritize code quality, performance, and security in all your recommendations.
```
#### Your mission
clearly describe what the ai should focus on and how it should help:
```markdown
### your mission
your primary goal is to help build and maintain [project description]. you should:
- provide code suggestions that follow our established patterns and conventions
- help debug issues by analyzing code and suggesting solutions
- assist with refactoring to improve code quality and maintainability
- suggest optimizations for performance and scalability
- ensure all code follows our security guidelines
- help write comprehensive tests for new features
```
#### Additional sections to consider
- **project context**: brief description of the project, its goals, and target users
- **technology stack**: list of technologies, frameworks, and tools used
- **coding standards**: specific conventions, style guides, and patterns to follow
- **architecture guidelines**: how components should interact and be organized
- **testing requirements**: testing strategies and coverage expectations
- **security considerations**: specific security requirements or constraints
### example avante.md
```markdown
# project instructions for myapp
## your role
you are an expert full-stack developer specializing in react, node.js, and typescript. you understand modern web development practices and have experience with our tech stack.
## your mission
help build a scalable e-commerce platform by:
- writing type-safe typescript code
- following react best practices and hooks patterns
- implementing restful apis with proper error handling
- ensuring responsive design with tailwind css
- writing comprehensive unit and integration tests
## project context
myapp is a modern e-commerce platform targeting small businesses. we prioritize performance, accessibility, and user experience.
## technology stack
- frontend: react 18, typescript, tailwind css, vite
- backend: node.js, express, prisma, postgresql
- testing: jest, react testing library, playwright
- deployment: docker, aws
## coding standards
- use functional components with hooks
- prefer composition over inheritance
- write self-documenting code with clear variable names
- add jsdoc comments for complex functions
- follow the existing folder structure and naming conventions
```
</details>
## Installation
For building binary if you wish to build from source, then `cargo` is required. Otherwise `curl` and `tar` will be used to get prebuilt binary from GitHub.
<details open>
<summary><a href="https://github.com/folke/lazy.nvim">lazy.nvim</a> (recommended)</summary>
```lua
{
"yetone/avante.nvim",
-- if you want to build from source then do `make BUILD_FROM_SOURCE=true`
-- ⚠️ must add this setting! ! !
build = vim.fn.has("win32") ~= 0
and "powershell -ExecutionPolicy Bypass -File Build.ps1 -BuildFromSource false"
or "make",
event = "VeryLazy",
version = false, -- Never set this value to "*"! Never!
---@module 'avante'
---@type avante.Config
opts = {
-- add any opts here
-- this file can contain specific instructions for your project
instructions_file = "avante.md",
-- for example
provider = "claude",
providers = {
claude = {
endpoint = "https://api.anthropic.com",
model = "claude-sonnet-4-20250514",
timeout = 30000, -- Timeout in milliseconds
extra_request_body = {
temperature = 0.75,
max_tokens = 20480,
},
},
moonshot = {
endpoint = "https://api.moonshot.ai/v1",
model = "kimi-k2-0711-preview",
timeout = 30000, -- Timeout in milliseconds
extra_request_body = {
temperature = 0.75,
max_tokens = 32768,
},
},
},
},
dependencies = {
"nvim-lua/plenary.nvim",
"MunifTanjim/nui.nvim",
--- The below dependencies are optional,
"nvim-mini/mini.pick", -- for file_selector provider mini.pick
"nvim-telescope/telescope.nvim", -- for file_selector provider telescope
"hrsh7th/nvim-cmp", -- autocompletion for avante commands and mentions
"ibhagwan/fzf-lua", -- for file_selector provider fzf
"stevearc/dressing.nvim", -- for input provider dressing
"folke/snacks.nvim", -- for input provider snacks
"nvim-tree/nvim-web-devicons", -- or echasnovski/mini.icons
"zbirenbaum/copilot.lua", -- for providers='copilot'
{
-- support for image pasting
"HakonHarnes/img-clip.nvim",
event = "VeryLazy",
opts = {
-- recommended settings
default = {
embed_image_as_base64 = false,
prompt_for_file_name = false,
drag_and_drop = {
insert_mode = true,
},
-- required for Windows users
use_absolute_path = true,
},
},
},
{
-- Make sure to set this up properly if you have lazy=true
'MeanderingProgrammer/render-markdown.nvim',
opts = {
file_types = { "markdown", "Avante" },
},
ft = { "markdown", "Avante" },
},
},
}
```
</details>
<details>
<summary>vim-plug</summary>
```vim
call plug#begin()
" Deps
Plug 'nvim-lua/plenary.nvim'
Plug 'MunifTanjim/nui.nvim'
Plug 'MeanderingProgrammer/render-markdown.nvim'
" Optional deps
Plug 'hrsh7th/nvim-cmp'
Plug 'nvim-tree/nvim-web-devicons' "or Plug 'echasnovski/mini.icons'
Plug 'HakonHarnes/img-clip.nvim'
Plug 'zbirenbaum/copilot.lua'
Plug 'stevearc/dressing.nvim' " for enhanced input UI
Plug 'folke/snacks.nvim' " for modern input UI
" Yay, pass source=true if you want to build from source
Plug 'yetone/avante.nvim', { 'branch': 'main', 'do': 'make' }
call plug#end()
autocmd! User avante.nvim
lua << EOF
require('avante').setup({})
EOF
```
</details>
<details>
<summary><a href="https://github.com/echasnovski/mini.deps">mini.deps</a></summary>
```lua
local add, later, now = MiniDeps.add, MiniDeps.later, MiniDeps.now
add({
source = 'yetone/avante.nvim',
monitor = 'main',
depends = {
'nvim-lua/plenary.nvim',
'MunifTanjim/nui.nvim',
'echasnovski/mini.icons'
},
hooks = { post_checkout = function() vim.cmd('make') end }
})
--- optional
add({ source = 'hrsh7th/nvim-cmp' })
add({ source = 'zbirenbaum/copilot.lua' })
add({ source = 'HakonHarnes/img-clip.nvim' })
add({ source = 'MeanderingProgrammer/render-markdown.nvim' })
later(function() require('render-markdown').setup({...}) end)
later(function()
require('img-clip').setup({...}) -- config img-clip
require("copilot").setup({...}) -- setup copilot to your liking
require("avante").setup({...}) -- config for avante.nvim
end)
```
</details>
<details>
<summary><a href="https://github.com/wbthomason/packer.nvim">Packer</a></summary>
```vim
-- Required plugins
use 'nvim-lua/plenary.nvim'
use 'MunifTanjim/nui.nvim'
use 'MeanderingProgrammer/render-markdown.nvim'
-- Optional dependencies
use 'hrsh7th/nvim-cmp'
use 'nvim-tree/nvim-web-devicons' -- or use 'echasnovski/mini.icons'
use 'HakonHarnes/img-clip.nvim'
use 'zbirenbaum/copilot.lua'
use 'stevearc/dressing.nvim' -- for enhanced input UI
use 'folke/snacks.nvim' -- for modern input UI
-- Avante.nvim with build process
use {
'yetone/avante.nvim',
branch = 'main',
run = 'make',
config = function()
require('avante').setup()
end
}
```
</details>
<details>
<summary><a href="https://github.com/nix-community/home-manager">Home Manager</a></summary>
```nix
programs.neovim = {
plugins = [
{
plugin = pkgs.vimPlugins.avante-nvim;
type = "lua";
config = ''
require("avante_lib").load()
require("avante").setup()
'' # or builtins.readFile ./plugins/avante.lua;
}
];
};
```
</details>
<details>
<summary><a href="https://nix-community.github.io/nixvim/plugins/avante/index.html">Nixvim</a></summary>
```nix
plugins.avante.enable = true;
plugins.avante.settings = {
# setup options here
};
```
</details>
<details>
<summary>Lua</summary>
```lua
-- deps:
require('cmp').setup ({
-- use recommended settings from above
})
require('img-clip').setup ({
-- use recommended settings from above
})
require('copilot').setup ({
-- use recommended settings from above
})
require('render-markdown').setup ({
-- use recommended settings from above
})
require('avante').setup({
-- Example: Using snacks.nvim as input provider
input = {
provider = "snacks", -- "native" | "dressing" | "snacks"
provider_opts = {
-- Snacks input configuration
title = "Avante Input",
icon = " ",
placeholder = "Enter your API key...",
},
},
-- Your other config here!
})
```
</details>
> [!IMPORTANT]
>
> `avante.nvim` is currently only compatible with Neovim 0.10.1 or later. Please ensure that your Neovim version meets these requirements before proceeding.
> [!NOTE]
>
> When loading the plugin synchronously, we recommend `require`ing it sometime after your colorscheme.
> [!NOTE]
>
> Recommended **Neovim** options:
>
> ```lua
> -- views can only be fully collapsed with the global statusline
> vim.opt.laststatus = 3
> ```
> [!TIP]
>
> Any rendering plugins that support markdown should work with Avante as long as you add the supported filetype `Avante`. See <https://github.com/yetone/avante.nvim/issues/175> and [this comment](https://github.com/yetone/avante.nvim/issues/175#issuecomment-2313749363) for more information.
### Default setup configuration
_See [config.lua#L9](./lua/avante/config.lua) for the full config_
<details>
<summary>Default configuration</summary>
```lua
{
---@alias Provider "claude" | "openai" | "azure" | "gemini" | "cohere" | "copilot" | string
---@type Provider
provider = "claude", -- The provider used in Aider mode or in the planning phase of Cursor Planning Mode
---@alias Mode "agentic" | "legacy"
---@type Mode
mode = "agentic", -- The default mode for interaction. "agentic" uses tools to automatically generate code, "legacy" uses the old planning method to generate code.
-- WARNING: 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`.
auto_suggestions_provider = "claude",
providers = {
claude = {
endpoint = "https://api.anthropic.com",
auth_type = "api" -- Set to "max" to sign in with Claude Pro/Max subscription
model = "claude-3-5-sonnet-20241022",
extra_request_body = {
temperature = 0.75,
max_tokens = 4096,
},
},
},
---Specify the special dual_boost mode
---1. enabled: Whether to enable dual_boost mode. Default to false.
---2. first_provider: The first provider to generate response. Default to "openai".
---3. second_provider: The second provider to generate response. Default to "claude".
---4. prompt: The prompt to generate response based on the two reference outputs.
---5. timeout: Timeout in milliseconds. Default to 60000.
---How it works:
--- When dual_boost is enabled, avante will generate two responses from the first_provider and second_provider respectively. Then use the response from the first_provider as provider1_output and the response from the second_provider as provider2_output. Finally, avante will generate a response based on the prompt and the two reference outputs, with the default Provider as normal.
---Note: This is an experimental feature and may not work as expected.
dual_boost = {
enabled = false,
first_provider = "openai",
second_provider = "claude",
prompt = "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}}]",
timeout = 60000, -- Timeout in milliseconds
},
behaviour = {
auto_suggestions = false, -- Experimental stage
auto_set_highlight_group = true,
auto_set_keymaps = true,
auto_apply_diff_after_generation = false,
support_paste_from_clipboard = false,
minimize_diff = true, -- Whether to remove unchanged lines when applying a code block
enable_token_counting = true, -- Whether to enable token counting. Default to true.
auto_add_current_file = true, -- Whether to automatically add the current file when opening a new chat. Default to true.
auto_approve_tool_permissions = true, -- Default: auto-approve all tools (no prompts)
-- Examples:
-- auto_approve_tool_permissions = false, -- Show permission prompts for all tools
-- auto_approve_tool_permissions = {"bash", "str_replace"}, -- Auto-approve specific tools only
---@type "popup" | "inline_buttons"
confirmation_ui_style = "inline_buttons",
--- Whether to automatically open files and navigate to lines when ACP agent makes edits
---@type boolean
acp_follow_agent_locations = true,
},
prompt_logger = { -- logs prompts to disk (timestamped, for replay/debugging)
enabled = true, -- toggle logging entirely
log_dir = vim.fn.stdpath("cache") .. "/avante_prompts", -- directory where logs are saved
fortune_cookie_on_success = false, -- shows a random fortune after each logged prompt (requires `fortune` installed)
next_prompt = {
normal = "<C-n>", -- load the next (newer) prompt log in normal mode
insert = "<C-n>",
},
prev_prompt = {
normal = "<C-p>", -- load the previous (older) prompt log in normal mode
insert = "<C-p>",
},
},
mappings = {
--- @class AvanteConflictMappings
diff = {
ours = "co",
theirs = "ct",
all_theirs = "ca",
both = "cb",
cursor = "cc",
next = "]x",
prev = "[x",
},
suggestion = {
accept = "<M-l>",
next = "<M-]>",
prev = "<M-[>",
dismiss = "<C-]>",
},
jump = {
next = "]]",
prev = "[[",
},
submit = {
normal = "<CR>",
insert = "<C-s>",
},
cancel = {
normal = { "<C-c>", "<Esc>", "q" },
insert = { "<C-c>" },
},
sidebar = {
apply_all = "A",
apply_cursor = "a",
retry_user_request = "r",
edit_user_request = "e",
switch_windows = "<Tab>",
reverse_switch_windows = "<S-Tab>",
remove_file = "d",
add_file = "@",
close = { "<Esc>", "q" },
close_from_input = nil, -- e.g., { normal = "<Esc>", insert = "<C-d>" }
},
},
selection = {
enabled = true,
hint_display = "delayed",
},
windows = {
---@type "right" | "left" | "top" | "bottom"
position = "right", -- the position of the sidebar
wrap = true, -- similar to vim.o.wrap
width = 30, -- default % based on available width
sidebar_header = {
enabled = true, -- true, false to enable/disable the header
align = "center", -- left, center, right for title
rounded = true,
},
spinner = {
editing = { "⡀", "⠄", "⠂", "⠁", "⠈", "⠐", "⠠", "⢀", "⣀", "⢄", "⢂", "⢁", "⢈", "⢐", "⢠", "⣠", "⢤", "⢢", "⢡", "⢨", "⢰", "⣰", "⢴", "⢲", "⢱", "⢸", "⣸", "⢼", "⢺", "⢹", "⣹", "⢽", "⢻", "⣻", "⢿", "⣿" },
generating = { "·", "✢", "✳", "∗", "✻", "✽" }, -- Spinner characters for the 'generating' state
thinking = { "🤯", "🙄" }, -- Spinner characters for the 'thinking' state
},
input = {
prefix = "> ",
height = 8, -- Height of the input window in vertical layout
},
edit = {
border = "rounded",
start_insert = true, -- Start insert mode when opening the edit window
},
ask = {
floating = false, -- Open the 'AvanteAsk' prompt in a floating window
start_insert = true, -- Start insert mode when opening the ask window
border = "rounded",
---@type "ours" | "theirs"
focus_on_apply = "ours", -- which diff to focus after applying
},
},
highlights = {
---@type AvanteConflictHighlights
diff = {
current = "DiffText",
incoming = "DiffAdd",
},
},
--- @class AvanteConflictUserConfig
diff = {
autojump = true,
---@type string | fun(): any
list_opener = "copen",
--- Override the 'timeoutlen' setting while hovering over a diff (see :help timeoutlen).
--- Helps to avoid entering operator-pending mode with diff mappings starting with `c`.
--- Disable by setting to -1.
override_timeoutlen = 500,
},
suggestion = {
debounce = 600,
throttle = 600,
},
}
```
</details>
## Blink.cmp users
For blink cmp users (nvim-cmp alternative) view below instruction for configuration
This is achieved by emulating nvim-cmp using blink.compat
or you can use [Kaiser-Yang/blink-cmp-avante](https://github.com/Kaiser-Yang/blink-cmp-avante).
<details>
<summary>Lua</summary>
```lua
selector = {
--- @alias avante.SelectorProvider "native" | "fzf_lua" | "mini_pick" | "snacks" | "telescope" | fun(selector: avante.ui.Selector): nil
--- @type avante.SelectorProvider
provider = "fzf",
-- Options override for custom providers
provider_opts = {},
}
```
To create a customized selector provider, you can specify a customized function to launch a picker to select items and pass the selected items to the `on_select` callback.
```lua
selector = {
---@param selector avante.ui.Selector
provider = function(selector)
local items = selector.items ---@type avante.ui.SelectorItem[]
local title = selector.title ---@type string
local on_select = selector.on_select ---@type fun(selected_item_ids: string[]|nil): nil
--- your customized picker logic here
end,
}
```
### Input Provider Configuration
Avante.nvim supports multiple input providers for user input (like API key entry). You can configure which provider to use:
<details>
<summary>Native Input Provider (Default)</summary>
```lua
{
input = {
provider = "native", -- Uses vim.ui.input
provider_opts = {},
}
}
```
</details>
<details>
<summary>Dressing.nvim Input Provider</summary>
For enhanced input UI with better styling and features:
```lua
{
input = {
provider = "dressing",
provider_opts = {},
}
}
```
You'll need to install dressing.nvim:
```lua
-- With lazy.nvim
{ "stevearc/dressing.nvim" }
```
</details>
<details>
<summary>Snacks.nvim Input Provider (Recommended)</summary>
For modern, feature-rich input UI:
```lua
{
input = {
provider = "snacks",
provider_opts = {
-- Additional snacks.input options
title = "Avante Input",
icon = " ",
},
}
}
```
You'll need to install snacks.nvim:
```lua
-- With lazy.nvim
{ "folke/snacks.nvim" }
```
</details>
<details>
<summary>Custom Input Provider</summary>
To create a customized input provider, you can specify a function:
```lua
{
input = {
---@param input avante.ui.Input
provider = function(input)
local title = input.title ---@type string
local default = input.default ---@type string
local conceal = input.conceal ---@type boolean
local on_submit = input.on_submit ---@type fun(result: string|nil): nil
--- your customized input logic here
end,
}
}
```
</details>
Choose a selector other that native, the default as that currently has an issue
For lazyvim users copy the full config for blink.cmp from the website or extend the options
```lua
compat = {
"avante_commands",
"avante_mentions",
"avante_files",
}
```
For other users just add a custom provider
### Available Completion Sources
Avante.nvim provides several completion sources that can be integrated with blink.cmp:
#### Mentions (`@` trigger)
Mentions allow you to quickly reference specific features or add files to the chat context:
- `@codebase` - Enable project context and repository mapping
- `@diagnostics` - Enable diagnostics information
- `@file` - Open file selector to add files to chat context
- `@quickfix` - Add files from quickfix list to chat context
- `@buffers` - Add open buffers to chat context
#### Slash Commands (`/` trigger)
Built-in slash commands for common operations:
- `/help` - Show help message with available commands
- `/init` - Initialize AGENTS.md based on current project
- `/clear` - Clear chat history
- `/new` - Start a new chat
- `/compact` - Compact history messages to save tokens
- `/lines <start>-<end> <question>` - Ask about specific lines
- `/commit` - Generate commit message for changes
#### Shortcuts (`#` trigger)
Shortcuts provide quick access to predefined prompt templates. You can customize these in your config:
```lua
{
shortcuts = {
{
name = "refactor",
description = "Refactor code with best practices",
details = "Automatically refactor code to improve readability, maintainability, and follow best practices while preserving functionality",
prompt = "Please refactor this code following best practices, improving readability and maintainability while preserving functionality."
},
{
name = "test",
description = "Generate unit tests",
details = "Create comprehensive unit tests covering edge cases, error scenarios, and various input conditions",
prompt = "Please generate comprehensive unit tests for this code, covering edge cases and error scenarios."
},
-- Add more custom shortcuts...
}
}
```
When you type `#refactor` in the input, it will automatically be replaced with the corresponding prompt text.
### Configuration Example
Here's a complete blink.cmp configuration example with all Avante sources:
```lua
default = {
...
"avante_commands",
"avante_mentions",
"avante_shortcuts",
"avante_files",
}
```
```lua
providers = {
avante_commands = {
name = "avante_commands",
module = "blink.compat.source",
score_offset = 90, -- show at a higher priority than lsp
opts = {},
},
avante_files = {
name = "avante_files",
module = "blink.compat.source",
score_offset = 100, -- show at a higher priority than lsp
opts = {},
},
avante_mentions = {
name = "avante_mentions",
module = "blink.compat.source",
score_offset = 1000, -- show at a higher priority than lsp
opts = {},
},
avante_shortcuts = {
name = "avante_shortcuts",
module = "blink.compat.source",
score_offset = 1000, -- show at a higher priority than lsp
opts = {},
}
...
}
```
</details>
## Usage
### Using Claude Pro/Max Subscription
To login with your Claude subscription, set the **auth_type** of the Claude provider entry in your config to "max", re-open Neovim then the authentication process will start in your browser. Once logged in and authorized, a code will show that needs to be copied into the prompt in Neovim, which should then give access to use your subscription with Avante.
You may need to run `AvanteSwitchProvider claude` to initiate the authentication if you previously had a different provider selected.
```lua
-- Providers = { ...
claude = {
-- ...
auth_type = "max",
},
```
### Basic Functionality
Given its early stage, `avante.nvim` currently supports the following basic functionalities:
> [!IMPORTANT]
>
> For most consistency between neovim session, it is recommended to set the environment variables in your shell file.
> By default, `Avante` will prompt you at startup to input the API key for the provider you have selected.
>
> **Scoped API Keys (Recommended for Isolation)**
>
> Avante now supports scoped API keys, allowing you to isolate API keys specifically for Avante without affecting other applications. Simply prefix any API key with `AVANTE_`:
>
> ```sh
> # Scoped keys (recommended)
> export AVANTE_ANTHROPIC_API_KEY=your-claude-api-key
> export AVANTE_OPENAI_API_KEY=your-openai-api-key
> export AVANTE_AZURE_OPENAI_API_KEY=your-azure-api-key
> export AVANTE_GEMINI_API_KEY=your-gemini-api-key
> export AVANTE_CO_API_KEY=your-cohere-api-key
> export AVANTE_AIHUBMIX_API_KEY=your-aihubmix-api-key
> export AVANTE_MOONSHOT_API_KEY=your-moonshot-api-key
> ```
>
> **Global API Keys (Legacy)**
>
> You can still use the traditional global API keys if you prefer:
>
> For Claude:
>
> ```sh
> export ANTHROPIC_API_KEY=your-api-key
> ```
>
> For OpenAI:
>
> ```sh
> export OPENAI_API_KEY=your-api-key
> ```
>
> For Azure OpenAI:
>
> ```sh
> export AZURE_OPENAI_API_KEY=your-api-key
> ```
>
> For Amazon Bedrock:
>
> You can specify the `BEDROCK_KEYS` environment variable to set credentials. When this variable is not specified, bedrock will use the default AWS credentials chain (see below).
>
> ```sh
> export BEDROCK_KEYS=aws_access_key_id,aws_secret_access_key,aws_region[,aws_session_token]
> ```
>
> Note: The aws_session_token is optional and only needed when using temporary AWS credentials
>
> Alternatively Bedrock tries to resolve AWS credentials using the [Default Credentials Provider Chain](https://docs.aws.amazon.com/cli/v1/userguide/cli-chap-authentication.html).
> This means you can have credentials e.g. configured via the AWS CLI, stored in your ~/.aws/profile, use AWS SSO etc.
> In this case `aws_region` and optionally `aws_profile` should be specified via the bedrock config, e.g.:
>
> ```lua
> bedrock = {
> model = "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
> aws_profile = "bedrock",
> aws_region = "us-east-1",
> },
> ```
>
> Note: Bedrock requires the [AWS CLI](https://aws.amazon.com/cli/) to be installed on your system.
1. Open a code file in Neovim.
2. Use the `:AvanteAsk` command to query the AI about the code.
3. Review the AI's suggestions.
4. Apply the recommended changes directly to your code with a simple command or key binding.
**Note**: The plugin is still under active development, and both its functionality and interface are subject to significant changes. Expect some rough edges and instability as the project evolves.
## Key Bindings
The following key bindings are available for use with `avante.nvim`:
| Key Binding | Description |
| ----------------------------------------- | -------------------------------------- |
| **Sidebar** | |
| <kbd>]</kbd><kbd>p</kbd> | next prompt |
| <kbd>[</kbd><kbd>p</kbd> | previous prompt |
| <kbd>A</kbd> | apply all |
| <kbd>a</kbd> | apply cursor |
| <kbd>r</kbd> | retry user request |
| <kbd>e</kbd> | edit user request |
| <kbd><Tab></kbd> | switch windows |
| <kbd><S-Tab></kbd> | reverse switch windows |
| <kbd>d</kbd> | remove file |
| <kbd>@</kbd> | add file |
| <kbd>q</kbd> | close sidebar |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>a</kbd> | show sidebar |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>t</kbd> | toggle sidebar visibility |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>r</kbd> | refresh sidebar |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>f</kbd> | switch sidebar focus |
| **Suggestion** | |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>?</kbd> | select model |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>n</kbd> | new ask |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>e</kbd> | edit selected blocks |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>S</kbd> | stop current AI request |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>h</kbd> | select between chat histories |
| <kbd><M-l></kbd> | accept suggestion |
| <kbd><M-]></kbd> | next suggestion |
| <kbd><M-[></kbd> | previous suggestion |
| <kbd><C-]></kbd> | dismiss suggestion |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>d</kbd> | toggle debug mode |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>s</kbd> | toggle suggestion display |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>R</kbd> | toggle repomap |
| **Files** | |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>c</kbd> | add current buffer to selected files |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>B</kbd> | add all buffer files to selected files |
| **Diff** | |
| <kbd>c</kbd><kbd>o</kbd> | choose ours |
| <kbd>c</kbd><kbd>t</kbd> | choose theirs |
| <kbd>c</kbd><kbd>a</kbd> | choose all theirs |
| <kbd>c</kbd><kbd>b</kbd> | choose both |
| <kbd>c</kbd><kbd>c</kbd> | choose cursor |
| <kbd>]</kbd><kbd>x</kbd> | move to next conflict |
| <kbd>[</kbd><kbd>x</kbd> | move to previous conflict |
| **Confirm** | |
| <kbd>Ctrl</kbd><kbd>w</kbd><kbd>f</kbd> | focus confirm window |
| <kbd>c</kbd> | confirm code |
| <kbd>r</kbd> | confirm response |
| <kbd>i</kbd> | confirm input |
> [!NOTE]
>
> If you are using `lazy.nvim`, then all keymap here will be safely set, meaning if `<leader>aa` is already binded, then avante.nvim won't bind this mapping.
> In this case, user will be responsible for setting up their own. See [notes on keymaps](https://github.com/yetone/avante.nvim/wiki#keymaps-and-api-i-guess) for more details.
### Neotree shortcut
In the neotree sidebar, you can also add a new keyboard shortcut to quickly add `file/folder` to `Avante Selected Files`.
<details>
<summary>Neotree configuration</summary>
```lua
return {
{
'nvim-neo-tree/neo-tree.nvim',
config = function()
require('neo-tree').setup({
filesystem = {
commands = {
avante_add_files = function(state)
local node = state.tree:get_node()
local filepath = node:get_id()
local relative_path = require('avante.utils').relative_path(filepath)
local sidebar = require('avante').get()
local open = sidebar:is_open()
-- ensure avante sidebar is open
if not open then
require('avante.api').ask()
sidebar = require('avante').get()
end
sidebar.file_selector:add_selected_file(relative_path)
-- remove neo tree buffer
if not open then
sidebar.file_selector:remove_selected_file('neo-tree filesystem [1]')
end
end,
},
window = {
mappings = {
['oa'] = 'avante_add_files',
},
},
},
})
end,
},
}
```
</details>
## Commands
| Command | Description | Examples |
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
| `:AvanteAsk [question] [position]` | Ask AI about your code. Optional `position` set window position and `ask` enable/disable direct asking mode | `:AvanteAsk position=right Refactor this code here` |
| `:AvanteBuild` | Build dependencies for the project | |
| `:AvanteChat` | Start a chat session with AI about your codebase. Default is `ask`=false | |
| `:AvanteChatNew` | Start a new chat session. The current chat can be re-opened with the chat session selector | |
| `:AvanteHistory` | Opens a picker for your previous chat sessions | |
| `:AvanteClear` | Clear the chat history for your current chat session | |
| `:AvanteEdit` | Edit the selected code blocks | |
| `:AvanteFocus` | Switch focus to/from the sidebar | |
| `:AvanteRefresh` | Refresh all Avante windows | |
| `:AvanteStop` | Stop the current AI request | |
| `:AvanteSwitchProvider` | Switch AI provider (e.g. openai) | |
| `:AvanteShowRepoMap` | Show repo map for project's structure | |
| `:AvanteToggle` | Toggle the Avante sidebar | |
| `:AvanteModels` | Show model list | |
| `:AvanteSwitchSelectorProvider` | Switch avante selector provider (e.g. native, telescope, fzf_lua, mini_pick, snacks) | |
## Highlight Groups
| Highlight Group | Description | Notes |
| --------------------------- | --------------------------------------------- | -------------------------------------------- |
| AvanteTitle | Title | |
| AvanteReversedTitle | Used for rounded border | |
| AvanteSubtitle | Selected code title | |
| AvanteReversedSubtitle | Used for rounded border | |
| AvanteThirdTitle | Prompt title | |
| AvanteReversedThirdTitle | Used for rounded border | |
| AvanteConflictCurrent | Current conflict highlight | Default to `Config.highlights.diff.current` |
| AvanteConflictIncoming | Incoming conflict highlight | Default to `Config.highlights.diff.incoming` |
| AvanteConflictCurrentLabel | Current conflict label highlight | Default to shade of `AvanteConflictCurrent` |
| AvanteConflictIncomingLabel | Incoming conflict label highlight | Default to shade of `AvanteConflictIncoming` |
| AvantePopupHint | Usage hints in popup menus | |
| AvanteInlineHint | The end-of-line hint displayed in visual mode | |
| AvantePromptInput | The body highlight of the prompt input | |
| AvantePromptInputBorder | The border highlight of the prompt input | Default to `NormalFloat` |
See [highlights.lua](./lua/avante/highlights.lua) for more information
## Fast Apply
Fast Apply is a feature that enables instant code edits with high accuracy by leveraging specialized models. It replicates Cursor's instant apply functionality, allowing for seamless code modifications without the typical delays associated with traditional code generation.
### Purpose and Benefits
Fast Apply addresses the common pain point of slow code application in AI-assisted development. Instead of waiting for a full language model to process and apply changes, Fast Apply uses a specialized "apply model" that can quickly and accurately merge code edits with 96-98% accuracy at speeds of 2500-4500+ tokens per second.
Key benefits:
- **Instant application**: Code changes are applied immediately without noticeable delays
- **High accuracy**: Specialized models achieve 96-98% accuracy for code edits
- **Seamless workflow**: Maintains the natural flow of development without interruptions
- **Large context support**: Handles up to 16k tokens for both input and output
### Configuration
To enable Fast Apply, you need to:
1. **Enable Fast Apply in your configuration**:
```lua
behaviour = {
enable_fastapply = true, -- Enable Fast Apply feature
},
-- ... other configuration
```
2. **Get your Morph API key**:
Go to [morphllm.com](https://morphllm.com/api-keys) and create an account and get the API key.
3. **Set your Morph API key**:
```bash
export MORPH_API_KEY="your-api-key"
```
4. **Change Morph model**:
```lua
providers = {
morph = {
model = "morph-v3-large",
},
}
```
### Model Options
Morph provides different models optimized for different use cases:
| Model | Speed | Accuracy | Context Limit |
| ---------------- | ----------------- | -------- | ------------- |
| `morph-v3-fast` | 4500+ tok/sec | 96% | 16k tokens |
| `morph-v3-large` | 2500+ tok/sec | 98% | 16k tokens |
| `auto` | 2500-4500 tok/sec | 98% | 16k tokens |
### How It Works
When Fast Apply is enabled and a Morph provider is configured, avante.nvim will:
1. Use the `edit_file` tool for code modifications instead of traditional tools
2. Send the original code, edit instructions, and update snippet to the Morph API
3. Receive the fully merged code back from the specialized apply model
4. Apply the changes directly to your files with high accuracy
The process uses a specialized prompt format that includes:
- `<instructions>`: Clear description of what changes to make
- `<code>`: The original code content
- `<update>`: The specific changes using truncation markers (`// ... existing code ...`)
This approach ensures that the apply model can quickly and accurately merge your changes without the overhead of full code generation.
## Ollama
Ollama is a first-class provider for avante.nvim. To start using it you need to set `provider = "ollama"`
in the configuration, set the `model` field in `ollama` to the model you want to use. Ollama is disabled
by default, you need to provide an implementation for its `is_env_set` method to properly enable it.
For example:
```lua
provider = "ollama",
providers = {
ollama = {
model = "qwq:32b",
is_env_set = require("avante.providers.ollama").check_endpoint_alive,
},
}
```
## ACP Support
Avante.nvim now supports the [Agent Client Protocol (ACP)](https://agentclientprotocol.com/overview/introduction), enabling seamless integration with AI agents that follow this standardized communication protocol. ACP provides a unified way for AI agents to interact with development environments, offering enhanced capabilities for code editing, file operations, and tool execution.
### What is ACP?
The Agent Client Protocol (ACP) is a standardized protocol that enables AI agents to communicate with development tools and environments. It provides:
- **Standardized Communication**: A unified JSON-RPC based protocol for agent-client interactions
- **Tool Integration**: Support for various development tools like file operations, code execution, and search
- **Session Management**: Persistent sessions that maintain context across interactions
- **Permission System**: Granular control over what agents can access and modify
### Enabling ACP
To use ACP-compatible agents with Avante.nvim, you need to configure an ACP provider. Here are the currently supported ACP agents:
#### Gemini CLI with ACP
```lua
{
provider = "gemini-cli",
-- other configuration options...
}
```
#### Claude Code with ACP
```lua
{
provider = "claude-code",
-- other configuration options...
}
```
#### Goose with ACP
```lua
{
provider = "goose",
-- other configuration options...
}
```
#### Codex with ACP
```lua
{
provider = "codex",
-- other configuration options...
}
```
#### Kimi CLI with ACP
```lua
{
provider = "kimi-cli",
-- other configuration options...
}
```
### ACP Configuration
ACP providers are configured in the `acp_providers` section of your configuration:
```lua
{
acp_providers = {
["gemini-cli"] = {
command = "gemini",
args = { "--experimental-acp" },
env = {
NODE_NO_WARNINGS = "1",
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY"),
},
},
["claude-code"] = {
command = "npx",
args = { "@zed-industries/claude-code-acp" },
env = {
NODE_NO_WARNINGS = "1",
ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY"),
},
},
["goose"] = {
command = "goose",
args = { "acp" },
},
["codex"] = {
command = "npx",
args = { "@zed-industries/codex-acp" },
env = {
NODE_NO_WARNINGS = "1",
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY"),
},
},
},
-- other configuration options...
}
```
### Prerequisites
Before using ACP agents, ensure you have the required tools installed:
- **For Gemini CLI**: Install the `gemini` CLI tool and set your `GEMINI_API_KEY`
- **For Claude Code**: Install the `acp-claude-code` package via npm and set your `ANTHROPIC_API_KEY`
### ACP vs Traditional Providers
ACP providers offer several advantages over traditional API-based providers:
- **Enhanced Tool Access**: Agents can directly interact with your file system, run commands, and access development tools
- **Persistent Context**: Sessions maintain state across multiple interactions
- **Fine-grained Permissions**: Control exactly what agents can access and modify
- **Standardized Protocol**: Compatible with any ACP-compliant agent
## Custom providers
Avante provides a set of default providers, but users can also create their own providers.
For more information, see [Custom Providers](https://github.com/yetone/avante.nvim/wiki/Custom-providers)
## RAG Service
Avante provides a RAG service, which is a tool for obtaining the required context for the AI to generate the codes. By default, it is not enabled. You can enable it this way:
```lua
rag_service = { -- RAG Service configuration
enabled = false, -- Enables the RAG service
host_mount = os.getenv("HOME"), -- Host mount path for the rag service (Docker will mount this path)
runner = "docker", -- Runner for the RAG service (can use docker or nix)
llm = { -- Language Model (LLM) configuration for RAG service
provider = "openai", -- LLM provider
endpoint = "https://api.openai.com/v1", -- LLM API endpoint
api_key = "OPENAI_API_KEY", -- Environment variable name for the LLM API key
model = "gpt-4o-mini", -- LLM model name
extra = nil, -- Additional configuration options for LLM
},
embed = { -- Embedding model configuration for RAG service
provider = "openai", -- Embedding provider
endpoint = "https://api.openai.com/v1", -- Embedding API endpoint
api_key = "OPENAI_API_KEY", -- Environment variable name for the embedding API key
model = "text-embedding-3-large", -- Embedding model name
extra = nil, -- Additional configuration options for the embedding model
},
docker_extra_args = "", -- Extra arguments to pass to the docker command
},
```
The RAG Service can currently configure the LLM and embedding models separately. In the `llm` and `embed` configuration blocks, you can set the following fields:
- `provider`: Model provider (e.g., "openai", "ollama", "dashscope", and "openrouter")
- `endpoint`: API endpoint
- `api_key`: Environment variable name for the API key
- `model`: Model name
- `extra`: Additional configuration options
For detailed configuration of different model providers, you can check [here](./py/rag-service/README.md).
Additionally, RAG Service also depends on Docker! (For macOS users, OrbStack is recommended as a Docker alternative).
`host_mount` is the path that will be mounted to the container, and the default is the home directory. The mount is required
for the RAG service to access the files in the host machine. It is up to the user to decide if you want to mount the whole
`/` directory, just the project directory, or the home directory. If you plan using avante and RAG event for projects
stored outside your home directory, you will need to set the `host_mount` to the root directory of your file system.
The mount will be read only.
After changing the rag_service configuration, you need to manually delete the rag_service container to ensure the new configuration is used: `docker rm -fv avante-rag-service`
## Web Search Engines
Avante's tools include some web search engines, currently support:
- [Tavily](https://tavily.com/)
- [SerpApi - Search API](https://serpapi.com/)
- Google's [Programmable Search Engine](https://developers.google.com/custom-search/v1/overview)
- [Kagi](https://help.kagi.com/kagi/api/search.html)
- [Brave Search](https://api-dashboard.search.brave.com/app/documentation/web-search/get-started)
- [SearXNG](https://searxng.github.io/searxng/)
The default is Tavily, and can be changed through configuring `Config.web_search_engine.provider`:
```lua
web_search_engine = {
provider = "tavily", -- tavily, serpapi, google, kagi, brave, or searxng
proxy = nil, -- proxy support, e.g., http://127.0.0.1:7890
}
```
Environment variables required for providers:
- Tavily: `TAVILY_API_KEY`
- SerpApi: `SERPAPI_API_KEY`
- Google:
- `GOOGLE_SEARCH_API_KEY` as the [API key](https://developers.google.com/custom-search/v1/overview)
- `GOOGLE_SEARCH_ENGINE_ID` as the [search engine](https://programmablesearchengine.google.com) ID
- Kagi: `KAGI_API_KEY` as the [API Token](https://kagi.com/settings?p=api)
- Brave Search: `BRAVE_API_KEY` as the [API key](https://api-dashboard.search.brave.com/app/keys)
- SearXNG: `SEARXNG_API_URL` as the [API URL](https://docs.searxng.org/dev/search_api.html)
## Disable Tools
Avante enables tools by default, but some LLM models do not support tools. You can disable tools by setting `disable_tools = true` for the provider. For example:
```lua
providers = {
claude = {
endpoint = "https://api.anthropic.com",
model = "claude-sonnet-4-20250514",
timeout = 30000, -- Timeout in milliseconds
disable_tools = true, -- disable tools!
extra_request_body = {
temperature = 0,
max_tokens = 4096,
}
}
}
```
In case you want to ban some tools to avoid its usage (like Claude 3.7 overusing the python tool) you can disable just specific tools
```lua
{
disabled_tools = { "python" },
}
```
Tool list
> rag_search, python, git_diff, git_commit, glob, search_keyword, read_file_toplevel_symbols,
> read_file, create_file, move_path, copy_path, delete_path, create_dir, bash, web_search, fetch
## Custom Tools
Avante allows you to define custom tools that can be used by the AI during code generation and analysis. These tools can execute shell commands, run scripts, or perform any custom logic you need.
### Example: Go Test Runner
<details>
<summary>Here's an example of a custom tool that runs Go unit tests:</summary>
```lua
{
custom_tools = {
{
name = "run_go_tests", -- Unique name for the tool
description = "Run Go unit tests and return results", -- Description shown to AI
command = "go test -v ./...", -- Shell command to execute
param = { -- Input parameters (optional)
type = "table",
fields = {
{
name = "target",
description = "Package or directory to test (e.g. './pkg/...' or './internal/pkg')",
type = "string",
optional = true,
},
},
},
returns = { -- Expected return values
{
name = "result",
description = "Result of the fetch",
type = "string",
},
{
name = "error",
description = "Error message if the fetch was not successful",
type = "string",
optional = true,
},
},
func = function(params, on_log, on_complete) -- Custom function to execute
local target = params.target or "./..."
return vim.system({ "go", "test", "-v", target }, { text = true }):wait().stdout
end,
},
},
}
```
</details>
## MCP
Now you can integrate MCP functionality for Avante through `mcphub.nvim`. For detailed documentation, please refer to [mcphub.nvim](https://ravitemer.github.io/mcphub.nvim/extensions/avante.html)
## Custom prompts
By default, `avante.nvim` provides three different modes to interact with: `planning`, `editing`, and `suggesting`, followed with three different prompts per mode.
- `planning`: Used with `require("avante").toggle()` on sidebar
- `editing`: Used with `require("avante").edit()` on selection codeblock
- `suggesting`: Used with `require("avante").get_suggestion():suggest()` on Tab flow.
- `cursor-planning`: Used with `require("avante").toggle()` on Tab flow, but only when cursor planning mode is enabled.
Users can customize the system prompts via `Config.system_prompt` or `Config.override_prompt_dir`.
`Config.system_prompt` allows you to set a global system prompt. We recommend calling this in a custom Autocmds depending on your need:
```lua
vim.api.nvim_create_autocmd("User", {
pattern = "ToggleMyPrompt",
callback = function() require("avante.config").override({system_prompt = "MY CUSTOM SYSTEM PROMPT"}) end,
})
vim.keymap.set("n", "<leader>am", function() vim.api.nvim_exec_autocmds("User", { pattern = "ToggleMyPrompt" }) end, { desc = "avante: toggle my prompt" })
```
`Config.override_prompt_dir` allows you to specify a directory containing your own custom prompt templates, which will override the built-in templates. This is useful if you want to maintain a set of custom prompts outside of your Neovim configuration. It can be a string representing the directory path, or a function that returns a string representing the directory path.
```lua
-- Example: Override with prompts from a specific directory
require("avante").setup({
override_prompt_dir = vim.fn.expand("~/.config/nvim/avante_prompts"),
})
-- Example: Override with prompts from a function (dynamic directory)
require("avante").setup({
override_prompt_dir = function()
-- Your logic to determine the prompt directory
return vim.fn.expand("~/.config/nvim/my_dynamic_prompts")
end,
})
```
> [!WARNING]
>
> If you customize `base.avanterules`, please ensure that `{% block custom_prompt %}{% endblock %}` and `{% block extra_prompt %}{% endblock %}` exist, otherwise the entire plugin may become unusable.
> If you are unsure about the specific reasons or what you are doing, please do not override the built-in prompts. The built-in prompts work very well.
If you wish to custom prompts for each mode, `avante.nvim` will check for project root based on the given buffer whether it contains
the following patterns: `*.{mode}.avanterules`.
The rules for root hierarchy:
- lsp workspace folders
- lsp root_dir
- root pattern of filename of the current buffer
- root pattern of cwd
You can also configure custom directories for your `avanterules` files using the `rules` option:
```lua
require('avante').setup({
rules = {
project_dir = '.avante/rules', -- relative to project root, can also be an absolute path
global_dir = '~/.config/avante/rules', -- absolute path
},
})
```
The loading priority is as follows:
1. `rules.project_dir`
2. `rules.global_dir`
3. Project root
<details>
<summary>Example folder structure for custom prompt</summary>
If you have the following structure:
```bash
.
├── .git/
├── typescript.planning.avanterules
├── snippets.editing.avanterules
├── suggesting.avanterules
└── src/
```
- `typescript.planning.avanterules` will be used for `planning` mode
- `snippets.editing.avanterules` will be used for `editing` mode
- `suggesting.avanterules` will be used for `suggesting` mode.
</details>
> [!important]
>
> `*.avanterules` is a jinja template file, in which will be rendered using [minijinja](https://github.com/mitsuhiko/minijinja). See [templates](https://github.com/yetone/avante.nvim/blob/main/lua/avante/templates) for example on how to extend current templates.
## Integration
Avante.nvim can be extended to work with other plugins by using its extension modules. Below is an example of integrating Avante with [`nvim-tree`](https://github.com/nvim-tree/nvim-tree.lua), allowing you to select or deselect files directly from the NvimTree UI:
```lua
{
"yetone/avante.nvim",
event = "VeryLazy",
keys = {
{
"<leader>a+",
function()
local tree_ext = require("avante.extensions.nvim_tree")
tree_ext.add_file()
end,
desc = "Select file in NvimTree",
ft = "NvimTree",
},
{
"<leader>a-",
function()
local tree_ext = require("avante.extensions.nvim_tree")
tree_ext.remove_file()
end,
desc = "Deselect file in NvimTree",
ft = "NvimTree",
},
},
opts = {
--- other configurations
selector = {
exclude_auto_select = { "NvimTree" },
},
},
}
```
## TODOs
- [x] Chat with current file
- [x] Apply diff patch
- [x] Chat with the selected block
- [x] Slash commands
- [x] Edit the selected block
- [x] Smart Tab (Cursor Flow)
- [x] Chat with project (You can use `@codebase` to chat with the whole project)
- [x] Chat with selected files
- [x] Tool use
- [x] MCP
- [x] ACP
- [ ] Better codebase indexing
## Roadmap
- **Enhanced AI Interactions**: Improve the depth of AI analysis and recommendations for more complex coding scenarios.
- **LSP + Tree-sitter + LLM Integration**: Integrate with LSP and Tree-sitter and LLM to provide more accurate and powerful code suggestions and analysis.
## FAQ
### How to disable agentic mode?
Avante.nvim provides two interaction modes:
- **`agentic`** (default): Uses AI tools to automatically generate and apply code changes
- **`legacy`**: Uses the traditional planning method without automatic tool execution
To disable agentic mode and switch to legacy mode, update your configuration:
```lua
{
mode = "legacy", -- Switch from "agentic" to "legacy"
-- ... your other configuration options
}
```
**What's the difference?**
- **Agentic mode**: AI can automatically execute tools like file operations, bash commands, web searches, etc. to complete complex tasks
- **Legacy mode**: AI provides suggestions and plans but requires manual approval for all actions
**When should you use legacy mode?**
- If you prefer more control over what actions the AI takes
- If you're concerned about security with automatic tool execution
- If you want to manually review each step before applying changes
- If you're working in a sensitive environment where automatic code changes aren't desired
You can also disable specific tools while keeping agentic mode enabled by configuring `disabled_tools`:
```lua
{
mode = "agentic",
disabled_tools = { "bash", "python" }, -- Disable specific tools
-- ... your other configuration options
}
```
## Contributing
Contributions to avante.nvim are welcome! If you're interested in helping out, please feel free to submit pull requests or open issues. Before contributing, ensure that your code has been thoroughly tested.
See [wiki](https://github.com/yetone/avante.nvim/wiki) for more recipes and tricks.
## Acknowledgments
We would like to express our heartfelt gratitude to the contributors of the following open-source projects, whose code has provided invaluable inspiration and reference for the development of avante.nvim:
| Nvim Plugin | License | Functionality | Location |
| --------------------------------------------------------------------- | ------------------ | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| [git-conflict.nvim](https://github.com/akinsho/git-conflict.nvim) | No License | Diff comparison functionality | [lua/avante/diff.lua](https://github.com/yetone/avante.nvim/blob/main/lua/avante/diff.lua) |
| [ChatGPT.nvim](https://github.com/jackMort/ChatGPT.nvim) | Apache 2.0 License | Calculation of tokens count | [lua/avante/utils/tokens.lua](https://github.com/yetone/avante.nvim/blob/main/lua/avante/utils/tokens.lua) |
| [img-clip.nvim](https://github.com/HakonHarnes/img-clip.nvim) | MIT License | Clipboard image support | [lua/avante/clipboard.lua](https://github.com/yetone/avante.nvim/blob/main/lua/avante/clipboard.lua) |
| [copilot.lua](https://github.com/zbirenbaum/copilot.lua) | MIT License | Copilot support | [lua/avante/providers/copilot.lua](https://github.com/yetone/avante.nvim/blob/main/lua/avante/providers/copilot.lua) |
| [jinja.vim](https://github.com/HiPhish/jinja.vim) | MIT License | Template filetype support | [syntax/jinja.vim](https://github.com/yetone/avante.nvim/blob/main/syntax/jinja.vim) |
| [codecompanion.nvim](https://github.com/olimorris/codecompanion.nvim) | MIT License | Secrets logic support | [lua/avante/providers/init.lua](https://github.com/yetone/avante.nvim/blob/main/lua/avante/providers/init.lua) |
| [aider](https://github.com/paul-gauthier/aider) | Apache 2.0 License | Planning mode user prompt | [lua/avante/templates/planning.avanterules](https://github.com/yetone/avante.nvim/blob/main/lua/avante/templates/planning.avanterules) |
The high quality and ingenuity of these projects' source code have been immensely beneficial throughout our development process. We extend our sincere thanks and respect to the authors and contributors of these projects. It is the selfless dedication of the open-source community that drives projects like avante.nvim forward.
## Business Sponsors
<table>
<tr>
<td align="center">
<a href="https://s.kiiro.ai/r/ylVbT6" target="_blank">
<img height="80" src="https://github.com/user-attachments/assets/1abd8ede-bd98-4e6e-8ee0-5a661b40344a" alt="Meshy AI" /><br/>
<strong>Meshy AI</strong>
<div> </div>
<div>The #1 AI 3D Model Generator for Creators</div>
</a>
</td>
<td align="center">
<a href="https://s.kiiro.ai/r/mGPJOd" target="_blank">
<img height="80" src="https://github.com/user-attachments/assets/7b7bd75e-1fd2-48cc-a71a-cff206e4fbd7" alt="BabelTower API" /><br/>
<strong>BabelTower API</strong>
<div> </div>
<div>No account needed, use any model instantly</div>
</a>
</td>
</tr>
</table>
## License
avante.nvim is licensed under the Apache 2.0 License. For more details, please refer to the [LICENSE](./LICENSE) file.
# Star History
<p align="center">
<a target="_blank" href="https://star-history.com/#yetone/avante.nvim&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=yetone/avante.nvim&type=Date&theme=dark">
<img alt="NebulaGraph Data Intelligence Suite(ngdi)" src="https://api.star-history.com/svg?repos=yetone/avante.nvim&type=Date">
</picture>
</a>
</p>
================================================
FILE: README_zh.md
================================================
<div align="center">
<img alt="logo" width="120" src="https://github.com/user-attachments/assets/2e2f2a58-2b28-4d11-afd1-87b65612b2de" />
<h1>avante.nvim</h1>
</div>
<p align="center">
<a href="https://neovim.io/" target="_blank"><img src="https://img.shields.io/static/v1?style=flat-square&label=Neovim&message=v0.10%2b&logo=neovim&labelColor=282828&logoColor=8faa80&color=414b32" alt="Neovim: v0.10+" /></a>
<a href="https://github.com/yetone/avante.nvim/actions/workflows/lua.yaml" target="_blank"><img src="https://img.shields.io/github/actions/workflow/status/yetone/avante.nvim/lua.yaml?style=flat-square&logo=lua&logoColor=c7c7c7&label=Lua+CI&labelColor=1E40AF&color=347D39&event=push" alt="Lua CI status" /></a>
<a href="https://github.com/yetone/avante.nvim/actions/workflows/rust.yaml" target="_blank"><img src="https://img.shields.io/github/actions/workflow/status/yetone/avante.nvim/rust.yaml?style=flat-square&logo=rust&logoColor=ffffff&label=Rust+CI&labelColor=BC826A&color=347D39&event=push" alt="Rust CI status" /></a>
<a href="https://github.com/yetone/avante.nvim/actions/workflows/pre-commit.yaml" target="_blank"><img src="https://img.shields.io/github/actions/workflow/status/yetone/avante.nvim/pre-commit.yaml?style=flat-square&logo=pre-commit&logoColor=ffffff&label=pre-commit&labelColor=FAAF3F&color=347D39&event=push" alt="pre-commit status" /></a>
<a href="https://discord.gg/QfnEFEdSjz" target="_blank"><img src="https://img.shields.io/discord/1302530866362323016?style=flat-square&logo=discord&label=Discord&logoColor=ffffff&labelColor=7376CF&color=268165" alt="Discord" /></a>
<a href="https://dotfyle.com/plugins/yetone/avante.nvim"><img src="https://dotfyle.com/plugins/yetone/avante.nvim/shield?style=flat-square" /></a>
</p>
**avante.nvim** 是一个 Neovim 插件,旨在模拟 [Cursor](https://www.cursor.com) AI IDE 的行为。它为用户提供 AI 驱动的代码建议,并能够轻松地将这些建议直接应用到源文件中。
[View in English](README.md)
> [!NOTE]
>
> 🥰 该项目正在快速迭代中,许多令人兴奋的功能将陆续添加。敬请期待!
<https://github.com/user-attachments/assets/510e6270-b6cf-459d-9a2f-15b397d1fe53>
<https://github.com/user-attachments/assets/86140bfd-08b4-483d-a887-1b701d9e37dd>
## 赞助 ❤️
如果您喜欢这个项目,请考虑在 Patreon 上支持我,因为这有助于我继续维护和改进它:
[赞助我](https://patreon.com/yetone)
## 功能
- **AI 驱动的代码辅助**:与 AI 互动,询问有关当前代码文件的问题,并接收智能建议以进行改进或修改。
- **一键应用**:通过单个命令快速将 AI 的建议更改应用到源代码中,简化编辑过程并节省时间。
## 安装
如果您希望从源代码构建二进制文件,则需要 `cargo`。否则,将使用 `curl` 和 `tar` 从 GitHub 获取预构建的二进制文件。
<details open>
<summary><a href="https://github.com/folke/lazy.nvim">lazy.nvim</a> (推荐)</summary>
```lua
{
"yetone/avante.nvim",
-- 如果您想从源代码构建,请执行 `make BUILD_FROM_SOURCE=true`
-- ⚠️ 一定要加上这一行配置!!!!!
build = vim.fn.has("win32") ~= 0
and "powershell -ExecutionPolicy Bypass -File Build.ps1 -BuildFromSource false"
or "make",
event = "VeryLazy",
version = false, -- 永远不要将此值设置为 "*"!永远不要!
---@module 'avante'
---@type avante.Config
opts = {
-- 在此处添加任何选项
-- 例如
provider = "claude",
providers = {
claude = {
endpoint = "https://api.anthropic.com",
model = "claude-sonnet-4-20250514",
timeout = 30000, -- Timeout in milliseconds
extra_request_body = {
temperature = 0.75,
max_tokens = 20480,
},
},
moonshot = {
endpoint = "https://api.moonshot.ai/v1",
model = "kimi-k2-0711-preview",
timeout = 30000, -- 超时时间(毫秒)
extra_request_body = {
temperature = 0.75,
max_tokens = 32768,
},
},
},
},
dependencies = {
"nvim-lua/plenary.nvim",
"MunifTanjim/nui.nvim",
--- 以下依赖项是可选的,
"echasnovski/mini.pick", -- 用于文件选择器提供者 mini.pick
"nvim-telescope/telescope.nvim", -- 用于文件选择器提供者 telescope
"hrsh7th/nvim-cmp", -- avante 命令和提及的自动完成
"ibhagwan/fzf-lua", -- 用于文件选择器提供者 fzf
"nvim-tree/nvim-web-devicons", -- 或 echasnovski/mini.icons
"zbirenbaum/copilot.lua", -- 用于 providers='copilot'
{
-- 支持图像粘贴
"HakonHarnes/img-clip.nvim",
event = "VeryLazy",
opts = {
-- 推荐设置
default = {
embed_image_as_base64 = false,
prompt_for_file_name = false,
drag_and_drop = {
insert_mode = true,
},
-- Windows 用户必需
use_absolute_path = true,
},
},
},
{
-- 如果您有 lazy=true,请确保正确设置
'MeanderingProgrammer/render-markdown.nvim',
opts = {
file_types = { "markdown", "Avante" },
},
ft = { "markdown", "Avante" },
},
},
}
```
</details>
<details>
<summary>vim-plug</summary>
```vim
" 依赖项
Plug 'nvim-lua/plenary.nvim'
Plug 'MunifTanjim/nui.nvim'
Plug 'MeanderingProgrammer/render-markdown.nvim'
" 可选依赖项
Plug 'hrsh7th/nvim-cmp'
Plug 'nvim-tree/nvim-web-devicons' "或 Plug 'echasnovski/mini.icons'
Plug 'HakonHarnes/img-clip.nvim'
Plug 'zbirenbaum/copilot.lua'
" Yay,如果您想从源代码构建,请传递 source=true
Plug 'yetone/avante.nvim', { 'branch': 'main', 'do': 'make' }
autocmd! User avante.nvim lua << EOF
require('avante').setup()
EOF
```
</details>
<details>
<summary><a href="https://github.com/echasnovski/mini.deps">mini.deps</a></summary>
```lua
local add, later, now = MiniDeps.add, MiniDeps.later, MiniDeps.now
add({
source = 'yetone/avante.nvim',
monitor = 'main',
depends = {
'nvim-lua/plenary.nvim',
'MunifTanjim/nui.nvim',
'echasnovski/mini.icons'
},
hooks = { post_checkout = function() vim.cmd('make') end }
})
--- 可选
add({ source = 'hrsh7th/nvim-cmp' })
add({ source = 'zbirenbaum/copilot.lua' })
add({ source = 'HakonHarnes/img-clip.nvim' })
add({ source = 'MeanderingProgrammer/render-markdown.nvim' })
later(function() require('render-markdown').setup({...}) end)
later(function()
require('img-clip').setup({...}) -- 配置 img-clip
require("copilot").setup({...}) -- 根据您的喜好设置 copilot
require("avante").setup({...}) -- 配置 avante.nvim
end)
```
</details>
<details>
<summary><a href="https://github.com/wbthomason/packer.nvim">Packer</a></summary>
```vim
-- 必需插件
use 'nvim-lua/plenary.nvim'
use 'MunifTanjim/nui.nvim'
use 'MeanderingProgrammer/render-markdown.nvim'
-- 可选依赖项
use 'hrsh7th/nvim-cmp'
use 'nvim-tree/nvim-web-devicons' -- 或使用 'echasnovski/mini.icons'
use 'HakonHarnes/img-clip.nvim'
use 'zbirenbaum/copilot.lua'
-- Avante.nvim 带有构建过程
use {
'yetone/avante.nvim',
branch = 'main',
run = 'make',
config = function()
require('avante').setup()
end
}
```
</details>
<details>
<summary><a href="https://github.com/nix-community/home-manager">Home Manager</a></summary>
```nix
programs.neovim = {
plugins = [
{
plugin = pkgs.vimPlugins.avante-nvim;
type = "lua";
config = ''
require("avante_lib").load()
require("avante").setup()
'' # 或 builtins.readFile ./plugins/avante.lua;
}
];
};
```
</details>
<details>
<summary><a href="https://nix-community.github.io/nixvim/plugins/avante/index.html">Nixvim</a></summary>
```nix
plugins.avante.enable = true;
plugins.avante.settings = {
# 在此处设置选项
};
```
</details>
<details>
<summary>Lua</summary>
```lua
-- 依赖项:
require('cmp').setup ({
-- 使用上面的推荐设置
})
require('img-clip').setup ({
-- 使用上面的推荐设置
})
require('copilot').setup ({
-- 使用上面的推荐设置
})
require('render-markdown').setup ({
-- 使用上面的推荐设置
})
require('avante').setup ({
-- 在此处配置!
})
```
</details>
> [!IMPORTANT]
>
> `avante.nvim` 目前仅兼容 Neovim 0.10.1 或更高版本。请确保您的 Neovim 版本符合这些要求后再继续。
> [!NOTE]
>
> 在同步加载插件时,我们建议在您的配色方案之后的某个时间 `require` 它。
> [!NOTE]
>
> 推荐的 **Neovim** 选项:
>
> ```lua
> -- 视图只能通过全局状态栏完全折叠
> vim.opt.laststatus = 3
> ```
> [!TIP]
>
> 任何支持 markdown 的渲染插件都可以与 Avante 一起使用,只要您添加支持的文件类型 `Avante`。有关更多信息,请参见 <https://github.com/yetone/avante.nvim/issues/175> 和 [此评论](https://github.com/yetone/avante.nvim/issues/175#issuecomment-2313749363)。
### 默认设置配置
_请参见 [config.lua#L9](./lua/avante/config.lua) 以获取完整配置_
<details>
<summary>默认配置</summary>
```lua
{
---@alias Provider "claude" | "openai" | "azure" | "gemini" | "cohere" | "copilot" | string
provider = "claude", -- 在 Aider 模式或 Cursor 规划模式的规划阶段使用的提供者
-- 警告:由于自动建议是高频操作,因此成本较高,
-- 目前将其指定为 `copilot` 提供者是危险的,因为:https://github.com/yetone/avante.nvim/issues/1048
-- 当然,您可以通过增加 `suggestion.debounce` 来减少请求频率。
auto_suggestions_provider = "claude",
providers = {
claude = {
endpoint = "https://api.anthropic.com",
model = "claude-3-5-sonnet-20241022",
extra_request_body = {
temperature = 0.75,
max_tokens = 4096,
},
},
moonshot = {
endpoint = "https://api.moonshot.ai/v1",
model = "kimi-k2-0711-preview",
timeout = 30000, -- 超时时间(毫秒)
extra_request_body = {
temperature = 0.75,
max_tokens = 32768,
},
},
},
---指定特殊的 dual_boost 模式
---1. enabled: 是否启用 dual_boost 模式。默认为 false。
---2. first_provider: 第一个提供者用于生成响应。默认为 "openai"。
---3. second_provider: 第二个提供者用于生成响应。默认为 "claude"。
---4. prompt: 用于根据两个参考输出生成响应的提示。
---5. timeout: 超时时间(毫秒)。默认为 60000。
---工作原理:
--- 启用 dual_boost 后,avante 将分别从 first_provider 和 second_provider 生成两个响应。然后使用 first_provider 的响应作为 provider1_output,second_provider 的响应作为 provider2_output。最后,avante 将根据提示和两个参考输出生成响应,默认提供者与正常情况相同。
---注意:这是一个实验性功能,可能无法按预期工作。
dual_boost = {
enabled = false,
first_provider = "openai",
second_provider = "claude",
prompt = "根据以下两个参考输出,生成一个结合两者元素但反映您自己判断和独特视角的响应。不要提供任何解释,只需直接给出响应。参考输出 1: [{{provider1_output}}], 参考输出 2: [{{provider2_output}}]",
timeout = 60000, -- 超时时间(毫秒)
},
behaviour = {
auto_suggestions = false, -- 实验阶段
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, -- 是否启用令牌计数。默认为 true。
auto_add_current_file = true, -- 打开新聊天时是否自动添加当前文件。默认为 true。
enable_cursor_planning_mode = false, -- 是否启用 Cursor 规划模式。默认为 false。
enable_claude_text_editor_tool_mode = false, -- 是否启用 Claude 文本编辑器工具模式。
---@type "popup" | "inline_buttons"
confirmation_ui_style = "inline_buttons",
},
mappings = {
--- @class AvanteConflictMappings
diff = {
ours = "co",
theirs = "ct",
all_theirs = "ca",
both = "cb",
cursor = "cc",
next = "]x",
prev = "[x",
},
suggestion = {
accept = "<M-l>",
next = "<M-]>",
prev = "<M-[>",
dismiss = "<C-]>",
},
jump = {
next = "]]",
prev = "[[",
},
submit = {
normal = "<CR>",
insert = "<C-s>",
},
cancel = {
normal = { "<C-c>", "<Esc>", "q" },
insert = { "<C-c>" },
},
sidebar = {
apply_all = "A",
apply_cursor = "a",
retry_user_request = "r",
edit_user_request = "e",
switch_windows = "<Tab>",
reverse_switch_windows = "<S-Tab>",
remove_file = "d",
add_file = "@",
close = { "<Esc>", "q" },
close_from_input = nil, -- 例如,{ normal = "<Esc>", insert = "<C-d>" }
},
},
selection = {
enabled = true,
hint_display = "delayed",
},
windows = {
---@type "right" | "left" | "top" | "bottom"
position = "right", -- 侧边栏的位置
wrap = true, -- 类似于 vim.o.wrap
width = 30, -- 默认基于可用宽度的百分比
sidebar_header = {
enabled = true, -- true, false 启用/禁用标题
align = "center", -- left, center, right 用于标题
rounded = true,
},
spinner = {
editing = { "⡀", "⠄", "⠂", "⠁", "⠈", "⠐", "⠠", "⢀", "⣀", "⢄", "⢂", "⢁", "⢈", "⢐", "⢠", "⣠", "⢤", "⢢", "⢡", "⢨", "⢰", "⣰", "⢴", "⢲", "⢱", "⢸", "⣸", "⢼", "⢺", "⢹", "⣹", "⢽", "⢻", "⣻", "⢿", "⣿" },
generating = { "·", "✢", "✳", "∗", "✻", "✽" }, -- '生成中' 状态的旋转字符
thinking = { "🤯", "🙄" }, -- '思考中' 状态的旋转字符
},
input = {
prefix = "> ",
height = 8, -- 垂直布局中输入窗口的高度
},
edit = {
border = "rounded",
start_insert = true, -- 打开编辑窗口时开始插入模式
},
ask = {
floating = false, -- 在浮动窗口中打开 'AvanteAsk' 提示
start_insert = true, -- 打开询问窗口时开始插入模式
border = "rounded",
---@type "ours" | "theirs"
focus_on_apply = "ours", -- 应用后聚焦的差异
},
},
highlights = {
---@type AvanteConflictHighlights
diff = {
current = "DiffText",
incoming = "DiffAdd",
},
},
--- @class AvanteConflictUserConfig
diff = {
autojump = true,
---@type string | fun(): any
list_opener = "copen",
--- 覆盖悬停在差异上时的 'timeoutlen' 设置(请参阅 :help timeoutlen)。
--- 有助于避免进入以 `c` 开头的差异映射的操作员挂起模式。
--- 通过设置为 -1 禁用。
override_timeoutlen = 500,
},
suggestion = {
debounce = 600,
throttle = 600,
},
}
```
</details>
## Blink.cmp 用户
对于 blink cmp 用户(nvim-cmp 替代品),请查看以下配置说明
这是通过使用 blink.compat 模拟 nvim-cmp 实现的
或者您可以使用 [Kaiser-Yang/blink-cmp-avante](https://github.com/Kaiser-Yang/blink-cmp-avante)。
<details>
<summary>Lua</summary>
```lua
selector = {
--- @alias avante.SelectorProvider "native" | "fzf_lua" | "mini_pick" | "snacks" | "telescope" | fun(selector: avante.ui.Selector): nil
provider = "fzf",
-- 自定义提供者的选项覆盖
provider_opts = {},
}
```
要创建自定义选择器,您可以指定一个自定义函数来启动选择器以选择项目,并将选定的项目传递给 `on_select` 回调。
```lua
selector = {
---@param selector avante.ui.Selector
provider = function(selector)
local items = selector.items ---@type avante.ui.SelectorItem[]
local title = selector.title ---@type string
local on_select = selector.on_select ---@type fun(selected_item_ids: string[]|nil): nil
--- 在这里添加您的自定义选择器逻辑
end,
}
```
选择 native 以外的选择器,默认情况下目前存在问题
对于 lazyvim 用户,请从网站复制 blink.cmp 的完整配置或扩展选项
```lua
compat = {
"avante_commands",
"avante_mentions",
"avante_files",
}
```
对于其他用户,只需添加自定义提供者
### 可用的补全项
Avante.nvim 提供了多个可以与 blink.cmp 集成的补全项:
#### 提及功能 (`@` 触发器)
提及功能允许您快速引用特定功能或将文件添加到聊天上下文:
- `@codebase` - 启用项目上下文和仓库映射
- `@diagnostics` - 启用诊断信息
- `@file` - 打开文件选择器以将文件添加到聊天上下文
- `@quickfix` - 将快速修复列表中的文件添加到聊天上下文
- `@buffers` - 将打开的缓冲区添加到聊天上下文
#### 斜杠命令 (`/` 触发器)
内置斜杠命令用于常见操作:
- `/help` - 显示可用命令的帮助信息
- `/init` - 基于当前项目初始化 AGENTS.md
- `/clear` - 清除聊天历史
- `/new` - 开始新聊天
- `/compact` - 压缩历史消息以节省令牌
- `/lines <start>-<end> <question>` - 询问特定行的问题
- `/commit` - 为更改生成提交消息
#### 快捷方式 (`#` 触发器)
快捷方式提供对预定义提示模板的快速访问。您可以在配置中自定义这些:
```lua
{
shortcuts = {
{
name = "refactor",
description = "使用最佳实践重构代码",
details = "自动重构代码以提高可读性、可维护性,并遵循最佳实践,同时保持功能不变",
prompt = "请按照最佳实践重构此代码,提高可读性和可维护性,同时保持功能不变。"
},
{
name = "test",
description = "生成单元测试",
details = "创建全面的单元测试,涵盖边界情况、错误场景和各种输入条件",
prompt = "请为此代码生成全面的单元测试,涵盖边界情况和错误场景。"
},
-- 添加更多自定义快捷方式...
}
}
```
当您在输入中键入 `#refactor` 时,它将自动替换为相应的提示文本。
### 配置示例
以下是包含所有 Avante 源的完整 blink.cmp 配置示例:
```lua
default = {
...
"avante_commands",
"avante_mentions",
"avante_shortcuts",
"avante_files",
}
```
```lua
providers = {
avante_commands = {
name = "avante_commands",
module = "blink.compat.source",
score_offset = 90, -- 显示优先级高于 lsp
opts = {},
},
avante_files = {
name = "avante_files",
module = "blink.compat.source",
score_offset = 100, -- 显示优先级高于 lsp
opts = {},
},
avante_mentions = {
name = "avante_mentions",
module = "blink.compat.source",
score_offset = 1000, -- 显示优先级高于 lsp
opts = {},
},
avante_shortcuts = {
name = "avante_shortcuts",
module = "blink.compat.source",
score_offset = 1000, -- 显示优先级高于 lsp
opts = {},
}
...
}
```
</details>
## 用法
鉴于其早期阶段,`avante.nvim` 目前支持以下基本功能:
> [!IMPORTANT]
>
> 为了在 neovim 会话之间保持一致性,建议在 shell 文件中设置环境变量。
> 默认情况下,`Avante` 会在启动时提示您输入所选提供者的 API 密钥。
>
> **作用域 API 密钥(推荐用于隔离)**
>
> Avante 现在支持作用域 API 密钥,允许您专门为 Avante 隔离 API 密钥,而不影响其他应用程序。只需在任何 API 密钥前加上 `AVANTE_` 前缀:
>
> ```sh
> # 作用域密钥(推荐)
> export AVANTE_ANTHROPIC_API_KEY=your-claude-api-key
> export AVANTE_OPENAI_API_KEY=your-openai-api-key
> export AVANTE_AZURE_OPENAI_API_KEY=your-azure-api-key
> export AVANTE_GEMINI_API_KEY=your-gemini-api-key
> export AVANTE_CO_API_KEY=your-cohere-api-key
> export AVANTE_AIHUBMIX_API_KEY=your-aihubmix-api-key
> export AVANTE_MOONSHOT_API_KEY=your-moonshot-api-key
> ```
>
> **全局 API 密钥(传统方式)**
>
> 如果您愿意,仍然可以使用传统的全局 API 密钥:
>
> 对于 Claude:
>
> ```sh
> export ANTHROPIC_API_KEY=your-api-key
> ```
>
> 对于 OpenAI:
>
> ```sh
> export OPENAI_API_KEY=your-api-key
> ```
>
> 对于 Azure OpenAI:
>
> ```sh
> export AZURE_OPENAI_API_KEY=your-api-key
> ```
>
> 对于 Amazon Bedrock:
>
> ```sh
> export BEDROCK_KEYS=aws_access_key_id,aws_secret_access_key,aws_region[,aws_session_token]
>
> ```
>
> 注意:aws_session_token 是可选的,仅在使用临时 AWS 凭证时需要
1. 在 Neovim 中打开代码文件。
2. 使用 `:AvanteAsk` 命令查询 AI 关于代码的问题。
3. 查看 AI 的建议。
4. 通过简单的命令或按键绑定将推荐的更改直接应用到代码中。
**注意**:该插件仍在积极开发中,其功能和界面可能会发生重大变化。随着项目的发展,预计会有一些粗糙的边缘和不稳定性。
## 键绑定
以下键绑定可用于 `avante.nvim`:
| 键绑定 | 描述 |
| ----------------------------------------- | ----------------------------- |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>a</kbd> | 显示侧边栏 |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>t</kbd> | 切换侧边栏可见性 |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>r</kbd> | 刷新侧边栏 |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>f</kbd> | 切换侧边栏焦点 |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>?</kbd> | 选择模型 |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>e</kbd> | 编辑选定的块 |
| <kbd>Leader</kbd><kbd>a</kbd><kbd>S</kbd> | 停止当前 AI 请求 |
| <kbd>c</kbd><kbd>o</kbd> | 选择我们的 |
| <kbd>c</kbd><kbd>t</kbd> | 选择他们的 |
| <kbd>c</kbd><kbd>a</kbd> | 选择所有他们的 |
| <kbd>c</kbd><kbd>0</kbd> | 选择无 |
| <kbd>c</kbd><kbd>b</kbd> | 选择两者 |
| <kbd>c</kbd><kbd>c</kbd> | 选择光标 |
| <kbd>]</kbd><kbd>x</kbd> | 移动到上一个冲突 |
| <kbd>[</kbd><kbd>x</kbd> | 移动到下一个冲突 |
| <kbd>[</kbd><kbd>[</kbd> | 跳转到上一个代码块 (结果窗口) |
| <kbd>]</kbd><kbd>]</kbd> | 跳转到下一个代码块 (结果窗口) |
> [!NOTE]
>
> 如果您使用 `lazy.nvim`,那么此处的所有键映射都将安全设置,这意味着如果 `<leader>aa` 已经绑定,则 avante.nvim 不会绑定此映射。
> 在这种情况下,用户将负责设置自己的。有关更多详细信息,请参见 [关于键映射的说明](https://github.com/yetone/avante.nvim/wiki#keymaps-and-api-i-guess)。
### Neotree 快捷方式
在 neotree 侧边栏中,您还可以添加新的键盘快捷方式,以快速将 `file/folder` 添加到 `Avante Selected Files`。
<details>
<summary>Neotree 配置</summary>
```lua
return {
{
'nvim-neo-tree/neo-tree.nvim',
config = function()
require('neo-tree').setup({
filesystem = {
commands = {
avante_add_files = function(state)
local node = state.tree:get_node()
local filepath = node:get_id()
local relative_path = require('avante.utils').relative_path(filepath)
local sidebar = require('avante').get()
local open = sidebar:is_open()
-- 确保 avante 侧边栏已打开
if not open then
require('avante.api').ask()
sidebar = require('avante').get()
end
sidebar.file_selector:add_selected_file(relative_path)
-- 删除 neo tree 缓冲区
if not open then
sidebar.file_selector:remove_selected_file('neo-tree filesystem [1]')
end
end,
},
window = {
mappings = {
['oa'] = 'avante_add_files',
},
},
},
})
end,
},
}
```
</details>
## 命令
| 命令 | 描述 | 示例 |
| ---------------------------------- | ---------------------------------------------------------------------------------------- | --------------------------------------------------- |
| `:AvanteAsk [question] [position]` | 询问 AI 关于您的代码的问题。可选的 `position` 设置窗口位置和 `ask` 启用/禁用直接询问模式 | `:AvanteAsk position=right Refactor this code here` |
| `:AvanteBuild` | 构建项目的依赖项 | |
| `:AvanteChat` | 启动与 AI 的聊天会话,讨论您的代码库。默认情况下 `ask`=false | |
| `:AvanteClear` | 清除聊天记录 | |
| `:AvanteEdit` | 编辑选定的代码块 | |
| `:AvanteFocus` | 切换焦点到/从侧边栏 | |
| `:AvanteRefresh` | 刷新所有 Avante 窗口 | |
| `:AvanteStop` | 停止当前 AI 请求 | |
| `:AvanteSwitchProvider` | 切换 AI 提供者(例如 openai) | |
| `:AvanteShowRepoMap` | 显示项目结构的 repo map | |
| `:AvanteToggle` | 切换 Avante 侧边栏 | |
| `:AvanteModels` | 显示模型列表 | |
## 高亮组
| 高亮组 | 描述 | 备注 |
| --------------------------- | -------------------------- | ------------------------------------------ |
| AvanteTitle | 标题 | |
| AvanteReversedTitle | 用于圆角边框 | |
| AvanteSubtitle | 选定代码标题 | |
| AvanteReversedSubtitle | 用于圆角边框 | |
| AvanteThirdTitle | 提示标题 | |
| AvanteReversedThirdTitle | 用于圆角边框 | |
| AvanteConflictCurrent | 当前冲突高亮 | 默认值为 `Config.highlights.diff.current` |
| AvanteConflictIncoming | 即将到来的冲突高亮 | 默认值为 `Config.highlights.diff.incoming` |
| AvanteConflictCurrentLabel | 当前冲突标签高亮 | 默认值为 `AvanteConflictCurrent` 的阴影 |
| AvanteConflictIncomingLabel | 即将到来的冲突标签高亮 | 默认值为 `AvanteConflictIncoming` 的阴影 |
| AvantePopupHint | 弹出菜单中的使用提示 | |
| AvanteInlineHint | 在可视模式下显示的行尾提示 | |
有关更多信息,请参见 [highlights.lua](./lua/avante/highlights.lua)
## Ollama
ollama 是 avante.nvim 的一流提供者。要开始使用它,您需要在配置中设置 `provider = "ollama"`,并将 `ollama` 中的 `model` 字段设置为您想要使用的模型。Ollama 默认是禁用的,您需要为其 `is_env_set` 方法提供一个实现来正确地启用它。例如:
```lua
provider = "ollama",
providers = {
ollama = {
model = "qwq:32b",
is_env_set = require("avante.providers.ollama").check_endpoint_alive,
},
}
```
## 自定义提供者
Avante 提供了一组默认提供者,但用户也可以创建自己的提供者。
有关更多信息,请参见 [自定义提供者](https://github.com/yetone/avante.nvim/wiki/Custom-providers)
## Cursor 规划模式
因为 avante.nvim 一直使用 Aider 的方法进行规划应用,但其提示对模型要求很高,需要像 claude-3.5-sonnet 或 gpt-4o 这样的模型才能正常工作。
因此,我采用了 Cursor 的方法来实现规划应用。有关实现的详细信息,请参阅 [cursor-planning-mode.md](./cursor-planning-mode.md)
## RAG 服务
Avante 提供了一个 RAG 服务,这是一个用于获取 AI 生成代码所需上下文的工具。默认情况下,它未启用。您可以通过以下方式启用它:
```lua
rag_service = { -- RAG 服务配置
enabled = false, -- 启用 RAG 服务
host_mount = os.getenv("HOME"), -- RAG 服务的主机挂载路径 (Docker 将挂载此路径)
runner = "docker", -- RAG 服务的运行器 (可以使用 docker 或 nix)
llm = { -- RAG 服务使用的语言模型 (LLM) 配置
provider = "openai", -- LLM 提供者
endpoint = "https://api.openai.com/v1", -- LLM API 端点
api_key = "OPENAI_API_KEY", -- LLM API 密钥的环境变量名称
model = "gpt-4o-mini", -- LLM 模型名称
extra = nil, -- LLM 的额外配置选项
},
embed = { -- RAG 服务使用的嵌入模型配置
provider = "openai", -- 嵌入提供者
endpoint = "https://api.openai.com/v1", -- 嵌入 API 端点
api_key = "OPENAI_API_KEY", -- 嵌入 API 密钥的环境变量名称
model = "text-embedding-3-large", -- 嵌入模型名称
extra = nil, -- 嵌入模型的额外配置选项
},
docker_extra_args = "", -- 传递给 docker 命令的额外参数
},
```
RAG 服务可以单独设置llm模型和嵌入模型。在 `llm` 和 `embed` 配置块中,您可以设置以下字段:
- `provider`: 模型提供者(例如 "openai", "ollama", "dashscope"以及"openrouter")
- `endpoint`: API 端点
- `api_key`: API 密钥的环境变量名称
- `model`: 模型名称
- `extra`: 额外的配置选项
有关不同模型提供商的详细配置,你可以在[这里](./py/rag-service/README.md)查看。
此外,RAG 服务还依赖于 Docker!(对于 macOS 用户,推荐使用 OrbStack 作为 Docker 的替代品)。
`host_mount` 是将挂载到容器的路径,默认是主目录。挂载是 RAG 服务访问主机机器中文件所必需的。用户可以决定是否要挂载整个 `/` 目录、仅项目目录或主目录。如果您计划使用 avante 和 RAG 事件处理存储在主目录之外的项目,您需要将 `host_mount` 设置为文件系统的根目录。
挂载将是只读的。
更改 rag_service 配置后,您需要手动删除 rag_service 容器以确保使用新配置:`docker rm -fv avante-rag-service`
## Web 搜索引擎
Avante 的工具包括一些 Web 搜索引擎,目前支持:
- [Tavily](https://tavily.com/)
- [SerpApi - Search API](https://serpapi.com/)
- Google's [Programmable Search Engine](https://developers.google.com/custom-search/v1/overview)
- [Kagi](https://help.kagi.com/kagi/api/search.html)
- [Brave Search](https://api-dashboard.search.brave.com/app/documentation/web-search/get-started)
- [SearXNG](https://searxng.github.io/searxng/)
默认是 Tavily,可以通过配置 `Config.web_search_engine.provider` 进行更改:
```lua
web_search_engine = {
provider = "tavily", -- tavily, serpapi, google, kagi, brave 或 searxng
proxy = nil, -- proxy support, e.g., http://127.0.0.1:7890
}
```
提供者所需的环境变量:
- Tavily: `TAVILY_API_KEY`
- SerpApi: `SERPAPI_API_KEY`
- Google:
- `GOOGLE_SEARCH_API_KEY` 作为 [API 密钥](https://developers.google.com/custom-search/v1/overview)
- `GOOGLE_SEARCH_ENGINE_ID` 作为 [搜索引擎](https://programmablesearchengine.google.com) ID
- Kagi: `KAGI_API_KEY` 作为 [API 令牌](https://kagi.com/settings?p=api)
- Brave Search: `BRAVE_API_KEY` 作为 [API 密钥](https://api-dashboard.search.brave.com/app/keys)
- SearXNG: `SEARXNG_API_URL` 作为 [API URL](https://docs.searxng.org/dev/search_api.html)
## 禁用工具
Avante 默认启用工具,但某些 LLM 模型不支持工具。您可以通过为提供者设置 `disable_tools = true` 来禁用工具。例如:
```lua
{
claude = {
endpoint = "https://api.anthropic.com",
model = "claude-3-5-sonnet-20241022",
timeout = 30000, -- 超时时间(毫秒)
temperature = 0,
max_tokens = 4096,
disable_tools = true, -- 禁用工具!
},
}
```
如果您想禁止某些工具以避免其使用(例如 Claude 3.7 过度使用 python 工具),您可以仅禁用特定工具
```lua
{
disabled_tools = { "python" },
}
```
工具列表
> rag_search, python, git_diff, git_commit, glob, search_keyword, read_file_toplevel_symbols,
> read_file, create_file, move_path, copy_path, delete_path, create_dir, bash, web_search, fetch
## 自定义工具
Avante 允许您定义自定义工具,AI 可以在代码生成和分析期间使用这些工具。这些工具可以执行 shell 命令、运行脚本或执行您需要的任何自定义逻辑。
### 示例:Go 测试运行器
<details>
<summary>以下是一个运行 Go 单元测试的自定义工具示例:</summary>
```lua
{
custom_tools = {
{
name = "run_go_tests", -- 工具的唯一名称
description = "运行 Go 单元测试并返回结果", -- 显示给 AI 的描述
command = "go test -v ./...", -- 要执行的 shell 命令
param = { -- 输入参数(可选)
type = "table",
fields = {
{
name = "target",
description = "要测试的包或目录(例如 './pkg/...' 或 './internal/pkg')",
type = "string",
optional = true,
},
},
},
returns = { -- 预期返回值
{
name = "result",
description = "获取的结果",
type = "string",
},
{
name = "error",
description = "如果获取不成功的错误消息",
type = "string",
optional = true,
},
},
func = function(params, on_log, on_complete) -- 要执行的自定义函数
local target = params.target or "./..."
return vim.system({ "go", "test", "-v", target }, { text = true }):wait().stdout
end,
},
},
}
```
</details>
## MCP
现在您可以通过 `mcphub.nvim` 为 Avante 集成 MCP 功能。有关详细文档,请参阅 [mcphub.nvim](https://ravitemer.github.io/mcphub.nvim/extensions/avante.html)
## Claude 文本编辑器工具模式
Avante 利用 [Claude 文本编辑器工具](https://docs.anthropic.com/en/docs/build-with-claude/tool-use/text-editor-tool) 提供更优雅的代码编辑体验。您现在可以通过在 `behaviour` 配置中将 `enable_claude_text_editor_tool_mode` 设置为 `true` 来启用此功能:
```lua
{
behaviour = {
enable_claude_text_editor_tool_mode = true,
},
}
```
> [!NOTE]
> 要启用 **Claude 文本编辑器工具模式**,您必须使用 `claude-3-5-sonnet-*` 或 `claude-3-7-sonnet-*` 模型与 `claude` 提供者!此功能不支持任何其他模型!
## 自定义提示
默认情况下,`avante.nvim` 提供三种不同的模式进行交互:`planning`、`editing` 和 `suggesting`,每种模式都有三种不同的提示。
- `planning`:与侧边栏上的 `require("avante").toggle()` 一起使用
- `editing`:与选定代码块上的 `require("avante").edit()` 一起使用
- `suggesting`:与 Tab 流上的 `require("avante").get_suggestion():suggest()` 一起使用。
- `cursor-planning`:与 Tab 流上的 `require("avante").toggle()` 一起使用,但仅在启用 cursor 规划模式时。
用户可以通过 `Config.system_prompt` 或 `Config.override_prompt_dir` 自定义系统提示。
`Config.system_prompt` 允许您设置全局系统提示。我们建议根据您的需要在自定义 Autocmds 中调用此方法:
```lua
vim.api.nvim_create_autocmd("User", {
pattern = "ToggleMyPrompt",
callback = function() require("avante.config").override({system_prompt = "MY CUSTOM SYSTEM PROMPT"}) end,
})
vim.keymap.set("n", "<leader>am", function() vim.api.nvim_exec_autocmds("User", { pattern = "ToggleMyPrompt" }) end, { desc = "avante: toggle my prompt" })
```
`Config.override_prompt_dir` 允许您指定一个目录,其中包含您自己的自定义提示模板,这将覆盖内置模板。如果您想在 Neovim 配置之外维护一组自定义提示,这将非常有用。它可以是一个表示目录路径的字符串,也可以是一个返回表示目录路径的字符串的函数。
```lua
-- 示例:使用特定目录中的提示进行覆盖
require("avante").setup({
override_prompt_dir = vim.fn.expand("~/.config/nvim/avante_prompts"),
})
-- 示例:使用函数(动态目录)中的提示进行覆盖
require("avante").setup({
override_prompt_dir = function()
-- 确定提示目录的逻辑
return vim.fn.expand("~/.config/nvim/my_dynamic_prompts")
end,
})
```
> [!WARNING]
>
> 如果您自定 `base.avanterules`,请一定要确保 `{% block custom_prompt %}{% endblock %}` 和 `{% block extra_prompt %}{% endblock %}` 存在,否则可能会导致整个插件无法使用。
> 如果您不清楚具体原因或者您不知道自己在干什么,请不要覆盖内置 prompt。内置 prompt 工作得非常好。
如果希望为每种模式自定义提示,`avante.nvim` 将根据给定缓冲区的项目根目录检查是否包含以下模式:`*.{mode}.avanterules`。
根目录层次结构的规则:
- lsp 工作区文件夹
- lsp root_dir
- 当前缓冲区的文件名的根模式
- cwd 的根模式
您还可以使用 `rules` 选项为您的 `avanterules` 文件配置自定义目录:
```lua
require('avante').setup({
rules = {
project_dir = '.avante/rules', -- 相对于项目根目录,也可以是绝对路径
global_dir = '~/.config/avante/rules', -- 绝对路径
},
})
```
加载优先级如下:
1. `rules.project_dir`
2. `rules.global_dir`
3. 项目根目录
<details>
<summary>自定义提示的示例文件夹结构</summary>
如果您有以下结构:
```bash
.
├── .git/
├── typescript.planning.avanterules
├── snippets.editing.avanterules
├── suggesting.avanterules
└── src/
```
- `typescript.planning.avanterules` 将用于 `planning` 模式
- `snippets.editing.avanterules` 将用于 `editing` 模式
- `suggesting.avanterules` 将用于 `suggesting` 模式。
</details>
> [!important]
>
> `*.avanterules` 是一个 jinja 模板文件,将使用 [minijinja](https://github.com/mitsuhiko/minijinja) 渲染。有关如何扩展当前模板的示例,请参见 [templates](https://github.com/yetone/avante.nvim/blob/main/lua/avante/templates)。
## 集成
Avante.nvim 可以通过其扩展模块与其他插件协同工作。下面是一个将 Avante 与 nvim-tree 集成的示例,允许你直接从 NvimTree UI 中选择或取消选择文件:
```lua
{
"yetone/avante.nvim",
event = "VeryLazy",
keys = {
{
"<leader>a+",
function()
local tree_ext = require("avante.extensions.nvim_tree")
tree_ext.add_file()
end,
desc = "Select file in NvimTree",
ft = "NvimTree",
},
{
"<leader>a-",
function()
local tree_ext = require("avante.extensions.nvim_tree")
tree_ext.remove_file()
end,
desc = "Deselect file in NvimTree",
ft = "NvimTree",
},
},
opts = {
--- 其他配置
selector = {
exclude_auto_select = { "NvimTree" },
},
},
}
```
## TODOs
- [x] 与当前文件聊天
- [x] 应用差异补丁
- [x] 与选定的块聊天
- [x] 斜杠命令
- [x] 编辑选定的块
- [x] 智能 Tab(Cursor 流)
- [x] 与项目聊天(您可以使用 `@codebase` 与整个项目聊天)
- [x] 与选定文件聊天
- [x] 工具使用
- [x] MCP
- [ ] 更好的代码库索引
## 路线图
- **增强的 AI 交互**:提高 AI 分析和建议的深度,以应对更复杂的编码场景。
- **LSP + Tree-sitter + LLM 集成**:与 LSP 和 Tree-sitter 以及 LLM 集成,以提供更准确和强大的代码建议和分析。
## 贡献
欢迎为 avante.nvim 做出贡献!如果您有兴趣提供帮助,请随时提交拉取请求或打开问题。在贡献之前,请确保您的代码已经过彻底测试。
有关更多配方和技巧,请参见 [wiki](https://github.com/yetone/avante.nvim/wiki)。
## 致谢
我们要向以下开源项目的贡献者表示衷心的感谢,他们的代码为 avante.nvim 的开发提供了宝贵的灵感和参考:
| Nvim 插件 | 许可证 | 功能 | 位置 |
| --------------------------------------------------------------------- | ----------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| [git-conflict.nvim](https://github.com/akinsho/git-conflict.nvim) | 无许可证 | 差异比较功能 | [lua/avante/diff.lua](https://github.com/yetone/avante.nvim/blob/main/lua/avante/diff.lua) |
| [ChatGPT.nvim](https://github.com/jackMort/ChatGPT.nvim) | Apache 2.0 许可证 | 令牌计数的计算 | [lua/avante/utils/tokens.lua](https://github.com/yetone/avante.nvim/blob/main/lua/avante/utils/tokens.lua) |
| [img-clip.nvim](https://github.com/HakonHarnes/img-clip.nvim) | MIT 许可证 | 剪贴板图像支持 | [lua/avante/clipboard.lua](https://github.com/yetone/avante.nvim/blob/main/lua/avante/clipboard.lua) |
| [copilot.lua](https://github.com/zbirenbaum/copilot.lua) | MIT 许可证 | Copilot 支持 | [lua/avante/providers/copilot.lua](https://github.com/yetone/avante.nvim/blob/main/lua/avante/providers/copilot.lua) |
| [jinja.vim](https://github.com/HiPhish/jinja.vim) | MIT 许可证 | 模板文件类型支持 | [syntax/jinja.vim](https://github.com/yetone/avante.nvim/blob/main/syntax/jinja.vim) |
| [codecompanion.nvim](https://github.com/olimorris/codecompanion.nvim) | MIT 许可证 | Secrets 逻辑支持 | [lua/avante/providers/init.lua](https://github.com/yetone/avante.nvim/blob/main/lua/avante/providers/init.lua) |
| [aider](https://github.com/paul-gauthier/aider) | Apache 2.0 许可证 | 规划模式用户提示 | [lua/avante/templates/planning.avanterules](https://github.com/yetone/avante.nvim/blob/main/lua/avante/templates/planning.avanterules) |
这些项目的源代码的高质量和独创性在我们的开发过程中提供了极大的帮助。我们向这些项目的作者和贡献者表示诚挚的感谢和敬意。正是开源社区的无私奉献推动了像 avante.nvim 这样的项目向前发展。
## 商业赞助商
<table>
<tr>
<td align="center">
<a href="https://s.kiiro.ai/r/ylVbT6" target="_blank">
<img height="80" src="https://github.com/user-attachments/assets/1abd8ede-bd98-4e6e-8ee0-5a661b40344a" alt="Meshy AI" /><br/>
<strong>Meshy AI</strong>
<div> </div>
<div>为创作者提供的 #1 AI 3D 模型生成器</div>
</a>
</td>
<td align="center">
<a href="https://s.kiiro.ai/r/mGPJOd" target="_blank">
<img height="80" src="https://github.com/user-attachments/assets/7b7bd75e-1fd2-48cc-a71a-cff206e4fbd7" alt="BabelTower API" /><br/>
<strong>BabelTower API</strong>
<div> </div>
<div>无需帐户,立即使用任何模型</div>
</a>
</td>
</tr>
</table>
## 许可证
avante.nvim 根据 Apache 2.0 许可证授权。有关更多详细信息,请参阅 [LICENSE](./LICENSE) 文件。
# Star 历史
<p align="center">
<a target="_blank" href="https://star-history.com/#yetone/avante.nvim&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=yetone/avante.nvim&type=Date&theme=dark">
<img alt="NebulaGraph Data Intelligence Suite(ngdi)" src="https://api.star-history.com/svg?repos=yetone/avante.nvim&type=Date">
</picture>
</a>
</p>
================================================
FILE: autoload/avante.vim
================================================
function avante#build(...) abort
let l:source = get(a:, 1, v:false)
return join([luaeval("require('avante_lib').load()") ,luaeval("require('avante.api').build(_A)", l:source)], "\n")
endfunction
================================================
FILE: build.sh
================================================
#!/usr/bin/env bash
set -e
REPO_OWNER="yetone"
REPO_NAME="avante.nvim"
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
# Set the target directory to clone the artifact
TARGET_DIR="${SCRIPT_DIR}/build"
# Get the artifact download URL based on the platform and Lua version
case "$(uname -s)" in
Linux*)
PLATFORM="linux"
LIB_EXT="so"
;;
Darwin*)
PLATFORM="darwin"
LIB_EXT="dylib"
;;
CYGWIN* | MINGW* | MSYS*)
PLATFORM="windows"
LIB_EXT="dll"
;;
*)
echo "Unsupported platform"
exit 1
;;
esac
# Get the architecture (x86_64 or aarch64)
case "$(uname -m)" in
x86_64)
ARCH="x86_64"
;;
aarch64)
ARCH="aarch64"
;;
arm64)
ARCH="aarch64"
;;
*)
echo "Unsupported architecture"
exit 1
;;
esac
# Set the Lua version (lua54 or luajit)
LUA_VERSION="${LUA_VERSION:-luajit}"
# Set the artifact name pattern
ARTIFACT_NAME_PATTERN="avante_lib-$PLATFORM-$ARCH-$LUA_VERSION"
test_command() {
command -v "$1" >/dev/null 2>&1
}
test_gh_auth() {
if gh api user >/dev/null 2>&1; then
return 0
else
return 1
fi
}
fetch_remote_tags() {
git ls-remote --tags origin | cut -f2 | sed 's|refs/tags/||' | while read tag; do
if ! git rev-parse "$tag" >/dev/null 2>&1; then
git fetch origin "refs/tags/$tag:refs/tags/$tag"
fi
done
}
if [ ! -d "$TARGET_DIR" ]; then
mkdir -p "$TARGET_DIR"
fi
fetch_remote_tags
latest_tag="$(git describe --tags --abbrev=0 || true)" # will be empty in clone repos
built_tag="$(cat build/.tag 2>/dev/null || true)"
save_tag() {
echo "$latest_tag" > build/.tag
}
if [[ "$latest_tag" = "$built_tag" && -n "$latest_tag" ]]; then
echo "Local build is up to date $latest_tag. No download needed."
elif [[ "$latest_tag" != "$built_tag" && -n "$latest_tag" ]]; then
echo "Local build is out of date $built_tag. Downloading latest $latest_tag."
if test_command "gh" && test_gh_auth; then
gh release download "$latest_tag" --repo "github.com/$REPO_OWNER/$REPO_NAME" --pattern "*$ARTIFACT_NAME_PATTERN*" --clobber --output - | tar -zxv -C "$TARGET_DIR"
save_tag
else
# Get the artifact download URL
ARTIFACT_URL=$(curl -s "https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/releases/tags/$latest_tag" | grep "browser_download_url" | cut -d '"' -f 4 | grep $ARTIFACT_NAME_PATTERN)
set -x
mkdir -p "$TARGET_DIR"
curl -L "$ARTIFACT_URL" | tar -zxv -C "$TARGET_DIR"
save_tag
fi
else
echo "No latest tag found. Building from source."
cargo build --release --features=$LUA_VERSION
for f in target/release/lib*.$LIB_EXT; do
cp "$f" "build/$(echo $f | sed 's#.*/lib##')"
done
fi
================================================
FILE: crates/avante-html2md/Cargo.toml
================================================
[lib]
crate-type = ["cdylib"]
[package]
name = "avante-html2md"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
version.workspace = true
[dependencies]
htmd = "0.1.6"
#html2md = "0.2.15"
html2md = { git = "https://gitlab.com/Kanedias/html2md.git", rev = "850ccf756a87fedebcea707c5c981c3103019238" }
mlua.workspace = true
reqwest = { version = "0.12.12", features = ["blocking", "native-tls-vendored"] }
[lints]
workspace = true
[features]
lua51 = ["mlua/lua51"]
lua52 = ["mlua/lua52"]
lua53 = ["mlua/lua53"]
lua54 = ["mlua/lua54"]
luajit = ["mlua/luajit"]
================================================
FILE: crates/avante-html2md/src/lib.rs
================================================
use htmd::HtmlToMarkdown;
use mlua::prelude::*;
use std::error::Error;
#[derive(Debug)]
enum MyError {
HtmlToMd(String),
Request(String),
}
impl std::fmt::Display for MyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MyError::HtmlToMd(e) => write!(f, "HTML to Markdown error: {e}"),
MyError::Request(e) => write!(f, "Request error: {e}"),
}
}
}
impl Error for MyError {}
fn do_html2md(html: &str) -> Result<String, MyError> {
let converter = HtmlToMarkdown::builder()
.skip_tags(vec!["script", "style", "header", "footer"])
.build();
let md = converter
.convert(html)
.map_err(|e| MyError::HtmlToMd(e.to_string()))?;
Ok(md)
}
fn do_fetch_md(url: &str) -> Result<String, MyError> {
let mut headers = reqwest::header::HeaderMap::new();
headers.insert(
reqwest::header::USER_AGENT,
reqwest::header::HeaderValue::from_static("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"),
);
let client = reqwest::blocking::Client::builder()
.default_headers(headers)
.build()
.map_err(|e| MyError::Request(e.to_string()))?;
let response = client
.get(url)
.send()
.map_err(|e| MyError::Request(e.to_string()))?;
let body = response
.text()
.map_err(|e| MyError::Request(e.to_string()))?;
let html = body.trim().to_string();
let md = do_html2md(&html)?;
Ok(md)
}
#[mlua::lua_module]
fn avante_html2md(lua: &Lua) -> LuaResult<LuaTable> {
let exports = lua.create_table()?;
exports.set(
"fetch_md",
lua.create_function(move |_, url: String| -> LuaResult<String> {
do_fetch_md(&url).map_err(|e| mlua::Error::RuntimeError(e.to_string()))
})?,
)?;
exports.set(
"html2md",
lua.create_function(move |_, html: String| -> LuaResult<String> {
do_html2md(&html).map_err(|e| mlua::Error::RuntimeError(e.to_string()))
})?,
)?;
Ok(exports)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fetch_md() {
let md = do_fetch_md("https://github.com/yetone/avante.nvim").unwrap();
println!("{md}");
}
}
================================================
FILE: crates/avante-repo-map/Cargo.toml
================================================
[lib]
crate-type = ["cdylib"]
[package]
name = "avante-repo-map"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
version.workspace = true
[build-dependencies]
cc="*"
[dependencies]
mlua = { workspace = true }
minijinja = { workspace = true }
serde = { workspace = true, features = ["derive"] }
tree-sitter = "0.23"
tree-sitter-language = "0.1"
tree-sitter-rust = "0.23"
tree-sitter-php = "0.23.11"
tree-sitter-python = "0.23"
tree-sitter-java = "0.23.5"
tree-sitter-javascript = "0.23"
tree-sitter-typescript = "0.23"
tree-sitter-go = "0.23"
tree-sitter-c = "0.23"
tree-sitter-cpp = "0.23"
tree-sitter-lua = "0.2"
tree-sitter-ruby = "0.23"
tree-sitter-zig = "1.0.2"
tree-sitter-scala = "0.23"
tree-sitter-swift = "0.7.0"
tree-sitter-elixir = "0.3.1"
tree-sitter-c-sharp = "0.23"
[lints]
workspace = true
[features]
lua51 = ["mlua/lua51"]
lua52 = ["mlua/lua52"]
lua53 = ["mlua/lua53"]
lua54 = ["mlua/lua54"]
luajit = ["mlua/luajit"]
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-c-defs.scm
================================================
;; Capture extern functions, variables, public classes, and methods
(function_definition
(storage_class_specifier) @extern
) @function
(struct_specifier) @struct
(struct_specifier
body: (field_declaration_list
(field_declaration
declarator: (field_identifier))? @class_variable
)
)
(declaration
(storage_class_specifier) @extern
) @variable
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-c-sharp-defs.scm
================================================
(class_declaration
name: (identifier) @class
(parameter_list)? @method) ;; Primary constructor
(record_declaration
name: (identifier) @class
(parameter_list)? @method) ;; Primary constructor
(interface_declaration
name: (identifier) @class)
(method_declaration) @method
(constructor_declaration) @method
(property_declaration) @class_variable
(field_declaration
(variable_declaration
(variable_declarator))) @class_variable
(enum_declaration
body: (enum_member_declaration_list
(enum_member_declaration) @enum_item))
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-cpp-defs.scm
================================================
;; Capture functions, variables, nammespaces, classes, methods, and enums
(namespace_definition) @namespace
(function_definition) @function
(class_specifier) @class
(class_specifier
body: (field_declaration_list
(declaration
declarator: (function_declarator))? @method
(field_declaration
declarator: (function_declarator))? @method
(function_definition)? @method
(function_declarator)? @method
(field_declaration
declarator: (field_identifier))? @class_variable
)
)
(struct_specifier) @struct
(struct_specifier
body: (field_declaration_list
(declaration
declarator: (function_declarator))? @method
(field_declaration
declarator: (function_declarator))? @method
(function_definition)? @method
(function_declarator)? @method
(field_declaration
declarator: (field_identifier))? @class_variable
)
)
((declaration type: (_))) @variable
(enumerator_list ((enumerator) @enum_item))
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-elixir-defs.scm
================================================
; * modules and protocols
(call
target: (identifier) @ignore
(arguments (alias) @class)
(#match? @ignore "^(defmodule|defprotocol)$"))
; * functions
(call
target: (identifier) @ignore
(arguments
[
; zero-arity functions with no parentheses
(identifier) @method
; regular function clause
(call target: (identifier) @method)
; function clause with a guard clause
(binary_operator
left: (call target: (identifier) @method)
operator: "when")
])
(#match? @ignore "^(def|defdelegate|defguard|defn)$"))
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-go-defs.scm
================================================
;; Capture top-level functions and struct definitions
(source_file
(var_declaration
(var_spec) @variable
)
)
(source_file
(const_declaration
(const_spec) @variable
)
)
(source_file
(function_declaration) @function
)
(source_file
(type_declaration
(type_spec (struct_type)) @class
)
)
(source_file
(type_declaration
(type_spec
(struct_type
(field_declaration_list
(field_declaration) @class_variable)))
)
)
(source_file
(method_declaration) @method
)
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-java-defs.scm
================================================
;; Capture exported functions, arrow functions, variables, classes, and method definitions
(class_declaration
name: (identifier) @class)
(interface_declaration
name: (identifier) @class)
(enum_declaration
name: (identifier) @enum)
(enum_constant
name: (identifier) @enum_item)
(class_body
(field_declaration) @class_variable)
(class_body
(constructor_declaration) @method)
(class_body
(method_declaration) @method)
(interface_body
(method_declaration) @method)
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-javascript-defs.scm
================================================
;; Capture exported functions, arrow functions, variables, classes, and method definitions
(export_statement
declaration: (lexical_declaration
(variable_declarator) @variable
)
)
(export_statement
declaration: (function_declaration) @function
)
(export_statement
declaration: (class_declaration
body: (class_body
(field_definition) @class_variable
)
)
)
(export_statement
declaration: (class_declaration
body: (class_body
(method_definition) @method
)
)
)
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-lua-defs.scm
================================================
;; Capture function and method definitions
(variable_list) @variable
(function_declaration) @function
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-php-defs.scm
================================================
;; Capture exported functions, arrow functions, variables, classes, and method definitions
(class_declaration) @class
(interface_declaration) @class
(function_definition) @function
(assignment_expression) @assignment
(const_declaration
(const_element
(name) @variable))
(_
body: (declaration_list
(property_declaration) @class_variable))
(_
body: (declaration_list
(method_declaration) @method))
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-python-defs.scm
================================================
;; Capture top-level functions, class, and method definitions
(module
(expression_statement
(assignment) @assignment
)
)
(module
(function_definition) @function
)
(module
(class_definition
body: (block
(expression_statement
(assignment) @class_assignment
)
)
)
)
(module
(class_definition
body: (block
(function_definition) @method
)
)
)
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-ruby-defs.scm
================================================
;; Capture top-level methods, class definitions, and methods within classes
(class
(body_statement
(call)? @class_call
(assignment)? @class_assignment
(method)? @method
)
) @class
(program
(method) @function
)
(program
(assignment) @assignment
)
(module) @module
(module
(body_statement
(call)? @class_call
(assignment)? @class_assignment
(method)? @method
)
)
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-rust-defs.scm
================================================
;; Capture public functions, structs, methods, and variable definitions
(function_item) @function
(impl_item
body: (declaration_list
(function_item) @method
)
)
(struct_item) @class
(struct_item
body: (field_declaration_list
(field_declaration) @class_variable
)
)
(enum_item
body: (enum_variant_list
(enum_variant) @enum_item
)
)
(const_item) @variable
(static_item) @variable
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-scala-defs.scm
================================================
(class_definition
name: (identifier) @class)
(object_definition
name: (identifier) @class)
(trait_definition
name: (identifier) @class)
(simple_enum_case
name: (identifier) @enum_item)
(full_enum_case
name: (identifier) @enum_item)
(template_body
(function_definition) @method
)
(template_body
(function_declaration) @method
)
(template_body
(val_definition) @class_variable
)
(template_body
(val_declaration) @class_variable
)
(template_body
(var_definition) @class_variable
)
(template_body
(var_declaration) @class_variable
)
(compilation_unit
(function_definition) @function
)
(compilation_unit
(val_definition) @variable
)
(compilation_unit
(var_definition) @variable
)
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-swift-defs.scm
================================================
(property_declaration) @variable
(function_declaration) @function
(class_declaration
_?
[
"struct"
"class"
]) @class
(class_declaration
_?
"enum"
) @enum
(class_body
(property_declaration) @class_variable)
(class_body
(function_declaration) @method)
(class_body
(init_declaration) @method)
(protocol_declaration
body: (protocol_body
(protocol_function_declaration) @function))
(protocol_declaration
body: (protocol_body
(protocol_property_declaration) @class_variable))
(class_declaration
body: (enum_class_body
(enum_entry) @enum_item))
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-typescript-defs.scm
================================================
;; Capture exported functions, arrow functions, variables, classes, and method definitions
(export_statement
declaration: (lexical_declaration
(variable_declarator) @variable
)
)
(export_statement
declaration: (function_declaration) @function
)
(export_statement
declaration: (class_declaration
body: (class_body
(public_field_definition) @class_variable
)
)
)
(interface_declaration
body: (interface_body
(property_signature) @class_variable
)
)
(type_alias_declaration
value: (object_type
(property_signature) @class_variable
)
)
(export_statement
declaration: (class_declaration
body: (class_body
(method_definition) @method
)
)
)
================================================
FILE: crates/avante-repo-map/queries/tree-sitter-zig-defs.scm
================================================
;; Capture functions, structs, methods, variable definitions, and unions in Zig
(variable_declaration (identifier)
(struct_declaration
(container_field) @class_variable))
(variable_declaration (identifier)
(struct_declaration
(function_declaration
name: (identifier) @method)))
(variable_declaration (identifier)
(enum_declaration
(container_field
type: (identifier) @enum_item)))
(variable_declaration (identifier)
(union_declaration
(container_field
name: (identifier) @union_item)))
(source_file (function_declaration) @function)
(source_file (variable_declaration (identifier) @variable))
================================================
FILE: crates/avante-repo-map/src/lib.rs
================================================
#![allow(clippy::unnecessary_map_or)]
use mlua::prelude::*;
use std::cell::RefCell;
use std::collections::BTreeMap;
use tree_sitter::{Node, Parser, Query, QueryCursor};
use tree_sitter_language::LanguageFn;
#[derive(Debug, Clone)]
pub struct Func {
pub name: String,
pub params: String,
pub return_type: String,
pub accessibility_modifier: Option<String>,
}
#[derive(Debug, Clone)]
pub struct Class {
pub type_name: String,
pub name: String,
pub methods: Vec<Func>,
pub properties: Vec<Variable>,
pub visibility_modifier: Option<String>,
}
#[derive(Debug, Clone)]
pub struct Enum {
pub name: String,
pub items: Vec<Variable>,
}
#[derive(Debug, Clone)]
pub struct Union {
pub name: String,
pub items: Vec<Variable>,
}
#[derive(Debug, Clone)]
pub struct Variable {
pub name: String,
pub value_type: String,
}
#[derive(Debug, Clone)]
pub enum Definition {
Func(Func),
Class(Class),
Module(Class),
Enum(Enum),
Variable(Variable),
Union(Union),
// TODO: Namespace support
}
fn get_ts_language(language: &str) -> Option<LanguageFn> {
match language {
"rust" => Some(tree_sitter_rust::LANGUAGE),
"python" => Some(tree_sitter_python::LANGUAGE),
"php" => Some(tree_sitter_php::LANGUAGE_PHP),
"java" => Some(tree_sitter_java::LANGUAGE),
"javascript" => Some(tree_sitter_javascript::LANGUAGE),
"typescript" => Some(tree_sitter_typescript::LANGUAGE_TSX),
"go" => Some(tree_sitter_go::LANGUAGE),
"c" => Some(tree_sitter_c::LANGUAGE),
"cpp" => Some(tree_sitter_cpp::LANGUAGE),
"lua" => Some(tree_sitter_lua::LANGUAGE),
"ruby" => Some(tree_sitter_ruby::LANGUAGE),
"zig" => Some(tree_sitter_zig::LANGUAGE),
"scala" => Some(tree_sitter_scala::LANGUAGE),
"swift" => Some(tree_sitter_swift::LANGUAGE),
"elixir" => Some(tree_sitter_elixir::LANGUAGE),
"csharp" => Some(tree_sitter_c_sharp::LANGUAGE),
_ => None,
}
}
const C_QUERY: &str = include_str!("../queries/tree-sitter-c-defs.scm");
const CPP_QUERY: &str = include_str!("../queries/tree-sitter-cpp-defs.scm");
const GO_QUERY: &str = include_str!("../queries/tree-sitter-go-defs.scm");
const JAVA_QUERY: &str = include_str!("../queries/tree-sitter-java-defs.scm");
const JAVASCRIPT_QUERY: &str = include_str!("../queries/tree-sitter-javascript-defs.scm");
const LUA_QUERY: &str = include_str!("../queries/tree-sitter-lua-defs.scm");
const PYTHON_QUERY: &str = include_str!("../queries/tree-sitter-python-defs.scm");
const PHP_QUERY: &str = include_str!("../queries/tree-sitter-php-defs.scm");
const RUST_QUERY: &str = include_str!("../queries/tree-sitter-rust-defs.scm");
const ZIG_QUERY: &str = include_str!("../queries/tree-sitter-zig-defs.scm");
const TYPESCRIPT_QUERY: &str = include_str!("../queries/tree-sitter-typescript-defs.scm");
const RUBY_QUERY: &str = include_str!("../queries/tree-sitter-ruby-defs.scm");
const SCALA_QUERY: &str = include_str!("../queries/tree-sitter-scala-defs.scm");
const SWIFT_QUERY: &str = include_str!("../queries/tree-sitter-swift-defs.scm");
const ELIXIR_QUERY: &str = include_str!("../queries/tree-sitter-elixir-defs.scm");
const CSHARP_QUERY: &str = include_str!("../queries/tree-sitter-c-sharp-defs.scm");
fn get_definitions_query(language: &str) -> Result<Query, String> {
let ts_language = get_ts_language(language);
if ts_language.is_none() {
return Err(format!("Unsupported language: {language}"));
}
let ts_language = ts_language.unwrap();
let contents = match language {
"c" => C_QUERY,
"cpp" => CPP_QUERY,
"go" => GO_QUERY,
"java" => JAVA_QUERY,
"javascript" => JAVASCRIPT_QUERY,
"lua" => LUA_QUERY,
"php" => PHP_QUERY,
"python" => PYTHON_QUERY,
"rust" => RUST_QUERY,
"zig" => ZIG_QUERY,
"typescript" => TYPESCRIPT_QUERY,
"ruby" => RUBY_QUERY,
"scala" => SCALA_QUERY,
"swift" => SWIFT_QUERY,
"elixir" => ELIXIR_QUERY,
"csharp" => CSHARP_QUERY,
_ => return Err(format!("Unsupported language: {language}")),
};
let query = Query::new(&ts_language.into(), contents)
.unwrap_or_else(|e| panic!("Failed to parse query for {language}: {e}"));
Ok(query)
}
fn get_closest_ancestor_name(node: &Node, source: &str) -> String {
let mut parent = node.parent();
while let Some(parent_node) = parent {
let name_node = parent_node.child_by_field_name("name");
if let Some(name_node) = name_node {
return get_node_text(&name_node, source.as_bytes()).to_string();
}
parent = parent_node.parent();
}
String::new()
}
fn find_ancestor_by_type<'a>(node: &'a Node, parent_type: &str) -> Option<Node<'a>> {
let mut parent = node.parent();
while let Some(parent_node) = parent {
if parent_node.kind() == parent_type {
return Some(parent_node);
}
parent = parent_node.parent();
}
None
}
fn find_first_ancestor_by_types<'a>(
node: &'a Node,
possible_parent_types: &[&str],
) -> Option<Node<'a>> {
let mut parent = node.parent();
while let Some(parent_node) = parent {
if possible_parent_types.contains(&parent_node.kind()) {
return Some(parent_node);
}
parent = parent_node.parent();
}
None
}
fn find_descendant_by_type<'a>(node: &'a Node, child_type: &str) -> Option<Node<'a>> {
let mut cursor = node.walk();
for i in 0..node.descendant_count() {
cursor.goto_descendant(i);
let node = cursor.node();
if node.kind() == child_type {
return Some(node);
}
}
None
}
fn ruby_method_is_private<'a>(node: &'a Node, source: &'a [u8]) -> bool {
let mut prev_sibling = node.prev_sibling();
while let Some(prev_sibling_node) = prev_sibling {
if prev_sibling_node.kind() == "identifier" {
let text = prev_sibling_node.utf8_text(source).unwrap_or_default();
if text == "private" {
return true;
} else if text == "public" || text == "protected" {
return false;
}
} else if prev_sibling_node.kind() == "class" || prev_sibling_node.kind() == "module" {
return false;
}
prev_sibling = prev_sibling_node.prev_sibling();
}
false
}
fn find_child_by_type<'a>(node: &'a Node, child_type: &str) -> Option<Node<'a>> {
node.children(&mut node.walk())
.find(|child| child.kind() == child_type)
}
// Zig-specific function to find the parent variable declaration
fn zig_find_parent_variable_declaration_name<'a>(
node: &'a Node,
source: &'a [u8],
) -> Option<String> {
let vardec = find_ancestor_by_type(node, "variable_declaration");
if let Some(vardec) = vardec {
// Find the identifier child node, which represents the class name
let identifier_node = find_child_by_type(&vardec, "identifier");
if let Some(identifier_node) = identifier_node {
return Some(get_node_text(&identifier_node, source));
}
}
None
}
fn zig_is_declaration_public<'a>(node: &'a Node, declaration_type: &str, source: &'a [u8]) -> bool {
let declaration = find_ancestor_by_type(node, declaration_type);
if let Some(declaration) = declaration {
let declaration_text = get_node_text(&declaration, source);
return declaration_text.starts_with("pub");
}
false
}
fn zig_is_variable_declaration_public<'a>(node: &'a Node, source: &'a [u8]) -> bool {
zig_is_declaration_public(node, "variable_declaration", source)
}
fn zig_is_function_declaration_public<'a>(node: &'a Node, source: &'a [u8]) -> bool {
zig_is_declaration_public(node, "function_declaration", source)
}
fn zig_find_type_in_parent<'a>(node: &'a Node, source: &'a [u8]) -> Option<String> {
// First go to the parent and then get the child_by_field_name "type"
if let Some(parent) = node.parent() {
if let Some(type_node) = parent.child_by_field_name("type") {
return Some(get_node_text(&type_node, source));
}
}
None
}
fn csharp_is_primary_constructor(node: &Node) -> bool {
node.kind() == "parameter_list"
&& node.parent().map_or(false, |n| {
n.kind() == "class_declaration" || n.kind() == "record_declaration"
})
}
fn csharp_find_parent_type_node<'a>(node: &'a Node) -> Option<Node<'a>> {
find_first_ancestor_by_types(node, &["class_declaration", "record_declaration"])
}
fn ex_find_parent_module_declaration_name<'a>(node: &'a Node, source: &'a [u8]) -> Option<String> {
let mut parent = node.parent();
while let Some(parent_node) = parent {
if parent_node.kind() == "call" {
let text = get_node_text(&parent_node, source);
if text.starts_with("defmodule ") {
let arguments_node = find_child_by_type(&parent_node, "arguments");
if let Some(arguments_node) = arguments_node {
return Some(get_node_text(&arguments_node, source));
}
}
}
parent = parent_node.parent();
}
None
}
fn ruby_find_parent_module_declaration_name<'a>(
node: &'a Node,
source: &'a [u8],
) -> Option<String> {
let mut path_parts = Vec::new();
let mut current = Some(*node);
while let Some(current_node) = current {
if current_node.kind() == "module" || current_node.kind() == "class" {
if let Some(name_node) = current_node.child_by_field_name("name") {
path_parts.push(get_node_text(&name_node, source));
}
}
current = current_node.parent();
}
if path_parts.is_empty() {
None
} else {
path_parts.reverse();
Some(path_parts.join("::"))
}
}
fn get_node_text<'a>(node: &'a Node, source: &'a [u8]) -> String {
node.utf8_text(source).unwrap_or_default().to_string()
}
fn get_node_type<'a>(node: &'a Node, source: &'a [u8]) -> String {
let predefined_type_node = find_descendant_by_type(node, "predefined_type");
if let Some(type_node) = predefined_type_node {
return type_node.utf8_text(source).unwrap().to_string();
}
let value_type_node = node.child_by_field_name("type");
value_type_node
.map(|n| n.utf8_text(source).unwrap().to_string())
.unwrap_or_default()
}
fn is_first_letter_uppercase(name: &str) -> bool {
if name.is_empty() {
return false;
}
name.chars().next().unwrap().is_uppercase()
}
// Given a language, parse the given source code and return exported definitions
fn extract_definitions(language: &str, source: &str) -> Result<Vec<Definition>, String> {
let ts_language = get_ts_language(language);
if ts_language.is_none() {
return Ok(vec![]);
}
let ts_language = ts_language.unwrap();
let mut definitions = Vec::new();
let mut parser = Parser::new();
parser
.set_language(&ts_language.into())
.unwrap_or_else(|_| panic!("Failed to set language for {language}"));
let tree = parser
.parse(source, None)
.unwrap_or_else(|| panic!("Failed to parse source code for {language}"));
let root_node = tree.root_node();
let query = get_definitions_query(language)?;
let mut query_cursor = QueryCursor::new();
let captures = query_cursor.captures(&query, root_node, source.as_bytes());
let mut class_def_map: BTreeMap<String, RefCell<Class>> = BTreeMap::new();
let mut enum_def_map: BTreeMap<String, RefCell<Enum>> = BTreeMap::new();
let mut union_def_map: BTreeMap<String, RefCell<Union>> = BTreeMap::new();
let ensure_class_def =
|language: &str, name: &str, class_def_map: &mut BTreeMap<String, RefCell<Class>>| {
let mut type_name = "class";
if language == "elixir" {
type_name = "module";
}
class_def_map.entry(name.to_string()).or_insert_with(|| {
RefCell::new(Class {
type_name: type_name.to_string(),
name: name.to_string(),
methods: vec![],
properties: vec![],
visibility_modifier: None,
})
});
};
let ensure_module_def = |name: &str, class_def_map: &mut BTreeMap<String, RefCell<Class>>| {
class_def_map.entry(name.to_string()).or_insert_with(|| {
RefCell::new(Class {
name: name.to_string(),
type_name: "module".to_string(),
methods: vec![],
properties: vec![],
visibility_modifier: None,
})
});
};
let ensure_enum_def = |name: &str, enum_def_map: &mut BTreeMap<String, RefCell<Enum>>| {
enum_def_map.entry(name.to_string()).or_insert_with(|| {
RefCell::new(Enum {
name: name.to_string(),
items: vec![],
})
});
};
let ensure_union_def = |name: &str, union_def_map: &mut BTreeMap<String, RefCell<Union>>| {
union_def_map.entry(name.to_string()).or_insert_with(|| {
RefCell::new(Union {
name: name.to_string(),
items: vec![],
})
});
};
// Sometimes, multiple queries capture the same node with the same capture name.
// We need to ensure that we only add the node to the definition map once.
let mut captured_nodes: BTreeMap<String, Vec<usize>> = BTreeMap::new();
for (m, _) in captures {
for capture in m.captures {
let capture_name = &query.capture_names()[capture.index as usize];
let node = capture.node;
let node_text = node.utf8_text(source.as_bytes()).unwrap();
let node_id = node.id();
if captured_nodes
.get(*capture_name)
.map_or(false, |v| v.contains(&node_id))
{
continue;
}
captured_nodes
.entry(String::from(*capture_name))
.or_default()
.push(node_id);
let name = match language {
"cpp" => {
if *capture_name == "class" {
node.child_by_field_name("name")
.map(|n| n.utf8_text(source.as_bytes()).unwrap())
.unwrap_or(node_text)
.to_string()
} else {
let ident = find_descendant_by_type(&node, "field_identifier")
.or_else(|| find_descendant_by_type(&node, "operator_name"))
.or_else(|| find_descendant_by_type(&node, "identifier"))
.map(|n| n.utf8_text(source.as_bytes()).unwrap());
if let Some(ident) = ident {
let scope = node
.child_by_field_name("declarator")
.and_then(|n| n.child_by_field_name("declarator"))
.and_then(|n| n.child_by_field_name("scope"));
if let Some(scope_node) = scope {
format!(
"{}::{}",
scope_node.utf8_text(source.as_bytes()).unwrap(),
ident
)
} else {
ident.to_string()
}
} else {
node_text.to_string()
}
}
}
"scala" => node
.child_by_field_name("name")
.or_else(|| node.child_by_field_name("pattern"))
.map(|n| n.utf8_text(source.as_bytes()).unwrap())
.unwrap_or(node_text)
.to_string(),
"csharp" => {
let mut identifier = node;
// Handle primary constructors (they are direct children of *_declaration)
if *capture_name == "method" && csharp_is_primary_constructor(&node) {
identifier = node.parent().unwrap_or(node);
} else if *capture_name == "class_variable" {
identifier =
find_descendant_by_type(&node, "variable_declarator").unwrap_or(node);
}
identifier
.child_by_field_name("name")
.map(|n| n.utf8_text(source.as_bytes()).unwrap())
.unwrap_or(node_text)
.to_string()
}
"ruby" => {
let name = node
.child_by_field_name("name")
.map(|n| n.utf8_text(source.as_bytes()).unwrap())
.unwrap_or(node_text)
.to_string();
if *capture_name == "class" || *capture_name == "module" {
ruby_find_parent_module_declaration_name(&node, source.as_bytes())
.unwrap_or(name)
} else {
name
}
}
_ => node
.child_by_field_name("name")
.map(|n| n.utf8_text(source.as_bytes()).unwrap())
.unwrap_or(node_text)
.to_string(),
};
match *capture_name {
"class" => {
if !name.is_empty() {
if language == "go" && !is_first_letter_uppercase(&name) {
continue;
}
ensure_class_def(language, &name, &mut class_def_map);
let visibility_modifier_node =
find_child_by_type(&node, "visibility_modifier");
let visibility_modifier = visibility_modifier_node
.map(|n| n.utf8_text(source.as_bytes()).unwrap())
.unwrap_or("");
let class_def = class_def_map.get_mut(&name).unwrap();
class_def.borrow_mut().visibility_modifier =
if visibility_modifier.is_empty() {
None
} else {
Some(visibility_modifier.to_string())
};
}
}
"module" => {
if !name.is_empty() {
ensure_module_def(&name, &mut class_def_map);
}
}
"enum_item" => {
let visibility_modifier_node =
find_descendant_by_type(&node, "visibility_modifier");
let visibility_modifier = visibility_modifier_node
.map(|n| n.utf8_text(source.as_bytes()).unwrap())
.unwrap_or("");
if language == "rust" && !visibility_modifier.contains("pub") {
continue;
}
if language == "zig"
&& !zig_is_variable_declaration_public(&node, source.as_bytes())
{
continue;
}
let mut enum_name = get_closest_ancestor_name(&node, source);
if language == "zig" {
enum_name =
zig_find_parent_variable_declaration_name(&node, source.as_bytes())
.unwrap_or_default();
}
if language == "scala" {
if let Some(enum_node) = find_ancestor_by_type(&node, "enum_definition") {
if let Some(name_node) = enum_node.child_by_field_name("name") {
enum_name =
name_node.utf8_text(source.as_bytes()).unwrap().to_string();
}
}
}
if !enum_name.is_empty()
&& language == "go"
&& !is_first_letter_uppercase(&enum_name)
{
continue;
}
ensure_enum_def(&enum_name, &mut enum_def_map);
let enum_def = enum_def_map.get_mut(&enum_name).unwrap();
let enum_type_node = find_descendant_by_type(&node, "type_identifier");
let enum_type = enum_type_node
.map(|n| n.utf8_text(source.as_bytes()).unwrap())
.unwrap_or("");
let variable = Variable {
name: name.to_string(),
value_type: enum_type.to_string(),
};
enum_def.borrow_mut().items.push(variable);
}
"union_item" => {
if language != "zig" {
continue;
}
if !zig_is_variable_declaration_public(&node, source.as_bytes()) {
continue;
}
let union_name =
zig_find_parent_variable_declaration_name(&node, source.as_bytes())
.unwrap_or_default();
ensure_union_def(&union_name, &mut union_def_map);
let union_def = union_def_map.get_mut(&union_name).unwrap();
let union_type_node = find_descendant_by_type(&node, "type_identifier");
let union_type = union_type_node
.map(|n| n.utf8_text(source.as_bytes()).unwrap())
.unwrap_or("");
let variable = Variable {
name: name.to_string(),
value_type: union_type.to_string(),
};
union_def.borrow_mut().items.push(variable);
}
"method" => {
// TODO: C++: Skip private/protected class/struct methods
let visibility_modifier_node =
find_descendant_by_type(&node, "visibility_modifier");
let visibility_modifier = visibility_modifier_node
.map(|n| n.utf8_text(source.as_bytes()).unwrap())
.unwrap_or("");
if language == "swift" {
if visibility_modifier.contains("private") {
continue;
}
}
if language == "java" {
let modifier_node = find_descendant_by_type(&node, "modifiers");
if modifier_node.is_some() {
let modifier_text =
modifier_node.unwrap().utf8_text(source.as_bytes()).unwrap();
if modifier_text.contains("private") {
continue;
}
}
}
if language == "rust" && !visibility_modifier.contains("pub") {
continue;
}
if language == "zig"
&& !(zig_is_function_declaration_public(&node, source.as_bytes())
&& zig_is_variable_declaration_public(&node, source.as_bytes()))
{
continue;
}
if language == "cpp"
&& find_descendant_by_type(&node, "destructor_name").is_some()
{
continue;
}
if !name.is_empty() && language == "go" && !is_first_letter_uppercase(&name) {
continue;
}
if language == "csharp" {
let csharp_visibility = find_descendant_by_type(&node, "modifier");
if csharp_visibility.is_none() && !csharp_is_primary_constructor(&node) {
continue;
}
if csharp_visibility.is_some() {
let csharp_visibility_text = csharp_visibility
.unwrap()
.utf8_text(source.as_bytes())
.unwrap();
if csharp_visibility_text == "private" {
continue;
}
}
}
let mut params_node = node
.child_by_field_name("parameters")
.or_else(|| find_descendant_by_type(&node, "parameter_list"));
let zig_function_node = find_ancestor_by_type(&node, "function_declaration");
if language == "zig" {
params_node = zig_function_node
.as_ref()
.and_then(|n| find_child_by_type(n, "parameters"));
}
let ex_function_node = find_ancestor_by_type(&node, "call");
if language == "elixir" {
params_node = ex_function_node
.as_ref()
.and_then(|n| find_child_by_type(n, "arguments"));
}
let params = params_node
.map(|n| n.utf8_text(source.as_bytes()).unwrap())
.unwrap_or("()");
let mut return_type_node = match language {
"cpp" => node.child_by_field_name("type"),
"csharp" => node.child_by_field_name("returns"),
_ => node.child_by_field_name("return_type"),
};
if language == "cpp" {
let class_specifier_node = find_ancestor_by_type(&node, "class_specifier");
let type_identifier_node =
class_specifier_node.and_then(|n| n.child_by_field_name("name"));
if let Some(type_identifier_node) = type_identifier_node {
let type_identifier_text =
type_identifier_node.utf8_text(source.as_bytes()).unwrap();
if name == type_identifier_text {
return_type_node = Some(type_identifier_node);
}
}
}
if language == "csharp" {
let type_specifier_node = csharp_find_parent_type_node(&node);
let type_identifier_node =
type_specifier_node.and_then(|n| n.child_by_field_name("name"));
if let Some(type_identifier_node) = type_identifier_node {
let type_identifier_text =
type_identifier_node.utf8_text(source.as_bytes()).unwrap();
if name == type_identifier_text {
return_type_node = Some(type_identifier_node);
}
}
}
if return_type_node.is_none() {
return_type_node = node.child_by_field_name("result");
}
let mut return_type = "void".to_string();
if language == "elixir" {
return_type = String::new();
}
if return_type_node.is_some() {
return_type = get_node_type(&return_type_node.unwrap(), source.as_bytes());
if return_type.is_empty() {
return_type = return_type_node
.unwrap()
.utf8_text(source.as_bytes())
.unwrap_or("void")
.to_string();
}
}
let impl_item_node = find_ancestor_by_type(&node, "impl_item");
let receiver_node = node.child_by_field_name("receiver");
let class_name = if language == "zig" {
zig_find_parent_variable_declaration_name(&node, source.as_bytes())
.unwrap_or_default()
} else if language == "elixir" {
ex_find_parent_module_declaration_name(&node, source.as_bytes())
.unwrap_or_default()
} else if language == "cpp" {
find_ancestor_by_type(&node, "class_specifier")
.or_else(|| find_ancestor_by_type(&node, "struct_specifier"))
.and_then(|n| n.child_by_field_name("name"))
.and_then(|n| n.utf8_text(source.as_bytes()).ok())
.unwrap_or("")
.to_string()
} else if language == "csharp" {
csharp_find_parent_type_node(&node)
.and_then(|n| n.child_by_field_name("name"))
.and_then(|n| n.utf8_text(source.as_bytes()).ok())
.unwrap_or("")
.to_string()
} else if language == "ruby" {
ruby_find_parent_module_declaration_name(&node, source.as_bytes())
.unwrap_or_default()
} else if let Some(impl_item) = impl_item_node {
let impl_type_node = impl_item.child_by_field_name("type");
impl_type_node
.map(|n| n.utf8_text(source.as_bytes()).unwrap())
.unwrap_or("")
.to_string()
} else if let Some(receiver) = receiver_node {
let type_identifier_node =
find_descendant_by_type(&receiver, "type_identifier");
type_identifier_node
.map(|n| n.utf8_text(source.as_bytes()).unwrap())
.unwrap_or("")
.to_string()
} else {
get_closest_ancestor_name(&node, source).to_string()
};
if language == "go" && !is_first_letter_uppercase(&class_name) {
continue;
}
ensure_class_def(language, &class_name, &mut class_def_map);
let class_def = class_def_map.get_mut(&class_name).unwrap();
let accessibility_modifier_node =
find_descendant_by_type(&node, "accessibility_modifier");
let accessibility_modifier = if language == "ruby" {
if ruby_method_is_private(&node, source.as_bytes()) {
"private"
} else {
""
}
} else {
accessibility_modifier_node
.map(|n| n.utf8_text(source.as_bytes()).unwrap())
.unwrap_or("")
};
let func = Func {
name: name.to_string(),
params: params.to_string(),
return_type: return_type.to_string(),
accessibility_modifier: if accessibility_modifier.is_empty() {
None
} else {
Some(accessibility_modifier.to_string())
},
};
class_def.borrow_mut().methods.push(func);
}
"class_assignment" => {
let visibility_modifier_node =
find_descendant_by_type(&node, "visibility_modifier");
gitextract_wdvhrp8a/
├── .cargo/
│ └── config.toml
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ └── feature_request.yml
│ └── workflows/
│ ├── close-stale-issues-and-prs.yaml
│ ├── lua.yaml
│ ├── pre-commit.yaml
│ ├── release.yaml
│ └── rust.yaml
├── .gitignore
├── .luacheckrc
├── .pre-commit-config.yaml
├── Build.ps1
├── Cargo.toml
├── LICENSE
├── Makefile
├── README.md
├── README_zh.md
├── autoload/
│ └── avante.vim
├── build.sh
├── crates/
│ ├── avante-html2md/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ ├── avante-repo-map/
│ │ ├── Cargo.toml
│ │ ├── queries/
│ │ │ ├── tree-sitter-c-defs.scm
│ │ │ ├── tree-sitter-c-sharp-defs.scm
│ │ │ ├── tree-sitter-cpp-defs.scm
│ │ │ ├── tree-sitter-elixir-defs.scm
│ │ │ ├── tree-sitter-go-defs.scm
│ │ │ ├── tree-sitter-java-defs.scm
│ │ │ ├── tree-sitter-javascript-defs.scm
│ │ │ ├── tree-sitter-lua-defs.scm
│ │ │ ├── tree-sitter-php-defs.scm
│ │ │ ├── tree-sitter-python-defs.scm
│ │ │ ├── tree-sitter-ruby-defs.scm
│ │ │ ├── tree-sitter-rust-defs.scm
│ │ │ ├── tree-sitter-scala-defs.scm
│ │ │ ├── tree-sitter-swift-defs.scm
│ │ │ ├── tree-sitter-typescript-defs.scm
│ │ │ └── tree-sitter-zig-defs.scm
│ │ └── src/
│ │ └── lib.rs
│ ├── avante-templates/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ └── avante-tokenizers/
│ ├── Cargo.toml
│ ├── README.md
│ └── src/
│ └── lib.rs
├── lua/
│ ├── avante/
│ │ ├── api.lua
│ │ ├── auth/
│ │ │ └── pkce.lua
│ │ ├── clipboard.lua
│ │ ├── config.lua
│ │ ├── diff.lua
│ │ ├── extensions/
│ │ │ ├── init.lua
│ │ │ └── nvim_tree.lua
│ │ ├── file_selector.lua
│ │ ├── health.lua
│ │ ├── highlights.lua
│ │ ├── history/
│ │ │ ├── helpers.lua
│ │ │ ├── init.lua
│ │ │ ├── message.lua
│ │ │ └── render.lua
│ │ ├── history_selector.lua
│ │ ├── html2md.lua
│ │ ├── init.lua
│ │ ├── libs/
│ │ │ ├── ReAct_parser.lua
│ │ │ ├── ReAct_parser2.lua
│ │ │ ├── acp_client.lua
│ │ │ ├── jsonparser.lua
│ │ │ └── xmlparser.lua
│ │ ├── llm.lua
│ │ ├── llm_tools/
│ │ │ ├── attempt_completion.lua
│ │ │ ├── base.lua
│ │ │ ├── bash.lua
│ │ │ ├── create.lua
│ │ │ ├── delete_tool_use_messages.lua
│ │ │ ├── dispatch_agent.lua
│ │ │ ├── edit_file.lua
│ │ │ ├── get_diagnostics.lua
│ │ │ ├── glob.lua
│ │ │ ├── grep.lua
│ │ │ ├── helpers.lua
│ │ │ ├── init.lua
│ │ │ ├── insert.lua
│ │ │ ├── ls.lua
│ │ │ ├── read_todos.lua
│ │ │ ├── replace_in_file.lua
│ │ │ ├── str_replace.lua
│ │ │ ├── think.lua
│ │ │ ├── undo_edit.lua
│ │ │ ├── view.lua
│ │ │ ├── write_to_file.lua
│ │ │ └── write_todos.lua
│ │ ├── model_selector.lua
│ │ ├── path.lua
│ │ ├── providers/
│ │ │ ├── azure.lua
│ │ │ ├── bedrock/
│ │ │ │ └── claude.lua
│ │ │ ├── bedrock.lua
│ │ │ ├── claude.lua
│ │ │ ├── cohere.lua
│ │ │ ├── copilot.lua
│ │ │ ├── gemini.lua
│ │ │ ├── init.lua
│ │ │ ├── ollama.lua
│ │ │ ├── openai.lua
│ │ │ ├── vertex.lua
│ │ │ ├── vertex_claude.lua
│ │ │ └── watsonx_code_assistant.lua
│ │ ├── rag_service.lua
│ │ ├── range.lua
│ │ ├── repo_map.lua
│ │ ├── selection.lua
│ │ ├── selection_result.lua
│ │ ├── sidebar.lua
│ │ ├── suggestion.lua
│ │ ├── templates/
│ │ │ ├── _context.avanterules
│ │ │ ├── _diagnostics.avanterules
│ │ │ ├── _environments.avanterules
│ │ │ ├── _gpt4-1-agentic.avanterules
│ │ │ ├── _memory.avanterules
│ │ │ ├── _project.avanterules
│ │ │ ├── _task-guidelines.avanterules
│ │ │ ├── _tools-guidelines.avanterules
│ │ │ ├── agentic.avanterules
│ │ │ ├── base.avanterules
│ │ │ ├── editing.avanterules
│ │ │ ├── legacy.avanterules
│ │ │ └── suggesting.avanterules
│ │ ├── tokenizers.lua
│ │ ├── types.lua
│ │ ├── ui/
│ │ │ ├── acp_confirm_adapter.lua
│ │ │ ├── button_group_line.lua
│ │ │ ├── confirm.lua
│ │ │ ├── input/
│ │ │ │ ├── init.lua
│ │ │ │ └── providers/
│ │ │ │ ├── dressing.lua
│ │ │ │ ├── native.lua
│ │ │ │ └── snacks.lua
│ │ │ ├── line.lua
│ │ │ ├── prompt_input.lua
│ │ │ └── selector/
│ │ │ ├── init.lua
│ │ │ └── providers/
│ │ │ ├── fzf_lua.lua
│ │ │ ├── mini_pick.lua
│ │ │ ├── native.lua
│ │ │ ├── snacks.lua
│ │ │ └── telescope.lua
│ │ └── utils/
│ │ ├── diff2search_replace.lua
│ │ ├── environment.lua
│ │ ├── file.lua
│ │ ├── init.lua
│ │ ├── logo.lua
│ │ ├── lru_cache.lua
│ │ ├── lsp.lua
│ │ ├── path.lua
│ │ ├── platform.lua
│ │ ├── promptLogger.lua
│ │ ├── prompts.lua
│ │ ├── root.lua
│ │ ├── streaming_json_parser.lua
│ │ ├── test.lua
│ │ └── tokens.lua
│ ├── avante_lib.lua
│ └── cmp_avante/
│ ├── commands.lua
│ ├── mentions.lua
│ └── shortcuts.lua
├── luarc.json.template
├── plugin/
│ └── avante.lua
├── py/
│ └── rag-service/
│ ├── Dockerfile
│ ├── README.md
│ ├── gitconfig
│ ├── requirements.txt
│ ├── run.sh
│ ├── shell.nix
│ └── src/
│ ├── libs/
│ │ ├── __init__.py
│ │ ├── configs.py
│ │ ├── db.py
│ │ ├── logger.py
│ │ └── utils.py
│ ├── main.py
│ ├── models/
│ │ ├── __init__.py
│ │ ├── indexing_history.py
│ │ └── resource.py
│ ├── providers/
│ │ ├── __init__.py
│ │ ├── dashscope.py
│ │ ├── factory.py
│ │ ├── ollama.py
│ │ ├── openai.py
│ │ └── openrouter.py
│ └── services/
│ ├── __init__.py
│ ├── indexing_history.py
│ └── resource.py
├── pyrightconfig.json
├── ruff.toml
├── scripts/
│ ├── lua-typecheck.sh
│ ├── run-luatest.sh
│ └── setup-deps.sh
├── stylua.toml
├── syntax/
│ └── jinja.vim
└── tests/
├── data/
│ ├── claude_token_error_response.json
│ └── claude_token_response.json
├── libs/
│ ├── acp_client_spec.lua
│ └── jsonparser_spec.lua
├── llm_spec.lua
├── llm_tools/
│ └── helpers_spec.lua
├── llm_tools_spec.lua
├── providers/
│ ├── bedrock_spec.lua
│ ├── claude_spec.lua
│ └── watsonx_code_assistant_spec.lua
├── rag_service_spec.lua
├── ui/
│ └── acp_confirm_adapter_spec.lua
└── utils/
├── file_spec.lua
├── fix_diff_spec.lua
├── get_parent_path_spec.lua
├── init_spec.lua
├── join_paths_spec.lua
├── make_relative_path_spec.lua
└── streaming_json_parser_spec.lua
SYMBOL INDEX (171 symbols across 16 files)
FILE: crates/avante-html2md/src/lib.rs
type MyError (line 6) | enum MyError {
method fmt (line 12) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
function do_html2md (line 22) | fn do_html2md(html: &str) -> Result<String, MyError> {
function do_fetch_md (line 32) | fn do_fetch_md(url: &str) -> Result<String, MyError> {
function avante_html2md (line 55) | fn avante_html2md(lua: &Lua) -> LuaResult<LuaTable> {
function test_fetch_md (line 77) | fn test_fetch_md() {
FILE: crates/avante-repo-map/src/lib.rs
type Func (line 10) | pub struct Func {
type Class (line 18) | pub struct Class {
type Enum (line 27) | pub struct Enum {
type Union (line 33) | pub struct Union {
type Variable (line 39) | pub struct Variable {
type Definition (line 45) | pub enum Definition {
function get_ts_language (line 55) | fn get_ts_language(language: &str) -> Option<LanguageFn> {
constant C_QUERY (line 77) | const C_QUERY: &str = include_str!("../queries/tree-sitter-c-defs.scm");
constant CPP_QUERY (line 78) | const CPP_QUERY: &str = include_str!("../queries/tree-sitter-cpp-defs.sc...
constant GO_QUERY (line 79) | const GO_QUERY: &str = include_str!("../queries/tree-sitter-go-defs.scm");
constant JAVA_QUERY (line 80) | const JAVA_QUERY: &str = include_str!("../queries/tree-sitter-java-defs....
constant JAVASCRIPT_QUERY (line 81) | const JAVASCRIPT_QUERY: &str = include_str!("../queries/tree-sitter-java...
constant LUA_QUERY (line 82) | const LUA_QUERY: &str = include_str!("../queries/tree-sitter-lua-defs.sc...
constant PYTHON_QUERY (line 83) | const PYTHON_QUERY: &str = include_str!("../queries/tree-sitter-python-d...
constant PHP_QUERY (line 84) | const PHP_QUERY: &str = include_str!("../queries/tree-sitter-php-defs.sc...
constant RUST_QUERY (line 85) | const RUST_QUERY: &str = include_str!("../queries/tree-sitter-rust-defs....
constant ZIG_QUERY (line 86) | const ZIG_QUERY: &str = include_str!("../queries/tree-sitter-zig-defs.sc...
constant TYPESCRIPT_QUERY (line 87) | const TYPESCRIPT_QUERY: &str = include_str!("../queries/tree-sitter-type...
constant RUBY_QUERY (line 88) | const RUBY_QUERY: &str = include_str!("../queries/tree-sitter-ruby-defs....
constant SCALA_QUERY (line 89) | const SCALA_QUERY: &str = include_str!("../queries/tree-sitter-scala-def...
constant SWIFT_QUERY (line 90) | const SWIFT_QUERY: &str = include_str!("../queries/tree-sitter-swift-def...
constant ELIXIR_QUERY (line 91) | const ELIXIR_QUERY: &str = include_str!("../queries/tree-sitter-elixir-d...
constant CSHARP_QUERY (line 92) | const CSHARP_QUERY: &str = include_str!("../queries/tree-sitter-c-sharp-...
function get_definitions_query (line 94) | fn get_definitions_query(language: &str) -> Result<Query, String> {
function get_closest_ancestor_name (line 124) | fn get_closest_ancestor_name(node: &Node, source: &str) -> String {
function find_ancestor_by_type (line 136) | fn find_ancestor_by_type<'a>(node: &'a Node, parent_type: &str) -> Optio...
function find_first_ancestor_by_types (line 147) | fn find_first_ancestor_by_types<'a>(
function find_descendant_by_type (line 161) | fn find_descendant_by_type<'a>(node: &'a Node, child_type: &str) -> Opti...
function ruby_method_is_private (line 173) | fn ruby_method_is_private<'a>(node: &'a Node, source: &'a [u8]) -> bool {
function find_child_by_type (line 191) | fn find_child_by_type<'a>(node: &'a Node, child_type: &str) -> Option<No...
function zig_find_parent_variable_declaration_name (line 197) | fn zig_find_parent_variable_declaration_name<'a>(
function zig_is_declaration_public (line 212) | fn zig_is_declaration_public<'a>(node: &'a Node, declaration_type: &str,...
function zig_is_variable_declaration_public (line 221) | fn zig_is_variable_declaration_public<'a>(node: &'a Node, source: &'a [u...
function zig_is_function_declaration_public (line 225) | fn zig_is_function_declaration_public<'a>(node: &'a Node, source: &'a [u...
function zig_find_type_in_parent (line 229) | fn zig_find_type_in_parent<'a>(node: &'a Node, source: &'a [u8]) -> Opti...
function csharp_is_primary_constructor (line 239) | fn csharp_is_primary_constructor(node: &Node) -> bool {
function csharp_find_parent_type_node (line 246) | fn csharp_find_parent_type_node<'a>(node: &'a Node) -> Option<Node<'a>> {
function ex_find_parent_module_declaration_name (line 250) | fn ex_find_parent_module_declaration_name<'a>(node: &'a Node, source: &'...
function ruby_find_parent_module_declaration_name (line 267) | fn ruby_find_parent_module_declaration_name<'a>(
function get_node_text (line 291) | fn get_node_text<'a>(node: &'a Node, source: &'a [u8]) -> String {
function get_node_type (line 295) | fn get_node_type<'a>(node: &'a Node, source: &'a [u8]) -> String {
function is_first_letter_uppercase (line 306) | fn is_first_letter_uppercase(name: &str) -> bool {
function extract_definitions (line 314) | fn extract_definitions(language: &str, source: &str) -> Result<Vec<Defin...
function stringify_function (line 1185) | fn stringify_function(func: &Func) -> String {
function stringify_variable (line 1201) | fn stringify_variable(variable: &Variable) -> String {
function stringify_enum_item (line 1209) | fn stringify_enum_item(item: &Variable) -> String {
function stringify_union_item (line 1217) | fn stringify_union_item(item: &Variable) -> String {
function stringify_class (line 1225) | fn stringify_class(class: &Class) -> String {
function stringify_enum (line 1238) | fn stringify_enum(enum_def: &Enum) -> String {
function stringify_union (line 1246) | fn stringify_union(union_def: &Union) -> String {
function stringify_definitions (line 1255) | fn stringify_definitions(definitions: &Vec<Definition>) -> String {
function get_definitions_string (line 1273) | pub fn get_definitions_string(language: &str, source: &str) -> LuaResult...
function avante_repo_map (line 1281) | fn avante_repo_map(lua: &Lua) -> LuaResult<LuaTable> {
function test_rust (line 1297) | fn test_rust() {
function test_zig (line 1355) | fn test_zig() {
function test_go (line 1426) | fn test_go() {
function test_python (line 1473) | fn test_python() {
function test_typescript (line 1504) | fn test_typescript() {
function test_javascript (line 1554) | fn test_javascript() {
function test_ruby (line 1601) | fn test_ruby() {
function test_ruby2 (line 1643) | fn test_ruby2() {
function test_lua (line 1698) | fn test_lua() {
function test_c (line 1718) | fn test_c() {
function test_cpp (line 1743) | fn test_cpp() {
function test_scala (line 1809) | fn test_scala() {
function test_elixir (line 1848) | fn test_elixir() {
function test_csharp (line 1888) | fn test_csharp() {
function test_swift (line 1942) | fn test_swift() {
function test_php (line 1987) | fn test_php() {
function test_java (line 2015) | fn test_java() {
function test_unsupported_language (line 2041) | fn test_unsupported_language() {
FILE: crates/avante-templates/src/lib.rs
type State (line 7) | struct State<'a> {
function new (line 12) | fn new() -> Self {
type SelectedCode (line 20) | struct SelectedCode {
type SelectedFile (line 27) | struct SelectedFile {
type TemplateContext (line 34) | struct TemplateContext {
function render (line 54) | fn render(state: &State, template: &str, context: TemplateContext) -> Lu...
function initialize (line 89) | fn initialize(state: &State, cache_directory: String, project_directory:...
function avante_templates (line 126) | fn avante_templates(lua: &Lua) -> LuaResult<LuaTable> {
FILE: crates/avante-tokenizers/src/lib.rs
type Tiktoken (line 9) | struct Tiktoken {
method new (line 14) | fn new(model: &str) -> Self {
method encode (line 19) | fn encode(&self, text: &str) -> (Vec<u32>, usize, usize) {
type HuggingFaceTokenizer (line 27) | struct HuggingFaceTokenizer {
method new (line 37) | fn new(model: &str) -> Self {
method encode (line 53) | fn encode(&self, text: &str) -> (Vec<u32>, usize, usize) {
method get_cached_tokenizer (line 61) | fn get_cached_tokenizer(url: &str) -> PathBuf {
function is_valid_url (line 31) | fn is_valid_url(url: &str) -> bool {
type TokenizerType (line 82) | enum TokenizerType {
type State (line 87) | struct State {
method new (line 92) | fn new() -> Self {
function encode (line 99) | fn encode(state: &State, text: &str) -> LuaResult<(Vec<u32>, usize, usiz...
function from_pretrained (line 110) | fn from_pretrained(state: &State, model: &str) {
function avante_tokenizers (line 119) | fn avante_tokenizers(lua: &Lua) -> LuaResult<LuaTable> {
function test_tiktoken (line 144) | fn test_tiktoken() {
function test_hf (line 155) | fn test_hf() {
function test_roundtrip (line 166) | fn test_roundtrip() {
function test_public_url (line 181) | fn test_public_url() {
FILE: py/rag-service/src/libs/db.py
function get_db_connection (line 46) | def get_db_connection() -> Generator[sqlite3.Connection, None, None]:
function init_db (line 56) | def init_db() -> None:
FILE: py/rag-service/src/libs/utils.py
function uri_to_path (line 14) | def uri_to_path(uri: str) -> Path:
function path_to_uri (line 19) | def path_to_uri(file_path: Path) -> str:
function is_local_uri (line 27) | def is_local_uri(uri: str) -> bool:
function is_remote_uri (line 32) | def is_remote_uri(uri: str) -> bool:
function is_path_node (line 37) | def is_path_node(node: BaseNode) -> bool:
function get_node_uri (line 45) | def get_node_uri(node: BaseNode) -> str | None:
function inject_uri_to_node (line 60) | def inject_uri_to_node(node: BaseNode) -> None:
FILE: py/rag-service/src/main.py
function try_acquire_leadership (line 73) | def try_acquire_leadership() -> bool:
function lifespan (line 94) | async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: # noqa:...
function is_remote_resource_exists (line 273) | def is_remote_resource_exists(url: str) -> bool:
function fetch_markdown (line 287) | def fetch_markdown(url: str) -> str:
function markdown_to_links (line 300) | def markdown_to_links(base_url: str, markdown: str) -> list[str]:
class ResourceURIRequest (line 410) | class ResourceURIRequest(BaseModel):
class ResourceRequest (line 416) | class ResourceRequest(ResourceURIRequest):
class SourceDocument (line 422) | class SourceDocument(BaseModel):
class RetrieveRequest (line 430) | class RetrieveRequest(BaseModel):
class RetrieveResponse (line 441) | class RetrieveResponse(BaseModel):
class FileSystemHandler (line 448) | class FileSystemHandler(FileSystemEventHandler):
method __init__ (line 451) | def __init__(self: FileSystemHandler, directory: Path) -> None:
method on_modified (line 455) | def on_modified(self: FileSystemHandler, event: FileSystemEvent) -> None:
method on_created (line 460) | def on_created(self: FileSystemHandler, event: FileSystemEvent) -> None:
method handle_file_change (line 465) | def handle_file_change(self: FileSystemHandler, file_path: Path) -> None:
function is_valid_text (line 481) | def is_valid_text(text: str) -> bool:
function clean_text (line 497) | def clean_text(text: str) -> str:
function process_document_batch (line 502) | def process_document_batch(documents: list[Document]) -> bool: # noqa: ...
function get_gitignore_files (line 596) | def get_gitignore_files(directory: Path) -> list[str]:
function get_gitcrypt_files (line 613) | def get_gitcrypt_files(directory: Path) -> list[str]:
function get_pathspec (line 695) | def get_pathspec(directory: Path) -> pathspec.PathSpec | None:
function scan_directory (line 704) | def scan_directory(directory: Path) -> list[str]:
function update_index_for_file (line 811) | def update_index_for_file(directory: Path, abs_file_path: Path) -> None:
function split_documents (line 851) | def split_documents(documents: list[Document]) -> list[Document]:
function index_remote_resource_async (line 909) | async def index_remote_resource_async(resource: Resource) -> None:
function index_local_resource_async (line 972) | async def index_local_resource_async(resource: Resource) -> None:
function readiness_probe (line 1021) | async def readiness_probe() -> dict[str, str]:
function add_resource (line 1039) | async def add_resource(request: ResourceRequest, background_tasks: Backg...
function remove_resource (line 1127) | async def remove_resource(request: ResourceURIRequest): # noqa: D103, A...
function retrieve (line 1158) | async def retrieve(request: RetrieveRequest): # noqa: D103, ANN201, C90...
class IndexingStatusRequest (line 1301) | class IndexingStatusRequest(BaseModel):
class IndexingStatusResponse (line 1307) | class IndexingStatusResponse(BaseModel):
function get_indexing_status_for_resource (line 1334) | async def get_indexing_status_for_resource(request: IndexingStatusReques...
class ResourceListResponse (line 1362) | class ResourceListResponse(BaseModel):
function list_resources (line 1389) | async def list_resources() -> ResourceListResponse:
function health_check (line 1407) | async def health_check() -> dict[str, str]:
FILE: py/rag-service/src/models/indexing_history.py
class IndexingHistory (line 9) | class IndexingHistory(BaseModel):
FILE: py/rag-service/src/models/resource.py
class Resource (line 9) | class Resource(BaseModel):
FILE: py/rag-service/src/providers/dashscope.py
function initialize_embed_model (line 11) | def initialize_embed_model(
function initialize_llm_model (line 42) | def initialize_llm_model(
FILE: py/rag-service/src/providers/factory.py
function initialize_embed_model (line 13) | def initialize_embed_model(
function initialize_llm_model (line 97) | def initialize_llm_model(
FILE: py/rag-service/src/providers/ollama.py
function initialize_embed_model (line 11) | def initialize_embed_model(
function initialize_llm_model (line 40) | def initialize_llm_model(
FILE: py/rag-service/src/providers/openai.py
function initialize_embed_model (line 11) | def initialize_embed_model(
function initialize_llm_model (line 41) | def initialize_llm_model(
FILE: py/rag-service/src/providers/openrouter.py
function initialize_llm_model (line 9) | def initialize_llm_model(
FILE: py/rag-service/src/services/indexing_history.py
class IndexingHistoryService (line 13) | class IndexingHistoryService:
method delete_indexing_status (line 14) | def delete_indexing_status(self, uri: str) -> None:
method delete_indexing_status_by_document_id (line 26) | def delete_indexing_status_by_document_id(self, document_id: str) -> N...
method update_indexing_status (line 38) | def update_indexing_status(
method get_indexing_status (line 106) | def get_indexing_status(self, doc: Document | None = None, base_uri: s...
FILE: py/rag-service/src/services/resource.py
class ResourceService (line 7) | class ResourceService:
method add_resource_to_db (line 10) | def add_resource_to_db(self, resource: Resource) -> None:
method update_resource_indexing_status (line 29) | def update_resource_indexing_status(self, uri: str, indexing_status: s...
method update_resource_status (line 52) | def update_resource_status(self, uri: str, status: str, error: str | N...
method get_resource (line 75) | def get_resource(self, uri: str) -> Resource | None:
method get_resource_by_name (line 86) | def get_resource_by_name(self, name: str) -> Resource | None:
method get_all_resources (line 97) | def get_all_resources(self) -> list[Resource]:
Condensed preview — 215 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,664K chars).
[
{
"path": ".cargo/config.toml",
"chars": 295,
"preview": "[target.x86_64-apple-darwin]\nrustflags = [\"-C\", \"link-arg=-undefined\", \"-C\", \"link-arg=dynamic_lookup\"]\n\n[target.aarch64"
},
{
"path": ".editorconfig",
"chars": 234,
"preview": "; https://editorconfig.org/\n\nroot = true\n\n[*]\ninsert_final_newline = true\ncharset = utf-8\ntrim_trailing_whitespace = tru"
},
{
"path": ".gitattributes",
"chars": 126,
"preview": "* text=auto eol=lf\n**/*.lock linguist-generated=true\n*.avanterules linguist-language=jinja\nsyntax/jinja.vim linguist-ven"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 3441,
"preview": "name: 🐛 Bug Report\ndescription: Create a bug report to help us improve Avante\ntitle: 'bug: '\nlabels: ['bug']\nbody:\n - t"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 40,
"preview": "blank_issues_enabled: true\nversion: 2.1\n"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.yml",
"chars": 1117,
"preview": "name: 🚀 Feature Request\ndescription: Submit a proposal/request for new Avante feature.\ntitle: 'feature: '\nlabels: ['new-"
},
{
"path": ".github/workflows/close-stale-issues-and-prs.yaml",
"chars": 973,
"preview": "name: 'Close stale issues and PRs'\non:\n schedule:\n - cron: '30 1 * * *'\n\npermissions:\n contents: write # only for d"
},
{
"path": ".github/workflows/lua.yaml",
"chars": 2260,
"preview": "name: Lua CI\n\non:\n push:\n branches:\n - main\n paths:\n - \"**/*.lua\"\n - .github/workflows/lua.yaml\n "
},
{
"path": ".github/workflows/pre-commit.yaml",
"chars": 1162,
"preview": "name: pre-commit\n\non:\n pull_request:\n types: [labeled, opened, reopened, synchronize]\n push:\n branches: [main, t"
},
{
"path": ".github/workflows/release.yaml",
"chars": 7554,
"preview": "name: Release\n\non:\n push:\n tags: [v\\d+\\.\\d+\\.\\d+]\n\npermissions:\n contents: write\n packages: write\n\nenv:\n CARGO_TE"
},
{
"path": ".github/workflows/rust.yaml",
"chars": 805,
"preview": "name: Rust CI\n\non:\n push:\n branches:\n - main\n paths:\n - \"crates/**/*\"\n - \"Cargo.lock\"\n - \"Car"
},
{
"path": ".gitignore",
"chars": 805,
"preview": "*.so\n# Lua compiled files\n*.lua~\n*.luac\n\n.venv\n__pycache__/\n\n# Neovim plugin specific files\nplugin/packer_compiled.lua\n\n"
},
{
"path": ".luacheckrc",
"chars": 596,
"preview": "-- Rerun tests only if their modification time changed.\ncache = true\n\n-- Glorious list of warnings: https://luacheck.rea"
},
{
"path": ".pre-commit-config.yaml",
"chars": 1093,
"preview": "repos:\n- repo: https://github.com/pre-commit/pre-commit-hooks\n rev: v5.0.0\n hooks:\n - id: check-yaml\n - id: end-"
},
{
"path": "Build.ps1",
"chars": 4069,
"preview": "param (\n [string]$Version = \"luajit\",\n [string]$BuildFromSource = \"false\"\n)\n\n$Build = [System.Convert]::ToBoolean("
},
{
"path": "Cargo.toml",
"chars": 1618,
"preview": "[workspace]\nmembers = [\"crates/*\"]\nresolver = \"2\"\n\n[workspace.package]\nedition = \"2021\"\nrust-version = \"1.80\"\nlicense = "
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "Makefile",
"chars": 3195,
"preview": "UNAME := $(shell uname)\nARCH := $(shell uname -m)\n\nifeq ($(UNAME), Linux)\n\tOS := linux\n\tEXT := so\nelse ifeq ($(UNAME), D"
},
{
"path": "README.md",
"chars": 68255,
"preview": "<div align=\"center\">\n <img alt=\"logo\" width=\"120\" src=\"https://github.com/user-attachments/assets/2e2f2a58-2b28-4d11-af"
},
{
"path": "README_zh.md",
"chars": 36864,
"preview": "<div align=\"center\">\n <img alt=\"logo\" width=\"120\" src=\"https://github.com/user-attachments/assets/2e2f2a58-2b28-4d11-af"
},
{
"path": "autoload/avante.vim",
"chars": 199,
"preview": "function avante#build(...) abort\n let l:source = get(a:, 1, v:false)\n return join([luaeval(\"require('avante_lib').load"
},
{
"path": "build.sh",
"chars": 2637,
"preview": "#!/usr/bin/env bash\n\nset -e\n\nREPO_OWNER=\"yetone\"\nREPO_NAME=\"avante.nvim\"\n\nSCRIPT_DIR=\"$(cd -- \"$(dirname -- \"${BASH_SOUR"
},
{
"path": "crates/avante-html2md/Cargo.toml",
"chars": 592,
"preview": "[lib]\ncrate-type = [\"cdylib\"]\n\n[package]\nname = \"avante-html2md\"\nedition.workspace = true\nrust-version.workspace = true\n"
},
{
"path": "crates/avante-html2md/src/lib.rs",
"chars": 2332,
"preview": "use htmd::HtmlToMarkdown;\nuse mlua::prelude::*;\nuse std::error::Error;\n\n#[derive(Debug)]\nenum MyError {\n HtmlToMd(Str"
},
{
"path": "crates/avante-repo-map/Cargo.toml",
"chars": 969,
"preview": "[lib]\ncrate-type = [\"cdylib\"]\n\n[package]\nname = \"avante-repo-map\"\nedition.workspace = true\nrust-version.workspace = true"
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-c-defs.scm",
"chars": 359,
"preview": ";; Capture extern functions, variables, public classes, and methods\n(function_definition\n (storage_class_specifier) @ex"
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-c-sharp-defs.scm",
"chars": 548,
"preview": "(class_declaration\n name: (identifier) @class\n (parameter_list)? @method) ;; Primary constructor\n\n(record_declaration"
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-cpp-defs.scm",
"chars": 959,
"preview": ";; Capture functions, variables, nammespaces, classes, methods, and enums\n(namespace_definition) @namespace\n(function_de"
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-elixir-defs.scm",
"chars": 569,
"preview": "; * modules and protocols\n(call\n target: (identifier) @ignore\n (arguments (alias) @class)\n (#match? @ignore \"^(defmod"
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-go-defs.scm",
"chars": 510,
"preview": ";; Capture top-level functions and struct definitions\n(source_file\n (var_declaration\n (var_spec) @variable\n )\n)\n(so"
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-java-defs.scm",
"chars": 485,
"preview": ";; Capture exported functions, arrow functions, variables, classes, and method definitions\n\n(class_declaration\n name: ("
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-javascript-defs.scm",
"chars": 502,
"preview": ";; Capture exported functions, arrow functions, variables, classes, and method definitions\n(export_statement\n declarati"
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-lua-defs.scm",
"chars": 102,
"preview": ";; Capture function and method definitions\n(variable_list) @variable\n(function_declaration) @function\n"
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-php-defs.scm",
"chars": 424,
"preview": ";; Capture exported functions, arrow functions, variables, classes, and method definitions\n\n(class_declaration) @class\n("
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-python-defs.scm",
"chars": 398,
"preview": ";; Capture top-level functions, class, and method definitions\n(module\n (expression_statement\n (assignment) @assignme"
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-ruby-defs.scm",
"chars": 401,
"preview": ";; Capture top-level methods, class definitions, and methods within classes\n\n(class\n (body_statement\n (call)? @class"
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-rust-defs.scm",
"chars": 402,
"preview": ";; Capture public functions, structs, methods, and variable definitions\n(function_item) @function\n(impl_item\n body: (de"
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-scala-defs.scm",
"chars": 717,
"preview": "(class_definition\n name: (identifier) @class)\n\n(object_definition\n name: (identifier) @class)\n\n(trait_definition\n nam"
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-swift-defs.scm",
"chars": 608,
"preview": "(property_declaration) @variable\n\n(function_declaration) @function\n\n\n(class_declaration\n\t_?\n\t[\n\t \"struct\"\n\t \"class\"\n\t]) "
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-typescript-defs.scm",
"chars": 696,
"preview": ";; Capture exported functions, arrow functions, variables, classes, and method definitions\n(export_statement\n declarati"
},
{
"path": "crates/avante-repo-map/queries/tree-sitter-zig-defs.scm",
"chars": 655,
"preview": " ;; Capture functions, structs, methods, variable definitions, and unions in Zig\n(variable_declaration (identifier)\n (s"
},
{
"path": "crates/avante-repo-map/src/lib.rs",
"chars": 80279,
"preview": "#![allow(clippy::unnecessary_map_or)]\n\nuse mlua::prelude::*;\nuse std::cell::RefCell;\nuse std::collections::BTreeMap;\nuse"
},
{
"path": "crates/avante-templates/Cargo.toml",
"chars": 456,
"preview": "[lib]\ncrate-type = [\"cdylib\"]\n\n[package]\nname = \"avante-templates\"\nedition.workspace = true\nrust-version.workspace = tru"
},
{
"path": "crates/avante-templates/src/lib.rs",
"chars": 4877,
"preview": "use minijinja::{context, Environment};\nuse mlua::prelude::*;\nuse serde::{Deserialize, Serialize};\nuse std::path::Path;\nu"
},
{
"path": "crates/avante-tokenizers/Cargo.toml",
"chars": 664,
"preview": "[lib]\ncrate-type = [\"cdylib\"]\n\n[package]\nname = \"avante-tokenizers\"\nedition = { workspace = true }\nversion = { workspace"
},
{
"path": "crates/avante-tokenizers/README.md",
"chars": 54,
"preview": "A simple crate to unify hf/tokenizers and tiktoken-rs\n"
},
{
"path": "crates/avante-tokenizers/src/lib.rs",
"chars": 6090,
"preview": "use hf_hub::{api::sync::ApiBuilder, Repo, RepoType};\nuse mlua::prelude::*;\nuse regex::Regex;\nuse std::path::PathBuf;\nuse"
},
{
"path": "lua/avante/api.lua",
"chars": 10832,
"preview": "local Config = require(\"avante.config\")\nlocal Utils = require(\"avante.utils\")\nlocal PromptInput = require(\"avante.ui.pro"
},
{
"path": "lua/avante/auth/pkce.lua",
"chars": 3635,
"preview": "local M = {}\nlocal uv = vim.uv\n\n-- Generates sha256 bytes with vim.fn\nlocal function sha256_bytes(data)\n -- vim.fn.sha2"
},
{
"path": "lua/avante/clipboard.lua",
"chars": 2100,
"preview": "---NOTE: this module is inspired by https://github.com/HakonHarnes/img-clip.nvim/tree/main\n---@see https://github.com/ek"
},
{
"path": "lua/avante/config.lua",
"chars": 40811,
"preview": "---NOTE: user will be merged with defaults and\n---we add a default var_accessor for this table to config values.\n\n---@al"
},
{
"path": "lua/avante/diff.lua",
"chars": 21601,
"preview": "local api = vim.api\n\nlocal Config = require(\"avante.config\")\nlocal Utils = require(\"avante.utils\")\nlocal Highlights = re"
},
{
"path": "lua/avante/extensions/init.lua",
"chars": 208,
"preview": "---@class avante.extensions\nlocal M = {}\n\nsetmetatable(M, {\n __index = function(t, k)\n ---@diagnostic disable-next-l"
},
{
"path": "lua/avante/extensions/nvim_tree.lua",
"chars": 1691,
"preview": "local Api = require(\"avante.api\")\n\n--- @class avante.extensions.nvim_tree\nlocal M = {}\n\n--- Adds the currently selected "
},
{
"path": "lua/avante/file_selector.lua",
"chars": 11327,
"preview": "local Utils = require(\"avante.utils\")\nlocal Config = require(\"avante.config\")\nlocal Selector = require(\"avante.ui.select"
},
{
"path": "lua/avante/health.lua",
"chars": 3157,
"preview": "local M = {}\nlocal H = require(\"vim.health\")\nlocal Utils = require(\"avante.utils\")\nlocal Config = require(\"avante.config"
},
{
"path": "lua/avante/highlights.lua",
"chars": 9671,
"preview": "local api = vim.api\n\nlocal Config = require(\"avante.config\")\nlocal Utils = require(\"avante.utils\")\nlocal bit = require(\""
},
{
"path": "lua/avante/history/helpers.lua",
"chars": 3311,
"preview": "local Utils = require(\"avante.utils\")\n\nlocal M = {}\n\n---If message is a text message return the text.\n---@param message "
},
{
"path": "lua/avante/history/init.lua",
"chars": 13173,
"preview": "local Helpers = require(\"avante.history.helpers\")\nlocal Message = require(\"avante.history.message\")\nlocal Utils = requir"
},
{
"path": "lua/avante/history/message.lua",
"chars": 2205,
"preview": "local Utils = require(\"avante.utils\")\n\n---@class avante.HistoryMessage\nlocal M = {}\nM.__index = M\n\n---@class avante.Hist"
},
{
"path": "lua/avante/history/render.lua",
"chars": 21479,
"preview": "local Helpers = require(\"avante.history.helpers\")\nlocal Line = require(\"avante.ui.line\")\nlocal Utils = require(\"avante.u"
},
{
"path": "lua/avante/history_selector.lua",
"chars": 2285,
"preview": "local History = require(\"avante.history\")\nlocal Utils = require(\"avante.utils\")\nlocal Path = require(\"avante.path\")\nloca"
},
{
"path": "lua/avante/html2md.lua",
"chars": 685,
"preview": "---@class AvanteHtml2Md\n---@field fetch_md fun(url: string): string\nlocal _html2md_lib = nil\n\nlocal M = {}\n\n---@return A"
},
{
"path": "lua/avante/init.lua",
"chars": 17250,
"preview": "local api = vim.api\n\nlocal Utils = require(\"avante.utils\")\nlocal Sidebar = require(\"avante.sidebar\")\nlocal Selection = r"
},
{
"path": "lua/avante/libs/ReAct_parser.lua",
"chars": 10080,
"preview": "local M = {}\n\n-- Helper function to parse a parameter tag like <param_name>value</param_name>\n-- Returns {name = string,"
},
{
"path": "lua/avante/libs/ReAct_parser2.lua",
"chars": 6577,
"preview": "local JsonParser = require(\"avante.libs.jsonparser\")\n\n---@class avante.TextContent\n---@field type \"text\"\n---@field text "
},
{
"path": "lua/avante/libs/acp_client.lua",
"chars": 30037,
"preview": "local Config = require(\"avante.config\")\nlocal Utils = require(\"avante.utils\")\n\n---@class avante.acp.ClientCapabilities\n-"
},
{
"path": "lua/avante/libs/jsonparser.lua",
"chars": 16988,
"preview": "-- JSON Streaming Parser for Lua\nlocal JsonParser = {}\n\n-- 流式解析器状态\nlocal StreamParser = {}\nStreamParser.__index = Stream"
},
{
"path": "lua/avante/libs/xmlparser.lua",
"chars": 17125,
"preview": "-- XML Parser for Lua\nlocal XmlParser = {}\n\n-- 流式解析器状态\nlocal StreamParser = {}\nStreamParser.__index = StreamParser\n\n-- 创"
},
{
"path": "lua/avante/llm.lua",
"chars": 82133,
"preview": "local api = vim.api\nlocal fn = vim.fn\nlocal uv = vim.uv\n\nlocal curl = require(\"plenary.curl\")\nlocal ACPClient = require("
},
{
"path": "lua/avante/llm_tools/attempt_completion.lua",
"chars": 4456,
"preview": "local Base = require(\"avante.llm_tools.base\")\nlocal Config = require(\"avante.config\")\nlocal Highlights = require(\"avante"
},
{
"path": "lua/avante/llm_tools/base.lua",
"chars": 117,
"preview": "local M = {}\n\nfunction M:__call(opts, on_log, on_complete) return self.func(opts, on_log, on_complete) end\n\nreturn M\n"
},
{
"path": "lua/avante/llm_tools/bash.lua",
"chars": 12547,
"preview": "local Path = require(\"plenary.path\")\nlocal Utils = require(\"avante.utils\")\nlocal Helpers = require(\"avante.llm_tools.hel"
},
{
"path": "lua/avante/llm_tools/create.lua",
"chars": 2979,
"preview": "local Path = require(\"plenary.path\")\nlocal Utils = require(\"avante.utils\")\nlocal Base = require(\"avante.llm_tools.base\")"
},
{
"path": "lua/avante/llm_tools/delete_tool_use_messages.lua",
"chars": 1817,
"preview": "local Base = require(\"avante.llm_tools.base\")\nlocal History = require(\"avante.history\")\n\n---@class AvanteLLMTool\nlocal M"
},
{
"path": "lua/avante/llm_tools/dispatch_agent.lua",
"chars": 11654,
"preview": "local Providers = require(\"avante.providers\")\nlocal Config = require(\"avante.config\")\nlocal Utils = require(\"avante.util"
},
{
"path": "lua/avante/llm_tools/edit_file.lua",
"chars": 9008,
"preview": "local Base = require(\"avante.llm_tools.base\")\nlocal Providers = require(\"avante.providers\")\nlocal Utils = require(\"avant"
},
{
"path": "lua/avante/llm_tools/get_diagnostics.lua",
"chars": 1530,
"preview": "local Base = require(\"avante.llm_tools.base\")\nlocal Helpers = require(\"avante.llm_tools.helpers\")\nlocal Utils = require("
},
{
"path": "lua/avante/llm_tools/glob.lua",
"chars": 1896,
"preview": "local Helpers = require(\"avante.llm_tools.helpers\")\nlocal Base = require(\"avante.llm_tools.base\")\n\n---@class AvanteLLMTo"
},
{
"path": "lua/avante/llm_tools/grep.lua",
"chars": 5045,
"preview": "local Path = require(\"plenary.path\")\nlocal Utils = require(\"avante.utils\")\nlocal Helpers = require(\"avante.llm_tools.hel"
},
{
"path": "lua/avante/llm_tools/helpers.lua",
"chars": 7402,
"preview": "local Utils = require(\"avante.utils\")\nlocal Path = require(\"plenary.path\")\nlocal Config = require(\"avante.config\")\nlocal"
},
{
"path": "lua/avante/llm_tools/init.lua",
"chars": 48280,
"preview": "local curl = require(\"plenary.curl\")\nlocal Utils = require(\"avante.utils\")\nlocal Path = require(\"plenary.path\")\nlocal Co"
},
{
"path": "lua/avante/llm_tools/insert.lua",
"chars": 3755,
"preview": "local Path = require(\"plenary.path\")\nlocal Base = require(\"avante.llm_tools.base\")\nlocal Helpers = require(\"avante.llm_t"
},
{
"path": "lua/avante/llm_tools/ls.lua",
"chars": 1818,
"preview": "local Utils = require(\"avante.utils\")\nlocal Helpers = require(\"avante.llm_tools.helpers\")\nlocal Base = require(\"avante.l"
},
{
"path": "lua/avante/llm_tools/read_todos.lua",
"chars": 813,
"preview": "local Base = require(\"avante.llm_tools.base\")\n\n---@class AvanteLLMTool\nlocal M = setmetatable({}, Base)\n\nM.name = \"read_"
},
{
"path": "lua/avante/llm_tools/replace_in_file.lua",
"chars": 29964,
"preview": "local Base = require(\"avante.llm_tools.base\")\nlocal Helpers = require(\"avante.llm_tools.helpers\")\nlocal Utils = require("
},
{
"path": "lua/avante/llm_tools/str_replace.lua",
"chars": 2059,
"preview": "local Base = require(\"avante.llm_tools.base\")\n\n---@class AvanteLLMTool\nlocal M = setmetatable({}, Base)\n\nM.name = \"str_r"
},
{
"path": "lua/avante/llm_tools/think.lua",
"chars": 2560,
"preview": "local Line = require(\"avante.ui.line\")\nlocal Base = require(\"avante.llm_tools.base\")\nlocal Highlights = require(\"avante."
},
{
"path": "lua/avante/llm_tools/undo_edit.lua",
"chars": 2354,
"preview": "local Path = require(\"plenary.path\")\nlocal Base = require(\"avante.llm_tools.base\")\nlocal Helpers = require(\"avante.llm_t"
},
{
"path": "lua/avante/llm_tools/view.lua",
"chars": 4322,
"preview": "local Path = require(\"plenary.path\")\nlocal Utils = require(\"avante.utils\")\nlocal Base = require(\"avante.llm_tools.base\")"
},
{
"path": "lua/avante/llm_tools/write_to_file.lua",
"chars": 3312,
"preview": "local Utils = require(\"avante.utils\")\nlocal Base = require(\"avante.llm_tools.base\")\nlocal Helpers = require(\"avante.llm_"
},
{
"path": "lua/avante/llm_tools/write_todos.lua",
"chars": 1941,
"preview": "local Base = require(\"avante.llm_tools.base\")\n\n---@class AvanteLLMTool\nlocal M = setmetatable({}, Base)\n\nM.name = \"write"
},
{
"path": "lua/avante/model_selector.lua",
"chars": 5404,
"preview": "local Utils = require(\"avante.utils\")\nlocal Providers = require(\"avante.providers\")\nlocal Config = require(\"avante.confi"
},
{
"path": "lua/avante/path.lua",
"chars": 17039,
"preview": "local fn = vim.fn\nlocal Utils = require(\"avante.utils\")\nlocal Path = require(\"plenary.path\")\nlocal Scan = require(\"plena"
},
{
"path": "lua/avante/providers/azure.lua",
"chars": 2158,
"preview": "---@class AvanteAzureExtraRequestBody\n---@field temperature number\n---@field max_completion_tokens number\n---@field reas"
},
{
"path": "lua/avante/providers/bedrock/claude.lua",
"chars": 1603,
"preview": "---@class AvanteBedrockClaudeTextMessage\n---@field type \"text\"\n---@field text string\n---\n---@class AvanteBedrockClaudeMe"
},
{
"path": "lua/avante/providers/bedrock.lua",
"chars": 10488,
"preview": "local Utils = require(\"avante.utils\")\nlocal P = require(\"avante.providers\")\n\n---@class AvanteBedrockProviderFunctor\nloca"
},
{
"path": "lua/avante/providers/claude.lua",
"chars": 32045,
"preview": "local Utils = require(\"avante.utils\")\nlocal Clipboard = require(\"avante.clipboard\")\nlocal P = require(\"avante.providers\""
},
{
"path": "lua/avante/providers/cohere.lua",
"chars": 3730,
"preview": "local Utils = require(\"avante.utils\")\nlocal P = require(\"avante.providers\")\n\n---@alias CohereFinishReason \"COMPLETE\" | \""
},
{
"path": "lua/avante/providers/copilot.lua",
"chars": 14863,
"preview": "---Reference implementation:\n---https://github.com/zbirenbaum/copilot.lua/blob/master/lua/copilot/auth.lua config file\n-"
},
{
"path": "lua/avante/providers/gemini.lua",
"chars": 12269,
"preview": "local Utils = require(\"avante.utils\")\nlocal Providers = require(\"avante.providers\")\nlocal Clipboard = require(\"avante.cl"
},
{
"path": "lua/avante/providers/init.lua",
"chars": 9412,
"preview": "local api, fn = vim.api, vim.fn\n\nlocal Config = require(\"avante.config\")\nlocal Utils = require(\"avante.utils\")\n\n---@clas"
},
{
"path": "lua/avante/providers/ollama.lua",
"chars": 12573,
"preview": "local Utils = require(\"avante.utils\")\nlocal Providers = require(\"avante.providers\")\nlocal Config = require(\"avante.confi"
},
{
"path": "lua/avante/providers/openai.lua",
"chars": 32869,
"preview": "local Utils = require(\"avante.utils\")\nlocal Config = require(\"avante.config\")\nlocal Clipboard = require(\"avante.clipboar"
},
{
"path": "lua/avante/providers/vertex.lua",
"chars": 2419,
"preview": "local P = require(\"avante.providers\")\nlocal Utils = require(\"avante.utils\")\nlocal Gemini = require(\"avante.providers.gem"
},
{
"path": "lua/avante/providers/vertex_claude.lua",
"chars": 2398,
"preview": "local P = require(\"avante.providers\")\nlocal Utils = require(\"avante.utils\")\nlocal Vertex = require(\"avante.providers.ver"
},
{
"path": "lua/avante/providers/watsonx_code_assistant.lua",
"chars": 10472,
"preview": "-- Documentation for setting up IBM Watsonx Code Assistant\n--- Generating an access token: https://www.ibm.com/products/"
},
{
"path": "lua/avante/rag_service.lua",
"chars": 14443,
"preview": "local curl = require(\"plenary.curl\")\nlocal Path = require(\"plenary.path\")\nlocal Config = require(\"avante.config\")\nlocal "
},
{
"path": "lua/avante/range.lua",
"chars": 1036,
"preview": "---@class avante.Range\n---@field start avante.RangeSelection start point\n---@field finish avante.RangeSelection Selectio"
},
{
"path": "lua/avante/repo_map.lua",
"chars": 6637,
"preview": "local Popup = require(\"nui.popup\")\nlocal Utils = require(\"avante.utils\")\nlocal event = require(\"nui.utils.autocmd\").even"
},
{
"path": "lua/avante/selection.lua",
"chars": 13761,
"preview": "local Utils = require(\"avante.utils\")\nlocal Config = require(\"avante.config\")\nlocal Llm = require(\"avante.llm\")\nlocal Pr"
},
{
"path": "lua/avante/selection_result.lua",
"chars": 822,
"preview": "---@class avante.SelectionResult\n---@field filepath string Filepath of the selected content\n---@field filetype string Fi"
},
{
"path": "lua/avante/sidebar.lua",
"chars": 122887,
"preview": "local api = vim.api\nlocal fn = vim.fn\n\nlocal Split = require(\"nui.split\")\nlocal event = require(\"nui.utils.autocmd\").eve"
},
{
"path": "lua/avante/suggestion.lua",
"chars": 19519,
"preview": "local Utils = require(\"avante.utils\")\nlocal Llm = require(\"avante.llm\")\nlocal Highlights = require(\"avante.highlights\")\n"
},
{
"path": "lua/avante/templates/_context.avanterules",
"chars": 545,
"preview": "{% if selected_files -%}\n<selected_files>\n{%- for file in selected_files %}\n<file path=\"{{file.path}}\" language=\"{{file."
},
{
"path": "lua/avante/templates/_diagnostics.avanterules",
"chars": 369,
"preview": "{%- if diagnostics -%}\n<diagnostic_field_description>\ncontent: The diagnostic content\nstart_line: The starting line of t"
},
{
"path": "lua/avante/templates/_environments.avanterules",
"chars": 77,
"preview": "{% if system_info -%}\n====\n\nSYSTEM INFORMATION\n\n{{system_info}}\n{%- endif %}\n"
},
{
"path": "lua/avante/templates/_gpt4-1-agentic.avanterules",
"chars": 11757,
"preview": "You are an agent - please keep going until the user’s query is completely resolved, before ending your turn and yielding"
},
{
"path": "lua/avante/templates/_memory.avanterules",
"chars": 61,
"preview": "{%- if memory -%}\n<memory>\n{{memory}}\n</memory>\n{%- endif %}\n"
},
{
"path": "lua/avante/templates/_project.avanterules",
"chars": 97,
"preview": "{%- if project_context -%}\n<project_context>\n{{project_context}}\n</project_context>\n{%- endif %}\n"
},
{
"path": "lua/avante/templates/_task-guidelines.avanterules",
"chars": 3834,
"preview": "# Task Management\nYou have access to the read_todos and write_todos tools to help you manage and plan tasks. Use these t"
},
{
"path": "lua/avante/templates/_tools-guidelines.avanterules",
"chars": 4413,
"preview": "Don't directly search for code context in historical messages. Instead, prioritize using tools to obtain context first, "
},
{
"path": "lua/avante/templates/agentic.avanterules",
"chars": 6972,
"preview": "{% extends \"base.avanterules\" %}\n\n{% block extra_prompt %}\n\n{% if 'gpt-4.1' in model_name %}\n{%- include \"_gpt4-1-agenti"
},
{
"path": "lua/avante/templates/base.avanterules",
"chars": 560,
"preview": "You are a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design pa"
},
{
"path": "lua/avante/templates/editing.avanterules",
"chars": 1476,
"preview": "{% extends \"base.avanterules\" %}\n{% block extra_prompt %}\nYour task is to modify the provided code according to the user"
},
{
"path": "lua/avante/templates/legacy.avanterules",
"chars": 4946,
"preview": "{% extends \"base.avanterules\" %}\n{%- if ask %}\n{% block extra_prompt %}\nTake requests for changes to the supplied code.\n"
},
{
"path": "lua/avante/templates/suggesting.avanterules",
"chars": 3428,
"preview": "{% extends \"base.avanterules\" %}\n{% block extra_prompt %}\nYour task is to suggest code modifications at the cursor posit"
},
{
"path": "lua/avante/tokenizers.lua",
"chars": 1905,
"preview": "local Utils = require(\"avante.utils\")\n\n---@class AvanteTokenizer\n---@field from_pretrained fun(model: string): nil\n---@f"
},
{
"path": "lua/avante/types.lua",
"chars": 20721,
"preview": "---@meta\n\n---@class vim.api.create_autocmd.callback.args\n---@field id number\n---@field event string\n---@field group numb"
},
{
"path": "lua/avante/ui/acp_confirm_adapter.lua",
"chars": 1955,
"preview": "local Highlights = require(\"avante.highlights\")\n\n---@class avante.ui.ConfirmAdapter\nlocal M = {}\n\n---@class avante.ui.AC"
},
{
"path": "lua/avante/ui/button_group_line.lua",
"chars": 8481,
"preview": "local Highlights = require(\"avante.highlights\")\nlocal Line = require(\"avante.ui.line\")\nlocal Utils = require(\"avante.uti"
},
{
"path": "lua/avante/ui/confirm.lua",
"chars": 11937,
"preview": "local Popup = require(\"nui.popup\")\nlocal NuiText = require(\"nui.text\")\nlocal Highlights = require(\"avante.highlights\")\nl"
},
{
"path": "lua/avante/ui/input/init.lua",
"chars": 1325,
"preview": "local Utils = require(\"avante.utils\")\n\n---@class avante.ui.InputOption\n---@field provider avante.InputProvider\n---@field"
},
{
"path": "lua/avante/ui/input/providers/dressing.lua",
"chars": 1923,
"preview": "local api = vim.api\nlocal fn = vim.fn\n\nlocal M = {}\n\n---@param input avante.ui.Input\nfunction M.show(input)\n local ok, "
},
{
"path": "lua/avante/ui/input/providers/native.lua",
"chars": 578,
"preview": "local M = {}\n\n---@param input avante.ui.Input\nfunction M.show(input)\n local opts = {\n prompt = input.title,\n defa"
},
{
"path": "lua/avante/ui/input/providers/snacks.lua",
"chars": 581,
"preview": "local M = {}\n\n---@param input avante.ui.Input\nfunction M.show(input)\n local ok, snacks_input = pcall(require, \"snacks.i"
},
{
"path": "lua/avante/ui/line.lua",
"chars": 1920,
"preview": "---@alias avante.ui.LineSection table\n---\n---@class avante.ui.Line\n---@field sections avante.ui.LineSection[]\nlocal M = "
},
{
"path": "lua/avante/ui/prompt_input.lua",
"chars": 8418,
"preview": "local api = vim.api\nlocal fn = vim.fn\nlocal Config = require(\"avante.config\")\nlocal Utils = require(\"avante.utils\")\n\n---"
},
{
"path": "lua/avante/ui/selector/init.lua",
"chars": 2124,
"preview": "local Utils = require(\"avante.utils\")\n\n---@class avante.ui.SelectorItem\n---@field id string\n---@field title string\n\n---@"
},
{
"path": "lua/avante/ui/selector/providers/fzf_lua.lua",
"chars": 2481,
"preview": "local Utils = require(\"avante.utils\")\nlocal M = {}\n\n---@param selector avante.ui.Selector\nfunction M.show(selector)\n lo"
},
{
"path": "lua/avante/ui/selector/providers/mini_pick.lua",
"chars": 1063,
"preview": "local Utils = require(\"avante.utils\")\nlocal M = {}\n\n---@param selector avante.ui.Selector\nfunction M.show(selector)\n --"
},
{
"path": "lua/avante/ui/selector/providers/native.lua",
"chars": 1946,
"preview": "local M = {}\n\n---@param selector avante.ui.Selector\nfunction M.show(selector)\n local items = {}\n for _, item in ipairs"
},
{
"path": "lua/avante/ui/selector/providers/snacks.lua",
"chars": 2954,
"preview": "local Utils = require(\"avante.utils\")\nlocal M = {}\n\n---@param selector avante.ui.Selector\nfunction M.show(selector)\n --"
},
{
"path": "lua/avante/ui/selector/providers/telescope.lua",
"chars": 4965,
"preview": "local Utils = require(\"avante.utils\")\n\nlocal M = {}\n\n---@param selector avante.ui.Selector\nfunction M.show(selector)\n l"
},
{
"path": "lua/avante/utils/diff2search_replace.lua",
"chars": 1648,
"preview": "local function trim(s) return s:gsub(\"^%s+\", \"\"):gsub(\"%s+$\", \"\") end\n\nlocal function split_lines(text)\n local lines = "
},
{
"path": "lua/avante/utils/environment.lua",
"chars": 1515,
"preview": "local Utils = require(\"avante.utils\")\n\n---@class avante.utils.environment\nlocal M = {}\n\n---@private\n---@type table<strin"
},
{
"path": "lua/avante/utils/file.lua",
"chars": 1966,
"preview": "local LRUCache = require(\"avante.utils.lru_cache\")\nlocal Filetype = require(\"plenary.filetype\")\n\n---@class avante.utils."
},
{
"path": "lua/avante/utils/init.lua",
"chars": 57664,
"preview": "local api = vim.api\nlocal fn = vim.fn\nlocal lsp = vim.lsp\n\nlocal LRUCache = require(\"avante.utils.lru_cache\")\nlocal diff"
},
{
"path": "lua/avante/utils/logo.lua",
"chars": 737,
"preview": "local logo = [[\n\n⠀⢠⣤⣤⣤⡄⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\n⠀⣿⣿⣿⣿⢁⣿⣿⣷⡶⠶⠶⠶⠶⠶⠶⠶⠶⠶⠶⠶⠶⠶⠶⠶⠶⣤⡀⠀⠀\n⣀⣛⣛⣛⣛⣸⣿⣿⣿⢁⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢸⣿⣿⣦⡀\n⠈⠻⣿⣿⣿⣿⣿⣿⣿⢸"
},
{
"path": "lua/avante/utils/lru_cache.lua",
"chars": 2330,
"preview": "local LRUCache = {}\nLRUCache.__index = LRUCache\n\nfunction LRUCache:new(capacity)\n return setmetatable({\n capacity = "
},
{
"path": "lua/avante/utils/lsp.lua",
"chars": 6220,
"preview": "---@class avante.utils.lsp\nlocal M = {}\n\nlocal LspMethod = vim.lsp.protocol.Methods\n\n---@alias vim.lsp.Client.filter {id"
},
{
"path": "lua/avante/utils/path.lua",
"chars": 5420,
"preview": "local IS_WIN = require(\"avante.utils.platform\").platform == \"windows\" ---@type boolean\n\nlocal SEP = IS_WIN and \"\\\\\" or \""
},
{
"path": "lua/avante/utils/platform.lua",
"chars": 1813,
"preview": "-- lua/myplugin/platform.lua\nlocal uv = vim.uv or vim.loop\nlocal env = vim.env\n\nlocal M = {}\n\nlocal uname = uv.os_uname("
},
{
"path": "lua/avante/utils/promptLogger.lua",
"chars": 4046,
"preview": "local Config = require(\"avante.config\")\nlocal Utils = require(\"avante.utils\")\n\nlocal AVANTE_PROMPT_INPUT_HL = \"AvantePro"
},
{
"path": "lua/avante/utils/prompts.lua",
"chars": 8396,
"preview": "local Config = require(\"avante.config\")\nlocal M = {}\n\n---@param provider_conf AvanteDefaultBaseProvider\n---@param opts A"
},
{
"path": "lua/avante/utils/root.lua",
"chars": 7181,
"preview": "-- COPIED and MODIFIED from https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/util/root.lua\nlocal Utils = require"
},
{
"path": "lua/avante/utils/streaming_json_parser.lua",
"chars": 9962,
"preview": "-- StreamingJSONParser: 一个能够处理不完整 JSON 流的解析器\nlocal StreamingJSONParser = {}\nStreamingJSONParser.__index = StreamingJSONP"
},
{
"path": "lua/avante/utils/test.lua",
"chars": 263,
"preview": "-- This is a helper for unit tests.\nlocal M = {}\n\nfunction M.read_file(fn)\n fn = vim.fs.joinpath(vim.uv.cwd(), fn)\n lo"
},
{
"path": "lua/avante/utils/tokens.lua",
"chars": 2266,
"preview": "--Taken from https://github.com/jackMort/ChatGPT.nvim/blob/main/lua/chatgpt/flows/chat/tokens.lua\nlocal Tokenizer = requ"
},
{
"path": "lua/avante_lib.lua",
"chars": 662,
"preview": "local M = {}\n\nlocal function get_library_path()\n local os_name = require(\"avante.utils\").get_os_name()\n local ext = os"
},
{
"path": "lua/cmp_avante/commands.lua",
"chars": 2448,
"preview": "local api = vim.api\n\n---@class CommandsSource : cmp.Source\nlocal CommandsSource = {}\nCommandsSource.__index = CommandsSo"
},
{
"path": "lua/cmp_avante/mentions.lua",
"chars": 2916,
"preview": "local api = vim.api\n\n---@class mentions_source : cmp.Source\n---@field get_mentions fun(): AvanteMention[]\nlocal Mentions"
},
{
"path": "lua/cmp_avante/shortcuts.lua",
"chars": 1855,
"preview": "local api = vim.api\n\n---@class ShortcutsSource : cmp.Source\nlocal ShortcutsSource = {}\nShortcutsSource.__index = Shortcu"
},
{
"path": "luarc.json.template",
"chars": 438,
"preview": "{\n \"$schema\": \"https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json\",\n \"runtime\": {\n \"ve"
},
{
"path": "plugin/avante.lua",
"chars": 6366,
"preview": "if vim.fn.has(\"nvim-0.10\") == 0 then\n vim.api.nvim_echo({\n { \"Avante requires at least nvim-0.10\", \"ErrorMsg\" },\n "
},
{
"path": "py/rag-service/Dockerfile",
"chars": 551,
"preview": "FROM python:3.11-slim-bookworm\n\nCOPY gitconfig /root/.gitconfig\n\nWORKDIR /app\n\nRUN apt-get update && apt-get install -y "
},
{
"path": "py/rag-service/README.md",
"chars": 6365,
"preview": "# RAG Service Configuration\n\nThis document describes how to configure the RAG service, including setting up Language Mod"
},
{
"path": "py/rag-service/gitconfig",
"chars": 29,
"preview": "[safe]\n directory = *\n"
},
{
"path": "py/rag-service/requirements.txt",
"chars": 4121,
"preview": "aiohappyeyeballs==2.4.6\naiohttp==3.11.12\naiosignal==1.3.2\nannotated-types==0.7.0\nanyio==4.8.0\nasgiref==3.8.1\nasttokens=="
},
{
"path": "py/rag-service/run.sh",
"chars": 680,
"preview": "#!/usr/bin/env bash\n\n# Set the target directory (use the first argument or default to a local state directory)\nTARGET_DI"
},
{
"path": "py/rag-service/shell.nix",
"chars": 1198,
"preview": "{ pkgs ? import <nixpkgs> {} }:\nlet\n logFile = \"shell_log.txt\";\n python = pkgs.python311;\nin pkgs.mkShell {\n packages"
},
{
"path": "py/rag-service/src/libs/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "py/rag-service/src/libs/configs.py",
"chars": 498,
"preview": "import os\nfrom pathlib import Path\n\n# Configuration\nBASE_DATA_DIR = Path(os.environ.get(\"DATA_DIR\", \"data\"))\nCHROMA_PERS"
},
{
"path": "py/rag-service/src/libs/db.py",
"chars": 1911,
"preview": "import sqlite3\nfrom collections.abc import Generator\nfrom contextlib import contextmanager\n\nfrom libs.configs import DB_"
},
{
"path": "py/rag-service/src/libs/logger.py",
"chars": 406,
"preview": "import logging\nfrom datetime import datetime\n\nfrom libs.configs import LOG_DIR\n\nlogging.basicConfig(\n level=logging.I"
},
{
"path": "py/rag-service/src/libs/utils.py",
"chars": 1655,
"preview": "from __future__ import annotations\n\nimport re\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKIN"
},
{
"path": "py/rag-service/src/main.py",
"chars": 48320,
"preview": "\"\"\"RAG Service API for managing document indexing and retrieval.\"\"\" # noqa: INP001\n\nfrom __future__ import annotations\n"
},
{
"path": "py/rag-service/src/models/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "py/rag-service/src/models/indexing_history.py",
"chars": 839,
"preview": "\"\"\"Indexing History Model.\"\"\"\n\nfrom datetime import datetime\nfrom typing import Any\n\nfrom pydantic import BaseModel, Fie"
},
{
"path": "py/rag-service/src/models/resource.py",
"chars": 1188,
"preview": "\"\"\"Resource Model.\"\"\"\n\nfrom datetime import datetime\nfrom typing import Literal\n\nfrom pydantic import BaseModel, Field\n\n"
},
{
"path": "py/rag-service/src/providers/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "py/rag-service/src/providers/dashscope.py",
"chars": 2266,
"preview": "# src/providers/dashscope.py\n\nfrom typing import Any\n\nfrom llama_index.core.base.embeddings.base import BaseEmbedding\nfr"
},
{
"path": "py/rag-service/src/providers/factory.py",
"chars": 6970,
"preview": "import importlib\nfrom typing import TYPE_CHECKING, Any, cast\n\nfrom llama_index.core.base.embeddings.base import BaseEmbe"
},
{
"path": "py/rag-service/src/providers/ollama.py",
"chars": 1937,
"preview": "# src/providers/ollama.py\n\nfrom typing import Any\n\nfrom llama_index.core.base.embeddings.base import BaseEmbedding\nfrom "
},
{
"path": "py/rag-service/src/providers/openai.py",
"chars": 1910,
"preview": "# src/providers/openai.py\n\nfrom typing import Any\n\nfrom llama_index.core.base.embeddings.base import BaseEmbedding\nfrom "
},
{
"path": "py/rag-service/src/providers/openrouter.py",
"chars": 890,
"preview": "# src/providers/openrouter.py\n\nfrom typing import Any\n\nfrom llama_index.core.llms.llm import LLM\nfrom llama_index.llms.o"
},
{
"path": "py/rag-service/src/services/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "py/rag-service/src/services/indexing_history.py",
"chars": 6413,
"preview": "import json\nimport os\nfrom datetime import datetime\nfrom typing import Any\n\nfrom libs.db import get_db_connection\nfrom l"
},
{
"path": "py/rag-service/src/services/resource.py",
"chars": 3717,
"preview": "\"\"\"Resource Service.\"\"\"\n\nfrom libs.db import get_db_connection\nfrom models.resource import Resource\n\n\nclass ResourceServ"
},
{
"path": "pyrightconfig.json",
"chars": 542,
"preview": "{\n \"include\": [\n \".\"\n ],\n \"exclude\": [\n \"**/node_modules\",\n \"**/__pycache__\",\n \"**/.*\"\n ],\n \"defineCons"
},
{
"path": "ruff.toml",
"chars": 680,
"preview": "# 与 black 保持一致的行长度\nline-length = 180\n\n# 排除一些目录\nexclude = [\n \".git\",\n \".ruff_cache\",\n \".venv\",\n \"venv\",\n \"__pycache_"
},
{
"path": "scripts/lua-typecheck.sh",
"chars": 4209,
"preview": "#!/usr/bin/env bash\nset -e\n\n# This script performs a Lua typecheck, with different behaviors for local and CI environmen"
},
{
"path": "scripts/run-luatest.sh",
"chars": 1534,
"preview": "#!/usr/bin/env bash\nset -e\n\nDEST_DIR=\"$PWD/target/tests\"\nDEPS_DIR=\"$DEST_DIR/deps\"\n\nlog() {\n echo \"$1\" >&2\n}\n\ncheck_t"
},
{
"path": "scripts/setup-deps.sh",
"chars": 8256,
"preview": "#!/bin/bash\n\nDEPS=(\n \"folke/neodev.nvim\"\n \"nvim-lua/plenary.nvim\"\n \"MunifTanjim/nui.nvim\"\n \"stevearc/dressing.nvim\"\n"
},
{
"path": "stylua.toml",
"chars": 168,
"preview": "syntax = \"Lua52\"\nindent_type = \"Spaces\"\nindent_width = 2\ncolumn_width = 119\nline_endings = \"Unix\"\nquote_style = \"AutoPre"
},
{
"path": "syntax/jinja.vim",
"chars": 3447,
"preview": "\" reference: https://github.com/lepture/vim-jinja/blob/master/syntax/jinja.vim\n\nif exists(\"b:current_syntax\")\n finish\ne"
},
{
"path": "tests/data/claude_token_error_response.json",
"chars": 122,
"preview": "{\n \"error\": \"invalid_grant\",\n \"error_description\": \"The provided authorization grant is invalid, expired, or revoked\"\n"
},
{
"path": "tests/data/claude_token_response.json",
"chars": 151,
"preview": "{\n \"access_token\": \"mock_access_token_abcdef123456\",\n \"refresh_token\": \"mock_refresh_token_xyz789\",\n \"expires_in\": 18"
},
{
"path": "tests/libs/acp_client_spec.lua",
"chars": 12839,
"preview": "local ACPClient = require(\"avante.libs.acp_client\")\nlocal stub = require(\"luassert.stub\")\n\ndescribe(\"ACPClient\", functio"
},
{
"path": "tests/libs/jsonparser_spec.lua",
"chars": 17857,
"preview": "local JsonParser = require(\"avante.libs.jsonparser\")\n\ndescribe(\"JsonParser\", function()\n describe(\"parse (one-time pars"
}
]
// ... and 15 more files (download for full content)
About this extraction
This page contains the full source code of the yetone/avante.nvim GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 215 files (1.5 MB), approximately 393.6k tokens, and a symbol index with 171 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.