Skip to content

Commit

Permalink
Implement command tokens and handlers in parser
Browse files Browse the repository at this point in the history
For now only font commands are commands, previously these were styles
and implemented along with other prefixes. Now commands will become
new binary prefix nodes in the AST which can apply special commands on
the nodes below. For fonts this means to some text transforms or add style
attributes. In the future we might implement color #40 and align #39
with command tokens.

**Language Changes**

- Now you can stack some font commands to combine them. For example,
  if you want bold italic A you can write `bf it A`. Not all font
  commands stack though e.g. `fr bb` will not give you double-struck
  fraktur.

**Output Changes**

- With the exception of `mathvariant="normal"` we no longer use the
  `mathvariant` attribute. Instead we apply the relevant text
  transform directly and the unicode characters in the output (see #70).
- Text gets some font commands applied via CSS (see #78). Specifically
  this is `bf`, `it`, `sf` and `tt` on texts (e.g. `bf tt "text"`).
  The latter two change the font-family of the output. If you want
  control of sans-serif and monospace fonts in the output you can set
  the CSS custom properties `--mathup-font-family-sans-serif`
  and `--mathup-font-family-monospace` respectively.

**Breaking Changes**

- Font commands now only applies to the first item in a term,
  previously it was applied on the entire term (see #77). `bf A_(i j)`
  would previously also boldface the indices (i j), but now it only
  boldfaces the matrix A.
- Font commands will no longer unwrap fences around the operant. For
  example if you write `bf(A)` previously the parenteses would be
  stripped, and you would only end up with A. Now the parenteses are
  left as is.

Resolves: #70
Resolves: #77
Resolves: #78
  • Loading branch information
runarberg committed Nov 2, 2023
1 parent 55a7d12 commit a0e160d
Show file tree
Hide file tree
Showing 24 changed files with 1,176 additions and 161 deletions.
38 changes: 31 additions & 7 deletions demo/test-cases.html
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ <h2>Groupings</h2>
<test-case>NN = {1, 2, 3, ...}</test-case>

<test-case display="block">
(: V(t)^2 :) = lim _ T-&gt;oo 1/T int_(-T/2)^(T/2) V(t)^2 dt
(: V(t)^2 :) = lim_(T-&gt;oo) 1/T int_(-T/2)^(T/2) V(t)^2 dt
</test-case>
</section>

Expand All @@ -244,9 +244,9 @@ <h2>Super and Subscripts</h2>
<section id="test-cases-over-underscripts">
<h2>Over and Underscripts</h2>

<test-case display="block">lim _ a-&gt;b</test-case>
<test-case display="block">sum _ i=0 ^ n</test-case>
<test-case display="block">prod _ i=1 ^ n</test-case>
<test-case display="block">lim_(a-&gt;b)</test-case>
<test-case display="block">sum_(i=0)^n</test-case>
<test-case display="block">prod_(i=1)^n</test-case>

<test-case display="block">
phi =.^"def" a/b = a+b / a
Expand Down Expand Up @@ -316,22 +316,40 @@ <h2>Matrices</h2>
<section id="test-cases-fonts">
<h2>Fonts</h2>

<test-case display="block">
bb E[X] = int_(-oo)^oo x f(x) bb it dx
</test-case>

<test-case display="block">
bb P(x) = 1 \for 0 &leq; x &leq; 1
</test-case>

<test-case display="block">
it`proj`_(bf v) bf a = (bf a*v) / (norm(bf v)^2) bf v
</test-case>

<section>
<h3>Text</h3>

<test-case>"abcd"</test-case>
<test-case>rm"AaBbCc"</test-case>
<test-case>it"AaBbCc"</test-case>
<test-case>bf"AaBbCc"</test-case>
<test-case>bf it "AaBbCc"</test-case>
<test-case>bb"AaBbCc"</test-case>
<test-case>cc"AaBbCc"</test-case>
<test-case>bf cc"AaBbCc"</test-case>
<test-case>fr"AaBbCc"</test-case>
<test-case>fr bf"AaBbCc"</test-case>
<test-case>sf"AaBbCc"</test-case>
<test-case>it sf"AaBbCc"</test-case>
<test-case>bf sf"AaBbCc"</test-case>
<test-case>it bf sf"AaBbCc"</test-case>
<test-case>tt"AaBbCc"</test-case>
<test-case>bf tt"AaBbCc"</test-case>
<test-case>it tt"AaBbCc"</test-case>
<test-case>it bf tt"AaBbCc"</test-case>

<test-case display="block">
it`proj`_(bf v) bf a = bf(a*v) / (norm(bf v)^2) bf`v`
</test-case>
</section>

<section id="test-cases-forced-identifiers">
Expand All @@ -340,12 +358,18 @@ <h3>Forced identifiers</h3>
<test-case>`Gamma` != Gamma</test-case>
<test-case>rm`e`</test-case>
<test-case>it`ln`</test-case>
<test-case>bf it`ln`</test-case>
<test-case>bf`1234`</test-case>
<test-case>bb`1234`</test-case>
<test-case>cc`l`</test-case>
<test-case>bf cc`l`</test-case>
<test-case>fr`g`</test-case>
<test-case>bf fr`g`</test-case>
<test-case>sf`1234`</test-case>
<test-case>bf sf`1234`</test-case>
<test-case>it sf`AaBbCc`</test-case>
<test-case>tt`1234`</test-case>
<test-case>i rm i</test-case>
</section>
</section>

Expand Down
94 changes: 79 additions & 15 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ <h1>Mathup</h1>
<div class="input">
<p><label for="try-input">You write…</label></p>

<textarea id="try-input">bb E [X] = int_(-oo)^oo x f(x) dx</textarea>
<textarea id="try-input">bb E[X] = int_(-oo)^oo x f(x) dx</textarea>

<div class="options">
<label for="try-decimalmark">Decimal mark</label>
Expand Down Expand Up @@ -1404,7 +1404,7 @@ <h3>Spaces</h3>
<li>
<!-- prettier-ignore -->
<use-example>
bb P (x) = 1 \for 0 &leq; x &leq; 1
bb P(x) = 1 \for 0 &leq; x &leq; 1
</use-example>
</li>

Expand Down Expand Up @@ -1759,7 +1759,7 @@ <h3>Fenced Groups</h3>
<li>
<!-- prettier-ignore -->
<use-example>
&lt;&lt;V(t)^2&gt;&gt; = lim_ T-&gt;oo 1/T int _ -T/2 ^ T/2 V(t)^2 dt
&lt;&lt;V(t)^2&gt;&gt; = lim_(T-&gt;oo) 1/T int_(-T/2)^(T/2) V(t)^2 dt
</use-example>
</li>
</ul>
Expand Down Expand Up @@ -1971,8 +1971,23 @@ <h3>Accents</h3>
<h3>Font commands</h3>

<p>
You can prefix any expression with a font command. Then all token
elements in that expression will have the following variant.
You can prefix any expression with a font command. Then
all token elements in that expression will have the
following variant. Some variants can be combined, order
doesn’t matter.
</p>

<p>
Bold (<code>bf</code>), italic (<code>it</code>),
sans-serif (<code>sf</code>), and monospace
(<code>tt</code>) on texts (<code>bf tt "text"</code>) are
set using CSS. If you want to control the font-family of
sans-serif and monospace texts, you can set
the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties">CSS
custom
properties</a> <code>--mathup-font-family-sans-serif</code>
and <code>--mathup-font-family-monospace</code>
respectively.
</p>

<details>
Expand All @@ -1982,56 +1997,98 @@ <h3>Font commands</h3>
<dt><code>rm</code></dt>
<dd>
<math>
<mtext mathvariant="normal">normal</mtext>
<mtext>normal</mtext>
</math>
</dd>

<dt><code>bf</code></dt>
<dd>
<math>
<mtext mathvariant="bold">bold</mtext>
<mtext style="font-weight:bold;">bold</mtext>
</math>
</dd>

<dt><code>it</code></dt>
<dd>
<math>
<mtext mathvariant="italic">italic</mtext>
<mtext style="font-style:italic;">italic</mtext>
</math>
</dd>

<dt><code>bf it</code></dt>
<dd>
<math>
<mtext style="font-weight:bold;font-style:italic;">bold italic</mtext>
</math>
</dd>

<dt><code>bb</code></dt>
<dd>
<math>
<mtext mathvariant="double-struck">double-struck</mtext>
<mtext>𝕕𝕠𝕦𝕓𝕝𝕖-𝕤𝕥𝕣𝕦𝕔𝕜</mtext>
</math>
</dd>

<dt><code>cc</code></dt>
<dd>
<math>
<mtext mathvariant="script">script</mtext>
<mtext>𝓈𝒸𝓇𝒾𝓅𝓉</mtext>
</math>
</dd>

<dt><code>bf cc</code></dt>
<dd>
<math>
<mtext>𝓼𝓬𝓻𝓲𝓹𝓽</mtext>
</math>
</dd>

<dt><code>fr</code></dt>
<dd>
<math>
<mtext mathvariant="fraktur">fraktur</mtext>
<mtext>𝔣𝔯𝔞𝔠𝔱𝔲𝔯</mtext>
</math>
</dd>

<dt><code>bf fr</code></dt>
<dd>
<math>
<mtext>𝖋𝖗𝖆𝖈𝖙𝖚𝖗</mtext>
</math>
</dd>

<dt><code>sf</code></dt>
<dd>
<math>
<mtext mathvariant="sans-serif">sans-serif</mtext>
<mtext>𝗌𝖺𝗇𝗌-𝗌𝖾𝗋𝗂𝖿</mtext>
</math>
</dd>

<dt><code>bf sf</code></dt>
<dd>
<math>
<mtext>𝘀𝗮𝗻𝘀-𝘀𝗲𝗿𝗶𝗳</mtext>
</math>
</dd>

<dt><code>it sf</code></dt>
<dd>
<math>
<mtext>𝘴𝘢𝘯𝘴-𝘴𝘦𝘳𝘪𝘧</mtext>
</math>
</dd>

<dt><code>bf it sf</code></dt>
<dd>
<math>
<mtext>𝙨𝙖𝙣𝙨-𝙨𝙚𝙧𝙞𝙛</mtext>
</math>
</dd>

<dt><code>tt</code></dt>
<dd>
<math>
<mtext mathvariant="monospace">monospace</mtext>
<mtext>𝚖𝚘𝚗𝚘𝚜𝚙𝚊𝚌𝚎</mtext>
</math>
</dd>
</dl>
Expand All @@ -2042,14 +2099,21 @@ <h3>Font commands</h3>
<li>
<!-- prettier-ignore -->
<use-example>
bb`1` _({x in X})
bb`1`_({x in X})
</use-example>
</li>

<li>
<!-- prettier-ignore -->
<use-example>
it`proj`_(bf v) bf a = (bf a*v) / (norm(bf v)^2) bf v
</use-example>
</li>

<li>
<!-- prettier-ignore -->
<use-example>
it`proj` _(bf v) bf a = (bf a*v) / (norm(bf v)^2) bf v
bb E[X] = int_(-oo)^oo x f(x) bb it d x
</use-example>
</li>
</ul>
Expand Down
81 changes: 81 additions & 0 deletions src/compiler/parser/handlers/command.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import expr from "./expr.js";

/**
* @typedef {import("../index.js").Node} Node
* @typedef {import("../index.js").UnaryOperation} UnaryOperation
* @typedef {import("../index.js").Term} Term
*/

/**
* @param {import("../parse.js").State} State
* @return {{ node: UnaryOperation | Term, end: number }}
*/
export default function command({ start, tokens }) {
const token = tokens[start];

if (!token.name) {
throw new Error("Got command token without a name");
}

const textTransforms = [];

if (token.name === "text-transform" && token.value) {
textTransforms.push(token.value);
}

let pos = start + 1;
let nextToken = tokens[pos];
while (
nextToken &&
(nextToken.type === "command" || nextToken.type === "space")
) {
if (
nextToken.type === "command" &&
nextToken.name === "text-transform" &&
token.value
) {
textTransforms.push(nextToken.value);
}

pos += 1;
nextToken = tokens[pos];
}

const next = expr({ stack: [], start: pos, tokens });

if (next.node.type === "Term") {
// Only apply command to the first item in the term
const [first, ...rest] = next.node.items;

/** @type {Node[]} */
const items = first
? [
{
type: "UnaryOperation",
name: "command",
transforms: textTransforms,
items: [first],
},
...rest,
]
: [];

return {
node: {
type: "Term",
items,
},
end: next.end,
};
}

return {
node: {
type: "UnaryOperation",
name: "command",
transforms: textTransforms,
items: [next.node],
},
end: next.end,
};
}
Loading

0 comments on commit a0e160d

Please sign in to comment.