From: Bobby R. Bruce Date: Tue, 24 Sep 2019 21:28:29 +0000 (-0700) Subject: misc: Added line wrapping functionality for Sim-Object desc X-Git-Tag: v19.0.0.0~509 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=772ca27a97239208d5eafb795c7ec92863d671ee;p=gem5.git misc: Added line wrapping functionality for Sim-Object desc Descriptions were previously printed on one line, unless explicitly broken when writing the description of the Sim-Object. In this commit, line wrapping is enabled when printing these descriptions. Developers, when writing the Sim-Object descriptions, may now over multiple lines with triple double-quotes and still have the description output correctly when viewing the Sim-Objects within the CLI. E.g.: X86System previously had the following load_addr_mask component which was output as: load_addr_mask default: 18446744073709551615 desc: Address to mask loading binaries with, if 0, system \ auto-calculates the mask to be the most restrictive, otherwise it obeys a \ custom mask. This was defined by the developer via: load_addr_mask = Param.UInt64(0xffffffffffffffff, "Address to mask loading binaries with, if 0, system " "auto-calculates the mask to be the most restrictive, " "otherwise it obeys a custom mask.") This is now displayed as: load_addr_mask default: 18446744073709551615 desc: Address to mask loading binaries with, if 0, system auto-calculates the mask to be the most restrictive, otherwise it obeys a custom mask. JiraID: Gem5-57 Built: Linux (GCC) Tested: Ran quick tests for X86, ARM, and RISC-V Change-Id: If012304e50af60f6ba10c1fa2b44da8bac1c09cf Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/21179 Tested-by: kokoro Reviewed-by: Andreas Sandberg Reviewed-by: Daniel Carvalho Maintainer: Andreas Sandberg --- diff --git a/src/python/SConscript b/src/python/SConscript index 758ab3df9..8264e380b 100644 --- a/src/python/SConscript +++ b/src/python/SConscript @@ -61,6 +61,7 @@ PySource('m5.util', 'm5/util/sorteddict.py') PySource('m5.util', 'm5/util/terminal.py') PySource('m5.util', 'm5/util/pybind.py') PySource('m5.util', 'm5/util/fdthelper.py') +PySource('m5.util', 'm5/util/terminal_formatter.py') PySource('m5.internal', 'm5/internal/__init__.py') PySource('m5.internal', 'm5/internal/params.py') diff --git a/src/python/m5/main.py b/src/python/m5/main.py index 295108c9d..92d9bb4f1 100644 --- a/src/python/m5/main.py +++ b/src/python/m5/main.py @@ -227,6 +227,7 @@ def main(*args): from . import trace from .util import inform, fatal, panic, isInteractive + from m5.util.terminal_formatter import TerminalFormatter if len(args) == 0: options, arguments = parse_options() @@ -306,18 +307,21 @@ def main(*args): print("SimObjects:") objects = list(SimObject.allClasses.keys()) objects.sort() + terminal_formatter = TerminalFormatter() for name in objects: obj = SimObject.allClasses[name] - print(" %s" % obj) + print(terminal_formatter.format_output(str(obj), indent=4)) params = list(obj._params.keys()) params.sort() for pname in params: param = obj._params[pname] default = getattr(param, 'default', '') - print(" %s" % pname) + print(terminal_formatter.format_output(pname, indent=8)) if default: - print(" default: %s" % default) - print(" desc: %s" % param.desc) + print(terminal_formatter.format_output( + str(default), label="default: ", indent=21)) + print(terminal_formatter.format_output( + param.desc, label="desc: ", indent=21)) print() print() diff --git a/src/python/m5/util/terminal_formatter.py b/src/python/m5/util/terminal_formatter.py new file mode 100644 index 000000000..84c21dbe4 --- /dev/null +++ b/src/python/m5/util/terminal_formatter.py @@ -0,0 +1,133 @@ +# Copyright (c) 2019 The Regents of the University of California +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Bobby R. Bruce + + + +import textwrap + +class TerminalFormatter: + + def __init__(self, max_width=80): + # text_width holds the actual width we'll be wrapping to. + # This takes into account the current terminal size. + self.__text_width = min(max_width, self.__terminal_size()[0]) + + def __terminal_size(self): + import fcntl, termios, struct + h, w, hp, wp = struct.unpack('HHHH', + fcntl.ioctl(0, termios.TIOCGWINSZ, + struct.pack('HHHH', 0, 0, 0, 0))) + return w, h + + def __get_paragraphs(self, text, flatten=False): + + """ + This function takes a text and returns a list of constituent + paragraphs, defining a paragraph as a block of text separated from + other text by a blank line (or one containing only whitespace). If the + "flatten" argument is set to true, all line breaks within paragraphs + will be removed. + + E.g.: + + text = '''Hello, this is + paragraph number 1. + + This is paragraph number 2. + + And this is + paragraph number 3. + ''' + + __get_paragraphs(text, False) + ["Hello, this is\nparagraph number 1", "This is paragraph number 2.", + "And this is\npagraph number 3."] + + __get_paragraphs(text, True) + ["Hello, this is paragraph number 1", "This is paragraph number 2.", + "And this is pagraph number 3."] + """ + + paragraphs = [] + cur_paragraph = [] + + for line in text.splitlines(): + stripped = line.strip() + if not stripped: #I.e. a blank line. + paragraphs.append( + {False: "\n", True: " "}[flatten].join(cur_paragraph)) + cur_paragraph = [] + else: + cur_paragraph.append(stripped) + + paragraphs.append( + {False: "\n", True: " "}[flatten].join(cur_paragraph)) + + return paragraphs + + def format_output(self, text, label="", indent=0): + """ + This function aids in the formatting of outputs. When obtaining + the list of sim object we desire the output in the following + format: + + desc: Address to mask loading binaries with, if 0, + system auto-calculates the mask to be the most + restrictive, otherwise it obeys a custom mask. + + We must take into account the width of the text, and wrap + accordingly. We also must display the label. + + Keyword arguments: + + text --- The description text. + label --- The label of the output (e.g. "desc: "). + indent --- The white space width before each line. + """ + + if not text.strip(): + return "" + + # The text may be over multiple lines (as when using triple + # double quotes). First, we split the text into its constituent + # paragraphs and remove new line characters from each. + paragraphs = self.__get_paragraphs(text, True) + + # Wrap and Indent the paragraphs + wrapper = textwrap.TextWrapper(width = + max((self.__text_width - indent),1)) + # The first paragraph is special case due to the inclusion of the label + formatted_paragraphs = [' ' * max((indent - len(label)),0) \ + + label + wrapper.wrap(paragraphs[0])[0]] + for paragraph in paragraphs: + for line in wrapper.wrap(paragraph[1:])[1:]: + formatted_paragraphs.append(' ' * indent + line) + formatted_paragraphs.append('\n') + + # Remove the last line break + return '\n'.join(formatted_paragraphs[:-1])