Skip to content

Commit ecf8f12

Browse files
authored
fix: Suppress VGitSync during staging (#425)
Adds suppress_sync_and_refresh() API to git_buffer_store. Instead of refreshing all tracked buffers on git index changes, this suppresses the VGitSync broadcast and refreshes only the affected buffer after a delay. Applied in DiffScreen (stage/unstage/reset operations) and Hunks (stage_all, cursor_stage). Performance from local profiling: 95% reduction in calls (10,421 → 564 per session staging 39 hunks), 99.6% reduction in LiveGutter:fetch (1,380 → 6).
1 parent 9f52b9d commit ecf8f12

3 files changed

Lines changed: 56 additions & 0 deletions

File tree

lua/vgit/features/buffer/Hunks.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ function Hunks:stage_all()
6868
local buffer = git_buffer_store.current()
6969
if not buffer then return end
7070

71+
-- Performance: Suppress VGitSync broadcast; refresh only this buffer after delay
72+
git_buffer_store.suppress_sync_and_refresh(buffer, 200)
73+
7174
loop.free_textlock()
7275
local _, err = buffer:stage()
7376
if err then return console.debug.error(err) end
@@ -82,6 +85,9 @@ function Hunks:cursor_stage()
8285
if not buffer then return end
8386
if buffer:editing() then return end
8487

88+
-- Performance: Suppress VGitSync broadcast; refresh only this buffer after delay
89+
git_buffer_store.suppress_sync_and_refresh(buffer, 200)
90+
8591
if not buffer:is_tracked() then
8692
local _, err = buffer:stage()
8793
if err then return console.debug.error(err) end

lua/vgit/features/screens/DiffScreen/init.lua

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ function DiffScreen:reset(buffer)
138138
local filename = self.model:get_filename()
139139
if not filename then return end
140140

141+
-- Performance: Suppress VGitSync broadcast; refresh only this buffer after delay
142+
local git_buffer_store = require('vgit.git.git_buffer_store')
143+
git_buffer_store.suppress_sync_and_refresh(buffer, 200)
144+
141145
loop.free_textlock()
142146
self.model:reset_file(filename)
143147

@@ -185,6 +189,10 @@ function DiffScreen:stage_hunk(buffer)
185189
local hunk, index = self.diff_view:get_hunk_under_cursor()
186190
if not hunk then return end
187191

192+
-- Performance: Suppress VGitSync broadcast; refresh only this buffer after delay
193+
local git_buffer_store = require('vgit.git.git_buffer_store')
194+
git_buffer_store.suppress_sync_and_refresh(buffer, 200)
195+
188196
self.model:stage_hunk(filename, hunk)
189197

190198
loop.free_textlock()
@@ -212,6 +220,10 @@ function DiffScreen:unstage_hunk(buffer)
212220
local hunk, index = self.diff_view:get_hunk_under_cursor()
213221
if not hunk then return end
214222

223+
-- Performance: Suppress VGitSync broadcast; refresh only this buffer after delay
224+
local git_buffer_store = require('vgit.git.git_buffer_store')
225+
git_buffer_store.suppress_sync_and_refresh(buffer, 200)
226+
215227
loop.free_textlock()
216228
self.model:unstage_hunk(filename, hunk)
217229

@@ -247,6 +259,10 @@ function DiffScreen:reset_hunk(buffer)
247259

248260
if decision ~= 'yes' and decision ~= 'y' then return end
249261

262+
-- Performance: Suppress VGitSync broadcast; refresh only this buffer after delay
263+
local git_buffer_store = require('vgit.git.git_buffer_store')
264+
git_buffer_store.suppress_sync_and_refresh(buffer, 200)
265+
250266
loop.free_textlock()
251267
self.model:reset_hunk(filename, hunk)
252268

@@ -271,6 +287,10 @@ function DiffScreen:stage(buffer)
271287
local filename = self.model:get_filename()
272288
if not filename then return end
273289

290+
-- Performance: Suppress VGitSync broadcast; refresh only this buffer after delay
291+
local git_buffer_store = require('vgit.git.git_buffer_store')
292+
git_buffer_store.suppress_sync_and_refresh(buffer, 200)
293+
274294
loop.free_textlock()
275295
self.model:stage_file(filename)
276296

@@ -292,6 +312,10 @@ function DiffScreen:unstage(buffer)
292312
local filename = self.model:get_filename()
293313
if not filename then return end
294314

315+
-- Performance: Suppress VGitSync broadcast; refresh only this buffer after delay
316+
local git_buffer_store = require('vgit.git.git_buffer_store')
317+
git_buffer_store.suppress_sync_and_refresh(buffer, 200)
318+
295319
loop.free_textlock()
296320
self.model:unstage_file(filename)
297321

lua/vgit/git/git_buffer_store.lua

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ local events = {
1616
}
1717
local is_registered = false
1818

19+
-- When true, VGitSync events are suppressed (e.g., during staging operations)
20+
local suppress_sync = false
21+
1922
local git_buffer_store = {}
2023

2124
git_buffer_store.register_events = loop.coroutine(function()
@@ -40,6 +43,8 @@ git_buffer_store.register_events = loop.coroutine(function()
4043
-- Use vim.schedule to avoid "must not be called in a lua loop callback" error
4144
vim.schedule(function()
4245
event.custom_on('VGitSync', function()
46+
if suppress_sync then return end
47+
4348
git_buffer_store.for_each(function(buffer)
4449
git_buffer_store.dispatch(buffer, 'sync')
4550
end)
@@ -181,4 +186,25 @@ git_buffer_store.collect = function()
181186
git_buffer_store.dispatch(git_buffer, 'attach')
182187
end
183188

189+
-- Suppress VGitSync broadcast and refresh only the specified buffer after delay.
190+
-- This prevents refreshing all tracked buffers when only one needs updating.
191+
--
192+
-- Note: External git operations during the suppression window won't trigger a
193+
-- refresh until the next VGitSync event. This is an acceptable tradeoff given
194+
-- the short window (typically 200ms).
195+
git_buffer_store.suppress_sync_and_refresh = function(buffer, ms)
196+
local git_buffer = git_buffer_store.get(buffer)
197+
if not git_buffer then return end
198+
199+
suppress_sync = true
200+
201+
vim.defer_fn(loop.coroutine(function()
202+
suppress_sync = false
203+
204+
if git_buffer:is_valid() then
205+
git_buffer_store.dispatch(git_buffer, 'sync')
206+
end
207+
end), ms)
208+
end
209+
184210
return git_buffer_store

0 commit comments

Comments
 (0)