Skip to content

Instantly share code, notes, and snippets.

@reagle
Created May 13, 2021 18:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reagle/3457fb5ef94e898f47777cb4065aa1f1 to your computer and use it in GitHub Desktop.
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.
# 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