Skip to content
65 changes: 46 additions & 19 deletions src/click/_termui_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import typing as t
from gettext import gettext as _
from io import StringIO
from shutil import which
from types import TracebackType

from ._compat import _default_text_stdout
Expand Down Expand Up @@ -377,16 +378,16 @@ def pager(generator: t.Iterable[str], color: t.Optional[bool] = None) -> None:
if os.environ.get("TERM") in ("dumb", "emacs"):
return _nullpager(stdout, generator, color)
if WIN or sys.platform.startswith("os2"):
return _tempfilepager(generator, "more <", color)
if hasattr(os, "system") and os.system("(less) 2>/dev/null") == 0:
return _tempfilepager(generator, "more", color, pipe=True)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed _pipepager exists now. Should we not use that instead here and remove the pipe argument I introduced?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that works as well, I'm usually in favor of avoiding new arguments.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try to test this on Windows and get this merged then.

if which("less") is not None:
return _pipepager(generator, "less", color)

import tempfile

fd, filename = tempfile.mkstemp()
os.close(fd)
try:
if hasattr(os, "system") and os.system(f'more "{filename}"') == 0:
if which("more") is not None:
return _pipepager(generator, "more", color)
return _nullpager(stdout, generator, color)
finally:
Expand Down Expand Up @@ -444,9 +445,17 @@ def _pipepager(generator: t.Iterable[str], cmd: str, color: t.Optional[bool]) ->


def _tempfilepager(
generator: t.Iterable[str], cmd: str, color: t.Optional[bool]
generator: t.Iterable[str],
cmd: str,
color: t.Optional[bool],
pipe: bool = False,
) -> None:
"""Page through text by invoking a program on a temporary file."""
"""Page through text by invoking a program on a temporary file.

By default executes `cmd` as `cmd tmpfile`. If `pipe` is `True`, it will
instead pipe the text via stdin like `cat tmpfile | cmd`.
"""
import subprocess
import tempfile

fd, filename = tempfile.mkstemp()
Expand All @@ -458,7 +467,14 @@ def _tempfilepager(
with open_stream(filename, "wb")[0] as f:
f.write(text.encode(encoding))
try:
os.system(f'{cmd} "{filename}"')
if pipe:
with open_stream(filename, "rb")[0] as f:
subprocess.call([cmd], stdin=f)
else:
subprocess.call([cmd, filename])
except OSError:
# Command not found
pass
finally:
os.close(fd)
os.unlink(filename)
Expand Down Expand Up @@ -497,7 +513,7 @@ def get_editor(self) -> str:
if WIN:
return "notepad"
for editor in "sensible-editor", "vim", "nano":
if os.system(f"which {editor} >/dev/null 2>&1") == 0:
if which(editor) is not None:
return editor
return "vi"

Expand Down Expand Up @@ -596,22 +612,33 @@ def _unquote_file(url: str) -> str:
null.close()
elif WIN:
if locate:
url = _unquote_file(url.replace('"', ""))
args = f'explorer /select,"{url}"'
url = _unquote_file(url)
args = ["explorer", f"/select,{url}"]
else:
url = url.replace('"', "")
wait_str = "/WAIT" if wait else ""
args = f'start {wait_str} "" "{url}"'
return os.system(args)
args = ["start"]
if wait:
args.append("/WAIT")
args.append("")
args.append(url)
try:
return subprocess.call(args)
except OSError:
# Command not found
return 127
elif CYGWIN:
if locate:
url = os.path.dirname(_unquote_file(url).replace('"', ""))
args = f'cygstart "{url}"'
url = _unquote_file(url)
args = ["cygstart", os.path.dirname(url)]
else:
url = url.replace('"', "")
wait_str = "-w" if wait else ""
args = f'cygstart {wait_str} "{url}"'
return os.system(args)
args = ["cygstart"]
if wait:
args.append("-w")
args.append(url)
try:
return subprocess.call(args)
except OSError:
# Command not found
return 127

try:
if locate:
Expand Down
1 change: 1 addition & 0 deletions tests/test_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def tracking_import(module, locals=None, globals=None, fromlist=None,
"typing",
"types",
"gettext",
"shutil",
}

if WIN:
Expand Down