Created
May 13, 2021 18:32
-
-
Save reagle/3457fb5ef94e898f47777cb4065aa1f1 to your computer and use it in GitHub Desktop.
A Sublime Text 3 (python 2.7) plugin for wrapping text, including semantic wraps.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# A Sublime Text 3 (python 2.7) plugin for wrapping text, including | |
# semantic wraps. | |
import re | |
import sublime # https://www.sublimetext.com/docs/3/api_reference.html | |
import sublime_plugin | |
SEMANTIC_BREAK_RE = re.compile( | |
r""" | |
( # end of sentence includes... | |
[a-z]{2,}| # end of word | |
[0-9]{1,} # end of a page or chapter number | |
) | |
( # terminal punctuation | |
\. | |
|\? | |
|\! | |
|\} | |
|: | |
|\.\) # period paren | |
|\)\. # paren period | |
|\.\] # period bracket | |
|\]\. # bracket period | |
|\." # period quote | |
|"\. # quote quote | |
|"\)\. # quote paren period | |
|\?\) # question paren | |
|\)\? # paren question | |
|\?\] # question bracket | |
|\]\? # bracket question | |
|\?" # question quote | |
|"\? # quote question | |
|\!\) # exclaim paren | |
|\)\! # paren exclaim | |
|\!\] # exclaim bracket | |
|\]\! # bracket exclaim | |
|\!" # exclaim quote | |
|"\! # quote exclaim | |
) | |
(\s) # a whitespace | |
(?!\d) # negative lookahead for digit | |
""", | |
re.VERBOSE, | |
) | |
QUOTES_RE = re.compile( | |
r""" | |
(^[> ]+) # start quotes | |
(.*) # rest of line | |
""", | |
re.VERBOSE, | |
) | |
def apply_semantic_regex(text): | |
"""Use the regular expressions above to break all terminating punctuation | |
and join everything else""" | |
# if quoted, count quotes and restore when wrapped | |
if text.startswith(">"): | |
quotes, text = QUOTES_RE.match(text).groups() | |
text = text.replace(quotes, " ") | |
wrapped_text = SEMANTIC_BREAK_RE.sub(r"""\1\2\3\n%s""" % quotes, text) | |
return quotes + wrapped_text + "\n" | |
else: | |
return SEMANTIC_BREAK_RE.sub(r"""\1\2\3\n""", text) + "\n" | |
def break_paras_and_wrap(text): | |
"""break text, including email with quotes, into paragraphs""" | |
print("\n" * 5, "=" * 20) | |
paragraphs = [] | |
paragraph = [] | |
for line in text.split("\n"): | |
print("LINE = '%s'" % line) | |
# convert indent quote to '>' quotes | |
if re.match(r"^>( )+", line): | |
line = line.replace(" ", ">") | |
# print("REPLACE indents, line = %s" % line) | |
# special case for quote header: On [some date] [someone] wrote: | |
if re.match(r"^On \d", line): | |
print("QUOTE header; add to its own paragraph") | |
paragraphs.append(apply_semantic_regex("".join(paragraph))) | |
paragraphs.append(line + "\n") | |
paragraph = [] | |
print("PARAGRAPHS = '%s'" % paragraphs) | |
continue | |
# a quoted line | |
elif re.match(r"^[>\s]+$", line): | |
print("LINE is just \\s or quote: wrap, append, start new para") | |
paragraph.append(line) | |
paragraphs.append(apply_semantic_regex("".join(paragraph))) | |
paragraph = [] | |
print("PARAGRAPHS = '''%s'''" % paragraphs) | |
continue | |
# ordinary line | |
else: | |
print("ADD line to ongoing paragraph") | |
paragraph.append(line) | |
print("PARAGRAPH = '''%s'''" % paragraph) | |
paragraphs.append( | |
apply_semantic_regex(" ".join(paragraph)) | |
) # last one in pipeline | |
print("PARAGRAPHS = '''%s'''" % paragraphs) | |
# remove repeating sequences | |
paragraphs_trimmed = ["\n"] | |
for paragraph in paragraphs: | |
if paragraph != paragraphs_trimmed[-1]: | |
print("PARAGRAPH IS NOT SAME AS LAST") | |
paragraphs_trimmed.append(paragraph) | |
print("PARAGRAPHS_TRIMMED = '''%s'''" % paragraphs_trimmed) | |
return "".join(paragraphs_trimmed).strip() | |
class SemanticWrap(sublime_plugin.TextCommand): | |
def run(self, edit): | |
# print("=====================================") | |
for region in self.view.sel(): | |
line = self.view.rowcol(region.begin())[0] | |
# print("LINE = %s" % line) | |
self.view.run_command("expand_selection_to_paragraph") | |
chunk_loc = self.view.sel()[0] | |
# print("CHUNK_LOC = %s" % chunk_loc) | |
chunk = self.view.substr(chunk_loc) | |
print("CHUNK = '''%s'''" % chunk) | |
wrapped_paras = break_paras_and_wrap(chunk) | |
print("WRAPPED_PARAS = '''%s'''" % wrapped_paras) | |
self.view.replace(edit, chunk_loc, wrapped_paras) | |
self.view.run_command("goto_line", {"line": line + 1}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment