将公式渲染更改为了typst

This commit is contained in:
WeiCJ 2024-11-29 15:34:29 +08:00
parent 928c1d476a
commit d0c0ed968e
3 changed files with 178 additions and 179 deletions

62
app/pnpm-lock.yaml generated
View file

@ -26,10 +26,10 @@ importers:
version: 2.19.0
clean-webpack-plugin:
specifier: ^4.0.0
version: 4.0.0(webpack@5.95.0)
version: 4.0.0(webpack@5.95.0(webpack-cli@4.10.0))
css-loader:
specifier: ^6.7.1
version: 6.7.1(webpack@5.95.0)
version: 6.7.1(webpack@5.95.0(webpack-cli@4.10.0))
dayjs:
specifier: ^1.11.5
version: 1.11.5
@ -38,28 +38,28 @@ importers:
version: 32.2.5
electron-builder:
specifier: 24.13.3
version: 24.13.3(electron-builder-squirrel-windows@25.0.5)
version: 24.13.3(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3))
encoding:
specifier: ^0.1.13
version: 0.1.13
esbuild-loader:
specifier: ^3.0.1
version: 3.0.1(webpack@5.95.0)
version: 3.0.1(webpack@5.95.0(webpack-cli@4.10.0))
eslint:
specifier: ^9.15.0
version: 9.15.0
file-loader:
specifier: ^6.2.0
version: 6.2.0(webpack@5.95.0)
version: 6.2.0(webpack@5.95.0(webpack-cli@4.10.0))
globals:
specifier: ^15.12.0
version: 15.12.0
html-loader:
specifier: ^2.1.2
version: 2.1.2(webpack@5.95.0)
version: 2.1.2(webpack@5.95.0(webpack-cli@4.10.0))
html-webpack-plugin:
specifier: ^5.5.0
version: 5.5.0(webpack@5.95.0)
version: 5.5.0(webpack@5.95.0(webpack-cli@4.10.0))
iconv-lite:
specifier: ^0.6.3
version: 0.6.3
@ -68,7 +68,7 @@ importers:
version: 2.3.2
mini-css-extract-plugin:
specifier: 2.7.6
version: 2.7.6(webpack@5.95.0)
version: 2.7.6(webpack@5.95.0(webpack-cli@4.10.0))
path-browserify:
specifier: ^1.0.1
version: 1.0.1
@ -80,7 +80,7 @@ importers:
version: 1.53.0
sass-loader:
specifier: ^12.6.0
version: 12.6.0(sass@1.53.0)(webpack@5.95.0)
version: 12.6.0(sass@1.53.0)(webpack@5.95.0(webpack-cli@4.10.0))
typescript:
specifier: ^4.7.4
version: 4.7.4
@ -3327,17 +3327,17 @@ snapshots:
'@webassemblyjs/ast': 1.12.1
'@xtuc/long': 4.2.2
'@webpack-cli/configtest@1.2.0(webpack-cli@4.10.0)(webpack@5.95.0)':
'@webpack-cli/configtest@1.2.0(webpack-cli@4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.95.0))(webpack@5.95.0(webpack-cli@4.10.0))':
dependencies:
webpack: 5.95.0(webpack-cli@4.10.0)
webpack-cli: 4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.95.0)
'@webpack-cli/info@1.5.0(webpack-cli@4.10.0)':
'@webpack-cli/info@1.5.0(webpack-cli@4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.95.0))':
dependencies:
envinfo: 7.8.1
webpack-cli: 4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.95.0)
'@webpack-cli/serve@1.7.0(webpack-cli@4.10.0)':
'@webpack-cli/serve@1.7.0(webpack-cli@4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.95.0))':
dependencies:
webpack-cli: 4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.95.0)
@ -3426,7 +3426,7 @@ snapshots:
app-builder-bin@5.0.0-alpha.7: {}
app-builder-lib@24.13.3(dmg-builder@24.13.3)(electron-builder-squirrel-windows@25.0.5):
app-builder-lib@24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)):
dependencies:
'@develar/schema-utils': 2.6.5
'@electron/notarize': 2.2.1
@ -3460,7 +3460,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
app-builder-lib@25.0.5(dmg-builder@24.13.3)(electron-builder-squirrel-windows@25.0.5):
app-builder-lib@25.0.5(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)):
dependencies:
'@develar/schema-utils': 2.6.5
'@electron/notarize': 2.3.2
@ -3755,7 +3755,7 @@ snapshots:
clean-stack@2.2.0: {}
clean-webpack-plugin@4.0.0(webpack@5.95.0):
clean-webpack-plugin@4.0.0(webpack@5.95.0(webpack-cli@4.10.0)):
dependencies:
del: 4.1.1
webpack: 5.95.0(webpack-cli@4.10.0)
@ -3863,7 +3863,7 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
css-loader@6.7.1(webpack@5.95.0):
css-loader@6.7.1(webpack@5.95.0(webpack-cli@4.10.0)):
dependencies:
icss-utils: 5.1.0(postcss@8.4.31)
postcss: 8.4.31
@ -3942,7 +3942,7 @@ snapshots:
dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5):
dependencies:
app-builder-lib: 24.13.3(dmg-builder@24.13.3)(electron-builder-squirrel-windows@25.0.5)
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3))
builder-util: 24.13.1
builder-util-runtime: 9.2.4
fs-extra: 10.1.0
@ -4013,7 +4013,7 @@ snapshots:
electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3):
dependencies:
app-builder-lib: 25.0.5(dmg-builder@24.13.3)(electron-builder-squirrel-windows@25.0.5)
app-builder-lib: 25.0.5(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3))
archiver: 5.3.2
builder-util: 25.0.3
fs-extra: 10.1.0
@ -4022,9 +4022,9 @@ snapshots:
- dmg-builder
- supports-color
electron-builder@24.13.3(electron-builder-squirrel-windows@25.0.5):
electron-builder@24.13.3(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3)):
dependencies:
app-builder-lib: 24.13.3(dmg-builder@24.13.3)(electron-builder-squirrel-windows@25.0.5)
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@25.0.5))(electron-builder-squirrel-windows@25.0.5(dmg-builder@24.13.3))
builder-util: 24.13.1
builder-util-runtime: 9.2.4
chalk: 4.1.2
@ -4105,7 +4105,7 @@ snapshots:
es6-error@4.1.1:
optional: true
esbuild-loader@3.0.1(webpack@5.95.0):
esbuild-loader@3.0.1(webpack@5.95.0(webpack-cli@4.10.0)):
dependencies:
esbuild: 0.17.10
get-tsconfig: 4.4.0
@ -4262,7 +4262,7 @@ snapshots:
dependencies:
flat-cache: 4.0.1
file-loader@6.2.0(webpack@5.95.0):
file-loader@6.2.0(webpack@5.95.0(webpack-cli@4.10.0)):
dependencies:
loader-utils: 2.0.4
schema-utils: 3.1.1
@ -4475,7 +4475,7 @@ snapshots:
dependencies:
lru-cache: 6.0.0
html-loader@2.1.2(webpack@5.95.0):
html-loader@2.1.2(webpack@5.95.0(webpack-cli@4.10.0)):
dependencies:
html-minifier-terser: 5.1.1
parse5: 6.0.1
@ -4501,7 +4501,7 @@ snapshots:
relateurl: 0.2.7
terser: 5.14.1
html-webpack-plugin@5.5.0(webpack@5.95.0):
html-webpack-plugin@5.5.0(webpack@5.95.0(webpack-cli@4.10.0)):
dependencies:
'@types/html-minifier-terser': 6.1.0
html-minifier-terser: 6.1.0
@ -4835,7 +4835,7 @@ snapshots:
mimic-response@3.1.0: {}
mini-css-extract-plugin@2.7.6(webpack@5.95.0):
mini-css-extract-plugin@2.7.6(webpack@5.95.0(webpack-cli@4.10.0)):
dependencies:
schema-utils: 4.2.0
webpack: 5.95.0(webpack-cli@4.10.0)
@ -5288,7 +5288,7 @@ snapshots:
dependencies:
truncate-utf8-bytes: 1.0.2
sass-loader@12.6.0(sass@1.53.0)(webpack@5.95.0):
sass-loader@12.6.0(sass@1.53.0)(webpack@5.95.0(webpack-cli@4.10.0)):
dependencies:
klona: 2.0.5
neo-async: 2.6.2
@ -5484,7 +5484,7 @@ snapshots:
async-exit-hook: 2.0.1
fs-extra: 10.1.0
terser-webpack-plugin@5.3.10(webpack@5.95.0):
terser-webpack-plugin@5.3.10(webpack@5.95.0(webpack-cli@4.10.0)):
dependencies:
'@jridgewell/trace-mapping': 0.3.25
jest-worker: 27.5.1
@ -5613,9 +5613,9 @@ snapshots:
webpack-cli@4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.95.0):
dependencies:
'@discoveryjs/json-ext': 0.5.7
'@webpack-cli/configtest': 1.2.0(webpack-cli@4.10.0)(webpack@5.95.0)
'@webpack-cli/info': 1.5.0(webpack-cli@4.10.0)
'@webpack-cli/serve': 1.7.0(webpack-cli@4.10.0)
'@webpack-cli/configtest': 1.2.0(webpack-cli@4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.95.0))(webpack@5.95.0(webpack-cli@4.10.0))
'@webpack-cli/info': 1.5.0(webpack-cli@4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.95.0))
'@webpack-cli/serve': 1.7.0(webpack-cli@4.10.0(webpack-bundle-analyzer@4.5.0)(webpack@5.95.0))
colorette: 2.0.19
commander: 7.2.0
cross-spawn: 7.0.3
@ -5662,7 +5662,7 @@ snapshots:
neo-async: 2.6.2
schema-utils: 3.3.0
tapable: 2.2.1
terser-webpack-plugin: 5.3.10(webpack@5.95.0)
terser-webpack-plugin: 5.3.10(webpack@5.95.0(webpack-cli@4.10.0))
watchpack: 2.4.2
webpack-sources: 3.2.3
optionalDependencies:

View file

@ -1,132 +1,150 @@
import {addScript} from "../util/addScript";
import {addStyle} from "../util/addStyle";
import {Constants} from "../../constants";
import {hasNextSibling, hasPreviousSibling} from "../wysiwyg/getBlock";
import {hasClosestBlock} from "../util/hasClosest";
import {looseJsonParse} from "../../util/functions";
import { addScript } from "../util/addScript";
import { addStyle } from "../util/addStyle";
import { Constants } from "../../constants";
import { hasNextSibling, hasPreviousSibling } from "../wysiwyg/getBlock";
import { hasClosestBlock } from "../util/hasClosest";
import { looseJsonParse } from "../../util/functions";
export const mathRender = (element: Element, cdn = Constants.PROTYLE_CDN, maxWidth = false) => {
let mathElements: Element[] = [];
if (element.getAttribute("data-subtype") === "math") {
// 编辑器内代码块编辑渲染
mathElements = [element];
} else {
mathElements = Array.from(element.querySelectorAll('[data-subtype="math"]'));
}
if (mathElements.length === 0) {
return;
}
addStyle(`${cdn}/js/katex/katex.min.css?v=0.16.9`, "protyleKatexStyle");
addScript(`${cdn}/js/katex/katex.min.js?v=0.16.9`, "protyleKatexScript").then(() => {
addScript(`${cdn}/js/katex/mhchem.min.js?v=0.16.9`, "protyleKatexMhchemScript").then(() => {
mathElements.forEach((mathElement: HTMLElement) => {
if (mathElement.getAttribute("data-render") === "true") {
return;
}
mathElement.setAttribute("data-render", "true");
let renderElement = mathElement;
if (mathElement.tagName === "DIV") {
renderElement = mathElement.firstElementChild as HTMLElement;
}
let macros = {};
try {
macros = looseJsonParse(window.siyuan.config.editor.katexMacros || "{}");
} catch (e) {
console.warn("KaTex macros is not JSON", e);
}
try {
renderElement.innerHTML = window.katex.renderToString(Lute.UnEscapeHTMLStr(mathElement.getAttribute("data-content")), {
displayMode: mathElement.tagName === "DIV",
output: "html",
macros,
trust: true, // REF: https://katex.org/docs/supported#html
strict: (errorCode) => errorCode === "unicodeTextInMathMode" ? "ignore" : "warn",
});
renderElement.classList.remove("ft__error");
const blockElement = hasClosestBlock(mathElement);
if (mathElement.tagName === "DIV") {
renderElement.firstElementChild.setAttribute("contenteditable", "false");
if (renderElement.childElementCount < 2) {
// 不能使用 contenteditable="false",否则光标无法移动到该块
renderElement.insertAdjacentHTML("beforeend", `<span style="position: absolute;right: 0;top: 0;">${Constants.ZWSP}</span>`);
}
// https://github.com/siyuan-note/siyuan/issues/3541
const baseElements = renderElement.querySelectorAll(".base");
if (baseElements.length > 0) {
baseElements[baseElements.length - 1].insertAdjacentHTML("afterend", "<span class='fn__flex-1'></span>");
}
// https://github.com/siyuan-note/siyuan/issues/4334
const newlineElement = renderElement.querySelector(".katex-html > .newline");
if (newlineElement) {
newlineElement.parentElement.style.display = "block";
}
} else {
if (blockElement && mathElement.getBoundingClientRect().width > blockElement.clientWidth) {
mathElement.style.maxWidth = "100%";
mathElement.style.overflowX = "auto";
mathElement.style.overflowY = "hidden";
mathElement.style.display = "inline-block";
} else {
mathElement.style.maxWidth = "";
mathElement.style.overflowX = "";
mathElement.style.overflowY = "";
mathElement.style.display = "";
}
const nextSibling = hasNextSibling(mathElement) as HTMLElement;
if (!nextSibling) {
// 表格编辑问题 https://ld246.com/article/1629191424824
if (mathElement.parentElement.tagName !== "TH" && mathElement.parentElement.tagName !== "TD") {
// 光标无法移动到末尾 https://github.com/siyuan-note/siyuan/issues/2112
mathElement.insertAdjacentText("afterend", "\n");
} else {
// https://ld246.com/article/1651595975481https://ld246.com/article/1658903123429
// 随着浏览器的升级,从 beforeend 修改为 afterend
mathElement.insertAdjacentText("afterend", Constants.ZWSP);
}
} else if (nextSibling && nextSibling.nodeType !== 3 &&
(
nextSibling.getAttribute("data-type")?.indexOf("inline-math") > -1 ||
nextSibling.classList.contains("img")
)) {
// 相邻的数学公式删除或光标移动有问题
mathElement.after(document.createTextNode(Constants.ZWSP));
} else if (nextSibling &&
!nextSibling.textContent.startsWith("\n") && // https://github.com/siyuan-note/insider/issues/1089
// 输入 $a$ 后,光标移动到其他块,再点击 a 后,光标不显示 https://github.com/siyuan-note/insider/issues/1076#issuecomment-1253215515
nextSibling.textContent !== Constants.ZWSP) {
// 数学公式后一个字符删除多 br https://ld246.com/article/1647157880974
// 数学公式后有 \n 不能再添加 &#xFEFF; https://ld246.com/article/1647329437541
mathElement.insertAdjacentHTML("beforeend", "&#xFEFF;");
}
// 光标无法移动到段首 https://ld246.com/article/1623551823742
if (mathElement.previousSibling?.textContent.endsWith("\n")) {
mathElement.insertAdjacentText("beforebegin", Constants.ZWSP);
} else if (!hasPreviousSibling(mathElement) && ["TH", "TD"].includes(mathElement.parentElement.tagName)) {
// 单元格中只有数学公式时,光标无法移动到数学公式前
mathElement.insertAdjacentText("afterbegin", Constants.ZWSP);
}
}
const cache = new Map<string, string>();
// export pdf
if (maxWidth) {
setTimeout(() => {
if (mathElement.tagName === "DIV") {
const katexElement = mathElement.querySelector(".katex-display");
if (katexElement.clientWidth < katexElement.scrollWidth) {
katexElement.firstElementChild.setAttribute("style", `font-size:${katexElement.clientWidth * 100 / katexElement.scrollWidth}%`);
}
} else {
if (blockElement && mathElement.offsetWidth > blockElement.clientWidth) {
mathElement.firstElementChild.setAttribute("style", `font-size:${blockElement.clientWidth * 100 / mathElement.offsetWidth}%`);
}
}
});
}
} catch (e) {
renderElement.innerHTML = e.message;
renderElement.classList.add("ft__error");
}
});
});
});
export const mathRender = (
element: Element,
cdn = Constants.PROTYLE_CDN,
maxWidth = false
) => {
let mathElements: Element[] = [];
if (element.getAttribute("data-subtype") === "math") {
// 编辑器内代码块编辑渲染
mathElements = [element];
} else {
mathElements = Array.from(
element.querySelectorAll('[data-subtype="math"]')
);
}
if (mathElements.length === 0) {
return;
}
console.time("Test Code");
mathElements.forEach(async (mathElement: HTMLElement, index: number) => {
if (mathElement.getAttribute("data-render") === "true") {
return;
}
mathElement.setAttribute("data-render", "true");
let renderElement = mathElement;
// 如果是 DIV 标签,渲染的目标是其第一个子元素
if (mathElement.tagName === "DIV") {
renderElement = mathElement.firstElementChild as HTMLElement;
}
try {
// 获取数学公式的内容
const mathContent = mathElement.getAttribute("data-content") || "";
// if (cache.has(mathContent)) {
// return Promise.resolve(cache.get(mathContent)!); // 使用缓存结果
// }
// 如果缓存中已经有该公式的结果,直接返回
console.time(`render${index}`);
let svg = "";
if (cache.has(mathContent)) {
console.log("use cache")
svg = cache.get(mathContent)!
} else {
const typst_content = `
#set page(width:auto,height:auto,margin:1mm, background:none)
#set text(size:12pt)
\$
${mathContent}
\$`;
// 调用 Typst 渲染 API 获取 SVG
svg = await fetchTypstSvg(typst_content, index);
cache.set(mathContent, svg);
}
console.timeEnd(`render${index}`);
// cache.set(mathContent, svg); // 缓存结果
// 替换渲染元素内容为 SVG
console.time(`render2-${index}`);
renderElement.innerHTML = svg;
renderElement.classList.remove("ft__error");
// 如果是块级数学公式
if (mathElement.tagName === "DIV") {
console.log("set block element 0");
renderElement.firstElementChild.setAttribute(
"contenteditable",
"false"
);
// 插入占位符,防止光标移动问题
if (renderElement.childElementCount < 2) {
renderElement.insertAdjacentHTML(
"beforeend",
`<span style="position: absolute;right: 0;top: 0;">${Constants.ZWSP}</span>`
);
}
} else {
// 行内公式的样式调整
const blockElement = hasClosestBlock(mathElement);
console.log("set block element 11");
mathElement.style.display = "inline-block";
if (
blockElement &&
mathElement.getBoundingClientRect().width > blockElement.clientWidth
) {
console.log("set block element");
mathElement.style.maxWidth = "100%";
mathElement.style.overflowX = "auto";
mathElement.style.overflowY = "hidden";
mathElement.style.display = "inline-block";
} else {
mathElement.style.maxWidth = "";
mathElement.style.overflowX = "";
mathElement.style.overflowY = "";
mathElement.style.display = "";
}
}
console.timeEnd(`render2-${index}`);
} catch (e) {
// 处理渲染错误
renderElement.innerHTML = e.message;
renderElement.classList.add("ft__error");
}
});
console.timeEnd("Test Code");
/**
* Typst HTTP API SVG
* @param mathContent
* @returns SVG
*/
async function fetchTypstSvg(
mathContent: string,
index: number
): Promise<string> {
try {
console.time(`network-${index}`);
const response = await fetch("http://127.0.0.1:19966/typst_render", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
content: mathContent,
config: "",
}),
});
console.timeEnd(`network-${index}`);
if (!response.ok) {
throw new Error(`Typst API Error: ${response.statusText}`);
}
const data = await response.json();
return data.svg || ""; // 假设返回数据中包含 `svg` 字段
} catch (error) {
console.error("Failed to fetch SVG from Typst API:", error);
throw new Error("Failed to render math formula with Typst");
}
}
};

View file

@ -35,14 +35,6 @@ if errorlevel 1 (
exit /b %errorlevel%
)
echo 'Building Kernel arm64'
set GOARCH=arm64
@REM if you want to build arm64, you need to install aarch64-w64-mingw32-gcc
set CC="D:/Program Files/llvm-mingw-20240518-ucrt-x86_64/bin/aarch64-w64-mingw32-gcc.exe"
go build --tags fts5 -v -o "../app/kernel-arm64/SiYuan-Kernel.exe" -ldflags "-s -w -H=windowsgui" .
if errorlevel 1 (
exit /b %errorlevel%
)
cd ..
echo 'Building Electron App amd64'
@ -51,14 +43,3 @@ call pnpm run dist
if errorlevel 1 (
exit /b %errorlevel%
)
echo 'Building Electron App arm64'
call pnpm run dist-arm64
if errorlevel 1 (
exit /b %errorlevel%
)
cd ..
echo 'Building Appx'
echo 'Building Appx should be disabled if you do not need it. Not configured correctly will lead to build failures'
cd . > app\build\win-unpacked\resources\ms-store
electron-windows-store --input-directory app\build\win-unpacked --output-directory app\build\ --package-version 1.0.0.0 --package-name SiYuan --manifest app\appx\AppxManifest.xml --assets app\appx\assets\ --make-pri true