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