10d24de9dSSimon Glass# Copyright (c) 2011 The Chromium OS Authors. 20d24de9dSSimon Glass# 31a459660SWolfgang Denk# SPDX-License-Identifier: GPL-2.0+ 40d24de9dSSimon Glass# 50d24de9dSSimon Glass 60d24de9dSSimon Glass"""Terminal utilities 70d24de9dSSimon Glass 80d24de9dSSimon GlassThis module handles terminal interaction including ANSI color codes. 90d24de9dSSimon Glass""" 100d24de9dSSimon Glass 11bbd01435SSimon Glassimport os 12bbd01435SSimon Glassimport sys 13bbd01435SSimon Glass 14bbd01435SSimon Glass# Selection of when we want our output to be colored 15bbd01435SSimon GlassCOLOR_IF_TERMINAL, COLOR_ALWAYS, COLOR_NEVER = range(3) 16bbd01435SSimon Glass 173c6c0f81SSimon Glass# Initially, we are set up to print to the terminal 183c6c0f81SSimon Glassprint_test_mode = False 193c6c0f81SSimon Glassprint_test_list = [] 203c6c0f81SSimon Glass 213c6c0f81SSimon Glassclass PrintLine: 223c6c0f81SSimon Glass """A line of text output 233c6c0f81SSimon Glass 243c6c0f81SSimon Glass Members: 253c6c0f81SSimon Glass text: Text line that was printed 263c6c0f81SSimon Glass newline: True to output a newline after the text 273c6c0f81SSimon Glass colour: Text colour to use 283c6c0f81SSimon Glass """ 293c6c0f81SSimon Glass def __init__(self, text, newline, colour): 303c6c0f81SSimon Glass self.text = text 313c6c0f81SSimon Glass self.newline = newline 323c6c0f81SSimon Glass self.colour = colour 333c6c0f81SSimon Glass 343c6c0f81SSimon Glass def __str__(self): 353c6c0f81SSimon Glass return 'newline=%s, colour=%s, text=%s' % (self.newline, self.colour, 363c6c0f81SSimon Glass self.text) 373c6c0f81SSimon Glass 383c6c0f81SSimon Glassdef Print(text='', newline=True, colour=None): 393c6c0f81SSimon Glass """Handle a line of output to the terminal. 403c6c0f81SSimon Glass 413c6c0f81SSimon Glass In test mode this is recorded in a list. Otherwise it is output to the 423c6c0f81SSimon Glass terminal. 433c6c0f81SSimon Glass 443c6c0f81SSimon Glass Args: 453c6c0f81SSimon Glass text: Text to print 463c6c0f81SSimon Glass newline: True to add a new line at the end of the text 473c6c0f81SSimon Glass colour: Colour to use for the text 483c6c0f81SSimon Glass """ 493c6c0f81SSimon Glass if print_test_mode: 503c6c0f81SSimon Glass print_test_list.append(PrintLine(text, newline, colour)) 513c6c0f81SSimon Glass else: 523c6c0f81SSimon Glass if colour: 533c6c0f81SSimon Glass col = Color() 543c6c0f81SSimon Glass text = col.Color(colour, text) 553c6c0f81SSimon Glass print text, 563c6c0f81SSimon Glass if newline: 573c6c0f81SSimon Glass print 58*8b4919edSSimon Glass else: 59*8b4919edSSimon Glass sys.stdout.flush() 603c6c0f81SSimon Glass 613c6c0f81SSimon Glassdef SetPrintTestMode(): 623c6c0f81SSimon Glass """Go into test mode, where all printing is recorded""" 633c6c0f81SSimon Glass global print_test_mode 643c6c0f81SSimon Glass 653c6c0f81SSimon Glass print_test_mode = True 663c6c0f81SSimon Glass 673c6c0f81SSimon Glassdef GetPrintTestLines(): 683c6c0f81SSimon Glass """Get a list of all lines output through Print() 693c6c0f81SSimon Glass 703c6c0f81SSimon Glass Returns: 713c6c0f81SSimon Glass A list of PrintLine objects 723c6c0f81SSimon Glass """ 733c6c0f81SSimon Glass global print_test_list 743c6c0f81SSimon Glass 753c6c0f81SSimon Glass ret = print_test_list 763c6c0f81SSimon Glass print_test_list = [] 773c6c0f81SSimon Glass return ret 783c6c0f81SSimon Glass 793c6c0f81SSimon Glassdef EchoPrintTestLines(): 803c6c0f81SSimon Glass """Print out the text lines collected""" 813c6c0f81SSimon Glass for line in print_test_list: 823c6c0f81SSimon Glass if line.colour: 833c6c0f81SSimon Glass col = Color() 843c6c0f81SSimon Glass print col.Color(line.colour, line.text), 853c6c0f81SSimon Glass else: 863c6c0f81SSimon Glass print line.text, 873c6c0f81SSimon Glass if line.newline: 883c6c0f81SSimon Glass print 893c6c0f81SSimon Glass 903c6c0f81SSimon Glass 910d24de9dSSimon Glassclass Color(object): 920d24de9dSSimon Glass """Conditionally wraps text in ANSI color escape sequences.""" 930d24de9dSSimon Glass BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8) 940d24de9dSSimon Glass BOLD = -1 9543bca004SSimon Glass BRIGHT_START = '\033[1;%dm' 9643bca004SSimon Glass NORMAL_START = '\033[22;%dm' 970d24de9dSSimon Glass BOLD_START = '\033[1m' 980d24de9dSSimon Glass RESET = '\033[0m' 990d24de9dSSimon Glass 100bbd01435SSimon Glass def __init__(self, colored=COLOR_IF_TERMINAL): 1010d24de9dSSimon Glass """Create a new Color object, optionally disabling color output. 1020d24de9dSSimon Glass 1030d24de9dSSimon Glass Args: 1040d24de9dSSimon Glass enabled: True if color output should be enabled. If False then this 1050d24de9dSSimon Glass class will not add color codes at all. 1060d24de9dSSimon Glass """ 107e752edcbSSimon Glass try: 108bbd01435SSimon Glass self._enabled = (colored == COLOR_ALWAYS or 109e752edcbSSimon Glass (colored == COLOR_IF_TERMINAL and 110e752edcbSSimon Glass os.isatty(sys.stdout.fileno()))) 111e752edcbSSimon Glass except: 112e752edcbSSimon Glass self._enabled = False 1130d24de9dSSimon Glass 11443bca004SSimon Glass def Start(self, color, bright=True): 1150d24de9dSSimon Glass """Returns a start color code. 1160d24de9dSSimon Glass 1170d24de9dSSimon Glass Args: 1180d24de9dSSimon Glass color: Color to use, .e.g BLACK, RED, etc. 1190d24de9dSSimon Glass 1200d24de9dSSimon Glass Returns: 1216ba5737fSSimon Glass If color is enabled, returns an ANSI sequence to start the given 1226ba5737fSSimon Glass color, otherwise returns empty string 1230d24de9dSSimon Glass """ 1240d24de9dSSimon Glass if self._enabled: 12543bca004SSimon Glass base = self.BRIGHT_START if bright else self.NORMAL_START 12643bca004SSimon Glass return base % (color + 30) 1270d24de9dSSimon Glass return '' 1280d24de9dSSimon Glass 1290d24de9dSSimon Glass def Stop(self): 1300d24de9dSSimon Glass """Retruns a stop color code. 1310d24de9dSSimon Glass 1320d24de9dSSimon Glass Returns: 1336ba5737fSSimon Glass If color is enabled, returns an ANSI color reset sequence, 1346ba5737fSSimon Glass otherwise returns empty string 1350d24de9dSSimon Glass """ 1360d24de9dSSimon Glass if self._enabled: 1370d24de9dSSimon Glass return self.RESET 1380d24de9dSSimon Glass return '' 1390d24de9dSSimon Glass 14043bca004SSimon Glass def Color(self, color, text, bright=True): 1410d24de9dSSimon Glass """Returns text with conditionally added color escape sequences. 1420d24de9dSSimon Glass 1430d24de9dSSimon Glass Keyword arguments: 1446ba5737fSSimon Glass color: Text color -- one of the color constants defined in this 1456ba5737fSSimon Glass class. 1460d24de9dSSimon Glass text: The text to color. 1470d24de9dSSimon Glass 1480d24de9dSSimon Glass Returns: 1490d24de9dSSimon Glass If self._enabled is False, returns the original text. If it's True, 1506ba5737fSSimon Glass returns text with color escape sequences based on the value of 1516ba5737fSSimon Glass color. 1520d24de9dSSimon Glass """ 1530d24de9dSSimon Glass if not self._enabled: 1540d24de9dSSimon Glass return text 1550d24de9dSSimon Glass if color == self.BOLD: 1560d24de9dSSimon Glass start = self.BOLD_START 1570d24de9dSSimon Glass else: 15843bca004SSimon Glass base = self.BRIGHT_START if bright else self.NORMAL_START 15943bca004SSimon Glass start = base % (color + 30) 1600d24de9dSSimon Glass return start + text + self.RESET 161