Line data Source code
1 : -- lua/yoda/integrations/gitsigns.lua
2 : -- GitSigns integration utilities
3 :
4 21 : local M = {}
5 :
6 21 : local timer_manager = require("yoda.timer_manager")
7 :
8 : -- ============================================================================
9 : -- Constants
10 : -- ============================================================================
11 :
12 21 : local BATCH_WINDOW = 200 -- ms - batching window for multiple refresh requests
13 21 : local BATCH_TIMER_ID = "gitsigns_batch"
14 :
15 : -- ============================================================================
16 : -- Private State
17 : -- ============================================================================
18 :
19 21 : local batch_state = {
20 : timer = nil,
21 21 : requests = {},
22 : window_start = 0,
23 : request_count = 0,
24 : batch_count = 0,
25 : }
26 :
27 : -- ============================================================================
28 : -- Public API
29 : -- ============================================================================
30 :
31 : --- Check if gitsigns plugin is loaded
32 : --- @return boolean
33 21 : function M.is_available()
34 2 : return package.loaded.gitsigns ~= nil
35 21 : end
36 :
37 : --- Get the gitsigns module if available
38 : --- @return table|nil gitsigns module or nil
39 21 : function M.get_gitsigns()
40 49 : return package.loaded.gitsigns
41 21 : end
42 :
43 : --- Refresh git signs with batching - collects multiple requests in 200ms window
44 : --- This deduplicates rapid refresh triggers (BufWritePost, FocusGained, FileChangedShell)
45 21 : function M.refresh_batched()
46 36 : local gs = M.get_gitsigns()
47 36 : if not gs then
48 1 : return
49 : end
50 :
51 60 : local current_time = vim.uv.hrtime() / 1000000
52 :
53 : -- Track the request
54 35 : local buf = vim.api.nvim_get_current_buf()
55 35 : batch_state.requests[buf] = true
56 35 : batch_state.request_count = batch_state.request_count + 1
57 :
58 : -- Start batch window if not already started
59 35 : if not batch_state.timer then
60 14 : batch_state.window_start = current_time
61 14 : batch_state.batch_count = batch_state.batch_count + 1
62 :
63 28 : batch_state.timer = timer_manager.create_vim_timer(function()
64 11 : batch_state.timer = nil
65 :
66 : -- Collect all buffers that requested refresh
67 11 : local buffers = {}
68 24 : for b, _ in pairs(batch_state.requests) do
69 21 : if vim.api.nvim_buf_is_valid(b) then
70 11 : table.insert(buffers, b)
71 : end
72 : end
73 :
74 : -- Clear batch state
75 11 : batch_state.requests = {}
76 11 : batch_state.request_count = 0
77 :
78 : -- Execute batched refresh
79 22 : vim.schedule(function()
80 11 : local gitsigns = M.get_gitsigns()
81 11 : if gitsigns then
82 22 : for _, b in ipairs(buffers) do
83 17 : if vim.api.nvim_buf_is_valid(b) then
84 11 : pcall(gitsigns.refresh, b)
85 : end
86 : end
87 : end
88 22 : end)
89 39 : end, BATCH_WINDOW, BATCH_TIMER_ID)
90 : end
91 56 : end
92 :
93 : --- Reset any pending refresh timers (for cleanup or testing)
94 21 : function M.reset_timers()
95 88 : if timer_manager.is_vim_timer_active(BATCH_TIMER_ID) then
96 3 : timer_manager.stop_vim_timer(BATCH_TIMER_ID)
97 3 : batch_state.timer = nil
98 3 : batch_state.requests = {}
99 3 : batch_state.request_count = 0
100 : end
101 65 : end
102 :
103 : --- Get batch statistics (for testing/debugging)
104 : --- @return table stats Batch statistics
105 21 : function M.get_batch_stats()
106 4 : return {
107 4 : active = batch_state.timer ~= nil,
108 4 : pending_requests = batch_state.request_count,
109 4 : total_batches = batch_state.batch_count,
110 4 : window_ms = BATCH_WINDOW,
111 4 : }
112 21 : end
113 :
114 : --- Reset batch statistics (for testing)
115 21 : function M.reset_batch_stats()
116 17 : batch_state.batch_count = 0
117 17 : batch_state.request_count = 0
118 17 : batch_state.requests = {}
119 38 : end
120 :
121 21 : return M
|