diff --git a/src/buildHTML.js b/src/buildHTML.js
index b1b023243..7f0dcbbc1 100644
--- a/src/buildHTML.js
+++ b/src/buildHTML.js
@@ -530,9 +530,11 @@ var groupTypes = {
var inrow = group.value.body[r];
var height = arstrutHeight; // \@array adds an \@arstrut
var depth = arstrutDepth; // to each tow (via the template)
+
if (nc < inrow.length) {
nc = inrow.length;
}
+
var outrow = new Array(inrow.length);
for (c = 0; c < inrow.length; ++c) {
var elt = buildGroup(inrow[c], options);
@@ -544,6 +546,7 @@ var groupTypes = {
}
outrow[c] = elt;
}
+
var gap = 0;
if (group.value.rowGaps[r]) {
gap = group.value.rowGaps[r].value;
@@ -566,6 +569,7 @@ var groupTypes = {
gap = 0;
}
}
+
outrow.height = height;
outrow.depth = depth;
totalHeight += height;
@@ -573,21 +577,64 @@ var groupTypes = {
totalHeight += depth + gap; // \@yargarraycr
body[r] = outrow;
}
+
var offset = totalHeight / 2 + fontMetrics.metrics.axisHeight;
- var coldescriptions = group.value.cols || [];
+ var colDescriptions = group.value.cols || [];
var cols = [];
- var colsep;
- for (c = 0; c < nc; ++c) {
- var coldescr = coldescriptions[c] || {};
+ var colSep;
+ var colDescrNum;
+ for (c = 0, colDescrNum = 0;
+ // Continue while either there are more columns or more column
+ // descriptions, so trailing separators don't get lost.
+ c < nc || colDescrNum < colDescriptions.length;
+ ++c, ++colDescrNum) {
+
+ var colDescr = colDescriptions[colDescrNum] || {};
+
+ var firstSeparator = true;
+ while (colDescr.type === "separator") {
+ // If there is more than one separator in a row, add a space
+ // between them.
+ if (!firstSeparator) {
+ colSep = makeSpan(["arraycolsep"], []);
+ colSep.style.width =
+ fontMetrics.metrics.doubleRuleSep + "em";
+ cols.push(colSep);
+ }
+
+ if (colDescr.separator === "|") {
+ var separator = makeSpan(
+ ["vertical-separator"],
+ []);
+ separator.style.height = totalHeight + "em";
+ separator.style.verticalAlign =
+ -(totalHeight - offset) + "em";
+
+ cols.push(separator);
+ } else {
+ throw new ParseError(
+ "Invalid separator type: " + colDescr.separator);
+ }
+
+ colDescrNum++;
+ colDescr = colDescriptions[colDescrNum] || {};
+ firstSeparator = false;
+ }
+
+ if (c >= nc) {
+ continue;
+ }
+
var sepwidth;
if (c > 0 || group.value.hskipBeforeAndAfter) {
- sepwidth = utils.deflt(coldescr.pregap, arraycolsep);
+ sepwidth = utils.deflt(colDescr.pregap, arraycolsep);
if (sepwidth !== 0) {
- colsep = makeSpan(["arraycolsep"], []);
- colsep.style.width = sepwidth + "em";
- cols.push(colsep);
+ colSep = makeSpan(["arraycolsep"], []);
+ colSep.style.width = sepwidth + "em";
+ cols.push(colSep);
}
}
+
var col = [];
for (r = 0; r < nr; ++r) {
var row = body[r];
@@ -600,17 +647,19 @@ var groupTypes = {
elem.height = row.height;
col.push({type: "elem", elem: elem, shift: shift});
}
+
col = buildCommon.makeVList(col, "individualShift", null, options);
col = makeSpan(
- ["col-align-" + (coldescr.align || "c")],
+ ["col-align-" + (colDescr.align || "c")],
[col]);
cols.push(col);
+
if (c < nc - 1 || group.value.hskipBeforeAndAfter) {
- sepwidth = utils.deflt(coldescr.postgap, arraycolsep);
+ sepwidth = utils.deflt(colDescr.postgap, arraycolsep);
if (sepwidth !== 0) {
- colsep = makeSpan(["arraycolsep"], []);
- colsep.style.width = sepwidth + "em";
- cols.push(colsep);
+ colSep = makeSpan(["arraycolsep"], []);
+ colSep.style.width = sepwidth + "em";
+ cols.push(colSep);
}
}
}
diff --git a/src/environments.js b/src/environments.js
index 7575a158f..ff294ca7a 100644
--- a/src/environments.js
+++ b/src/environments.js
@@ -65,14 +65,19 @@ var environmentDefinitions = [
numArgs: 1,
handler: function(pos, mode, envName, colalign, positions) {
var parser = this;
- // Currently only supports alignment, no separators like | yet.
colalign = colalign.value.map ? colalign.value : [colalign];
var cols = colalign.map(function(node) {
var ca = node.value;
if ("lcr".indexOf(ca) !== -1) {
return {
+ type: "align",
align: ca
};
+ } else if (ca === "|") {
+ return {
+ type: "separator",
+ separator: "|"
+ };
}
throw new ParseError(
"Unknown column alignment: " + node.value,
@@ -134,10 +139,12 @@ var environmentDefinitions = [
type: "array",
arraystretch: 1.2,
cols: [{
+ type: "align",
align: "l",
pregap: 0,
postgap: fontMetrics.metrics.quad
}, {
+ type: "align",
align: "l",
pregap: 0,
postgap: 0
diff --git a/src/fontMetrics.js b/src/fontMetrics.js
index faa046f3f..b66bc276a 100644
--- a/src/fontMetrics.js
+++ b/src/fontMetrics.js
@@ -67,6 +67,10 @@ var xi13 = 0.1;
// match.
var ptPerEm = 10.0;
+// The space between adjacent `|` columns in an array definition. From
+// `\showthe\doublerulesep` in LaTeX.
+var doubleRuleSep = 2.0 / ptPerEm;
+
/**
* This is just a mapping from common names to real metrics
*/
@@ -94,6 +98,7 @@ var metrics = {
bigOpSpacing5: xi13,
ptPerEm: ptPerEm,
emPerEx: sigma5 / sigma6,
+ doubleRuleSep: doubleRuleSep,
// TODO(alpert): Missing parallel structure here. We should probably add
// style-specific metrics for all of these.
diff --git a/static/katex.less b/static/katex.less
index 43d6d7450..626aab74f 100644
--- a/static/katex.less
+++ b/static/katex.less
@@ -497,20 +497,28 @@
}
}
- .arraycolsep {
- display: inline-block;
- }
+ .mtable {
+ .vertical-separator {
+ display: inline-block;
+ margin: 0 -0.025em;
+ border-right: 0.05em solid black;
+ }
- .col-align-c > .vlist {
- text-align: center;
- }
+ .arraycolsep {
+ display: inline-block;
+ }
- .col-align-l > .vlist {
- text-align: left;
- }
+ .col-align-c > .vlist {
+ text-align: center;
+ }
- .col-align-r > .vlist {
- text-align: right;
+ .col-align-l > .vlist {
+ text-align: left;
+ }
+
+ .col-align-r > .vlist {
+ text-align: right;
+ }
}
}
diff --git a/test/katex-spec.js b/test/katex-spec.js
index 271cf5e8c..9d2867f1f 100644
--- a/test/katex-spec.js
+++ b/test/katex-spec.js
@@ -1463,7 +1463,22 @@ describe("An array environment", function() {
it("should accept a single alignment character", function() {
var parse = getParsed("\\begin{array}r1\\\\20\\end{array}");
expect(parse[0].type).toBe("array");
- expect(parse[0].value.cols).toEqual([{align:"r"}]);
+ expect(parse[0].value.cols).toEqual([
+ { type: "align", align: "r" }
+ ]);
+ });
+
+ it("should accept vertical separators", function() {
+ var parse = getParsed("\\begin{array}{|l||c|}\\end{array}");
+ expect(parse[0].type).toBe("array");
+ expect(parse[0].value.cols).toEqual([
+ { type: "separator", separator: "|" },
+ { type: "align", align: "l" },
+ { type: "separator", separator: "|" },
+ { type: "separator", separator: "|" },
+ { type: "align", align: "c" },
+ { type: "separator", separator: "|" }
+ ]);
});
});
diff --git a/test/screenshotter/images/Arrays-firefox.png b/test/screenshotter/images/Arrays-firefox.png
index 9f963254d..297c0e133 100644
Binary files a/test/screenshotter/images/Arrays-firefox.png and b/test/screenshotter/images/Arrays-firefox.png differ
diff --git a/test/screenshotter/ss_data.yaml b/test/screenshotter/ss_data.yaml
index 48a1d6a5a..9a31d4ce6 100644
--- a/test/screenshotter/ss_data.yaml
+++ b/test/screenshotter/ss_data.yaml
@@ -13,7 +13,7 @@
Accents: \vec{A}\vec{x}\vec x^2\vec{x}_2^2\vec{A}^2\vec{xA}^2
Arrays: |
- \left(\begin{array}{rlc}
+ \left(\begin{array}{|rl|c||}
1&2&3\\
1+1&2+1&3+1\cr1\over2&\scriptstyle 1/2&\frac12\\[1ex]
\begin{pmatrix}x\\y\end{pmatrix}&0&\begin{vmatrix}a&b\\c&d\end{vmatrix}