103 lines
3.5 KiB
Python
103 lines
3.5 KiB
Python
|
from __future__ import annotations
|
||
|
|
||
|
import sys
|
||
|
from typing import TextIO, cast
|
||
|
|
||
|
from prompt_toolkit.utils import (
|
||
|
get_bell_environment_variable,
|
||
|
get_term_environment_variable,
|
||
|
is_conemu_ansi,
|
||
|
)
|
||
|
|
||
|
from .base import DummyOutput, Output
|
||
|
from .color_depth import ColorDepth
|
||
|
from .plain_text import PlainTextOutput
|
||
|
|
||
|
__all__ = [
|
||
|
"create_output",
|
||
|
]
|
||
|
|
||
|
|
||
|
def create_output(
|
||
|
stdout: TextIO | None = None, always_prefer_tty: bool = False
|
||
|
) -> Output:
|
||
|
"""
|
||
|
Return an :class:`~prompt_toolkit.output.Output` instance for the command
|
||
|
line.
|
||
|
|
||
|
:param stdout: The stdout object
|
||
|
:param always_prefer_tty: When set, look for `sys.stderr` if `sys.stdout`
|
||
|
is not a TTY. Useful if `sys.stdout` is redirected to a file, but we
|
||
|
still want user input and output on the terminal.
|
||
|
|
||
|
By default, this is `False`. If `sys.stdout` is not a terminal (maybe
|
||
|
it's redirected to a file), then a `PlainTextOutput` will be returned.
|
||
|
That way, tools like `print_formatted_text` will write plain text into
|
||
|
that file.
|
||
|
"""
|
||
|
# Consider TERM, PROMPT_TOOLKIT_BELL, and PROMPT_TOOLKIT_COLOR_DEPTH
|
||
|
# environment variables. Notice that PROMPT_TOOLKIT_COLOR_DEPTH value is
|
||
|
# the default that's used if the Application doesn't override it.
|
||
|
term_from_env = get_term_environment_variable()
|
||
|
bell_from_env = get_bell_environment_variable()
|
||
|
color_depth_from_env = ColorDepth.from_env()
|
||
|
|
||
|
if stdout is None:
|
||
|
# By default, render to stdout. If the output is piped somewhere else,
|
||
|
# render to stderr.
|
||
|
stdout = sys.stdout
|
||
|
|
||
|
if always_prefer_tty:
|
||
|
for io in [sys.stdout, sys.stderr]:
|
||
|
if io is not None and io.isatty():
|
||
|
# (This is `None` when using `pythonw.exe` on Windows.)
|
||
|
stdout = io
|
||
|
break
|
||
|
|
||
|
# If the output is still `None`, use a DummyOutput.
|
||
|
# This happens for instance on Windows, when running the application under
|
||
|
# `pythonw.exe`. In that case, there won't be a terminal Window, and
|
||
|
# stdin/stdout/stderr are `None`.
|
||
|
if stdout is None:
|
||
|
return DummyOutput()
|
||
|
|
||
|
# If the patch_stdout context manager has been used, then sys.stdout is
|
||
|
# replaced by this proxy. For prompt_toolkit applications, we want to use
|
||
|
# the real stdout.
|
||
|
from prompt_toolkit.patch_stdout import StdoutProxy
|
||
|
|
||
|
while isinstance(stdout, StdoutProxy):
|
||
|
stdout = stdout.original_stdout
|
||
|
|
||
|
if sys.platform == "win32":
|
||
|
from .conemu import ConEmuOutput
|
||
|
from .win32 import Win32Output
|
||
|
from .windows10 import Windows10_Output, is_win_vt100_enabled
|
||
|
|
||
|
if is_win_vt100_enabled():
|
||
|
return cast(
|
||
|
Output,
|
||
|
Windows10_Output(stdout, default_color_depth=color_depth_from_env),
|
||
|
)
|
||
|
if is_conemu_ansi():
|
||
|
return cast(
|
||
|
Output, ConEmuOutput(stdout, default_color_depth=color_depth_from_env)
|
||
|
)
|
||
|
else:
|
||
|
return Win32Output(stdout, default_color_depth=color_depth_from_env)
|
||
|
else:
|
||
|
from .vt100 import Vt100_Output
|
||
|
|
||
|
# Stdout is not a TTY? Render as plain text.
|
||
|
# This is mostly useful if stdout is redirected to a file, and
|
||
|
# `print_formatted_text` is used.
|
||
|
if not stdout.isatty():
|
||
|
return PlainTextOutput(stdout)
|
||
|
|
||
|
return Vt100_Output.from_pty(
|
||
|
stdout,
|
||
|
term=term_from_env,
|
||
|
default_color_depth=color_depth_from_env,
|
||
|
enable_bell=bell_from_env,
|
||
|
)
|