|
42 | 42 | get_common_complete_suffix,
|
43 | 43 | )
|
44 | 44 | from .document import Document
|
| 45 | +from .eventloop import aclosing |
45 | 46 | from .filters import FilterOrBool, to_filter
|
46 | 47 | from .history import History, InMemoryHistory
|
47 | 48 | from .search import SearchDirection, SearchState
|
@@ -1736,15 +1737,41 @@ def proceed() -> bool:
|
1736 | 1737 | while generating completions."""
|
1737 | 1738 | return self.complete_state == complete_state
|
1738 | 1739 |
|
1739 |
| - async for completion in self.completer.get_completions_async( |
1740 |
| - document, complete_event |
1741 |
| - ): |
1742 |
| - complete_state.completions.append(completion) |
1743 |
| - self.on_completions_changed.fire() |
| 1740 | + refresh_needed = asyncio.Event() |
| 1741 | + |
| 1742 | + async def refresh_while_loading() -> None: |
| 1743 | + """Background loop to refresh the UI at most 3 times a second |
| 1744 | + while the completion are loading. Calling |
| 1745 | + `on_completions_changed.fire()` for every completion that we |
| 1746 | + receive is too expensive when there are many completions. (We |
| 1747 | + could tune `Application.max_render_postpone_time` and |
| 1748 | + `Application.min_redraw_interval`, but having this here is a |
| 1749 | + better approach.) |
| 1750 | + """ |
| 1751 | + while True: |
| 1752 | + self.on_completions_changed.fire() |
| 1753 | + refresh_needed.clear() |
| 1754 | + await asyncio.sleep(0.3) |
| 1755 | + await refresh_needed.wait() |
1744 | 1756 |
|
1745 |
| - # If the input text changes, abort. |
1746 |
| - if not proceed(): |
1747 |
| - break |
| 1757 | + refresh_task = asyncio.create_task(refresh_while_loading()) |
| 1758 | + try: |
| 1759 | + # Load. |
| 1760 | + async with aclosing( |
| 1761 | + self.completer.get_completions_async(document, complete_event) |
| 1762 | + ) as async_generator: |
| 1763 | + async for completion in async_generator: |
| 1764 | + complete_state.completions.append(completion) |
| 1765 | + refresh_needed.set() |
| 1766 | + |
| 1767 | + # If the input text changes, abort. |
| 1768 | + if not proceed(): |
| 1769 | + break |
| 1770 | + finally: |
| 1771 | + refresh_task.cancel() |
| 1772 | + |
| 1773 | + # Refresh one final time after we got everything. |
| 1774 | + self.on_completions_changed.fire() |
1748 | 1775 |
|
1749 | 1776 | completions = complete_state.completions
|
1750 | 1777 |
|
|
0 commit comments