[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"similar-Robitx--gp.nvim":3,"tool-Robitx--gp.nvim":61},[4,18,26,36,44,53],{"id":5,"name":6,"github_repo":7,"description_zh":8,"stars":9,"difficulty_score":10,"last_commit_at":11,"category_tags":12,"status":17},4358,"openclaw","openclaw\u002Fopenclaw","OpenClaw 是一款专为个人打造的本地化 AI 助手，旨在让你在自己的设备上拥有完全可控的智能伙伴。它打破了传统 AI 助手局限于特定网页或应用的束缚，能够直接接入你日常使用的各类通讯渠道，包括微信、WhatsApp、Telegram、Discord、iMessage 等数十种平台。无论你在哪个聊天软件中发送消息，OpenClaw 都能即时响应，甚至支持在 macOS、iOS 和 Android 设备上进行语音交互，并提供实时的画布渲染功能供你操控。\n\n这款工具主要解决了用户对数据隐私、响应速度以及“始终在线”体验的需求。通过将 AI 部署在本地，用户无需依赖云端服务即可享受快速、私密的智能辅助，真正实现了“你的数据，你做主”。其独特的技术亮点在于强大的网关架构，将控制平面与核心助手分离，确保跨平台通信的流畅性与扩展性。\n\nOpenClaw 非常适合希望构建个性化工作流的技术爱好者、开发者，以及注重隐私保护且不愿被单一生态绑定的普通用户。只要具备基础的终端操作能力（支持 macOS、Linux 及 Windows WSL2），即可通过简单的命令行引导完成部署。如果你渴望拥有一个懂你",349277,3,"2026-04-06T06:32:30",[13,14,15,16],"Agent","开发框架","图像","数据工具","ready",{"id":19,"name":20,"github_repo":21,"description_zh":22,"stars":23,"difficulty_score":10,"last_commit_at":24,"category_tags":25,"status":17},3808,"stable-diffusion-webui","AUTOMATIC1111\u002Fstable-diffusion-webui","stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面，旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点，将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。\n\n无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师，还是想要深入探索模型潜力的开发者与研究人员，都能从中获益。其核心亮点在于极高的功能丰富度：不仅支持文生图、图生图、局部重绘（Inpainting）和外绘（Outpainting）等基础模式，还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外，它内置了 GFPGAN 和 CodeFormer 等人脸修复工具，支持多种神经网络放大算法，并允许用户通过插件系统无限扩展能力。即使是显存有限的设备，stable-diffusion-webui 也提供了相应的优化选项，让高质量的 AI 艺术创作变得触手可及。",162132,"2026-04-05T11:01:52",[14,15,13],{"id":27,"name":28,"github_repo":29,"description_zh":30,"stars":31,"difficulty_score":32,"last_commit_at":33,"category_tags":34,"status":17},1381,"everything-claude-code","affaan-m\u002Feverything-claude-code","everything-claude-code 是一套专为 AI 编程助手（如 Claude Code、Codex、Cursor 等）打造的高性能优化系统。它不仅仅是一组配置文件，而是一个经过长期实战打磨的完整框架，旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。\n\n通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能，everything-claude-code 能显著提升 AI 在复杂任务中的表现，帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略，使得模型响应更快、成本更低，同时有效防御潜在的攻击向量。\n\n这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库，还是需要 AI 协助进行安全审计与自动化测试，everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目，它融合了多语言支持与丰富的实战钩子（hooks），让 AI 真正成长为懂上",156804,2,"2026-04-15T11:34:33",[14,13,35],"语言模型",{"id":37,"name":38,"github_repo":39,"description_zh":40,"stars":41,"difficulty_score":32,"last_commit_at":42,"category_tags":43,"status":17},2271,"ComfyUI","Comfy-Org\u002FComfyUI","ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎，专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式，采用直观的节点式流程图界面，让用户通过连接不同的功能模块即可构建个性化的生成管线。\n\n这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景，也能自由组合模型、调整参数并实时预览效果，轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性，不仅支持 Windows、macOS 和 Linux 全平台，还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构，并率先支持 SDXL、Flux、SD3 等前沿模型。\n\n无论是希望深入探索算法潜力的研究人员和开发者，还是追求极致创作自由度的设计师与资深 AI 绘画爱好者，ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能，使其成为当前最灵活、生态最丰富的开源扩散模型工具之一，帮助用户将创意高效转化为现实。",108322,"2026-04-10T11:39:34",[14,15,13],{"id":45,"name":46,"github_repo":47,"description_zh":48,"stars":49,"difficulty_score":32,"last_commit_at":50,"category_tags":51,"status":17},6121,"gemini-cli","google-gemini\u002Fgemini-cli","gemini-cli 是一款由谷歌推出的开源 AI 命令行工具，它将强大的 Gemini 大模型能力直接集成到用户的终端环境中。对于习惯在命令行工作的开发者而言，它提供了一条从输入提示词到获取模型响应的最短路径，无需切换窗口即可享受智能辅助。\n\n这款工具主要解决了开发过程中频繁上下文切换的痛点，让用户能在熟悉的终端界面内直接完成代码理解、生成、调试以及自动化运维任务。无论是查询大型代码库、根据草图生成应用，还是执行复杂的 Git 操作，gemini-cli 都能通过自然语言指令高效处理。\n\n它特别适合广大软件工程师、DevOps 人员及技术研究人员使用。其核心亮点包括支持高达 100 万 token 的超长上下文窗口，具备出色的逻辑推理能力；内置 Google 搜索、文件操作及 Shell 命令执行等实用工具；更独特的是，它支持 MCP（模型上下文协议），允许用户灵活扩展自定义集成，连接如图像生成等外部能力。此外，个人谷歌账号即可享受免费的额度支持，且项目基于 Apache 2.0 协议完全开源，是提升终端工作效率的理想助手。",100752,"2026-04-10T01:20:03",[52,13,15,14],"插件",{"id":54,"name":55,"github_repo":56,"description_zh":57,"stars":58,"difficulty_score":32,"last_commit_at":59,"category_tags":60,"status":17},4721,"markitdown","microsoft\u002Fmarkitdown","MarkItDown 是一款由微软 AutoGen 团队打造的轻量级 Python 工具，专为将各类文件高效转换为 Markdown 格式而设计。它支持 PDF、Word、Excel、PPT、图片（含 OCR）、音频（含语音转录）、HTML 乃至 YouTube 链接等多种格式的解析，能够精准提取文档中的标题、列表、表格和链接等关键结构信息。\n\n在人工智能应用日益普及的今天，大语言模型（LLM）虽擅长处理文本，却难以直接读取复杂的二进制办公文档。MarkItDown 恰好解决了这一痛点，它将非结构化或半结构化的文件转化为模型“原生理解”且 Token 效率极高的 Markdown 格式，成为连接本地文件与 AI 分析 pipeline 的理想桥梁。此外，它还提供了 MCP（模型上下文协议）服务器，可无缝集成到 Claude Desktop 等 LLM 应用中。\n\n这款工具特别适合开发者、数据科学家及 AI 研究人员使用，尤其是那些需要构建文档检索增强生成（RAG）系统、进行批量文本分析或希望让 AI 助手直接“阅读”本地文件的用户。虽然生成的内容也具备一定可读性，但其核心优势在于为机器",93400,"2026-04-06T19:52:38",[52,14],{"id":62,"github_repo":63,"name":64,"description_en":65,"description_zh":66,"ai_summary_zh":66,"readme_en":67,"readme_zh":68,"quickstart_zh":69,"use_case_zh":70,"hero_image_url":71,"owner_login":72,"owner_name":73,"owner_avatar_url":74,"owner_bio":75,"owner_company":75,"owner_location":75,"owner_email":76,"owner_twitter":75,"owner_website":75,"owner_url":77,"languages":78,"stars":83,"forks":84,"last_commit_at":85,"license":86,"difficulty_score":32,"env_os":87,"env_gpu":88,"env_ram":88,"env_deps":89,"category_tags":96,"github_topics":99,"view_count":32,"oss_zip_url":75,"oss_zip_packed_at":75,"status":17,"created_at":120,"updated_at":121,"faqs":122,"releases":153},7789,"Robitx\u002Fgp.nvim","gp.nvim","Gp.nvim (GPT prompt) Neovim AI plugin: ChatGPT sessions & Instructable text\u002Fcode operations & Speech to text [OpenAI, Ollama, Anthropic, ..]","gp.nvim 是一款专为 Neovim 打造的轻量级 AI 插件，旨在将大语言模型（如 ChatGPT、Ollama、Anthropic 等）的能力无缝融入代码编辑流程。它不仅仅是一个聊天机器人，更是一个强大的生产力助手，支持在编辑器内直接进行流式对话、执行代码生成与重构指令，甚至实现语音转文字和图像生成功能。\n\n对于长期依赖键盘操作的开发者而言，gp.nvim 解决了频繁切换窗口至浏览器询问 AI 的痛点。它允许用户在当前缓冲区直接获取 AI 回复，支持中途取消生成，并能通过简单的撤销操作回滚修改，确保了编辑体验的流畅与自然。此外，它还支持基于项目自定义指令文件，让 AI 更懂你的代码规范。\n\n这款工具特别适合追求高效工作流的 Neovim 重度用户、软件工程师及技术研究人员。其核心亮点在于极低的依赖要求（仅需 curl 等基础工具）和高度可扩展性：用户可以通过配置钩子函数轻松定制功能，无需依赖其他 Lua 插件。无论是快速编写单元测试、解释复杂代码段，还是通过语音口述注释，gp.nvim 都能以原生且非侵入的方式，显著提升编码效率。","\u003C!-- panvimdoc-ignore-start -->\n\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fblob\u002Fmain\u002FLICENSE\">\u003Cimg alt=\"GitHub\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Flicense\u002Frobitx\u002Fgp.nvim\">\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fstargazers\">\u003Cimg alt=\"GitHub Repo stars\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fstars\u002FRobitx\u002Fgp.nvim\">\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\">\u003Cimg alt=\"GitHub closed issues\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fissues-closed\u002FRobitx\u002Fgp.nvim\">\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fpulls\">\u003Cimg alt=\"GitHub closed pull requests\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fissues-pr-closed\u002FRobitx\u002Fgp.nvim?label=PRs\">\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fgraphs\u002Fcontributors\">\u003Cimg alt=\"GitHub contributors\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fcontributors-anon\u002FRobitx\u002Fgp.nvim\">\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fsearch?q=%2F%5E%5B%5Cs%5D*require%5C%28%5B%27%22%5Dgp%5B%27%22%5D%5C%29%5C.setup%2F+language%3ALua&type=code&p=1\">\u003Cimg alt=\"Static Badge\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FUse%20in%20the%20Wild-8A2BE2\">\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fdiscord.gg\u002FdYyHmyNpv7\">\u003Cimg alt=\"Discord\" src=\"https:\u002F\u002Fimg.shields.io\u002Fdiscord\u002F1200485978725433484?label=Discord\">\u003C\u002Fa>\n\n\n# Gp.nvim (GPT prompt) Neovim AI plugin\n\n\u003C!-- panvimdoc-ignore-end -->\n\n\u003Cbr>\n\n**ChatGPT like sessions, Instructable text\u002Fcode operations, Speech to text and Image generation in your favorite editor.**\n\n\u003Cp align=\"left\">\n\u003Cimg src=\"https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FRobitx_gp.nvim_readme_514254e8b91b.png\" width=\"49%\">\n\u003Cimg src=\"https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FRobitx_gp.nvim_readme_87f46d3a3453.png\" width=\"49%\">\n\u003C\u002Fp>\n\n### Youtube demos\n\n- [5-min-demo](https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=X-cT7s47PLo) (December 2023)\n- [older-5-min-demo](https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=wPDcBnQgNCc) (screen capture, no sound)\n\n# Goals and Features\n\nThe goal is to extend Neovim with the **power of GPT models in a simple unobtrusive extensible way.**  \nTrying to keep things as native as possible - reusing and integrating well with the natural features of (Neo)vim.\n\n- **Streaming responses**\n  - no spinner wheel and waiting for the full answer\n  - response generation can be canceled half way through\n  - properly working undo (response can be undone with a single `u`)\n- **Infinitely extensible** via hook functions specified as part of the config\n  - hooks have access to everything in the plugin and are automatically registered as commands\n  - see [5. Configuration](#5-configuration) and [Extend functionality](#extend-functionality) sections for details\n- **Minimum dependencies** (`neovim`, `curl`, `grep` and optionally `sox`)\n  - zero dependencies on other lua plugins to minimize chance of breakage\n- **ChatGPT like sessions**\n  - just good old neovim buffers formated as markdown with autosave and few buffer bound shortcuts\n  - last chat also quickly accessible via toggable popup window\n  - chat finder - management popup for searching, previewing, deleting and opening chat sessions\n- **Instructable text\u002Fcode operations**\n  - templating mechanism to combine user instructions, selections etc into the gpt query\n  - multimodal - same command works for normal\u002Finsert mode, with selection or a range\n  - many possible output targets - rewrite, prepend, append, new buffer, popup\n  - non interactive command mode available for common repetitive tasks implementable as simple hooks  \n    (explain something in a popup window, write unit tests for selected code into a new buffer,  \n    finish selected code based on comments in it, etc.)\n  - custom instructions per repository with `.gp.md` file  \n    (instruct gpt to generate code using certain libs, packages, conventions and so on)\n- **Speech to text support**\n  - a mouth is 2-4x faster than fingers when it comes to outputting words - use it where it makes sense  \n    (dicating comments and notes, asking gpt questions, giving instructions for code operations, ..)\n- **Image generation**\n  - be even less tempted to open the browser with the ability to generate images directly from Neovim\n\n# Install\n\n## 1. Install the plugin\n\nSnippets for your preferred package manager:\n\n```lua\n-- lazy.nvim\n{\n    \"robitx\u002Fgp.nvim\",\n    config = function()\n        local conf = {\n            -- For customization, refer to Install > Configuration in the Documentation\u002FReadme\n        }\n        require(\"gp\").setup(conf)\n\n        -- Setup shortcuts here (see Usage > Shortcuts in the Documentation\u002FReadme)\n    end,\n}\n```\n\n```lua\n-- packer.nvim\nuse({\n    \"robitx\u002Fgp.nvim\",\n    config = function()\n        local conf = {\n            -- For customization, refer to Install > Configuration in the Documentation\u002FReadme\n        }\n        require(\"gp\").setup(conf)\n\n        -- Setup shortcuts here (see Usage > Shortcuts in the Documentation\u002FReadme)\n    end,\n})\n```\n\n```lua\n-- vim-plug\nPlug 'robitx\u002Fgp.nvim'\n\nlocal conf = {\n    -- For customization, refer to Install > Configuration in the Documentation\u002FReadme\n}\nrequire(\"gp\").setup(conf)\n\n-- Setup shortcuts here (see Usage > Shortcuts in the Documentation\u002FReadme)\n```\n## 2. OpenAI API key\n\nMake sure you have OpenAI API key. [Get one here](https:\u002F\u002Fplatform.openai.com\u002Faccount\u002Fapi-keys) and use it in the [5. Configuration](#5-configuration). Also consider setting up [usage limits](https:\u002F\u002Fplatform.openai.com\u002Faccount\u002Fbilling\u002Flimits) so you won't get suprised at the end of the month.\n\nThe OpenAI API key can be passed to the plugin in multiple ways:\n\n| Method                    | Example                                                        | Security Level      |\n| ------------------------- | -------------------------------------------------------------- | ------------------- |\n| hardcoded string          | `openai_api_key: \"sk-...\",`                                    | Low                 |\n| default env var           | set `OPENAI_API_KEY` environment variable in shell config      | Medium              |\n| custom env var            | `openai_api_key = os.getenv(\"CUSTOM_ENV_NAME\"),`               | Medium              |\n| read from file            | `openai_api_key = { \"cat\", \"path_to_api_key\" },`               | Medium-High         |\n| password manager          | `openai_api_key = { \"bw\", \"get\", \"password\", \"OAI_API_KEY\" },` | High                |\n\nIf `openai_api_key` is a table, Gp runs it asynchronously to avoid blocking Neovim (password managers can take a second or two).\n\n## 3. Multiple providers\nThe following LLM providers are currently supported besides OpenAI:\n\n- [Ollama](https:\u002F\u002Fgithub.com\u002Follama\u002Follama) for local\u002Foffline open-source models. The plugin assumes you have the Ollama service up and running with configured models available (the default Ollama agent uses Llama3).\n- [GitHub Copilot](https:\u002F\u002Fgithub.com\u002Fsettings\u002Fcopilot) with a Copilot license ([zbirenbaum\u002Fcopilot.lua](https:\u002F\u002Fgithub.com\u002Fzbirenbaum\u002Fcopilot.lua) or [github\u002Fcopilot.vim](https:\u002F\u002Fgithub.com\u002Fgithub\u002Fcopilot.vim) for autocomplete). You can access the underlying GPT-4 model without paying anything extra (essentially unlimited GPT-4 access).\n- [Perplexity.ai](https:\u002F\u002Fwww.perplexity.ai\u002Fpro) Pro users have $5\u002Fmonth free API credits available (the default PPLX agent uses Mixtral-8x7b).\n- [Anthropic](https:\u002F\u002Fwww.anthropic.com\u002Fapi) to access Claude models, which currently outperform GPT-4 in some benchmarks.\n- [Google Gemini](https:\u002F\u002Fai.google.dev\u002F) with a quite generous free range but some geo-restrictions (EU).\n- Any other \"OpenAI chat\u002Fcompletions\" compatible endpoint (Azure, LM Studio, etc.)\n\nBelow is an example of the relevant configuration part enabling some of these. The `secret` field has the same capabilities as `openai_api_key` (which is still supported for compatibility).\n\n```lua\n\tproviders = {\n\t\topenai = {\n\t\t\tendpoint = \"https:\u002F\u002Fapi.openai.com\u002Fv1\u002Fchat\u002Fcompletions\",\n\t\t\tsecret = os.getenv(\"OPENAI_API_KEY\"),\n\t\t},\n\n\t\t-- azure = {...},\n\n\t\tcopilot = {\n\t\t\tendpoint = \"https:\u002F\u002Fapi.githubcopilot.com\u002Fchat\u002Fcompletions\",\n\t\t\tsecret = {\n\t\t\t\t\"bash\",\n\t\t\t\t\"-c\",\n\t\t\t\t\"cat ~\u002F.config\u002Fgithub-copilot\u002Fapps.json | sed -e 's\u002F.*oauth_token...\u002F\u002F;s\u002F\\\".*\u002F\u002F'\",\n\t\t\t},\n\t\t},\n\n\t\tpplx = {\n\t\t\tendpoint = \"https:\u002F\u002Fapi.perplexity.ai\u002Fchat\u002Fcompletions\",\n\t\t\tsecret = os.getenv(\"PPLX_API_KEY\"),\n\t\t},\n\n\t\tollama = {\n\t\t\tendpoint = \"http:\u002F\u002Flocalhost:11434\u002Fv1\u002Fchat\u002Fcompletions\",\n\t\t},\n\n\t\tgoogleai = {\n\t\t\tendpoint = \"https:\u002F\u002Fgenerativelanguage.googleapis.com\u002Fv1beta\u002Fmodels\u002F{{model}}:streamGenerateContent?key={{secret}}\",\n\t\t\tsecret = os.getenv(\"GOOGLEAI_API_KEY\"),\n\t\t},\n\n\t\tanthropic = {\n\t\t\tendpoint = \"https:\u002F\u002Fapi.anthropic.com\u002Fv1\u002Fmessages\",\n\t\t\tsecret = os.getenv(\"ANTHROPIC_API_KEY\"),\n\t\t},\n\t},\n```\n\nEach of these providers has some agents preconfigured. Below is an example of how to disable predefined ChatGPT3-5 agent and create a custom one. If the `provider` field is missing, OpenAI is assumed for backward compatibility.\n\n```lua\n\tagents = {\n\t\t{\n\t\t\tname = \"ChatGPT3-5\",\n\t\t\tdisable = true,\n\t\t},\n\t\t{\n\t\t\tname = \"MyCustomAgent\",\n\t\t\tprovider = \"copilot\",\n\t\t\tchat = true,\n\t\t\tcommand = true,\n\t\t\tmodel = { model = \"gpt-4-turbo\" },\n\t\t\tsystem_prompt = \"Answer any query with just: Sure thing..\",\n\t\t},\n\t},\n\n```\n\n\n## 4. Dependencies\n\nThe core plugin only needs `curl` installed to make calls to OpenAI API and `grep` for ChatFinder. So Linux, BSD and Mac OS should be covered.\n\nVoice commands (`:GpWhisper*`) depend on `SoX` (Sound eXchange) to handle audio recording and processing:\n\n- Mac OS: `brew install sox`\n- Ubuntu\u002FDebian: `apt-get install sox libsox-fmt-mp3`\n- Arch Linux: `pacman -S sox`\n- Redhat\u002FCentOS: `yum install sox`\n- NixOS: `nix-env -i sox`\n\n## 5. Configuration\n\nBelow is a linked snippet with the default values, but I suggest starting with minimal config possible (just `openai_api_key` if you don't have `OPENAI_API_KEY` env set up). Defaults change over time to improve things, options might get deprecated and so on - it's better to change only things where the default doesn't fit your needs.\n\n\u003C!-- README_REFERENCE_MARKER_REPLACE_NEXT_LINE -->\nhttps:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fblob\u002Fb910a540f16875af77b27e49288021368cc674cf\u002Flua\u002Fgp\u002Fconfig.lua#L10-L650\n\n# Usage\n\n## Chat commands\n\n#### `:GpChatNew` \u003C!-- {doc=:GpChatNew}  -->\n\nOpen a fresh chat in the current window. It can be either empty or include the visual selection or specified range as context. This command also supports subcommands for layout specification:\n\n- `:GpChatNew vsplit` Open a fresh chat in a vertical split window.\n- `:GpChatNew split` Open a fresh chat in a horizontal split window.\n- `:GpChatNew tabnew` Open a fresh chat in a new tab.\n- `:GpChatNew popup` Open a fresh chat in a popup window.\n\n#### `:GpChatPaste` \u003C!-- {doc=:GpChatPaste}  -->\n\nPaste the selection or specified range into the latest chat, simplifying the addition of code from multiple files into a single chat buffer. This command also supports subcommands for layout specification:\n\n- `:GpChatPaste vsplit` Paste into the latest chat in a vertical split window.\n- `:GpChatPaste split` Paste into the latest chat in a horizontal split window.\n- `:GpChatPaste tabnew` Paste into the latest chat in a new tab.\n- `:GpChatPaste popup` Paste into the latest chat in a popup window.\n\n#### `:GpChatToggle` \u003C!-- {doc=:GpChatToggle}  -->\n\nOpen chat in a toggleable popup window, showing the last active chat or a fresh one with selection or a range as a context. This command also supports subcommands for layout specification:\n\n- `:GpChatToggle vsplit` Toggle chat in a vertical split window.\n- `:GpChatToggle split` Toggle chat in a horizontal split window.\n- `:GpChatToggle tabnew` Toggle chat in a new tab.\n- `:GpChatToggle popup` Toggle chat in a popup window.\n\n#### `:GpChatFinder` \u003C!-- {doc=:GpChatFinder}  -->\n\nOpen a dialog to search through chats.\n\n#### `:GpChatRespond` \u003C!-- {doc=:GpChatRespond}  -->\n\nRequest a new GPT response for the current chat. Usin`:GpChatRespond N` request a new GPT response with only the last N messages as context, using everything from the end up to the Nth instance of `🗨:..` (N=1 is like asking a question in a new chat).\n\n#### `:GpChatDelete` \u003C!-- {doc=:GpChatDelete}  -->\n\nDelete the current chat. By default requires confirmation before delete, which can be disabled in config using `chat_confirm_delete = false,`.\n\n## Text\u002FCode commands\n\n#### `:GpRewrite`\u003C!-- {doc=:GpRewrite}  -->\n\nOpens a dialog for entering a prompt. After providing prompt instructions into the dialog, the generated response replaces the current line in normal\u002Finsert mode, selected lines in visual mode, or the specified range (e.g., `:%GpRewrite` applies the rewrite to the entire buffer).\n\n`:GpRewrite {prompt}` Executes directly with specified `{prompt}` instructions, bypassing the dialog. Suitable for mapping repetitive tasks to keyboard shortcuts or for automation using headless Neovim via terminal or shell scripts.\n\n#### `:GpAppend` \u003C!-- {doc=:GpAppend}  -->\n\nSimilar to `:GpRewrite`, but the answer is added after the current line, visual selection, or range.\n\n#### `:GpPrepend` \u003C!-- {doc=:GpPrepend}  -->\n\nSimilar to `:GpRewrite`, but the answer is added before the current line, visual selection, or range.\n\n#### `:GpEnew` \u003C!-- {doc=:GpEnew}  -->\n\nSimilar to `:GpRewrite`, but the answer is added into a new buffer in the current window.\n\n#### `:GpNew` \u003C!-- {doc=:GpNew}  -->\n\nSimilar to `:GpRewrite`, but the answer is added into a new horizontal split window.\n\n#### `:GpVnew` \u003C!-- {doc=:GpVnew}  -->\n\nSimilar to `:GpRewrite`, but the answer is added into a new vertical split window.\n\n#### `:GpTabnew` \u003C!-- {doc=:GpTabnew}  -->\n\nSimilar to `:GpRewrite`, but the answer is added into a new tab.\n\n#### `:GpPopup` \u003C!-- {doc=:GpPopup}  -->\n\nSimilar to `:GpRewrite`, but the answer is added into a pop-up window.\n\n#### `:GpImplement` \u003C!-- {doc=:GpImplement}  -->\n\nExample hook command to develop code from comments in a visual selection or specified range.\n\n#### `:GpContext`\u003C!-- {doc=:GpContext}  -->\n\nProvides custom context per repository:\n\n- opens `.gp.md` file for a given repository in a toggable window.\n- appends selection\u002Frange to the context file when used in visual\u002Frange mode.\n- also supports subcommands for layout specification:\n\n  - `:GpContext vsplit` Open `.gp.md` in a vertical split window.\n  - `:GpContext split` Open `.gp.md` in a horizontal split window.\n  - `:GpContext tabnew` Open `.gp.md` in a new tab.\n  - `:GpContext popup` Open `.gp.md` in a popup window.\n\n- refer to [Custom Instructions](#custom-instructions) for more details.\n\n## Speech commands\n\n#### `:GpWhisper` {lang?} \u003C!-- {doc=:GpWhisper}  -->\n\nTranscription replaces the current line, visual selection or range in the current buffer. Use your mouth to ask a question in a chat buffer instead of writing it by hand, dictate some comments for the code, notes or even your next novel..\n\nFor the rest of the whisper commands, the transcription is used as an editable prompt for the equivalent non whisper command - `GpWhisperRewrite` dictates instructions for `GpRewrite` etc.\n\nYou can override the default language by setting {lang} with the 2 letter\nshortname of your language (e.g. \"en\" for English, \"fr\" for French etc).\n\n#### `:GpWhisperRewrite` \u003C!-- {doc=:GpWhisperRewrite}  -->\n\nSimilar to `:GpRewrite`, but the prompt instruction dialog uses transcribed spoken instructions.\n\n#### `:GpWhisperAppend` \u003C!-- {doc=:GpWhisperAppend}  -->\n\nSimilar to `:GpAppend`, but the prompt instruction dialog uses transcribed spoken instructions for adding content after the current line, visual selection, or range.\n\n#### `:GpWhisperPrepend` \u003C!-- {doc=:GpWhisperPrepend}  -->\n\nSimilar to `:GpPrepend`, but the prompt instruction dialog uses transcribed spoken instructions for adding content before the current line, selection, or range.\n\n#### `:GpWhisperEnew` \u003C!-- {doc=:GpWhisperEnew}  -->\n\nSimilar to `:GpEnew`, but the prompt instruction dialog uses transcribed spoken instructions for opening content in a new buffer within the current window.\n\n#### `:GpWhisperNew` \u003C!-- {doc=:GpWhisperNew}  -->\n\nSimilar to `:GpNew`, but the prompt instruction dialog uses transcribed spoken instructions for opening content in a new horizontal split window.\n\n#### `:GpWhisperVnew` \u003C!-- {doc=:GpWhisperVnew}  -->\n\nSimilar to `:GpVnew`, but the prompt instruction dialog uses transcribed spoken instructions for opening content in a new vertical split window.\n\n#### `:GpWhisperTabnew` \u003C!-- {doc=:GpWhisperTabnew}  -->\n\nSimilar to `:GpTabnew`, but the prompt instruction dialog uses transcribed spoken instructions for opening content in a new tab.\n\n#### `:GpWhisperPopup` \u003C!-- {doc=:GpWhisperPopup}  -->\n\nSimilar to `:GpPopup`, but the prompt instruction dialog uses transcribed spoken instructions for displaying content in a pop-up window.\n\n## Agent commands\n\n#### `:GpNextAgent` \u003C!-- {doc=:GpNextAgent}  -->\n\nCycles between available agents based on the current buffer (chat agents if current buffer is a chat and command agents otherwise). The agent setting is persisted on disk across Neovim instances.\n\n#### `:GpAgent` \u003C!-- {doc=:GpAgent}  -->\n\nDisplays currently used agents for chat and command instructions.\n\n#### `:GpAgent XY` \u003C!-- {doc=:GpAgent-XY}  -->\n\nChoose a new agent based on its name, listing options based on the current buffer (chat agents if current buffer is a chat and command agents otherwise). The agent setting is persisted on disk across Neovim instances.\n\n#### `:GpSelectAgent` \u003C!-- {doc=:GpSelectAgent}  -->\n\nOpens a selection interface using `vim.ui.select` to choose from all available agents, allowing you to directly select the desired agent from a list. Works seamlessly with telescope if available.\n\n## Image commands\n\n#### `:GpImage` \u003C!-- {doc=:GpImage}  -->\n\nOpens a dialog for entering a prompt describing wanted images. When the generation is done it opens dialog for storing the image to the disk.\n\n#### `:GpImageAgent` \u003C!-- {doc=:GpImageAgent}  -->\n\nDisplays currently used image agent (configuration).\n\n#### `:GpImageAgent XY` \u003C!-- {doc=:GpImageAgent-XY}  -->\n\nChoose a new \"image agent\" based on its name. In the context of images, agent is basically a configuration for model, image size, quality and so on. The agent setting is persisted on disk across Neovim instances.\n\n## Other commands\n\n#### `:GpStop` \u003C!-- {doc=:GpStop}  -->\n\nStops all currently running responses and jobs.\n\n#### `:GpInspectPlugin` \u003C!-- {doc=:GpInspectPlugin}  -->\n\nInspects the GPT prompt plugin object in a new scratch buffer.\n\n## GpDone autocommand\n\nCommands like `GpRewrite`, `GpAppend` etc. run asynchronously and generate event `GpDone`, so you can define autocmd (like auto formating) to run when gp finishes:\n\n```lua\n    vim.api.nvim_create_autocmd({ \"User\" }, {\n        pattern = {\"GpDone\"},\n        callback = function(event)\n            print(\"event fired:\\n\", vim.inspect(event))\n            -- local b = event.buf\n            -- DO something\n        end,\n    })\n```\n\n## Custom instructions\n\nBy calling `:GpContext` you can make `.gp.md` markdown file in a root of a repository. Commands such as `:GpRewrite`, `:GpAppend` etc. will respect instructions provided in this file (works better with gpt4, gpt 3.5 doesn't always listen to system commands). For example:\n\n```md\nUse ‎C++17.\nUse Testify library when writing Go tests.\nUse Early return\u002FGuard Clauses pattern to avoid excessive nesting.\n...\n```\n\nHere is [another example](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fblob\u002Fmain\u002F.gp.md).\n\n## Scripting\n\n`GpDone` event + `.gp.md` custom instructions provide a possibility to run gp.nvim using headless (neo)vim from terminal or shell script. So you can let gp run edits accross many files if you put it in a loop.\n\n`test` file:\n\n```\n1\n2\n3\n4\n5\n```\n\n`.gp.md` file:\n\n````\nIf user says hello, please respond with:\n\n```\nAhoy there!\n```\n````\n\ncalling gp.nvim from terminal\u002Fscript:\n\n- register autocommand to save and quit nvim when Gp is done\n- second jumps to occurrence of something I want to rewrite\u002Fappend\u002Fprepend to (in this case number `3`)\n- selecting the line\n- calling gp.nvim acction\n\n```\n$ nvim --headless -c \"autocmd User GpDone wq\" -c \"\u002F3\" -c \"normal V\" -c \"GpAppend hello there\"  test\n```\n\nresulting `test` file:\n\n```\n1\n2\n3\nAhoy there!\n4\n5\n```\n\n# Shortcuts\n\nThere are no default global shortcuts to mess with your own config. Below are examples for you to adjust or just use directly.\n\n## Native\n\nYou can use the good old `vim.keymap.set` and paste the following after `require(\"gp\").setup(conf)` call\n(or anywhere you keep shortcuts if you want them at one place).\n\n```lua\nlocal function keymapOptions(desc)\n    return {\n        noremap = true,\n        silent = true,\n        nowait = true,\n        desc = \"GPT prompt \" .. desc,\n    }\nend\n\n-- Chat commands\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>c\", \"\u003Ccmd>GpChatNew\u003Ccr>\", keymapOptions(\"New Chat\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>t\", \"\u003Ccmd>GpChatToggle\u003Ccr>\", keymapOptions(\"Toggle Chat\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>f\", \"\u003Ccmd>GpChatFinder\u003Ccr>\", keymapOptions(\"Chat Finder\"))\n\nvim.keymap.set(\"v\", \"\u003CC-g>c\", \":\u003CC-u>'\u003C,'>GpChatNew\u003Ccr>\", keymapOptions(\"Visual Chat New\"))\nvim.keymap.set(\"v\", \"\u003CC-g>p\", \":\u003CC-u>'\u003C,'>GpChatPaste\u003Ccr>\", keymapOptions(\"Visual Chat Paste\"))\nvim.keymap.set(\"v\", \"\u003CC-g>t\", \":\u003CC-u>'\u003C,'>GpChatToggle\u003Ccr>\", keymapOptions(\"Visual Toggle Chat\"))\n\nvim.keymap.set({ \"n\", \"i\" }, \"\u003CC-g>\u003CC-x>\", \"\u003Ccmd>GpChatNew split\u003Ccr>\", keymapOptions(\"New Chat split\"))\nvim.keymap.set({ \"n\", \"i\" }, \"\u003CC-g>\u003CC-v>\", \"\u003Ccmd>GpChatNew vsplit\u003Ccr>\", keymapOptions(\"New Chat vsplit\"))\nvim.keymap.set({ \"n\", \"i\" }, \"\u003CC-g>\u003CC-t>\", \"\u003Ccmd>GpChatNew tabnew\u003Ccr>\", keymapOptions(\"New Chat tabnew\"))\n\nvim.keymap.set(\"v\", \"\u003CC-g>\u003CC-x>\", \":\u003CC-u>'\u003C,'>GpChatNew split\u003Ccr>\", keymapOptions(\"Visual Chat New split\"))\nvim.keymap.set(\"v\", \"\u003CC-g>\u003CC-v>\", \":\u003CC-u>'\u003C,'>GpChatNew vsplit\u003Ccr>\", keymapOptions(\"Visual Chat New vsplit\"))\nvim.keymap.set(\"v\", \"\u003CC-g>\u003CC-t>\", \":\u003CC-u>'\u003C,'>GpChatNew tabnew\u003Ccr>\", keymapOptions(\"Visual Chat New tabnew\"))\n\n-- Prompt commands\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>r\", \"\u003Ccmd>GpRewrite\u003Ccr>\", keymapOptions(\"Inline Rewrite\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>a\", \"\u003Ccmd>GpAppend\u003Ccr>\", keymapOptions(\"Append (after)\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>b\", \"\u003Ccmd>GpPrepend\u003Ccr>\", keymapOptions(\"Prepend (before)\"))\n\nvim.keymap.set(\"v\", \"\u003CC-g>r\", \":\u003CC-u>'\u003C,'>GpRewrite\u003Ccr>\", keymapOptions(\"Visual Rewrite\"))\nvim.keymap.set(\"v\", \"\u003CC-g>a\", \":\u003CC-u>'\u003C,'>GpAppend\u003Ccr>\", keymapOptions(\"Visual Append (after)\"))\nvim.keymap.set(\"v\", \"\u003CC-g>b\", \":\u003CC-u>'\u003C,'>GpPrepend\u003Ccr>\", keymapOptions(\"Visual Prepend (before)\"))\nvim.keymap.set(\"v\", \"\u003CC-g>i\", \":\u003CC-u>'\u003C,'>GpImplement\u003Ccr>\", keymapOptions(\"Implement selection\"))\n\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>gp\", \"\u003Ccmd>GpPopup\u003Ccr>\", keymapOptions(\"Popup\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>ge\", \"\u003Ccmd>GpEnew\u003Ccr>\", keymapOptions(\"GpEnew\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>gn\", \"\u003Ccmd>GpNew\u003Ccr>\", keymapOptions(\"GpNew\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>gv\", \"\u003Ccmd>GpVnew\u003Ccr>\", keymapOptions(\"GpVnew\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>gt\", \"\u003Ccmd>GpTabnew\u003Ccr>\", keymapOptions(\"GpTabnew\"))\n\nvim.keymap.set(\"v\", \"\u003CC-g>gp\", \":\u003CC-u>'\u003C,'>GpPopup\u003Ccr>\", keymapOptions(\"Visual Popup\"))\nvim.keymap.set(\"v\", \"\u003CC-g>ge\", \":\u003CC-u>'\u003C,'>GpEnew\u003Ccr>\", keymapOptions(\"Visual GpEnew\"))\nvim.keymap.set(\"v\", \"\u003CC-g>gn\", \":\u003CC-u>'\u003C,'>GpNew\u003Ccr>\", keymapOptions(\"Visual GpNew\"))\nvim.keymap.set(\"v\", \"\u003CC-g>gv\", \":\u003CC-u>'\u003C,'>GpVnew\u003Ccr>\", keymapOptions(\"Visual GpVnew\"))\nvim.keymap.set(\"v\", \"\u003CC-g>gt\", \":\u003CC-u>'\u003C,'>GpTabnew\u003Ccr>\", keymapOptions(\"Visual GpTabnew\"))\n\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>x\", \"\u003Ccmd>GpContext\u003Ccr>\", keymapOptions(\"Toggle Context\"))\nvim.keymap.set(\"v\", \"\u003CC-g>x\", \":\u003CC-u>'\u003C,'>GpContext\u003Ccr>\", keymapOptions(\"Visual Toggle Context\"))\n\nvim.keymap.set({\"n\", \"i\", \"v\", \"x\"}, \"\u003CC-g>s\", \"\u003Ccmd>GpStop\u003Ccr>\", keymapOptions(\"Stop\"))\nvim.keymap.set({\"n\", \"i\", \"v\", \"x\"}, \"\u003CC-g>n\", \"\u003Ccmd>GpNextAgent\u003Ccr>\", keymapOptions(\"Next Agent\"))\nvim.keymap.set({\"n\", \"i\", \"v\", \"x\"}, \"\u003CC-g>l\", \"\u003Ccmd>GpSelectAgent\u003Ccr>\", keymapOptions(\"Select Agent\"))\n\n-- optional Whisper commands with prefix \u003CC-g>w\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>ww\", \"\u003Ccmd>GpWhisper\u003Ccr>\", keymapOptions(\"Whisper\"))\nvim.keymap.set(\"v\", \"\u003CC-g>ww\", \":\u003CC-u>'\u003C,'>GpWhisper\u003Ccr>\", keymapOptions(\"Visual Whisper\"))\n\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>wr\", \"\u003Ccmd>GpWhisperRewrite\u003Ccr>\", keymapOptions(\"Whisper Inline Rewrite\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>wa\", \"\u003Ccmd>GpWhisperAppend\u003Ccr>\", keymapOptions(\"Whisper Append (after)\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>wb\", \"\u003Ccmd>GpWhisperPrepend\u003Ccr>\", keymapOptions(\"Whisper Prepend (before) \"))\n\nvim.keymap.set(\"v\", \"\u003CC-g>wr\", \":\u003CC-u>'\u003C,'>GpWhisperRewrite\u003Ccr>\", keymapOptions(\"Visual Whisper Rewrite\"))\nvim.keymap.set(\"v\", \"\u003CC-g>wa\", \":\u003CC-u>'\u003C,'>GpWhisperAppend\u003Ccr>\", keymapOptions(\"Visual Whisper Append (after)\"))\nvim.keymap.set(\"v\", \"\u003CC-g>wb\", \":\u003CC-u>'\u003C,'>GpWhisperPrepend\u003Ccr>\", keymapOptions(\"Visual Whisper Prepend (before)\"))\n\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>wp\", \"\u003Ccmd>GpWhisperPopup\u003Ccr>\", keymapOptions(\"Whisper Popup\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>we\", \"\u003Ccmd>GpWhisperEnew\u003Ccr>\", keymapOptions(\"Whisper Enew\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>wn\", \"\u003Ccmd>GpWhisperNew\u003Ccr>\", keymapOptions(\"Whisper New\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>wv\", \"\u003Ccmd>GpWhisperVnew\u003Ccr>\", keymapOptions(\"Whisper Vnew\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>wt\", \"\u003Ccmd>GpWhisperTabnew\u003Ccr>\", keymapOptions(\"Whisper Tabnew\"))\n\nvim.keymap.set(\"v\", \"\u003CC-g>wp\", \":\u003CC-u>'\u003C,'>GpWhisperPopup\u003Ccr>\", keymapOptions(\"Visual Whisper Popup\"))\nvim.keymap.set(\"v\", \"\u003CC-g>we\", \":\u003CC-u>'\u003C,'>GpWhisperEnew\u003Ccr>\", keymapOptions(\"Visual Whisper Enew\"))\nvim.keymap.set(\"v\", \"\u003CC-g>wn\", \":\u003CC-u>'\u003C,'>GpWhisperNew\u003Ccr>\", keymapOptions(\"Visual Whisper New\"))\nvim.keymap.set(\"v\", \"\u003CC-g>wv\", \":\u003CC-u>'\u003C,'>GpWhisperVnew\u003Ccr>\", keymapOptions(\"Visual Whisper Vnew\"))\nvim.keymap.set(\"v\", \"\u003CC-g>wt\", \":\u003CC-u>'\u003C,'>GpWhisperTabnew\u003Ccr>\", keymapOptions(\"Visual Whisper Tabnew\"))\n```\n\n## Whichkey\n\nOr go more fancy by using [which-key.nvim](https:\u002F\u002Fgithub.com\u002Ffolke\u002Fwhich-key.nvim) plugin:\n\n```lua\nrequire(\"which-key\").add({\n    -- VISUAL mode mappings\n    -- s, x, v modes are handled the same way by which_key\n    {\n        mode = { \"v\" },\n        nowait = true,\n        remap = false,\n        { \"\u003CC-g>\u003CC-t>\", \":\u003CC-u>'\u003C,'>GpChatNew tabnew\u003Ccr>\", desc = \"ChatNew tabnew\" },\n        { \"\u003CC-g>\u003CC-v>\", \":\u003CC-u>'\u003C,'>GpChatNew vsplit\u003Ccr>\", desc = \"ChatNew vsplit\" },\n        { \"\u003CC-g>\u003CC-x>\", \":\u003CC-u>'\u003C,'>GpChatNew split\u003Ccr>\", desc = \"ChatNew split\" },\n        { \"\u003CC-g>a\", \":\u003CC-u>'\u003C,'>GpAppend\u003Ccr>\", desc = \"Visual Append (after)\" },\n        { \"\u003CC-g>b\", \":\u003CC-u>'\u003C,'>GpPrepend\u003Ccr>\", desc = \"Visual Prepend (before)\" },\n        { \"\u003CC-g>c\", \":\u003CC-u>'\u003C,'>GpChatNew\u003Ccr>\", desc = \"Visual Chat New\" },\n        { \"\u003CC-g>g\", group = \"generate into new ..\" },\n        { \"\u003CC-g>ge\", \":\u003CC-u>'\u003C,'>GpEnew\u003Ccr>\", desc = \"Visual GpEnew\" },\n        { \"\u003CC-g>gn\", \":\u003CC-u>'\u003C,'>GpNew\u003Ccr>\", desc = \"Visual GpNew\" },\n        { \"\u003CC-g>gp\", \":\u003CC-u>'\u003C,'>GpPopup\u003Ccr>\", desc = \"Visual Popup\" },\n        { \"\u003CC-g>gt\", \":\u003CC-u>'\u003C,'>GpTabnew\u003Ccr>\", desc = \"Visual GpTabnew\" },\n        { \"\u003CC-g>gv\", \":\u003CC-u>'\u003C,'>GpVnew\u003Ccr>\", desc = \"Visual GpVnew\" },\n        { \"\u003CC-g>i\", \":\u003CC-u>'\u003C,'>GpImplement\u003Ccr>\", desc = \"Implement selection\" },\n        { \"\u003CC-g>n\", \"\u003Ccmd>GpNextAgent\u003Ccr>\", desc = \"Next Agent\" },\n        { \"\u003CC-g>l\", \"\u003Ccmd>GpSelectAgent\u003Ccr>\", desc = \"Select Agent\" },\n        { \"\u003CC-g>p\", \":\u003CC-u>'\u003C,'>GpChatPaste\u003Ccr>\", desc = \"Visual Chat Paste\" },\n        { \"\u003CC-g>r\", \":\u003CC-u>'\u003C,'>GpRewrite\u003Ccr>\", desc = \"Visual Rewrite\" },\n        { \"\u003CC-g>s\", \"\u003Ccmd>GpStop\u003Ccr>\", desc = \"GpStop\" },\n        { \"\u003CC-g>t\", \":\u003CC-u>'\u003C,'>GpChatToggle\u003Ccr>\", desc = \"Visual Toggle Chat\" },\n        { \"\u003CC-g>w\", group = \"Whisper\" },\n        { \"\u003CC-g>wa\", \":\u003CC-u>'\u003C,'>GpWhisperAppend\u003Ccr>\", desc = \"Whisper Append\" },\n        { \"\u003CC-g>wb\", \":\u003CC-u>'\u003C,'>GpWhisperPrepend\u003Ccr>\", desc = \"Whisper Prepend\" },\n        { \"\u003CC-g>we\", \":\u003CC-u>'\u003C,'>GpWhisperEnew\u003Ccr>\", desc = \"Whisper Enew\" },\n        { \"\u003CC-g>wn\", \":\u003CC-u>'\u003C,'>GpWhisperNew\u003Ccr>\", desc = \"Whisper New\" },\n        { \"\u003CC-g>wp\", \":\u003CC-u>'\u003C,'>GpWhisperPopup\u003Ccr>\", desc = \"Whisper Popup\" },\n        { \"\u003CC-g>wr\", \":\u003CC-u>'\u003C,'>GpWhisperRewrite\u003Ccr>\", desc = \"Whisper Rewrite\" },\n        { \"\u003CC-g>wt\", \":\u003CC-u>'\u003C,'>GpWhisperTabnew\u003Ccr>\", desc = \"Whisper Tabnew\" },\n        { \"\u003CC-g>wv\", \":\u003CC-u>'\u003C,'>GpWhisperVnew\u003Ccr>\", desc = \"Whisper Vnew\" },\n        { \"\u003CC-g>ww\", \":\u003CC-u>'\u003C,'>GpWhisper\u003Ccr>\", desc = \"Whisper\" },\n        { \"\u003CC-g>x\", \":\u003CC-u>'\u003C,'>GpContext\u003Ccr>\", desc = \"Visual GpContext\" },\n    },\n\n    -- NORMAL mode mappings\n    {\n        mode = { \"n\" },\n        nowait = true,\n        remap = false,\n        { \"\u003CC-g>\u003CC-t>\", \"\u003Ccmd>GpChatNew tabnew\u003Ccr>\", desc = \"New Chat tabnew\" },\n        { \"\u003CC-g>\u003CC-v>\", \"\u003Ccmd>GpChatNew vsplit\u003Ccr>\", desc = \"New Chat vsplit\" },\n        { \"\u003CC-g>\u003CC-x>\", \"\u003Ccmd>GpChatNew split\u003Ccr>\", desc = \"New Chat split\" },\n        { \"\u003CC-g>a\", \"\u003Ccmd>GpAppend\u003Ccr>\", desc = \"Append (after)\" },\n        { \"\u003CC-g>b\", \"\u003Ccmd>GpPrepend\u003Ccr>\", desc = \"Prepend (before)\" },\n        { \"\u003CC-g>c\", \"\u003Ccmd>GpChatNew\u003Ccr>\", desc = \"New Chat\" },\n        { \"\u003CC-g>f\", \"\u003Ccmd>GpChatFinder\u003Ccr>\", desc = \"Chat Finder\" },\n        { \"\u003CC-g>g\", group = \"generate into new ..\" },\n        { \"\u003CC-g>ge\", \"\u003Ccmd>GpEnew\u003Ccr>\", desc = \"GpEnew\" },\n        { \"\u003CC-g>gn\", \"\u003Ccmd>GpNew\u003Ccr>\", desc = \"GpNew\" },\n        { \"\u003CC-g>gp\", \"\u003Ccmd>GpPopup\u003Ccr>\", desc = \"Popup\" },\n        { \"\u003CC-g>gt\", \"\u003Ccmd>GpTabnew\u003Ccr>\", desc = \"GpTabnew\" },\n        { \"\u003CC-g>gv\", \"\u003Ccmd>GpVnew\u003Ccr>\", desc = \"GpVnew\" },\n        { \"\u003CC-g>n\", \"\u003Ccmd>GpNextAgent\u003Ccr>\", desc = \"Next Agent\" },\n        { \"\u003CC-g>l\", \"\u003Ccmd>GpSelectAgent\u003Ccr>\", desc = \"Select Agent\" },\n        { \"\u003CC-g>r\", \"\u003Ccmd>GpRewrite\u003Ccr>\", desc = \"Inline Rewrite\" },\n        { \"\u003CC-g>s\", \"\u003Ccmd>GpStop\u003Ccr>\", desc = \"GpStop\" },\n        { \"\u003CC-g>t\", \"\u003Ccmd>GpChatToggle\u003Ccr>\", desc = \"Toggle Chat\" },\n        { \"\u003CC-g>w\", group = \"Whisper\" },\n        { \"\u003CC-g>wa\", \"\u003Ccmd>GpWhisperAppend\u003Ccr>\", desc = \"Whisper Append (after)\" },\n        { \"\u003CC-g>wb\", \"\u003Ccmd>GpWhisperPrepend\u003Ccr>\", desc = \"Whisper Prepend (before)\" },\n        { \"\u003CC-g>we\", \"\u003Ccmd>GpWhisperEnew\u003Ccr>\", desc = \"Whisper Enew\" },\n        { \"\u003CC-g>wn\", \"\u003Ccmd>GpWhisperNew\u003Ccr>\", desc = \"Whisper New\" },\n        { \"\u003CC-g>wp\", \"\u003Ccmd>GpWhisperPopup\u003Ccr>\", desc = \"Whisper Popup\" },\n        { \"\u003CC-g>wr\", \"\u003Ccmd>GpWhisperRewrite\u003Ccr>\", desc = \"Whisper Inline Rewrite\" },\n        { \"\u003CC-g>wt\", \"\u003Ccmd>GpWhisperTabnew\u003Ccr>\", desc = \"Whisper Tabnew\" },\n        { \"\u003CC-g>wv\", \"\u003Ccmd>GpWhisperVnew\u003Ccr>\", desc = \"Whisper Vnew\" },\n        { \"\u003CC-g>ww\", \"\u003Ccmd>GpWhisper\u003Ccr>\", desc = \"Whisper\" },\n        { \"\u003CC-g>x\", \"\u003Ccmd>GpContext\u003Ccr>\", desc = \"Toggle GpContext\" },\n    },\n\n    -- INSERT mode mappings\n    {\n        mode = { \"i\" },\n        nowait = true,\n        remap = false,\n        { \"\u003CC-g>\u003CC-t>\", \"\u003Ccmd>GpChatNew tabnew\u003Ccr>\", desc = \"New Chat tabnew\" },\n        { \"\u003CC-g>\u003CC-v>\", \"\u003Ccmd>GpChatNew vsplit\u003Ccr>\", desc = \"New Chat vsplit\" },\n        { \"\u003CC-g>\u003CC-x>\", \"\u003Ccmd>GpChatNew split\u003Ccr>\", desc = \"New Chat split\" },\n        { \"\u003CC-g>a\", \"\u003Ccmd>GpAppend\u003Ccr>\", desc = \"Append (after)\" },\n        { \"\u003CC-g>b\", \"\u003Ccmd>GpPrepend\u003Ccr>\", desc = \"Prepend (before)\" },\n        { \"\u003CC-g>c\", \"\u003Ccmd>GpChatNew\u003Ccr>\", desc = \"New Chat\" },\n        { \"\u003CC-g>f\", \"\u003Ccmd>GpChatFinder\u003Ccr>\", desc = \"Chat Finder\" },\n        { \"\u003CC-g>g\", group = \"generate into new ..\" },\n        { \"\u003CC-g>ge\", \"\u003Ccmd>GpEnew\u003Ccr>\", desc = \"GpEnew\" },\n        { \"\u003CC-g>gn\", \"\u003Ccmd>GpNew\u003Ccr>\", desc = \"GpNew\" },\n        { \"\u003CC-g>gp\", \"\u003Ccmd>GpPopup\u003Ccr>\", desc = \"Popup\" },\n        { \"\u003CC-g>gt\", \"\u003Ccmd>GpTabnew\u003Ccr>\", desc = \"GpTabnew\" },\n        { \"\u003CC-g>gv\", \"\u003Ccmd>GpVnew\u003Ccr>\", desc = \"GpVnew\" },\n        { \"\u003CC-g>n\", \"\u003Ccmd>GpNextAgent\u003Ccr>\", desc = \"Next Agent\" },\n        { \"\u003CC-g>l\", \"\u003Ccmd>GpSelectAgent\u003Ccr>\", desc = \"Select Agent\" },\n        { \"\u003CC-g>r\", \"\u003Ccmd>GpRewrite\u003Ccr>\", desc = \"Inline Rewrite\" },\n        { \"\u003CC-g>s\", \"\u003Ccmd>GpStop\u003Ccr>\", desc = \"GpStop\" },\n        { \"\u003CC-g>t\", \"\u003Ccmd>GpChatToggle\u003Ccr>\", desc = \"Toggle Chat\" },\n        { \"\u003CC-g>w\", group = \"Whisper\" },\n        { \"\u003CC-g>wa\", \"\u003Ccmd>GpWhisperAppend\u003Ccr>\", desc = \"Whisper Append (after)\" },\n        { \"\u003CC-g>wb\", \"\u003Ccmd>GpWhisperPrepend\u003Ccr>\", desc = \"Whisper Prepend (before)\" },\n        { \"\u003CC-g>we\", \"\u003Ccmd>GpWhisperEnew\u003Ccr>\", desc = \"Whisper Enew\" },\n        { \"\u003CC-g>wn\", \"\u003Ccmd>GpWhisperNew\u003Ccr>\", desc = \"Whisper New\" },\n        { \"\u003CC-g>wp\", \"\u003Ccmd>GpWhisperPopup\u003Ccr>\", desc = \"Whisper Popup\" },\n        { \"\u003CC-g>wr\", \"\u003Ccmd>GpWhisperRewrite\u003Ccr>\", desc = \"Whisper Inline Rewrite\" },\n        { \"\u003CC-g>wt\", \"\u003Ccmd>GpWhisperTabnew\u003Ccr>\", desc = \"Whisper Tabnew\" },\n        { \"\u003CC-g>wv\", \"\u003Ccmd>GpWhisperVnew\u003Ccr>\", desc = \"Whisper Vnew\" },\n        { \"\u003CC-g>ww\", \"\u003Ccmd>GpWhisper\u003Ccr>\", desc = \"Whisper\" },\n        { \"\u003CC-g>x\", \"\u003Ccmd>GpContext\u003Ccr>\", desc = \"Toggle GpContext\" },\n    },\n})\n```\n\n# Extend functionality\n\nYou can extend\u002Foverride the plugin functionality with your own, by putting functions into `config.hooks`.\nHooks have access to everything (see `InspectPlugin` example in defaults) and are\nautomatically registered as commands (`GpInspectPlugin`).\n\nHere are some more examples:\n\n- `:GpUnitTests`\n\n  ````lua\n  -- example of adding command which writes unit tests for the selected code\n  UnitTests = function(gp, params)\n      local template = \"I have the following code from {{filename}}:\\n\\n\"\n          .. \"```{{filetype}}\\n{{selection}}\\n```\\n\\n\"\n          .. \"Please respond by writing table driven unit tests for the code above.\"\n      local agent = gp.get_command_agent()\n      gp.Prompt(params, gp.Target.vnew, agent, template)\n  end,\n  ````\n\n- `:GpExplain`\n\n  ````lua\n  -- example of adding command which explains the selected code\n  Explain = function(gp, params)\n      local template = \"I have the following code from {{filename}}:\\n\\n\"\n          .. \"```{{filetype}}\\n{{selection}}\\n```\\n\\n\"\n          .. \"Please respond by explaining the code above.\"\n      local agent = gp.get_chat_agent()\n      gp.Prompt(params, gp.Target.popup, agent, template)\n  end,\n  ````\n\n- `:GpCodeReview`\n\n  ````lua\n  -- example of usig enew as a function specifying type for the new buffer\n  CodeReview = function(gp, params)\n      local template = \"I have the following code from {{filename}}:\\n\\n\"\n          .. \"```{{filetype}}\\n{{selection}}\\n```\\n\\n\"\n          .. \"Please analyze for code smells and suggest improvements.\"\n      local agent = gp.get_chat_agent()\n      gp.Prompt(params, gp.Target.enew(\"markdown\"), agent, template)\n  end,\n  ````\n\n- `:GpTranslator`\n\n  ```lua\n  -- example of adding command which opens new chat dedicated for translation\n  Translator = function(gp, params)\n      local chat_system_prompt = \"You are a Translator, please translate between English and Chinese.\"\n      gp.cmd.ChatNew(params, chat_system_prompt)\n\n      -- -- you can also create a chat with a specific fixed agent like this:\n      -- local agent = gp.get_chat_agent(\"ChatGPT4o\")\n      -- gp.cmd.ChatNew(params, chat_system_prompt, agent)\n  end,\n  ```\n\n- `:GpBufferChatNew`\n\n  ```lua\n  -- example of making :%GpChatNew a dedicated command which\n  -- opens new chat with the entire current buffer as a context\n  BufferChatNew = function(gp, _)\n      -- call GpChatNew command in range mode on whole buffer\n      vim.api.nvim_command(\"%\" .. gp.config.cmd_prefix .. \"ChatNew\")\n  end,\n  ```\n\nThe raw plugin text editing method `Prompt` has following signature:\n```lua\n---@param params table  # vim command parameters such as range, args, etc.\n---@param target integer | function | table  # where to put the response\n---@param agent table  # obtained from get_command_agent or get_chat_agent\n---@param template string  # template with model instructions\n---@param prompt string | nil  # nil for non interactive commads\n---@param whisper string | nil  # predefined input (e.g. obtained from Whisper)\n---@param callback function | nil  # callback(response) after completing the prompt\nPrompt(params, target, agent, template, prompt, whisper, callback)\n```\n\n- `params` is a [table passed to neovim user commands](https:\u002F\u002Fneovim.io\u002Fdoc\u002Fuser\u002Flua-guide.html#lua-guide-commands-create), `Prompt` currently uses:\n\n  - `range, line1, line2` to work with [ranges](https:\u002F\u002Fneovim.io\u002Fdoc\u002Fuser\u002Fusr_10.html#10.3)\n  - `args` so instructions can be passed directly after command (`:GpRewrite something something`)\n\n  ```lua\n  params = {\n        args = \"\",\n        bang = false,\n        count = -1,\n        fargs = {},\n        line1 = 1352,\n        line2 = 1352,\n        mods = \"\",\n        name = \"GpChatNew\",\n        range = 0,\n        reg = \"\",\n        smods = {\n              browse = false,\n              confirm = false,\n              emsg_silent = false,\n              hide = false,\n              horizontal = false,\n              keepalt = false,\n              keepjumps = false,\n              keepmarks = false,\n              keeppatterns = false,\n              lockmarks = false,\n              noautocmd = false,\n              noswapfile = false,\n              sandbox = false,\n              silent = false,\n              split = \"\",\n              tab = -1,\n              unsilent = false,\n              verbose = -1,\n              vertical = false\n        }\n  }\n  ```\n\n- `target` specifying where to direct GPT response\n\n  - enew\u002Fnew\u002Fvnew\u002Ftabnew can be used as a function so you can pass in a filetype\n    for the new buffer (`enew\u002Fenew()\u002Fenew(\"markdown\")\u002F..`)\n\n  ```lua\n  M.Target = {\n      rewrite = 0, -- for replacing the selection, range or the current line\n      append = 1, -- for appending after the selection, range or the current line\n      prepend = 2, -- for prepending before the selection, range or the current line\n      popup = 3, -- for writing into the popup window\n\n      -- for writing into a new buffer\n      ---@param filetype nil | string # nil = same as the original buffer\n      ---@return table # a table with type=4 and filetype=filetype\n      enew = function(filetype)\n          return { type = 4, filetype = filetype }\n      end,\n\n      --- for creating a new horizontal split\n      ---@param filetype nil | string # nil = same as the original buffer\n      ---@return table # a table with type=5 and filetype=filetype\n      new = function(filetype)\n          return { type = 5, filetype = filetype }\n      end,\n\n      --- for creating a new vertical split\n      ---@param filetype nil | string # nil = same as the original buffer\n      ---@return table # a table with type=6 and filetype=filetype\n      vnew = function(filetype)\n          return { type = 6, filetype = filetype }\n      end,\n\n      --- for creating a new tab\n      ---@param filetype nil | string # nil = same as the original buffer\n      ---@return table # a table with type=7 and filetype=filetype\n      tabnew = function(filetype)\n          return { type = 7, filetype = filetype }\n      end,\n  }\n  ```\n\n\n- `agent` table obtainable via `get_command_agent` and `get_chat_agent` methods which have following signature:\n  ```lua\n  ---@param name string | nil\n  ---@return table # { cmd_prefix, name, model, system_prompt, provider }\n  get_command_agent(name)\n  ```\n\n- `template`\n\n  - template of the user message send to gpt\n  - string can include variables below:\n\n    | name            | Description                       |\n    | --------------- | --------------------------------- |\n    | `{{filetype}}`  | filetype of the current buffer    |\n    | `{{selection}}` | last or currently selected text   |\n    | `{{command}}`   | instructions provided by the user |\n\n- `prompt`\n  - string used similarly as bash\u002Fzsh prompt in terminal, when plugin asks for user command to gpt.\n  - if `nil`, user is not asked to provide input (for specific predefined commands - document this, explain that, write tests ..)\n  - simple `🤖 ~ ` might be used or you could use different msg to convey info about the method which is called  \n    (`🤖 rewrite ~`, `🤖 popup ~`, `🤖 enew ~`, `🤖 inline ~`, etc.)\n- `whisper`\n  - optional string serving as a default for input prompt (for example generated from speech by Whisper)\n- `callback`\n  - optional callback function allowing post processing logic on the prompt response  \n    (for example letting the model to generate commit message and using the callback to make actual commit)\n","\u003C!-- panvimdoc-ignore-start -->\n\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fblob\u002Fmain\u002FLICENSE\">\u003Cimg alt=\"GitHub\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Flicense\u002Frobitx\u002Fgp.nvim\">\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fstargazers\">\u003Cimg alt=\"GitHub Repo stars\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fstars\u002FRobitx\u002Fgp.nvim\">\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\">\u003Cimg alt=\"GitHub closed issues\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fissues-closed\u002FRobitx\u002Fgp.nvim\">\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fpulls\">\u003Cimg alt=\"GitHub closed pull requests\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fissues-pr-closed\u002FRobitx\u002Fgp.nvim?label=PRs\">\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fgraphs\u002Fcontributors\">\u003Cimg alt=\"GitHub contributors\" src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fcontributors-anon\u002FRobitx\u002Fgp.nvim\">\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fsearch?q=%2F%5E%5B%5Cs%5D*require%5C%28%5B%27%22%5Dgp%5B%27%22%5D%5C%29%5C.setup%2F+language%3ALua&type=code&p=1\">\u003Cimg alt=\"Static Badge\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FUse%20in%20the%20Wild-8A2BE2\">\u003C\u002Fa>\n\u003Ca href=\"https:\u002F\u002Fdiscord.gg\u002FdYyHmyNpv7\">\u003Cimg alt=\"Discord\" src=\"https:\u002F\u002Fimg.shields.io\u002Fdiscord\u002F1200485978725433484?label=Discord\">\u003C\u002Fa>\n\n\n# Gp.nvim (GPT prompt) Neovim AI 插件\n\n\u003C!-- panvimdoc-ignore-end -->\n\n\u003Cbr>\n\n**类 ChatGPT 的会话、可指导的文本\u002F代码操作、语音转文本以及在您最喜欢的编辑器中生成图像。**\n\n\u003Cp align=\"left\">\n\u003Cimg src=\"https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FRobitx_gp.nvim_readme_514254e8b91b.png\" width=\"49%\">\n\u003Cimg src=\"https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FRobitx_gp.nvim_readme_87f46d3a3453.png\" width=\"49%\">\n\u003C\u002Fp>\n\n### YouTube 演示视频\n\n- [5 分钟演示](https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=X-cT7s47PLo)（2023 年 12 月）\n- [较早的 5 分钟演示](https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=wPDcBnQgNCc)（屏幕录像，无声音）\n\n# 目标与特性\n\n目标是以一种简单、不突兀且可扩展的方式，将 **GPT 模型的强大功能扩展到 Neovim 中。**  \n同时尽可能保持原生性——复用并良好地集成 (Neo)vim 的自然特性。\n\n- **流式响应**\n  - 无需旋转的加载动画和等待完整答案\n  - 可以在响应生成过程中途取消\n  - 完美支持撤销（只需按一下 `u` 键即可撤销响应）\n- **无限可扩展性**，通过配置中指定的钩子函数实现\n  - 钩子函数可以访问插件中的所有内容，并自动注册为命令\n  - 详情请参见 [5. 配置](#5-configuration) 和 [扩展功能](#extend-functionality) 部分\n- **最少依赖项**（`neovim`、`curl`、`grep`，可选 `sox`）\n  - 不依赖其他 Lua 插件，以最大限度减少出错的可能性\n- **类 ChatGPT 的会话**\n  - 使用格式化为 Markdown 的传统 Neovim 缓冲区，具备自动保存功能和少量缓冲区绑定的快捷键\n  - 最近的聊天记录可通过可切换的弹出窗口快速访问\n  - 聊天查找器——一个用于搜索、预览、删除和打开聊天会话的管理弹出窗口\n- **可指导的文本\u002F代码操作**\n  - 提供模板机制，可将用户指令、选区等内容组合成 GPT 查询\n  - 多模态支持——同一命令适用于普通模式和插入模式，无论是带选区还是范围均可使用\n  - 输出目标多样——重写、前置、追加、新建缓冲区、弹出窗口等\n  - 提供非交互式命令模式，适用于可由简单钩子实现的常见重复性任务  \n    （例如，在弹出窗口中解释某事、将选中的代码单元测试写入新缓冲区、根据注释完成选中代码等）\n  - 支持按仓库自定义指令，通过 `.gp.md` 文件实现  \n    （指示 GPT 使用特定库、包、规范等来生成代码）\n- **语音转文本支持**\n  - 说话的速度通常是打字的 2 到 4 倍——在合适的情况下充分利用这一优势  \n    （口述注释和笔记、向 GPT 提问、给出代码操作指令等）\n- **图像生成**\n  - 无需再打开浏览器，直接在 Neovim 中就能生成图像，进一步提升效率\n\n# 安装\n\n## 1. 安装插件\n\n您常用包管理器的代码片段：\n\n```lua\n-- lazy.nvim\n{\n    \"robitx\u002Fgp.nvim\",\n    config = function()\n        local conf = {\n            -- 如需自定义，请参考文档\u002FREADME 中的“安装 > 配置”部分\n        }\n        require(\"gp\").setup(conf)\n\n        -- 在此处设置快捷键（参见文档\u002FREADME 中的“使用 > 快捷键”部分）\n    end,\n}\n```\n\n```lua\n-- packer.nvim\nuse({\n    \"robitx\u002Fgp.nvim\",\n    config = function()\n        local conf = {\n            -- 如需自定义，请参考文档\u002FREADME 中的“安装 > 配置”部分\n        }\n        require(\"gp\").setup(conf)\n\n        -- 在此处设置快捷键（参见文档\u002FREADME 中的“使用 > 快捷键”部分）\n    end,\n})\n```\n\n```lua\n-- vim-plug\nPlug 'robitx\u002Fgp.nvim'\n\nlocal conf = {\n    -- 如需自定义，请参考文档\u002FREADME 中的“安装 > 配置”部分\n}\nrequire(\"gp\").setup(conf)\n\n-- 在此处设置快捷键（参见文档\u002FREADME 中的“使用 > 快捷键”部分）\n```\n## 2. OpenAI API 密钥\n\n请确保您已拥有 OpenAI API 密钥。[在此处获取](https:\u002F\u002Fplatform.openai.com\u002Faccount\u002Fapi-keys)，并在 [5. 配置](#5-configuration) 中使用它。同时建议设置 [使用限制](https:\u002F\u002Fplatform.openai.com\u002Faccount\u002Fbilling\u002Flimits)，以免月底收到意外账单。\n\nOpenAI API 密钥可以通过多种方式传递给插件：\n\n| 方法                    | 示例                                                        | 安全级别      |\n| ------------------------- | -------------------------------------------------------------- | ------------------- |\n| 硬编码字符串          | `openai_api_key: \"sk-...\",`                                    | 低                 |\n| 默认环境变量           | 在 shell 配置中设置 `OPENAI_API_KEY` 环境变量                | 中等              |\n| 自定义环境变量            | `openai_api_key = os.getenv(\"CUSTOM_ENV_NAME\"),`               | 中等              |\n| 从文件读取            | `openai_api_key = { \"cat\", \"path_to_api_key\" },`               | 中高              |\n| 密码管理器          | `openai_api_key = { \"bw\", \"get\", \"password\", \"OAI_API_KEY\" },` | 高                |\n\n如果 `openai_api_key` 是一个表，Gp 会异步执行它，以避免阻塞 Neovim（密码管理器可能需要一两秒钟）。\n\n## 3. 多个提供商\n除了 OpenAI 之外，目前还支持以下 LLM 提供商：\n\n- [Ollama](https:\u002F\u002Fgithub.com\u002Follama\u002Follama)，用于本地\u002F离线的开源模型。该插件假设您已启动并运行 Ollama 服务，并配置了可用的模型（默认的 Ollama 代理使用 Llama3）。\n- [GitHub Copilot](https:\u002F\u002Fgithub.com\u002Fsettings\u002Fcopilot)，需要 Copilot 许可证（可通过 [zbirenbaum\u002Fcopilot.lua](https:\u002F\u002Fgithub.com\u002Fzbirenbaum\u002Fcopilot.lua) 或 [github\u002Fcopilot.vim](https:\u002F\u002Fgithub.com\u002Fgithub\u002Fcopilot.vim) 实现自动补全）。您可以无需额外付费即可访问底层的 GPT-4 模型（相当于无限制地使用 GPT-4）。\n- [Perplexity.ai](https:\u002F\u002Fwww.perplexity.ai\u002Fpro)，Pro 用户每月可获得价值 5 美元的免费 API 信用额度（默认的 PPLX 代理使用 Mixtral-8x7b）。\n- [Anthropic](https:\u002F\u002Fwww.anthropic.com\u002Fapi)，用于访问 Claude 模型，这些模型在某些基准测试中目前表现优于 GPT-4。\n- [Google Gemini](https:\u002F\u002Fai.google.dev\u002F)，提供相当慷慨的免费使用范围，但存在一些地理限制（例如欧盟地区）。\n- 任何其他兼容“OpenAI chat\u002Fcompletions”接口的端点（如 Azure、LM Studio 等）。\n\n以下是启用其中部分提供商的相关配置示例。`secret` 字段的功能与 `openai_api_key` 相同（为保持兼容性，`openai_api_key` 仍被支持）。\n\n```lua\n\tproviders = {\n\t\topenai = {\n\t\t\tendpoint = \"https:\u002F\u002Fapi.openai.com\u002Fv1\u002Fchat\u002Fcompletions\",\n\t\t\tsecret = os.getenv(\"OPENAI_API_KEY\"),\n\t\t},\n\n\t\t-- azure = {...},\n\n\t\tcopilot = {\n\t\t\tendpoint = \"https:\u002F\u002Fapi.githubcopilot.com\u002Fchat\u002Fcompletions\",\n\t\t\tsecret = {\n\t\t\t\t\"bash\",\n\t\t\t\t\"-c\",\n\t\t\t\t\"cat ~\u002F.config\u002Fgithub-copilot\u002Fapps.json | sed -e 's\u002F.*oauth_token...\u002F\u002F;s\u002F\\\".*\u002F\u002F'\",\n\t\t\t},\n\t\t},\n\n\t\tpplx = {\n\t\t\tendpoint = \"https:\u002F\u002Fapi.perplexity.ai\u002Fchat\u002Fcompletions\",\n\t\t\tsecret = os.getenv(\"PPLX_API_KEY\"),\n\t\t},\n\n\t\tollama = {\n\t\t\tendpoint = \"http:\u002F\u002Flocalhost:11434\u002Fv1\u002Fchat\u002Fcompletions\",\n\t\t},\n\n\t\tgoogleai = {\n\t\t\tendpoint = \"https:\u002F\u002Fgenerativelanguage.googleapis.com\u002Fv1beta\u002Fmodels\u002F{{model}}:streamGenerateContent?key={{secret}}\",\n\t\t\tsecret = os.getenv(\"GOOGLEAI_API_KEY\"),\n\t\t},\n\n\t\tanthropic = {\n\t\t\tendpoint = \"https:\u002F\u002Fapi.anthropic.com\u002Fv1\u002Fmessages\",\n\t\t\tsecret = os.getenv(\"ANTHROPIC_API_KEY\"),\n\t\t},\n\t},\n```\n\n每个提供商都预配置了一些代理。以下是一个禁用预定义的 ChatGPT3-5 代理并创建自定义代理的示例。如果缺少 `provider` 字段，则出于向后兼容性考虑，默认会使用 OpenAI。\n\n```lua\n\tagents = {\n\t\t{\n\t\t\tname = \"ChatGPT3-5\",\n\t\t\tdisable = true,\n\t\t},\n\t\t{\n\t\t\tname = \"MyCustomAgent\",\n\t\t\tprovider = \"copilot\",\n\t\t\tchat = true,\n\t\t\tcommand = true,\n\t\t\tmodel = { model = \"gpt-4-turbo\" },\n\t\t\tsystem_prompt = \"Answer any query with just: Sure thing..\",\n\t\t},\n\t},\n```\n\n## 4. 依赖项\n\n核心插件仅需安装 `curl` 来调用 OpenAI API，以及 `grep` 用于 ChatFinder 功能。因此，Linux、BSD 和 Mac OS 均可支持。\n\n语音命令（`:GpWhisper*`）依赖于 `SoX`（Sound eXchange）来处理音频录制和处理：\n\n- Mac OS：`brew install sox`\n- Ubuntu\u002FDebian：`apt-get install sox libsox-fmt-mp3`\n- Arch Linux：`pacman -S sox`\n- Redhat\u002FCentOS：`yum install sox`\n- NixOS：`nix-env -i sox`\n\n## 5. 配置\n\n以下是包含默认值的代码片段链接，但我建议从尽可能简单的配置开始（如果您尚未设置 `OPENAI_API_KEY` 环境变量，则只需配置 `openai_api_key` 即可）。默认值会随时间变化以改进功能，某些选项可能会被弃用等；因此，最好只修改那些默认设置无法满足您需求的部分。\n\n\u003C!-- README_REFERENCE_MARKER_REPLACE_NEXT_LINE -->\nhttps:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fblob\u002Fb910a540f16875af77b27e49288021368cc674cf\u002Flua\u002Fgp\u002Fconfig.lua#L10-L650\n\n# 使用方法\n\n## 聊天命令\n\n#### `:GpChatNew` \u003C!-- {doc=:GpChatNew}  -->\n\n在当前窗口中打开一个新的聊天窗口。它可以是空的，也可以包含可视选区或指定范围作为上下文。此命令还支持布局指定子命令：\n\n- `:GpChatNew vsplit` 在垂直分屏窗口中打开一个新的聊天窗口。\n- `:GpChatNew split` 在水平分屏窗口中打开一个新的聊天窗口。\n- `:GpChatNew tabnew` 在新标签页中打开一个新的聊天窗口。\n- `:GpChatNew popup` 在弹出窗口中打开一个新的聊天窗口。\n\n#### `:GpChatPaste` \u003C!-- {doc=:GpChatPaste}  -->\n\n将选区或指定范围的内容粘贴到最近的聊天窗口中，从而简化将多个文件中的代码合并到单个聊天缓冲区的操作。此命令也支持布局指定子命令：\n\n- `:GpChatPaste vsplit` 将内容粘贴到垂直分屏窗口中的最新聊天中。\n- `:GpChatPaste split` 将内容粘贴到水平分屏窗口中的最新聊天中。\n- `:GpChatPaste tabnew` 将内容粘贴到新标签页中的最新聊天中。\n- `:GpChatPaste popup` 将内容粘贴到弹出窗口中的最新聊天中。\n\n#### `:GpChatToggle` \u003C!-- {doc=:GpChatToggle}  -->\n\n以可切换的弹出窗口形式打开聊天，显示上次活跃的聊天，或者以选区或指定范围作为上下文打开一个新的聊天窗口。此命令也支持布局指定子命令：\n\n- `:GpChatToggle vsplit` 在垂直分屏窗口中切换聊天。\n- `:GpChatToggle split` 在水平分屏窗口中切换聊天。\n- `:GpChatToggle tabnew` 在新标签页中切换聊天。\n- `:GpChatToggle popup` 在弹出窗口中切换聊天。\n\n#### `:GpChatFinder` \u003C!-- {doc=:GpChatFinder}  -->\n\n打开一个对话框，用于搜索聊天记录。\n\n#### `:GpChatRespond` \u003C!-- {doc=:GpChatRespond}  -->\n\n为当前聊天请求新的 GPT 回答。使用 `:GpChatRespond N` 可以仅以最近 N 条消息作为上下文请求新的 GPT 回答，即从最后一条消息开始，直到第 N 次出现的 `🗨:..` 为止（N=1 相当于在新聊天中提问）。\n\n#### `:GpChatDelete` \u003C!-- {doc=:GpChatDelete}  -->\n\n删除当前聊天。默认情况下，删除前需要确认，但您可以在配置中通过设置 `chat_confirm_delete = false` 来禁用此确认提示。\n\n## 文本\u002F代码命令\n\n#### `:GpRewrite`\u003C!-- {doc=:GpRewrite}  -->\n\n打开一个用于输入提示的对话框。在对话框中提供提示指令后，生成的回复会替换普通模式或插入模式下的当前行、可视模式下的选中行，或者指定的范围（例如，`:GpRewrite %` 会将重写应用到整个缓冲区）。\n\n`:GpRewrite {prompt}` 直接使用指定的 `{prompt}` 指令执行，跳过对话框。适用于将重复性任务映射到键盘快捷键，或通过终端或 Shell 脚本以无头模式运行 Neovim 进行自动化。\n\n#### `:GpAppend` \u003C!-- {doc=:GpAppend}  -->\n\n与 `:GpRewrite` 类似，但答案会被添加到当前行、可视选区或范围之后。\n\n#### `:GpPrepend` \u003C!-- {doc=:GpPrepend}  -->\n\n与 `:GpRewrite` 类似，但答案会被添加到当前行、可视选区或范围之前。\n\n#### `:GpEnew` \u003C!-- {doc=:GpEnew}  -->\n\n与 `:GpRewrite` 类似，但答案会被添加到当前窗口中的新缓冲区中。\n\n#### `:GpNew` \u003C!-- {doc=:GpNew}  -->\n\n与 `:GpRewrite` 类似，但答案会被添加到一个新的水平分割窗口中。\n\n#### `:GpVnew` \u003C!-- {doc=:GpVnew}  -->\n\n与 `:GpRewrite` 类似，但答案会被添加到一个新的垂直分割窗口中。\n\n#### `:GpTabnew` \u003C!-- {doc=:GpTabnew}  -->\n\n与 `:GpRewrite` 类似，但答案会被添加到一个新的标签页中。\n\n#### `:GpPopup` \u003C!-- {doc=:GpPopup}  -->\n\n与 `:GpRewrite` 类似，但答案会被添加到一个弹出窗口中。\n\n#### `:GpImplement` \u003C!-- {doc=:GpImplement}  -->\n\n示例钩子命令，用于根据可视选区或指定范围内的注释来开发代码。\n\n#### `:GpContext`\u003C!-- {doc=:GpContext}  -->\n\n为每个仓库提供自定义上下文：\n\n- 在可切换的窗口中打开给定仓库的 `.gp.md` 文件。\n- 在可视模式或范围模式下使用时，会将选区或范围追加到上下文文件中。\n- 还支持布局指定的子命令：\n\n  - `:GpContext vsplit` 在垂直分割窗口中打开 `.gp.md`。\n  - `:GpContext split` 在水平分割窗口中打开 `.gp.md`。\n  - `:GpContext tabnew` 在新标签页中打开 `.gp.md`。\n  - `:GpContext popup` 在弹出窗口中打开 `.gp.md`。\n\n- 更多详情请参阅[自定义指令](#custom-instructions)。\n\n## 语音命令\n\n#### `:GpWhisper` {lang?} \u003C!-- {doc=:GpWhisper}  -->\n\n转录内容会替换当前缓冲区中的当前行、可视选区或范围。你可以用口述的方式在聊天缓冲区中提问，而不是手动输入；也可以口述一些代码注释、笔记，甚至是你的下一部小说……\n\n对于其余的 Whisper 命令，转录内容会被用作等效非 Whisper 命令的可编辑提示——例如，`GpWhisperRewrite` 口述的指令会用于 `GpRewrite` 等命令。\n\n你可以通过设置 {lang} 参数来覆盖默认语言，该参数应为你的语言的两位字母简称（例如，“en”代表英语，“fr”代表法语等）。\n\n#### `:GpWhisperRewrite` \u003C!-- {doc=:GpWhisperRewrite}  -->\n\n与 `:GpRewrite` 类似，但提示指令对话框会使用转录后的语音指令。\n\n#### `:GpWhisperAppend` \u003C!-- {doc=:GpWhisperAppend}  -->\n\n与 `:GpAppend` 类似，但提示指令对话框会使用转录后的语音指令来在当前行、可视选区或范围之后添加内容。\n\n#### `:GpWhisperPrepend` \u003C!-- {doc=:GpWhisperPrepend}  -->\n\n与 `:GpPrepend` 类似，但提示指令对话框会使用转录后的语音指令来在当前行、选区或范围之前添加内容。\n\n#### `:GpWhisperEnew` \u003C!-- {doc=:GpWhisperEnew}  -->\n\n与 `:GpEnew` 类似，但提示指令对话框会使用转录后的语音指令来在当前窗口中打开新的缓冲区。\n\n#### `:GpWhisperNew` \u003C!-- {doc=:GpWhisperNew}  -->\n\n与 `:GpNew` 类似，但提示指令对话框会使用转录后的语音指令来在新的水平分割窗口中打开内容。\n\n#### `:GpWhisperVnew` \u003C!-- {doc=:GpWhisperVnew}  -->\n\n与 `:GpVnew` 类似，但提示指令对话框会使用转录后的语音指令来在新的垂直分割窗口中打开内容。\n\n#### `:GpWhisperTabnew` \u003C!-- {doc=:GpWhisperTabnew}  -->\n\n与 `:GpTabnew` 类似，但提示指令对话框会使用转录后的语音指令来在新标签页中打开内容。\n\n#### `:GpWhisperPopup` \u003C!-- {doc=:GpWhisperPopup}  -->\n\n与 `:GpPopup` 类似，但提示指令对话框会使用转录后的语音指令来在弹出窗口中显示内容。\n\n## 代理命令\n\n#### `:GpNextAgent` \u003C!-- {doc=:GpNextAgent}  -->\n\n根据当前缓冲区在可用代理之间循环切换：如果当前缓冲区是聊天缓冲区，则使用聊天代理；否则使用命令代理。代理设置会在磁盘上持久化，跨 Neovim 实例生效。\n\n#### `:GpAgent` \u003C!-- {doc=:GpAgent}  -->\n\n显示当前用于聊天和命令指令的代理。\n\n#### `:GpAgent XY` \u003C!-- {doc=:GpAgent-XY}  -->\n\n根据代理名称选择新的代理，选项列表基于当前缓冲区（如果当前缓冲区是聊天缓冲区，则显示聊天代理；否则显示命令代理）。代理设置会在磁盘上持久化，跨 Neovim 实例生效。\n\n#### `:GpSelectAgent` \u003C!-- {doc=:GpSelectAgent}  -->\n\n使用 `vim.ui.select` 打开选择界面，从所有可用代理中进行选择，允许你直接从列表中选择所需的代理。如果安装了 Telescope 插件，可以无缝配合使用。\n\n## 图像命令\n\n#### `:GpImage` \u003C!-- {doc=:GpImage}  -->\n\n打开一个对话框，用于输入描述所需图像的提示。生成完成后，会打开一个对话框，用于将图像保存到磁盘。\n\n#### `:GpImageAgent` \u003C!-- {doc=:GpImageAgent}  -->\n\n显示当前使用的图像代理（配置）。\n\n#### `:GpImageAgent XY` \u003C!-- {doc=:GpImageAgent-XY}  -->\n\n根据名称选择新的“图像代理”。在图像的上下文中，代理基本上是指模型、图像尺寸、质量等方面的配置。代理设置会在磁盘上持久化，跨 Neovim 实例生效。\n\n## 其他命令\n\n#### `:GpStop` \u003C!-- {doc=:GpStop}  -->\n\n停止所有当前正在运行的响应和作业。\n\n#### `:GpInspectPlugin` \u003C!-- {doc=:GpInspectPlugin}  -->\n\n在新的临时缓冲区中检查 GPT 提示插件对象。\n\n## GpDone 自动命令\n\n像 `GpRewrite`、`GpAppend` 等命令都是异步执行的，并会生成 `GpDone` 事件，因此你可以定义自动命令（比如自动格式化），在 GP 完成时运行：\n\n```lua\n    vim.api.nvim_create_autocmd({ \"User\" }, {\n        pattern = {\"GpDone\"},\n        callback = function(event)\n            print(\"event fired:\\n\", vim.inspect(event))\n            -- local b = event.buf\n            -- DO something\n        end,\n    })\n```\n\n## 自定义指令\n\n通过调用 `:GpContext`，你可以在仓库的根目录下创建一个 `.gp.md` Markdown 文件。诸如 `:GpRewrite`、`:GpAppend` 等命令会尊重该文件中提供的指令（使用 gpt4 时效果更好，而 gpt 3.5 并不总是会听从系统指令）。例如：\n\n```md\n使用 C++17。\n编写 Go 测试时使用 Testify 库。\n采用提前返回\u002F卫语句模式以避免过度嵌套。\n...\n```\n\n这里有一个[示例](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fblob\u002Fmain\u002F.gp.md)。\n\n## 脚本化\n\n结合 `GpDone` 事件和 `.gp.md` 自定义指令，你可以通过终端或 Shell 脚本以无头（neo）Vim 的方式运行 gp.nvim。因此，如果你将其放入循环中，就可以让 gp 在多个文件中执行编辑操作。\n\n`test` 文件内容如下：\n\n```\n1\n2\n3\n4\n5\n```\n\n`.gp.md` 文件内容如下：\n\n````\n如果用户说“你好”，请回复：\n\n```\n嗨，朋友！\n```\n````\n\n从终端\u002F脚本调用 gp.nvim：\n\n- 注册自动命令，在 Gp 完成时保存并退出 nvim；\n- 第二步跳转到我想要重写\u002F追加\u002F前置的内容出现的位置（本例中为数字 `3`）；\n- 选中该行；\n- 调用 gp.nvim 动作。\n\n```\n$ nvim --headless -c \"autocmd User GpDone wq\" -c \"\u002F3\" -c \"normal V\" -c \"GpAppend hello there\"  test\n```\n\n最终生成的 `test` 文件内容如下：\n\n```\n1\n2\n3\n嗨，朋友！\n4\n5\n```\n\n# 快捷键\n\n默认情况下没有全局快捷键，以便不影响你的自定义配置。以下是一些供你调整或直接使用的示例。\n\n## 原生快捷键\n\n你可以使用传统的 `vim.keymap.set`，并在 `require(\"gp\").setup(conf)` 调用之后（或者如果你想将所有快捷键集中管理，也可以放在其他位置）粘贴以下代码：\n\n```lua\nlocal function keymapOptions(desc)\n    return {\n        noremap = true,\n        silent = true,\n        nowait = true,\n        desc = \"GPT 提示 \" .. desc,\n    }\nend\n\n-- 对话命令\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>c\", \"\u003Ccmd>GpChatNew\u003Ccr>\", keymapOptions(\"新建对话\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>t\", \"\u003Ccmd>GpChatToggle\u003Ccr>\", keymapOptions(\"切换对话\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>f\", \"\u003Ccmd>GpChatFinder\u003Ccr>\", keymapOptions(\"对话查找\"))\n\nvim.keymap.set(\"v\", \"\u003CC-g>c\", \":\u003CC-u>'\u003C,'>GpChatNew\u003Ccr>\", keymapOptions(\"视觉模式新建对话\"))\nvim.keymap.set(\"v\", \"\u003CC-g>p\", \":\u003CC-u>'\u003C,'>GpChatPaste\u003Ccr>\", keymapOptions(\"视觉模式粘贴对话\"))\nvim.keymap.set(\"v\", \"\u003CC-g>t\", \":\u003CC-u>'\u003C,'>GpChatToggle\u003Ccr>\", keymapOptions(\"视觉模式切换对话\"))\n\nvim.keymap.set({ \"n\", \"i\" }, \"\u003CC-g>\u003CC-x>\", \"\u003Ccmd>GpChatNew split\u003Ccr>\", keymapOptions(\"新建分屏对话\"))\nvim.keymap.set({ \"n\", \"i\" }, \"\u003CC-g>\u003CC-v>\", \"\u003Ccmd>GpChatNew vsplit\u003Ccr>\", keymapOptions(\"新建垂直分屏对话\"))\nvim.keymap.set({ \"n\", \"i\" }, \"\u003CC-g>\u003CC-t>\", \"\u003Ccmd>GpChatNew tabnew\u003Ccr>\", keymapOptions(\"新建标签页对话\"))\n\nvim.keymap.set(\"v\", \"\u003CC-g>\u003CC-x>\", \":\u003CC-u>'\u003C,'>GpChatNew split\u003Ccr>\", keymapOptions(\"视觉模式新建分屏对话\"))\nvim.keymap.set(\"v\", \"\u003CC-g>\u003CC-v>\", \":\u003CC-u>'\u003C,'>GpChatNew vsplit\u003Ccr>\", keymapOptions(\"视觉模式新建垂直分屏对话\"))\nvim.keymap.set(\"v\", \"\u003CC-g>\u003CC-t>\", \":\u003CC-u>'\u003C,'>GpChatNew tabnew\u003Ccr>\", keymapOptions(\"视觉模式新建标签页对话\"))\n\n-- 提示命令\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>r\", \"\u003Ccmd>GpRewrite\u003Ccr>\", keymapOptions(\"内联重写\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>a\", \"\u003Ccmd>GpAppend\u003Ccr>\", keymapOptions(\"追加（后）\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>b\", \"\u003Ccmd>GpPrepend\u003Ccr>\", keymapOptions(\"前置（前）\"))\n\nvim.keymap.set(\"v\", \"\u003CC-g>r\", \":\u003CC-u>'\u003C,'>GpRewrite\u003Ccr>\", keymapOptions(\"视觉模式重写\"))\nvim.keymap.set(\"v\", \"\u003CC-g>a\", \":\u003CC-u>'\u003C,'>GpAppend\u003Ccr>\", keymapOptions(\"视觉模式追加（后）\"))\nvim.keymap.set(\"v\", \"\u003CC-g>b\", \":\u003CC-u>'\u003C,'>GpPrepend\u003Ccr>\", keymapOptions(\"视觉模式前置（前）\"))\nvim.keymap.set(\"v\", \"\u003CC-g>i\", \":\u003CC-u>'\u003C,'>GpImplement\u003Ccr>\", keymapOptions(\"实现选区代码\"))\n\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>gp\", \"\u003Ccmd>GpPopup\u003Ccr>\", keymapOptions(\"弹出窗口\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>ge\", \"\u003Ccmd>GpEnew\u003Ccr>\", keymapOptions(\"GpEnew\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>gn\", \"\u003Ccmd>GpNew\u003Ccr>\", keymapOptions(\"GpNew\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>gv\", \"\u003Ccmd>GpVnew\u003Ccr>\", keymapOptions(\"GpVnew\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>gt\", \"\u003Ccmd>GpTabnew\u003Ccr>\", keymapOptions(\"GpTabnew\"))\n\nvim.keymap.set(\"v\", \"\u003CC-g>gp\", \":\u003CC-u>'\u003C,'>GpPopup\u003Ccr>\", keymapOptions(\"视觉模式弹出窗口\"))\nvim.keymap.set(\"v\", \"\u003CC-g>ge\", \":\u003CC-u>'\u003C,'>GpEnew\u003Ccr>\", keymapOptions(\"视觉模式 GpEnew\"))\nvim.keymap.set(\"v\", \"\u003CC-g>gn\", \":\u003CC-u>'\u003C,'>GpNew\u003Ccr>\", keymapOptions(\"视觉模式 GpNew\"))\nvim.keymap.set(\"v\", \"\u003CC-g>gv\", \":\u003CC-u>'\u003C,'>GpVnew\u003Ccr>\", keymapOptions(\"视觉模式 GpVnew\"))\nvim.keymap.set(\"v\", \"\u003CC-g>gt\", \":\u003CC-u>'\u003C,'>GpTabnew\u003Ccr>\", keymapOptions(\"视觉模式 GpTabnew\"))\n\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>x\", \"\u003Ccmd>GpContext\u003Ccr>\", keymapOptions(\"切换上下文\"))\nvim.keymap.set(\"v\", \"\u003CC-g>x\", \":\u003CC-u>'\u003C,'>GpContext\u003Ccr>\", keymapOptions(\"视觉模式切换上下文\"))\n\nvim.keymap.set({\"n\", \"i\", \"v\", \"x\"}, \"\u003CC-g>s\", \"\u003Ccmd>GpStop\u003Ccr>\", keymapOptions(\"停止\"))\nvim.keymap.set({\"n\", \"i\", \"v\", \"x\"}, \"\u003CC-g>n\", \"\u003Ccmd>GpNextAgent\u003Ccr>\", keymapOptions(\"下一个助手\"))\nvim.keymap.set({\"n\", \"i\", \"v\", \"x\"}, \"\u003CC-g>l\", \"\u003Ccmd>GpSelectAgent\u003Ccr>\", keymapOptions(\"选择助手\"))\n\n-- 可选的 Whisper 命令，带有前缀 \u003CC-g>w\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>ww\", \"\u003Ccmd>GpWhisper\u003Ccr>\", keymapOptions(\"低语\"))\nvim.keymap.set(\"v\", \"\u003CC-g>ww\", \":\u003CC-u>'\u003C,'>GpWhisper\u003Ccr>\", keymapOptions(\"视觉模式低语\"))\n\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>wr\", \"\u003Ccmd>GpWhisperRewrite\u003Ccr>\", keymapOptions(\"低语内联重写\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>wa\", \"\u003Ccmd>GpWhisperAppend\u003Ccr>\", keymapOptions(\"低语追加（后）\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>wb\", \"\u003Ccmd>GpWhisperPrepend\u003Ccr>\", keymapOptions(\"低语前置（前）\"))\n\nvim.keymap.set(\"v\", \"\u003CC-g>wr\", \":\u003CC-u>'\u003C,'>GpWhisperRewrite\u003Ccr>\", keymapOptions(\"视觉模式低语重写\"))\nvim.keymap.set(\"v\", \"\u003CC-g>wa\", \":\u003CC-u>'\u003C,'>GpWhisperAppend\u003Ccr>\", keymapOptions(\"视觉模式低语追加（后）\"))\nvim.keymap.set(\"v\", \"\u003CC-g>wb\", \":\u003CC-u>'\u003C,'>GpWhisperPrepend\u003Ccr>\", keymapOptions(\"视觉模式低语前置（前）\"))\n\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>wp\", \"\u003Ccmd>GpWhisperPopup\u003Ccr>\", keymapOptions(\"低语弹出窗口\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>we\", \"\u003Ccmd>GpWhisperEnew\u003Ccr>\", keymapOptions(\"低语 Enew\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>wn\", \"\u003Ccmd>GpWhisperNew\u003Ccr>\", keymapOptions(\"低语新\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>wv\", \"\u003Ccmd>GpWhisperVnew\u003Ccr>\", keymapOptions(\"低语 Vnew\"))\nvim.keymap.set({\"n\", \"i\"}, \"\u003CC-g>wt\", \"\u003Ccmd>GpWhisperTabnew\u003Ccr>\", keymapOptions(\"低语 Tabnew\"))。\n\nvim.keymap.set(\"v\", \"\u003CC-g>wp\", \":\u003CC-u>'\u003C,'>GpWhisperPopup\u003Ccr>\", keymapOptions(\"视觉模式低语弹出窗口\"))\nvim.keymap.set(\"v\", \"\u003CC-g>we\", \":\u003CC-u>'\u003C,'>GpWhisperEnew\u003Ccr>\", keymapOptions(\"视觉模式低语 Enew\"))\nvim.keymap.set(\"v\", \"\u003CC-g>wn\", \":\u003CC-u>'\u003C,'>GpWhisperNew\u003Ccr>\", keymapOptions(\"视觉模式低语新\"))\nvim.keymap.set(\"v\", \"\u003CC-g>wv\", \":\u003CC-u>'\u003C,'>GpWhisperVnew\u003Ccr>\", keymapOptions(\"视觉模式低语 Vnew\"))\nvim.keymap.set(\"v\", \"\u003CC-g>wt\", \":\u003CC-u>'\u003C,'>GpWhisperTabnew\u003Ccr>\", keymapOptions(\"视觉模式低语 Tabnew\"))。\n```\n\n## Whichkey\n\n或者使用 [which-key.nvim](https:\u002F\u002Fgithub.com\u002Ffolke\u002Fwhich-key.nvim) 插件来实现更炫酷的效果：\n\n```lua\nrequire(\"which-key\").add({\n    -- 可视模式映射\n    -- s、x、v 模式由 which_key 统一处理\n    {\n        mode = { \"v\" },\n        nowait = true,\n        remap = false,\n        { \"\u003CC-g>\u003CC-t>\", \":\u003CC-u>'\u003C,'>GpChatNew tabnew\u003Ccr>\", desc = \"新建聊天标签页\" },\n        { \"\u003CC-g>\u003CC-v>\", \":\u003CC-u>'\u003C,'>GpChatNew vsplit\u003Ccr>\", desc = \"新建聊天垂直分屏\" },\n        { \"\u003CC-g>\u003CC-x>\", \":\u003CC-u>'\u003C,'>GpChatNew split\u003Ccr>\", desc = \"新建聊天水平分屏\" },\n        { \"\u003CC-g>a\", \":\u003CC-u>'\u003C,'>GpAppend\u003Ccr>\", desc = \"可视模式追加（在选区后）\" },\n        { \"\u003CC-g>b\", \":\u003CC-u>'\u003C,'>GpPrepend\u003Ccr>\", desc = \"可视模式插入（在选区前）\" },\n        { \"\u003CC-g>c\", \":\u003CC-u>'\u003C,'>GpChatNew\u003Ccr>\", desc = \"可视模式新建聊天\" },\n        { \"\u003CC-g>g\", group = \"生成到新 ..\" },\n        { \"\u003CC-g>ge\", \":\u003CC-u>'\u003C,'>GpEnew\u003Ccr>\", desc = \"可视模式 GpEnew\" },\n        { \"\u003CC-g>gn\", \":\u003CC-u>'\u003C,'>GpNew\u003Ccr>\", desc = \"可视模式 GpNew\" },\n        { \"\u003CC-g>gp\", \":\u003CC-u>'\u003C,'>GpPopup\u003Ccr>\", desc = \"可视模式弹出窗口\" },\n        { \"\u003CC-g>gt\", \":\u003CC-u>'\u003C,'>GpTabnew\u003Ccr>\", desc = \"可视模式 GpTabnew\" },\n        { \"\u003CC-g>gv\", \":\u003CC-u>'\u003C,'>GpVnew\u003Ccr>\", desc = \"可视模式 GpVnew\" },\n        { \"\u003CC-g>i\", \":\u003CC-u>'\u003C,'>GpImplement\u003Ccr>\", desc = \"实现选中文本\" },\n        { \"\u003CC-g>n\", \"\u003Ccmd>GpNextAgent\u003Ccr>\", desc = \"下一个助手\" },\n        { \"\u003CC-g>l\", \"\u003Ccmd>GpSelectAgent\u003Ccr>\", desc = \"选择助手\" },\n        { \"\u003CC-g>p\", \":\u003CC-u>'\u003C,'>GpChatPaste\u003Ccr>\", desc = \"可视模式粘贴到聊天\" },\n        { \"\u003CC-g>r\", \":\u003CC-u>'\u003C,'>GpRewrite\u003Ccr>\", desc = \"可视模式重写\" },\n        { \"\u003CC-g>s\", \"\u003Ccmd>GpStop\u003Ccr>\", desc = \"停止助手\" },\n        { \"\u003CC-g>t\", \":\u003CC-u>'\u003C,'>GpChatToggle\u003Ccr>\", desc = \"切换聊天模式\" },\n        { \"\u003CC-g>w\", group = \"Whisper\" },\n        { \"\u003CC-g>wa\", \":\u003CC-u>'\u003C,'>GpWhisperAppend\u003Ccr>\", desc = \"Whisper 追加文本\" },\n        { \"\u003CC-g>wb\", \":\u003CC-u>'\u003C,'>GpWhisperPrepend\u003Ccr>\", desc = \"Whisper 插入文本\" },\n        { \"\u003CC-g>we\", \":\u003CC-u>'\u003C,'>GpWhisperEnew\u003Ccr>\", desc = \"Whisper 新建文件\" },\n        { \"\u003CC-g>wn\", \":\u003CC-u>'\u003C,'>GpWhisperNew\u003Ccr>\", desc = \"Whisper 新建文件\" },\n        { \"\u003CC-g>wp\", \":\u003CC-u>'\u003C,'>GpWhisperPopup\u003Ccr>\", desc = \"Whisper 弹出窗口\" },\n        { \"\u003CC-g>wr\", \":\u003CC-u>'\u003C,'>GpWhisperRewrite\u003Ccr>\", desc = \"Whisper 内联重写\" },\n        { \"\u003CC-g>wt\", \":\u003CC-u>'\u003C,'>GpWhisperTabnew\u003Ccr>\", desc = \"Whisper 新建标签页\" },\n        { \"\u003CC-g>wv\", \":\u003CC-u>'\u003C,'>GpWhisperVnew\u003Ccr>\", desc = \"Whisper 新建垂直分屏\" },\n        { \"\u003CC-g>ww\", \":\u003CC-u>'\u003C,'>GpWhisper\u003Ccr>\", desc = \"Whisper\" },\n        { \"\u003CC-g>x\", \":\u003CC-u>'\u003C,'>GpContext\u003Ccr>\", desc = \"切换 GpContext\" },\n    },\n\n    -- 普通模式映射\n    {\n        mode = { \"n\" },\n        nowait = true,\n        remap = false,\n        { \"\u003CC-g>\u003CC-t>\", \"\u003Ccmd>GpChatNew tabnew\u003Ccr>\", desc = \"新建聊天标签页\" },\n        { \"\u003CC-g>\u003CC-v>\", \"\u003Ccmd>GpChatNew vsplit\u003Ccr>\", desc = \"新建聊天垂直分屏\" },\n        { \"\u003CC-g>\u003CC-x>\", \"\u003Ccmd>GpChatNew split\u003Ccr>\", desc = \"新建聊天水平分屏\" },\n        { \"\u003CC-g>a\", \"\u003Ccmd>GpAppend\u003Ccr>\", desc = \"追加文本（在光标后）\" },\n        { \"\u003CC-g>b\", \"\u003Ccmd>GpPrepend\u003Ccr>\", desc = \"插入文本（在光标前）\" },\n        { \"\u003CC-g>c\", \"\u003Ccmd>GpChatNew\u003Ccr>\", desc = \"新建聊天\" },\n        { \"\u003CC-g>f\", \"\u003Ccmd>GpChatFinder\u003Ccr>\", desc = \"聊天查找器\" },\n        { \"\u003CC-g>g\", group = \"生成到新 ..\" },\n        { \"\u003CC-g>ge\", \"\u003Ccmd>GpEnew\u003Ccr>\", desc = \"GpEnew\" },\n        { \"\u003CC-g>gn\", \"\u003Ccmd>GpNew\u003Ccr>\", desc = \"GpNew\" },\n        { \"\u003CC-g>gp\", \"\u003Ccmd>GpPopup\u003Ccr>\", desc = \"弹出窗口\" },\n        { \"\u003CC-g>gt\", \"\u003Ccmd>GpTabnew\u003Ccr>\", desc = \"GpTabnew\" },\n        { \"\u003CC-g>gv\", \"\u003Ccmd>GpVnew\u003Ccr>\", desc = \"GpVnew\" },\n        { \"\u003CC-g>n\", \"\u003Ccmd>GpNextAgent\u003Ccr>\", desc = \"下一个助手\" },\n        { \"\u003CC-g>l\", \"\u003Ccmd>GpSelectAgent\u003Ccr>\", desc = \"选择助手\" },\n        { \"\u003CC-g>r\", \"\u003Ccmd>GpRewrite\u003Ccr>\", desc = \"内联重写\" },\n        { \"\u003CC-g>s\", \"\u003Ccmd>GpStop\u003Ccr>\", desc = \"停止助手\" },\n        { \"\u003CC-g>t\", \"\u003Ccmd>GpChatToggle\u003Ccr>\", desc = \"切换聊天模式\" },\n        { \"\u003CC-g>w\", group = \"Whisper\" },\n        { \"\u003CC-g>wa\", \"\u003Ccmd>GpWhisperAppend\u003Ccr>\", desc = \"Whisper 追加文本（在光标后）\" },\n        { \"\u003CC-g>wb\", \"\u003Ccmd>GpWhisperPrepend\u003Ccr>\", desc = \"Whisper 插入文本（在光标前）\" },\n        { \"\u003CC-g>we\", \"\u003Ccmd>GpWhisperEnew\u003Ccr>\", desc = \"Whisper 新建文件\" },\n        { \"\u003CC-g>wn\", \"\u003Ccmd>GpWhisperNew\u003Ccr>\", desc = \"Whisper 新建文件\" },\n        { \"\u003CC-g>wp\", \"\u003Ccmd>GpWhisperPopup\u003Ccr>\", desc = \"Whisper 弹出窗口\" },\n        { \"\u003CC-g>wr\", \"\u003Ccmd>GpWhisperRewrite\u003Ccr>\", desc = \"Whisper 内联重写\" },\n        { \"\u003CC-g>wt\", \"\u003Ccmd>GpWhisperTabnew\u003Ccr>\", desc = \"Whisper 新建标签页\" },\n        { \"\u003CC-g>wv\", \"\u003Ccmd>GpWhisperVnew\u003Ccr>\", desc = \"Whisper 新建垂直分屏\" },\n        { \"\u003CC-g>ww\", \"\u003Ccmd>GpWhisper\u003Ccr>\", desc = \"Whisper\" },\n        { \"\u003CC-g>x\", \"\u003Ccmd>GpContext\u003Ccr>\", desc = \"切换 GpContext\" },\n    },\n\n    -- 插入模式映射\n    {\n        mode = { \"i\" },\n        nowait = true,\n        remap = false,\n        { \"\u003CC-g>\u003CC-t>\", \"\u003Ccmd>GpChatNew tabnew\u003Ccr>\", desc = \"新建聊天标签页\" },\n        { \"\u003CC-g>\u003CC-v>\", \"\u003Ccmd>GpChatNew vsplit\u003Ccr>\", desc = \"新建聊天垂直分屏\" },\n        { \"\u003CC-g>\u003CC-x>\", \"\u003Ccmd>GpChatNew split\u003Ccr>\", desc = \"新建聊天水平分屏\" },\n        { \"\u003CC-g>a\", \"\u003Ccmd>GpAppend\u003Ccr>\", desc = \"追加文本（在光标后）\" },\n        { \"\u003CC-g>b\", \"\u003Ccmd>GpPrepend\u003Ccr>\", desc = \"插入文本（在光标前）\" },\n        { \"\u003CC-g>c\", \"\u003Ccmd>GpChatNew\u003Ccr>\", desc = \"新建聊天\" },\n        { \"\u003CC-g>f\", \"\u003Ccmd>GpChatFinder\u003Ccr>\", desc = \"聊天查找器\" },\n        { \"\u003CC-g>g\", group = \"生成到新 ..\" },\n        { \"\u003CC-g>ge\", \"\u003Ccmd>GpEnew\u003Ccr>\", desc = \"GpEnew\" },\n        { \"\u003CC-g>gn\", \"\u003Ccmd>GpNew\u003Ccr>\", desc = \"GpNew\" },\n        { \"\u003CC-g>gp\", \"\u003Ccmd>GpPopup\u003Ccr>\", desc = \"弹出窗口\" },\n        { \"\u003CC-g>gt\", \"\u003Ccmd>GpTabnew\u003Ccr>\", desc = \"GpTabnew\" },\n        { \"\u003CC-g>gv\", \"\u003Ccmd>GpVnew\u003Ccr>\", desc = \"GpVnew\" },\n        { \"\u003CC-g>n\", \"\u003Ccmd>GpNextAgent\u003Ccr>\", desc = \"下一个助手\" },\n        { \"\u003CC-g>l\", \"\u003Ccmd>GpSelectAgent\u003Ccr>\", desc = \"选择助手\" },\n        { \"\u003CC-g>r\", \"\u003Ccmd>GpRewrite\u003Ccr>\", desc = \"内联重写\" },\n        { \"\u003CC-g>s\", \"\u003Ccmd>GpStop\u003Ccr>\", desc = \"停止助手\" },\n        { \"\u003CC-g>t\", \"\u003Ccmd>GpChatToggle\u003Ccr>\", desc = \"切换聊天模式\" },\n        { \"\u003CC-g>w\", group = \"Whisper\" },\n        { \"\u003CC-g>wa\", \"\u003Ccmd>GpWhisperAppend\u003Ccr>\", desc = \"Whisper 追加文本（在光标后）\" },\n        { \"\u003CC-g>wb\", \"\u003Ccmd>GpWhisperPrepend\u003Ccr>\", desc = \"Whisper 插入文本（在光标前）\" },\n        { \"\u003CC-g>we\", \"\u003Ccmd>GpWhisperEnew\u003Ccr>\", desc = \"Whisper 新建文件\" },\n        { \"\u003CC-g>wn\", \"\u003Ccmd>GpWhisperNew\u003Ccr>\", desc = \"Whisper 新建文件\" },\n        { \"\u003CC-g>wp\", \"\u003Ccmd>GpWhisperPopup\u003Ccr>\", desc = \"Whisper 弹出窗口\" },\n        { \"\u003CC-g>wr\", \"\u003Ccmd>GpWhisperRewrite\u003Ccr>\", desc = \"Whisper 内联重写\" },\n        { \"\u003CC-g>wt\", \"\u003Ccmd>GpWhisperTabnew\u003Ccr>\", desc = \"Whisper 新建标签页\" },\n        { \"\u003CC-g>wv\", \"\u003Ccmd>GpWhisperVnew\u003Ccr>\", desc = \"Whisper 新建垂直分屏\" },\n        { \"\u003CC-g>ww\", \"\u003Ccmd>GpWhisper\u003Ccr>\", desc = \"Whisper\" },\n        { \"\u003CC-g>x\", \"\u003Ccmd>GpContext\u003Ccr>\", desc = \"切换 GpContext\" },\n    },\n})\n```\n\n# 扩展功能\n\n你可以通过将函数放入 `config.hooks` 中，用自己的功能扩展或覆盖插件的功能。钩子可以访问所有内容（参见默认设置中的 `InspectPlugin` 示例），并且会自动注册为命令（如 `GpInspectPlugin`）。\n\n以下是一些更多示例：\n\n- `:GpUnitTests`\n\n  ````lua\n  -- 添加一个为选中文本编写单元测试的命令示例\n  UnitTests = function(gp, params)\n      local template = \"我有来自 {{filename}} 的以下代码：\\n\\n\"\n          .. \"```{{filetype}}\\n{{selection}}\\n```\\n\\n\"\n          .. \"请回复，为上述代码编写基于表格驱动的单元测试。\"\n      local agent = gp.get_command_agent()\n      gp.Prompt(params, gp.Target.vnew, agent, template)\n  end,\n  ````\n\n- `:GpExplain`\n\n  ````lua\n  -- 添加一个解释选中文本的命令示例\n  Explain = function(gp, params)\n      local template = \"我有来自 {{filename}} 的以下代码：\\n\\n\"\n          .. \"```{{filetype}}\\n{{selection}}\\n```\\n\\n\"\n          .. \"请回复，解释上述代码。\"\n      local agent = gp.get_chat_agent()\n      gp.Prompt(params, gp.Target.popup, agent, template)\n  end,\n  ````\n\n- `:GpCodeReview`\n\n  ````lua\n  -- 使用 enew 作为指定新缓冲区类型的函数示例\n  CodeReview = function(gp, params)\n      local template = \"我有来自 {{filename}} 的以下代码：\\n\\n\"\n          .. \"```{{filetype}}\\n{{selection}}\\n```\\n\\n\"\n          .. \"请分析其中的代码异味并提出改进建议。\"\n      local agent = gp.get_chat_agent()\n      gp.Prompt(params, gp.Target.enew(\"markdown\"), agent, template)\n  end,\n  ````\n\n- `:GpTranslator`\n\n  ```lua\n  -- 添加一个专门用于翻译的新聊天窗口的命令示例\n  Translator = function(gp, params)\n      local chat_system_prompt = \"你是一名翻译员，请在英语和中文之间进行翻译。\"\n      gp.cmd.ChatNew(params, chat_system_prompt)\n\n      -- 也可以这样创建一个使用特定固定代理的聊天：\n      -- local agent = gp.get_chat_agent(\"ChatGPT4o\")\n      -- gp.cmd.ChatNew(params, chat_system_prompt, agent)\n  end,\n  ```\n\n- `:GpBufferChatNew`\n\n  ```lua\n  -- 将 :%GpChatNew 制作成一个专用命令，该命令会以当前整个缓冲区作为上下文打开一个新的聊天窗口\n  BufferChatNew = function(gp, _)\n      -- 在全缓冲区范围内调用 GpChatNew 命令\n      vim.api.nvim_command(\"%\" .. gp.config.cmd_prefix .. \"ChatNew\")\n  end,\n  ```\n\n原始插件文本编辑方法 `Prompt` 的签名如下：\n```lua\n---@param params table  # vim 命令参数，例如范围、参数等。\n---@param target integer | function | table  # 回应将被放置的位置\n---@param agent table  # 从 get_command_agent 或 get_chat_agent 获取\n---@param template string  # 包含模型指令的模板\n---@param prompt string | nil  # 对于非交互式命令，值为 nil\n---@param whisper string | nil  # 预定义输入（例如从 Whisper 获取）\n---@param callback function | nil  # 完成提示后执行的回调函数 (response)\nPrompt(params, target, agent, template, prompt, whisper, callback)\n```\n\n- `params` 是一个 [传递给 Neovim 用户命令的表](https:\u002F\u002Fneovim.io\u002Fdoc\u002Fuser\u002Flua-guide.html#lua-guide-commands-create)，`Prompt` 目前使用：\n\n  - `range, line1, line2` 来处理 [范围](https:\u002F\u002Fneovim.io\u002Fdoc\u002Fuser\u002Fusr_10.html#10.3)\n  - `args` 以便可以在命令后直接传递指令（`:GpRewrite something something`）\n\n  ```lua\n  params = {\n        args = \"\",\n        bang = false,\n        count = -1,\n        fargs = {},\n        line1 = 1352,\n        line2 = 1352,\n        mods = \"\",\n        name = \"GpChatNew\",\n        range = 0,\n        reg = \"\",\n        smods = {\n              browse = false,\n              confirm = false,\n              emsg_silent = false,\n              hide = false,\n              horizontal = false,\n              keepalt = false,\n              keepjumps = false,\n              keepmarks = false,\n              keeppatterns = false,\n              lockmarks = false,\n              noautocmd = false,\n              noswapfile = false,\n              sandbox = false,\n              silent = false,\n              split = \"\",\n              tab = -1,\n              unsilent = false,\n              verbose = -1,\n              vertical = false\n        }\n  }\n  ```\n\n- `target` 指定 GPT 响应的输出位置\n\n  - 可以使用 enew\u002Fnew\u002Fvnew\u002Ftabnew 作为函数，并传入新缓冲区的文件类型（`enew\u002Fenew()\u002Fenew(\"markdown\")\u002F..`）\n\n  ```lua\n  M.Target = {\n      rewrite = 0, -- 用于替换选区、范围或当前行\n      append = 1, -- 用于在选区、范围或当前行之后追加\n      prepend = 2, -- 用于在选区、范围或当前行之前插入\n      popup = 3, -- 用于写入弹出窗口\n\n      -- 用于写入新缓冲区\n      ---@param filetype nil | string # nil = 与原缓冲区相同\n      ---@return table # 一个 type=4 且 filetype=filetype 的表\n      enew = function(filetype)\n          return { type = 4, filetype = filetype }\n      end,\n\n      --- 用于创建新的水平分割\n      ---@param filetype nil | string # nil = 与原缓冲区相同\n      ---@return table # 一个 type=5 且 filetype=filetype 的表\n      new = function(filetype)\n          return { type = 5, filetype = filetype }\n      end,\n\n      --- 用于创建新的垂直分割\n      ---@param filetype nil | string # nil = 与原缓冲区相同\n      ---@return table # 一个 type=6 且 filetype=filetype 的表\n      vnew = function(filetype)\n          return { type = 6, filetype = filetype }\n      end,\n\n      --- 用于创建新标签页\n      ---@param filetype nil | string # nil = 与原缓冲区相同\n      ---@return table # 一个 type=7 且 filetype=filetype 的表\n      tabnew = function(filetype)\n          return { type = 7, filetype = filetype }\n      end,\n  }\n  ```\n\n\n- `agent` 表可以通过 `get_command_agent` 和 `get_chat_agent` 方法获取，其签名如下：\n  ```lua\n  ---@param name string | nil\n  ---@return table # { cmd_prefix, name, model, system_prompt, provider }\n  get_command_agent(name)\n  ```\n\n- `template`\n\n  - 发送给 GPT 的用户消息模板\n  - 字符串中可以包含以下变量：\n\n    | 名称            | 描述                       |\n    | --------------- | --------------------------------- |\n    | `{{filetype}}`  | 当前缓冲区的文件类型    |\n    | `{{selection}}` | 最后一次或当前选中的文本   |\n    | `{{command}}`   | 用户提供的指令             |\n\n- `prompt`\n  - 一个字符串，用法类似于终端中的 bash\u002Fzsh 提示符，当插件需要用户输入命令传递给 GPT 时使用。\n  - 如果为 `nil`，则不会提示用户输入（适用于一些预定义的特定命令，如文档说明、解释、编写测试等）。\n  - 可以使用简单的 `🤖 ~`，也可以采用不同的提示信息来传达当前调用的方法类型，例如 `🤖 rewrite ~`、`🤖 popup ~`、`🤖 enew ~`、`🤖 inline ~` 等。\n- `whisper`\n  - 可选的字符串，默认作为输入提示（例如由 Whisper 模型从语音中生成的内容）。\n- `callback`\n  - 可选的回调函数，用于对提示响应进行后处理逻辑。\n    （例如让模型生成提交信息，然后通过回调函数实际执行提交操作。）","# gp.nvim 快速上手指南\n\ngp.nvim 是一个强大的 Neovim AI 插件，支持类似 ChatGPT 的对话会话、可指令化的文本\u002F代码操作、语音转文字以及图像生成功能。它旨在以简单、无侵入且可扩展的方式将 GPT 模型的能力集成到编辑器中。\n\n## 环境准备\n\n### 系统要求\n- **Neovim**: 建议最新版本\n- **操作系统**: Linux, macOS, BSD (Windows 需通过 WSL 或类似环境)\n\n### 前置依赖\n核心功能仅需以下工具（通常系统已预装）：\n- `curl`: 用于调用 API\n- `grep`: 用于聊天历史搜索\n\n**可选依赖**（如需使用语音命令 `:GpWhisper*`）：\n需要安装 `SoX` (Sound eXchange) 来处理录音：\n- **macOS**: `brew install sox`\n- **Ubuntu\u002FDebian**: `apt-get install sox libsox-fmt-mp3`\n- **Arch Linux**: `pacman -S sox`\n- **CentOS\u002FRHEL**: `yum install sox`\n\n## 安装步骤\n\n### 1. 获取 API Key\n在使用前，请确保你拥有有效的 API Key。\n- **OpenAI**: [点击获取](https:\u002F\u002Fplatform.openai.com\u002Faccount\u002Fapi-keys)\n- **其他提供商**: 如 Ollama (本地), GitHub Copilot, Perplexity, Anthropic, Google Gemini 等也受支持。\n\n> **安全提示**: 建议将 Key 设置为环境变量 `OPENAI_API_KEY`，或使用密码管理器读取，避免硬编码在配置文件中。\n\n### 2. 插件安装\n使用你喜欢的包管理器安装。以下是 `lazy.nvim` 的配置示例：\n\n```lua\n{\n    \"robitx\u002Fgp.nvim\",\n    config = function()\n        local conf = {\n            -- 如果未设置环境变量 OPENAI_API_KEY，可在此处手动指定\n            -- openai_api_key = \"sk-...\", \n            -- 或者配置其他提供商 (Ollama, Copilot 等)\n        }\n        require(\"gp\").setup(conf)\n\n        -- 在此处设置快捷键 (参考下文基本使用)\n    end,\n}\n```\n\n如果你使用 **Ollama** 等本地模型，需在配置中添加 provider 信息：\n```lua\nproviders = {\n    ollama = {\n        endpoint = \"http:\u002F\u002Flocalhost:11434\u002Fv1\u002Fchat\u002Fcompletions\",\n        -- 本地模型通常不需要 secret\n    },\n},\nagents = {\n    {\n        name = \"LocalLlama\",\n        provider = \"ollama\",\n        chat = true,\n        command = true,\n        model = { model = \"llama3\" }, -- 确保本地已拉取该模型\n    },\n},\n```\n\n## 基本使用\n\n安装完成后，重启 Neovim 即可使用。以下是核心功能的最简用法：\n\n### 1. 开启对话聊天\n在命令行模式下输入以下命令开启一个新的聊天窗口：\n\n```vim\n:GpChatNew\n```\n*支持子命令指定布局*: `:GpChatNew vsplit` (垂直分割), `:GpChatNew popup` (弹窗) 等。\n\n在打开的缓冲区中直接输入你的问题（支持 Markdown 格式），发送后 AI 将流式输出回答。\n\n### 2. 代码指令操作\n选中一段代码（可视模式），然后运行指令让 AI 处理（例如解释代码、重构、写单元测试）：\n\n```vim\n:'\u003C,'>GpRewrite Explain this code in Chinese\n```\n或者使用预设的命令（需在配置中绑定快捷键或自定义 hook）：\n```vim\n:'\u003C,'>GpAppend Write unit tests for this selection\n```\n*常用操作目标*:\n- `GpRewrite`: 重写选中内容\n- `GpAppend`: 追加到选中内容后\n- `GpPrepend`: 插入到选中内容前\n- `GpNew`: 在新缓冲区生成结果\n\n### 3. 快捷管理\n- **切换最近聊天**: `:GpChatToggle` (快速弹出\u002F隐藏最近的聊天窗口)\n- **查找历史会话**: `:GpChatFinder` (搜索、预览或删除过往聊天)\n- **重新生成回答**: `:GpChatRespond` (基于当前上下文重新请求回答)\n\n### 4. 语音输入 (需安装 SoX)\n按住快捷键（需自行配置映射）或运行命令开始录音，说完后自动转为文字输入到聊天框：\n```vim\n:GpWhisper\n```\n\n---\n*提示：更多高级功能（如自定义 Hook、多仓库指令文件 `.gp.md`）请参考完整文档配置章节。*","资深后端工程师正在使用 Neovim 重构一个遗留的 Python 微服务模块，需要快速为复杂逻辑补充单元测试并优化代码注释。\n\n### 没有 gp.nvim 时\n- **上下文切换频繁**：必须复制代码片段切换到浏览器打开 ChatGPT 网页，粘贴后再将生成的代码拷回编辑器，打断心流。\n- **等待过程焦虑**：生成响应时只能盯着网页上的加载动画，无法在编辑器内继续其他操作，且一旦生成中途想取消非常麻烦。\n- **操作繁琐易错**：针对重复性任务（如“为选中函数写测试”），每次都要手动输入冗长的提示词，难以统一团队代码规范。\n- **记录难以管理**：历史对话散落在浏览器标签页中，缺乏类似代码文件的管理机制，难以回溯之前的调试思路。\n\n### 使用 gp.nvim 后\n- **无缝原生集成**：直接在 Neovim 缓冲区选中代码块，通过快捷键唤起指令，AI 生成的测试代码直接以流式输出插入新缓冲区，全程无需离开终端。\n- **高效可控交互**：响应实时逐字显示，若发现方向错误可立即中断生成，且支持标准的 `u` 键撤销操作，像编辑普通文本一样自然。\n- **自动化定制工作流**：利用项目根目录的 `.gp.md` 文件预设团队规范，一键执行“生成单元测试”钩子命令，自动产出符合内部库要求的测试代码。\n- **会话持久化管理**：所有对话自动保存为 Markdown 文件，可通过内置查找器快速检索、预览或复用历史会话，将 AI 交互纳入版本控制体系。\n\ngp.nvim 将 AI 能力深度融入 Neovim 的原生编辑流，让开发者在不打断思路的前提下，实现从“复制粘贴”到“指令即代码”的效率飞跃。","https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FRobitx_gp.nvim_514254e8.gif","Robitx","Tibor Schmidt","https:\u002F\u002Foss.gittoolsai.com\u002Favatars\u002FRobitx_2dadcaf9.png",null,"robitx@gmail.com","https:\u002F\u002Fgithub.com\u002FRobitx",[79],{"name":80,"color":81,"percentage":82},"Lua","#000080",100,1313,127,"2026-04-14T12:30:43","MIT","Linux, macOS, BSD","未说明",{"notes":90,"python":88,"dependencies":91},"该工具是 Neovim 插件，主要依赖外部 API（如 OpenAI、Ollama 等）而非本地运行大模型，因此无本地 GPU 或高内存需求。若使用本地模型（如通过 Ollama），需另行配置对应的服务环境。语音转文字功能需安装 SoX。支持多种 LLM 提供商（OpenAI, GitHub Copilot, Perplexity, Anthropic, Google Gemini, Ollama 等）。",[92,93,94,95],"Neovim","curl","grep","sox (可选，用于语音功能)",[97,35,98,52,14],"其他","音频",[100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119],"copilot","neovim","nvim","speech-to-text","whisper","vim","codeium","lua","voice","llm","ollama","claude","gpt4o","gpt-4o","sonnet","gemini","mistral","perplexity","stt","parrot","2026-03-27T02:49:30.150509","2026-04-16T01:43:20.613709",[123,128,133,138,143,148],{"id":124,"question_zh":125,"answer_zh":126,"source_url":127},34891,"如何处理超过 8K token 的长文件导致响应为空的问题？","可以使用递归定义导入文件的功能来解决。你可以创建一个文件，其中包含针对常用参考文件的导入命令。这样，当你提问时，只需引用这个模板文件，它会自动包含所有内容，从而充分利用 128K 或更大的上下文窗口，避免直接粘贴超长文本导致的长度限制错误。","https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F192",{"id":129,"question_zh":130,"answer_zh":131,"source_url":132},34892,"运行 GpChatRespond 时提示“文件看起来不像聊天文件”怎么办？","这通常与符号链接（symlinks）的处理有关。请确保将插件升级到最新版本（至少 v2.4.9），该版本已修复了对符号链接的正确处理逻辑。升级后重新尝试即可解决。","https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F104",{"id":134,"question_zh":135,"answer_zh":136,"source_url":137},34893,"配置正确且无报错，但模型响应序列发生后输出为空（No output）是什么原因？","这可能是因为底层 API 返回了错误但插件未将其传播显示。维护者已确认需要改进错误传播机制。遇到此问题时，建议检查网络日志或尝试在其他类似插件中验证 API Key 是否有效。如果确认是插件问题，请关注后续版本更新以获取更明确的错误提示。","https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F31",{"id":139,"question_zh":140,"answer_zh":141,"source_url":142},34894,"使用 GpImplement 或其他命令时，为什么生成的代码完全不符合指令或与所选范围无关？","这通常是因为用户在按下冒号 `:` 进入命令模式后，手动删除了 Vim 自动生成的可视范围标记（如 `'\u003C,'>`）。这些标记对于告诉插件操作哪部分代码至关重要。请务必保留这些符号，不要将其视为垃圾字符删除。","https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F194",{"id":144,"question_zh":145,"answer_zh":146,"source_url":147},34895,"自定义 Explain Hook 运行时提示“未接收到选中文本”，只收到了文件路径，如何解决？","这通常是因为 Hook 函数中参数传递或模板变量使用不当。确保在 `gp.Prompt` 调用中正确使用了 `{{selection}}` 占位符，并且该 Hook 是在可视模式下触发的。检查配置中 `params` 是否正确传递了选区信息，参考官方文档确保模板字符串拼接无误。","https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F141",{"id":149,"question_zh":150,"answer_zh":151,"source_url":152},34896,"如何配置以支持本地离线模型（如 Ollama）或 OpenAI 兼容的其他替代方案？","可以通过在 Agent 级别暴露 `open_ai_url` 配置项来支持 OpenAI 兼容的替代方案（默认指向 OpenAI API）。对于本地模型（如 Ollama），通常需要通过 Docker 提供可调用的 API，并在插件配置中将 endpoint 指向本地服务地址。这样可以实现按 Agent 混合使用不同的解决方案。","https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F56",[154,159,164,169,174,179,184,189,194,199,204,209,214],{"id":155,"version":156,"summary_zh":157,"released_at":158},272224,"v3.9.0","## [3.9.0](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcompare\u002Fv3.8.0...v3.9.0) (2024-08-12)\n\n\n### 功能\n\n* 支持无选区执行命令（问题：[#194](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F194)）([03f34e6](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F03f34e6db6ed47b4ed1f75d30c1f8de056bbc366))\n\n\n### 错误修复\n\n* 避免在 Windows 上遇到命令长度限制（问题：[#192](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F192)）([a2df34c](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002Fa2df34cd3879e33333757ee6674fc5d41440ccd0))","2024-08-12T08:54:01",{"id":160,"version":161,"summary_zh":162,"released_at":163},272225,"v3.8.0","## [3.8.0](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcompare\u002Fv3.7.1...v3.8.0) (2024-08-05)\n\n\n### 功能\n\n* 支持 Ollama 和 Perplexity，使用 llama3.1-8B 模型 ([8b448c0](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F8b448c06651ebfc6b810bf37029d0a1ee43c237e))\n\n\n### 错误修复\n\n* 修复 Windows 系统下 Git 根目录搜索时出现的无限循环问题（问题：[#126](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F126)）([7eb91da](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F7eb91daa43d5c6b318be699e2af770904625a4d6))","2024-08-05T23:45:21",{"id":165,"version":166,"summary_zh":167,"released_at":168},272226,"v3.7.1","## [3.7.1](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcompare\u002Fv3.7.0...v3.7.1) (2024-08-05)\n\n\n### 错误修复\n\n* 在修剪反引号时检查是否发生下溢（问题：[#152](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F152)）([3510217](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F3510217650e2c3fffb3fc71fd4f5233504851d02))\n* 不覆盖已添加的密钥（问题：[#188](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F188)）([757c78f](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F757c78fb4cb17b3ec16108704a19c7b7a41ab10b))","2024-08-05T04:32:25",{"id":170,"version":171,"summary_zh":172,"released_at":173},272227,"v3.7.0","## [3.7.0](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcompare\u002Fv3.6.2...v3.7.0)（2024-08-04）\n\n### 功能\n\n* 记住上次聊天，无需使用符号链接（[#176](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F176)）（[df9adc2](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002Fdf9adc22450c052c9228714cde9b9cf90d6ca3e5)）\n* 支持 Copilot 与 GPT-4-O 集成（[c782f9a](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002Fc782f9ace9c95f42c3e169df8366537d8980a62f)）\n* 改进状态日志记录（[63098a5](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F63098a530a0fd5ba6dae5d7fb45236d9290ac8c2)）\n* 懒加载密钥（问题：[#152](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F152)）（[4cea5ae](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F4cea5aecd1bc4ce0081d2407710ba4741f193b6e)）\n* 可配置默认代理（[#85](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F85)、[#148](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F148)）（[49d1986](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F49d1986aa98ef748397594aa26e137dbc9cb2798)）\n\n### 错误修复\n\n* 如果缓冲区已准备就绪，则跳过 BufEnter 逻辑（问题：[#139](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F139)）（[2c3d818](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F2c3d818a47a9b156af921c9b768c7a31dcccf00f)）","2024-08-04T01:01:41",{"id":175,"version":176,"summary_zh":177,"released_at":178},272228,"v3.6.1","## [3.6.1](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcompare\u002Fv3.6.0...v3.6.1) (2024-08-01)\n\n\n### Bug修复\n\n* 移除代码残留 ([4c2f1d4](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F4c2f1d42083905e41fe68f0fe8bc6f1b920b45e5))","2024-08-01T22:15:06",{"id":180,"version":181,"summary_zh":182,"released_at":183},272229,"v3.6.0","## [3.6.0](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcompare\u002Fv3.5.1...v3.6.0) (2024-08-01)\n\n\n### 功能\n\n* 可配置的 zindex，默认值为 49（解决：[#132](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F132)）([6dca8ea](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F6dca8ead9ffcfdb97d09a97369613ddd30170605))\n\n\n### 错误修复\n\n* 默认命令的代理刷新（[d5fcd00](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002Fd5fcd00b06d2dab95481f15c79eb1455ff3a4da7)）\n* Win32 系统检测（[6d0f1b5](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F6d0f1b5f23c3353b89d8ebadb397a5652e29cead)）","2024-08-01T18:26:10",{"id":185,"version":186,"summary_zh":187,"released_at":188},272230,"v3.5.1","## [3.5.1](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcompare\u002Fv3.5.0...v3.5.1) (2024-07-31)\n\n\n### 错误修复\n\n* 在 Windows 上无管理员权限时处理符号链接 ([#177](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F177)) ([0f3b5bd](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F0f3b5bd090871471890502a22fda3ee1abb7c8a2))","2024-07-31T13:28:11",{"id":190,"version":191,"summary_zh":192,"released_at":193},272231,"v3.5.0","## [3.5.0](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcompare\u002Fv3.4.1...v3.5.0) (2024-07-29)\n\n\n### 功能特性\n\n* 捕获 ChatRespond 前面的数字 ([#178](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F178)) ([14a37df](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F14a37dfed125782a5a337b26c06201a30d02ca6e))\n* 可配置的敏感日志记录到文件 ([7794e8a](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F7794e8adf361682ab1488bd910be4ba3828aab03))\n* 弃用 image_ 配置变量，改用嵌套在 image 表中的方式 ([dcf116a](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002Fdcf116a3390150e2d975e8e74be5fec7c35370e3))\n* **logger:** 敏感标记 ([85a5f1c](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F85a5f1cfd976a70677092165b5b1923c9acf9638))\n* 在聊天选择器中复用 chat_confirm_delete 快捷键 ([919fdd4](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F919fdd49fa42a9c2bef3ce85f1532d891c71b953))\n* 截断日志文件和 GpInspectLog ([bf38d16](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002Fbf38d16e7151db86287ca54b167b8afd990a632a))\n* 弃用 whisper_ 配置变量，改用嵌套在 whisper 表中的方式 ([3eb215](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F3eb2152bb0741e943f374264807a62273fa4c8cb))\n\n\n### 错误修复\n\n* 移除已过时的 API 密钥验证 ([352b0c3](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F352b0c363bfb1574528743f5771dbd1efbba0046))","2024-07-29T12:00:14",{"id":195,"version":196,"summary_zh":197,"released_at":198},272232,"v3.4.1","## [3.4.1](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcompare\u002Fv3.4.0...v3.4.1) (2024-07-26)\n\n\n### 错误修复\n\n* 处理 ChatDelete 的符号链接问题 ([#171](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F171)) ([129c2f8](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F129c2f8a1b068b93763c1a5ef950966d1c10ec37))","2024-07-26T08:06:41",{"id":200,"version":201,"summary_zh":202,"released_at":203},272233,"v3.4.0","## [3.4.0](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcompare\u002Fv3.3.0...v3.4.0) (2024-07-24)\n\n\n### 功能\n\n* 默认使用与 OpenAI 兼容的请求头 ([#168](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F168)) ([7b84846](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F7b8484667b6ddd16189b156f72c1af0ff8e35131))","2024-07-24T19:56:20",{"id":205,"version":206,"summary_zh":207,"released_at":208},272234,"v3.3.0","## [3.3.0](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcompare\u002Fv3.2.0...v3.3.0) (2024-07-23)\n\n\n### Features\n\n* add logging to file ([#166](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F166)) ([33812a6](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F33812a62d6e3a34a10d24c696106337a5e2ef4b3))","2024-07-23T22:02:13",{"id":210,"version":211,"summary_zh":212,"released_at":213},272235,"v3.2.0","## [3.2.0](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcompare\u002Fv3.1.0...v3.2.0) (2024-07-23)\n\n\n### Features\n\n* replace gpt3.5 agents with gpt-4o-mini ([a062dbe](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002Fa062dbea91340fc6423fd06b6c3f84f252ba8f38))","2024-07-23T01:44:48",{"id":215,"version":216,"summary_zh":217,"released_at":218},272236,"v3.1.0","## [3.1.0](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcompare\u002Fv3.0.1...v3.1.0) (2024-07-23)\n\n\n### Features\n\n* add claude 3.5 sonnet among default agents ([3409487](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F34094879c4ea9f654245cb70dc011c57151f4a94))\n* chat templates with {{tag}} syntax ([5b5f944](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F5b5f94460ee163763d45a5f1dbad97cb2f2dd775))\n* configurable whisper endpoint ([12cedc7](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F12cedc70b4fdf190034f9294e2839b684d078f84))\n* expose default_(chat|code)_system_prompt to user ([56740e0](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F56740e089ac0117e7a61e3c03e979c1bfbe1a498))\n* improve gp.cmd.ChatNew signature ([f3664de](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002Ff3664deee8fc99013c28523d1069f19d5f3ea854))\n* keep git repo name in template_render ([2409cd5](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F2409cd56b29df499a5907c441966b51bfbd83a05))\n* picking specific agent via get_chat_agent\u002Fget_command_agent(name) ([e1acbca](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002Fe1acbcad9c254e241a06f3d1339658cf1af836c1))\n* simplify Prompt function signature ([272eee1](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F272eee103b5d426b2fd203db0c8082536c50d136))\n\n\n### Bug Fixes\n\n* sys_prompt render for Prompt commands (resolve: [#162](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fissues\u002F162)) ([6172e15](https:\u002F\u002Fgithub.com\u002FRobitx\u002Fgp.nvim\u002Fcommit\u002F6172e15d859baf842e4ba4dbfb57f06e6b9878d8))","2024-07-23T00:13:43"]