|
1 | 1 | if not _G.vim then |
| 2 | + local next_timer_id = 0 |
| 3 | + |
2 | 4 | _G.vim = { ---@type vim_global_api |
3 | 5 | schedule_wrap = function(fn) |
4 | 6 | return fn |
@@ -192,7 +194,49 @@ if not _G.vim then |
192 | 194 | end, |
193 | 195 |
|
194 | 196 | loop = { |
195 | | - timer_stop = function(_timer) -- Prefix unused param with underscore |
| 197 | + now = function() |
| 198 | + return 0 |
| 199 | + end, |
| 200 | + new_timer = function() |
| 201 | + next_timer_id = next_timer_id + 1 |
| 202 | + |
| 203 | + local timer = { |
| 204 | + _id = next_timer_id, |
| 205 | + _start_calls = 0, |
| 206 | + _stop_calls = 0, |
| 207 | + _close_calls = 0, |
| 208 | + _callback = nil, |
| 209 | + } |
| 210 | + |
| 211 | + function timer:start(timeout, repeat_interval, callback) |
| 212 | + self._start_calls = self._start_calls + 1 |
| 213 | + self._timeout = timeout |
| 214 | + self._repeat_interval = repeat_interval |
| 215 | + self._callback = callback |
| 216 | + return true |
| 217 | + end |
| 218 | + |
| 219 | + function timer:stop() |
| 220 | + self._stop_calls = self._stop_calls + 1 |
| 221 | + return true |
| 222 | + end |
| 223 | + |
| 224 | + function timer:close() |
| 225 | + self._close_calls = self._close_calls + 1 |
| 226 | + return true |
| 227 | + end |
| 228 | + |
| 229 | + function timer:fire() |
| 230 | + assert(self._callback, "Timer has no callback; did you call :start()?") |
| 231 | + return self._callback() |
| 232 | + end |
| 233 | + |
| 234 | + return timer |
| 235 | + end, |
| 236 | + timer_stop = function(timer) |
| 237 | + if timer and timer.stop then |
| 238 | + timer:stop() |
| 239 | + end |
196 | 240 | return true |
197 | 241 | end, |
198 | 242 | }, |
@@ -362,6 +406,76 @@ describe("Selection module", function() |
362 | 406 | assert(selection.state.latest_selection == nil) |
363 | 407 | end) |
364 | 408 |
|
| 409 | + describe("debounce_update", function() |
| 410 | + it("should cancel and close previous debounce timer when re-debouncing", function() |
| 411 | + local update_calls = 0 |
| 412 | + local old_update_selection = selection.update_selection |
| 413 | + |
| 414 | + selection.update_selection = function() |
| 415 | + update_calls = update_calls + 1 |
| 416 | + end |
| 417 | + |
| 418 | + selection.debounce_update() |
| 419 | + local timer1 = selection.state.debounce_timer |
| 420 | + assert(timer1 ~= nil) |
| 421 | + |
| 422 | + selection.debounce_update() |
| 423 | + local timer2 = selection.state.debounce_timer |
| 424 | + assert(timer2 ~= nil) |
| 425 | + assert.are_not.equal(timer1, timer2) |
| 426 | + |
| 427 | + assert.are.equal(1, timer1._stop_calls) |
| 428 | + assert.are.equal(1, timer1._close_calls) |
| 429 | + |
| 430 | + -- Clean up the active timer |
| 431 | + timer2:fire() |
| 432 | + assert.are.equal(1, update_calls) |
| 433 | + |
| 434 | + selection.update_selection = old_update_selection |
| 435 | + end) |
| 436 | + |
| 437 | + it("should ignore stale debounce timer callbacks", function() |
| 438 | + local update_calls = 0 |
| 439 | + local old_update_selection = selection.update_selection |
| 440 | + |
| 441 | + selection.update_selection = function() |
| 442 | + update_calls = update_calls + 1 |
| 443 | + end |
| 444 | + |
| 445 | + selection.debounce_update() |
| 446 | + local timer1 = selection.state.debounce_timer |
| 447 | + assert(timer1 ~= nil) |
| 448 | + |
| 449 | + selection.debounce_update() |
| 450 | + local timer2 = selection.state.debounce_timer |
| 451 | + assert(timer2 ~= nil) |
| 452 | + |
| 453 | + -- A callback from a cancelled timer should be ignored. |
| 454 | + timer1:fire() |
| 455 | + assert.are.equal(0, update_calls) |
| 456 | + |
| 457 | + timer2:fire() |
| 458 | + assert.are.equal(1, update_calls) |
| 459 | + assert(selection.state.debounce_timer == nil) |
| 460 | + assert.are.equal(1, timer2._stop_calls) |
| 461 | + assert.are.equal(1, timer2._close_calls) |
| 462 | + |
| 463 | + selection.update_selection = old_update_selection |
| 464 | + end) |
| 465 | + |
| 466 | + it("disable() should cancel an active debounce timer", function() |
| 467 | + selection.enable(mock_server) |
| 468 | + selection.debounce_update() |
| 469 | + local timer = selection.state.debounce_timer |
| 470 | + assert(timer ~= nil) |
| 471 | + |
| 472 | + selection.disable() |
| 473 | + assert(selection.state.debounce_timer == nil) |
| 474 | + assert.are.equal(1, timer._stop_calls) |
| 475 | + assert.are.equal(1, timer._close_calls) |
| 476 | + end) |
| 477 | + end) |
| 478 | + |
365 | 479 | it("should get cursor position in normal mode", function() |
366 | 480 | local old_win_get_cursor = _G.vim.api.nvim_win_get_cursor |
367 | 481 | _G.vim.api.nvim_win_get_cursor = function() |
|
0 commit comments