CopilotChat.nvim
CopilotChat.nvim copied to clipboard
Feature Request: support sub-commands in CopilotChat.nvim
Context
GitHub Copilot for VS Code offers a range of useful sub-commands like /new, /fix, /explain, and /tests that enhance the coding experience. These commands allow users to generate new code, fix issues, get explanations, and write tests efficiently.
Proposal
Integrate these sub-commands into CopilotChat.nvim to bring similar functionalities to Neovim. Below are the specific commands and their intended functionalities:
- /new: Generate new code blocks or files.
- /fix: Automatically suggest fixes for highlighted code issues.
- /explain: Provide detailed explanations for specific code segments.
- /tests: Generate test cases for existing code.
Technical Considerations
- We could add a command like
GCFIX
,GCTests
, etc for each sub command. - We might need to migrate to pure lua plugin if needed.
Request for Feedback
I am not sure about the feasibility of this without Github Copilot team input. Let me know if you have any thoughts on plan on this. @gptlang Thanks for great work for bring this plugin to Neovim community. 👏
I was not aware of these features (Not a user of VScode). Thank you.
I will look into this.
I'm really interested in this, since my main reason for still using Copilot on VS Code is the /workspace sub-command. It lets you make questions to CoPilot on the context of the whole local codebase. It's amazing for exploring and understand projects you had no prior contact with. That's what actually made me renew my copilot license.
I wonder if this kind of feature is even accessible outside VS Code, though, or if it uses VS Code internals to guess which files it have to look at.
There are a lot of wasm files as part of the Copilot Chat VSCode plugin. It will take a lot of effort to get it working 1 to 1 but getting to a hacky blind implementation could maybe be done another way. Open to suggestions from others more knowledgeable than I am on how this can be done.
I personally have no clue how Copilot automagically gets code snippets. Some sort of vector db/index + text similarity tuned for code?
I'll have to abandon porting everything to lua since this might be a bit too complicated for me to do in a new language
~~I've got some of the sub-commands down but my VSCode is missing @workspace
among others from the video~~
Edit: I haven't updated VScode in a loooong time
Hi @gptlang Just FYI - I have just watched this video about how @workspace
works. https://youtu.be/a2DDYMEPwbE?si=rQeeCA-21O5jD8IK
I'm still working on this. Running into a bit of trouble. During the embedding request, it sends each function/class with ... for omitted code. I don't know how they parse/identify the functions.
e.g.
File: `rplugin/python3/copilot.py`
```py
class Copilot:
...
def request_auth(self):
url = "https://github.com/login/device/code"
response = self.session.post(
url,
headers=LOGIN_HEADERS,
data=json.dumps({
"client_id": "Iv1.b507a08c87ecfe98",
"scope": "read:user"
})
).json()
return response
...
File: `rplugin/python3/copilot.py`
```py
class Copilot:
def __init__(self, token: str = None):
if token is None:
token = utilities.get_cached_token()
self.github_token = token
self.token: dict[str, any] = None
self.chat_history: list[typings.Message] = []
self.vscode_sessionid: str = None
self.machineid = utilities.random_hex()
self.session = requests.Session()
...
Maybe tree sitter? Not sure how to ensure that the parser for any specific language is installed.
Looks like I was right. They bundle the parsers into the extension.
I don't think I have the energy to properly implement tree-sitter. If anyone has a shortcut, let me know.
I don't use AI much so I'm gonna put this in my backlog and work on other stuff first.
This is awesome work gptlang! I now use copilot and copilotchat with vsplit. works like a charm! made my day! :)
Thank you for the wonderful plugin. I'm sure there is a better way, but I looked into how to parse python code. Omit everything other than the function and class definition part under the cursor. I hope this helps even a little.
local pythonParseSample = function()
local ts_utils = require 'nvim-treesitter.ts_utils'
local current_node = ts_utils.get_node_at_cursor()
local expr = current_node
local lines = {}
local target_function = nil
local target_class = nil
-- get function and class definition node
while expr do
if target_function == nil and string.find(expr:type(), 'function_definition') then
target_function = expr
end
if string.find(expr:type(), 'class_definition') then
target_class = expr
break
end
expr = expr:parent()
end
if target_class == nil and target_function ~= nil then
-- return function define body
lines = ts_utils.get_node_text(target_function)
return table.concat(lines, "\n")
end
if target_class ~= nil then
local class_lines = ts_utils.get_node_text(target_class)
if target_function == nil then
-- return class define body
return table.concat(class_lines, "\n")
end
local class_definition_line = class_lines[1]
table.insert(lines, class_definition_line)
local class_start_row = target_class:start()
local class_end_row = target_class:end_()
local function_start_row = target_function:start()
local function_end_row = target_function:end_()
if function_start_row ~= class_start_row + 1 then
-- insert ... between class definition and function definition
table.insert(lines, "...")
end
for _, node in ipairs(ts_utils.get_node_text(target_function)) do
table.insert(lines, node)
end
if function_end_row ~= class_end_row then
-- insert ... between function definition and class definition
table.insert(lines, "...")
end
return table.concat(lines, "\n")
end
end
@neutrinoA4 thanks for the suggestion! Is this language agnostic (via tree-sitter) or specific to Python?
@gptlang This code is Python specific. Mainly "function_definition" and "class_definition" in the following parts differ depending on the language.
-- get function and class definition node
while expr do
if target_function == nil and string.find(expr:type(), 'function_definition') then
target_function = expr
end
if string.find(expr:type(), 'class_definition') then
target_class = expr
break
end
For example, struct in rust language is "struct_item", functions are specified as "function_item"
I think #360 is better description for remainder of this, as we already have subcommands, we just dont have full context awareness, so closing as duplicate