diff --git a/.all-contributorsrc b/.all-contributorsrc index 0a5effab..034e0948 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -46,6 +46,20 @@ "avatar_url": "https://avatars.githubusercontent.com/u/9963717?v=4", "profile": "https://www.linkedin.com/in/guruprakashrajakkannu/", "contributions": ["code"] + }, + { + "login": "kristofka", + "name": "kristofka", + "avatar_url": "https://avatars.githubusercontent.com/u/140354?v=4", + "profile": "https://github.com/kristofka", + "contributions": ["code"] + }, + { + "login": "PostCyberPunk", + "name": "PostCyberPunk", + "avatar_url": "https://avatars.githubusercontent.com/u/134976996?v=4", + "profile": "https://github.com/PostCyberPunk", + "contributions": ["doc"] } ], "contributorsPerLine": 7, diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..ce9dcccd --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +github: [acheong08, jellydn] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8123c9e1..1b355bf7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,10 +16,15 @@ jobs: docs: runs-on: ubuntu-latest + permissions: + # Give the default GITHUB_TOKEN write permission to commit and push the changed files back to the repository. + contents: write name: pandoc to vimdoc if: ${{ github.ref == 'refs/heads/main' }} steps: - uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} - name: panvimdoc uses: kdheepak/panvimdoc@main with: @@ -31,6 +36,7 @@ jobs: commit_user_name: "github-actions[bot]" commit_user_email: "github-actions[bot]@users.noreply.github.com" commit_author: "github-actions[bot] " + commit_options: "--no-verify" test: name: Run Test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9860c202..a0cc66fc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,7 +1,16 @@ name: Release on: push: + branches: + - release pull_request: + branches: + - main + - release + +permissions: + contents: write + pull-requests: write jobs: release: @@ -13,6 +22,7 @@ jobs: with: release-type: simple package-name: CopilotChat.nvim + token: ${{ secrets.GITHUB_TOKEN }} - uses: actions/checkout@v3 - name: tag stable versions if: ${{ steps.release.outputs.release_created }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d0ab5b9..8fb88ce0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,38 +1,40 @@ # Changelog -## 1.0.0 (2024-02-03) - - -### ⚠ BREAKING CHANGES - -* drop new buffer mode - -### Features - -* add a note for help user to continue the chat ([8a80ee7](https://github.com/jellydn/CopilotChat.nvim/commit/8a80ee7d3f9d0dcb65b315255d629c2cd8263dac)) -* add CCExplain command ([640f361](https://github.com/jellydn/CopilotChat.nvim/commit/640f361a54be51e7c479257c374d4a26d8fcd31d)) -* add CCTests command ([b34a78f](https://github.com/jellydn/CopilotChat.nvim/commit/b34a78f05ebe65ca093e4dc4b66de9120a681f4c)) -* add configuration options for wrap and filetype ([b4c6e76](https://github.com/jellydn/CopilotChat.nvim/commit/b4c6e760232ec54d4632edef3869e1a05ec61751)) -* add CopilotChatToggleLayout ([07988b9](https://github.com/jellydn/CopilotChat.nvim/commit/07988b95a412756169016e991dabcf190a930c7e)) -* add debug flag ([d0dbd4c](https://github.com/jellydn/CopilotChat.nvim/commit/d0dbd4c6fb9be75ccaa591b050198d40c097f423)) -* add health check ([974f14f](https://github.com/jellydn/CopilotChat.nvim/commit/974f14f0d0978d858cbe0126568f30fd63262cb6)) -* add new keymap to get previous user prompt ([6e7e80f](https://github.com/jellydn/CopilotChat.nvim/commit/6e7e80f118c589a009fa1703a284ad292260e3a0)) -* set filetype to markdown and text wrapping ([9b19d51](https://github.com/jellydn/CopilotChat.nvim/commit/9b19d51deacdf5c958933e99a2e75ebe4c968a9b)) -* show chat in markdown format ([9c14152](https://github.com/jellydn/CopilotChat.nvim/commit/9c141523de12e723b1d72d95760f2daddcecd1d9)) +## [1.0.1](https://github.com/CopilotC-Nvim/CopilotChat.nvim/compare/v1.0.0...v1.0.1) (2024-02-08) ### Bug Fixes -* **ci:** generate doc ([6287fd4](https://github.com/jellydn/CopilotChat.nvim/commit/6287fd452d83d43a739d4c7c7a5524537032fc5d)) -* Close spinner if the buffer does not exist ([#11](https://github.com/jellydn/CopilotChat.nvim/issues/11)) ([0ea238d](https://github.com/jellydn/CopilotChat.nvim/commit/0ea238d7be9c7872dd9932a56d3521531b2297db)) -* remove LiteralString, use Any for fixing issue on Python 3.10 ([b68c352](https://github.com/jellydn/CopilotChat.nvim/commit/b68c3522d03c8ac9a332169c56e725b69a43b07c)), closes [#45](https://github.com/jellydn/CopilotChat.nvim/issues/45) +* multi-byte languages by manually tracking last_line_col for buf_set_text ([20a4234](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/20a4234a542deef1a128aca4d0dd7e8d429a1f2a)) +## 1.0.0 (2024-02-06) -### Reverts +### ⚠ BREAKING CHANGES -* change back to CopilotChat command ([e304f79](https://github.com/jellydn/CopilotChat.nvim/commit/e304f792a5fbba412c2a5a1f717ec7e2ab12e5b0)) +- disable extra info as default +- drop new buffer mode +### Features -### Code Refactoring +- add a note for help user to continue the chat ([8a80ee7](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/8a80ee7d3f9d0dcb65b315255d629c2cd8263dac)) +- add CCExplain command ([640f361](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/640f361a54be51e7c479257c374d4a26d8fcd31d)) +- add CCTests command ([b34a78f](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/b34a78f05ebe65ca093e4dc4b66de9120a681f4c)) +- add configuration options for wrap and filetype ([b4c6e76](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/b4c6e760232ec54d4632edef3869e1a05ec61751)) +- add CopilotChatDebugInfo command ([#51](https://github.com/CopilotC-Nvim/CopilotChat.nvim/issues/51)) ([89b6276](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/89b6276e995de2e05ea391a9d1045676737c93bd)) +- add CopilotChatToggleLayout ([07988b9](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/07988b95a412756169016e991dabcf190a930c7e)) +- add debug flag ([d0dbd4c](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/d0dbd4c6fb9be75ccaa591b050198d40c097f423)) +- add health check ([974f14f](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/974f14f0d0978d858cbe0126568f30fd63262cb6)) +- add new keymap to get previous user prompt ([6e7e80f](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/6e7e80f118c589a009fa1703a284ad292260e3a0)) +- set filetype to markdown and text wrapping ([9b19d51](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/9b19d51deacdf5c958933e99a2e75ebe4c968a9b)) +- show chat in markdown format ([9c14152](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/9c141523de12e723b1d72d95760f2daddcecd1d9)) +- show date time and additional information on end separator ([#53](https://github.com/CopilotC-Nvim/CopilotChat.nvim/issues/53)) ([b8d0a9d](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/b8d0a9d0e0824ff3b643a2652202be2a51b37dbc)) + +### Bug Fixes -* drop new buffer mode ([0a30b7c](https://github.com/jellydn/CopilotChat.nvim/commit/0a30b7cfbd8b52bf8a9e4cd96dcade4995e6eb3a)) +- **ci:** generate doc ([6287fd4](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/6287fd452d83d43a739d4c7c7a5524537032fc5d)) +- **ci:** generate vimdoc on main branch ([94fb10c](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/94fb10cb65bc32cc0c1d96c93ec2d94c4f5d40eb)) +- **ci:** setup release action ([2f1e046](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/2f1e0466af30c26fdcd2b94d331ea4004d32bb07)) +- **ci:** skip git hook on vimdoc ([94fb10c](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/94fb10cb65bc32cc0c1d96c93ec2d94c4f5d40eb)) +- Close spinner if the buffer does not exist ([#11](https://github.com/CopilotC-Nvim/CopilotChat.nvim/issues/11)) ([0ea238d](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/0ea238d7be9c7872dd9932a56d3521531b2297db)) +- handle get remote plugin path on Windows ([0b917f6](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/0b917f633eaef621d293f344965e9e0545be9a80)) +- remove LiteralString, use Any for fixing issue on Python 3.10 ([b68c352](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/b68c3522d03c8ac9a332169c56e725b69a43b07c)), closes [#45](https://github.com/CopilotC-Nvim/CopilotChat.nvim/issues/45) diff --git a/README.md b/README.md index 46c6022c..8ccf84a2 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,19 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-8-orange.svg?style=flat-square)](#contributors-) > [!NOTE] > A new command, `CopilotChatInPlace` has been introduced. It functions like the ChatGPT plugin. Please run ":UpdateRemotePlugins" command and restart Neovim before starting a chat with Copilot. To stay updated on our roadmap, please join our [Discord](https://discord.gg/vy6hJsTWaZ) community. +## Prerequisites + +Ensure you have the following installed: + +- Python 3.10 or later + ## Authentication It will prompt you with instructions on your first start. If you already have `Copilot.vim` or `Copilot.lua`, it will work automatically. @@ -24,11 +30,11 @@ It will prompt you with instructions on your first start. If you already have `C ```lua return { { - "jellydn/CopilotChat.nvim", - dependencies = { "zbirenbaum/copilot.lua" }, -- Or { "github/copilot.vim" } + "CopilotC-Nvim/CopilotChat.nvim", opts = { show_help = "yes", -- Show help text for CopilotChatInPlace, default: yes debug = false, -- Enable or disable debug mode, the log file will be in ~/.local/state/nvim/CopilotChat.nvim.log + disable_extra_info = 'no', -- Disable extra information (e.g: system prompt) in the response. }, build = function() vim.notify("Please update the remote plugins by running ':UpdateRemotePlugins', then restart Neovim.") @@ -76,7 +82,7 @@ call remote#host#RegisterPlugin('python3', '/Users/huynhdung/.local/share/nvim/l 1. Put the files in the right place ``` -$ git clone https://github.com/jellydn/CopilotChat.nvim +$ git clone https://github.com/CopilotC-Nvim/CopilotChat.nvim $ cd CopilotChat.nvim $ cp -r --backup=nil rplugin ~/.config/nvim/ ``` @@ -111,7 +117,7 @@ You have the capability to expand the prompts to create more versatile commands: ```lua return { - "jellydn/CopilotChat.nvim", + "CopilotC-Nvim/CopilotChat.nvim", opts = { debug = true, show_help = "yes", @@ -174,7 +180,13 @@ For further reference, you can view @jellydn's [configuration](https://github.co [![In-place Demo](https://i.gyazo.com/4a5badaa109cd483c1fc23d296325cb0.gif)](https://gyazo.com/4a5badaa109cd483c1fc23d296325cb0) -## Receipts +## Tips + +### Debugging with `:messages` and `:CopilotChatDebugInfo` + +If you encounter any issues, you can run the command `:messages` to inspect the log. You can also run the command `:CopilotChatDebugInfo` to inspect the debug information. + +[![Debug Info](https://i.gyazo.com/bf00e700bcee1b77bcbf7b516b552521.gif)](https://gyazo.com/bf00e700bcee1b77bcbf7b516b552521) ### How to setup with `which-key.nvim` @@ -182,7 +194,7 @@ A special thanks to @ecosse3 for the configuration of [which-key](https://github ```lua { - "jellydn/CopilotChat.nvim", + "CopilotC-Nvim/CopilotChat.nvim", event = "VeryLazy", opts = { prompts = { @@ -243,6 +255,36 @@ Follow the example below to create a simple input for CopilotChat. }, ``` +### Add same keybinds in both visual and normal mode + +```lua + { + "CopilotC-Nvim/CopilotChat.nvim", + keys = + function() + local keybinds={ + --add your custom keybinds here + } + -- change prompt and keybinds as per your need + local my_prompts = { + {prompt = "In Neovim.",desc = "Neovim",key = "n"}, + {prompt = "Help with this",desc = "Help",key = "h"}, + {prompt = "Simplify and imporve readablilty",desc = "Simplify",key = "s"}, + {prompt = "Optimize the code to improve perfomance and readablilty.",desc = "Optimize",key = "o"}, + {prompt = "Find possible errors and fix them for me",desc = "Fix",key = "f"}, + {prompt = "Explain in detail",desc = "Explain",key = "e"}, + {prompt = "Write a shell scirpt",desc = "Shell",key = "S"}, + } + -- you can change cc to your desired keybind prefix + for _,v in pairs(my_prompts) do + table.insert(keybinds,{ "cc"..v.key, ":CopilotChatVisual "..v.prompt.."", mode = "x", desc = "CopilotChat - "..v.desc }) + table.insert(keybinds,{ "cc"..v.key, "CopilotChat "..v.prompt.."", desc = "CopilotChat - "..v.desc }) + end + return keybinds + end, + }, +``` + ## Roadmap - Translation to pure Lua @@ -278,6 +320,10 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Trí Thiện Nguyễn
Trí Thiện Nguyễn

💻 He Zhizhou
He Zhizhou

💻 Guruprakash Rajakkannu
Guruprakash Rajakkannu

💻 + kristofka
kristofka

💻 + + + PostCyberPunk
PostCyberPunk

📖 @@ -287,4 +333,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome! + +### Stargazers over time + +[![Stargazers over time](https://starchart.cc/CopilotC-Nvim/CopilotChat.nvim.svg)](https://starchart.cc/CopilotC-Nvim/CopilotChat.nvim) diff --git a/cspell-tool.txt b/cspell-tool.txt index 73288a14..3893944c 100644 --- a/cspell-tool.txt +++ b/cspell-tool.txt @@ -1,10 +1,17 @@ +keymap pynvim nvim nargs +rplugin +Rplugin +checkhealth +bufnr +noremap Neovim healthcheck bufexists vlog +sysname vararg tjdevries neovim @@ -16,14 +23,19 @@ lineinfo currentline echom tiktoken -jellydn -zbirenbaum -rplugin +Nvim +huynhdung +Autocmd jellydn's ecosse pcall -noremap nowait +keybinds +imporve +readablilty +perfomance +scirpt +keybind gptlang Huynh Haracic @@ -32,20 +44,19 @@ Nguyễn Zhizhou Guruprakash Rajakkannu +kristofka vsplit mypynvim -Nvim AUTOCMD -Autocmd getreg -bufnr autocmd dotenv machineid winnr Nightfly -keymaps +foldmethod linebreak +keymaps diffthis diffoff conceallevel @@ -62,7 +73,4 @@ autocmds shrinked zindex noautocmd -roleplay -vusted -luarocks -isort \ No newline at end of file +roleplay \ No newline at end of file diff --git a/doc/CopilotChat.txt b/doc/CopilotChat.txt index 868a9f45..facc0432 100644 --- a/doc/CopilotChat.txt +++ b/doc/CopilotChat.txt @@ -1,13 +1,14 @@ -*CopilotChat.txt* For NVIM v0.8.0 Last change: 2024 February 03 +*CopilotChat.txt* For NVIM v0.8.0 Last change: 2024 February 08 ============================================================================== Table of Contents *CopilotChat-table-of-contents* 1. Copilot Chat for Neovim |CopilotChat-copilot-chat-for-neovim| + - Prerequisites |CopilotChat-copilot-chat-for-neovim-prerequisites| - Authentication |CopilotChat-copilot-chat-for-neovim-authentication| - Installation |CopilotChat-copilot-chat-for-neovim-installation| - Usage |CopilotChat-copilot-chat-for-neovim-usage| - - Receipts |CopilotChat-copilot-chat-for-neovim-receipts| + - Tips |CopilotChat-copilot-chat-for-neovim-tips| - Roadmap |CopilotChat-copilot-chat-for-neovim-roadmap| - Development |CopilotChat-copilot-chat-for-neovim-development| - Contributors ✨ |CopilotChat-copilot-chat-for-neovim-contributors-✨| @@ -23,6 +24,13 @@ Table of Contents *CopilotChat-table-of-contents* Neovim before starting a chat with Copilot. To stay updated on our roadmap, please join our Discord community. +PREREQUISITES *CopilotChat-copilot-chat-for-neovim-prerequisites* + +Ensure you have the following installed: + +- Python 3.10 or later + + AUTHENTICATION *CopilotChat-copilot-chat-for-neovim-authentication* It will prompt you with instructions on your first start. If you already have @@ -41,11 +49,11 @@ LAZY.NVIM ~ >lua return { { - "jellydn/CopilotChat.nvim", - dependencies = { "zbirenbaum/copilot.lua" }, -- Or { "github/copilot.vim" } + "CopilotC-Nvim/CopilotChat.nvim", opts = { show_help = "yes", -- Show help text for CopilotChatInPlace, default: yes debug = false, -- Enable or disable debug mode, the log file will be in ~/.local/state/nvim/CopilotChat.nvim.log + disable_extra_info = 'no', -- Disable extra information (e.g: system prompt) in the response. }, build = function() vim.notify("Please update the remote plugins by running ':UpdateRemotePlugins', then restart Neovim.") @@ -94,7 +102,7 @@ MANUAL ~ 1. Put the files in the right place > - $ git clone https://github.com/jellydn/CopilotChat.nvim + $ git clone https://github.com/CopilotC-Nvim/CopilotChat.nvim $ cd CopilotChat.nvim $ cp -r --backup=nil rplugin ~/.config/nvim/ < @@ -133,7 +141,7 @@ commands: >lua return { - "jellydn/CopilotChat.nvim", + "CopilotC-Nvim/CopilotChat.nvim", opts = { debug = true, show_help = "yes", @@ -199,7 +207,16 @@ IN-PLACE CHAT POPUP ~ -RECEIPTS *CopilotChat-copilot-chat-for-neovim-receipts* +TIPS *CopilotChat-copilot-chat-for-neovim-tips* + + +DEBUGGING WITH :MESSAGES AND :COPILOTCHATDEBUGINFO ~ + +If you encounter any issues, you can run the command `:messages` to inspect the +log. You can also run the command `:CopilotChatDebugInfo` to inspect the debug +information. + + HOW TO SETUP WITH WHICH-KEY.NVIM ~ @@ -209,7 +226,7 @@ A special thanks to @ecosse3 for the configuration of which-key >lua { - "jellydn/CopilotChat.nvim", + "CopilotC-Nvim/CopilotChat.nvim", event = "VeryLazy", opts = { prompts = { @@ -272,6 +289,37 @@ Follow the example below to create a simple input for CopilotChat. < +ADD SAME KEYBINDS IN BOTH VISUAL AND NORMAL MODE ~ + +>lua + { + "CopilotC-Nvim/CopilotChat.nvim", + keys = + function() + local keybinds={ + --add your custom keybinds here + } + -- change prompt and keybinds as per your need + local my_prompts = { + {prompt = "In Neovim.",desc = "Neovim",key = "n"}, + {prompt = "Help with this",desc = "Help",key = "h"}, + {prompt = "Simplify and imporve readablilty",desc = "Simplify",key = "s"}, + {prompt = "Optimize the code to improve perfomance and readablilty.",desc = "Optimize",key = "o"}, + {prompt = "Find possible errors and fix them for me",desc = "Fix",key = "f"}, + {prompt = "Explain in detail",desc = "Explain",key = "e"}, + {prompt = "Write a shell scirpt",desc = "Shell",key = "S"}, + } + -- you can change cc to your desired keybind prefix + for _,v in pairs(my_prompts) do + table.insert(keybinds,{ "cc"..v.key, ":CopilotChatVisual "..v.prompt.."", mode = "x", desc = "CopilotChat - "..v.desc }) + table.insert(keybinds,{ "cc"..v.key, "CopilotChat "..v.prompt.."", desc = "CopilotChat - "..v.desc }) + end + return keybinds + end, + }, +< + + ROADMAP *CopilotChat-copilot-chat-for-neovim-roadmap* - Translation to pure Lua @@ -300,21 +348,28 @@ CONTRIBUTORS ✨ *CopilotChat-copilot-chat-for-neovim-contributors-✨* Thanks goes to these wonderful people (emoji key ): -gptlang💻 📖Dung Duc Huynh (Kaka)💻 📖Ahmed Haracic💻Trí Thiện Nguyễn💻He Zhizhou💻Guruprakash Rajakkannu💻This project follows the all-contributors +gptlang💻 📖Dung Duc Huynh (Kaka)💻 📖Ahmed Haracic💻Trí Thiện Nguyễn💻He Zhizhou💻Guruprakash Rajakkannu💻kristofka💻PostCyberPunk📖This project follows the all-contributors specification. -Contributions of any kind welcome! +Contributions of any kind are welcome! + + +STARGAZERS OVER TIME ~ + + ============================================================================== 2. Links *CopilotChat-links* -1. *All Contributors*: https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square +1. *All Contributors*: https://img.shields.io/badge/all_contributors-8-orange.svg?style=flat-square 2. *@jellydn*: 3. *Chat Demo*: https://i.gyazo.com/10fbd1543380d15551791c1a6dcbcd46.gif 4. *Explain Code Demo*: https://i.gyazo.com/e5031f402536a1a9d6c82b2c38d469e3.gif 5. *Generate tests*: https://i.gyazo.com/f285467d4b8d8f8fd36aa777305312ae.gif 6. *Fold Demo*: https://i.gyazo.com/766fb3b6ffeb697e650fc839882822a8.gif 7. *In-place Demo*: https://i.gyazo.com/4a5badaa109cd483c1fc23d296325cb0.gif -8. *@ecosse3*: +8. *Debug Info*: https://i.gyazo.com/bf00e700bcee1b77bcbf7b516b552521.gif +9. *@ecosse3*: +10. *Stargazers over time*: https://starchart.cc/CopilotC-Nvim/CopilotChat.nvim.svg Generated by panvimdoc diff --git a/lua/CopilotChat/health.lua b/lua/CopilotChat/health.lua index 6677898c..f109065f 100644 --- a/lua/CopilotChat/health.lua +++ b/lua/CopilotChat/health.lua @@ -38,8 +38,8 @@ function M.check() end local major, minor = string.match(python_version, 'Python (%d+)%.(%d+)') - if not (major and minor and tonumber(major) >= 3 and tonumber(minor) >= 7) then - warn('Python version 3.7 or higher is required') + if not (major and minor and tonumber(major) >= 3 and tonumber(minor) >= 10) then + warn('Python version 3.10 or higher is required') else ok('Python version ' .. major .. '.' .. minor .. ' is supported') end diff --git a/lua/CopilotChat/init.lua b/lua/CopilotChat/init.lua index d3058d41..9fe5f325 100644 --- a/lua/CopilotChat/init.lua +++ b/lua/CopilotChat/init.lua @@ -12,10 +12,12 @@ _COPILOT_CHAT_GLOBAL_CONFIG = {} -- Set up the plugin ---@param options (table | nil) -- - show_help: ('yes' | 'no') default: 'yes'. +-- - disable_extra_info: ('yes' | 'no') default: 'yes'. -- - prompts: (table?) default: default_prompts. -- - debug: (boolean?) default: false. M.setup = function(options) vim.g.copilot_chat_show_help = options and options.show_help or 'yes' + vim.g.copilot_chat_disable_separators = options and options.disable_extra_info or 'yes' local debug = options and options.debug or false _COPILOT_CHAT_GLOBAL_CONFIG.debug = debug @@ -30,6 +32,68 @@ M.setup = function(options) end, { nargs = '*', range = true }) end + -- Show debug info + utils.create_cmd('CopilotChatDebugInfo', function() + -- Get the log file path + local log_file_path = utils.get_log_file_path() + + -- Get the rplugin path + local rplugin_path = utils.get_remote_plugins_path() + + -- Create a popup with the log file path + local lines = { + 'CopilotChat.nvim Info:', + '- Log file path: ' .. log_file_path, + '- Rplugin path: ' .. rplugin_path, + 'If you are facing issues, run `:checkhealth CopilotChat` and share the output.', + 'There is a common issue is "Ambiguous use of user-defined command". Please check the pin issues on the repository.', + 'Press `q` to close this window.', + 'Press `?` to open the rplugin file.', + } + + local width = 0 + for _, line in ipairs(lines) do + width = math.max(width, #line) + end + local height = #lines + local opts = { + relative = 'editor', + width = width + 4, + height = height + 2, + row = (vim.o.lines - height) / 2 - 1, + col = (vim.o.columns - width) / 2, + style = 'minimal', + border = 'rounded', + } + local bufnr = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) + vim.api.nvim_open_win(bufnr, true, opts) + + -- Bind 'q' to close the window + vim.api.nvim_buf_set_keymap( + bufnr, + 'n', + 'q', + 'close', + { noremap = true, silent = true } + ) + + -- Bind `?` to open remote plugin detail + vim.api.nvim_buf_set_keymap( + bufnr, + 'n', + '?', + -- Close the current window and open the rplugin file + 'closeedit ' + .. rplugin_path + .. '', + { noremap = true, silent = true } + ) + end, { + nargs = '*', + range = true, + }) + utils.log_info( 'Execute ":UpdateRemotePlugins" and restart Neovim before starting a chat with Copilot.' ) diff --git a/lua/CopilotChat/utils.lua b/lua/CopilotChat/utils.lua index 3402d5b6..3d83bdc3 100644 --- a/lua/CopilotChat/utils.lua +++ b/lua/CopilotChat/utils.lua @@ -2,6 +2,25 @@ local M = {} local log = require('CopilotChat.vlog') +--- Get the log file path +---@return string +M.get_log_file_path = function() + return log.get_log_file() +end + +-- The CopilotChat.nvim is built using remote plugins. +-- This is the path to the rplugin.vim file. +-- Refer https://neovim.io/doc/user/remote_plugin.html#%3AUpdateRemotePlugins +-- @return string +M.get_remote_plugins_path = function() + local os = vim.loop.os_uname().sysname + if os == 'Linux' or os == 'Darwin' then + return '~/.local/share/nvim/rplugin.vim' + else + return '~/AppData/Local/nvim/rplugin.vim' + end +end + --- Create custom command ---@param cmd string The command name ---@param func function The function to execute diff --git a/rplugin/python3/copilot.py b/rplugin/python3/copilot.py index ee471b64..4a86ae26 100644 --- a/rplugin/python3/copilot.py +++ b/rplugin/python3/copilot.py @@ -127,10 +127,11 @@ def ask( ) ) for line in response.iter_lines(): - line = line.decode("utf-8").replace("data: ", "").strip() - if line.startswith("[DONE]"): + line: bytes = line + line = line.replace(b"data: ", b"") + if line.startswith(b"[DONE]"): break - elif line == "": + elif line == b"": continue try: line = json.loads(line) diff --git a/rplugin/python3/handlers/chat_handler.py b/rplugin/python3/handlers/chat_handler.py index ebcdfac6..166af537 100644 --- a/rplugin/python3/handlers/chat_handler.py +++ b/rplugin/python3/handlers/chat_handler.py @@ -1,6 +1,8 @@ +import time +from datetime import datetime from typing import Optional, cast -import prompts as prompts +import prompts as system_prompts from copilot import Copilot from mypynvim.core.buffer import MyBuffer from mypynvim.core.nvim import MyNvim @@ -14,10 +16,11 @@ def is_module_installed(name): return False +# TODO: Abort request if the user closes the layout class ChatHandler: def __init__(self, nvim: MyNvim, buffer: MyBuffer): self.nvim: MyNvim = nvim - self.copilot = None + self.copilot: Copilot = None self.buffer: MyBuffer = buffer # public @@ -33,9 +36,11 @@ def chat( disable_end_separator: bool = False, model: str = "gpt-4", ): + disable_separators = ( + self.nvim.eval("g:copilot_chat_disable_separators") == "yes" + ) if system_prompt is None: system_prompt = self._construct_system_prompt(prompt) - # Start the spinner self.nvim.exec_lua('require("CopilotChat.spinner").show()') @@ -44,7 +49,9 @@ def chat( ) if not disable_start_separator: - self._add_start_separator(system_prompt, prompt, code, filetype, winnr) + self._add_start_separator( + system_prompt, prompt, code, filetype, winnr, disable_separators + ) self._add_chat_messages(system_prompt, prompt, code, filetype, model) @@ -52,18 +59,18 @@ def chat( self.nvim.exec_lua('require("CopilotChat.spinner").hide()') if not disable_end_separator: - self._add_end_separator() + self._add_end_separator(model, disable_separators) # private def _construct_system_prompt(self, prompt: str): - system_prompt = prompts.COPILOT_INSTRUCTIONS - if prompt == prompts.FIX_SHORTCUT: - system_prompt = prompts.COPILOT_FIX - elif prompt == prompts.TEST_SHORTCUT: - system_prompt = prompts.COPILOT_TESTS - elif prompt == prompts.EXPLAIN_SHORTCUT: - system_prompt = prompts.COPILOT_EXPLAIN + system_prompt = system_prompts.COPILOT_INSTRUCTIONS + if prompt == system_prompts.FIX_SHORTCUT: + system_prompt = system_prompts.COPILOT_FIX + elif prompt == system_prompts.TEST_SHORTCUT: + system_prompt = system_prompts.COPILOT_TESTS + elif prompt == system_prompts.EXPLAIN_SHORTCUT: + system_prompt = system_prompts.COPILOT_EXPLAIN return system_prompt def _add_start_separator( @@ -73,14 +80,15 @@ def _add_start_separator( code: str, file_type: str, winnr: int, + no_annoyance: bool = False, ): - if is_module_installed("tiktoken"): + if is_module_installed("tiktoken") and not no_annoyance: self._add_start_separator_with_token_count( system_prompt, prompt, code, file_type, winnr ) else: self._add_regular_start_separator( - system_prompt, prompt, code, file_type, winnr + system_prompt, prompt, code, file_type, winnr, no_annoyance ) def _add_regular_start_separator( @@ -90,15 +98,17 @@ def _add_regular_start_separator( code: str, file_type: str, winnr: int, + no_annoyance: bool = False, ): - if code: + if code and not no_annoyance: code = f"\n \nCODE:\n```{file_type}\n{code}\n```" last_row_before = len(self.buffer.lines()) system_prompt_height = len(system_prompt.split("\n")) code_height = len(code.split("\n")) - start_separator = f"""### User + start_separator = ( + f"""### User SYSTEM PROMPT: ``` @@ -109,8 +119,13 @@ def _add_regular_start_separator( ### Copilot """ + if not no_annoyance + else f"### User\n{prompt}\n\n### Copilot\n\n" + ) self.buffer.append(start_separator.split("\n")) + if no_annoyance: + return self._add_folds(code, code_height, last_row_before, system_prompt_height, winnr) def _add_start_separator_with_token_count( @@ -166,6 +181,7 @@ def _add_folds( system_prompt_height: int, winnr: int, ): + self.nvim.command("set foldmethod=manual") system_fold_start = last_row_before + 2 system_fold_end = system_fold_start + system_prompt_height + 3 main_command = f"{system_fold_start}, {system_fold_end} fold | normal! Gzz" @@ -184,7 +200,23 @@ def _add_chat_messages( ): if self.copilot is None: self.copilot = Copilot() - + if self.copilot.github_token is None: + req = self.copilot.request_auth() + self.nvim.out_write( + f"Please visit {req['verification_uri']} and enter the code {req['user_code']}\n" + ) + current_time = time.time() + wait_until = current_time + req["expires_in"] + while self.copilot.github_token is None: + self.copilot.poll_auth(req["device_code"]) + time.sleep(req["interval"]) + if time.time() > wait_until: + self.nvim.out_write("Timed out waiting for authentication\n") + return + self.nvim.out_write("Successfully authenticated with Copilot\n") + self.copilot.authenticate() + + last_line_col = 0 for token in self.copilot.ask( system_prompt, prompt, code, language=cast(str, file_type), model=model ): @@ -193,8 +225,6 @@ def _add_chat_messages( ) buffer_lines = cast(list[str], self.buffer.lines()) last_line_row = len(buffer_lines) - 1 - last_line_col = len(buffer_lines[-1]) - self.nvim.api.buf_set_text( self.buffer.number, last_line_row, @@ -203,7 +233,21 @@ def _add_chat_messages( last_line_col, token.split("\n"), ) + last_line_col += len(token.encode("utf-8")) + if "\n" in token: + last_line_col = 0 + + def _add_end_separator(self, model: str, disable_separators: bool = False): + current_datetime = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + model_info = f"\n#### Answer provided by Copilot (Model: `{model}`) on {current_datetime}." + additional_instructions = ( + "\n> For additional queries, please use the `CopilotChat` command." + ) + disclaimer = "\n> Please be aware that the AI's output may not always be accurate. Always cross-verify the output." + + end_message = model_info + additional_instructions + disclaimer + + if disable_separators: + end_message = "\n" + current_datetime + "\n\n---\n" - def _add_end_separator(self): - end_separator = "\n---\n" - self.buffer.append(end_separator.split("\n")) + self.buffer.append(end_message.split("\n")) diff --git a/rplugin/python3/handlers/inplace_chat_handler.py b/rplugin/python3/handlers/inplace_chat_handler.py index d3b36dc2..dc5db6ac 100644 --- a/rplugin/python3/handlers/inplace_chat_handler.py +++ b/rplugin/python3/handlers/inplace_chat_handler.py @@ -5,15 +5,12 @@ from mypynvim.ui_components.layout import Box, Layout from mypynvim.ui_components.popup import PopUp -from . import prompts - # Define constants for the models MODEL_GPT4 = "gpt-4" MODEL_GPT35_TURBO = "gpt-3.5-turbo" # TODO: change the layout, e.g: move to right side of the screen -# TODO: Abort request if the user closes the layout class InPlaceChatHandler: """This class handles in-place chat functionality.""" @@ -243,10 +240,10 @@ def _set_keymaps(self): self.prompt_popup.map("n", "", lambda cb=self._toggle_system_model: cb()) self.prompt_popup.map( - "n", "'", lambda: self._set_prompt(prompts.PROMPT_SIMPLE_DOCSTRING) + "n", "'", lambda: self._set_prompt(system_prompts.PROMPT_SIMPLE_DOCSTRING) ) self.prompt_popup.map( - "n", "s", lambda: self._set_prompt(prompts.PROMPT_SEPARATE) + "n", "s", lambda: self._set_prompt(system_prompts.PROMPT_SEPARATE) ) self.prompt_popup.map( diff --git a/rplugin/python3/handlers/prompts.py b/rplugin/python3/handlers/prompts.py deleted file mode 100644 index f12db7c7..00000000 --- a/rplugin/python3/handlers/prompts.py +++ /dev/null @@ -1,2 +0,0 @@ -PROMPT_SIMPLE_DOCSTRING = "add simple docstring to this code" -PROMPT_SEPARATE = "add comments separating the code into sections" diff --git a/rplugin/python3/mypynvim/ui_components/popup.py b/rplugin/python3/mypynvim/ui_components/popup.py index 9040b452..cab2bac9 100644 --- a/rplugin/python3/mypynvim/ui_components/popup.py +++ b/rplugin/python3/mypynvim/ui_components/popup.py @@ -2,7 +2,7 @@ from copy import deepcopy from dataclasses import dataclass -from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Union, Unpack +from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Union if TYPE_CHECKING: from mypynvim.core.nvim import MyNvim @@ -14,7 +14,7 @@ from mypynvim.core.window import MyWindow from .calculator import Calculator -from .types import PaddingKeys, PopUpArgs, PopUpConfiguration, Relative +from .types import PaddingKeys, PopUpConfiguration, Relative @dataclass @@ -33,7 +33,7 @@ def __init__( padding: PaddingKeys = {}, enter: bool = False, opts={}, - **kwargs: Unpack[PopUpArgs], + **kwargs, ): self.nvim: MyNvim = nvim self.calculator: Calculator = Calculator(self.nvim) diff --git a/rplugin/python3/prompts.py b/rplugin/python3/prompts.py index 34a857a4..1290cbb0 100644 --- a/rplugin/python3/prompts.py +++ b/rplugin/python3/prompts.py @@ -247,3 +247,5 @@ Your code output should keep the same level of indentation as the user's code. You MUST add whitespace in the beginning of each line as needed to match the user's code. """ +PROMPT_SIMPLE_DOCSTRING = "add simple docstring to this code" +PROMPT_SEPARATE = "add comments separating the code into sections" diff --git a/version.txt b/version.txt new file mode 100644 index 00000000..7dea76ed --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +1.0.1