From 9f9ca13e3e23b5de08c49e319b2885af3f08013e Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Fri, 8 Aug 2025 23:33:10 +0200 Subject: [PATCH] refactor(chat): unify message/block API for cursor access Refactored chat window API to use `get_message(role, cursor)` and `get_block(role, cursor)` for both last and cursor-closest access. Removed legacy `get_closest_message` and `get_closest_block` methods. Updated mappings and documentation to reflect unified API. This simplifies usage and improves consistency for message/block retrieval and removal actions. --- README.md | 8 ++-- lua/CopilotChat/config/mappings.lua | 14 +++---- lua/CopilotChat/ui/chat.lua | 64 ++++++++++++++--------------- 3 files changed, 42 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 4177c1e9..f4111a0f 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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 diff --git a/lua/CopilotChat/config/mappings.lua b/lua/CopilotChat/config/mappings.lua index 4fcf03c7..5f411473 100644 --- a/lua/CopilotChat/config/mappings.lua +++ b/lua/CopilotChat/config/mappings.lua @@ -162,7 +162,7 @@ return { normal = '', insert = '', callback = function() - local message = copilot.chat:get_closest_message('user') + local message = copilot.chat:get_message('user', true) if not message then return end @@ -234,7 +234,7 @@ return { normal = '', insert = '', 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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/lua/CopilotChat/ui/chat.lua b/lua/CopilotChat/ui/chat.lua index 2752e6d0..bb4492b1 100644 --- a/lua/CopilotChat/ui/chat.lua +++ b/lua/CopilotChat/ui/chat.lua @@ -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 @@ -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 @@ -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