diff --git a/CHANGELOG.md b/CHANGELOG.md index e1c4200e..8fea78a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [1.5.0](https://github.com/CopilotC-Nvim/CopilotChat.nvim/compare/v1.4.0...v1.5.0) (2024-02-17) + + +### Features + +* add options to hide system prompts ([98a6191](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/98a61913f4cd798fb042f4b21f6a3e1a457c3959)) +* add prompt actions support in Telescope integration ([f124645](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/f124645d4b48df59790c9763687b94cf7dd3f5bf)) +* integrate CopilotChat with telescope.nvim for code actions ([0cabac6](https://github.com/CopilotC-Nvim/CopilotChat.nvim/commit/0cabac6af8c838d4984b766f5d985a04259d3a4d)) + ## [1.4.0](https://github.com/CopilotC-Nvim/CopilotChat.nvim/compare/v1.3.0...v1.4.0) (2024-02-16) diff --git a/README.md b/README.md index 48fd1ddb..b6cf11bc 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,9 @@ You have the ability to tailor this plugin to your specific needs using the conf { debug = false, -- Enable or disable debug mode show_help = 'yes', -- Show help text for CopilotChatInPlace + disable_extra_info = 'no', -- Disable extra information in the response + hide_system_prompt = 'yes', -- Hide system prompts in the response + proxy = '', -- Proxies requests via https or socks prompts = { -- Set dynamic prompts for CopilotChat commands Explain = 'Explain how it works.', Tests = 'Briefly explain how the selected code works, then generate unit tests.', @@ -212,6 +215,45 @@ For further reference, you can view @jellydn's [configuration](https://github.co ## Tips +### Integration with `telescope.nvim` + +To integrate CopilotChat with Telescope, you can add the following configuration to your keymap: + +```lua + { + "CopilotC-Nvim/CopilotChat.nvim", + event = "VeryLazy", + dependencies = { + { "nvim-telescope/telescope.nvim" }, -- Use telescope for help actions + { "nvim-lua/plenary.nvim" }, + }, + keys = { + -- Show help actions with telescope + { + "cch", + function() + require("CopilotChat.code_actions").show_help_actions() + end, + desc = "CopilotChat - Help actions", + }, + -- Show prompts actions with telescope + { + "ccp", + function() + require("CopilotChat.code_actions").show_prompt_actions() + end, + desc = "CopilotChat - Help actions", + }, + } + } +``` + +1. Select help actions base the diagnostic message under the cursor. + [![Help action with Copilot Chat](https://i.gyazo.com/146dc35368592ba9f5de047ddc4728ad.gif)](https://gyazo.com/146dc35368592ba9f5de047ddc4728ad) + +2. Select action base on user prompts. + [![Select action base on user prompts](https://i.gyazo.com/a9c41e6398591c2f1d1d872fd58a2c63.gif)](https://gyazo.com/a9c41e6398591c2f1d1d872fd58a2c63) + ### Integration with `edgy.nvim` Consider integrating this plugin with [`edgy.nvim`](https://github.com/folke/edgy.nvim). This will allow you to create a chat window on the right side of your screen, occupying 40% of the width, as illustrated below. diff --git a/doc/CopilotChat.txt b/doc/CopilotChat.txt index 2146cc10..cc4df58b 100644 --- a/doc/CopilotChat.txt +++ b/doc/CopilotChat.txt @@ -1,4 +1,4 @@ -*CopilotChat.txt* For NVIM v0.8.0 Last change: 2024 February 16 +*CopilotChat.txt* For NVIM v0.8.0 Last change: 2024 February 17 ============================================================================== Table of Contents *CopilotChat-table-of-contents* @@ -148,6 +148,9 @@ configuration options outlined below: { debug = false, -- Enable or disable debug mode show_help = 'yes', -- Show help text for CopilotChatInPlace + disable_extra_info = 'no', -- Disable extra information in the response + hide_system_prompt = 'yes', -- Hide system prompts in the response + proxy = '', -- Proxies requests via https or socks prompts = { -- Set dynamic prompts for CopilotChat commands Explain = 'Explain how it works.', Tests = 'Briefly explain how the selected code works, then generate unit tests.', @@ -242,6 +245,50 @@ TOGGLE VERTICAL SPLIT WITH :COPILOTCHATVSPLITTOGGLE ~ TIPS *CopilotChat-copilot-chat-for-neovim-tips* +INTEGRATION WITH TELESCOPE.NVIM ~ + +To integrate CopilotChat with Telescope, you can add the following +configuration to your keymap: + +>lua + { + "CopilotC-Nvim/CopilotChat.nvim", + event = "VeryLazy", + dependencies = { + { "nvim-telescope/telescope.nvim" }, -- Use telescope for help actions + { "nvim-lua/plenary.nvim" }, + }, + keys = { + -- Show help actions with telescope + { + "cch", + function() + require("CopilotChat.code_actions").show_help_actions() + end, + desc = "CopilotChat - Help actions", + }, + -- Show prompts actions with telescope + { + "ccp", + function() + require("CopilotChat.code_actions").show_prompt_actions() + end, + desc = "CopilotChat - Help actions", + }, + } + } +< + +1. Select help actions base the diagnostic message under the cursor. + + + +2. Select action base on user prompts. + + + + + INTEGRATION WITH EDGY.NVIM ~ Consider integrating this plugin with `edgy.nvim` @@ -427,10 +474,12 @@ STARGAZERS OVER TIME ~ 7. *Fold Demo*: https://i.gyazo.com/766fb3b6ffeb697e650fc839882822a8.gif 8. *In-place Demo*: https://i.gyazo.com/4a5badaa109cd483c1fc23d296325cb0.gif 9. *Toggle*: https://i.gyazo.com/db5af9e5d88cd2fd09f58968914fa521.gif -10. *Layout*: https://i.gyazo.com/550daf6cbb729027ca9bd703c21af53e.png -11. *Debug Info*: https://i.gyazo.com/bf00e700bcee1b77bcbf7b516b552521.gif -12. *@ecosse3*: -13. *Stargazers over time*: https://starchart.cc/CopilotC-Nvim/CopilotChat.nvim.svg +10. *Help action with Copilot Chat*: https://i.gyazo.com/146dc35368592ba9f5de047ddc4728ad.gif +11. *Select action base on user prompts*: https://i.gyazo.com/a9c41e6398591c2f1d1d872fd58a2c63.gif +12. *Layout*: https://i.gyazo.com/550daf6cbb729027ca9bd703c21af53e.png +13. *Debug Info*: https://i.gyazo.com/bf00e700bcee1b77bcbf7b516b552521.gif +14. *@ecosse3*: +15. *Stargazers over time*: https://starchart.cc/CopilotC-Nvim/CopilotChat.nvim.svg Generated by panvimdoc diff --git a/lua/CopilotChat/code_actions.lua b/lua/CopilotChat/code_actions.lua new file mode 100644 index 00000000..1c19e551 --- /dev/null +++ b/lua/CopilotChat/code_actions.lua @@ -0,0 +1,165 @@ +local actions = require('telescope.actions') +local action_state = require('telescope.actions.state') +local telescope_pickers = require('telescope.pickers') +local finders = require('telescope.finders') +local themes = require('telescope.themes') +local conf = require('telescope.config').values +local utils = require('CopilotChat.utils') + +local help_actions = {} +local prompt_actions = {} + +local function fix_diagnostic() + local diagnostic = utils.get_diagnostics() + local file_name = vim.fn.expand('%:t') + local line_number = vim.fn.line('.') + return 'Please assist with fixing the following diagnostic issue in file: "' + .. file_name + .. ':' + .. line_number + .. '". ' + .. diagnostic +end + +local function explain_diagnostic() + local diagnostic = utils.get_diagnostics() + local file_name = vim.fn.expand('%:t') + local line_number = vim.fn.line('.') + return 'Please explain the following diagnostic issue in file: "' + .. file_name + .. ':' + .. line_number + .. '". ' + .. diagnostic +end + +--- Help command for telescope picker +--- This will copy all the lines in the buffer to the unnamed register +--- Then will send the diagnostic to copilot chat +---@param prefix string +local function help_command(prefix) + if prefix == nil then + prefix = '' + else + prefix = prefix .. ' ' + end + + return function(prompt_bufnr, _) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + + -- Select all the lines in the buffer to uname register + vim.cmd('normal! ggVG"*y') + + -- Get value from the help_actions and execute the command + local value = '' + for _, action in pairs(help_actions) do + if action.name == selection[1] then + value = action.label + break + end + end + + vim.cmd(prefix .. value) + end) + return true + end +end + +--- Prompt command for telescope picker +--- This will show all the user prompts in the telescope picker +--- Then will execute the command selected by the user +---@param prefix string +local function prompt_command(prefix) + if prefix == nil then + prefix = '' + else + prefix = prefix .. ' ' + end + + return function(prompt_bufnr, _) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + + -- Get value from the prompt_actions and execute the command + local value = '' + for _, action in pairs(prompt_actions) do + if action.name == selection[1] then + value = action.label + break + end + end + + vim.cmd(prefix .. value) + end) + return true + end +end + +local function show_help_actions() + help_actions = { + { + label = fix_diagnostic(), + name = 'Fix diagnostic', + }, + { + label = explain_diagnostic(), + name = 'Explain diagnostic', + }, + } + + -- Filter all no diagnostics available actions + help_actions = vim.tbl_filter(function(value) + return value.label ~= 'No diagnostics available' + end, help_actions) + + -- Show the menu with telescope pickers + local opts = themes.get_dropdown({}) + local picker_names = {} + for _, value in pairs(help_actions) do + table.insert(picker_names, value.name) + end + telescope_pickers + .new(opts, { + prompt_title = 'Copilot Chat Help Actions', + finder = finders.new_table({ + results = picker_names, + }), + sorter = conf.generic_sorter(opts), + attach_mappings = help_command('CopilotChat'), + }) + :find() +end + +local function show_prompt_actions() + -- Convert user prompts to a table of actions + prompt_actions = {} + + for key, prompt in pairs(vim.g.copilot_chat_user_prompts) do + table.insert(prompt_actions, { name = key, label = prompt }) + end + + -- Show the menu with telescope pickers + local opts = themes.get_dropdown({}) + local picker_names = {} + for _, value in pairs(prompt_actions) do + table.insert(picker_names, value.name) + end + telescope_pickers + .new(opts, { + prompt_title = 'Copilot Chat Actions', + finder = finders.new_table({ + results = picker_names, + }), + sorter = conf.generic_sorter(opts), + attach_mappings = prompt_command('CopilotChat'), + }) + :find() +end + +return { + show_help_actions = show_help_actions, + show_prompt_actions = show_prompt_actions, +} diff --git a/lua/CopilotChat/init.lua b/lua/CopilotChat/init.lua index 693769a4..f1ba227f 100644 --- a/lua/CopilotChat/init.lua +++ b/lua/CopilotChat/init.lua @@ -13,11 +13,14 @@ _COPILOT_CHAT_GLOBAL_CONFIG = {} ---@param options (table | nil) -- - show_help: ('yes' | 'no') default: 'yes'. -- - disable_extra_info: ('yes' | 'no') default: 'yes'. +-- - hide_system_prompt: ('yes' | 'no') default: 'yes'. +-- - proxy: (string?) default: ''. -- - 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' + vim.g.copilot_chat_hide_system_prompt = options and options.hide_system_prompt or 'yes' vim.g.copilot_chat_proxy = options and options.proxy or '' local debug = options and options.debug or false _COPILOT_CHAT_GLOBAL_CONFIG.debug = debug diff --git a/rplugin/python3/CopilotChat/handlers/chat_handler.py b/rplugin/python3/CopilotChat/handlers/chat_handler.py index 07637cb8..4d3e88fc 100644 --- a/rplugin/python3/CopilotChat/handlers/chat_handler.py +++ b/rplugin/python3/CopilotChat/handlers/chat_handler.py @@ -108,6 +108,13 @@ def _add_regular_start_separator( winnr: int, no_annoyance: bool = False, ): + hide_system_prompt = ( + self.nvim.eval("g:copilot_chat_hide_system_prompt") == "yes" + ) + + if hide_system_prompt: + system_prompt = "...System prompt hidden..." + if code and not no_annoyance: code = f"\n \nCODE:\n```{file_type}\n{code}\n```" @@ -148,11 +155,17 @@ def _add_start_separator_with_token_count( encoding = tiktoken.encoding_for_model("gpt-4") + hide_system_prompt = ( + self.nvim.eval("g:copilot_chat_hide_system_prompt") == "yes" + ) num_total_tokens = len(encoding.encode(f"{system_prompt}\n{prompt}\n{code}")) num_system_tokens = len(encoding.encode(system_prompt)) num_prompt_tokens = len(encoding.encode(prompt)) num_code_tokens = len(encoding.encode(code)) + if hide_system_prompt: + system_prompt = "... System prompt hidden ..." + if code: code = f"\n \nCODE: {num_code_tokens} Tokens \n```{file_type}\n{code}\n```" diff --git a/version.txt b/version.txt index 88c5fb89..bc80560f 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.4.0 +1.5.0