feat: text-mode cedilla accent via \c (#3036)

* feat: text-mode cedilla accent via \c

Add text-mode accent function `\c` and corresponding Unicode support.

Part of #638

Co-authored-by: Kevin Barabash <kevinb@khanacademy.org>

* Update screenshots

Co-authored-by: Kevin Barabash <kevinb@khanacademy.org>
This commit is contained in:
Erik Demaine
2021-08-28 18:29:53 -04:00
committed by GitHub
parent f8c211da3c
commit 952fb844da
9 changed files with 22 additions and 8 deletions

View File

@@ -951,7 +951,8 @@ export default class Parser {
if (!unicodeAccents[accent]) { if (!unicodeAccents[accent]) {
throw new ParseError(`Unknown accent ' ${accent}'`, nucleus); throw new ParseError(`Unknown accent ' ${accent}'`, nucleus);
} }
const command = unicodeAccents[accent][this.mode]; const command = unicodeAccents[accent][this.mode] ||
unicodeAccents[accent].text;
if (!command) { if (!command) {
throw new ParseError( throw new ParseError(
`Accent ${accent} unsupported in ${this.mode} mode`, `Accent ${accent} unsupported in ${this.mode} mode`,

View File

@@ -108,11 +108,9 @@ import metricMap from "./fontMetricsData";
const extraCharacterMap = { const extraCharacterMap = {
// Latin-1 // Latin-1
'Å': 'A', 'Å': 'A',
'Ç': 'C',
'Ð': 'D', 'Ð': 'D',
'Þ': 'o', 'Þ': 'o',
'å': 'a', 'å': 'a',
'ç': 'c',
'ð': 'd', 'ð': 'd',
'þ': 'o', 'þ': 'o',

View File

@@ -74,10 +74,14 @@ export const htmlBuilder: HtmlBuilderSupSub<"accent"> = (grp, options) => {
// TODO(emily): Find a better way to get the skew // TODO(emily): Find a better way to get the skew
} }
const accentBelow = group.label === "\\c";
// calculate the amount of space between the body and the accent // calculate the amount of space between the body and the accent
let clearance = Math.min( let clearance = accentBelow
body.height, ? body.height + body.depth
options.fontMetrics().xHeight); : Math.min(
body.height,
options.fontMetrics().xHeight);
// Build the accent // Build the accent
let accentBody; let accentBody;
@@ -100,6 +104,9 @@ export const htmlBuilder: HtmlBuilderSupSub<"accent"> = (grp, options) => {
// shift the accent over to a place we don't want. // shift the accent over to a place we don't want.
accent.italic = 0; accent.italic = 0;
width = accent.width; width = accent.width;
if (accentBelow) {
clearance += accent.depth;
}
} }
accentBody = buildCommon.makeSpan(["accent-body"], [accent]); accentBody = buildCommon.makeSpan(["accent-body"], [accent]);
@@ -244,7 +251,7 @@ defineFunction({
type: "accent", type: "accent",
names: [ names: [
"\\'", "\\`", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"', "\\'", "\\`", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"',
"\\r", "\\H", "\\v", "\\textcircled", "\\c", "\\r", "\\H", "\\v", "\\textcircled",
], ],
props: { props: {
numArgs: 1, numArgs: 1,

View File

@@ -706,6 +706,7 @@ defineSymbol(text, main, accent, "\u02dc", "\\~"); // tilde
defineSymbol(text, main, accent, "\u02c9", "\\="); // macron defineSymbol(text, main, accent, "\u02c9", "\\="); // macron
defineSymbol(text, main, accent, "\u02d8", "\\u"); // breve defineSymbol(text, main, accent, "\u02d8", "\\u"); // breve
defineSymbol(text, main, accent, "\u02d9", "\\."); // dot above defineSymbol(text, main, accent, "\u02d9", "\\."); // dot above
defineSymbol(text, main, accent, "\u00b8", "\\c"); // cedilla
defineSymbol(text, main, accent, "\u02da", "\\r"); // ring above defineSymbol(text, main, accent, "\u02da", "\\r"); // ring above
defineSymbol(text, main, accent, "\u02c7", "\\v"); // caron defineSymbol(text, main, accent, "\u02c7", "\\v"); // caron
defineSymbol(text, main, accent, "\u00a8", '\\"'); // diaresis defineSymbol(text, main, accent, "\u00a8", '\\"'); // diaresis
@@ -875,7 +876,7 @@ for (let i = 0; i < 10; i++) {
// but they are not actually in the font, nor are they supported by the // but they are not actually in the font, nor are they supported by the
// Unicode accent mechanism, so they fall back to Times font and look ugly. // Unicode accent mechanism, so they fall back to Times font and look ugly.
// TODO(edemaine): Fix this. // TODO(edemaine): Fix this.
export const extraLatin = "\u00c7\u00d0\u00de\u00e7\u00fe"; export const extraLatin = "\u00d0\u00de\u00fe";
for (let i = 0; i < extraLatin.length; i++) { for (let i = 0; i < extraLatin.length; i++) {
const ch = extraLatin.charAt(i); const ch = extraLatin.charAt(i);
defineSymbol(math, main, mathord, ch, ch); defineSymbol(math, main, mathord, ch, ch);

View File

@@ -14,4 +14,5 @@ module.exports = {
'\u0307': {text: '\\.', math: '\\dot'}, '\u0307': {text: '\\.', math: '\\dot'},
'\u030a': {text: '\\r', math: '\\mathring'}, '\u030a': {text: '\\r', math: '\\mathring'},
'\u030b': {text: '\\H'}, '\u030b': {text: '\\H'},
'\u0327': {text: '\\c'},
}; };

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -9,6 +9,12 @@ describe("unicode", function() {
.toBuild(); .toBuild();
}); });
it("should build Latin-1 inside \\text{} like accent commands", function() {
expect`\text{ÀÁÂÃÄÅÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝàáâãäåèéêëìíîïñòóôõöùúûüýÿÇç}`
.toParseLike`\text{\`A\'A\^A\~A\"A\r A\`E\'E\^E\"E\`I\'I\^I\"I\~N\`O\'O\^O\~O\"O\`U\'U\^U\"U\'Y\`a\'a\^a\~a\"a\r a\`e\'e\^e\"e\`ı\'ı\^ı\"ı\~n\`o\'o\^o\~o\"o\`u\'u\^u\"u\'y\"y\c C\c c}`;
// TODO(edemaine): A few characters don't have analogs yet.
});
it("should not parse Latin-1 outside \\text{} with strict", function() { it("should not parse Latin-1 outside \\text{} with strict", function() {
const chars = 'ÀÁÂÃÄÅÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝàáâãäåèéêëìíîïñòóôõöùúûüýÿÇÐÞçþ'; const chars = 'ÀÁÂÃÄÅÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝàáâãäåèéêëìíîïñòóôõöùúûüýÿÇÐÞçþ';
for (const ch of chars) { for (const ch of chars) {