Repository: KaTeX/KaTeX (js)

Issue:
add \emph
`\text{a}` and `\textit{a}` compile find with KaTeX, `\emph{a}` doesn't. Perhaps that'd be a worthwhile addition.

Pull request description:
feat: add \emph
<!-- PR title should follow Angular Commit Message Conventions (https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#-git-commit-guidelines) -->

**What is the previous behavior before this PR?**
`\emph` wasn't supported

**What is the new behavior after this PR?**
`\emph` is supported

![image](https://github.com/KaTeX/KaTeX/assets/8845364/1e1697ea-fcf3-4e7c-bf53-d977af0db170)

Implements default behavior of making text italic if it's not and making text upright if it's italic. Please let me know ff more complex rules are required.

Closes #3566 


Patch:
diff --git a/docs/support_table.md b/docs/support_table.md
index d1bc7680..675e4f48 100644
--- a/docs/support_table.md
+++ b/docs/support_table.md
@@ -369,7 +369,7 @@ use `\ce` instead|
 |\ell|$\ell$||
 |\else|<span style="color:firebrick;">Not supported</span>|[Issue #1003](https://github.com/KaTeX/KaTeX/issues/1003)|
 |\em|<span style="color:firebrick;">Not supported</span>||
-|\emph|<span style="color:firebrick;">Not supported</span>||
+|\emph|$\emph{nested \emph{emphasis}}$|`\emph{nested \emph{emphasis}}`|
 |\empty|$\empty$||
 |\emptyset|$\emptyset$||
 |\enclose|<span style="color:firebrick;">Not supported</span>|Non standard
diff --git a/docs/supported.md b/docs/supported.md
index 5c42bfdb..f5ff5f8b 100644
--- a/docs/supported.md
+++ b/docs/supported.md
@@ -595,17 +595,17 @@ For color definition, KaTeX color functions will accept the standard HTML [pred
 
 ||||
 |:------------------------------|:------------------------------|:-----
-|$\mathrm{Ab0}$ `\mathrm{Ab0}`  |$\mathbf{Ab0}$ `\mathbf{Ab0}`  |$\mathit{Ab0}$ `\mathit{Ab0}`
-|$\mathnormal{Ab0}$ `\mathnormal{Ab0}`|$\textbf{Ab0}$ `\textbf{Ab0}`  |$\textit{Ab0}$ `\textit{Ab0}`
-|$\textrm{Ab0}$ `\textrm{Ab0}`  |$\bf Ab0$ `\bf Ab0`            |$\it Ab0$ `\it Ab0`
-|$\rm Ab0$ `\rm Ab0`            |$\bold{Ab0}$ `\bold{Ab0}`      |$\textup{Ab0}$ `\textup{Ab0}`
-|$\textnormal{Ab0}$ `\textnormal{Ab0}`|$\boldsymbol{Ab0}$ `\boldsymbol{Ab}`|$\Bbb{AB}$ `\Bbb{AB}`
-|$\text{Ab0}$ `\text{Ab0}`      |$\bm{Ab0}$ `\bm{Ab0}`          |$\mathbb{AB}$ `\mathbb{AB}`
-|$\mathsf{Ab0}$ `\mathsf{Ab0}`  |$\textmd{Ab0}$ `\textmd{Ab0}`  |$\frak{Ab0}$ `\frak{Ab0}`
-|$\textsf{Ab0}$ `\textsf{Ab0}`  |$\mathtt{Ab0}$ `\mathtt{Ab0}`  |$\mathfrak{Ab0}$ `\mathfrak{Ab0}`
-|$\sf Ab0$ `\sf Ab0`            |$\texttt{Ab0}$ `\texttt{Ab0}`  |$\mathcal{AB0}$ `\mathcal{AB0}`
-|                               |$\tt Ab0$ `\tt Ab0`            |$\cal AB0$ `\cal AB0`
-|                               |                               |$\mathscr{AB}$ `\mathscr{AB}`
+|$\mathrm{Ab0}$ `\mathrm{Ab0}`  |$\mathbf{Ab0}$ `\mathbf{Ab0}`  |$\mathsf{Ab0}$ `\mathsf{Ab0}`
+|$\mathnormal{Ab0}$ `\mathnormal{Ab0}`|$\textbf{Ab0}$ `\textbf{Ab0}`  |$\textsf{Ab0}$ `\textsf{Ab0}`
+|$\textrm{Ab0}$ `\textrm{Ab0}`  |$\bf Ab0$ `\bf Ab0`            |$\sf Ab0$ `\sf Ab0`
+|$\rm Ab0$ `\rm Ab0`            |$\bold{Ab0}$ `\bold{Ab0}`      |$\Bbb{AB}$ `\Bbb{AB}`
+|$\textnormal{Ab0}$ `\textnormal{Ab0}`|$\boldsymbol{Ab0}$ `\boldsymbol{Ab}`|$\mathbb{AB}$ `\mathbb{AB}`
+|$\text{Ab0}$ `\text{Ab0}`      |$\bm{Ab0}$ `\bm{Ab0}`          |$\frak{Ab0}$ `\frak{Ab0}`
+|$\textup{Ab0}$ `\textup{Ab0}`  |$\textmd{Ab0}$ `\textmd{Ab0}`  |$\mathfrak{Ab0}$ `\mathfrak{Ab0}`
+|$\mathit{Ab0}$ `\mathit{Ab0}`  |$\mathtt{Ab0}$ `\mathtt{Ab0}`  |$\mathcal{AB0}$ `\mathcal{AB0}`
+|$\textit{Ab0}$ `\textit{Ab0}`  |$\texttt{Ab0}$ `\texttt{Ab0}`  |$\cal AB0$ `\cal AB0`
+|$\it Ab0$ `\it Ab0`            |$\tt Ab0$ `\tt Ab0`            |$\mathscr{AB}$ `\mathscr{AB}`
+|$\emph{Ab0}$ `\emph{Ab0}`      |                               ||
 
 One can stack font family, font weight, and font shape by using the `\textXX` versions of the font functions. So `\textsf{\textbf{H}}` will produce $\textsf{\textbf{H}}$. The other versions do not stack, e.g., `\mathsf{\mathbf{H}}` will produce $\mathsf{\mathbf{H}}$.
 
diff --git a/src/functions/text.js b/src/functions/text.js
index 7acf5434..9d3c674e 100644
--- a/src/functions/text.js
+++ b/src/functions/text.js
@@ -30,9 +30,13 @@ const optionsWithFont = (group, options) => {
         return options.withTextFontFamily(textFontFamilies[font]);
     } else if (textFontWeights[font]) {
         return options.withTextFontWeight(textFontWeights[font]);
-    } else {
-        return options.withTextFontShape(textFontShapes[font]);
+    } else if (font === "\\emph") {
+        return options.fontShape === "textit" ?
+            options.withTextFontShape("textup") :
+            options.withTextFontShape("textit");
     }
+
+    return options.withTextFontShape(textFontShapes[font]);
 };
 
 defineFunction({
@@ -43,7 +47,7 @@ defineFunction({
         // Font weights
         "\\textbf", "\\textmd",
         // Font Shapes
-        "\\textit", "\\textup",
+        "\\textit", "\\textup", "\\emph",
     ],
     props: {
         numArgs: 1,


Test patch:
diff --git a/test/katex-spec.js b/test/katex-spec.js
index ef6a5b37..a5b3ad2a 100644
--- a/test/katex-spec.js
+++ b/test/katex-spec.js
@@ -4241,3 +4241,21 @@ describe("\\relax", () => {
         expect`\kern2\relax em`.not.toParse();
     });
 });
+
+describe("\\emph", () => {
+    it("should toggle italics", () => {
+        expect`\emph{foo \emph{bar}}`.toBuildLike`\textit{foo \textup{bar}}`;
+    });
+
+    it("should toggle italics within text", () => {
+        expect`\text{\emph{foo \emph{bar}}}`.toBuildLike`\text{\textit{foo \textup{bar}}}`;
+    });
+
+    it("should toggle italics within textup", () => {
+        expect`\textup{\emph{foo \emph{bar}}}`.toBuildLike`\textup{\textit{foo \textup{bar}}}`;
+    });
+
+    it("should toggle italics within textit", () => {
+        expect`\textit{\emph{foo \emph{bar}}}`.toBuildLike`\textit{\textup{foo \textit{bar}}}`;
+    });
+});