// SPDX-License-Identifier: GPL-2.0-only "use strict"; (async () => { if (await subEnabled()) { console.log("TeX Type started."); function cmdToUnicode(name, args) { if (name === "^") return Array.from(args[0]).reduce( (acc, c) => acc + (window.unicodeMaps.toSuperscript[c] ?? "^" + c), "" ); if (name === "_") return Array.from(args[0]).reduce( (acc, c) => acc + (window.unicodeMaps.toSubscript[c] ?? "_" + c), "" ); let sym = { "\\x": "×", "\\times": "×", "\\.": "⋅", "\\cdot": "⋅", "\\pm": "±", "\\mp": "∓", "\\in": "∈", "\\/in": "∉", "\\\\": "\u200b\\", "\\{": "\u200b{", "\\}": "\u200b}", "\\^": "\u200b^", "\\_": "\u200b_", "<===": "⇐", "==>": "⇒", "<=>": "⇔", "<==": "⟸", "=>": "⟹", "\\implies": "⟹", "<>": "⟺", "\\iff": "⟺", "<=": "⩽", "\\le": "⩽", ">=": "⩾", "\\ge": "⩾", }[name]; if (sym) return sym; if (["\\bf", "\\mathbf"].includes(name)) return Array.from(args[0]).reduce( (acc, chr) => acc + (window.unicodeMaps.toBold[chr] ?? chr), "" ); console.error("unreachable"); } function getArgs(input, i, count) { const args = []; for (let argI = 0; argI < count; argI++) { while (input.value[i] === " ") i++; if (!input.value[i]) break; if (input.value[i] === "\\") { const start = i; i = handleCmd(input, i); if (failed) break; args.push(input.value.slice(start, i)); } else if (input.value[i] === "{") { const argStart = ++i; i = subCmds(input, i); if (i === input.value.length) break; const arg = input.value.slice(argStart, i++); args.push(arg); } else { args.push(input.value[i++]); } } return { args, argsEnd: i }; } function trySubCmd(input, nameStart) { let nameEnd; if (input.value[nameStart] === "\\") { const offset = input.value.slice(nameStart + 2).search(/\W/); nameEnd = nameStart + 2 + (offset < 0 ? 0 : offset); } else if ("^_".includes(input.value[nameStart])) nameEnd = nameStart + 1; else if ( "<>=".includes(input.value[nameStart]) && ">=".includes(input.value[nameStart + 1]) ) if ("<>=".includes(input.value[nameStart + 2])) if ("<>=".includes(input.value[nameStart + 3])) nameEnd = nameStart + 4; else if (/\s/.test(input.value[nameStart + 3])) nameEnd = nameStart + 3; else return { end: nameStart + 1, success: false }; else if (/\s/.test(input.value[nameStart + 2])) nameEnd = nameStart + 2; else return { end: nameStart + 1, success: false }; else if (input.value[nameStart] === "\u200b") return { end: nameStart + 2, success: true }; else return { end: nameStart + 1, success: false }; const name = input.value.slice(nameStart, nameEnd); const argsCount = { "\\x": 0, "\\times": 0, "\\.": 0, "\\cdot": 0, "\\pm": 0, "\\mp": 0, "\\in": 0, "\\/in": 0, "\\\\": 0, "\\{": 0, "\\}": 0, "\\^": 0, "\\_": 0, "<==": 0, "=>": 0, "<=>": 0, "<===": 0, "==>": 0, "\\implies": 0, "<>": 0, "\\iff": 0, "<=": 0, "\\le": 0, ">=": 0, "\\ge": 0, "\\bf": 1, "\\mathbf": 1, "^": 1, _: 1, }[name]; if (argsCount == null) return { end: nameEnd, success: false }; const argsRet = getArgs(input, nameEnd, argsCount); const args = argsRet.args; const argsEnd = argsRet.argsEnd; if (args.length < argsCount) return { end: argsEnd, success: false }; const unicode = cmdToUnicode(name, args); input.value = input.value.slice(0, nameStart) + unicode + input.value.slice(argsEnd); const caret = input.caret; if (caret > nameStart) input.caret = caret + nameStart - argsEnd + unicode.length; return { end: nameStart + unicode.length, success: true }; } function subCmds(input, i) { const starts = []; const ends = []; if (i == null) i = 0; while (i < input.value.length) { if (input.value[i] === "}") return i; else i = trySubCmd(input, i).end; } return input.value.length; } window.addEventListener("input", (event) => { if (event.target.selectionStart != null) { const input = { value: event.target.value, caret: event.target.selectionStart, }; subCmds(input); event.target.value = input.value; event.target.selectionStart = event.target.selectionEnd = input.caret; } else if (event.target.contentEditable === "true") { const textNode = window.getSelection().anchorNode; const input = { value: textNode.textContent, caret: window.getSelection().getRangeAt(0).startOffset, }; subCmds(input); textNode.textContent = input.value; window .getSelection() .setBaseAndExtent(textNode, input.caret, textNode, input.caret); } }); } })();