diff options
| -rw-r--r-- | ftplugin/rst_tables.vim | 62 | ||||
| -rw-r--r-- | src/rst_tables.py | 62 | ||||
| -rw-r--r-- | tests/test_rst_tables.py | 48 | 
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):  | 
