|
13 | 13 | Union,
|
14 | 14 | cast,
|
15 | 15 | )
|
| 16 | +from weakref import WeakKeyDictionary, WeakValueDictionary |
16 | 17 |
|
17 | 18 | from prompt_toolkit.application.current import get_app
|
18 | 19 | from prompt_toolkit.buffer import CompletionState
|
@@ -333,6 +334,16 @@ def __init__(self, min_rows: int = 3, suggested_max_column_width: int = 30) -> N
|
333 | 334 | self.suggested_max_column_width = suggested_max_column_width
|
334 | 335 | self.scroll = 0
|
335 | 336 |
|
| 337 | + # Cache for column width computations. This computation is not cheap, |
| 338 | + # so we don't want to do it over and over again while the user |
| 339 | + # navigates through the completions. |
| 340 | + # (map `completion_state` to `(completion_count, width)`. We remember |
| 341 | + # the count, because a completer can add new completions to the |
| 342 | + # `CompletionState` while loading.) |
| 343 | + self._column_width_for_completion_state: "WeakKeyDictionary[CompletionState, Tuple[int, int]]" = ( |
| 344 | + WeakKeyDictionary() |
| 345 | + ) |
| 346 | + |
336 | 347 | # Info of last rendering.
|
337 | 348 | self._rendered_rows = 0
|
338 | 349 | self._rendered_columns = 0
|
@@ -509,11 +520,26 @@ def get_line(i: int) -> StyleAndTextTuples:
|
509 | 520 |
|
510 | 521 | return UIContent(get_line=get_line, line_count=len(rows_))
|
511 | 522 |
|
512 |
| - def _get_column_width(self, complete_state: CompletionState) -> int: |
| 523 | + def _get_column_width(self, completion_state: CompletionState) -> int: |
513 | 524 | """
|
514 | 525 | Return the width of each column.
|
515 | 526 | """
|
516 |
| - return max(get_cwidth(c.display_text) for c in complete_state.completions) + 1 |
| 527 | + try: |
| 528 | + count, width = self._column_width_for_completion_state[completion_state] |
| 529 | + if count != len(completion_state.completions): |
| 530 | + # Number of completions changed, recompute. |
| 531 | + raise KeyError |
| 532 | + return width |
| 533 | + except KeyError: |
| 534 | + result = ( |
| 535 | + max(get_cwidth(c.display_text) for c in completion_state.completions) |
| 536 | + + 1 |
| 537 | + ) |
| 538 | + self._column_width_for_completion_state[completion_state] = ( |
| 539 | + len(completion_state.completions), |
| 540 | + result, |
| 541 | + ) |
| 542 | + return result |
517 | 543 |
|
518 | 544 | def mouse_handler(self, mouse_event: MouseEvent) -> "NotImplementedOrNone":
|
519 | 545 | """
|
|
0 commit comments