From a24303efafebd553f82ba8fd6b4772a9920f680a Mon Sep 17 00:00:00 2001 From: x0Lazarus <113273587+x0Lazarus@users.noreply.github.com> Date: Sat, 26 Sep 2026 11:43:40 -0700 Subject: [PATCH] Hide placeholders after a prompt finishes --- src/prompt_toolkit/shortcuts/prompt.py | 2 +- tests/test_shortcuts.py | 40 +++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/prompt_toolkit/shortcuts/prompt.py b/src/prompt_toolkit/shortcuts/prompt.py index f14ecd80c..8afd8f8a7 100644 --- a/src/prompt_toolkit/shortcuts/prompt.py +++ b/src/prompt_toolkit/shortcuts/prompt.py @@ -581,7 +581,7 @@ def display_placeholder() -> bool: DynamicProcessor(lambda: merge_processors(self.input_processors or [])), ConditionalProcessor( AfterInput(lambda: self.placeholder), - filter=display_placeholder, + filter=display_placeholder & ~is_done, ), ] diff --git a/tests/test_shortcuts.py b/tests/test_shortcuts.py index 287c6d33a..7e8a6c97e 100644 --- a/tests/test_shortcuts.py +++ b/tests/test_shortcuts.py @@ -1,10 +1,48 @@ from __future__ import annotations -from prompt_toolkit.shortcuts import print_container +import pytest + +from prompt_toolkit import renderer +from prompt_toolkit.formatted_text import ANSI +from prompt_toolkit.input.defaults import create_pipe_input +from prompt_toolkit.output import DummyOutput +from prompt_toolkit.shortcuts import PromptSession, print_container from prompt_toolkit.shortcuts.prompt import _split_multiline_prompt from prompt_toolkit.widgets import Frame, TextArea +@pytest.mark.parametrize( + "placeholder", ["Type a value", ANSI("\x1b[90mType a value\x1b[0m")] +) +@pytest.mark.parametrize("text", ["", "hello"]) +def test_placeholder_is_hidden_after_accepting_input(mocker, placeholder, text): + draw = mocker.spy(renderer, "_output_screen_diff") + with create_pipe_input() as inp: + session = PromptSession( + "Question: ", + placeholder=placeholder, + input=inp, + output=DummyOutput(), + ) + inp.send_text(text + "\r") + assert session.prompt() == text + + # Inspect the actual screens sent to the output, including the final redraw. + screens = [] + for call in draw.call_args_list: + screen, is_done = call.args[2], call.args[7] + content = "\n".join( + "".join(char.char for _, char in sorted(row.items())).rstrip() + for _, row in sorted(screen.data_buffer.items()) + ).rstrip() + screens.append((is_done, content)) + + assert any("Type a value" in content for is_done, content in screens if not is_done) + assert [content for is_done, content in screens if is_done] == [ + ("Question: " + text).rstrip() + ] + + def test_split_multiline_prompt(): # Test 1: no newlines: tokens = [("class:testclass", "ab")]