@@ -11,6 +11,7 @@ local config = require('gitsigns.config').config
11
11
local dprint = log .dprint
12
12
local dprintf = log .dprintf
13
13
local throttle_by_id = require (' gitsigns.debounce' ).throttle_by_id
14
+ local debounce_trailing = require (' gitsigns.debounce' ).debounce_trailing
14
15
15
16
local api = vim .api
16
17
local uv = vim .loop
@@ -216,6 +217,105 @@ local function get_buf_context(bufnr)
216
217
}
217
218
end
218
219
220
+ --- @param bufnr integer
221
+ --- @param old_relpath string
222
+ local function handle_moved (bufnr , old_relpath )
223
+ local bcache = assert (cache [bufnr ])
224
+ local git_obj = bcache .git_obj
225
+
226
+ local new_name = git_obj :has_moved ()
227
+ if new_name then
228
+ dprintf (' File moved to %s' , new_name )
229
+ git_obj .relpath = new_name
230
+ if not git_obj .orig_relpath then
231
+ git_obj .orig_relpath = old_relpath
232
+ end
233
+ elseif git_obj .orig_relpath then
234
+ local orig_file = git_obj .repo .toplevel .. util .path_sep .. git_obj .orig_relpath
235
+ if not git_obj :file_info (orig_file ).relpath then
236
+ return
237
+ end
238
+ --- File was moved in the index, but then reset
239
+ dprintf (' Moved file reset' )
240
+ git_obj .relpath = git_obj .orig_relpath
241
+ git_obj .orig_relpath = nil
242
+ else
243
+ -- File removed from index, do nothing
244
+ return
245
+ end
246
+
247
+ git_obj .file = git_obj .repo .toplevel .. util .path_sep .. git_obj .relpath
248
+ bcache .file = git_obj .file
249
+ git_obj :update ()
250
+ if not manager .schedule (bufnr ) then
251
+ return
252
+ end
253
+
254
+ local bufexists = util .bufexists (bcache .file )
255
+ local old_name = api .nvim_buf_get_name (bufnr )
256
+
257
+ if not bufexists then
258
+ -- Do not trigger BufFilePre/Post
259
+ -- TODO(lewis6991): figure out how to avoid reattaching without
260
+ -- disabling all autocommands.
261
+ util .noautocmd ({ ' BufFilePre' , ' BufFilePost' }, function ()
262
+ util .buf_rename (bufnr , bcache .file )
263
+ end )
264
+ end
265
+
266
+ local msg = bufexists and ' Cannot rename' or ' Renamed'
267
+ dprintf (' %s buffer %d from %s to %s' , msg , bufnr , old_name , bcache .file )
268
+ end
269
+
270
+ --- @async
271
+ --- @param bufnr integer
272
+ local function watcher_handler0 (bufnr )
273
+ local __FUNC__ = ' watcher_handler'
274
+
275
+ -- Avoid cache hit for detached buffer
276
+ -- ref: https://github.com/lewis6991/gitsigns.nvim/issues/956
277
+ if not manager .schedule (bufnr ) then
278
+ dprint (' buffer invalid (1)' )
279
+ return
280
+ end
281
+
282
+ local git_obj = cache [bufnr ].git_obj
283
+
284
+ Status :update (bufnr , { head = git_obj .repo .abbrev_head })
285
+
286
+ local was_tracked = git_obj .object_name ~= nil
287
+ local old_relpath = git_obj .relpath
288
+
289
+ git_obj :update ()
290
+ if not manager .schedule (bufnr ) then
291
+ dprint (' buffer invalid (3)' )
292
+ return
293
+ end
294
+
295
+ if config .watch_gitdir .follow_files and was_tracked and not git_obj .object_name then
296
+ -- File was tracked but is no longer tracked. Must of been removed or
297
+ -- moved. Check if it was moved and switch to it.
298
+ handle_moved (bufnr , old_relpath )
299
+ if not manager .schedule (bufnr ) then
300
+ dprint (' buffer invalid (4)' )
301
+ return
302
+ end
303
+ end
304
+
305
+ cache [bufnr ]:invalidate (true )
306
+
307
+ require (' gitsigns.manager' ).update (bufnr )
308
+ end
309
+
310
+ --- Debounce to:
311
+ --- - wait for all changes to the gitdir to complete.
312
+ --- Throttle to:
313
+ --- - ensure handler is only triggered once per git operation.
314
+ --- - prevent updates to the same buffer from interleaving as the handler is
315
+ --- async.
316
+ local watcher_handler =
317
+ debounce_trailing (200 , async .create (1 , throttle_by_id (watcher_handler0 , true )), 1 )
318
+
219
319
--- Ensure attaches cannot be interleaved for the same buffer.
220
320
--- Since attaches are asynchronous we need to make sure an attach isn't
221
321
--- performed whilst another one is in progress.
@@ -325,8 +425,9 @@ local attach_throttled = throttle_by_id(function(cbuf, ctx, aucmd)
325
425
})
326
426
327
427
if config .watch_gitdir .enable then
328
- local watcher = require (' gitsigns.watcher' )
329
- cache [cbuf ].gitdir_watcher = watcher .watch_gitdir (cbuf , git_obj .repo .gitdir )
428
+ cache [cbuf ].deregister_watcher = git_obj .repo :register_callback (function ()
429
+ watcher_handler (cbuf )
430
+ end )
330
431
end
331
432
332
433
if not api .nvim_buf_is_loaded (cbuf ) then
0 commit comments