summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorBen Pfaff <blp@ovn.org>2016-12-28 12:41:31 -0800
committerBen Pfaff <blp@ovn.org>2017-01-25 13:53:31 -0800
commit902323d32ed7656b58c9c37d5ac9ebe7986b0a68 (patch)
tree4b0ffc319bc4aa922e963033f0a6d47fb8695932 /python
parentbef503e8c094456ca82fefd044a8c3341d9d21ac (diff)
downloadopenvswitch-902323d32ed7656b58c9c37d5ac9ebe7986b0a68.tar.gz
nroff: Improve formatting of ASCII diagrams.
This makes diagrams in ASCII output look about as good as one might reasonably expect, so that in ovn-architecture(7), for example, this: . 9 bits: reserved (0) . 15 bits: ingress port . 16 bits: egress port . 24 bits: datapath now gets formatted as: 9 15 16 24 +--------+------------+-----------+--------+ |reserved|ingress port|egress port|datapath| +--------+------------+-----------+--------+ 0 which isn't perfect but certainly more evocative than a bulleted list. This will be more useful in upcoming commits that start using diagrams more frequently. Signed-off-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'python')
-rw-r--r--python/build/nroff.py80
1 files changed, 61 insertions, 19 deletions
diff --git a/python/build/nroff.py b/python/build/nroff.py
index ebb10e90d..2f31bb27e 100644
--- a/python/build/nroff.py
+++ b/python/build/nroff.py
@@ -121,7 +121,19 @@ def fatal(msg):
sys.exit(1)
-def diagram_header_to_nroff(header_node):
+def put_text(text, x, y, s):
+ extend = x + len(s) - len(text[y])
+ if extend > 0:
+ text[y] += ' ' * extend
+ text[y] = text[y][:x] + s + text[y][x + len(s):]
+
+
+def put_centered(text, x, width, y, s):
+ put_text(text, x + (width - len(s)) / 2, y, s)
+
+
+def diagram_header_to_nroff(header_node, text, x):
+ # Parse header.
header_fields = []
i = 0
for node in header_node.childNodes:
@@ -145,10 +157,11 @@ def diagram_header_to_nroff(header_node):
else:
fatal("unknown node %s in diagram <header> element" % node)
+ # Format pic version.
pic_s = ""
for f in header_fields:
- pic_s += " %s: box \"%s\" width %s" % (f['tag'], f['name'],
- f['width'])
+ name = f['name'].replace('...', '. . .')
+ pic_s += " %s: box \"%s\" width %s" % (f['tag'], name, f['width'])
if f['fill'] == 'yes':
pic_s += " fill"
pic_s += '\n'
@@ -164,43 +177,72 @@ def diagram_header_to_nroff(header_node):
pic_s += "from %s.nw + (0,textht) " % header_fields[0]['tag']
pic_s += "to %s.ne + (0,textht)\n" % header_fields[-1]['tag']
- text_s = ""
+ # Format text version.
+ header_width = 1
+ for f in header_fields:
+ field_width = max(len(f['above']), len(f['below']), len(f['name']))
+ f['width'] = field_width
+ header_width += field_width + 1
+ min_header_width = 2 + len(name)
+ while min_header_width > header_width:
+ for f in header_fields:
+ f['width'] += 1
+ header_width += 1
+ if header_width >= min_header_width:
+ break
+
+ if name != "":
+ put_centered(text, x, header_width, 0, name)
+ if header_width >= 4:
+ arrow = '<' + '-' * (header_width - 4) + '>'
+ put_text(text, x + 1, 1, arrow)
for f in header_fields:
- text_s += """.IP \\(bu
-%s bits""" % (f['above'])
- if f['name']:
- text_s += ": %s" % f['name']
- if f['below']:
- text_s += " (%s)" % f['below']
- text_s += "\n"
- return pic_s, text_s
+ box1 = '+' + '-' * f['width'] + '+'
+ box2 = '|' + ' ' * f['width'] + '|'
+ put_text(text, x, 3, box1)
+ put_text(text, x, 4, box2)
+ put_text(text, x, 5, box1)
+
+ put_centered(text, x + 1, f['width'], 2, f['above'])
+ put_centered(text, x + 1, f['width'], 4, f['name'])
+ put_centered(text, x + 1, f['width'], 6, f['below'])
+
+ x += f['width'] + 1
+
+ return pic_s, x + 1
def diagram_to_nroff(nodes, para):
pic_s = ''
- text_s = ''
+ text = [''] * 7
+ x = 0
move = False
for node in nodes:
if node.nodeType == node.ELEMENT_NODE and node.tagName == 'header':
if move:
pic_s += "move .1\n"
- text_s += ".sp\n"
- pic_header, text_header = diagram_header_to_nroff(node)
+ x += 1
+ elif x > 0:
+ x -= 1
+ pic_header, x = diagram_header_to_nroff(node, text, x)
pic_s += "[\n" + pic_header + "]\n"
- text_s += text_header
move = True
elif node.nodeType == node.ELEMENT_NODE and node.tagName == 'nospace':
move = False
elif node.nodeType == node.ELEMENT_NODE and node.tagName == 'dots':
pic_s += "move .1\n"
pic_s += '". . ." ljust\n'
- text_s += ".sp\n"
+
+ put_text(text, x, 4, " ... ")
+ x += 5
elif node.nodeType == node.COMMENT_NODE:
pass
elif node.nodeType == node.TEXT_NODE and node.data.isspace():
pass
else:
fatal("unknown node %s in diagram <header> element" % node)
+
+ text_s = '.br\n'.join(["\\fL%s\n" % s for s in text if s != ""])
return para + """
.\\" check if in troff mode (TTY)
.if t \{
@@ -213,9 +255,9 @@ fillval = .2
\\}
.\\" check if in nroff mode:
.if n \{
-.RS
+.nf
""" + text_s + """\
-.RE
+.fi
\\}"""