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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,10 @@ window:visible() -- Check if chat window is visible
window:focused() -- Check if chat window is focused

-- Message Management
window:get_message(role) -- Get last chat message by role (user, assistant, tool)
window:get_message(role, cursor) -- Get chat message by role, either last or closest to cursor
window:add_message({ role, content }, replace) -- Add or replace a message in chat
window:remove_message(role, cursor) -- Remove chat message by role, either last or closest to cursor
window:get_block(role, cursor) -- Get code block by role, either last or closest to cursor
window:add_sticky(sticky) -- Add sticky prompt to chat message

-- Content Management
Expand All @@ -473,9 +475,7 @@ window:follow() -- Move cursor to end of chat content
window:focus() -- Focus the chat window

-- Advanced Features
window:get_closest_message(role) -- Get message closest to cursor
window:get_closest_block(role) -- Get code block closest to cursor
window:overlay(opts) -- Show overlay with specified options
window:overlay(opts) -- Show overlay with specified options
```

## Example Usage
Expand Down
14 changes: 7 additions & 7 deletions lua/CopilotChat/config/mappings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ return {
normal = '<CR>',
insert = '<C-s>',
callback = function()
local message = copilot.chat:get_closest_message('user')
local message = copilot.chat:get_message('user', true)
if not message then
return
end
Expand Down Expand Up @@ -234,7 +234,7 @@ return {
normal = '<C-y>',
insert = '<C-y>',
callback = function(source)
local diff = get_diff(copilot.chat:get_closest_block())
local diff = get_diff(copilot.chat:get_block('assistant', true))
diff = prepare_diff_buffer(diff, source)
if not diff then
return
Expand All @@ -249,7 +249,7 @@ return {
jump_to_diff = {
normal = 'gj',
callback = function(source)
local diff = get_diff(copilot.chat:get_closest_block())
local diff = get_diff(copilot.chat:get_block('assistant', true))
diff = prepare_diff_buffer(diff, source)
if not diff then
return
Expand Down Expand Up @@ -326,7 +326,7 @@ return {
normal = 'gy',
register = '"', -- Default register to use for yanking
callback = function()
local block = copilot.chat:get_closest_block()
local block = copilot.chat:get_block('assistant', true)
if not block then
return
end
Expand All @@ -339,7 +339,7 @@ return {
normal = 'gd',
full_diff = false, -- Show full diff instead of unified diff when showing diff window
callback = function(source)
local diff = get_diff(copilot.chat:get_closest_block())
local diff = get_diff(copilot.chat:get_block('assistant', true))
diff = prepare_diff_buffer(diff, source)
if not diff then
return
Expand All @@ -356,7 +356,7 @@ return {
-- Apply all diffs from same file
if #modified > 0 then
-- Find all diffs from the same file in this section
local message = copilot.chat:get_closest_message('assistant')
local message = copilot.chat:get_message('assistant', true)
local section = message and message.section
local same_file_diffs = {}
if section then
Expand Down Expand Up @@ -429,7 +429,7 @@ return {
show_info = {
normal = 'gc',
callback = function(source)
local message = copilot.chat:get_closest_message('user')
local message = copilot.chat:get_message('user', true)
if not message then
return
end
Expand Down
64 changes: 31 additions & 33 deletions lua/CopilotChat/ui/chat.lua
Original file line number Diff line number Diff line change
Expand Up @@ -119,35 +119,11 @@ function Chat:focused()
return self:visible() and vim.api.nvim_get_current_win() == self.winnr
end

--- Get the closest message to the cursor.
---@param role string? If specified, only considers sections of the given role
---@return CopilotChat.ui.chat.Message?
function Chat:get_closest_message(role)
if not self:visible() then
return nil
end

self:render()
local cursor_pos = vim.api.nvim_win_get_cursor(self.winnr)
local cursor_line = cursor_pos[1]
local closest_message = nil
local max_line_below_cursor = -1

for _, message in ipairs(self.messages) do
local section = message.section
local matches_role = not role or message.role == role
if matches_role and section.start_line <= cursor_line and section.start_line > max_line_below_cursor then
max_line_below_cursor = section.start_line
closest_message = message
end
end

return closest_message
end

--- Get the closest code block to the cursor.
---@param role string? If specified, only considers sections of the given role
---@param cursor boolean? If true, returns the block closest to the cursor position
---@return CopilotChat.ui.chat.Block?
function Chat:get_closest_block()
function Chat:get_block(role, cursor)
if not self:visible() then
return nil
end
Expand All @@ -172,10 +148,31 @@ function Chat:get_closest_block()
end

--- Get last message by role in the chat window.
---@param role string? If specified, only considers sections of the given role
---@param cursor boolean? If true, returns the message closest to the cursor position
---@return CopilotChat.ui.chat.Message?
function Chat:get_message(role)
if not self:visible() then
return
function Chat:get_message(role, cursor)
if cursor then
if not self:visible() then
return nil
end

self:render()
local cursor_pos = vim.api.nvim_win_get_cursor(self.winnr)
local cursor_line = cursor_pos[1]
local closest_message = nil
local max_line_below_cursor = -1

for _, message in ipairs(self.messages) do
local section = message.section
local matches_role = not role or message.role == role
if matches_role and section.start_line <= cursor_line and section.start_line > max_line_below_cursor then
max_line_below_cursor = section.start_line
closest_message = message
end
end

return closest_message
end

for i = #self.messages, 1, -1 do
Expand Down Expand Up @@ -475,14 +472,15 @@ function Chat:add_message(message, replace)
end

--- Remove a message from the chat window by role.
---@param role string
function Chat:remove_message(role)
---@param role string? If specified, only considers sections of the given role
---@param cursor boolean? If true, removes the message closest to the cursor position
function Chat:remove_message(role, cursor)
if not self:visible() then
return
end

self:render()
local message = self:get_closest_message(role)
local message = self:get_message(role, cursor)
if not message then
return
end
Expand Down
Loading