Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/prompt_toolkit/key_binding/bindings/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ def _display_completions_like_readline(
term_width, max(get_cwidth(c.display_text) for c in completions) + 1
)
column_count = max(1, term_width // max_compl_width)
completions_per_page = column_count * (term_height - 1)
# Keep at least one row when the terminal has no room for the pager.
completions_per_page = column_count * max(1, term_height - 1)
page_count = int(math.ceil(len(completions) / float(completions_per_page)))
# Note: math.ceil can return float on Python2.

Expand Down
60 changes: 60 additions & 0 deletions tests/test_completion_bindings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from __future__ import annotations

import asyncio
from contextlib import asynccontextmanager
from importlib import import_module
from unittest.mock import AsyncMock, Mock

import pytest

from prompt_toolkit.application import Application
from prompt_toolkit.completion import Completion
from prompt_toolkit.data_structures import Size
from prompt_toolkit.formatted_text import fragment_list_to_text
from prompt_toolkit.input import DummyInput
from prompt_toolkit.key_binding.bindings import completion
from prompt_toolkit.output import DummyOutput


@pytest.mark.parametrize("rows, page_count", [(1, 3), (2, 3), (24, 1)])
def test_readline_completion_pagination_in_short_terminal(
monkeypatch, rows, page_count
):
class Output(DummyOutput):
def get_size(self):
return Size(rows=rows, columns=12)

@asynccontextmanager
async def in_terminal(**kwargs):
yield

confirm = AsyncMock(return_value=True)
more = AsyncMock(return_value=True)
monkeypatch.setattr(completion, "in_terminal", in_terminal)
monkeypatch.setattr(
import_module("prompt_toolkit.shortcuts.prompt"),
"create_confirm_session",
Mock(return_value=Mock(prompt_async=confirm)),
)
monkeypatch.setattr(
completion, "_create_more_session", Mock(return_value=Mock(prompt_async=more))
)
app = Application(input=DummyInput(), output=Output())
printed = Mock()
monkeypatch.setattr(app, "print_text", printed)
words = ["alpha", "bravo", "delta", "gamma", "omega", "sigma"]

async def run():
await completion._display_completions_like_readline(
app, [Completion(word) for word in words]
)

asyncio.run(run())

assert printed.call_count == page_count
assert confirm.await_count == (1 if page_count > 1 else 0)
assert more.await_count == page_count - 1
output = "".join(
fragment_list_to_text(call.args[0]) for call in printed.call_args_list
)
assert sorted(output.split()) == sorted(words)