diff --git a/src/buildHTML.js b/src/buildHTML.js
index dbd33a3fc..a0e2d5220 100644
--- a/src/buildHTML.js
+++ b/src/buildHTML.js
@@ -1178,6 +1178,25 @@ groupTypes.rule = function(group, options, prev) {
return rule;
};
+groupTypes.kern = function(group, options, prev) {
+ // Make an empty span for the rule
+ var rule = makeSpan(["mord", "rule"], [], options.getColor());
+
+ var dimension = 0;
+ if (group.value.dimension) {
+ dimension = group.value.dimension.number;
+ if (group.value.dimension.unit === "ex") {
+ dimension *= fontMetrics.metrics.xHeight;
+ }
+ }
+
+ dimension /= options.style.sizeMultiplier;
+
+ rule.style.marginLeft = dimension + "em";
+
+ return rule;
+};
+
groupTypes.accent = function(group, options, prev) {
// Accents are handled in the TeXbook pg. 443, rule 12.
var base = group.value.base;
diff --git a/src/buildMathML.js b/src/buildMathML.js
index f3c7c5e1c..0a4d54455 100644
--- a/src/buildMathML.js
+++ b/src/buildMathML.js
@@ -430,6 +430,13 @@ groupTypes.rule = function(group) {
return node;
};
+groupTypes.kern = function(group) {
+ // TODO(kevin): Figure out if there's a way to add space in MathML
+ var node = new mathMLTree.MathNode("mrow");
+
+ return node;
+};
+
groupTypes.llap = function(group, options) {
var node = new mathMLTree.MathNode(
"mpadded", [buildGroup(group.value.body, options)]);
diff --git a/src/functions.js b/src/functions.js
index 2fa124d3b..ea5c33ea7 100644
--- a/src/functions.js
+++ b/src/functions.js
@@ -187,6 +187,16 @@ defineFunction("\\rule", {
};
});
+defineFunction("\\kern", {
+ numArgs: 1,
+ argTypes: ["size"],
+}, function(context, args) {
+ return {
+ type: "kern",
+ dimension: args[0].value,
+ };
+});
+
// A KaTeX logo
defineFunction("\\KaTeX", {
numArgs: 0,
diff --git a/test/katex-spec.js b/test/katex-spec.js
index 75a0d393e..b6ac37e34 100644
--- a/test/katex-spec.js
+++ b/test/katex-spec.js
@@ -909,6 +909,31 @@ describe("A rule parser", function() {
});
});
+describe("A kern parser", function() {
+ var emKern = "\\kern{1em}";
+ var exKern = "\\kern{1ex}";
+ var badUnitRule = "\\kern{1px}";
+ var noNumberRule = "\\kern{em}";
+
+ it("should list the correct units", function() {
+ var emParse = getParsed(emKern)[0];
+ var exParse = getParsed(exKern)[0];
+
+ expect(emParse.value.dimension.unit).toEqual("em");
+ expect(exParse.value.dimension.unit).toEqual("ex");
+ });
+
+ it("should not parse invalid units", function() {
+ expect(badUnitRule).toNotParse();
+ expect(noNumberRule).toNotParse();
+ });
+
+ it("should parse negative sizes", function() {
+ var parse = getParsed("\\kern{-1em}")[0];
+ expect(parse.value.dimension.number).toBeCloseTo(-1);
+ });
+});
+
describe("A left/right parser", function() {
var normalLeftRight = "\\left( \\dfrac{x}{y} \\right)";
var emptyRight = "\\left( \\dfrac{x}{y} \\right.";
diff --git a/test/screenshotter/images/Kern-chrome.png b/test/screenshotter/images/Kern-chrome.png
new file mode 100644
index 000000000..232ace52c
Binary files /dev/null and b/test/screenshotter/images/Kern-chrome.png differ
diff --git a/test/screenshotter/images/Kern-firefox.png b/test/screenshotter/images/Kern-firefox.png
new file mode 100644
index 000000000..e33835dd4
Binary files /dev/null and b/test/screenshotter/images/Kern-firefox.png differ
diff --git a/test/screenshotter/ss_data.yaml b/test/screenshotter/ss_data.yaml
index d5e8736fa..6b41de8d5 100644
--- a/test/screenshotter/ss_data.yaml
+++ b/test/screenshotter/ss_data.yaml
@@ -58,6 +58,7 @@ FractionTest: \dfrac{a}{b}\frac{a}{b}\tfrac{a}{b}\;-\dfrac12\;1\tfrac12
Functions: \sin\cos\tan\ln\log
GreekLetters: \alpha\beta\gamma\omega
KaTeX: \KaTeX
+Kern: \frac{a\kern{1em}b}{c}a\kern{1em}b\kern{1ex}c\kern{-0.25em}d
Lap: ab\llap{f}cd\rlap{g}h
LeftRight: \left( x^2 \right) \left\{ x^{x^{x^{x^x}}} \right.
LeftRightListStyling: a+\left(x+y\right)-x