X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=tools%2Fpatman%2Fterminal.py;h=c709438bdc4f737b8509e6e69f6565381785994e;hb=04da42770b0cc3bea8841972bfc9568299ece826;hp=4ceab189bf3ccf1fe8797b8708b381d1ac8ee9e8;hpb=e8f80a5a58c9b506453cc0780687e8ed457d30a6;p=platform%2Fkernel%2Fu-boot.git diff --git a/tools/patman/terminal.py b/tools/patman/terminal.py index 4ceab18..c709438 100644 --- a/tools/patman/terminal.py +++ b/tools/patman/terminal.py @@ -7,9 +7,9 @@ This module handles terminal interaction including ANSI color codes. """ -from __future__ import print_function - import os +import re +import shutil import sys # Selection of when we want our output to be colored @@ -19,6 +19,13 @@ COLOR_IF_TERMINAL, COLOR_ALWAYS, COLOR_NEVER = range(3) print_test_mode = False print_test_list = [] +# The length of the last line printed without a newline +last_print_len = None + +# credit: +# stackoverflow.com/questions/14693701/how-can-i-remove-the-ansi-escape-sequences-from-a-string-in-python +ansi_escape = re.compile(r'\x1b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') + class PrintLine: """A line of text output @@ -36,7 +43,86 @@ class PrintLine: return 'newline=%s, colour=%s, text=%s' % (self.newline, self.colour, self.text) -def Print(text='', newline=True, colour=None): +def CalcAsciiLen(text): + """Calculate the length of a string, ignoring any ANSI sequences + + When displayed on a terminal, ANSI sequences don't take any space, so we + need to ignore them when calculating the length of a string. + + Args: + text: Text to check + + Returns: + Length of text, after skipping ANSI sequences + + >>> col = Color(COLOR_ALWAYS) + >>> text = col.Color(Color.RED, 'abc') + >>> len(text) + 14 + >>> CalcAsciiLen(text) + 3 + >>> + >>> text += 'def' + >>> CalcAsciiLen(text) + 6 + >>> text += col.Color(Color.RED, 'abc') + >>> CalcAsciiLen(text) + 9 + """ + result = ansi_escape.sub('', text) + return len(result) + +def TrimAsciiLen(text, size): + """Trim a string containing ANSI sequences to the given ASCII length + + The string is trimmed with ANSI sequences being ignored for the length + calculation. + + >>> col = Color(COLOR_ALWAYS) + >>> text = col.Color(Color.RED, 'abc') + >>> len(text) + 14 + >>> CalcAsciiLen(TrimAsciiLen(text, 4)) + 3 + >>> CalcAsciiLen(TrimAsciiLen(text, 2)) + 2 + >>> text += 'def' + >>> CalcAsciiLen(TrimAsciiLen(text, 4)) + 4 + >>> text += col.Color(Color.RED, 'ghi') + >>> CalcAsciiLen(TrimAsciiLen(text, 7)) + 7 + """ + if CalcAsciiLen(text) < size: + return text + pos = 0 + out = '' + left = size + + # Work through each ANSI sequence in turn + for m in ansi_escape.finditer(text): + # Find the text before the sequence and add it to our string, making + # sure it doesn't overflow + before = text[pos:m.start()] + toadd = before[:left] + out += toadd + + # Figure out how much non-ANSI space we have left + left -= len(toadd) + + # Add the ANSI sequence and move to the position immediately after it + out += m.group() + pos = m.start() + len(m.group()) + + # Deal with text after the last ANSI sequence + after = text[pos:] + toadd = after[:left] + out += toadd + + return out + + +def Print(text='', newline=True, colour=None, limit_to_line=False): """Handle a line of output to the terminal. In test mode this is recorded in a list. Otherwise it is output to the @@ -47,17 +133,31 @@ def Print(text='', newline=True, colour=None): newline: True to add a new line at the end of the text colour: Colour to use for the text """ + global last_print_len + if print_test_mode: print_test_list.append(PrintLine(text, newline, colour)) else: if colour: col = Color() text = col.Color(colour, text) - print(text, end='') if newline: - print() + print(text) + last_print_len = None else: - sys.stdout.flush() + if limit_to_line: + cols = shutil.get_terminal_size().columns + text = TrimAsciiLen(text, cols) + print(text, end='', flush=True) + last_print_len = CalcAsciiLen(text) + +def PrintClear(): + """Clear a previously line that was printed with no newline""" + global last_print_len + + if last_print_len: + print('\r%s\r' % (' '* last_print_len), end='', flush=True) + last_print_len = None def SetPrintTestMode(): """Go into test mode, where all printing is recorded""" @@ -128,7 +228,7 @@ class Color(object): return '' def Stop(self): - """Retruns a stop color code. + """Returns a stop color code. Returns: If color is enabled, returns an ANSI color reset sequence,