Skip to content

Commit 2c6e51d

Browse files
authored
chore: move watcher logic (#714)
Co-authored-by: Oli Morris <[email protected]>
1 parent f94b626 commit 2c6e51d

File tree

3 files changed

+112
-104
lines changed

3 files changed

+112
-104
lines changed

lua/codecompanion/strategies/chat/init.lua

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -591,58 +591,8 @@ function Chat:submit(opts)
591591

592592
local message = ts_parse_messages(self, user_role, self.header_line)
593593

594-
for _, ref in ipairs(self.refs) do
595-
if ref.bufnr and ref.opts and ref.opts.watched then
596-
local changes = self.watchers:get_changes(ref.bufnr)
597-
log:debug("Checking watched buffer %d, found %d changes", ref.bufnr, changes and #changes or 0)
598-
599-
if changes and #changes > 0 then
600-
local changes_text = string.format(
601-
"Changes detected in `%s` (buffer %d):\n",
602-
vim.fn.fnamemodify(api.nvim_buf_get_name(ref.bufnr), ":t"),
603-
ref.bufnr
604-
)
605-
606-
for _, change in ipairs(changes) do
607-
if change.type == "delete" then
608-
changes_text = changes_text
609-
.. string.format(
610-
"Lines %d-%d were deleted:\n```%s\n%s\n```\n",
611-
change.start,
612-
change.end_line,
613-
vim.bo[ref.bufnr].filetype,
614-
table.concat(change.lines, "\n")
615-
)
616-
elseif change.type == "modify" then
617-
changes_text = changes_text
618-
.. string.format(
619-
"Lines %d-%d were modified from:\n```%s\n%s\n```\nto:\n```%s\n%s\n```\n",
620-
change.start,
621-
change.end_line,
622-
vim.bo[ref.bufnr].filetype,
623-
table.concat(change.old_lines, "\n"),
624-
vim.bo[ref.bufnr].filetype,
625-
table.concat(change.new_lines, "\n")
626-
)
627-
else -- type == "add"
628-
changes_text = changes_text
629-
.. string.format(
630-
"Lines %d-%d were added:\n```%s\n%s\n```\n",
631-
change.start,
632-
change.end_line,
633-
vim.bo[ref.bufnr].filetype,
634-
table.concat(change.lines, "\n")
635-
)
636-
end
637-
end
638-
639-
self:add_message({
640-
role = config.constants.USER_ROLE,
641-
content = changes_text,
642-
}, { visible = true })
643-
end
644-
end
645-
end
594+
-- Check if any watched buffers have any changes
595+
self.watchers:check_for_changes(self)
646596

647597
if not self:has_user_messages(message) or message.content == "" then
648598
return log:warn("No messages to submit")

lua/codecompanion/strategies/chat/watchers.lua

Lines changed: 109 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,61 +3,11 @@ Watchers track changes in Neovim buffers by comparing buffer content over time.
33
a state for each watched buffer, recording the current content and last sent content. When
44
checked, it compares states to detect line additions, deletions, and modifications.
55
]]
6+
local config = require("codecompanion.config")
67
local log = require("codecompanion.utils.log")
78

89
local api = vim.api
910

10-
---@class CodeCompanion.Watchers
11-
local Watchers = {}
12-
13-
function Watchers.new()
14-
return setmetatable({
15-
buffers = {},
16-
augroup = api.nvim_create_augroup("CodeCompanionWatcher", { clear = true }),
17-
}, { __index = Watchers })
18-
end
19-
20-
---Watch a buffer for changes
21-
---@param bufnr number
22-
---@return nil
23-
function Watchers:watch(bufnr)
24-
if self.buffers[bufnr] then
25-
return
26-
end
27-
28-
if not api.nvim_buf_is_valid(bufnr) then
29-
log:debug("Cannot watch invalid buffer: %d", bufnr)
30-
return
31-
end
32-
33-
log:debug("Starting to watch buffer: %d", bufnr)
34-
local initial_content = api.nvim_buf_get_lines(bufnr, 0, -1, false)
35-
36-
self.buffers[bufnr] = {
37-
content = initial_content,
38-
last_sent = initial_content,
39-
changedtick = api.nvim_buf_get_changedtick(bufnr),
40-
}
41-
42-
api.nvim_create_autocmd("BufDelete", {
43-
group = self.augroup,
44-
buffer = bufnr,
45-
callback = function()
46-
self:unwatch(bufnr)
47-
end,
48-
})
49-
end
50-
51-
---Stop watching a buffer
52-
---@param bufnr number
53-
---@return nil
54-
function Watchers:unwatch(bufnr)
55-
if self.buffers[bufnr] then
56-
log:debug("Unwatching buffer %d", bufnr)
57-
self.buffers[bufnr] = nil
58-
end
59-
end
60-
6111
---Find the index of a line in a list of lines
6212
---@param line string
6313
---@param lines table
@@ -184,6 +134,57 @@ local function detect_changes(old_lines, new_lines)
184134
return changes
185135
end
186136

137+
---@class CodeCompanion.Watchers
138+
local Watchers = {}
139+
140+
function Watchers.new()
141+
return setmetatable({
142+
buffers = {},
143+
augroup = api.nvim_create_augroup("CodeCompanionWatcher", { clear = true }),
144+
}, { __index = Watchers })
145+
end
146+
147+
---Watch a buffer for changes
148+
---@param bufnr number
149+
---@return nil
150+
function Watchers:watch(bufnr)
151+
if self.buffers[bufnr] then
152+
return
153+
end
154+
155+
if not api.nvim_buf_is_valid(bufnr) then
156+
log:debug("Cannot watch invalid buffer: %d", bufnr)
157+
return
158+
end
159+
160+
log:debug("Starting to watch buffer: %d", bufnr)
161+
local initial_content = api.nvim_buf_get_lines(bufnr, 0, -1, false)
162+
163+
self.buffers[bufnr] = {
164+
content = initial_content,
165+
last_sent = initial_content,
166+
changedtick = api.nvim_buf_get_changedtick(bufnr),
167+
}
168+
169+
api.nvim_create_autocmd("BufDelete", {
170+
group = self.augroup,
171+
buffer = bufnr,
172+
callback = function()
173+
self:unwatch(bufnr)
174+
end,
175+
})
176+
end
177+
178+
---Stop watching a buffer
179+
---@param bufnr number
180+
---@return nil
181+
function Watchers:unwatch(bufnr)
182+
if self.buffers[bufnr] then
183+
log:debug("Unwatching buffer %d", bufnr)
184+
self.buffers[bufnr] = nil
185+
end
186+
end
187+
187188
---Get any changes in a watched buffer
188189
---@param bufnr number
189190
---@return CodeCompanion.Change[]|nil
@@ -210,4 +211,61 @@ function Watchers:get_changes(bufnr)
210211
return changes
211212
end
212213

214+
---Check all watched buffers for changes
215+
---@param chat CodeCompanion.Chat
216+
function Watchers:check_for_changes(chat)
217+
for _, ref in ipairs(chat.refs) do
218+
if ref.bufnr and ref.opts and ref.opts.watched then
219+
local changes = self:get_changes(ref.bufnr)
220+
log:debug("Checking watched buffer %d, found %d changes", ref.bufnr, changes and #changes or 0)
221+
222+
if changes and #changes > 0 then
223+
local changes_text = string.format(
224+
"Changes detected in `%s` (buffer %d):\n",
225+
vim.fn.fnamemodify(api.nvim_buf_get_name(ref.bufnr), ":t"),
226+
ref.bufnr
227+
)
228+
229+
for _, change in ipairs(changes) do
230+
if change.type == "delete" then
231+
changes_text = changes_text
232+
.. string.format(
233+
"Lines %d-%d were deleted:\n```%s\n%s\n```\n",
234+
change.start,
235+
change.end_line,
236+
vim.bo[ref.bufnr].filetype,
237+
table.concat(change.lines, "\n")
238+
)
239+
elseif change.type == "modify" then
240+
changes_text = changes_text
241+
.. string.format(
242+
"Lines %d-%d were modified from:\n```%s\n%s\n```\nto:\n```%s\n%s\n```\n",
243+
change.start,
244+
change.end_line,
245+
vim.bo[ref.bufnr].filetype,
246+
table.concat(change.old_lines, "\n"),
247+
vim.bo[ref.bufnr].filetype,
248+
table.concat(change.new_lines, "\n")
249+
)
250+
else -- type == "add"
251+
changes_text = changes_text
252+
.. string.format(
253+
"Lines %d-%d were added:\n```%s\n%s\n```\n",
254+
change.start,
255+
change.end_line,
256+
vim.bo[ref.bufnr].filetype,
257+
table.concat(change.lines, "\n")
258+
)
259+
end
260+
end
261+
262+
chat:add_message({
263+
role = config.constants.USER_ROLE,
264+
content = changes_text,
265+
}, { visible = false })
266+
end
267+
end
268+
end
269+
end
270+
213271
return Watchers

lua/codecompanion/types.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
---@field augroup integer The autocmd group ID
5656
---@field watch fun(self: CodeCompanion.Watchers, bufnr: number): nil Start watching a buffer
5757
---@field unwatch fun(self: CodeCompanion.Watchers, bufnr: number): nil Stop watching a buffer
58-
---@field get_changes fun(self: CodeCompanion.Watchers, bufnr: number): CodeCompanion.Change[]|nil Get changes since last check
58+
---@field get_changes fun(self: CodeCompanion.Watchers, bufnr: number): CodeCompanion.Change[]|nil Get the latest changes in the buffer
5959

6060
---@class CodeCompanion.WatcherState
6161
---@field content string[] Complete buffer content

0 commit comments

Comments
 (0)