Skip to content
This repository was archived by the owner on Feb 5, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@ It will prompt you with instructions on your first start. If you already have `C

### Lazy.nvim

1. `pip install python-dotenv requests pynvim prompt-toolkit`
1. `pip install python-dotenv requests pynvim==0.5.0 prompt-toolkit`
2. Put it in your lazy setup

```lua
require('lazy').setup({
{
"gptlang/CopilotChat.nvim",
"jellydn/CopilotChat.nvim",
branch = "canary",
opts = {},
build = function()
vim.cmd("UpdateRemotePlugins")
vim.defer_fn(function()
vim.cmd("UpdateRemotePlugins")
vim.notify("CopilotChat - Updated remote plugins. Please restart Neovim.")
end, 3000)
end,
event = "VeryLazy",
keys = {
Expand Down
8 changes: 6 additions & 2 deletions lua/CopilotChat/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ local utils = require('CopilotChat.utils')
local M = {}

-- Set up the plugin
M.setup = function()
---@param options (table | nil)
-- - mode: ('newbuffer' | 'split') default: newbuffer.
M.setup = function(options)
vim.g.copilot_chat_view_option = options and options.mode or 'newbuffer'

-- Add new command to explain the selected text with CopilotChat
utils.create_cmd('CopilotChatExplain', function(opts)
utils.create_cmd('CopilotChatExplain', function()
vim.cmd('CopilotChat Explain how it works')
end, { nargs = '*', range = true })

Expand Down
95 changes: 95 additions & 0 deletions lua/CopilotChat/spinner.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
-- spinner.lua
--
-- This library is free software; you can redistribute it and/or modify it
-- under the terms of the MIT license. See LICENSE for details.

local M = {}

-- User configuration section
local config = {
-- Show notification when done.
-- Set to false to disable.
show_notification = true,
-- Name of the plugin.
plugin = 'CopilotChat.nvim',
-- Spinner frames.
spinner_frames = {
'⠋',
'⠙',
'⠹',
'⠸',
'⠼',
'⠴',
'⠦',
'⠧',
'⠇',
'⠏',
},
}

-- {{{ NO NEED TO CHANGE

local spinner_index = 1
local spinner_timer = nil
local spinner_buf = nil
local spinner_win = nil

--- Show a spinner at the specified position.
---@param position? table
function M.show(position)
-- Default position: the top right corner
local default_position = {
relative = 'editor',
width = 1,
height = 1,
col = vim.o.columns - 1,
row = 0,
}
local options = position or default_position
options.style = 'minimal'

-- Create buffer and window for the spinner
spinner_buf = vim.api.nvim_create_buf(false, true)
spinner_win = vim.api.nvim_open_win(spinner_buf, false, options)

-- Set up timer and update spinner
spinner_timer = vim.loop.new_timer()
spinner_timer:start(
0,
100,
vim.schedule_wrap(function()
vim.api.nvim_buf_set_lines(
spinner_buf,
0,
-1,
false,
{ config.spinner_frames[spinner_index] }
)
spinner_index = spinner_index % #config.spinner_frames + 1
end)
)
end

--- Hide the spinner.
---@param show_msg? boolean
function M.hide(show_msg)
if spinner_timer then
spinner_timer:stop()
spinner_timer:close()
spinner_timer = nil
if spinner_win then
vim.api.nvim_win_close(spinner_win, true)
end
if spinner_buf then
vim.api.nvim_buf_delete(spinner_buf, { force = true })
end

if config.show_notification or show_msg then
vim.notify('Done!', vim.log.levels.INFO, { title = config.plugin })
end
end
end

-- }}}

return M
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
python-dotenv
requests
pynvim
pynvim==0.5.0
prompt-toolkit
77 changes: 53 additions & 24 deletions rplugin/python3/copilot-plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import copilot
import dotenv
import prompts
import pynvim

dotenv.load_dotenv()
Expand Down Expand Up @@ -34,41 +35,69 @@ def copilotChat(self, args: list[str]):
if self.copilot.github_token is None:
self.nvim.out_write("Please authenticate with Copilot first\n")
return

# Start the spinner
self.nvim.exec_lua('require("CopilotChat.spinner").show()')

prompt = " ".join(args)
if prompt == "/fix":
prompt = prompts.FIX_SHORTCUT
elif prompt == "/test":
prompt = prompts.TEST_SHORTCUT
elif prompt == "/explain":
prompt = prompts.EXPLAIN_SHORTCUT

# Get code from the unnamed register
code = self.nvim.eval("getreg('\"')")
file_type = self.nvim.eval("expand('%')").split(".")[-1]

# Get the view option from the command
view_option = self.nvim.eval("g:copilot_chat_view_option")

# Check if we're already in a chat buffer
if self.nvim.eval("getbufvar(bufnr(), '&buftype')") != "nofile":
# Create a new scratch buffer to hold the chat
self.nvim.command("enew")
if view_option == "split":
self.nvim.command("vnew")
else:
self.nvim.command("enew")
# Set the buffer type to nofile and hide it when it's not active
self.nvim.command("setlocal buftype=nofile bufhidden=hide noswapfile")
# Set filetype as markdown and wrap with linebreaks
self.nvim.command("setlocal filetype=markdown wrap linebreak")

if self.nvim.current.line != "":
# Go to end of file and insert a new line
self.nvim.command("normal Go")
self.nvim.current.line += "### User"
self.nvim.command("normal o")
# TODO: How to handle the case with the large text in from neovim command
self.nvim.current.line += prompt
self.nvim.command("normal o")
self.nvim.current.line += "### Copilot"
self.nvim.command("normal o")
# Get the current buffer
buf = self.nvim.current.buffer
self.nvim.api.buf_set_option(buf, "fileencoding", "utf-8")

# Add start separator
start_separator = f"""### User
{prompt}

### Copilot

"""
buf.append(start_separator.split("\n"), -1)

# Add chat messages
for token in self.copilot.ask(prompt, code, language=file_type):
if "\n" not in token:
self.nvim.current.line += token
continue
lines = token.split("\n")
for i in range(len(lines)):
self.nvim.current.line += lines[i]
if i != len(lines) - 1:
self.nvim.command("normal o")

self.nvim.command("normal o")
self.nvim.current.line += ""
self.nvim.command("normal o")
self.nvim.current.line += "---"
buffer_lines = self.nvim.api.buf_get_lines(buf, 0, -1, 0)
last_line_row = len(buffer_lines) - 1
last_line = buffer_lines[-1]
last_line_col = len(last_line.encode("utf-8"))

self.nvim.api.buf_set_text(
buf,
last_line_row,
last_line_col,
last_line_row,
last_line_col,
token.split("\n"),
)

# Stop the spinner
self.nvim.exec_lua('require("CopilotChat.spinner").hide()')

# Add end separator
end_separator = "\n---\n"
buf.append(end_separator.split("\n"), -1)
Loading