Skip to content

Instantly share code, notes, and snippets.

@dmlogv
Created February 6, 2025 15:20
Show Gist options
  • Save dmlogv/10a4ba185aeac50ad52963072c3fe120 to your computer and use it in GitHub Desktop.
Save dmlogv/10a4ba185aeac50ad52963072c3fe120 to your computer and use it in GitHub Desktop.
import sublime, sublime_plugin
""" Format text as table
"""
class AlignerCommand(sublime_plugin.TextCommand):
""" Split text by delimeter and format as table with limited width
@param 'limit': int - Max width of table, default is 80
@param 'splitter': str - Custom delimeter, default is ', '
@param 'after': bool - Delimeter position, default is False (before)
@param 'expand': int - Additional space between text and delimeter, default 1
@param 'align': str - Text align in cell, default is left
Example: view.run_command('aligner', {'limit':10, 'splitter':','})
"""
def run(self, edit, **kwargs):
# Default argument values
limit = kwargs.get('limit') or 80 # Table width limit
splitter = kwargs.get('splitter') or ', ' # Column delimeter
after = kwargs.get('after') or False # Delimeter position
expand = kwargs.get('expand') or 1 # Additional space in cell
align = kwargs.get('align') or 'left' # Text alignment
# Parameters value check
if limit < 0:
raise ValueError('Limit value must be greater or equal 0')
if not (type(splitter) == str or type(splitter) == unicode):
raise TypeError('Splitter must be a string')
if not type(after) == bool:
raise TypeError('After must be a boolean')
if expand < 0:
raise ValueError('Expand value must be greater or equal 0')
if align not in ['left', 'right']:
raise ValueError("Align value must be 'left' or 'right'")
# Get selected text or select all
region = self.view.sel()[0] or sublime.Region(0, self.view.size())
selection = self.view.substr(region)
# Split text by delimeter, exclude empty strings, trim spaces
parts = [
item.strip() for item
in filter(None, selection.split(splitter.strip() or ' '))
]
# Max cell length plus additional space
max_len = max([len(item) for item in parts]) + expand
# Number of cell in row or 1 if limit too short
per_line = max(limit // (max_len + len(splitter)), 1)
rows = []
# Loop cells by number of cells in row
for current_item in range(0, len(parts), per_line):
rows.append(
# Join cells in to row
(splitter).join(
[
# Align text in cell with spaces
{
'left': item.ljust(max_len),
'right': item.rjust(max_len)
}[align] for item
in parts[current_item : current_item + per_line]
]
)
)
# Replace region with output rows
row_splitter = {
True: splitter + '\r\n',
False: '\r\n' + splitter
}.get(after)
first_shift = {
True: '',
False: ' ' * len(splitter)
}.get(after)
self.view.replace(edit, region, first_shift + (row_splitter).join(rows))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment