Skip to content
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
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,6 @@ local chat = require("CopilotChat")
-- Basic Chat Functions
chat.ask(prompt, config) -- Ask a question with optional config
chat.response() -- Get the last response text
chat.resolve_prompt() -- Resolve prompt references
chat.resolve_tools() -- Resolve tools that are available for automatic use by LLM
chat.resolve_model() -- Resolve model from prompt (WARN: async, requires plenary.async.run)

-- Window Management
chat.open(config) -- Open chat window with optional config
Expand Down Expand Up @@ -456,6 +453,16 @@ window:focus() -- Focus the chat window
window:overlay(opts) -- Show overlay with specified options
```

## Prompt parser

```lua
local parser = require("CopilotChat.prompts")

parser.resolve_prompt() -- Resolve prompt references
parser.resolve_tools() -- Resolve tools that are available for automatic use by LLM
parser.resolve_model() -- Resolve model from prompt (WARN: async, requires plenary.async.run)
```

## Example Usage

```lua
Expand Down
78 changes: 48 additions & 30 deletions lua/CopilotChat/config/mappings.lua
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
local async = require('plenary.async')
local copilot = require('CopilotChat')
local client = require('CopilotChat.client')
local constants = require('CopilotChat.constants')
local select = require('CopilotChat.select')
local utils = require('CopilotChat.utils')
local diff = require('CopilotChat.utils.diff')
local files = require('CopilotChat.utils.files')

--- Prepare a buffer for applying a diff
Expand Down Expand Up @@ -77,22 +75,23 @@ return {
normal = 'q',
insert = '<C-c>',
callback = function()
copilot.close()
require('CopilotChat').close()
end,
},

reset = {
normal = '<C-l>',
insert = '<C-l>',
callback = function()
copilot.reset()
require('CopilotChat').reset()
end,
},

submit_prompt = {
normal = '<CR>',
insert = '<C-s>',
callback = function()
local copilot = require('CopilotChat')
local message = copilot.chat:get_message(constants.ROLE.USER, true)
if not message then
return
Expand All @@ -106,7 +105,10 @@ return {
normal = '<C-y>',
insert = '<C-y>',
callback = function(source)
local block = copilot.chat:get_block(constants.ROLE.ASSISTANT, true)
local chat = require('CopilotChat').chat
local diff = require('CopilotChat.utils.diff')

local block = chat:get_block(constants.ROLE.ASSISTANT, true)
if not block then
return
end
Expand All @@ -127,7 +129,10 @@ return {
jump_to_diff = {
normal = 'gj',
callback = function(source)
local block = copilot.chat:get_block(constants.ROLE.ASSISTANT, true)
local chat = require('CopilotChat').chat
local diff = require('CopilotChat.utils.diff')

local block = chat:get_block(constants.ROLE.ASSISTANT, true)
if not block then
return
end
Expand All @@ -147,19 +152,24 @@ return {
normal = 'gy',
register = '"', -- Default register to use for yanking
callback = function()
local block = copilot.chat:get_block(constants.ROLE.ASSISTANT, true)
local config = require('CopilotChat.config')
local chat = require('CopilotChat').chat
local block = chat:get_block(constants.ROLE.ASSISTANT, true)
if not block then
return
end

vim.fn.setreg(copilot.config.mappings.yank_diff.register, block.content)
vim.fn.setreg(config.mappings.yank_diff.register, block.content)
end,
},

show_diff = {
normal = 'gd',
callback = function(source)
local block = copilot.chat:get_block(constants.ROLE.ASSISTANT, true)
local chat = require('CopilotChat').chat
local diff = require('CopilotChat.utils.diff')

local block = chat:get_block(constants.ROLE.ASSISTANT, true)
if not block then
return
end
Expand All @@ -168,7 +178,7 @@ return {
local bufnr = prepare_diff_buffer(path, source)

-- Collect all blocks for the same filename
local message = copilot.chat:get_message(constants.ROLE.ASSISTANT, true)
local message = chat:get_message(constants.ROLE.ASSISTANT, true)
local blocks = {}
if message and message.section and message.section.blocks then
for _, b in ipairs(message.section.blocks) do
Expand Down Expand Up @@ -196,26 +206,27 @@ return {
vim.cmd('diffthis')
end)

vim.api.nvim_win_call(copilot.chat.winnr, function()
vim.api.nvim_win_call(chat.winnr, function()
vim.cmd('diffthis')
end)
end

opts.on_hide = function()
vim.api.nvim_win_call(copilot.chat.winnr, function()
vim.api.nvim_win_call(chat.winnr, function()
vim.cmd('diffoff')
end)
end

copilot.chat:overlay(opts)
chat:overlay(opts)
end,
},

quickfix_diffs = {
normal = 'gqd',
callback = function()
local chat = require('CopilotChat').chat
local items = {}
local messages = copilot.chat:get_messages()
local messages = chat:get_messages()
for _, message in ipairs(messages) do
if message.section then
for _, block in ipairs(message.section.blocks) do
Expand All @@ -225,7 +236,7 @@ return {
end

table.insert(items, {
bufnr = copilot.chat.bufnr,
bufnr = chat.bufnr,
lnum = block.start_line,
end_lnum = block.end_line,
text = text,
Expand All @@ -242,8 +253,9 @@ return {
quickfix_answers = {
normal = 'gqa',
callback = function()
local chat = require('CopilotChat').chat
local items = {}
local messages = copilot.chat:get_messages()
local messages = chat:get_messages()
for i, message in ipairs(messages) do
if message.section and message.role == constants.ROLE.ASSISTANT then
local prev_message = messages[i - 1]
Expand All @@ -253,7 +265,7 @@ return {
end

table.insert(items, {
bufnr = copilot.chat.bufnr,
bufnr = chat.bufnr,
lnum = message.section.start_line,
end_lnum = message.section.end_line,
text = text,
Expand All @@ -269,28 +281,31 @@ return {
show_info = {
normal = 'gc',
callback = function(source)
local message = copilot.chat:get_message(constants.ROLE.USER, true)
local chat = require('CopilotChat').chat
local prompts = require('CopilotChat.prompts')

local message = chat:get_message(constants.ROLE.USER, true)
if not message then
return
end

local lines = {}

async.run(function()
local config, prompt = copilot.resolve_prompt(message.content)
local config, prompt = prompts.resolve_prompt(message.content)
local system_prompt = config.system_prompt
local resolved_resources = copilot.resolve_functions(prompt, config)
local selected_tools = copilot.resolve_tools(prompt, config)
local selected_model = copilot.resolve_model(prompt, config)
local resolved_resources = prompts.resolve_functions(prompt, config)
local selected_tools = prompts.resolve_tools(prompt, config)
local selected_model = prompts.resolve_model(prompt, config)
local infos = client:info()

selected_tools = vim.tbl_map(function(tool)
return tool.name
end, selected_tools)

utils.schedule_main()
table.insert(lines, '**Logs**: `' .. copilot.config.log_path .. '`')
table.insert(lines, '**History**: `' .. copilot.config.history_path .. '`')
table.insert(lines, '**Logs**: `' .. config.log_path .. '`')
table.insert(lines, '**History**: `' .. config.history_path .. '`')
table.insert(lines, '')

for provider, infolines in pairs(infos) do
Expand Down Expand Up @@ -368,7 +383,7 @@ return {
table.insert(lines, '')
end

copilot.chat:overlay({
chat:overlay({
text = vim.trim(table.concat(lines, '\n')) .. '\n',
})
end)
Expand All @@ -378,6 +393,9 @@ return {
show_help = {
normal = 'gh',
callback = function()
local config = require('CopilotChat.config')
local chat = require('CopilotChat').chat

local chat_help = '**`Special tokens`**\n'
chat_help = chat_help .. '`@<function>` to share function\n'
chat_help = chat_help .. '`#<function>` to add resource\n'
Expand All @@ -387,22 +405,22 @@ return {
chat_help = chat_help .. '`> <text>` to make a sticky prompt (copied to next prompt)\n'

chat_help = chat_help .. '\n**`Mappings`**\n'
local chat_keys = vim.tbl_keys(copilot.config.mappings)
local chat_keys = vim.tbl_keys(config.mappings)
table.sort(chat_keys, function(a, b)
a = copilot.config.mappings[a]
a = config.mappings[a]
a = a and (a.normal or a.insert) or ''
b = copilot.config.mappings[b]
b = config.mappings[b]
b = b and (b.normal or b.insert) or ''
return a < b
end)
for _, name in ipairs(chat_keys) do
local info = utils.key_to_info(name, copilot.config.mappings[name], '`')
local info = utils.key_to_info(name, config.mappings[name], '`')
if info ~= '' then
chat_help = chat_help .. info .. '\n'
end
end

copilot.chat:overlay({
chat:overlay({
text = chat_help,
})
end,
Expand Down
43 changes: 4 additions & 39 deletions lua/CopilotChat/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -230,41 +230,6 @@ local function update_source()
M.chat:set_source(use_prev_window and vim.fn.win_getid(vim.fn.winnr('#')) or vim.api.nvim_get_current_win())
end

--- Resolve enabled tools from the prompt.
---@param prompt string?
---@param config CopilotChat.config.Shared?
---@return table<CopilotChat.client.Tool>, string
function M.resolve_tools(prompt, config)
return prompts.resolve_tools(prompt, config)
end

--- Call and resolve function calls from the prompt.
---@param prompt string?
---@param config CopilotChat.config.Shared?
---@return table<CopilotChat.client.Resource>, table<string>, table<string>, string
---@async
function M.resolve_functions(prompt, config)
return prompts.resolve_functions(prompt, config)
end

--- Resolve the final prompt and config from prompt template.
---@param prompt string?
---@param config CopilotChat.config.Shared?
---@return CopilotChat.config.prompts.Prompt, string
---@async
function M.resolve_prompt(prompt, config)
return prompts.resolve_prompt(prompt, config)
end

--- Resolve the model from the prompt.
---@param prompt string?
---@param config CopilotChat.config.Shared?
---@return string, string
---@async
function M.resolve_model(prompt, config)
return prompts.resolve_model(prompt, config)
end

--- Open the chat window.
---@param config CopilotChat.config.Shared?
function M.open(config)
Expand Down Expand Up @@ -449,11 +414,11 @@ function M.ask(prompt, config)
end

async.run(handle_error(config, function()
config, prompt = M.resolve_prompt(prompt, config)
config, prompt = prompts.resolve_prompt(prompt, config)
local system_prompt = config.system_prompt or ''
local selected_tools, prompt = M.resolve_tools(prompt, config)
local resolved_resources, resolved_tools, resolved_stickies, prompt = M.resolve_functions(prompt, config)
local selected_model, prompt = M.resolve_model(prompt, config)
local selected_tools, prompt = prompts.resolve_tools(prompt, config)
local resolved_resources, resolved_tools, resolved_stickies, prompt = prompts.resolve_functions(prompt, config)
local selected_model, prompt = prompts.resolve_model(prompt, config)

-- Remove sticky prefix
prompt = table.concat(
Expand Down
Loading