diff --git a/README.md b/README.md index 8afef9bc..db813af9 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,8 @@ answers = inquirer.prompt(questions) List questions can take one extra argument `carousel=False`. If set to true, the answers will rotate (back to first when pressing down on last choice, and down to last choice when pressing up on first choice) +Besides the arrow keys, `Page Up` and `Page Down` move the selection a full page at a time, which is handy for long lists. When `carousel` is enabled they wrap around just like the arrow keys. + ### Checkbox Shows a list of choices, with multiple selection. @@ -116,6 +118,8 @@ answers = inquirer.prompt(questions) Checkbox questions can take extra argument `carousel=False`. If set to true, the answers will rotate (back to first when pressing down on last choice, and down to last choice when pressing up on first choice) +As with `List`, `Page Up` and `Page Down` move the cursor a full page at a time and wrap around when `carousel` is enabled. + Another argument that can be used is `locked=`. The given choices in the locked argument cannot be removed. This is useful if you want to make clear that a specific option out of the choices must be chosen. ### Path diff --git a/src/inquirer/render/console/_checkbox.py b/src/inquirer/render/console/_checkbox.py index 6e40c5bd..43e53a0c 100644 --- a/src/inquirer/render/console/_checkbox.py +++ b/src/inquirer/render/console/_checkbox.py @@ -96,6 +96,18 @@ def process_input(self, pressed): else: self.current = min(len(self.question.choices) - 1, self.current + 1) return + elif pressed == key.PAGE_UP: + if question.carousel and self.current == 0: + self.current = len(question.choices) - 1 + else: + self.current = max(0, self.current - MAX_OPTIONS_DISPLAYED_AT_ONCE) + return + elif pressed == key.PAGE_DOWN: + if question.carousel and self.current == len(question.choices) - 1: + self.current = 0 + else: + self.current = min(len(self.question.choices) - 1, self.current + MAX_OPTIONS_DISPLAYED_AT_ONCE) + return elif pressed == key.SPACE: if self.question.choices[self.current] == GLOBAL_OTHER_CHOICE: self.other_input() diff --git a/src/inquirer/render/console/_list.py b/src/inquirer/render/console/_list.py index 38ac2baa..fced9a4e 100644 --- a/src/inquirer/render/console/_list.py +++ b/src/inquirer/render/console/_list.py @@ -78,6 +78,18 @@ def process_input(self, pressed): else: self.current = min(len(self.question.choices) - 1, self.current + 1) return + if pressed == key.PAGE_UP: + if question.carousel and self.current == 0: + self.current = len(question.choices) - 1 + else: + self.current = max(0, self.current - MAX_OPTIONS_DISPLAYED_AT_ONCE) + return + if pressed == key.PAGE_DOWN: + if question.carousel and self.current == len(question.choices) - 1: + self.current = 0 + else: + self.current = min(len(self.question.choices) - 1, self.current + MAX_OPTIONS_DISPLAYED_AT_ONCE) + return if pressed == key.ENTER: value = self.question.choices[self.current] diff --git a/tests/integration/console_render/test_checkbox.py b/tests/integration/console_render/test_checkbox.py index f1531971..9c49e034 100644 --- a/tests/integration/console_render/test_checkbox.py +++ b/tests/integration/console_render/test_checkbox.py @@ -428,3 +428,58 @@ def test_second_hint_is_shown(self): sut.render(question) self.assertInStdout("Bar") + + def test_page_down_jumps_a_page(self): + stdin = helper.event_factory(key.PAGE_DOWN, key.SPACE, key.ENTER) + choices = list(range(20)) + + question = questions.Checkbox("number", "Number message", choices=choices) + + sut = ConsoleRender(event_generator=stdin) + result = sut.render(question) + + assert result == [13] + + def test_page_up_jumps_a_page(self): + stdin = helper.event_factory(key.PAGE_DOWN, key.PAGE_UP, key.SPACE, key.ENTER) + choices = list(range(20)) + + question = questions.Checkbox("number", "Number message", choices=choices) + + sut = ConsoleRender(event_generator=stdin) + result = sut.render(question) + + assert result == [0] + + def test_page_down_stops_at_the_last_choice(self): + stdin = helper.event_factory(key.PAGE_DOWN, key.PAGE_DOWN, key.SPACE, key.ENTER) + choices = list(range(20)) + + question = questions.Checkbox("number", "Number message", choices=choices) + + sut = ConsoleRender(event_generator=stdin) + result = sut.render(question) + + assert result == [19] + + def test_page_up_wraps_when_carousel_is_enabled(self): + stdin = helper.event_factory(key.PAGE_UP, key.SPACE, key.ENTER) + choices = list(range(20)) + + question = questions.Checkbox("number", "Number message", choices=choices, carousel=True) + + sut = ConsoleRender(event_generator=stdin) + result = sut.render(question) + + assert result == [19] + + def test_page_down_wraps_when_carousel_is_enabled(self): + stdin = helper.event_factory(key.PAGE_DOWN, key.PAGE_DOWN, key.PAGE_DOWN, key.SPACE, key.ENTER) + choices = list(range(20)) + + question = questions.Checkbox("number", "Number message", choices=choices, carousel=True) + + sut = ConsoleRender(event_generator=stdin) + result = sut.render(question) + + assert result == [0] diff --git a/tests/integration/console_render/test_list.py b/tests/integration/console_render/test_list.py index 7cd3dea7..a7e1dd60 100644 --- a/tests/integration/console_render/test_list.py +++ b/tests/integration/console_render/test_list.py @@ -181,3 +181,58 @@ def test_taggedValue_with_dict(self): sut.render(question) self.assertInStdout("bb") + + def test_page_down_jumps_a_page(self): + stdin = helper.event_factory(key.PAGE_DOWN, key.ENTER) + choices = list(range(20)) + + question = questions.List("number", "Number message", choices=choices) + + sut = ConsoleRender(event_generator=stdin) + result = sut.render(question) + + assert result == 13 + + def test_page_up_jumps_a_page(self): + stdin = helper.event_factory(key.PAGE_DOWN, key.PAGE_UP, key.ENTER) + choices = list(range(20)) + + question = questions.List("number", "Number message", choices=choices) + + sut = ConsoleRender(event_generator=stdin) + result = sut.render(question) + + assert result == 0 + + def test_page_down_stops_at_the_last_choice(self): + stdin = helper.event_factory(key.PAGE_DOWN, key.PAGE_DOWN, key.ENTER) + choices = list(range(20)) + + question = questions.List("number", "Number message", choices=choices) + + sut = ConsoleRender(event_generator=stdin) + result = sut.render(question) + + assert result == 19 + + def test_page_up_wraps_when_carousel_is_enabled(self): + stdin = helper.event_factory(key.PAGE_UP, key.ENTER) + choices = list(range(20)) + + question = questions.List("number", "Number message", choices=choices, carousel=True) + + sut = ConsoleRender(event_generator=stdin) + result = sut.render(question) + + assert result == 19 + + def test_page_down_wraps_when_carousel_is_enabled(self): + stdin = helper.event_factory(key.PAGE_DOWN, key.PAGE_DOWN, key.PAGE_DOWN, key.ENTER) + choices = list(range(20)) + + question = questions.List("number", "Number message", choices=choices, carousel=True) + + sut = ConsoleRender(event_generator=stdin) + result = sut.render(question) + + assert result == 0