Skip to content

Commit

Permalink
Preserve preformatted text in help output.
Browse files Browse the repository at this point in the history
Look for leading whitepsace such as in cases like this..
    >>> print("Hello")
    >>> print("World")

And also simple lists as long as they begin with whitespace...

 1. First
 2. Second, and last.

Note that long lines are still wrapped but will inherit the indentation
of the preformatted section.
  • Loading branch information
mayfield committed Apr 9, 2017
1 parent 5ea7bc6 commit 61718a2
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 35 deletions.
25 changes: 12 additions & 13 deletions shellish/command/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ def parse_docstring(entity):
doc = inspect.getdoc(entity)
if not doc:
return None, None
doc = [x.strip() for x in doc.splitlines()]
if not doc[0]:
doc = doc.splitlines(keepends=True)
if not doc[0].strip():
doc.pop(0)
title = (doc and doc.pop(0)) or None
if doc and not doc[0]:
title = (doc and doc.pop(0).strip()) or None
if doc and not doc[0].strip():
doc.pop(0)
desc = '\n'.join(doc) or None
desc = ''.join(doc).rstrip() or None
return title, desc


Expand Down Expand Up @@ -72,14 +72,13 @@ def __init__(self, parent=None, title=None, desc=None, name=None, run=None,
self.name = name
if self.name is None:
raise RuntimeError("Command missing `name` attribute")
if type(self) is not Command:
alt_title, alt_desc = parse_docstring(self)
else:
alt_title, alt_desc = None, None
if not self.title or title:
self.title = title or alt_title
if not self.desc or desc:
self.desc = desc or alt_desc
if title is not None:
self.title = title
if desc is not None:
self.desc = desc
if self.title is None and self.desc is None and \
type(self) is not Command:
self.title, self.desc = parse_docstring(self)
if run is not None:
self.run = run
if prerun is not None:
Expand Down
56 changes: 40 additions & 16 deletions shellish/command/supplement.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def __len__(self):

class ShellishHelpFormatter(argparse.HelpFormatter):

hardline = re.compile('\n\s*\n+')
leadingws = re.compile('^\s+')
whitespace = re.compile('[ \n\t\v\f\r]+')
max_width = 100

class _Section(argparse.HelpFormatter._Section):
Expand Down Expand Up @@ -58,23 +59,44 @@ def format_help(self):
return self._root_section.format_help()

def _fill_text(self, text, width=None, indent=None):
r""" Reflow text but preserve hardlines (\n\n). """
""" Reflow text width while maintaining certain formatting
characteristics like double newlines and indented statements. """
assert isinstance(text, str)
paragraphs = self.hardline.split(text)
if indent is None:
indent = NBSP * self._current_indent
assert isinstance(indent, str)
paragraphs = []
line_buf = []
pre = ''
for fragment in text.splitlines():
pre_indent = self.leadingws.match(fragment)
if not fragment or pre_indent:
if line_buf:
line = ' '.join(line_buf)
paragraphs.append((pre, self.whitespace.sub(' ', line)))
if not fragment:
paragraphs.append(('', ''))
else:
pre = pre_indent.group()
fragment = self.leadingws.sub('', fragment)
paragraphs.append((pre, fragment))
line_buf = []
pre = ''
else:
line_buf.append(fragment)
if line_buf:
line = ' '.join(line_buf)
paragraphs.append((pre, self.whitespace.sub(' ', line)))
indent = VTMLBuffer(indent)
nl = VTMLBuffer('\n')
if width is None:
width = self._width - len(indent)
results = []
nl = VTMLBuffer('\n')
blankline = nl * 2
indent = VTMLBuffer(indent)
for x_text in paragraphs:
x_text = self._whitespace_matcher.sub(' ', x_text).strip()
results.append(nl.join((indent + x)
for x in vtmlrender(x_text).wrap(width)))
return blankline.join(results)
lines = []
for pre, paragraph in paragraphs:
pwidth = width - len(pre)
lines.append(nl.join((indent + pre + x)
for x in vtmlrender(paragraph).wrap(pwidth)))
return nl.join(lines)

def _format_text(self, text):
if '%(prog)' in text:
Expand Down Expand Up @@ -302,13 +324,15 @@ def format_help(self):
if len(desc) == 2 and '\n' not in desc[0]:
title, about = desc
else:
title, about = None, desc
title, about = '', desc
else:
title, about = self.description, None
title, about = self.description, ''
title = title.strip()
about = about.rstrip()
if title:
formatter.add_text('<b><u>%s</u></b>\n' % title.strip())
formatter.add_text('<b><u>%s</u></b>\n' % title)
if about:
formatter.add_text(about.strip())
formatter.add_text(about)
for group in self._action_groups:
formatter.start_section(group.title)
formatter.add_text(group.description)
Expand Down
4 changes: 2 additions & 2 deletions shellish/rendering/vtml.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ def beststr(*strings):
# * Hypens are kept on leftmost word.
# * Newlines are not grouped with other whitespace.
# * Other whitespace is grouped.
_textwrap_word_break = re.compile('(\n|[ \t\f\v]+|[^\s]+?-+)')
_whitespace = re.compile('[ \t\f\v]+')
_textwrap_word_break = re.compile('(\n|[ \t\f\v\r]+|[^\s]+?-+)')
_whitespace = re.compile('[ \t\f\v\r]+')


def is_whitespace(value):
Expand Down
8 changes: 4 additions & 4 deletions test/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ def test_no_title_desc_by_subclass(self):
class Foo(shellish.Command):
pass
f = Foo(name='foo')
self.assertEqual(f.title, None)
self.assertEqual(f.desc, None)
self.assertIsNone(f.title)
self.assertIsNone(f.desc)

def test_no_title_desc_by_compose(self):
f = shellish.Command(name='foo')
self.assertEqual(f.title, None)
self.assertEqual(f.desc, None)
self.assertIsNone(f.title)
self.assertIsNone(f.desc)

def test_title_desc_by_subclass_attrs(self):
class Foo(shellish.Command):
Expand Down

0 comments on commit 61718a2

Please sign in to comment.