Last active
February 26, 2017 01:26
-
-
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!
This file contains 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
# 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