From patchwork Sun Apr 5 15:21:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 237194 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Sun, 5 Apr 2020 09:21:21 -0600 Subject: [PATCH 12/22] patman: Support erasing a previously unfinished text line In-Reply-To: <20200405152131.98147-1-sjg@chromium.org> References: <20200405152131.98147-1-sjg@chromium.org> Message-ID: <20200405092116.12.Ibccb893865ead03f67a73ab6419a7927d4afd2a9@changeid> 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 cf53e532ddf..7f4ac9aef48 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 6541fa8f410..c7693eb57ad 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"""