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 11*a920a17bSPaul Burtonfrom __future__ import print_function 12*a920a17bSPaul Burton 13bbd01435SSimon Glassimport os 14bbd01435SSimon Glassimport sys 15bbd01435SSimon Glass 16bbd01435SSimon Glass# Selection of when we want our output to be colored 17bbd01435SSimon GlassCOLOR_IF_TERMINAL, COLOR_ALWAYS, COLOR_NEVER = range(3) 18bbd01435SSimon Glass 193c6c0f81SSimon Glass# Initially, we are set up to print to the terminal 203c6c0f81SSimon Glassprint_test_mode = False 213c6c0f81SSimon Glassprint_test_list = [] 223c6c0f81SSimon Glass 233c6c0f81SSimon Glassclass PrintLine: 243c6c0f81SSimon Glass """A line of text output 253c6c0f81SSimon Glass 263c6c0f81SSimon Glass Members: 273c6c0f81SSimon Glass text: Text line that was printed 283c6c0f81SSimon Glass newline: True to output a newline after the text 293c6c0f81SSimon Glass colour: Text colour to use 303c6c0f81SSimon Glass """ 313c6c0f81SSimon Glass def __init__(self, text, newline, colour): 323c6c0f81SSimon Glass self.text = text 333c6c0f81SSimon Glass self.newline = newline 343c6c0f81SSimon Glass self.colour = colour 353c6c0f81SSimon Glass 363c6c0f81SSimon Glass def __str__(self): 373c6c0f81SSimon Glass return 'newline=%s, colour=%s, text=%s' % (self.newline, self.colour, 383c6c0f81SSimon Glass self.text) 393c6c0f81SSimon Glass 403c6c0f81SSimon Glassdef Print(text='', newline=True, colour=None): 413c6c0f81SSimon Glass """Handle a line of output to the terminal. 423c6c0f81SSimon Glass 433c6c0f81SSimon Glass In test mode this is recorded in a list. Otherwise it is output to the 443c6c0f81SSimon Glass terminal. 453c6c0f81SSimon Glass 463c6c0f81SSimon Glass Args: 473c6c0f81SSimon Glass text: Text to print 483c6c0f81SSimon Glass newline: True to add a new line at the end of the text 493c6c0f81SSimon Glass colour: Colour to use for the text 503c6c0f81SSimon Glass """ 513c6c0f81SSimon Glass if print_test_mode: 523c6c0f81SSimon Glass print_test_list.append(PrintLine(text, newline, colour)) 533c6c0f81SSimon Glass else: 543c6c0f81SSimon Glass if colour: 553c6c0f81SSimon Glass col = Color() 563c6c0f81SSimon Glass text = col.Color(colour, text) 57*a920a17bSPaul Burton print(text, end='') 583c6c0f81SSimon Glass if newline: 59*a920a17bSPaul Burton print() 608b4919edSSimon Glass else: 618b4919edSSimon Glass sys.stdout.flush() 623c6c0f81SSimon Glass 633c6c0f81SSimon Glassdef SetPrintTestMode(): 643c6c0f81SSimon Glass """Go into test mode, where all printing is recorded""" 653c6c0f81SSimon Glass global print_test_mode 663c6c0f81SSimon Glass 673c6c0f81SSimon Glass print_test_mode = True 683c6c0f81SSimon Glass 693c6c0f81SSimon Glassdef GetPrintTestLines(): 703c6c0f81SSimon Glass """Get a list of all lines output through Print() 713c6c0f81SSimon Glass 723c6c0f81SSimon Glass Returns: 733c6c0f81SSimon Glass A list of PrintLine objects 743c6c0f81SSimon Glass """ 753c6c0f81SSimon Glass global print_test_list 763c6c0f81SSimon Glass 773c6c0f81SSimon Glass ret = print_test_list 783c6c0f81SSimon Glass print_test_list = [] 793c6c0f81SSimon Glass return ret 803c6c0f81SSimon Glass 813c6c0f81SSimon Glassdef EchoPrintTestLines(): 823c6c0f81SSimon Glass """Print out the text lines collected""" 833c6c0f81SSimon Glass for line in print_test_list: 843c6c0f81SSimon Glass if line.colour: 853c6c0f81SSimon Glass col = Color() 86*a920a17bSPaul Burton print(col.Color(line.colour, line.text), end='') 873c6c0f81SSimon Glass else: 88*a920a17bSPaul Burton print(line.text, end='') 893c6c0f81SSimon Glass if line.newline: 90*a920a17bSPaul Burton print() 913c6c0f81SSimon Glass 923c6c0f81SSimon Glass 930d24de9dSSimon Glassclass Color(object): 940d24de9dSSimon Glass """Conditionally wraps text in ANSI color escape sequences.""" 950d24de9dSSimon Glass BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8) 960d24de9dSSimon Glass BOLD = -1 9743bca004SSimon Glass BRIGHT_START = '\033[1;%dm' 9843bca004SSimon Glass NORMAL_START = '\033[22;%dm' 990d24de9dSSimon Glass BOLD_START = '\033[1m' 1000d24de9dSSimon Glass RESET = '\033[0m' 1010d24de9dSSimon Glass 102bbd01435SSimon Glass def __init__(self, colored=COLOR_IF_TERMINAL): 1030d24de9dSSimon Glass """Create a new Color object, optionally disabling color output. 1040d24de9dSSimon Glass 1050d24de9dSSimon Glass Args: 1060d24de9dSSimon Glass enabled: True if color output should be enabled. If False then this 1070d24de9dSSimon Glass class will not add color codes at all. 1080d24de9dSSimon Glass """ 109e752edcbSSimon Glass try: 110bbd01435SSimon Glass self._enabled = (colored == COLOR_ALWAYS or 111e752edcbSSimon Glass (colored == COLOR_IF_TERMINAL and 112e752edcbSSimon Glass os.isatty(sys.stdout.fileno()))) 113e752edcbSSimon Glass except: 114e752edcbSSimon Glass self._enabled = False 1150d24de9dSSimon Glass 11643bca004SSimon Glass def Start(self, color, bright=True): 1170d24de9dSSimon Glass """Returns a start color code. 1180d24de9dSSimon Glass 1190d24de9dSSimon Glass Args: 1200d24de9dSSimon Glass color: Color to use, .e.g BLACK, RED, etc. 1210d24de9dSSimon Glass 1220d24de9dSSimon Glass Returns: 1236ba5737fSSimon Glass If color is enabled, returns an ANSI sequence to start the given 1246ba5737fSSimon Glass color, otherwise returns empty string 1250d24de9dSSimon Glass """ 1260d24de9dSSimon Glass if self._enabled: 12743bca004SSimon Glass base = self.BRIGHT_START if bright else self.NORMAL_START 12843bca004SSimon Glass return base % (color + 30) 1290d24de9dSSimon Glass return '' 1300d24de9dSSimon Glass 1310d24de9dSSimon Glass def Stop(self): 1320d24de9dSSimon Glass """Retruns a stop color code. 1330d24de9dSSimon Glass 1340d24de9dSSimon Glass Returns: 1356ba5737fSSimon Glass If color is enabled, returns an ANSI color reset sequence, 1366ba5737fSSimon Glass otherwise returns empty string 1370d24de9dSSimon Glass """ 1380d24de9dSSimon Glass if self._enabled: 1390d24de9dSSimon Glass return self.RESET 1400d24de9dSSimon Glass return '' 1410d24de9dSSimon Glass 14243bca004SSimon Glass def Color(self, color, text, bright=True): 1430d24de9dSSimon Glass """Returns text with conditionally added color escape sequences. 1440d24de9dSSimon Glass 1450d24de9dSSimon Glass Keyword arguments: 1466ba5737fSSimon Glass color: Text color -- one of the color constants defined in this 1476ba5737fSSimon Glass class. 1480d24de9dSSimon Glass text: The text to color. 1490d24de9dSSimon Glass 1500d24de9dSSimon Glass Returns: 1510d24de9dSSimon Glass If self._enabled is False, returns the original text. If it's True, 1526ba5737fSSimon Glass returns text with color escape sequences based on the value of 1536ba5737fSSimon Glass color. 1540d24de9dSSimon Glass """ 1550d24de9dSSimon Glass if not self._enabled: 1560d24de9dSSimon Glass return text 1570d24de9dSSimon Glass if color == self.BOLD: 1580d24de9dSSimon Glass start = self.BOLD_START 1590d24de9dSSimon Glass else: 16043bca004SSimon Glass base = self.BRIGHT_START if bright else self.NORMAL_START 16143bca004SSimon Glass start = base % (color + 30) 1620d24de9dSSimon Glass return start + text + self.RESET 163