|
16 | 16 | "ThreadedCompleter",
|
17 | 17 | "DummyCompleter",
|
18 | 18 | "DynamicCompleter",
|
| 19 | + "ThrottledCompleter", |
19 | 20 | "CompleteEvent",
|
20 | 21 | "ConditionalCompleter",
|
21 | 22 | "merge_completers",
|
@@ -316,6 +317,46 @@ def __repr__(self) -> str:
|
316 | 317 | return f"DynamicCompleter({self.get_completer!r} -> {self.get_completer()!r})"
|
317 | 318 |
|
318 | 319 |
|
| 320 | +class ThrottledCompleter(Completer): |
| 321 | + """ |
| 322 | + Completer that throttles completion requests to prevent rapid successive calls. |
| 323 | +
|
| 324 | + :param completer: :class:`.Completer` instance. |
| 325 | + :param delay: Delay in seconds between completions. Default is 0.3. |
| 326 | + """ |
| 327 | + |
| 328 | + def __init__(self, completer: Completer, delay: float = 0.3): |
| 329 | + self.completer = completer |
| 330 | + self.delay = delay |
| 331 | + self._last_completion_time = 0 |
| 332 | + self._semaphore = asyncio.Semaphore(1) |
| 333 | + |
| 334 | + def get_completions( |
| 335 | + self, document: Document, complete_event: CompleteEvent |
| 336 | + ) -> Iterable[Completion]: |
| 337 | + """Get completions without throttling.""" |
| 338 | + yield from self.completer.get_completions(document, complete_event) |
| 339 | + |
| 340 | + async def get_completions_async( |
| 341 | + self, document: Document, complete_event: CompleteEvent |
| 342 | + ) -> AsyncGenerator[Completion, None]: |
| 343 | + """Get completions asynchronously, applying throttle delay.""" |
| 344 | + async with self._semaphore: |
| 345 | + current_time = asyncio.get_running_loop().time() |
| 346 | + time_since_last_completion = current_time - self._last_completion_time |
| 347 | + |
| 348 | + if time_since_last_completion < self.delay: |
| 349 | + await asyncio.sleep(self.delay - time_since_last_completion) |
| 350 | + |
| 351 | + self._last_completion_time = asyncio.get_running_loop().time() |
| 352 | + |
| 353 | + async with aclosing( |
| 354 | + self.completer.get_completions_async(document, complete_event) |
| 355 | + ) as async_generator: |
| 356 | + async for item in async_generator: |
| 357 | + yield item |
| 358 | + |
| 359 | + |
319 | 360 | class ConditionalCompleter(Completer):
|
320 | 361 | """
|
321 | 362 | Wrapper around any other completer that will enable/disable the completions
|
|
0 commit comments