Skip to content

Commit

Permalink
arrow symbols
Browse files Browse the repository at this point in the history
  • Loading branch information
qwinsi committed Aug 23, 2024
1 parent d13e6ab commit fe9681f
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 42 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tex2typst",
"version": "0.2.2",
"version": "0.2.6",
"description": "JavaScript library for converting TeX code to Typst",
"type": "module",
"main": "dist/index.js",
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { parseTex } from "./parser";
import { Tex2TypstOptions } from "./types";
import { TypstWriter } from "./writer";
import { symbolMap } from "./map";


export function tex2typst(tex: string, options?: Tex2TypstOptions): string {
Expand All @@ -26,4 +27,4 @@ export function tex2typst(tex: string, options?: Tex2TypstOptions): string {
return writer.finalize();
}

export { Tex2TypstOptions };
export { symbolMap, Tex2TypstOptions };
60 changes: 43 additions & 17 deletions src/map.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export const symbolMap = new Map<string, string>([
['gets', 'arrow.l'],
['nonumber', ''],
['vec', 'arrow'],
['neq', 'eq.not'],
Expand All @@ -25,14 +24,15 @@ export const symbolMap = new Map<string, string>([
['tfrac', 'frac'],

['boldsymbol', 'bold'],
['mathbf', 'bold'],
['mathbb', 'bb'],
['mathbf', 'bold'],
['mathcal', 'cal'],
['mathit', 'italic'],
['mathfrak', 'frak'],
['mathrm', 'upright'],
['mathsf', 'sans'],
['mathtt', 'mono'],

['mathrm', 'upright'],
['rm', 'upright'],

// TODO: \pmb need special logic to handle but it is not implemented now. See the commented test case.
Expand All @@ -58,18 +58,6 @@ export const symbolMap = new Map<string, string>([
['equiv', 'equiv'],
['propto', 'prop'],

/* arrows used in proofs */
// tex: \implies \iff \leftrightarrow \longleftrightarrow \rightrightarrows
// typst: arrow.r.double.long arrow.l.r.double.long arrow.l.r arrow.l.r.long arrows.rr
['implies', 'arrow.r.double.long'],
['Longrightarrow', 'arrow.r.double.long'], // Note: This macro is not supported by KaTeX
['iff', 'arrow.l.r.double.long'],
['Longleftrightarrow', 'arrow.l.r.double.long'], // Note: This macro is not supported by KaTeX
['leftrightarrow', 'arrow.l.r'],
['longleftrightarrow', 'arrow.l.r.long'],
['rightrightarrows', 'arrows.rr'],


/* left and right floor,ceil */
// tex: \lfloor \rfloor \lceil \rceil
// typst: ⌊ ⌋ ⌈ ⌉
Expand All @@ -80,19 +68,56 @@ export const symbolMap = new Map<string, string>([
['lceil', '⌈'],
['rceil', '⌉'],

/* arrows */
['gets', 'arrow.l'],
['hookleftarrow', 'arrow.l.hook'],
['leftharpoonup', 'harpoon.lt'],
['leftharpoondown', 'harpoon.lb'],
['rightleftharpoons', 'harpoons.rtlb'],
['longleftarrow', 'arrow.l.long'],
['longrightarrow', 'arrow.r.long'],
['longleftrightarrow', 'arrow.l.r.long'],
['Longleftarrow', 'arrow.l.double.long'],
['Longrightarrow', 'arrow.r.double.long'],
['Longleftrightarrow', 'arrow.l.r.double.long'],
['longmapsto', 'arrow.r.bar'],
['hookrightarrow', 'arrow.r.hook'],
['rightharpoonup', 'harpoon.rt'],
['rightharpoondown', 'harpoon.rb'],
['iff', 'arrow.l.r.double.long'],
['implies', 'arrow.r.double.long'],
['uparrow', 'arrow.t'],
['downarrow', 'arrow.b'],
['updownarrow', 'arrow.t.b'],
['Uparrow', 'arrow.t.double'],
['Downarrow', 'arrow.b.double'],
['Updownarrow', 'arrow.t.b.double'],
['nearrow', 'arrow.tr'],
['searrow', 'arrow.br'],
['swarrow', 'arrow.bl'],
['nwarrow', 'arrow.tl'],
['leadsto', 'arrow.squiggly'],

['leftleftarrows', 'arrows.ll'],
['rightrightarrows', 'arrows.rr'],


['Cap', 'sect.double'],
['Cup', 'union.double'],
['Delta', 'Delta'],
['Gamma', 'Gamma'],
['Join', 'join'],
['Lambda', 'Lambda'],
['Leftarrow', 'arrow.l.double'],
['Leftrightarrow', 'arrow.l.r.double'],
['Longrightarrow', 'arrow.r.double.long'],
['Omega', 'Omega'],
['P', 'pilcrow'],
['Phi', 'Phi'],
['Pi', 'Pi'],
['Psi', 'Psi'],
['Rightarrow', 'arrow.double'],
['Rightarrow', 'arrow.r.double'],
['S', 'section'],
['Sigma', 'Sigma'],
['Theta', 'Theta'],
['aleph', 'alef'],
Expand Down Expand Up @@ -126,6 +151,7 @@ export const symbolMap = new Map<string, string>([
['colon', 'colon'],
['cong', 'tilde.equiv'],
['coprod', 'product.co'],
['copyright', 'copyright'],
['cup', 'union'],
['curlyvee', 'or.curly'],
['curlywedge', 'and.curly'],
Expand Down Expand Up @@ -179,7 +205,7 @@ export const symbolMap = new Map<string, string>([
['leqslant', 'lt.eq.slant'],
['lhd', 'triangle.l'],
['ll', 'lt.double'],
['longmapsto', 'arrow.long.bar'],
['longmapsto', 'arrow.bar.long'],
['longrightarrow', 'arrow.long'],
['lor', 'or'],
['ltimes', 'times.l'],
Expand Down
27 changes: 8 additions & 19 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,25 @@ const UNARY_COMMANDS = [
'sqrt',
'text',

'arccos',
'arcsin',
'arctan',
'arg',
'bar',
'bold',
'boldsymbol',
'ddot',
'det',
'dim',
'dot',
'exp',
'gcd',
'hat',
'ker',
'mathbb',
'mathbf',
'mathcal',
'mathfrak',
'mathit',
'mathrm',
'mathscr',
'mathsf',
'mathtt',
'mathrm',
'max',
'min',
'mod',
'operatorname',
'overbrace',
'overline',
'pmb',
'sup',
'rm',
'tilde',
'underbrace',
Expand Down Expand Up @@ -295,17 +284,15 @@ function tokenize(latex: string): Token[] {
throw new LatexParserError('Expecting command name after \\');
}
const firstTwoChars = latex.slice(pos, pos + 2);
if (firstTwoChars === '\\\\') {
token = { type: 'control', value: '\\\\' };
pos += 2;
if (['\\\\', '\\,'].includes(firstTwoChars)) {
token = { type: 'control', value: firstTwoChars };
} else if (['\\{','\\}', '\\%', '\\$', '\\&', '\\#', '\\_'].includes(firstTwoChars)) {
token = { type: 'element', value: firstTwoChars };
pos += 2;
} else {
const command = eat_command_name(latex, pos + 1);
token = { type: 'command', value: '\\' + command};
pos += 1 + command.length;
}
pos += token.value.length;
break;
}
default: {
Expand Down Expand Up @@ -502,6 +489,8 @@ export class LatexParser {
throw new LatexParserError("Unmatched '}'");
case '\\\\':
return [{ type: 'control', content: '\\\\' }, start + 1];
case '\\,':
return [{ type: 'control', content: '\\,' }, start + 1];
case '_': {
let [sub, pos] = this.parseNextExpr(tokens, start + 1);
let sup: TexNode | undefined = undefined;
Expand Down
2 changes: 2 additions & 0 deletions src/writer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ export class TypstWriter {
} else if (node.type === 'control') {
if (node.content === '\\\\') {
this.queue.push({ type: 'symbol', content: node.content });
} else if (node.content === '\\,') {
this.queue.push({ type: 'symbol', content: 'thin' });
} else {
throw new TypstWriterError(`Unknown control sequence: ${node.content}`, node);
}
Expand Down
3 changes: 2 additions & 1 deletion test/cheat-sheet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import path from 'path';
import toml from 'toml';
import fs from 'node:fs';
import { describe, it, test, expect } from 'vitest';
import { tex2typst } from '../src';
import { tex2typst, symbolMap } from '../src';

interface CheatSheet {
math_commands: { [key: string]: string };
Expand Down Expand Up @@ -38,6 +38,7 @@ describe('cheat sheet', () => {
const expected = value;
const result = tex2typst(input);
expect(result).toBe(expected);
expect(symbolMap.get(key)).toBe(expected);
}
});
});
31 changes: 29 additions & 2 deletions test/cheat-sheet.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ ln = "ln"
log = "log"
mathbb = "bb"
mathcal = "cal"
mathit = "italic"
mathsf = "sans"
mathrm = "upright"
mathtt = "mono"
max = "max"
min = "min"
Expand All @@ -61,18 +63,41 @@ vec = "arrow"
widehat = "hat"

[math_symbols]
gets = "arrow.l"
hookleftarrow = "arrow.l.hook"
leftharpoonup = "harpoon.lt"
leftharpoondown = "harpoon.lb"
rightleftharpoons = "harpoons.rtlb"
longleftarrow = "arrow.l.long"
hookrightarrow = "arrow.r.hook"
rightharpoonup = "harpoon.rt"
rightharpoondown = "harpoon.rb"
iff = "arrow.l.r.double.long"
Uparrow = "arrow.t.double"
Downarrow = "arrow.b.double"
Updownarrow = "arrow.t.b.double"
nearrow = "arrow.tr"
searrow = "arrow.br"


Cap = "sect.double"
Cup = "union.double"
Delta = "Delta"
Gamma = "Gamma"
Join = "join"
Lambda = "Lambda"
Leftarrow = "arrow.l.double"
Leftrightarrow = "arrow.l.r.double"
Longleftarrow = "arrow.l.double.long"
Longleftrightarrow = "arrow.l.r.double.long"
Longrightarrow = "arrow.r.double.long"
Omega = "Omega"
P = "pilcrow"
Phi = "Phi"
Pi = "Pi"
Psi = "Psi"
Rightarrow = "arrow.double"
Rightarrow = "arrow.r.double"
S = "section"
Sigma = "Sigma"
Theta = "Theta"
aleph = "alef"
Expand Down Expand Up @@ -106,6 +131,7 @@ circ = "circle.small" # 'circle.small' or 'compose'
colon = "colon"
cong = "tilde.equiv"
coprod = "product.co"
copyright = "copyright"
cup = "union"
curlyvee = "or.curly"
curlywedge = "and.curly"
Expand Down Expand Up @@ -153,13 +179,14 @@ ldots = "dots.l"
le = "lt.eq"
leadsto = "arrow.squiggly"
leftarrow = "arrow.l"
leftleftarrows = "arrows.ll"
leftthreetimes = "times.three.l"
leftrightarrow = "arrow.l.r"
leq = "lt.eq"
leqslant = "lt.eq.slant"
lhd = "triangle.l"
ll = "lt.double"
longmapsto = "arrow.long.bar"
longmapsto = "arrow.bar.long"
longrightarrow = "arrow.long"
ltimes = "times.l"
mapsto = "arrow.bar"
Expand Down
8 changes: 7 additions & 1 deletion test/math.yml
Original file line number Diff line number Diff line change
Expand Up @@ -293,4 +293,10 @@ cases:
a + b // co
c + d
e + f // co
g + h
g + h
- title: mod
tex: a^{p-1} \equiv 1 \mod{p}
typst: a^(p - 1) equiv 1 mod p
- title: thin space
tex: a \, b
typst: a thin b

0 comments on commit fe9681f

Please sign in to comment.