From 5d96523f7d44612d6770c0f3be19555415f19f44 Mon Sep 17 00:00:00 2001 From: EricFromCanada Date: Mon, 5 Jan 2015 12:28:44 -0500 Subject: [PATCH] Fix LaTeX writer's handling of multirow table cells Originally the LaTeX writer could only handle one multirow cell per row. This commit fixes that and adds support for cells spanning both rows and columns. --- CHANGES | 2 ++ sphinx/writers/latex.py | 71 ++++++++++++++++++++++++++++++----------- tests/root/markup.txt | 16 +++++----- 3 files changed, 62 insertions(+), 27 deletions(-) diff --git a/CHANGES b/CHANGES index d84f2ff94..a2b56cc5f 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,8 @@ Features added Bugs fixed ---------- +* LaTeX writer now generates correct markup for cells spanning multiple rows. + Release 1.3b2 (released Dec 5, 2014) ==================================== diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 27e6d5f2c..842727b8a 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -288,9 +288,8 @@ class LaTeXTranslator(nodes.NodeVisitor): self.no_contractions = 0 self.compact_list = 0 self.first_param = 0 - self.previous_spanning_row = 0 - self.previous_spanning_column = 0 self.remember_multirow = {} + self.remember_multirowcol = {} def format_docclass(self, docclass): """ prepends prefix to sphinx document classes @@ -767,32 +766,49 @@ class LaTeXTranslator(nodes.NodeVisitor): self.visit_thead(node) self.body = self.tablebody def depart_tbody(self, node): - pass + self.remember_multirow = {} + self.remember_multirowcol = {} def visit_row(self, node): self.table.col = 0 + for key,value in self.remember_multirow.items(): + if not value and key in self.remember_multirowcol: + del self.remember_multirowcol[key] def depart_row(self, node): - if self.previous_spanning_row == 1: - self.previous_spanning_row = 0 self.body.append('\\\\\n') - self.body.append('\\hline') + if any(self.remember_multirow.values()): + linestart = 1 + for col in range(1, self.table.col + 1): + if self.remember_multirow.get(col): + if linestart != col: + linerange = str(linestart) + '-' + str(col - 1) + self.body.append('\\cline{' + linerange + '}') + linestart = col + 1 + if self.remember_multirowcol.get(col, 0): + linestart += self.remember_multirowcol[col] + if linestart <= col: + linerange = str(linestart) + '-' + str(col) + self.body.append('\\cline{' + linerange + '}') + else: + self.body.append('\\hline') self.table.rowcount += 1 def visit_entry(self, node): - if self.table.col > 0: - self.body.append(' & ') - elif self.remember_multirow.get(1, 0) > 1: - self.remember_multirow[1] -= 1 + if self.table.col == 0: + while self.remember_multirow.get(self.table.col + 1, 0): + self.table.col += 1 + self.remember_multirow[self.table.col] -= 1 + if self.remember_multirowcol.get(self.table.col, 0): + extracols = self.remember_multirowcol[self.table.col] + self.body.append(' \multicolumn{') + self.body.append(str(extracols + 1)) + self.body.append('}{|l|}{}') + self.table.col += extracols + self.body.append(' & ') + else: self.body.append(' & ') self.table.col += 1 context = '' - if 'morerows' in node: - self.body.append(' \multirow{') - self.previous_spanning_row = 1 - self.body.append(str(node.get('morerows') + 1)) - self.body.append('}{*}{') - context += '}' - self.remember_multirow[self.table.col] = node.get('morerows') + 1 if 'morecols' in node: self.body.append(' \multicolumn{') self.body.append(str(node.get('morecols') + 1)) @@ -801,12 +817,29 @@ class LaTeXTranslator(nodes.NodeVisitor): else: self.body.append('}{l|}{') context += '}' + if 'morerows' in node: + self.body.append(' \multirow{') + self.body.append(str(node.get('morerows') + 1)) + self.body.append('}{*}{') + context += '}' + self.remember_multirow[self.table.col] = node.get('morerows') + if 'morecols' in node: + if 'morerows' in node: + self.remember_multirowcol[self.table.col] = node.get('morecols') + self.table.col += node.get('morecols') if isinstance(node.parent.parent, nodes.thead): self.body.append('\\textsf{\\relax ') context += '}' - if self.remember_multirow.get(self.table.col + 1, 0) > 1: - self.remember_multirow[self.table.col + 1] -= 1 + while self.remember_multirow.get(self.table.col + 1, 0): + self.table.col += 1 + self.remember_multirow[self.table.col] -= 1 context += ' & ' + if self.remember_multirowcol.get(self.table.col, 0): + extracols = self.remember_multirowcol[self.table.col] + context += ' \multicolumn{' + context += str(extracols + 1) + context += '}{l|}{}' + self.table.col += extracols self.context.append(context) def depart_entry(self, node): self.body.append(self.context.pop()) # header diff --git a/tests/root/markup.txt b/tests/root/markup.txt index 1ad7a13b6..4d109eb6b 100644 --- a/tests/root/markup.txt +++ b/tests/root/markup.txt @@ -180,17 +180,17 @@ Tables | 2 | Empty cells: | | +----+----------------+----+ -Table with multicol: +Table with multirow and multicol: .. only:: latex - +----+---------------------+ - | 1 | test! | - +----+---------+------+----+ - | 2 | col | col | c | - | y +---------+------+----+ - | x | test | - +----+---------------------+ + +----+----------------+---------+ + | 1 | test! | c | + +----+---------+------+ | + | 2 | col | col | | + | y +---------+------+----+----+ + | x | multi-column cell | x | + +----+---------------------+----+ Figures