aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Driessen <vincent@datafox.nl>2010-08-19 16:37:33 +0200
committerVincent Driessen <vincent@datafox.nl>2010-08-19 16:38:23 +0200
commit135878107d87873bc2f539fe2d4dd0c179c757de (patch)
treeb88ec5251dcfa49bae8b88103a1ed3e9e1616b26
parentd8c457c07b22b16290878150a22f22330964f843 (diff)
downloadvim-rst-tables-135878107d87873bc2f539fe2d4dd0c179c757de.tar.gz
vim-rst-tables-135878107d87873bc2f539fe2d4dd0c179c757de.tar.bz2
vim-rst-tables-135878107d87873bc2f539fe2d4dd0c179c757de.zip
Add support for multi-line cell formatting.
For example, when given the following table: [['Foo', 'Bar'], ['x', 'This is a long line\nthat is spread out\nover multiple lines']] It will render as: +=====+=====================+ | Foo | Bar | +=====+=====================+ | x | This is a long line | | | that is spread out | | | over multiple lines | +-----+---------------------+
-rw-r--r--ftplugin/rst_tables.vim62
-rw-r--r--src/rst_tables.py62
-rw-r--r--tests/test_rst_tables.py48
3 files changed, 130 insertions, 42 deletions
diff --git a/ftplugin/rst_tables.vim b/ftplugin/rst_tables.vim
index c793dac..1077557 100644
--- a/ftplugin/rst_tables.vim
+++ b/ftplugin/rst_tables.vim
@@ -66,6 +66,7 @@ def join_rows(rows, sep='\n'):
def line_is_separator(line):
return re.match('^[\t +=-]+$', line)
+
def has_line_seps(raw_lines):
for line in raw_lines:
if line_is_separator(line):
@@ -157,6 +158,25 @@ def table_line(widths, header=False):
return sep.join(parts)
+def get_field_width(field_text):
+ return max(map(lambda s: len(s), field_text.split('\n')))
+
+
+def split_row_into_lines(row):
+ row = map(lambda field: field.split('\n'), row)
+ height = max(map(lambda field_lines: len(field_lines), row))
+ turn_table = []
+ for i in range(height):
+ fields = []
+ for field_lines in row:
+ if i < len(field_lines):
+ fields.append(field_lines[i])
+ else:
+ fields.append('')
+ turn_table.append(fields)
+ return turn_table
+
+
def get_column_widths(table):
widths = []
for row in table:
@@ -166,30 +186,25 @@ def get_column_widths(table):
widths.extend([0] * (num_fields - len(widths)))
for i in range(num_fields):
field_text = row[i]
- field_width = len(field_text)
+ field_width = get_field_width(field_text)
widths[i] = max(widths[i], field_width)
return widths
-def pad_fields(table, widths=None):
- """Pads fields of the table, so each row lines up nicely with the others.
- If the widths param is None, the widths are calculated automatically.
+def pad_fields(row, widths):
+ """Pads fields of the given row, so each field lines up nicely with the
+ others.
"""
- if widths is None:
- widths = get_column_widths(table)
widths = map(lambda w: ' %-' + str(w) + 's ', widths)
# Pad all fields using the calculated widths
- output = []
- for row in table:
- new_row = []
- for i in range(len(row)):
- col = row[i]
- col = widths[i] % col.strip()
- new_row.append(col)
- output.append(new_row)
- return output
+ new_row = []
+ for i in range(len(row)):
+ col = row[i]
+ col = widths[i] % col.strip()
+ new_row.append(col)
+ return new_row
def draw_table(table):
@@ -197,17 +212,24 @@ def draw_table(table):
return []
col_widths = get_column_widths(table)
- table = pad_fields(table, col_widths)
# Reserve room for the spaces
- col_widths = map(lambda x: x + 2, col_widths)
- header_line = table_line(col_widths, header=True)
- normal_line = table_line(col_widths, header=False)
+ sep_col_widths = map(lambda x: x + 2, col_widths)
+ header_line = table_line(sep_col_widths, header=True)
+ normal_line = table_line(sep_col_widths, header=False)
output = [header_line]
first = True
for row in table:
- output.append("|".join([''] + row + ['']))
+
+ row_lines = split_row_into_lines(row)
+
+ # draw the lines (num_lines) for this row
+ for row_line in row_lines:
+ row_line = pad_fields(row_line, col_widths)
+ output.append("|".join([''] + row_line + ['']))
+
+ # then, draw the separator
if first:
output.append(header_line)
first = False
diff --git a/src/rst_tables.py b/src/rst_tables.py
index 952a2b2..f689b35 100644
--- a/src/rst_tables.py
+++ b/src/rst_tables.py
@@ -47,6 +47,7 @@ def join_rows(rows, sep='\n'):
def line_is_separator(line):
return re.match('^[\t +=-]+$', line)
+
def has_line_seps(raw_lines):
for line in raw_lines:
if line_is_separator(line):
@@ -138,6 +139,25 @@ def table_line(widths, header=False):
return sep.join(parts)
+def get_field_width(field_text):
+ return max(map(lambda s: len(s), field_text.split('\n')))
+
+
+def split_row_into_lines(row):
+ row = map(lambda field: field.split('\n'), row)
+ height = max(map(lambda field_lines: len(field_lines), row))
+ turn_table = []
+ for i in range(height):
+ fields = []
+ for field_lines in row:
+ if i < len(field_lines):
+ fields.append(field_lines[i])
+ else:
+ fields.append('')
+ turn_table.append(fields)
+ return turn_table
+
+
def get_column_widths(table):
widths = []
for row in table:
@@ -147,30 +167,25 @@ def get_column_widths(table):
widths.extend([0] * (num_fields - len(widths)))
for i in range(num_fields):
field_text = row[i]
- field_width = len(field_text)
+ field_width = get_field_width(field_text)
widths[i] = max(widths[i], field_width)
return widths
-def pad_fields(table, widths=None):
- """Pads fields of the table, so each row lines up nicely with the others.
- If the widths param is None, the widths are calculated automatically.
+def pad_fields(row, widths):
+ """Pads fields of the given row, so each field lines up nicely with the
+ others.
"""
- if widths is None:
- widths = get_column_widths(table)
widths = map(lambda w: ' %-' + str(w) + 's ', widths)
# Pad all fields using the calculated widths
- output = []
- for row in table:
- new_row = []
- for i in range(len(row)):
- col = row[i]
- col = widths[i] % col.strip()
- new_row.append(col)
- output.append(new_row)
- return output
+ new_row = []
+ for i in range(len(row)):
+ col = row[i]
+ col = widths[i] % col.strip()
+ new_row.append(col)
+ return new_row
def draw_table(table):
@@ -178,17 +193,24 @@ def draw_table(table):
return []
col_widths = get_column_widths(table)
- table = pad_fields(table, col_widths)
# Reserve room for the spaces
- col_widths = map(lambda x: x + 2, col_widths)
- header_line = table_line(col_widths, header=True)
- normal_line = table_line(col_widths, header=False)
+ sep_col_widths = map(lambda x: x + 2, col_widths)
+ header_line = table_line(sep_col_widths, header=True)
+ normal_line = table_line(sep_col_widths, header=False)
output = [header_line]
first = True
for row in table:
- output.append("|".join([''] + row + ['']))
+
+ row_lines = split_row_into_lines(row)
+
+ # draw the lines (num_lines) for this row
+ for row_line in row_lines:
+ row_line = pad_fields(row_line, col_widths)
+ output.append("|".join([''] + row_line + ['']))
+
+ # then, draw the separator
if first:
output.append(header_line)
first = False
diff --git a/tests/test_rst_tables.py b/tests/test_rst_tables.py
index eac65fe..7d72e25 100644
--- a/tests/test_rst_tables.py
+++ b/tests/test_rst_tables.py
@@ -23,7 +23,7 @@ import unittest
from rst_tables import get_table_bounds, reformat_table, parse_table, \
draw_table, table_line, get_column_widths, \
pad_fields, unify_table, join_rows, \
- partition_raw_lines
+ partition_raw_lines, split_row_into_lines
class TestRSTTableFormatter(unittest.TestCase):
@@ -146,6 +146,43 @@ class TestRSTTableFormatter(unittest.TestCase):
['x\nblah', 'This became somewhat larger\nA new line']]
self.assertEquals(expect, parse_table(input))
+ def testParseMultiLineFields(self):
+ input = """\
++=====+=====================+
+| Foo | Bar |
++=====+=====================+
+| x | This is a long line |
+| | that is spread out |
+| | over multiple lines |
++-----+---------------------+""".split('\n')
+ expect = [['Foo', 'Bar'],
+ ['x', 'This is a long line\nthat is spread out\nover multiple lines']]
+ self.assertEquals(expect, parse_table(input))
+
+ def testSplitRowIntoLines(self):
+ input = ['Foo', 'Bar']
+ expect = [['Foo', 'Bar']]
+ self.assertEquals(expect, split_row_into_lines(input))
+ input = ['One\nTwo\nThree', 'Only one']
+ expect = [['One', 'Only one'], ['Two', ''], ['Three', '']]
+ self.assertEquals(expect, split_row_into_lines(input))
+ input = ['One\n\n\nThree', 'Foo\nBar']
+ expect = [['One', 'Foo'], ['', 'Bar'], ['', ''], ['Three', '']]
+ self.assertEquals(expect, split_row_into_lines(input))
+
+ def testDrawMultiLineFields(self):
+ input = [['Foo', 'Bar'],
+ ['x', 'This is a long line\nthat is spread out\nover multiple lines']]
+ expect = """\
++=====+=====================+
+| Foo | Bar |
++=====+=====================+
+| x | This is a long line |
+| | that is spread out |
+| | over multiple lines |
++-----+---------------------+""".split('\n')
+ self.assertEquals(expect, draw_table(input))
+
def testTableLine(self):
self.assertEquals('', table_line([], True))
self.assertEquals('++', table_line([0], True))
@@ -168,6 +205,11 @@ class TestRSTTableFormatter(unittest.TestCase):
['xx','yyy','zz'],
]))
+ def testGetColumnWidthsForMultiLineFields(self):
+ self.assertEquals([3,6],
+ get_column_widths([['Foo\nBar\nQux',
+ 'This\nis\nreally\nneat!']]))
+
def testPadFields(self):
table = [['Name', 'Type', 'Description'],
['Lollypop', 'Candy', 'Yummy'],
@@ -176,7 +218,9 @@ class TestRSTTableFormatter(unittest.TestCase):
[' Name ', ' Type ', ' Description '],
[' Lollypop ', ' Candy ', ' Yummy '],
[' Crisps ', ' Snacks ', ' Even more yummy, I tell you! ']]
- self.assertEquals(expected_padding, pad_fields(table))
+ widths = get_column_widths(table)
+ for input, expect in zip(table, expected_padding):
+ self.assertEquals(expect, pad_fields(input, widths))
def testDrawTable(self):