Source code for pyutil.wrap
#!/usr/bin/env python
# -*- coding: utf-8 -*-
r"""Wrap text similarly to :func:`textwrap.dedent()` but with multiple paragraphs.
Allow the user to input any parameters that are accepted by
:class:`textwrap.TextWrapper()`
Utilizes :mod:`prompt_toolkit.print_formatted_text` to easily display
prettified text.
.. seealso:: :mod:`IPython.utils.text`
Just dropped string2lines down there thanks to docutils and the
:mod:`docutils.state_machine`.
"""
import re
import sys
from textwrap import dedent, TextWrapper
try:
from prompt_toolkit import print_formatted_text as print
except (ImportError, ModuleNotFoundError):
pass
from pyutil.sys_checks import is_file
[docs]class ZimText(TextWrapper):
"""Subclass :class:`textwrap.TextWrapper()`.
Primarily want to modify initialized arguments.
Not entirely looking to reimplement the text formatting methods, both
private and public.
Now the publicly available methods from :class:`~textwrap.TextWrapper`.::
>>> from textwrap import TextWrapper
>>> dir(TextWrapper)
['_fix_sentence_endings',
'_handle_long_word',
'_munge_whitespace',
'_split',
'_split_chunks',
'_wrap_chunks',
'fill',
'sentence_end_re',
'unicode_whitespace_trans',
'uspace',
'wordsep_re',
'wordsep_simple_re',
'wrap',
'x']
"""
def __init__(self,
text=None,
width=80,
break_long_words=False,
break_on_hyphens=False,
**kwargs):
"""Initialize the class. ``__init__().text`` defaults to None.
However, it is still a required parameter. It's simply not enforced.
We're all responsible users here right?
"""
self.width = width
self.break_long_words = break_long_words
self.break_on_hyphens = break_on_hyphens
super().__init__(**kwargs)
[docs] def wrap_paragraphs(self):
"""Wrap multiple paragraphs to fit a specified width.
This is equivalent to :func:`textwrap.wrap()`, but with support for multiple
paragraphs, as separated by empty lines.
Parameters
----------
text : str
text to wrap using :mod:`re` and :func:`textwrap.dedent()`
ncols : int
column to wrap text at
Returns
-------
wrapped_text : list of str
list of complete paragraphs, wrapped to fill `ncols` columns.
Examples
--------
>>> from wrap import ZimText
>>> wrapper = ZimText()
>>> f = open('unix-ide-editing.txt')
>>> text = f.read()
>>> wrapped = wrapper.wrap(text)
>>> with open('unix-ide-editing.txt', 'wt') as f:
... f.write(text)
"""
paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE)
self.text = dedent(self.text).strip()
paragraphs = paragraph_re.split(
self.text)[::2] # every other entry is space
wrapped_text = []
indent_re = re.compile(r'\n\s+', re.MULTILINE)
for p in paragraphs:
# presume indentation that survives dedent is meaningful formatting,
# so don't fill unless text is flush.
if indent_re.search(p) is None:
# wrap paragraph
p = self.fill(p)
wrapped_text.append(p)
return wrapped_text
[docs] def string2lines(self, convert_whitespace=True):
"""
Parameters:
-----------
text : str
A multi-line string.
convert_whitespace : bool
convert form feeds and vertical tabs to spaces
Returns
-------
list of str
Return a list of one-line strings with tabs expanded, no newlines, and
trailing whitespace stripped.
"""
if convert_whitespace:
self.text = self._munge_whitespace(self.text)
new_text = [s for s in self.text.splitlines()]
return new_text
if __name__ == '__main__':
args = sys.argv[:]
if len(args) < 2:
raise RuntimeError("Needs a file to reformat as an argument.")
else:
for i in args[1:]:
if is_file(i):
print("Rewrapping " + i)
wrapper = ZimText()
wrapper.wrap_paragraphs(args[1:])