defaults.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. from __future__ import annotations
  2. import sys
  3. from typing import TYPE_CHECKING, TextIO, cast
  4. from prompt_toolkit.utils import (
  5. get_bell_environment_variable,
  6. get_term_environment_variable,
  7. is_conemu_ansi,
  8. )
  9. from .base import DummyOutput, Output
  10. from .color_depth import ColorDepth
  11. from .plain_text import PlainTextOutput
  12. if TYPE_CHECKING:
  13. from prompt_toolkit.patch_stdout import StdoutProxy
  14. __all__ = [
  15. "create_output",
  16. ]
  17. def create_output(
  18. stdout: TextIO | StdoutProxy | None = None, always_prefer_tty: bool = False
  19. ) -> Output:
  20. """
  21. Return an :class:`~prompt_toolkit.output.Output` instance for the command
  22. line.
  23. :param stdout: The stdout object
  24. :param always_prefer_tty: When set, look for `sys.stderr` if `sys.stdout`
  25. is not a TTY. Useful if `sys.stdout` is redirected to a file, but we
  26. still want user input and output on the terminal.
  27. By default, this is `False`. If `sys.stdout` is not a terminal (maybe
  28. it's redirected to a file), then a `PlainTextOutput` will be returned.
  29. That way, tools like `print_formatted_text` will write plain text into
  30. that file.
  31. """
  32. # Consider TERM, PROMPT_TOOLKIT_BELL, and PROMPT_TOOLKIT_COLOR_DEPTH
  33. # environment variables. Notice that PROMPT_TOOLKIT_COLOR_DEPTH value is
  34. # the default that's used if the Application doesn't override it.
  35. term_from_env = get_term_environment_variable()
  36. bell_from_env = get_bell_environment_variable()
  37. color_depth_from_env = ColorDepth.from_env()
  38. if stdout is None:
  39. # By default, render to stdout. If the output is piped somewhere else,
  40. # render to stderr.
  41. stdout = sys.stdout
  42. if always_prefer_tty:
  43. for io in [sys.stdout, sys.stderr]:
  44. if io is not None and io.isatty():
  45. # (This is `None` when using `pythonw.exe` on Windows.)
  46. stdout = io
  47. break
  48. # If the patch_stdout context manager has been used, then sys.stdout is
  49. # replaced by this proxy. For prompt_toolkit applications, we want to use
  50. # the real stdout.
  51. from prompt_toolkit.patch_stdout import StdoutProxy
  52. while isinstance(stdout, StdoutProxy):
  53. stdout = stdout.original_stdout
  54. # If the output is still `None`, use a DummyOutput.
  55. # This happens for instance on Windows, when running the application under
  56. # `pythonw.exe`. In that case, there won't be a terminal Window, and
  57. # stdin/stdout/stderr are `None`.
  58. if stdout is None:
  59. return DummyOutput()
  60. if sys.platform == "win32":
  61. from .conemu import ConEmuOutput
  62. from .win32 import Win32Output
  63. from .windows10 import Windows10_Output, is_win_vt100_enabled
  64. if is_win_vt100_enabled():
  65. return cast(
  66. Output,
  67. Windows10_Output(stdout, default_color_depth=color_depth_from_env),
  68. )
  69. if is_conemu_ansi():
  70. return cast(
  71. Output, ConEmuOutput(stdout, default_color_depth=color_depth_from_env)
  72. )
  73. else:
  74. return Win32Output(stdout, default_color_depth=color_depth_from_env)
  75. else:
  76. from .vt100 import Vt100_Output
  77. # Stdout is not a TTY? Render as plain text.
  78. # This is mostly useful if stdout is redirected to a file, and
  79. # `print_formatted_text` is used.
  80. if not stdout.isatty():
  81. return PlainTextOutput(stdout)
  82. return Vt100_Output.from_pty(
  83. stdout,
  84. term=term_from_env,
  85. default_color_depth=color_depth_from_env,
  86. enable_bell=bell_from_env,
  87. )