Skip to content

Instantly share code, notes, and snippets.

@karlrwjohnson
Last active February 26, 2017 01:26
Show Gist options
  • Save karlrwjohnson/3bbaaebe1625438bc5c26e46def4f5cc to your computer and use it in GitHub Desktop.
Save karlrwjohnson/3bbaaebe1625438bc5c26e46def4f5cc to your computer and use it in GitHub Desktop.
Sublime plugin that re-wraps plain text so it just fits under 80 characters. Supports indented blocks, too!
# Sublime plugin that re-wraps text blocks so that each line contains the
# maximum number of characters before line 80
# To install (Sublime 3?), find your Packages/User directory by going to
# Preferences Menu > Browse Packages...
#
# Save this file into that directory.
#
# To enable it in the [Ctrl+Shift+P] command palette, create a file called
# "mine.sublime-commands" (exact name before extension doesn't matter),
# and paste the following JSON inside it:
#
# [ { "caption": "Rewrap to line 80", "command": "rewrap_line" } ]
import sublime
import sublime_plugin
import re
max_width = 80 # Should be configurable somehow... not sure how.
print('RewrapLineCommand loaded') # Logs to debug console, accessed with Ctrl+`
class RewrapLineCommand(sublime_plugin.TextCommand):
def run(self, edit):
selection = self.view.sel()
for region in selection:
# Extend selection to span the entire line
region = self.view.line(region)
region_lines = self.view.substr(region).split('\n')
# Figure out which sets of lines belong together by looking
# at the "indent" before it. Indents may consist of whitespace,
# slashes, asterisks, and hashes (to accomadate most comments)
block_indent = None
block_lines = []
new_region_lines = []
def flush_block():
# Do nothing on the initial flush
if block_indent is None:
return
new_region_lines.extend(self.rewrap_block(
block_indent,
[
line.rstrip().lstrip(' \t*#/')
for line in block_lines
]
))
block_lines[:] = []
for line in region_lines:
# Detect whatever indentation (or line comments) is in place for
# this block. This won't work well for C-style comment blocks
# where the text begins on the same line as the "/*"
m = re.match(r'^(.*?)([^ \t*#/].*|$)', line)
line_indent = m.group(1)
line_content = m.group(2)
if line == '' or line_indent != block_indent:
# Flush previous block
flush_block()
block_indent = line_indent
block_lines.append(line_content)
flush_block()
self.view.replace(edit, region, '\n'.join(new_region_lines))
def is_enabled(self):
return len(self.view.sel()) > 0
def rewrap_block(self, indent, lines):
# Combine everything; we're about to split it up again.
content = ' '.join(lines)
# Pre-calculate static value
content_width = max_width - len(indent)
# Re-indented lines to return
ret = []
last_whitepace_before_max_width = re.compile(r'(.{1,' + str(content_width) + r'})\s+(.*)')
while len(content) > content_width:
# Find the last whitespace before character 80
m = last_whitepace_before_max_width.match(content)
if not m:
m = re.match(r'(\S+)\s*(.*)', content)
ret.append(indent + m.group(1))
content = m.group(2)
ret.append(indent + content)
return ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment