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 17*3c6c0f81SSimon Glass# Initially, we are set up to print to the terminal 18*3c6c0f81SSimon Glassprint_test_mode = False 19*3c6c0f81SSimon Glassprint_test_list = [] 20*3c6c0f81SSimon Glass 21*3c6c0f81SSimon Glassclass PrintLine: 22*3c6c0f81SSimon Glass """A line of text output 23*3c6c0f81SSimon Glass 24*3c6c0f81SSimon Glass Members: 25*3c6c0f81SSimon Glass text: Text line that was printed 26*3c6c0f81SSimon Glass newline: True to output a newline after the text 27*3c6c0f81SSimon Glass colour: Text colour to use 28*3c6c0f81SSimon Glass """ 29*3c6c0f81SSimon Glass def __init__(self, text, newline, colour): 30*3c6c0f81SSimon Glass self.text = text 31*3c6c0f81SSimon Glass self.newline = newline 32*3c6c0f81SSimon Glass self.colour = colour 33*3c6c0f81SSimon Glass 34*3c6c0f81SSimon Glass def __str__(self): 35*3c6c0f81SSimon Glass return 'newline=%s, colour=%s, text=%s' % (self.newline, self.colour, 36*3c6c0f81SSimon Glass self.text) 37*3c6c0f81SSimon Glass 38*3c6c0f81SSimon Glassdef Print(text='', newline=True, colour=None): 39*3c6c0f81SSimon Glass """Handle a line of output to the terminal. 40*3c6c0f81SSimon Glass 41*3c6c0f81SSimon Glass In test mode this is recorded in a list. Otherwise it is output to the 42*3c6c0f81SSimon Glass terminal. 43*3c6c0f81SSimon Glass 44*3c6c0f81SSimon Glass Args: 45*3c6c0f81SSimon Glass text: Text to print 46*3c6c0f81SSimon Glass newline: True to add a new line at the end of the text 47*3c6c0f81SSimon Glass colour: Colour to use for the text 48*3c6c0f81SSimon Glass """ 49*3c6c0f81SSimon Glass if print_test_mode: 50*3c6c0f81SSimon Glass print_test_list.append(PrintLine(text, newline, colour)) 51*3c6c0f81SSimon Glass else: 52*3c6c0f81SSimon Glass if colour: 53*3c6c0f81SSimon Glass col = Color() 54*3c6c0f81SSimon Glass text = col.Color(colour, text) 55*3c6c0f81SSimon Glass print text, 56*3c6c0f81SSimon Glass if newline: 57*3c6c0f81SSimon Glass print 58*3c6c0f81SSimon Glass 59*3c6c0f81SSimon Glassdef SetPrintTestMode(): 60*3c6c0f81SSimon Glass """Go into test mode, where all printing is recorded""" 61*3c6c0f81SSimon Glass global print_test_mode 62*3c6c0f81SSimon Glass 63*3c6c0f81SSimon Glass print_test_mode = True 64*3c6c0f81SSimon Glass 65*3c6c0f81SSimon Glassdef GetPrintTestLines(): 66*3c6c0f81SSimon Glass """Get a list of all lines output through Print() 67*3c6c0f81SSimon Glass 68*3c6c0f81SSimon Glass Returns: 69*3c6c0f81SSimon Glass A list of PrintLine objects 70*3c6c0f81SSimon Glass """ 71*3c6c0f81SSimon Glass global print_test_list 72*3c6c0f81SSimon Glass 73*3c6c0f81SSimon Glass ret = print_test_list 74*3c6c0f81SSimon Glass print_test_list = [] 75*3c6c0f81SSimon Glass return ret 76*3c6c0f81SSimon Glass 77*3c6c0f81SSimon Glassdef EchoPrintTestLines(): 78*3c6c0f81SSimon Glass """Print out the text lines collected""" 79*3c6c0f81SSimon Glass for line in print_test_list: 80*3c6c0f81SSimon Glass if line.colour: 81*3c6c0f81SSimon Glass col = Color() 82*3c6c0f81SSimon Glass print col.Color(line.colour, line.text), 83*3c6c0f81SSimon Glass else: 84*3c6c0f81SSimon Glass print line.text, 85*3c6c0f81SSimon Glass if line.newline: 86*3c6c0f81SSimon Glass print 87*3c6c0f81SSimon Glass 88*3c6c0f81SSimon Glass 890d24de9dSSimon Glassclass Color(object): 900d24de9dSSimon Glass """Conditionally wraps text in ANSI color escape sequences.""" 910d24de9dSSimon Glass BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8) 920d24de9dSSimon Glass BOLD = -1 9343bca004SSimon Glass BRIGHT_START = '\033[1;%dm' 9443bca004SSimon Glass NORMAL_START = '\033[22;%dm' 950d24de9dSSimon Glass BOLD_START = '\033[1m' 960d24de9dSSimon Glass RESET = '\033[0m' 970d24de9dSSimon Glass 98bbd01435SSimon Glass def __init__(self, colored=COLOR_IF_TERMINAL): 990d24de9dSSimon Glass """Create a new Color object, optionally disabling color output. 1000d24de9dSSimon Glass 1010d24de9dSSimon Glass Args: 1020d24de9dSSimon Glass enabled: True if color output should be enabled. If False then this 1030d24de9dSSimon Glass class will not add color codes at all. 1040d24de9dSSimon Glass """ 105e752edcbSSimon Glass try: 106bbd01435SSimon Glass self._enabled = (colored == COLOR_ALWAYS or 107e752edcbSSimon Glass (colored == COLOR_IF_TERMINAL and 108e752edcbSSimon Glass os.isatty(sys.stdout.fileno()))) 109e752edcbSSimon Glass except: 110e752edcbSSimon Glass self._enabled = False 1110d24de9dSSimon Glass 11243bca004SSimon Glass def Start(self, color, bright=True): 1130d24de9dSSimon Glass """Returns a start color code. 1140d24de9dSSimon Glass 1150d24de9dSSimon Glass Args: 1160d24de9dSSimon Glass color: Color to use, .e.g BLACK, RED, etc. 1170d24de9dSSimon Glass 1180d24de9dSSimon Glass Returns: 1196ba5737fSSimon Glass If color is enabled, returns an ANSI sequence to start the given 1206ba5737fSSimon Glass color, otherwise returns empty string 1210d24de9dSSimon Glass """ 1220d24de9dSSimon Glass if self._enabled: 12343bca004SSimon Glass base = self.BRIGHT_START if bright else self.NORMAL_START 12443bca004SSimon Glass return base % (color + 30) 1250d24de9dSSimon Glass return '' 1260d24de9dSSimon Glass 1270d24de9dSSimon Glass def Stop(self): 1280d24de9dSSimon Glass """Retruns a stop color code. 1290d24de9dSSimon Glass 1300d24de9dSSimon Glass Returns: 1316ba5737fSSimon Glass If color is enabled, returns an ANSI color reset sequence, 1326ba5737fSSimon Glass otherwise returns empty string 1330d24de9dSSimon Glass """ 1340d24de9dSSimon Glass if self._enabled: 1350d24de9dSSimon Glass return self.RESET 1360d24de9dSSimon Glass return '' 1370d24de9dSSimon Glass 13843bca004SSimon Glass def Color(self, color, text, bright=True): 1390d24de9dSSimon Glass """Returns text with conditionally added color escape sequences. 1400d24de9dSSimon Glass 1410d24de9dSSimon Glass Keyword arguments: 1426ba5737fSSimon Glass color: Text color -- one of the color constants defined in this 1436ba5737fSSimon Glass class. 1440d24de9dSSimon Glass text: The text to color. 1450d24de9dSSimon Glass 1460d24de9dSSimon Glass Returns: 1470d24de9dSSimon Glass If self._enabled is False, returns the original text. If it's True, 1486ba5737fSSimon Glass returns text with color escape sequences based on the value of 1496ba5737fSSimon Glass color. 1500d24de9dSSimon Glass """ 1510d24de9dSSimon Glass if not self._enabled: 1520d24de9dSSimon Glass return text 1530d24de9dSSimon Glass if color == self.BOLD: 1540d24de9dSSimon Glass start = self.BOLD_START 1550d24de9dSSimon Glass else: 15643bca004SSimon Glass base = self.BRIGHT_START if bright else self.NORMAL_START 15743bca004SSimon Glass start = base % (color + 30) 1580d24de9dSSimon Glass return start + text + self.RESET 159