|
42 | 42 | import base64 |
43 | 43 | import glob |
44 | 44 | import hashlib |
45 | | -import itertools |
46 | 45 | import os |
47 | 46 | import sys |
48 | | -import textwrap |
49 | 47 | import time |
50 | 48 |
|
51 | 49 | from blurb._template import ( |
52 | 50 | next_filename_unsanitize_sections, sanitize_section, |
53 | | - sanitize_section_legacy, sections, unsanitize_section, |
| 51 | + sanitize_section_legacy, sections, |
54 | 52 | ) |
55 | 53 |
|
56 | | -def textwrap_body(body, *, subsequent_indent=''): |
57 | | - """ |
58 | | - Accepts either a string or an iterable of strings. |
59 | | - (Iterable is assumed to be individual lines.) |
60 | | - Returns a string. |
61 | | - """ |
62 | | - if isinstance(body, str): |
63 | | - text = body |
64 | | - else: |
65 | | - text = "\n".join(body).rstrip() |
66 | | - |
67 | | - # textwrap merges paragraphs, ARGH |
68 | | - |
69 | | - # step 1: remove trailing whitespace from individual lines |
70 | | - # (this means that empty lines will just have \n, no invisible whitespace) |
71 | | - lines = [] |
72 | | - for line in text.split("\n"): |
73 | | - lines.append(line.rstrip()) |
74 | | - text = "\n".join(lines) |
75 | | - # step 2: break into paragraphs and wrap those |
76 | | - paragraphs = text.split("\n\n") |
77 | | - paragraphs2 = [] |
78 | | - kwargs = {'break_long_words': False, 'break_on_hyphens': False} |
79 | | - if subsequent_indent: |
80 | | - kwargs['subsequent_indent'] = subsequent_indent |
81 | | - dont_reflow = False |
82 | | - for paragraph in paragraphs: |
83 | | - # don't reflow bulleted / numbered lists |
84 | | - dont_reflow = dont_reflow or paragraph.startswith(("* ", "1. ", "#. ")) |
85 | | - if dont_reflow: |
86 | | - initial = kwargs.get("initial_indent", "") |
87 | | - subsequent = kwargs.get("subsequent_indent", "") |
88 | | - if initial or subsequent: |
89 | | - lines = [line.rstrip() for line in paragraph.split("\n")] |
90 | | - indents = itertools.chain( |
91 | | - itertools.repeat(initial, 1), |
92 | | - itertools.repeat(subsequent), |
93 | | - ) |
94 | | - lines = [indent + line for indent, line in zip(indents, lines)] |
95 | | - paragraph = "\n".join(lines) |
96 | | - paragraphs2.append(paragraph) |
97 | | - else: |
98 | | - # Why do we reflow the text twice? Because it can actually change |
99 | | - # between the first and second reflows, and we want the text to |
100 | | - # be stable. The problem is that textwrap.wrap is deliberately |
101 | | - # dumb about how many spaces follow a period in prose. |
102 | | - # |
103 | | - # We're reflowing at 76 columns, but let's pretend it's 30 for |
104 | | - # illustration purposes. If we give textwrap.wrap the following |
105 | | - # text--ignore the line of 30 dashes, that's just to help you |
106 | | - # with visualization: |
107 | | - # |
108 | | - # ------------------------------ |
109 | | - # xxxx xxxx xxxx xxxx xxxx. xxxx |
110 | | - # |
111 | | - # The first textwrap.wrap will return this: |
112 | | - # "xxxx xxxx xxxx xxxx xxxx.\nxxxx" |
113 | | - # |
114 | | - # If we reflow it again, textwrap will rejoin the lines, but |
115 | | - # only with one space after the period! So this time it'll |
116 | | - # all fit on one line, behold: |
117 | | - # ------------------------------ |
118 | | - # xxxx xxxx xxxx xxxx xxxx. xxxx |
119 | | - # and so it now returns: |
120 | | - # "xxxx xxxx xxxx xxxx xxxx. xxxx" |
121 | | - # |
122 | | - # textwrap.wrap supports trying to add two spaces after a peroid: |
123 | | - # https://docs.python.org/3/library/textwrap.html#textwrap.TextWrapper.fix_sentence_endings |
124 | | - # But it doesn't work all that well, because it's not smart enough |
125 | | - # to do a really good job. |
126 | | - # |
127 | | - # Since blurbs are eventually turned into ReST and rendered anyway, |
128 | | - # and since the Zen says "In the face of ambiguity, refuse the |
129 | | - # temptation to guess", I don't sweat it. I run textwrap.wrap |
130 | | - # twice, so it's stable, and this means occasionally it'll |
131 | | - # convert two spaces to one space, no big deal. |
132 | | - |
133 | | - paragraph = "\n".join(textwrap.wrap(paragraph.strip(), width=76, **kwargs)).rstrip() |
134 | | - paragraph = "\n".join(textwrap.wrap(paragraph.strip(), width=76, **kwargs)).rstrip() |
135 | | - paragraphs2.append(paragraph) |
136 | | - # don't reflow literal code blocks (I hope) |
137 | | - dont_reflow = paragraph.endswith("::") |
138 | | - if subsequent_indent: |
139 | | - kwargs['initial_indent'] = subsequent_indent |
140 | | - text = "\n\n".join(paragraphs2).rstrip() |
141 | | - if not text.endswith("\n"): |
142 | | - text += "\n" |
143 | | - return text |
144 | | - |
145 | 54 | def sortable_datetime(): |
146 | 55 | return time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) |
147 | 56 |
|
|
0 commit comments