Skip to content

Instantly share code, notes, and snippets.

@levigroker
Last active July 27, 2022 23:24
Show Gist options
  • Save levigroker/630b9920ff5d74840c37aa3538b5c78f to your computer and use it in GitHub Desktop.
Save levigroker/630b9920ff5d74840c37aa3538b5c78f to your computer and use it in GitHub Desktop.
A BBEdit Text Filter script to "pretty print" GitHub Flavored Markdown tables.
#!/usr/local/bin/python3
#
# Normalize Table.py
# https://gist.github.com/levigroker/630b9920ff5d74840c37aa3538b5c78f
#
# A BBEdit Text Filter script to "pretty print" GitHub Flavored Markdown tables.
# See http://bbeditextras.org/wiki/index.php?title=Text_Filters
# See # GitHub Flavored Markdown Spec: https://github.github.com/gfm/
#
# Originally from http://www.leancrew.com/all-this/2012/11/markdown-table-scripts-for-bbedit/
# and https://github.com/drdrang/wp-md
#
# Modified by Levi Brown
# @levigroker
# [email protected]
# 2022-07-27
##
import sys
def just(string, type, n):
"Justify a string to length n according to type."
if type == '::':
return string.center(n)
elif type == '-:':
return string.rjust(n)
elif type == ':-':
return string.ljust(n)
else:
return string
def normtable(text):
"Aligns the vertical bars in a text table."
# Start by turning the text into a list of lines.
lines = text.splitlines()
rows = len(lines)
# Figure out the cell formatting.
# First, find the separator line.
for i in range(rows):
if set(lines[i]).issubset('| :.-'):
formatline = lines[i]
formatrow = i
break
# Delete the separator line from the content.
del lines[formatrow]
# Determine how each column is to be justified.
formatline = formatline.strip(' ')
if formatline[0] == '|': formatline = formatline[1:]
if formatline[-1] == '|': formatline = formatline[:-1]
fstrings = formatline.split('|')
justify = []
for cell in fstrings:
ends = cell[0] + cell[-1]
if ends == '::':
justify.append('::')
elif ends == '-:':
justify.append('-:')
else:
justify.append(':-')
# Assume the number of columns in the separator line is the number
# for the entire table.
columns = len(justify)
# Extract the content into a matrix.
content = []
for line in lines:
line = line.strip(' ')
if line[0] == '|': line = line[1:]
if line[-1] == '|': line = line[:-1]
cells = line.split('|')
# Put exactly one space at each end as "bumpers."
linecontent = [ ' ' + x.strip() + ' ' for x in cells ]
content.append(linecontent)
# Append cells to rows that don't have enough.
rows = len(content)
for i in range(rows):
while len(content[i]) < columns:
content[i].append('')
# Get the width of the content in each column. The minimum width will
# be 2, because that's the shortest length of a formatting string and
# because that matches an empty column with "bumper" spaces.
widths = [2] * columns
for row in content:
for i in range(columns):
widths[i] = max(len(row[i]), widths[i])
# Add whitespace to make all the columns the same width and
formatted = []
for row in content:
formatted.append('|' + '|'.join([ just(s, t, n) for (s, t, n) in zip(row, justify, widths) ]) + '|')
# Recreate the format line with the appropriate column widths.
formatline = '|' + '|'.join([ s[0] + '-'*(n-2) + s[-1] for (s, n) in zip(justify, widths) ]) + '|'
# Insert the formatline back into the table.
formatted.insert(formatrow, formatline)
# Return the formatted table.
return '\n'.join(formatted)
# Read the input, process, and print.
unformatted = sys.stdin.read()
print(normtable(unformatted))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment