terminal.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. # Copyright (c) 2011 The Chromium OS Authors.
  2. #
  3. # SPDX-License-Identifier: GPL-2.0+
  4. #
  5. """Terminal utilities
  6. This module handles terminal interaction including ANSI color codes.
  7. """
  8. import os
  9. import sys
  10. # Selection of when we want our output to be colored
  11. COLOR_IF_TERMINAL, COLOR_ALWAYS, COLOR_NEVER = range(3)
  12. # Initially, we are set up to print to the terminal
  13. print_test_mode = False
  14. print_test_list = []
  15. class PrintLine:
  16. """A line of text output
  17. Members:
  18. text: Text line that was printed
  19. newline: True to output a newline after the text
  20. colour: Text colour to use
  21. """
  22. def __init__(self, text, newline, colour):
  23. self.text = text
  24. self.newline = newline
  25. self.colour = colour
  26. def __str__(self):
  27. return 'newline=%s, colour=%s, text=%s' % (self.newline, self.colour,
  28. self.text)
  29. def Print(text='', newline=True, colour=None):
  30. """Handle a line of output to the terminal.
  31. In test mode this is recorded in a list. Otherwise it is output to the
  32. terminal.
  33. Args:
  34. text: Text to print
  35. newline: True to add a new line at the end of the text
  36. colour: Colour to use for the text
  37. """
  38. if print_test_mode:
  39. print_test_list.append(PrintLine(text, newline, colour))
  40. else:
  41. if colour:
  42. col = Color()
  43. text = col.Color(colour, text)
  44. print text,
  45. if newline:
  46. print
  47. def SetPrintTestMode():
  48. """Go into test mode, where all printing is recorded"""
  49. global print_test_mode
  50. print_test_mode = True
  51. def GetPrintTestLines():
  52. """Get a list of all lines output through Print()
  53. Returns:
  54. A list of PrintLine objects
  55. """
  56. global print_test_list
  57. ret = print_test_list
  58. print_test_list = []
  59. return ret
  60. def EchoPrintTestLines():
  61. """Print out the text lines collected"""
  62. for line in print_test_list:
  63. if line.colour:
  64. col = Color()
  65. print col.Color(line.colour, line.text),
  66. else:
  67. print line.text,
  68. if line.newline:
  69. print
  70. class Color(object):
  71. """Conditionally wraps text in ANSI color escape sequences."""
  72. BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
  73. BOLD = -1
  74. BRIGHT_START = '\033[1;%dm'
  75. NORMAL_START = '\033[22;%dm'
  76. BOLD_START = '\033[1m'
  77. RESET = '\033[0m'
  78. def __init__(self, colored=COLOR_IF_TERMINAL):
  79. """Create a new Color object, optionally disabling color output.
  80. Args:
  81. enabled: True if color output should be enabled. If False then this
  82. class will not add color codes at all.
  83. """
  84. try:
  85. self._enabled = (colored == COLOR_ALWAYS or
  86. (colored == COLOR_IF_TERMINAL and
  87. os.isatty(sys.stdout.fileno())))
  88. except:
  89. self._enabled = False
  90. def Start(self, color, bright=True):
  91. """Returns a start color code.
  92. Args:
  93. color: Color to use, .e.g BLACK, RED, etc.
  94. Returns:
  95. If color is enabled, returns an ANSI sequence to start the given
  96. color, otherwise returns empty string
  97. """
  98. if self._enabled:
  99. base = self.BRIGHT_START if bright else self.NORMAL_START
  100. return base % (color + 30)
  101. return ''
  102. def Stop(self):
  103. """Retruns a stop color code.
  104. Returns:
  105. If color is enabled, returns an ANSI color reset sequence,
  106. otherwise returns empty string
  107. """
  108. if self._enabled:
  109. return self.RESET
  110. return ''
  111. def Color(self, color, text, bright=True):
  112. """Returns text with conditionally added color escape sequences.
  113. Keyword arguments:
  114. color: Text color -- one of the color constants defined in this
  115. class.
  116. text: The text to color.
  117. Returns:
  118. If self._enabled is False, returns the original text. If it's True,
  119. returns text with color escape sequences based on the value of
  120. color.
  121. """
  122. if not self._enabled:
  123. return text
  124. if color == self.BOLD:
  125. start = self.BOLD_START
  126. else:
  127. base = self.BRIGHT_START if bright else self.NORMAL_START
  128. start = base % (color + 30)
  129. return start + text + self.RESET