Skip to content

Commit

Permalink
Merge pull request #500 from LikaKavkasidze/latex-tables-none
Browse files Browse the repository at this point in the history
Implement new table system (tabularray) for LaTeX
  • Loading branch information
StaloneLab authored Apr 24, 2024
2 parents 4e46f74 + 56a9753 commit 07983fa
Show file tree
Hide file tree
Showing 12 changed files with 902 additions and 1,097 deletions.
534 changes: 234 additions & 300 deletions packages/rebber-plugins/__tests__/__snapshots__/rebber.test.js.snap

Large diffs are not rendered by default.

49 changes: 32 additions & 17 deletions packages/rebber-plugins/dist/type/gridTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,11 @@ class GridTableStringifier {
if (node.data && node.data.hProperties.rowSpan > 1) {
this.currentSpan = node.data.hProperties.rowSpan;
this.multiLineCellIndex = this.colIndex;
baseText = `\\multirow{${this.currentSpan}}{*}{\\parbox{\\linewidth}{${baseText}}}`;
baseText = `\\SetCell[r=${this.currentSpan}]{l} ${baseText}`;
this.colSpan = node.data.hProperties.colSpan > 1 ? node.data.hProperties.colSpan : 1;
} else if (node.data && node.data.hProperties.colSpan > 1) {
const colSpan = node.data.hProperties.colSpan;
const colDim = `m{\\dimexpr(\\linewidth) * ${colSpan} / \\number-of-column - 2 * \\tabcolsep}`;
baseText = `\\multicolumn{${colSpan}}{|${colDim}|}{\\parbox{\\linewidth}{${baseText}}}`;
baseText = `\\SetCell[c=${colSpan}]{l} ${baseText}`;
}
if (node.data && node.data.hProperties.colSpan > 1) {
this.colIndex -= 1;
Expand All @@ -74,21 +73,32 @@ class GridTableStringifier {
}
gridTableRow(ctx, node, index) {
const overriddenCtx = clone(ctx);
this.rowIndex++;
overriddenCtx.tableRow = undefined;
this.rowIndex++;
const extraCell = {
type: 'tableCell',
children: [{
type: 'paragraph',
children: [{
type: 'text',
value: ' '
}]
}]
};

// Duplicate cells with colSpan greater than one
for (let i = 0; i < node.children.length; i++) {
if (!node.children[i].data) continue;
const colSpan = node.children[i].data.hProperties.colSpan;
if (!colSpan || colSpan <= 1) continue;
for (let j = 0; j < colSpan - 1; j++) {
node.children.splice(i + 1, 0, extraCell);
}
}
if (this.previousRowWasMulti()) {
const lastMultiRowline = this.flushMultiRowLineIfNeeded();
for (let i = 0; i < lastMultiRowline.colSpan; i++) {
node.children.splice(lastMultiRowline.startCell - 1, 0, {
type: 'tableCell',
children: [{
type: 'paragraph',
children: [{
type: 'text',
value: ' '
}]
}]
});
node.children.splice(lastMultiRowline.startCell - 1, 0, extraCell);
}
this.colIndex = 0;
let rowStr = tableRow(overriddenCtx, node, index);
Expand Down Expand Up @@ -123,20 +133,25 @@ class GridTableStringifier {
}
return row;
}
gridTableheaderCounter(node) {
const tableHeaders = node.children.filter(n => n.data && n.data.hName === 'thead');
return tableHeaders.length >= 1 ? tableHeaders[0].children.length : 0;
}
gridTableHeaderParse() {
return `|m{\\dimexpr(\\linewidth) / ${this.nbOfColumns} - 2 * \\tabcolsep}`.repeat(this.nbOfColumns).concat('|');
return ' X[-1]'.repeat(this.nbOfColumns).substring(1);
}
previousRowWasMulti() {
return this.lastMultiRowLine !== null;
}
}
function gridTable(ctx, node) {
const overriddenCtx = clone(ctx);
overriddenCtx.spreadCell = '';
const stringifier = new GridTableStringifier();
overriddenCtx.break = () => ' \\endgraf'; // in gridtables '\\\\' won't work
// Inside tables, `\\\\` won't work
overriddenCtx.break = () => ' \\endgraf';
overriddenCtx.tableCell = stringifier.gridTableCell.bind(stringifier);
overriddenCtx.tableRow = stringifier.gridTableRow.bind(stringifier);
overriddenCtx.headerCounter = stringifier.gridTableheaderCounter.bind(stringifier);
overriddenCtx.headerParse = stringifier.gridTableHeaderParse.bind(stringifier);
overriddenCtx.image = overriddenCtx.image ? overriddenCtx.image : {};
overriddenCtx.image.inlineMatcher = () => true;
Expand Down
61 changes: 42 additions & 19 deletions packages/rebber-plugins/src/type/gridTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,11 @@ class GridTableStringifier {
if (node.data && node.data.hProperties.rowSpan > 1) {
this.currentSpan = node.data.hProperties.rowSpan
this.multiLineCellIndex = this.colIndex
baseText = `\\multirow{${this.currentSpan}}{*}{\\parbox{\\linewidth}{${baseText}}}`
baseText = `\\SetCell[r=${this.currentSpan}]{l} ${baseText}`
this.colSpan = node.data.hProperties.colSpan > 1 ? node.data.hProperties.colSpan : 1
} else if (node.data && node.data.hProperties.colSpan > 1) {
const colSpan = node.data.hProperties.colSpan
const colDim = `m{\\dimexpr(\\linewidth) * ${colSpan} / \\number-of-column - 2 * \\tabcolsep}`
baseText = `\\multicolumn{${colSpan}}{|${colDim}|}{\\parbox{\\linewidth}{${baseText}}}`
baseText = `\\SetCell[c=${colSpan}]{l} ${baseText}`
}

if (node.data && node.data.hProperties.colSpan > 1) {
Expand All @@ -81,22 +80,40 @@ class GridTableStringifier {

gridTableRow (ctx, node, index) {
const overriddenCtx = clone(ctx)
this.rowIndex++
overriddenCtx.tableRow = undefined

this.rowIndex++

const extraCell = {
type: 'tableCell',
children: [{
type: 'paragraph',
children: [{
type: 'text',
value: ' '
}]
}]
}

// Duplicate cells with colSpan greater than one
for (let i = 0; i < node.children.length; i++) {
if (!node.children[i].data) continue

const colSpan = node.children[i].data.hProperties.colSpan
if (!colSpan || colSpan <= 1) continue

for (let j = 0; j < colSpan - 1; j++) {
node.children.splice(i + 1, 0, extraCell)
}
}

if (this.previousRowWasMulti()) {
const lastMultiRowline = this.flushMultiRowLineIfNeeded()

for (let i = 0; i < lastMultiRowline.colSpan; i++) {
node.children.splice(lastMultiRowline.startCell - 1, 0, {
type: 'tableCell',
children: [{
type: 'paragraph',
children: [{
type: 'text',
value: ' '
}]
}]
})
node.children.splice(lastMultiRowline.startCell - 1, 0, extraCell)
}

this.colIndex = 0
let rowStr = tableRow(overriddenCtx, node, index)
if (lastMultiRowline.multilineCounter > 0) {
Expand Down Expand Up @@ -140,10 +157,15 @@ class GridTableStringifier {
return row
}

gridTableheaderCounter (node) {
const tableHeaders = node.children
.filter(n => n.data && n.data.hName === 'thead')

return tableHeaders.length >= 1 ? tableHeaders[0].children.length : 0
}

gridTableHeaderParse () {
return `|m{\\dimexpr(\\linewidth) / ${this.nbOfColumns} - 2 * \\tabcolsep}`
.repeat(this.nbOfColumns)
.concat('|')
return ' X[-1]'.repeat(this.nbOfColumns).substring(1)
}

previousRowWasMulti () {
Expand All @@ -153,11 +175,12 @@ class GridTableStringifier {

function gridTable (ctx, node) {
const overriddenCtx = clone(ctx)
overriddenCtx.spreadCell = ''
const stringifier = new GridTableStringifier()
overriddenCtx.break = () => ' \\endgraf' // in gridtables '\\\\' won't work
// Inside tables, `\\\\` won't work
overriddenCtx.break = () => ' \\endgraf'
overriddenCtx.tableCell = stringifier.gridTableCell.bind(stringifier)
overriddenCtx.tableRow = stringifier.gridTableRow.bind(stringifier)
overriddenCtx.headerCounter = stringifier.gridTableheaderCounter.bind(stringifier)
overriddenCtx.headerParse = stringifier.gridTableHeaderParse.bind(stringifier)

overriddenCtx.image = overriddenCtx.image ? overriddenCtx.image : {}
Expand Down
31 changes: 14 additions & 17 deletions packages/rebber/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,36 +156,33 @@ will stringify our example Markdown to `[inserted image located at "/foo.png"]`

(ctx, node) => ``,

To ensure a flexible rendering, `longtabu` environment is used by default.
Table stringification can be configured with some advanced options:

###### `options.spreadCell`
###### `options.tableEnvName`

` spread 0pt `
`longtblr`

Customize cells spacing (usually done using the `spread` command).
Common commands are ` spread <dimension> ` (add `<dimension>` as spacing ) or ` to <dimension> ` (fix the overall width of table).
Default value is ` spread 0pt ` (natural spacing).
Name of the environment to be used for tables.
Allows defining custom environments in LaTeX with `\NewTblrEnviron`.
To ensure a flexible rendering, the `longtblr` environment is used by default.

###### `options.firstLineRowFont`
###### `options.headerCounter: (node) => 1`

`'\\rowfont[c]{\\bfseries}'`
(tableRows) => 1

Customize the first line font (this is useful when your tables always have a header as first line).
Default value is `'\\rowfont[c]{\\bfseries}'` (bold, center aligned).
Function that counts the number of header rows (rows that should be emphasized).

###### `options.defaultOtherLineRowFont`
###### `options.headerProperties`

`'\\rowfont[l]{}'`
`font=\bfseries`

Customize table font for all lines except the first.
Default value is `'\\rowfont[l]{}'` (normal font, left aligned).
LaTeX properties added to header rows, follows the syntax of the underlying LaTeX package.

###### `options.headerParse: (tableRows) => ''`
###### `options.headerParse`

(tableRows) => ''
(tableRows) => ``

Cunction that computes the "latex header" part of the table environment, this generates strings such as `|c|c|r|`.
Function that computes the "latex header" part of the table environment, this generates strings such as `|c|c|r|`.
It gets an array of all the `tableRow` [mdast] nodes for the table as argument.
Default function extracts the number of columns for each row and uses the `X[-1]` handler ("find the best available width").
The result for a 3 column-table is `|X[-1]|X[-1]|X[-1]|`.
Expand Down
Loading

0 comments on commit 07983fa

Please sign in to comment.