diff --git a/common/package-lock.json b/common/package-lock.json index 5df6794..ee15bf5 100644 --- a/common/package-lock.json +++ b/common/package-lock.json @@ -13,7 +13,6 @@ "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^28.0.0", "@rollup/plugin-node-resolve": "^15.3.0", - "@types/chai-as-promised": "^8.0.1", "c8": "^10.1.2", "rollup": "^4.22.4", "rollup-plugin-cleanup": "^3.2.1" @@ -2199,17 +2198,9 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.0.0.tgz", "integrity": "sha512-+DwhEHAaFPPdJ2ral3kNHFQXnTfscEEFsUxzD+d7nlcLrFK23JtNjH71RGasTcHb88b4vVi4mTyfpf8u2L8bdA==", + "dev": true, "license": "MIT" }, - "node_modules/@types/chai-as-promised": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-8.0.1.tgz", - "integrity": "sha512-dAlDhLjJlABwAVYObo9TPWYTRg9NaQM5CXeaeJYcYAkvzUf0JRLIiog88ao2Wqy/20WUnhbbUZcgvngEbJ3YXQ==", - "license": "MIT", - "dependencies": { - "@types/chai": "*" - } - }, "node_modules/@types/chai-spies": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/chai-spies/-/chai-spies-1.0.6.tgz", diff --git a/common/package.json b/common/package.json index a368ef5..e85d3ff 100644 --- a/common/package.json +++ b/common/package.json @@ -25,7 +25,6 @@ "devDependencies": { "@types/chai": "^5.0.0", "@types/chai-spies": "^1.0.6", - "@types/chai-as-promised": "^8.0.1", "@types/mocha": "^10.0.8", "chai": "^5.1.1", "chai-as-promised": "^8.0.0", diff --git a/common/src/lib/expr-eval/polyfill.mjs b/common/src/lib/expr-eval/polyfill.mjs index a15c741..c618aaf 100644 --- a/common/src/lib/expr-eval/polyfill.mjs +++ b/common/src/lib/expr-eval/polyfill.mjs @@ -266,6 +266,11 @@ export function roundTo(value, exp) { return +(value[0] + "e" + (value[1] ? (+value[1] + exp) : exp)) } +export function setVar(name, value, variables) { + if(variables) variables[name] = value + return value +} + export function arrayIndex(array, index) { return array[index | 0] } diff --git a/common/src/module/latex.mjs b/common/src/module/latex.mjs index 216e3be..830f096 100644 --- a/common/src/module/latex.mjs +++ b/common/src/module/latex.mjs @@ -21,7 +21,7 @@ import * as Instruction from "../lib/expr-eval/instruction.mjs" import { escapeValue } from "../lib/expr-eval/expression.mjs" import { HelperInterface, LatexInterface } from "./interface.mjs" -const unicodechars = ["pi", "∞", +const unicodechars = [ "α", "β", "γ", "δ", "ε", "ζ", "η", "π", "θ", "κ", "λ", "μ", "ξ", "ρ", "ς", "σ", "τ", "φ", "χ", "ψ", "ω", @@ -30,9 +30,9 @@ const unicodechars = ["pi", "∞", "ₕ", "ₖ", "ₗ", "ₘ", "ₙ", "ₚ", "ₛ", "ₜ", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹", "⁰", "₁", "₂", "₃", - "₄", "₅", "₆", "₇", "₈", "₉", "₀" -] -const equivalchars = ["\\pi", "\\infty", + "₄", "₅", "₆", "₇", "₈", "₉", "₀", + "pi", "∞"] +const equivalchars = [ "\\alpha", "\\beta", "\\gamma", "\\delta", "\\epsilon", "\\zeta", "\\eta", "\\pi", "\\theta", "\\kappa", "\\lambda", "\\mu", "\\xi", "\\rho", "\\sigma", "\\sigma", "\\tau", "\\phi", "\\chi", "\\psi", "\\omega", @@ -42,7 +42,7 @@ const equivalchars = ["\\pi", "\\infty", "{}_{t}", "{}^{1}", "{}^{2}", "{}^{3}", "{}^{4}", "{}^{5}", "{}^{6}", "{}^{7}", "{}^{8}", "{}^{9}", "{}^{0}", "{}_{1}", "{}_{2}", "{}_{3}", "{}_{4}", "{}_{5}", "{}_{6}", "{}_{7}", "{}_{8}", "{}_{9}", "{}_{0}", -] + "\\pi", "\\infty"] /** * Class containing the result of a LaTeX render. @@ -62,7 +62,7 @@ class LatexRenderResult { class LatexAPI extends Module { /** @type {LatexInterface} */ #latex = null - + constructor() { super("Latex", { latex: LatexInterface, @@ -142,10 +142,9 @@ class LatexAPI extends Module { */ parif(elem, contents) { elem = elem.toString() - const contains = contents.some(x => elem.indexOf(x) > 0) - if(contains && (elem[0] !== "(" || elem.at(-1) !== ")")) + if(elem[0] !== "(" && elem.at(-1) !== ")" && contents.some(x => elem.indexOf(x) > 0)) return this.par(elem) - if(!contains && elem[0] === "(" && elem.at(-1) === ")") + if(elem[0] === "(" && elem.at(-1) === ")") return elem.removeEnclosure() return elem } @@ -170,14 +169,13 @@ class LatexAPI extends Module { else return `\\int\\limits_{${args[0]}}^{${args[1]}}${args[2]}(t) dt` case "sqrt": - const arg = this.parif(args.join(", "), []) - return `\\sqrt{${arg}}` + return `\\sqrt\\left(${args.join(", ")}\\right)` case "abs": return `\\left|${args.join(", ")}\\right|` case "floor": - return `\\left\\lfloor{${args.join(", ")}}\\right\\rfloor` + return `\\left\\lfloor${args.join(", ")}\\right\\rfloor` case "ceil": - return `\\left\\lceil{${args.join(", ")}}\\right\\rceil` + return `\\left\\lceil${args.join(", ")}\\right\\rceil` default: return `\\mathrm{${f}}\\left(${args.join(", ")}\\right)` } @@ -191,17 +189,16 @@ class LatexAPI extends Module { * @returns {string} */ variable(vari, wrapIn$ = false) { - if(wrapIn$) { + if(wrapIn$) for(let i = 0; i < unicodechars.length; i++) { if(vari.includes(unicodechars[i])) vari = vari.replaceAll(unicodechars[i], "$" + equivalchars[i] + "$") } - } else { + else for(let i = 0; i < unicodechars.length; i++) { if(vari.includes(unicodechars[i])) vari = vari.replaceAll(unicodechars[i], equivalchars[i]) } - } return vari } @@ -296,7 +293,7 @@ class LatexAPI extends Module { nstack.push(this.parif(n1, ["+", "-", "*", "/", "^"]) + "!") break default: - nstack.push(this.functionToLatex(f, [this.parif(n1, ["+", "-", "*", "/", "^"])])) + nstack.push(f + this.parif(n1, ["+", "-", "*", "/", "^"])) break } break @@ -331,6 +328,9 @@ class LatexAPI extends Module { throw new EvalError("invalid Expression") } } + if(nstack.length > 1) { + nstack = [nstack.join(";")] + } return String(nstack[0]) } } diff --git a/common/test/basics/polyfill.mjs b/common/test/basics/polyfill.mjs deleted file mode 100644 index ce018f2..0000000 --- a/common/test/basics/polyfill.mjs +++ /dev/null @@ -1,231 +0,0 @@ -/** - * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions. - * Copyright (C) 2021-2024 Ad5001 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -// Load prior tests - -import { describe, it } from "mocha" -import { expect } from "chai" - -import * as Polyfill from "../../src/lib/expr-eval/polyfill.mjs" -import { - andOperator, - cbrt, - equal, - expm1, - hypot, - lessThan, - log1p, - log2, - notEqual -} from "../../src/lib/expr-eval/polyfill.mjs" - -describe("Math/Polyfill", () => { - describe("#AADDDD", function() { - it("should add two numbers", function() { - expect(Polyfill.add(2, 3)).to.equal(5) - expect(Polyfill.add("2", "3")).to.equal(5) - }) - }) - - describe("#sub", function() { - it("should subtract two numbers", function() { - expect(Polyfill.sub(2, 1)).to.equal(1) - expect(Polyfill.sub("2", "1")).to.equal(1) - }) - }) - - describe("#mul", function() { - it("should multiply two numbers", function() { - expect(Polyfill.mul(2, 3)).to.equal(6) - expect(Polyfill.mul("2", "3")).to.equal(6) - }) - }) - - describe("#div", function() { - it("should divide two numbers", function() { - expect(Polyfill.div(10, 2)).to.equal(5) - expect(Polyfill.div("10", "2")).to.equal(5) - }) - }) - - describe("#mod", function() { - it("should return the modulo of two numbers", function() { - expect(Polyfill.mod(10, 3)).to.equal(1) - expect(Polyfill.mod("10", "3")).to.equal(1) - }) - }) - - describe("#concat", function() { - it("should return the concatenation of two strings", function() { - expect(Polyfill.concat(10, 3)).to.equal("103") - expect(Polyfill.concat("abc", "def")).to.equal("abcdef") - }) - }) - - describe("#equal", function() { - it("should return whether its two arguments are equal", function() { - expect(Polyfill.equal(10, 3)).to.be.false - expect(Polyfill.equal(10, 10)).to.be.true - expect(Polyfill.equal("abc", "def")).to.be.false - expect(Polyfill.equal("abc", "abc")).to.be.true - }) - }) - - describe("#notEqual", function() { - it("should return whether its two arguments are not equal", function() { - expect(Polyfill.notEqual(10, 3)).to.be.true - expect(Polyfill.notEqual(10, 10)).to.be.false - expect(Polyfill.notEqual("abc", "def")).to.be.true - expect(Polyfill.notEqual("abc", "abc")).to.be.false - }) - }) - - describe("#greaterThan", function() { - it("should return whether its first argument is strictly greater than its second", function() { - expect(Polyfill.greaterThan(10, 3)).to.be.true - expect(Polyfill.greaterThan(10, 10)).to.be.false - expect(Polyfill.greaterThan(10, 30)).to.be.false - }) - }) - - describe("#lessThan", function() { - it("should return whether its first argument is strictly less than its second", function() { - expect(Polyfill.lessThan(10, 3)).to.be.false - expect(Polyfill.lessThan(10, 10)).to.be.false - expect(Polyfill.lessThan(10, 30)).to.be.true - }) - }) - - describe("#greaterThanEqual", function() { - it("should return whether its first argument is greater or equal to its second", function() { - expect(Polyfill.greaterThanEqual(10, 3)).to.be.true - expect(Polyfill.greaterThanEqual(10, 10)).to.be.true - expect(Polyfill.greaterThanEqual(10, 30)).to.be.false - }) - }) - - describe("#lessThanEqual", function() { - it("should return whether its first argument is strictly less than its second", function() { - expect(Polyfill.lessThanEqual(10, 3)).to.be.false - expect(Polyfill.lessThanEqual(10, 10)).to.be.true - expect(Polyfill.lessThanEqual(10, 30)).to.be.true - }) - }) - - describe("#andOperator", function() { - it("should return whether its arguments are both true", function() { - expect(Polyfill.andOperator(true, true)).to.be.true - expect(Polyfill.andOperator(true, false)).to.be.false - expect(Polyfill.andOperator(false, true)).to.be.false - expect(Polyfill.andOperator(false, false)).to.be.false - expect(Polyfill.andOperator(10, 3)).to.be.true - expect(Polyfill.andOperator(10, 0)).to.be.false - expect(Polyfill.andOperator(0, 0)).to.be.false - }) - }) - - describe("#orOperator", function() { - it("should return whether one of its arguments is true", function() { - expect(Polyfill.orOperator(true, true)).to.be.true - expect(Polyfill.orOperator(true, false)).to.be.true - expect(Polyfill.orOperator(false, true)).to.be.true - expect(Polyfill.orOperator(false, false)).to.be.false - expect(Polyfill.orOperator(10, 3)).to.be.true - expect(Polyfill.orOperator(10, 0)).to.be.true - expect(Polyfill.orOperator(0, 0)).to.be.false - }) - }) - - describe("#inOperator", function() { - it("should check if second argument contains first", function() { - expect(Polyfill.inOperator("a", ["a", "b", "c"])).to.be.true - expect(Polyfill.inOperator(3, [0, 1, 2])).to.be.false - expect(Polyfill.inOperator(3, [0, 1, 3, 2])).to.be.true - expect(Polyfill.inOperator("a", "abcdef")).to.be.true - expect(Polyfill.inOperator("a", "bcdefg")).to.be.false - }) - }) - - describe("#sinh, #cosh, #tanh, #asinh, #acosh, #atanh", function() { - const EPSILON = 1e-12 - for(let x = -.9; x < 1; x += 0.1) { - expect(Polyfill.sinh(x)).to.be.approximately(Math.sinh(x), EPSILON) - expect(Polyfill.cosh(x)).to.be.approximately(Math.cosh(x), EPSILON) - expect(Polyfill.tanh(x)).to.be.approximately(Math.tanh(x), EPSILON) - expect(Polyfill.asinh(x)).to.be.approximately(Math.asinh(x), EPSILON) - expect(Polyfill.atanh(x)).to.be.approximately(Math.atanh(x), EPSILON) - } - for(let x = 1.1; x < 10; x += 0.1) { - expect(Polyfill.sinh(x)).to.be.approximately(Math.sinh(x), EPSILON) - expect(Polyfill.cosh(x)).to.be.approximately(Math.cosh(x), EPSILON) - expect(Polyfill.tanh(x)).to.be.approximately(Math.tanh(x), EPSILON) - expect(Polyfill.asinh(x)).to.be.approximately(Math.asinh(x), EPSILON) - expect(Polyfill.acosh(x)).to.be.approximately(Math.acosh(x), EPSILON) - expect(Polyfill.log10(x)).to.be.approximately(Math.log10(x), EPSILON) - } - }) - - describe("#trunc", function() { - it("should return the decimal part of floats", function() { - for(let x = -10; x < 10; x += 0.1) - expect(Polyfill.trunc(x)).to.equal(Math.trunc(x)) - }) - }) - - describe("#gamma", function() { - it("should return the product of factorial(x - 1)", function() { - expect(Polyfill.gamma(0)).to.equal(Infinity) - expect(Polyfill.gamma(1)).to.equal(1) - expect(Polyfill.gamma(2)).to.equal(1) - expect(Polyfill.gamma(3)).to.equal(2) - expect(Polyfill.gamma(4)).to.equal(6) - expect(Polyfill.gamma(5)).to.equal(24) - expect(Polyfill.gamma(172)).to.equal(Infinity) - expect(Polyfill.gamma(172.3)).to.equal(Infinity) - expect(Polyfill.gamma(.2)).to.approximately(4.590_843_712, 1e-8) - expect(Polyfill.gamma(5.5)).to.be.approximately(52.34277778, 1e-8) - expect(Polyfill.gamma(90.2)).to.equal(4.0565358202825355e+136) - }) - }) - - describe("#hypot", function() { - it("should return the hypothenus length of a triangle whose length are provided in arguments", function() { - for(let x = 0; x < 10; x += 0.3) { - expect(Polyfill.hypot(x)).to.be.approximately(Math.hypot(x), Number.EPSILON) - for(let y = 0; y < 10; y += 0.3) { - expect(Polyfill.hypot(x, y)).to.be.approximately(Math.hypot(x, y), Number.EPSILON) - } - } - }) - }) - - describe("#sign, #cbrt, #exmp1", function() { - for(let x = -10; x < 10; x += 0.3) { - expect(Polyfill.sign(x)).to.approximately(Math.sign(x), 1e-12) - expect(Polyfill.cbrt(x)).to.approximately(Math.cbrt(x), 1e-12) - expect(Polyfill.expm1(x)).to.approximately(Math.expm1(x), 1e-12) - } - }) - - describe("#log1p, #log2", function() { - for(let x = 1; x < 10; x += 0.3) { - expect(Polyfill.log1p(x)).to.be.approximately(Math.log1p(x), 1e-12) - expect(Polyfill.log2(x)).to.be.approximately(Math.log2(x), 1e-12) - } - }) -}) \ No newline at end of file diff --git a/common/test/hooks.mjs b/common/test/hooks.mjs index 66e9da9..abe468f 100644 --- a/common/test/hooks.mjs +++ b/common/test/hooks.mjs @@ -22,10 +22,8 @@ import { MockLatex } from "./mock/latex.mjs" import { use } from "chai" import spies from "chai-spies" -import promised from "chai-as-promised" function setup() { - use(promised) const { spy } = use(spies) globalThis.Helper = new MockHelper() diff --git a/common/test/mock/helper.mjs b/common/test/mock/helper.mjs index 4cab472..c2b024f 100644 --- a/common/test/mock/helper.mjs +++ b/common/test/mock/helper.mjs @@ -22,8 +22,7 @@ const DEFAULT_SETTINGS = { "check_for_updates": true, "reset_redo_stack": true, "last_install_greet": "0", - "enable_latex": true, - "enable_latex_async": true, + "enable_latex": false, "expression_editor": { "autoclose": true, "colorize": true, diff --git a/common/test/mock/latex.mjs b/common/test/mock/latex.mjs index 2d6fb5f..c0a029c 100644 --- a/common/test/mock/latex.mjs +++ b/common/test/mock/latex.mjs @@ -22,7 +22,10 @@ const PIXEL = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAACklEQVR4AWNgAAAAA export class MockLatex { constructor() { - this.supportsAsyncRender = true + } + + get supportsAsyncRender() { + return true } /** diff --git a/common/test/module/latex.mjs b/common/test/module/latex.mjs deleted file mode 100644 index 02aaca5..0000000 --- a/common/test/module/latex.mjs +++ /dev/null @@ -1,231 +0,0 @@ -/** - * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions. - * Copyright (C) 2021-2024 Ad5001 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -// Load prior tests -import "../basics/utils.mjs" -import "./base.mjs" -import "./expreval.mjs" - -import { describe, it } from "mocha" -import { expect } from "chai" -import { existsSync } from "../mock/fs.mjs" - -const { spy } = chaiPlugins - -import ExprEval from "../../src/module/expreval.mjs" -import LatexAPI from "../../src/module/latex.mjs" - -describe("Module/Latex", function() { - it("is defined as a global", function() { - expect(globalThis.Modules.Latex).to.equal(LatexAPI) - }) - - describe("#initialize", function() { - it("isn't enabled before initialization", function() { - expect(LatexAPI.enabled).to.be.false - }) - - it("is enabled after initialization", function() { - LatexAPI.initialize({ latex: Latex, helper: Helper }) - expect(LatexAPI.enabled).to.equal(Helper.getSetting("enable_latex")) - expect(LatexAPI.initialized).to.be.true - }) - }) - - describe("#requestAsyncRender", function() { - it("should return a render result with a valid source, a width, and a height", async function() { - const data = await LatexAPI.requestAsyncRender("\\frac{x}{3}", 13, "#AA0033") - expect(data).to.be.an("object") - expect(data.source).to.be.a("string") - expect(data.source).to.satisfy(existsSync) - expect(data.height).to.be.a("number") - expect(data.width).to.be.a("number") - }) - - it("should call functions from the LaTeX module", async function() { - const renderSyncSpy = spy.on(Latex, "renderSync") - const renderAsyncSpy = spy.on(Latex, "renderAsync") - Latex.supportsAsyncRender = true - await LatexAPI.requestAsyncRender("\\frac{x}{3}", 13, "#AA0033") - expect(renderAsyncSpy).to.have.been.called.once - expect(renderSyncSpy).to.have.been.called.once // Called async - Latex.supportsAsyncRender = false - await LatexAPI.requestAsyncRender("\\frac{x}{3}", 13, "#AA0033") - expect(renderAsyncSpy).to.have.been.called.once // From the time before - expect(renderSyncSpy).to.have.been.called.twice - Latex.supportsAsyncRender = true - }) - - it("should not reply with the same source for different markup, font size, or color.", async function() { - const datas = [ - await LatexAPI.requestAsyncRender("\\frac{x}{3}", 13, "#AA0033"), - await LatexAPI.requestAsyncRender("\\frac{x}{4}", 13, "#AA0033"), - await LatexAPI.requestAsyncRender("\\frac{x}{3}", 14, "#AA0033"), - await LatexAPI.requestAsyncRender("\\frac{x}{3}", 13, "#0033AA") - ] - const sources = datas.map(x => x.source) - expect(new Set(sources)).to.have.a.lengthOf(4) - }) - }) - - describe("#findPrerendered", function() { - it("should return the same data as async render for the same markup, font size, and color", async function() { - const data = await LatexAPI.requestAsyncRender("\\frac{x}{3}", 13, "#AA0033") - const found = LatexAPI.findPrerendered("\\frac{x}{3}", 13, "#AA0033") - expect(found).to.not.be.null - expect(found.source).to.equal(data.source) - expect(found.width).to.equal(data.width) - }) - - it("should return null if the markup hasn't been prerendered with the same markup, font size, and color", async function() { - await LatexAPI.requestAsyncRender("\\frac{x}{3}", 13, "#AA0033") - expect(LatexAPI.findPrerendered("\\frac{y}{3}", 13, "#AA0033")).to.be.null - expect(LatexAPI.findPrerendered("\\frac{x}{3}", 12, "#AA0033")).to.be.null - expect(LatexAPI.findPrerendered("\\frac{x}{3}", 13, "#3300AA")).to.be.null - }) - }) - - describe("#par", function() { - it("should add parentheses to strings", function() { - expect(LatexAPI.par("string")).to.equal("(string)") - expect(LatexAPI.par("aaaa")).to.equal("(aaaa)") - expect(LatexAPI.par("")).to.equal("()") - expect(LatexAPI.par("(example)")).to.equal("((example))") - }) - }) - - describe("#parif", function() { - it("should add parentheses to strings that contain one of the ones in the list", function() { - expect(LatexAPI.parif("string", ["+"])).to.equal("string") - expect(LatexAPI.parif("string+assert", ["+"])).to.equal("(string+assert)") - expect(LatexAPI.parif("string+assert", ["+", "-"])).to.equal("(string+assert)") - expect(LatexAPI.parif("string-assert", ["+", "-"])).to.equal("(string-assert)") - }) - - it("shouldn't add new parentheses to strings that contains one of the ones in the list if they already have one", function() { - expect(LatexAPI.parif("(string+assert", ["+"])).to.equal("((string+assert)") - expect(LatexAPI.parif("string+assert)", ["+"])).to.equal("(string+assert))") - expect(LatexAPI.parif("(string+assert)", ["+"])).to.equal("(string+assert)") - expect(LatexAPI.parif("(string+assert)", ["+", "-"])).to.equal("(string+assert)") - expect(LatexAPI.parif("(string-assert)", ["+", "-"])).to.equal("(string-assert)") - }) - - it("shouldn't add parentheses to strings that does not contains one of the ones in the list", function() { - expect(LatexAPI.parif("string", ["+"])).to.equal("string") - expect(LatexAPI.parif("string+assert", ["-"])).to.equal("string+assert") - expect(LatexAPI.parif("(string*assert", ["+", "-"])).to.equal("(string*assert") - expect(LatexAPI.parif("string/assert)", ["+", "-"])).to.equal("string/assert)") - }) - - it("should remove parentheses from strings that does not contains one of the ones in the list", function() { - expect(LatexAPI.parif("(string)", ["+"])).to.equal("string") - expect(LatexAPI.parif("(string+assert)", ["-"])).to.equal("string+assert") - expect(LatexAPI.parif("((string*assert)", ["+", "-"])).to.equal("(string*assert") - expect(LatexAPI.parif("(string/assert))", ["+", "-"])).to.equal("string/assert)") - }) - }) - - describe("#variable", function() { - const from = [ - "α", "β", "γ", "δ", "ε", "ζ", "η", - "π", "θ", "κ", "λ", "μ", "ξ", "ρ", - "ς", "σ", "τ", "φ", "χ", "ψ", "ω", - "Γ", "Δ", "Θ", "Λ", "Ξ", "Π", "Σ", - "Φ", "Ψ", "Ω", "ₐ", "ₑ", "ₒ", "ₓ", - "ₕ", "ₖ", "ₗ", "ₘ", "ₙ", "ₚ", "ₛ", - "ₜ", "¹", "²", "³", "⁴", "⁵", "⁶", - "⁷", "⁸", "⁹", "⁰", "₁", "₂", "₃", - "₄", "₅", "₆", "₇", "₈", "₉", "₀", - "pi", "∞"] - const to = [ - "\\alpha", "\\beta", "\\gamma", "\\delta", "\\epsilon", "\\zeta", "\\eta", - "\\pi", "\\theta", "\\kappa", "\\lambda", "\\mu", "\\xi", "\\rho", - "\\sigma", "\\sigma", "\\tau", "\\phi", "\\chi", "\\psi", "\\omega", - "\\Gamma", "\\Delta", "\\Theta", "\\Lambda", "\\Xi", "\\Pi", "\\Sigma", - "\\Phy", "\\Psi", "\\Omega", "{}_{a}", "{}_{e}", "{}_{o}", "{}_{x}", - "{}_{h}", "{}_{k}", "{}_{l}", "{}_{m}", "{}_{n}", "{}_{p}", "{}_{s}", - "{}_{t}", "{}^{1}", "{}^{2}", "{}^{3}", "{}^{4}", "{}^{5}", "{}^{6}", - "{}^{7}", "{}^{8}", "{}^{9}", "{}^{0}", "{}_{1}", "{}_{2}", "{}_{3}", - "{}_{4}", "{}_{5}", "{}_{6}", "{}_{7}", "{}_{8}", "{}_{9}", "{}_{0}", - "\\pi", "\\infty"] - - it("should convert unicode characters to their latex equivalent", function() { - for(let i = 0; i < from.length; i++) - expect(LatexAPI.variable(from[i])).to.include(to[i]) - }) - - it("should wrap within dollar signs when the option is included", function() { - for(let i = 0; i < from.length; i++) { - expect(LatexAPI.variable(from[i], false)).to.equal(to[i]) - expect(LatexAPI.variable(from[i], true)).to.equal(`$${to[i]}$`) - } - }) - - it("should be able to convert multiple of them", function() { - expect(LatexAPI.variable("α₂", false)).to.equal("\\alpha{}_{2}") - expect(LatexAPI.variable("∞piΠ", false)).to.equal("\\infty\\pi\\Pi") - }) - }) - - describe("#functionToLatex", function() { - it("should transform derivatives into latex fractions", function() { - const d1 = LatexAPI.functionToLatex("derivative", ["'3t'", "'t'", "x+2"]) - const d2 = LatexAPI.functionToLatex("derivative", ["f", "x+2"]) - expect(d1).to.equal("\\frac{d3x}{dx}") - expect(d2).to.equal("\\frac{df}{dx}(x+2)") - }) - - it("should transform integrals into latex limits", function() { - const i1 = LatexAPI.functionToLatex("integral", ["0", "x", "'3y'", "'y'"]) - const i2 = LatexAPI.functionToLatex("integral", ["1", "2", "f"]) - expect(i1).to.equal("\\int\\limits_{0}^{x}3y dy") - expect(i2).to.equal("\\int\\limits_{1}^{2}f(t) dt") - }) - - it("should transform sqrt functions to sqrt latex", function() { - const sqrt1 = LatexAPI.functionToLatex("sqrt", ["(x+2)"]) - const sqrt2 = LatexAPI.functionToLatex("sqrt", ["\\frac{x}{2}"]) - expect(sqrt1).to.equal("\\sqrt{x+2}") - expect(sqrt2).to.equal("\\sqrt{\\frac{x}{2}}") - }) - - it("should transform abs, floor and ceil", function() { - const abs = LatexAPI.functionToLatex("abs", ["x+3"]) - const floor = LatexAPI.functionToLatex("floor", ["x+3"]) - const ceil = LatexAPI.functionToLatex("ceil", ["x+3"]) - expect(abs).to.equal("\\left|x+3\\right|") - expect(floor).to.equal("\\left\\lfloor{x+3}\\right\\rfloor") - expect(ceil).to.equal("\\left\\lceil{x+3}\\right\\rceil") - }) - - it("should transform regular functions into latex", function() { - const f1 = LatexAPI.functionToLatex("f", ["x+3", true]) - const f2 = LatexAPI.functionToLatex("h_1", ["10"]) - expect(f1).to.equal("\\mathrm{f}\\left(x+3, true\\right)") - expect(f2).to.equal("\\mathrm{h_1}\\left(10\\right)") - }) - }) - - describe("#expression", function() { - it("should transform parsed expressions", function() { - const expr = ExprEval.parse("(+1! == 2/2 ? sin [-2.2][0] : f(t)^(1+1-1) + sqrt(A.t)) * 3 % 1") - const expected = "((((+1!))==(\\frac{2}{2}) ? (\\mathrm{sin}\\left(([(-2.2)][0])\\right)) : (\\mathrm{f}\\left(t\\right)^{1+1-1}+\\sqrt{A.t})) \\times 3) \\mathrm{mod} 1" - expect(LatexAPI.expression(expr.tokens)).to.equal(expected) - }) - }) -}) \ No newline at end of file diff --git a/runtime-pyside6/LogarithmPlotter/util/latex.py b/runtime-pyside6/LogarithmPlotter/util/latex.py index 71064fa..f36f07f 100644 --- a/runtime-pyside6/LogarithmPlotter/util/latex.py +++ b/runtime-pyside6/LogarithmPlotter/util/latex.py @@ -181,7 +181,7 @@ class Latex(QObject): """ markup_hash, render_hash, export_path = self.create_export_path(latex_markup, font_size, color) if self.latexSupported and not path.exists(export_path + ".png"): - print("Rendering", latex_markup) + print("Rendering", latex_markup, export_path) # Generating file latex_path = path.join(self.tempdir, str(markup_hash)) # If the formula is just recolored or the font is just changed, no need to recreate the DVI. diff --git a/runtime-pyside6/LogarithmPlotter/util/promise.py b/runtime-pyside6/LogarithmPlotter/util/promise.py index f65efa8..f43e85b 100644 --- a/runtime-pyside6/LogarithmPlotter/util/promise.py +++ b/runtime-pyside6/LogarithmPlotter/util/promise.py @@ -153,6 +153,7 @@ class PyPromise(QObject): def _fulfill(self, data): self._state = "fulfilled" no_return = [None, QJSValue.SpecialValue.UndefinedValue] + print("Fulfill") for i in range(len(self._fulfills)): try: result = self._fulfills[i](data)