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
7 changes: 7 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
.. currentmodule:: click

Version 8.x.x
--------------

- Fix readline functionality on Linux platforms. Prompt text is now passed
directly to readline instead of being printed separately, allowing proper
backspace, line editing, and line wrapping behavior. :issue:`2968` :pr:`2969`

Version 8.3.0
--------------

Expand Down
23 changes: 17 additions & 6 deletions src/click/termui.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
import sys
import typing as t
from contextlib import AbstractContextManager
from contextlib import redirect_stdout
from gettext import gettext as _

from ._compat import isatty
from ._compat import strip_ansi
from ._compat import WIN
from .exceptions import Abort
from .exceptions import UsageError
from .globals import resolve_color_default
Expand Down Expand Up @@ -136,12 +138,21 @@ def prompt(
def prompt_func(text: str) -> str:
f = hidden_prompt_func if hide_input else visible_prompt_func
try:
# Write the prompt separately so that we get nice
# coloring through colorama on Windows
echo(text.rstrip(" "), nl=False, err=err)
# Echo a space to stdout to work around an issue where
# readline causes backspace to clear the whole line.
return f(" ")
if WIN:
# Write the prompt separately so that we get nice
# coloring through colorama on Windows
echo(text.rstrip(" "), nl=False, err=err)
# Echo a space to stdout to work around an issue where
# readline causes backspace to clear the whole line.
return f(" ")
else:
# On non-Windows platforms, pass the full prompt to readline
# so it can properly handle line editing and cursor positioning
if err:
with redirect_stdout(sys.stderr):
return f(text)
else:
return f(text)
except (KeyboardInterrupt, EOFError):
# getpass doesn't print a newline if the user aborts input with ^C.
# Allegedly this behavior is inherited from getpass(3).
Expand Down
7 changes: 4 additions & 3 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ def f(_):
click.echo("interrupted")

out, err = capsys.readouterr()
assert out == "Password:\ninterrupted\n"
# On non-Windows, prompt is passed directly to getpass, not echoed separately
assert out == "\ninterrupted\n"


def test_prompts_eof(runner):
Expand Down Expand Up @@ -484,8 +485,8 @@ def emulate_input(text):
emulate_input("asdlkj\n")
click.prompt("Prompt to stderr", err=True)
out, err = capfd.readouterr()
assert out == " "
assert err == "Prompt to stderr:"
assert out == ""
assert err == "Prompt to stderr: "

emulate_input("y\n")
click.confirm("Prompt to stdin")
Expand Down
Loading