From 37b224f9f136f83f22de9221d48d9a0b1b2c3693 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 9 Apr 2020 15:08:40 -0600 Subject: [PATCH] patman: Support erasing a previously unfinished text line When printing progress it is useful to print a message and leave the cursor at the end of the line until the operation is finished. When it is finished, the line needs to be erased so a new line can start in its place. Add a function to handle clearing a line previously written by terminal.Print() Signed-off-by: Simon Glass --- tools/patman/patman.py | 2 +- tools/patman/terminal.py | 47 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/tools/patman/patman.py b/tools/patman/patman.py index cf53e532dd..7f4ac9aef4 100755 --- a/tools/patman/patman.py +++ b/tools/patman/patman.py @@ -93,7 +93,7 @@ elif options.test: suite = unittest.TestLoader().loadTestsFromTestCase(module) suite.run(result) - for module in ['gitutil', 'settings']: + for module in ['gitutil', 'settings', 'terminal']: suite = doctest.DocTestSuite(module) suite.run(result) diff --git a/tools/patman/terminal.py b/tools/patman/terminal.py index 6541fa8f41..c7693eb57a 100644 --- a/tools/patman/terminal.py +++ b/tools/patman/terminal.py @@ -10,6 +10,7 @@ This module handles terminal interaction including ANSI color codes. from __future__ import print_function import os +import re import sys # Selection of when we want our output to be colored @@ -19,6 +20,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,6 +44,33 @@ class PrintLine: return 'newline=%s, colour=%s, text=%s' % (self.newline, self.colour, self.text) +def CalcAsciiLen(text): + """Calculate the length of a string, ignoring any ANSI sequences + + 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 Print(text='', newline=True, colour=None): """Handle a line of output to the terminal. @@ -47,6 +82,8 @@ 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: @@ -55,8 +92,18 @@ def Print(text='', newline=True, colour=None): text = col.Color(colour, text) if newline: print(text) + last_print_len = None else: 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""" -- 2.39.5