From 9bb784e6f06ccd052e41da545c06c59100dd89c0 Mon Sep 17 00:00:00 2001 From: Myriad-Dreamin <35292584+Myriad-Dreamin@users.noreply.github.com> Date: Wed, 9 Jul 2025 19:34:57 +0800 Subject: [PATCH] feat: run prettier correctly (#1893) --- .prettierignore | 1 + editors/vscode/scripts/check-version.mjs | 18 +-- editors/vscode/scripts/postinstall.cjs | 30 ++--- editors/vscode/src/features/preview-compat.ts | 2 +- package.json | 2 +- tools/editor-tools/src/components/modal.ts | 11 +- .../editor-tools/src/features/diagnostics.ts | 20 +-- tools/editor-tools/src/features/docs.ts | 127 +++++++----------- tools/editor-tools/src/features/font-view.ts | 121 +++++++---------- .../editor-tools/src/features/symbol-view.ts | 97 ++++++------- .../src/features/template-gallery.ts | 104 ++++++-------- tools/editor-tools/src/utils.ts | 6 +- tools/editor-tools/vite.config.js | 14 +- tools/typst-dom/src/index.mts | 2 +- tools/typst-dom/src/index.preview.mts | 4 +- tools/typst-dom/src/typst-animation.mts | 2 +- tools/typst-dom/src/typst-doc.canvas.mts | 80 ++++------- tools/typst-dom/src/typst-doc.test.mts | 16 +-- tools/typst-dom/src/typst-outline.mts | 48 ++----- tools/typst-dom/src/typst-patch.mts | 16 +-- tools/typst-dom/src/typst-patch.svg.mts | 25 ++-- tools/typst-dom/src/typst-patch.test.mts | 82 +++-------- tools/typst-preview-frontend/src/drag.ts | 89 ++++++------ 23 files changed, 351 insertions(+), 566 deletions(-) diff --git a/.prettierignore b/.prettierignore index 8ffa0a072..cb2468c19 100644 --- a/.prettierignore +++ b/.prettierignore @@ -8,6 +8,7 @@ target/** dist/** icons/ node_modules/ +editors/vscode/test-dist/ editors/vscode/out/ editors/vscode/.vscode-test/** *.toml diff --git a/editors/vscode/scripts/check-version.mjs b/editors/vscode/scripts/check-version.mjs index 428e0f4cf..c6e002d14 100644 --- a/editors/vscode/scripts/check-version.mjs +++ b/editors/vscode/scripts/check-version.mjs @@ -1,15 +1,15 @@ - -import { readFileSync } from 'fs'; - +import { readFileSync } from "fs"; function check() { - const cargoToml = readFileSync('../../Cargo.toml', 'utf8'); - const cargoVersion = cargoToml.match(/version = "(.*?)"/)[1]; - const pkgVersion = JSON.parse(readFileSync('package.json', 'utf8')).version; + const cargoToml = readFileSync("../../Cargo.toml", "utf8"); + const cargoVersion = cargoToml.match(/version = "(.*?)"/)[1]; + const pkgVersion = JSON.parse(readFileSync("package.json", "utf8")).version; - if (cargoVersion !== pkgVersion) { - throw new Error(`Version mismatch: ${cargoVersion} (in Cargo.toml) !== ${pkgVersion} (in package.json)`); - } + if (cargoVersion !== pkgVersion) { + throw new Error( + `Version mismatch: ${cargoVersion} (in Cargo.toml) !== ${pkgVersion} (in package.json)`, + ); + } } check(); diff --git a/editors/vscode/scripts/postinstall.cjs b/editors/vscode/scripts/postinstall.cjs index 01e808e50..4d81c6c47 100644 --- a/editors/vscode/scripts/postinstall.cjs +++ b/editors/vscode/scripts/postinstall.cjs @@ -1,28 +1,24 @@ +const path = require("path"); +const fs = require("fs"); +const rimraf = require("rimraf"); -const path = require('path'); -const fs = require('fs'); -const rimraf = require('rimraf'); +const vscodeDir = path.join(__dirname, "../"); +const editorToolsDir = path.join(vscodeDir, "../../tools/editor-tools/"); -const vscodeDir = path.join(__dirname, '../'); -const editorToolsDir = path.join(vscodeDir, '../../tools/editor-tools/'); - -rimraf.sync(path.join(vscodeDir, 'out/editor-tools/')); -fs.mkdirSync(path.join(vscodeDir, 'out/editor-tools/'), { recursive: true }); +rimraf.sync(path.join(vscodeDir, "out/editor-tools/")); +fs.mkdirSync(path.join(vscodeDir, "out/editor-tools/"), { recursive: true }); function copyDir(src, dest) { fs.readdirSync(src).forEach((item) => { const srcPath = path.join(src, item); const destPath = path.join(dest, item); if (fs.lstatSync(srcPath).isDirectory()) { - fs.mkdirSync(destPath, - { recursive: true }); - copyDir(srcPath, destPath); + fs.mkdirSync(destPath, { recursive: true }); + copyDir(srcPath, destPath); + } else { + fs.copyFileSync(srcPath, destPath); } - else { - fs.copyFileSync(srcPath, destPath); - } -}); + }); } -copyDir(path.join(editorToolsDir, "dist"), path.join(vscodeDir, 'out/editor-tools/')); - +copyDir(path.join(editorToolsDir, "dist"), path.join(vscodeDir, "out/editor-tools/")); diff --git a/editors/vscode/src/features/preview-compat.ts b/editors/vscode/src/features/preview-compat.ts index 33fac54e3..0b0a6a8f5 100644 --- a/editors/vscode/src/features/preview-compat.ts +++ b/editors/vscode/src/features/preview-compat.ts @@ -681,4 +681,4 @@ export const revealDocumentCompat = async (args: any) => { export const ejectPreviewPanelCompat = async () => { vscode.window.showWarningMessage("Eject is not supported in compat mode"); -} +}; diff --git a/package.json b/package.json index 5077bbcab..293062db7 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "tools/typst-preview-frontend" ], "scripts": { - "fmt": "cargo fmt --all && npx prettier tools/**/*.{js,mjs,cjs,ts,mts,cts} editors/vscode/**/*.{js,mjs,cjs,ts,mts,cts}", + "fmt": "cargo fmt --all && npx prettier --write tools/**/*.{js,mjs,cjs,ts,mts,cts} editors/vscode/**/*.{js,mjs,cjs,ts,mts,cts}", "fmt:check": "cargo fmt --check --all && prettier --check tools/**/*.{js,mjs,cjs,ts,mts,cts} editors/vscode/**/*.{js,mjs,cjs,ts,mts,cts}", "build:editor-tools": "cd tools/editor-tools/ && yarn run build", "build:preview": "cd tools/typst-preview-frontend && yarn run build && rimraf ../../crates/tinymist-assets/src/typst-preview.html && cpr ./dist/index.html ../../crates/tinymist-assets/src/typst-preview.html", diff --git a/tools/editor-tools/src/components/modal.ts b/tools/editor-tools/src/components/modal.ts index 65f934851..25e901d9d 100644 --- a/tools/editor-tools/src/components/modal.ts +++ b/tools/editor-tools/src/components/modal.ts @@ -37,7 +37,7 @@ export function startModal(...contents: Node[]) { { class: "tinymist-button", }, - "Close" + "Close", ); const keydownHandler = (e: KeyboardEvent) => { if (e.key === "Escape" || e.key === " " || e.key === "Enter") { @@ -58,15 +58,12 @@ export function startModal(...contents: Node[]) { { class: "tinymist-button", style: "margin-left: 0.5em", - title: - "Click the close button or press esc/space/enter to close this window", + title: "Click the close button or press esc/space/enter to close this window", }, - "Help" + "Help", ); help.onclick = () => { - alert( - "Click the close button or press esc/space/enter to close this window" - ); + alert("Click the close button or press esc/space/enter to close this window"); }; floatingWindow.appendChild(help); diff --git a/tools/editor-tools/src/features/diagnostics.ts b/tools/editor-tools/src/features/diagnostics.ts index ec4f2aeab..95edc4346 100644 --- a/tools/editor-tools/src/features/diagnostics.ts +++ b/tools/editor-tools/src/features/diagnostics.ts @@ -22,8 +22,8 @@ export const Diagnostics = () => { `: error occurred in this call of function \`f\``, br(), a({ href: "javascript:void(0)" }, `test.typ(6, 2)`), - `: error occurred in this call of function \`g\`` - ) + `: error occurred in this call of function \`g\``, + ), ), div( { class: `tinymist-card`, style: "flex: 1; width: 100%; padding: 10px" }, @@ -44,7 +44,7 @@ export const Diagnostics = () => { }, `#let f(x, y) = `, span({ style: "text-decoration: underline" }, `x + y`), - `;` + `;`, ), br(), "where ", @@ -61,7 +61,7 @@ export const Diagnostics = () => { "2nd", " function parameter of ", code(a({ href: "javascript:void(0)" }, `f`)), - "." + ".", ), div( { @@ -82,7 +82,7 @@ export const Diagnostics = () => { }, `#let g(x, y, z) = `, span({ style: "text-decoration: underline" }, `f(x, y)`), - ` + z;` + ` + z;`, ), br(), "where ", @@ -99,7 +99,7 @@ export const Diagnostics = () => { "2nd", " function parameter of ", code(a({ href: "javascript:void(0)" }, `g`)), - "." + ".", ), div( { @@ -120,9 +120,9 @@ export const Diagnostics = () => { }, `#`, span({ style: "text-decoration: underline" }, `g(1, left, red)`), - `;` - ) - ) - ) + `;`, + ), + ), + ), ); }; diff --git a/tools/editor-tools/src/features/docs.ts b/tools/editor-tools/src/features/docs.ts index 597d4d0a2..7111a42be 100644 --- a/tools/editor-tools/src/features/docs.ts +++ b/tools/editor-tools/src/features/docs.ts @@ -40,8 +40,8 @@ export const Docs = () => { const v = parsedDocs.val; // console.log("updated", v); return div(MakeDoc(v)); - } - ) + }, + ), ); }; @@ -89,9 +89,7 @@ async function recoverDocsStructure(content: string) { let match; let lastIndex = 0; while ((match = reg.exec(content))) { - tokenPromises.push( - Promise.resolve([TokenKind.Text, content.slice(lastIndex, match.index)]) - ); + tokenPromises.push(Promise.resolve([TokenKind.Text, content.slice(lastIndex, match.index)])); tokenPromises.push(identifyCommentToken(match[1])); lastIndex = reg.lastIndex; } @@ -157,8 +155,7 @@ async function recoverDocsStructure(content: string) { }; if (sym) { current.id = `${sym.id}-param-${token[1]}`; - const renderedParams = (sym.data.renderedParams = - sym.data.renderedParams || {}); + const renderedParams = (sym.data.renderedParams = sym.data.renderedParams || {}); renderedParams[current.id] = current; } break; @@ -240,19 +237,11 @@ async function identifyCommentToken(comment: string) { case "end:errors": return [TokenKind.ErrorEnd, cs[1]]; case "begin:module": - return [ - TokenKind.ModuleStart, - cs[1], - JSON.parse(await base64ToUtf8(cs[2])), - ]; + return [TokenKind.ModuleStart, cs[1], JSON.parse(await base64ToUtf8(cs[2]))]; case "end:module": return [TokenKind.ModuleEnd, cs[1]]; case "begin:symbol": - return [ - TokenKind.SymbolStart, - cs[1], - JSON.parse(await base64ToUtf8(cs[2])), - ]; + return [TokenKind.SymbolStart, cs[1], JSON.parse(await base64ToUtf8(cs[2]))]; case "end:symbol": return [TokenKind.SymbolEnd, cs[1]]; case "begin:sig": @@ -312,7 +301,7 @@ function MakeDoc(root: DocElement) { (e) => e.namespace === child.data.namespace && e.name === child.data.name && - e.version === child.data.version + e.version === child.data.version, ); return; } @@ -494,9 +483,9 @@ function MakeDoc(root: DocElement) { style: "text-decoration: underline", title: `It is inaccessible by paths`, }, - "Module" + "Module", ), - code(" ", knownFiles[fileLoc]?.path || v.id) + code(" ", knownFiles[fileLoc]?.path || v.id), ); } else { title.push(span(`Module: ${v.id}`)); @@ -505,7 +494,7 @@ function MakeDoc(root: DocElement) { return div( { class: "tinymist-module" }, h1({ id: v.id }, ...(fid ? [span({ id: fid }, ...title)] : title)), - ModuleBody(v) + ModuleBody(v), ); } @@ -514,19 +503,14 @@ function MakeDoc(root: DocElement) { return div( h1(`@${v.data.namespace}/${v.data.name}:${v.data.version}`), p( - span( - "This documentation is generated locally. Please submit issues to " - ), - a( - { href: "https://github.com/Myriad-Dreamin/tinymist/issues" }, - "tinymist" - ), + span("This documentation is generated locally. Please submit issues to "), + a({ href: "https://github.com/Myriad-Dreamin/tinymist/issues" }, "tinymist"), span(" if you see "), strong(i("incorrect")), - span(" information in it.") + span(" information in it."), ), // ModuleBody(v) - ...v.children.map(Item) + ...v.children.map(Item), ); } @@ -546,16 +530,16 @@ function MakeDoc(root: DocElement) { style: "text-decoration: underline", title: `In external package @${extPkg.namespace}/${extPkg.name}:${extPkg.version}`, }, - "external" + "external", ) : span( { style: "text-decoration: underline", title: `In local package @${extPkg.namespace}/${extPkg.name}:${extPkg.version}`, }, - "external" + "external", ), - code(" ", v.data.name) + code(" ", v.data.name), ); } else { const file = knownFiles[fileLoc?.[0]]; @@ -567,9 +551,9 @@ function MakeDoc(root: DocElement) { style: "text-decoration: underline", title: `This module is inaccessible by paths`, }, - "internal" + "internal", ), - code(" ") + code(" "), ) : code(); @@ -579,8 +563,8 @@ function MakeDoc(root: DocElement) { { href: `#${fid}`, }, - v.data.name - ) + v.data.name, + ), ); } @@ -598,8 +582,8 @@ function MakeDoc(root: DocElement) { // View Source // }, - h3({ class: "doc-symbol-name" }, body) - ) + h3({ class: "doc-symbol-name" }, body), + ), ); } @@ -618,7 +602,7 @@ function MakeDoc(root: DocElement) { { id: v.id, }, - code(v.data.name) + code(v.data.name), ); let funcTitle = [...is_external, name]; if (sig) { @@ -652,10 +636,10 @@ function MakeDoc(root: DocElement) { { class: `detail-header doc-symbol-${v.data.kind}`, }, - h3({ class: "doc-symbol-name" }, code(...funcTitle)) + h3({ class: "doc-symbol-name" }, code(...funcTitle)), ), ...SigPreview(v), - ...(v.data.is_external ? ShortItemDoc(v) : [ItemDoc(v), ...SigDocs(v)]) + ...(v.data.is_external ? ShortItemDoc(v) : [ItemDoc(v), ...SigDocs(v)]), ); } @@ -728,10 +712,10 @@ function MakeDoc(root: DocElement) { { class: "doc-param-title", }, - strong(paramTitle) - ) - ) - ) + strong(paramTitle), + ), + ), + ), ); } @@ -751,7 +735,7 @@ function MakeDoc(root: DocElement) { { id: `param-${v.id}-${param.name}`, }, - param.name + param.name, ), ]; if (param.cano_type) { @@ -782,13 +766,13 @@ function MakeDoc(root: DocElement) { { class: "doc-param-title", }, - strong(code(paramTitle)) + strong(code(paramTitle)), ), div({ style: "margin-left: 0.62em", innerHTML: docsAll ? docsAll : "

-

", - }) - ) + }), + ), ); } @@ -826,19 +810,13 @@ function MakeDoc(root: DocElement) { href: v.data.external_link, title: "this symbol is re-exported from other modules", }, - kwHl("external") + kwHl("external"), ), code(" "), ] : []; - const sigTitle = [ - ...is_external, - kwHl("let"), - code(" "), - code(fnHl(v.data.name)), - code("("), - ]; + const sigTitle = [...is_external, kwHl("let"), code(" "), code(fnHl(v.data.name)), code("(")]; for (let i = 0; i < paramsAll.length; i++) { if (i > 0) { sigTitle.push(code(", ")); @@ -856,8 +834,8 @@ function MakeDoc(root: DocElement) { { href: `#param-${v.id}-${paramsAll[i].param.name}`, }, - ...paramTitle - ) + ...paramTitle, + ), ); } sigTitle.push(code(")")); @@ -877,9 +855,9 @@ function MakeDoc(root: DocElement) { { style: "margin: 0 1em", }, - code(...sigTitle) - ) - ) + code(...sigTitle), + ), + ), ); return res; @@ -896,26 +874,23 @@ function MakeDoc(root: DocElement) { }, h3( { class: "doc-symbol-name" }, - code(`${v.data.name}`) + code(`${v.data.name}`), // code( // { // style: "float: right; line-height: 1em", // }, // `${v.data.kind}` // ) - ) + ), ), - ItemDoc(v) + ItemDoc(v), ); } return Item(root); } -function sigTypeHighlighted( - inferred: [string, string] | undefined, - target: ChildDom[] -) { +function sigTypeHighlighted(inferred: [string, string] | undefined, target: ChildDom[]) { // todo: determine whether it is inferred // if (types) { // typeHighlighted(types, target); @@ -925,24 +900,20 @@ function sigTypeHighlighted( typeHighlighted(inferred[0], rendered, "|"); const infer = span( { class: "code-kw type-inferred", title: "inferred by type checker" }, - "infer" + "infer", ); target.push( code( { class: "type-inferred" }, infer, code(" "), - span({ class: "type-inferred-as", title: inferred[1] }, ...rendered) - ) + span({ class: "type-inferred-as", title: inferred[1] }, ...rendered), + ), ); } } -function typeHighlighted( - types: string, - target: ChildDom[], - by: RegExp | string = /[|,]/g -) { +function typeHighlighted(types: string, target: ChildDom[], by: RegExp | string = /[|,]/g) { const type = types.split(by); for (let i = 0; i < type.length; i++) { if (i > 0) { diff --git a/tools/editor-tools/src/features/font-view.ts b/tools/editor-tools/src/features/font-view.ts index b9a8e08ed..670e3f37a 100644 --- a/tools/editor-tools/src/features/font-view.ts +++ b/tools/editor-tools/src/features/font-view.ts @@ -15,17 +15,13 @@ export const FontView = () => { const FontResourcesData = `:[[preview:FontInformation]]:`; const fontResources = van.state( - FontResourcesData.startsWith(":") - ? DOC_MOCK - : JSON.parse(base64Decode(FontResourcesData)) + FontResourcesData.startsWith(":") ? DOC_MOCK : JSON.parse(base64Decode(FontResourcesData)), ); console.log("fontResources", fontResources); const StyleAtCursorData = `:[[preview:StyleAtCursor]]:`; const lastStylesAtCursor = van.state( - StyleAtCursorData.startsWith(":") - ? undefined - : JSON.parse(base64Decode(StyleAtCursorData)) + StyleAtCursorData.startsWith(":") ? undefined : JSON.parse(base64Decode(StyleAtCursorData)), ); console.log("styleAtCursorBase", lastStylesAtCursor); van.derive(() => { @@ -72,12 +68,11 @@ export const FontView = () => { icon: ChildDom, title: string, onclick: (this: HTMLDivElement) => void, - opts?: PropsWithKnownKeys & { active?: State } + opts?: PropsWithKnownKeys & { active?: State }, ) => { const classProp = opts?.active ? van.derive( - () => - `tinymist-button tinymist-font-action${opts?.active?.val ? " activated" : ""}` + () => `tinymist-button tinymist-font-action${opts?.active?.val ? " activated" : ""}`, ) : "tinymist-button tinymist-font-action"; @@ -89,7 +84,7 @@ export const FontView = () => { title, onclick, }, - icon + icon, ); }; @@ -106,17 +101,15 @@ export const FontView = () => { const machineTitle = `Weight ${font.weight || 400}, Stretch ${font.stretch || 1000}, at `; const baseName = code( - font.style === "normal" || !font.style - ? "" - : `${humanStyle(font.style)}, `, + font.style === "normal" || !font.style ? "" : `${humanStyle(font.style)}, `, (_dom?: Element) => { return span( humanWeight(font.weight, showNumberOpt.val), showNumber.val ? ", " : " ", - humanStretch(font.stretch, showNumberOpt.val) + humanStretch(font.stretch, showNumberOpt.val), ); }, - ` (${fileName})` + ` (${fileName})`, ); let variantName; @@ -127,8 +120,7 @@ export const FontView = () => { title = machineTitle + w.path; variantName = a( { - style: - "font-size: 1.2em; text-decoration: underline; cursor: pointer;", + style: "font-size: 1.2em; text-decoration: underline; cursor: pointer;", title, onclick() { if (w.kind === "fs") { @@ -136,7 +128,7 @@ export const FontView = () => { } }, }, - baseName + baseName, ); } else { title = machineTitle + `Embedded: ${w.name}`; @@ -145,7 +137,7 @@ export const FontView = () => { style: "font-size: 1.2em", title, }, - baseName + baseName, ); } } else { @@ -184,56 +176,44 @@ export const FontView = () => { div( { style: "margin: 1.2em; margin-left: 0.5em" }, div( - FontAction( - "Copy", - "Copy to clipboard", - function (this: HTMLDivElement) { - activeMe(this); - copyToClipboard(`"${family.name || ""}"`); - } - ), + FontAction("Copy", "Copy to clipboard", function (this: HTMLDivElement) { + activeMe(this); + copyToClipboard(`"${family.name || ""}"`); + }), " | ", - FontAction( - "Paste string", - "Paste as String", - function (this: HTMLDivElement) { - activeMe(this); - const rest = name; - const markup = `#${rest}`; - requestTextEdit({ - newText: { - kind: "by-mode", - markup, - rest, - }, - }); - } - ), + FontAction("Paste string", "Paste as String", function (this: HTMLDivElement) { + activeMe(this); + const rest = name; + const markup = `#${rest}`; + requestTextEdit({ + newText: { + kind: "by-mode", + markup, + rest, + }, + }); + }), " ", - FontAction( - "#set", - "Paste as Set Font Rule", - function (this: HTMLDivElement) { - activeMe(this); - const rest = name; - const markup = `#set text(font: ${rest})`; - requestTextEdit({ - newText: { - kind: "by-mode", - markup, - rest, - }, - }); - } - ) + FontAction("#set", "Paste as Set Font Rule", function (this: HTMLDivElement) { + activeMe(this); + const rest = name; + const markup = `#set text(font: ${rest})`; + requestTextEdit({ + newText: { + kind: "by-mode", + markup, + rest, + }, + }); + }), ), span({ style: "font-size: 1.2em" }, family.name), ".", br(), code("Variant"), ": ", - family.infos.map(FontSlot) - ) + family.infos.map(FontSlot), + ), ); }; @@ -245,7 +225,7 @@ export const FontView = () => { code(fontAtCursor), br(), "Checked at ", - code(fontPosition) + code(fontPosition), ); }; @@ -257,8 +237,7 @@ export const FontView = () => { div( { class: "flex-col", - style: - "justify-content: center; align-items: center; gap: 10px; width: 100%;", + style: "justify-content: center; align-items: center; gap: 10px; width: 100%;", }, div( { @@ -270,24 +249,22 @@ export const FontView = () => { () => { showNumber.val = !showNumber.val; }, - { active: showNumber } - ) + { active: showNumber }, + ), ), div( { class: `tinymist-card`, style: "flex: 1; width: 100%; padding: 10px; display: none", }, - (_dom?: Element) => SelectingSlot() + (_dom?: Element) => SelectingSlot(), ), - ...fontResources.val.families.map(FontFamilySlot) - ) + ...fontResources.val.families.map(FontFamilySlot), + ), ); }; -export type fontLocation = FontSource extends { kind: infer Kind } - ? Kind - : never; +export type fontLocation = FontSource extends { kind: infer Kind } ? Kind : never; interface FontInfo { name: string; diff --git a/tools/editor-tools/src/features/symbol-view.ts b/tools/editor-tools/src/features/symbol-view.ts index ee4edf262..a15a2a8ca 100644 --- a/tools/editor-tools/src/features/symbol-view.ts +++ b/tools/editor-tools/src/features/symbol-view.ts @@ -21,8 +21,7 @@ import { base64Decode } from "../utils"; // }; ortEnv.wasm.numThreads = 4; -ortEnv.wasm.wasmPaths = - "https://cdn.jsdelivr.net/npm/onnxruntime-web@1.17.1/dist/"; +ortEnv.wasm.wasmPaths = "https://cdn.jsdelivr.net/npm/onnxruntime-web@1.17.1/dist/"; type Point = [number, number]; type Stroke = Point[]; @@ -85,7 +84,7 @@ const SYMBOL_MOCK: SymbolInformation = { const SearchBar = ( state: State, - symbolSelected: State + symbolSelected: State, ) => { const def = MiniSearch.getDefault("tokenize"); const search = van.derive(() => { @@ -233,18 +232,15 @@ const CanvasPanel = (strokesState: State) => { startModal( p( "The ", - span( - { style: "font-weight: bold; text-decoration: underline" }, - "offline" - ), + span({ style: "font-weight: bold; text-decoration: underline" }, "offline"), " handwritten stroke recognizer is powered by ", a( { href: "https://github.com/QuarticCat/detypify", }, - "Detypify" + "Detypify", ), - ". Draw a symbol to search for it." + ". Draw a symbol to search for it.", ), h4("Cannot find some symbols?"), p( @@ -253,9 +249,9 @@ const CanvasPanel = (strokesState: State) => { { href: "https://github.com/QuarticCat/detypify/blob/main/assets/supported-symbols.txt", }, - "supported-symbols.txt" + "supported-symbols.txt", ), - "." + ".", ), p( "❤️‍🔥: Click the ", @@ -267,9 +263,9 @@ const CanvasPanel = (strokesState: State) => { { href: "https://detypify.quarticcat.com/", }, - "Detypify" + "Detypify", ), - "." + ".", ), p( "📝: Report the missing symbol to ", @@ -277,9 +273,9 @@ const CanvasPanel = (strokesState: State) => { { href: "https://github.com/QuarticCat/detypify/issues/new", }, - "GitHub Issues" + "GitHub Issues", ), - "." + ".", ), h4("Like it?"), p( @@ -288,16 +284,16 @@ const CanvasPanel = (strokesState: State) => { { href: "https://github.com/QuarticCat/detypify", }, - "Detypify" + "Detypify", ), - "!" - ) + "!", + ), ); }, }, - HelpIcon() + HelpIcon(), ), - srcCanvas + srcCanvas, ), button( { @@ -305,8 +301,8 @@ const CanvasPanel = (strokesState: State) => { title: "clear", onclick: drawClear, }, - "Clear" - ) + "Clear", + ), ); }; @@ -441,16 +437,14 @@ const CATEGORY_INFO: SymbolCategory[] = [ }, ]; // generate map from category value to category name -const categoryIndex = new Map( - CATEGORY_INFO.map((cat) => [cat.value, cat.name.toLowerCase()]) -); +const categoryIndex = new Map(CATEGORY_INFO.map((cat) => [cat.value, cat.name.toLowerCase()])); export const SymbolPicker = () => { const symbolInformationData = `:[[preview:SymbolInformation]]:`; const symInfo = van.state( symbolInformationData.startsWith(":") ? SYMBOL_MOCK - : JSON.parse(base64Decode(symbolInformationData)) + : JSON.parse(base64Decode(symbolInformationData)), ); console.log("symbolInformation", symInfo); const detypifyPromise = Detypify.create(); @@ -473,7 +467,7 @@ export const SymbolPicker = () => { () => ` ${symInfo.val.glyphDefs || ""} - ` + `, ), }); @@ -494,10 +488,7 @@ export const SymbolPicker = () => { }; const bboxXWidth = diff(primaryGlyph.xMin, primaryGlyph.xMax); - let xWidth = Math.max( - bboxXWidth, - primaryGlyph.xAdvance || fontSelected.unitsPerEm - ); + let xWidth = Math.max(bboxXWidth, primaryGlyph.xAdvance || fontSelected.unitsPerEm); let yReal = diff(primaryGlyph.yMin, primaryGlyph.yMax); let yGlobal = primaryGlyph.yAdvance || fontSelected.unitsPerEm; @@ -527,7 +518,7 @@ export const SymbolPicker = () => { // console.log(sym.typstCode, div({ innerHTML: imageData })); maskInfo.setAttribute( "style", - `width: ${symWidth}; height: ${symHeight}; -webkit-mask-image: url('data:image/svg+xml;utf8,${encodeURIComponent(imageData)}'); -webkit-mask-size: auto ${symHeight}; -webkit-mask-repeat: no-repeat; transition: background-color 200ms; background-color: currentColor;` + `width: ${symWidth}; height: ${symHeight}; -webkit-mask-image: url('data:image/svg+xml;utf8,${encodeURIComponent(imageData)}'); -webkit-mask-size: auto ${symHeight}; -webkit-mask-repeat: no-repeat; transition: background-color 200ms; background-color: currentColor;`, ); }, 1); } @@ -557,7 +548,7 @@ export const SymbolPicker = () => { }); }, }, - maskInfo + maskInfo, ); }; @@ -566,8 +557,8 @@ export const SymbolPicker = () => { div({ style: "font-size: 14px; margin: 8px 0" }, cat.name), div( { class: "flex-row", style: "flex-wrap: wrap; gap: 5px; width: 100%" }, - ...(cat.symbols || []).map((sym) => sym.elem) - ) + ...(cat.symbols || []).map((sym) => sym.elem), + ), ); }; @@ -580,25 +571,21 @@ export const SymbolPicker = () => { value, elem: SymbolCell(value), }; - }) - ); - const filteredPickers = van.state( - undefined + }), ); + const filteredPickers = van.state(undefined); function pickSymbolsBySearch( pickers: { key: string; value: SymbolItem; elem: Element }[], - filteredPickers: SelectedSymbolItem[] | undefined + filteredPickers: SelectedSymbolItem[] | undefined, ) { if (!filteredPickers) return pickers; - return pickers.filter((picker) => - filteredPickers.some((f) => f.typstCode === picker.key) - ); + return pickers.filter((picker) => filteredPickers.some((f) => f.typstCode === picker.key)); } function pickSymbolsByDrawCandidates( pickers: { key: string; value: SymbolItem; elem: Element }[], - drawCandidates: DetypifySymbol[] | undefined + drawCandidates: DetypifySymbol[] | undefined, ) { if (drawCandidates === undefined) return pickers; if (!drawCandidates.length) return []; @@ -623,7 +610,7 @@ export const SymbolPicker = () => { style: "flex: 0 0 auto; gap: 5px", }, SearchBar(symInfo, filteredPickers), - CanvasPanel(strokes) + CanvasPanel(strokes), ), div({ style: "flex: 1;" }, (_dom?: Element) => div( @@ -631,27 +618,23 @@ export const SymbolPicker = () => { CATEGORY_INFO, pickSymbolsBySearch( pickSymbolsByDrawCandidates(pickers.val, drawCandidates.val), - filteredPickers.val - ) + filteredPickers.val, + ), ) .filter((cat) => cat.symbols?.length) - .map((info) => CategoryPicker(info)) - ) - ) + .map((info) => CategoryPicker(info)), + ), + ), ); }; function categorize( catsRaw: SymbolCategory[], - symInfo: InstantiatedSymbolItem[] + symInfo: InstantiatedSymbolItem[], ): InstantiatedSymbolCategory[] { - let cats: InstantiatedSymbolCategory[] = [ - ...catsRaw.map((cat) => ({ ...cat })), - ]; + let cats: InstantiatedSymbolCategory[] = [...catsRaw.map((cat) => ({ ...cat }))]; // let misc - let misc: InstantiatedSymbolCategory = cats.find( - (cat) => cat.name === "Miscellaneous" - )!; + let misc: InstantiatedSymbolCategory = cats.find((cat) => cat.name === "Miscellaneous")!; // misc.symbols = symInfo.val.symbols; for (let sym of symInfo) { const { key, value } = sym; diff --git a/tools/editor-tools/src/features/template-gallery.ts b/tools/editor-tools/src/features/template-gallery.ts index 034d21c72..9b1040930 100644 --- a/tools/editor-tools/src/features/template-gallery.ts +++ b/tools/editor-tools/src/features/template-gallery.ts @@ -30,10 +30,7 @@ interface PackageMeta { template: any; } -const TemplateList = ( - packages: State, - catState: FilterState -) => { +const TemplateList = (packages: State, catState: FilterState) => { const AuthorItem = (author: string) => { // split by < const [nameStart, emailRest] = author.split("<"); @@ -55,10 +52,7 @@ const TemplateList = ( const AuthorList = (authors: string[]) => { if (authors.length <= 1) { - return span( - { class: `tinymist-author-container` }, - ...authors.map(AuthorItem) - ); + return span({ class: `tinymist-author-container` }, ...authors.map(AuthorItem)); } return span( @@ -70,57 +64,51 @@ const TemplateList = ( style: "text-decoration: underline", title: authors.slice(1).join(", "), }, - "et al." - ) + "et al.", + ), ); }; const highlightMatches = (text: string, searchResults?: SearchResult[]): HTMLSpanElement => { if (!searchResults || !text) return van.tags.span({}, text); - const searchTerms = searchResults.flatMap(result => result.queryTerms); - const regex = new RegExp(`(${searchTerms.join("|")})`, 'gi'); + const searchTerms = searchResults.flatMap((result) => result.queryTerms); + const regex = new RegExp(`(${searchTerms.join("|")})`, "gi"); const parts = text.split(regex); - return van.tags.span({}, ...parts.map(part => - regex.test(part) - ? van.tags.span({ class: 'tinymist-highlight' }, part) - : part - )); - } + return van.tags.span( + {}, + ...parts.map((part) => + regex.test(part) ? van.tags.span({ class: "tinymist-highlight" }, part) : part, + ), + ); + }; const TemplateListItem = (item: PackageMeta) => { - const TemplateAction = ( - icon: ChildDom, - title: string, - onclick: () => void - ) => + const TemplateAction = (icon: ChildDom, title: string, onclick: () => void) => button( { class: "tinymist-button tinymist-template-action", title, onclick, }, - icon + icon, ); return Card( "template-card", div( - a({ href: item.repository, style: "font-size: 1.2em" }, - () => { - return highlightMatches(item.name, catState.searchSelected.val); - } - ), + a({ href: item.repository, style: "font-size: 1.2em" }, () => { + return highlightMatches(item.name, catState.searchSelected.val); + }), span(" "), span({ style: "font-size: 0.8em" }, "v" + item.version), span(" by "), - AuthorList(item.authors) + AuthorList(item.authors), ), div( { - style: - "display: flex; align-items: center; gap: 0.25em; margin-top: 0.4em;", + style: "display: flex; align-items: center; gap: 0.25em; margin-top: 0.4em;", class: "tinymist-template-actions", }, button( @@ -134,13 +122,13 @@ const TemplateList = ( title: van.derive(() => catState.getIsFavorite("preview", item.name) ? "Removes from favorite" - : "Adds to favorite" + : "Adds to favorite", ), onclick() { catState.negIsFavorite("preview", item.name); }, }, - HeartIcon(16) + HeartIcon(16), ), TemplateAction(AddIcon(16), "Creates project", () => { const packageSpec = `@preview/${item.name}:${item.version}`; @@ -156,22 +144,22 @@ const TemplateList = ( } return { value: cat }; }) - .map(CategoryButton(catState)) + .map(CategoryButton(catState)), ), div({ style: "clear: both" }), - div({ style: "margin-top: 0.4em" }, + div( + { style: "margin-top: 0.4em" }, div({}, () => { return highlightMatches(item.description, catState.searchSelected.val); - }) - ) + }), + ), ); }; function runFilterSearch(searchResult: SearchResult[] | undefined) { // console.log("search", searchResult); const searchResultMap = new Set(searchResult?.map((result) => result.id)); - return (value: PackageMeta) => - searchResult === undefined || searchResultMap.has(value.id); + return (value: PackageMeta) => searchResult === undefined || searchResultMap.has(value.id); } function runFilterCategory(categoryFilter: Set) { @@ -197,8 +185,8 @@ const TemplateList = ( .filter(runFilterCategory(catState.categories.val)) .filter(runFilterFavorite) .filter(runFilterSearch(catState.searchSelected.val)) - .map(TemplateListItem) || [] - ) + .map(TemplateListItem) || [], + ), ); }; @@ -280,8 +268,7 @@ const CategoryButton = (catState: FilterState) => (category: Category) => { return button( { class: van.derive(() => { - const activatingCls = - category.value === catState.activating.val ? " activated" : ""; + const activatingCls = category.value === catState.activating.val ? " activated" : ""; return "tinymist-button" + activatingCls; }), title: "Filter by category: " + category.value, @@ -291,8 +278,8 @@ const CategoryButton = (catState: FilterState) => (category: Category) => { { style: "height: 16px;", }, - category.display || category.value - ) + category.display || category.value, + ), ); }; @@ -304,15 +291,14 @@ const FilterRow = (catState: FilterState) => { return "tinymist-button" + activatingCls; }), title: "Filter by favorite state", - onclick: () => - (catState.filterFavorite.val = !catState.filterFavorite.val), + onclick: () => (catState.filterFavorite.val = !catState.filterFavorite.val), }, - HeartIcon(16) + HeartIcon(16), ); return div( { class: "tinymist-category-filter" }, favButton, - ...CATEGORIES.map(CategoryButton(catState)) + ...CATEGORIES.map(CategoryButton(catState)), ); }; @@ -322,15 +308,13 @@ export const TemplateGallery = () => { const favoritePlaceholders = `:[[preview:FavoritePlaceholder]]:`; const catState = new FilterState( JSON.parse( - favoritePlaceholders.startsWith(":") - ? favoriteState - : base64Decode(favoritePlaceholders) - ) + favoritePlaceholders.startsWith(":") ? favoriteState : base64Decode(favoritePlaceholders), + ), ); van.derive(async () => { - const rawPackages = await fetch( - "https://packages.typst.org/preview/index.json" - ).then((res) => res.json()); + const rawPackages = await fetch("https://packages.typst.org/preview/index.json").then((res) => + res.json(), + ); // collect packages by version const packagesIndex = new Map(); @@ -355,9 +339,5 @@ export const TemplateGallery = () => { packages.val = packagesList; }); - return div( - SearchBar(packages, catState), - FilterRow(catState), - TemplateList(packages, catState) - ); + return div(SearchBar(packages, catState), FilterRow(catState), TemplateList(packages, catState)); }; diff --git a/tools/editor-tools/src/utils.ts b/tools/editor-tools/src/utils.ts index 024ca81ab..2893499e2 100644 --- a/tools/editor-tools/src/utils.ts +++ b/tools/editor-tools/src/utils.ts @@ -15,8 +15,4 @@ export const base64Decode = (encoded: string) => * @returns Base64 encoded string */ export const base64Encode = (utf8Str: string) => - btoa( - Array.from(utf82bytes.encode(utf8Str), (c) => String.fromCharCode(c)).join( - "" - ) - ); + btoa(Array.from(utf82bytes.encode(utf8Str), (c) => String.fromCharCode(c)).join("")); diff --git a/tools/editor-tools/vite.config.js b/tools/editor-tools/vite.config.js index f6f2e8e77..23eddced4 100644 --- a/tools/editor-tools/vite.config.js +++ b/tools/editor-tools/vite.config.js @@ -3,15 +3,15 @@ import { viteSingleFile } from "vite-plugin-singlefile"; // /src/main.ts -const compPrefix = '--component='; -const componentArgs = process.argv.find(arg => arg.startsWith(compPrefix)); -let output = 'dist/default'; +const compPrefix = "--component="; +const componentArgs = process.argv.find((arg) => arg.startsWith(compPrefix)); +let output = "dist/default"; if (componentArgs) { const component = componentArgs.substring(compPrefix.length); process.env.VITE_ENTRY = `/src/main.${component}.ts`; output = `dist/${component}`; } else { - process.env.VITE_ENTRY = '/src/main.ts'; + process.env.VITE_ENTRY = "/src/main.ts"; } export default defineConfig({ @@ -19,13 +19,13 @@ export default defineConfig({ assetsInclude: ["**/*.onnx"], build: { minify: false, - outDir: output + outDir: output, }, optimizeDeps: { esbuildOptions: { loader: { ".onnx": "dataurl", }, - } - } + }, + }, }); diff --git a/tools/typst-dom/src/index.mts b/tools/typst-dom/src/index.mts index bf04c72c1..551f2d23a 100644 --- a/tools/typst-dom/src/index.mts +++ b/tools/typst-dom/src/index.mts @@ -21,5 +21,5 @@ import { TypstDocumentContext, composeDoc, provideDoc } from "./typst-doc.mjs"; * ) {} */ export class TypstDocument extends provideDoc( - composeDoc(TypstDocumentContext, provideCanvasDoc, provideSvgDoc) + composeDoc(TypstDocumentContext, provideCanvasDoc, provideSvgDoc), ) {} diff --git a/tools/typst-dom/src/index.preview.mts b/tools/typst-dom/src/index.preview.mts index 114ad52d8..091213163 100644 --- a/tools/typst-dom/src/index.preview.mts +++ b/tools/typst-dom/src/index.preview.mts @@ -11,6 +11,6 @@ export class TypstPreviewDocument extends provideDoc( provideOutlineDoc, provideCanvasDoc, provideSvgDoc, - provideDebugJumpDoc - ) + provideDebugJumpDoc, + ), ) {} diff --git a/tools/typst-dom/src/typst-animation.mts b/tools/typst-dom/src/typst-animation.mts index 6a4e83b6d..9a37a6623 100644 --- a/tools/typst-dom/src/typst-animation.mts +++ b/tools/typst-dom/src/typst-animation.mts @@ -4,7 +4,7 @@ export function triggerRipple( top: number, className: string, animation: string, - color?: string + color?: string, ) { const ripple = document.createElement("div"); diff --git a/tools/typst-dom/src/typst-doc.canvas.mts b/tools/typst-dom/src/typst-doc.canvas.mts index a32f9e348..ed1af4ce0 100644 --- a/tools/typst-dom/src/typst-doc.canvas.mts +++ b/tools/typst-dom/src/typst-doc.canvas.mts @@ -35,9 +35,7 @@ export interface TypstCanvasDocument { } export function provideCanvasDoc< - TBase extends GConstructor< - TypstDocumentContext & Partial - >, + TBase extends GConstructor>, >(Base: TBase): TBase & GConstructor { return class CanvasDocument extends Base { feat$canvas = true; @@ -62,40 +60,28 @@ export function provideCanvasDoc< pageInfo.elem = document.createElement("div"); pageInfo.elem.setAttribute("class", "typst-page-canvas"); pageInfo.elem.style.transformOrigin = "0 0"; - pageInfo.elem.setAttribute( - "data-page-number", - pageInfo.index.toString() - ); + pageInfo.elem.setAttribute("data-page-number", pageInfo.index.toString()); const canvas = document.createElement("canvas"); pageInfo.elem.appendChild(canvas); pageInfo.container = document.createElement("div"); // todo: reuse by key - pageInfo.container.setAttribute( - TypstPatchAttrs.Tid, - `canvas:` + pageInfo.index - ); + pageInfo.container.setAttribute(TypstPatchAttrs.Tid, `canvas:` + pageInfo.index); pageInfo.container.setAttribute("class", "typst-page canvas-mode"); - pageInfo.container.setAttribute( - "data-page-number", - pageInfo.index.toString() - ); + pageInfo.container.setAttribute("data-page-number", pageInfo.index.toString()); pageInfo.container.appendChild(pageInfo.elem); // do scaling early this.prepareCanvas(pageInfo, canvas); rescale( pageInfo.container, - this.isContentPreview || this.renderMode !== "canvas" || isFirst + this.isContentPreview || this.renderMode !== "canvas" || isFirst, ); if (this.isContentPreview) { const pageNumberIndicator = document.createElement("div"); - pageNumberIndicator.setAttribute( - "class", - "typst-preview-canvas-page-number" - ); + pageNumberIndicator.setAttribute("class", "typst-preview-canvas-page-number"); pageNumberIndicator.textContent = `${pageInfo.index + 1}`; pageInfo.container.appendChild(pageNumberIndicator); @@ -146,10 +132,7 @@ export function provideCanvasDoc< return cached; } - async updateCanvas( - pages: CanvasPage[], - opts?: UpdateCanvasOptions - ): Promise { + async updateCanvas(pages: CanvasPage[], opts?: UpdateCanvasOptions): Promise { const tok = opts?.cancel || undefined; const perf = performance.now(); console.log("updateCanvas start"); @@ -181,8 +164,7 @@ export function provideCanvasDoc< let cached = this.prepareCanvas(pageInfo, canvas); - const cacheKey = - pageInfo.elem.getAttribute("data-cache-key") || undefined; + const cacheKey = pageInfo.elem.getAttribute("data-cache-key") || undefined; const result = await this.kModule.renderCanvas({ canvas: canvas.getContext("2d")!, pageOffset: pageInfo.index, @@ -221,18 +203,12 @@ export function provideCanvasDoc< if (noSpacingFromTop) { canvasContainer.style.marginTop = `0px`; } else { - canvasContainer.style.marginTop = `${ - this.isContentPreview ? 6 : 5 - }px`; + canvasContainer.style.marginTop = `${this.isContentPreview ? 6 : 5}px`; } let elem = canvasContainer.firstElementChild as HTMLDivElement; - const canvasWidth = Number.parseFloat( - elem.getAttribute("data-page-width")! - ); - const canvasHeight = Number.parseFloat( - elem.getAttribute("data-page-height")! - ); + const canvasWidth = Number.parseFloat(elem.getAttribute("data-page-width")!); + const canvasHeight = Number.parseFloat(elem.getAttribute("data-page-height")!); this.currentRealScale = this.previewMode === PreviewMode.Slide @@ -240,9 +216,7 @@ export function provideCanvasDoc< : cw / canvasWidth; const scale = // The element in svg is already scaled by svg host - this.renderMode === "svg" - ? 1 - : this.currentRealScale * this.currentScaleRatio; + this.renderMode === "svg" ? 1 : this.currentRealScale * this.currentScaleRatio; // apply scale const appliedScale = (scale / this.pixelPerPt).toString(); @@ -309,18 +283,16 @@ export function provideCanvasDoc< async rerender$canvas() { // console.log('toggleCanvasViewportChange!!!!!!', this.id, this.isRendering); - const pages: CanvasPage[] = this.kModule - .retrievePagesInfo() - .map((x, index) => { - return { - tag: "canvas", - index, - width: x.width, - height: x.height, - container: undefined as any as HTMLDivElement, - elem: undefined as any as HTMLDivElement, - }; - }); + const pages: CanvasPage[] = this.kModule.retrievePagesInfo().map((x, index) => { + return { + tag: "canvas", + index, + width: x.width, + height: x.height, + container: undefined as any as HTMLDivElement, + elem: undefined as any as HTMLDivElement, + }; + }); if (!this.hookedElem.firstElementChild) { this.hookedElem.innerHTML = `
`; @@ -338,9 +310,7 @@ export function provideCanvasDoc< checkChildren(canvasContainer); } if (canvasContainer.classList.contains("typst-page")) { - const pageNumber = Number.parseInt( - ch.getAttribute("data-page-number")! - ); + const pageNumber = Number.parseInt(ch.getAttribute("data-page-number")!); if (pageNumber >= pages.length) { // todo: cache key can shifted elem.removeChild(ch); @@ -358,9 +328,7 @@ export function provideCanvasDoc< if (!ch.classList.contains("typst-page")) { continue; } - const pageNumber = Number.parseInt( - ch.getAttribute("data-page-number")! - ); + const pageNumber = Number.parseInt(ch.getAttribute("data-page-number")!); if (pageNumber >= pages.length) { // todo: cache key shifted docDiv.removeChild(ch); diff --git a/tools/typst-dom/src/typst-doc.test.mts b/tools/typst-dom/src/typst-doc.test.mts index d700fbaa8..ceeb28b8c 100644 --- a/tools/typst-dom/src/typst-doc.test.mts +++ b/tools/typst-dom/src/typst-doc.test.mts @@ -14,9 +14,9 @@ interface TypstCanvasDocument { renderCanvas(): number; } -function provideCanvas< - TBase extends GConstructor ->(Base: TBase): TBase & GConstructor { +function provideCanvas>( + Base: TBase, +): TBase & GConstructor { return class extends Base { canvasFeat = 10; renderCanvas() { @@ -25,9 +25,9 @@ function provideCanvas< }; } -function provideSvg< - TBase extends GConstructor ->(Base: TBase): TBase & GConstructor { +function provideSvg>( + Base: TBase, +): TBase & GConstructor { return class extends Base { feat = 100; svgProp() { @@ -42,9 +42,7 @@ function provideSvg< describe("mixinClass", () => { it("doMixin", () => { const T = provideSvg( - provideCanvas( - TypstDocument as GConstructor - ) + provideCanvas(TypstDocument as GConstructor), ); const t = new T(); expect(t.renderCanvas()).toBe(51); diff --git a/tools/typst-dom/src/typst-outline.mts b/tools/typst-dom/src/typst-outline.mts index 97d892a21..386297afc 100644 --- a/tools/typst-dom/src/typst-outline.mts +++ b/tools/typst-dom/src/typst-outline.mts @@ -42,7 +42,7 @@ class GenElem { constructor( public tag: string, public container: HTMLElement, - public additions?: Record + public additions?: Record, ) {} push(child: GenNode) { @@ -171,7 +171,7 @@ class GenContext { export function patchOutlineEntry( prev: HTMLDivElement, pages: CanvasPage[], - items: OutlineItemData[] + items: OutlineItemData[], ) { const ctx = new GenContext(pages); // the root element of the generated outline @@ -190,8 +190,7 @@ export function patchOutlineEntry( for (const elem of ctx.allElemList) { // apply clickable behavior to node containing children if (elem.children.some(isDataNode)) { - const titleContentSpan = elem.additions!.title!.additions! - .content as HTMLSpanElement; + const titleContentSpan = elem.additions!.title!.additions!.content as HTMLSpanElement; titleContentSpan.style.textDecoration = "underline"; titleContentSpan.style.cursor = "pointer"; @@ -221,11 +220,7 @@ export function patchOutlineEntry( /// Replace the `prev` element with `next` element. /// Return true if the `prev` element is reused. /// Return false if the `prev` element is replaced. -function reuseOrPatchOutlineElem( - ctx: GenContext, - prev: Element, - next: Element -) { +function reuseOrPatchOutlineElem(ctx: GenContext, prev: Element, next: Element) { const canReuse = equalPatchElem(prev, next); /// Even if the element is reused, we still need to replace its attributes. @@ -237,9 +232,7 @@ function reuseOrPatchOutlineElem( if (canReuse) { if (isPageElem) { - const pageNumber = Number.parseInt( - next.getAttribute("data-page-number")! - ); + const pageNumber = Number.parseInt(next.getAttribute("data-page-number")!); // console.log('reuse canvas', ctx.pages[pageNumber], prev, next); const page = ctx.pages[pageNumber]; page.inserter = poisionCanvasMoved; @@ -264,7 +257,7 @@ function patchOutlineChildren(ctx: GenContext, prev: Element, next: Element) { prev.children as unknown as Element[], next.children as unknown as Element[], // todo: accurate calculation - false + false, ); // console.log("interpreted origin outline", targetView, toPatch); @@ -275,10 +268,7 @@ function patchOutlineChildren(ctx: GenContext, prev: Element, next: Element) { // console.log("interpreted target outline", targetView); - const originView = changeViewPerspective( - prev.children as unknown as Element[], - targetView - ); + const originView = changeViewPerspective(prev.children as unknown as Element[], targetView); runOriginViewInstructionsOnOutline(ctx, prev, originView); } @@ -286,7 +276,7 @@ function patchOutlineChildren(ctx: GenContext, prev: Element, next: Element) { function runOriginViewInstructionsOnOutline( ctx: GenContext, prev: Element, - originView: OriginViewInstruction[] + originView: OriginViewInstruction[], ) { // console.log("interpreted origin view", originView); for (const [op, off, fr] of originView) { @@ -300,9 +290,7 @@ function runOriginViewInstructionsOnOutline( break; case "remove": if (elem?.classList?.contains("typst-page")) { - const pageNumber = Number.parseInt( - elem.getAttribute("data-page-number")! - ); + const pageNumber = Number.parseInt(elem.getAttribute("data-page-number")!); if (pageNumber < ctx.pages.length) { const page = ctx.pages[pageNumber]; // console.log('recover canvas', page, pageNumber); @@ -321,22 +309,14 @@ function runOriginViewInstructionsOnOutline( } export interface TypstOutlineDocument { - patchOutlineEntry( - prev: HTMLDivElement, - pages: CanvasPage[], - items: OutlineItemData[] - ): void; + patchOutlineEntry(prev: HTMLDivElement, pages: CanvasPage[], items: OutlineItemData[]): void; } -export function provideOutlineDoc< - TBase extends GConstructor, ->(Base: TBase): TBase & GConstructor { +export function provideOutlineDoc>( + Base: TBase, +): TBase & GConstructor { return class DebugJumpDocument extends Base { - patchOutlineEntry( - prev: HTMLDivElement, - pages: CanvasPage[], - items: OutlineItemData[] - ) { + patchOutlineEntry(prev: HTMLDivElement, pages: CanvasPage[], items: OutlineItemData[]) { patchOutlineEntry(prev, pages, items); } }; diff --git a/tools/typst-dom/src/typst-patch.mts b/tools/typst-dom/src/typst-patch.mts index f82a77da9..717ae7cc8 100644 --- a/tools/typst-dom/src/typst-patch.mts +++ b/tools/typst-dom/src/typst-patch.mts @@ -72,10 +72,7 @@ export function equalPatchElem(prev: ElementChildren, next: ElementChildren) { /// To remove unused resources, An extra remove inst can remove a specify element /// /// Example5: resource:[o1, o2] -> -> [o1, t1] and remove o2 -export type TargetViewInstruction = - | ["append", T] - | ["reuse", number] - | ["remove", number]; +export type TargetViewInstruction = ["append", T] | ["reuse", number] | ["remove", number]; /// The recursive patch operation must be applied to this two element. export type PatchPair = [T /* origin */, T /* target */]; @@ -89,7 +86,7 @@ export function interpretTargetView( targetChildren: T[], // todo: remove this tag isPatchingSvg: boolean = true, // patch svg or outline - tIsU = (x: T): x is U => !!x.getAttribute(TypstPatchAttrs.Tid) + tIsU = (x: T): x is U => !!x.getAttribute(TypstPatchAttrs.Tid), ): ViewTransform { const availableOwnedResource = new Map(); const targetView: TargetViewInstruction[] = []; @@ -187,13 +184,10 @@ export type OriginViewInstruction = /// + Finally, it inserts the extra elements. /// /// Some better strategy would help and be implemented in future. -export function changeViewPerspective< - T extends ElementChildren, - U extends T = T ->( +export function changeViewPerspective( originChildren: T[], targetView: TargetViewInstruction[], - tIsU = (_x: T): _x is U => true + tIsU = (_x: T): _x is U => true, ): OriginViewInstruction[] { const originView: OriginViewInstruction[] = []; @@ -321,7 +315,7 @@ export function changeViewPerspective< export function runOriginViewInstructions( prev: Element, - originView: OriginViewInstruction[] + originView: OriginViewInstruction[], ) { // console.log("interpreted origin view", originView); for (const [op, off, fr] of originView) { diff --git a/tools/typst-dom/src/typst-patch.svg.mts b/tools/typst-dom/src/typst-patch.svg.mts index 2ddc38b7d..5d65f383a 100644 --- a/tools/typst-dom/src/typst-patch.svg.mts +++ b/tools/typst-dom/src/typst-patch.svg.mts @@ -43,7 +43,7 @@ function patchChildren(prev: Element, next: Element) { const originView = changeViewPerspective( prev.children as unknown as SVGGElement[], targetView, - isGElem + isGElem, ); runOriginViewInstructions(prev, originView); @@ -76,10 +76,7 @@ interface FrozenReplacement { debug?: string; } -function preReplaceNonSVGElements( - prev: Element, - next: Element -): FrozenReplacement { +function preReplaceNonSVGElements(prev: Element, next: Element): FrozenReplacement { const removedIndices: number[] = []; const frozenReplacement: FrozenReplacement = { inserts: [], @@ -118,9 +115,9 @@ function postReplaceNonSVGElements(prev: Element, frozen: FrozenReplacement) { /// Retrieve the `` elements from the `prev` element. const gElements = Array.from(prev.children).filter(isGElem); if (gElements.length + 1 !== frozen.inserts.length) { - throw new Error(`invalid frozen replacement: gElements.length (${gElements.length - }) + 1 !=== frozen.inserts.length (${frozen.inserts.length}) ${frozen.debug || "" - } + throw new Error(`invalid frozen replacement: gElements.length (${ + gElements.length + }) + 1 !=== frozen.inserts.length (${frozen.inserts.length}) ${frozen.debug || ""} current: ${prev.outerHTML}`); } @@ -156,10 +153,7 @@ function initOrPatchSvgHeader(svg: SVGElement) { } /// Create a global resource header - const resourceHeader = document.createElementNS( - "http://www.w3.org/2000/svg", - "svg" - ); + const resourceHeader = document.createElementNS("http://www.w3.org/2000/svg", "svg"); resourceHeader.id = "typst-svg-resources"; // set viewbox, width, and height resourceHeader.setAttribute("viewBox", "0 0 0 0"); @@ -195,10 +189,7 @@ function patchSvgHeader(prev: SVGElement, next: SVGElement) { // todo: gc prevChild.append(...nextChild.children); } - } else if ( - prevChild.tagName === "style" && - nextChild.getAttribute("data-reuse") !== "1" - ) { + } else if (prevChild.tagName === "style" && nextChild.getAttribute("data-reuse") !== "1") { // console.log("replace extra style", prevChild, nextChild); // todo: gc @@ -240,7 +231,7 @@ function patchSvgHeader(prev: SVGElement, next: SVGElement) { export function patchSvgToContainer( hookedElem: Element, patchStr: string, - decorateSvgElement: (elem: SVGElement) => void = () => void 0 + decorateSvgElement: (elem: SVGElement) => void = () => void 0, ) { if (hookedElem.firstElementChild) { const elem = document.createElement("div"); diff --git a/tools/typst-dom/src/typst-patch.test.mts b/tools/typst-dom/src/typst-patch.test.mts index c9d04bd47..0c24de86a 100644 --- a/tools/typst-dom/src/typst-patch.test.mts +++ b/tools/typst-dom/src/typst-patch.test.mts @@ -1,9 +1,5 @@ import { describe, expect, it } from "vitest"; -import { - PatchPair, - interpretTargetView, - changeViewPerspective, -} from "./typst-patch.mjs"; +import { PatchPair, interpretTargetView, changeViewPerspective } from "./typst-patch.mjs"; interface Attributes { [key: string]: string | null | undefined; @@ -15,7 +11,7 @@ interface Attributes { class MockElement { tagName = "g"; - constructor(public attrs: Attributes) { } + constructor(public attrs: Attributes) {} getAttribute(s: string): string | null { return this.attrs[s] ?? null; @@ -45,7 +41,7 @@ const repeatOrJust = (n: number | (number | null)[]): MockElement[] => { (i) => new MockElement({ "data-tid": i !== null ? i.toString() : null, - }) + }), ); } @@ -64,7 +60,7 @@ const reuseStub = (n: number | null) => function toSnapshot([targetView, patchPair]: [ (MockElement | number | string)[][], - PatchPair[] + PatchPair[], ]): string[] { const repr = (elem: unknown) => { if (elem instanceof MockElement) { @@ -76,33 +72,24 @@ function toSnapshot([targetView, patchPair]: [ const instructions = targetView.map((i) => { return i.map(repr).join(","); }); - const patches = patchPair.length - ? [patchPair.map((i) => i.map(repr).join("->")).join(",")] - : []; + const patches = patchPair.length ? [patchPair.map((i) => i.map(repr).join("->")).join(",")] : []; return [...instructions, ...patches]; } -const hasTid = (elem: MockElement): elem is MockElement => - elem.getAttribute("data-tid") !== null; +const hasTid = (elem: MockElement): elem is MockElement => elem.getAttribute("data-tid") !== null; -const indexTargetView = ( - init: number | (number | null)[], - rearrange: (number | null)[] -) => +const indexTargetView = (init: number | (number | null)[], rearrange: (number | null)[]) => interpretTargetView( injectOffsets("o", repeatOrJust(init)), injectOffsets("t", rearrange.map(reuseStub)), true, - hasTid + hasTid, ); -const indexOriginView = ( - init: number | (number | null)[], - rearrange: (number | null)[] -) => +const indexOriginView = (init: number | (number | null)[], rearrange: (number | null)[]) => changeViewPerspective( injectOffsets("o", repeatOrJust(init)), indexTargetView(init, rearrange)[0], - hasTid + hasTid, ); describe("interpretView", () => { @@ -262,10 +249,7 @@ describe("interpretView", () => { `); }); it("handleReusePreserveOrder2", () => { - const result = indexTargetView( - [0, 1, 2, 1, 2, 3, 4, 3, 4], - [1, 2, 3, 4, 3, 4, 1, 2] - ); + const result = indexTargetView([0, 1, 2, 1, 2, 3, 4, 3, 4], [1, 2, 3, 4, 3, 4, 1, 2]); expect(toSnapshot(result)).toMatchInlineSnapshot(` [ "reuse,1", @@ -282,10 +266,7 @@ describe("interpretView", () => { `); }); it("handleReusePreserveOrder2_origin", () => { - const result = indexOriginView( - [0, 1, 2, 1, 2, 3, 4, 3, 4], - [1, 2, 3, 4, 3, 4, 1, 2] - ); + const result = indexOriginView([0, 1, 2, 1, 2, 3, 4, 3, 4], [1, 2, 3, 4, 3, 4, 1, 2]); expect(toSnapshot([result, []])).toMatchInlineSnapshot(` [ "remove,0", @@ -301,17 +282,8 @@ describe("interpretView", () => { const target = injectOffsets("t", [0, null].map(reuseStub)); target[0].attrs["data-tid"] = "1"; target[1].attrs["data-tid"] = "0"; - const result = interpretTargetView( - origin, - target, - true, - hasTid - ); - const result2 = changeViewPerspective( - origin, - result[0], - hasTid - ); + const result = interpretTargetView(origin, target, true, hasTid); + const result2 = changeViewPerspective(origin, result[0], hasTid); expect(toSnapshot(result)).toMatchInlineSnapshot(` [ "reuse,3", @@ -328,17 +300,8 @@ describe("interpretView", () => { it("handleMasterproefThesisAffectedByEmptyPageAntiCase", () => { const origin = injectOffsets("o", repeatOrJust([null, null, null, 0, 1])); const target = injectOffsets("t", [0, 1].map(reuseStub)); - const result = interpretTargetView( - origin, - target, - true, - hasTid - ); - const result2 = changeViewPerspective( - origin, - result[0], - hasTid - ); + const result = interpretTargetView(origin, target, true, hasTid); + const result2 = changeViewPerspective(origin, result[0], hasTid); expect(toSnapshot(result)).toMatchInlineSnapshot(` [ "reuse,3", @@ -354,17 +317,8 @@ describe("interpretView", () => { it("handleReuseAppend", () => { const origin = injectOffsets("o", repeatOrJust([null, null, null, 0, 1])); const target = injectOffsets("t", [1, null, 0, null, 1].map(reuseStub)); - const result = interpretTargetView( - origin, - target, - true, - hasTid - ); - const result2 = changeViewPerspective( - origin, - result[0], - hasTid - ); + const result = interpretTargetView(origin, target, true, hasTid); + const result2 = changeViewPerspective(origin, result[0], hasTid); expect(toSnapshot(result)).toMatchInlineSnapshot(` [ "reuse,4", diff --git a/tools/typst-preview-frontend/src/drag.ts b/tools/typst-preview-frontend/src/drag.ts index 77fd4b7a9..e9906fbc1 100644 --- a/tools/typst-preview-frontend/src/drag.ts +++ b/tools/typst-preview-frontend/src/drag.ts @@ -1,50 +1,49 @@ export function setupDrag() { - let lastPos = { x: 0, y: 0 }; - let moved = false; - let containerElement: HTMLElement | null = null; - const mouseMoveHandler = function (e: MouseEvent) { - // How far the mouse has been moved - const dx = e.clientX - lastPos.x; - const dy = e.clientY - lastPos.y; + let lastPos = { x: 0, y: 0 }; + let moved = false; + let containerElement: HTMLElement | null = null; + const mouseMoveHandler = function (e: MouseEvent) { + // How far the mouse has been moved + const dx = e.clientX - lastPos.x; + const dy = e.clientY - lastPos.y; - window.scrollBy(-dx, -dy); - lastPos = { - x: e.clientX, - y: e.clientY, - }; - moved = true; + window.scrollBy(-dx, -dy); + lastPos = { + x: e.clientX, + y: e.clientY, }; - const mouseUpHandler = function () { - document.removeEventListener('mousemove', mouseMoveHandler); - document.removeEventListener('mouseup', mouseUpHandler); - if (!containerElement) return; - if (!moved) { - document.getSelection()?.removeAllRanges(); - } - containerElement.style.cursor = 'grab'; - }; - const mouseDownHandler = function (e: MouseEvent) { - lastPos = { - // Get the current mouse position - x: e.clientX, - y: e.clientY, - }; - if (!containerElement) return; - const elementUnderMouse = e.target as HTMLElement | null; - if (elementUnderMouse !== null && elementUnderMouse.classList.contains('tsel')) { - return; - } - e.preventDefault(); - containerElement.style.cursor = 'grabbing'; - moved = false; - - document.addEventListener('mousemove', mouseMoveHandler); - document.addEventListener('mouseup', mouseUpHandler); - }; - document.addEventListener('DOMContentLoaded', () => { - containerElement = document.getElementById('typst-container'); - if (!containerElement) return; - containerElement.addEventListener('mousedown', mouseDownHandler); + moved = true; + }; + const mouseUpHandler = function () { + document.removeEventListener("mousemove", mouseMoveHandler); + document.removeEventListener("mouseup", mouseUpHandler); + if (!containerElement) return; + if (!moved) { + document.getSelection()?.removeAllRanges(); } - ); + containerElement.style.cursor = "grab"; + }; + const mouseDownHandler = function (e: MouseEvent) { + lastPos = { + // Get the current mouse position + x: e.clientX, + y: e.clientY, + }; + if (!containerElement) return; + const elementUnderMouse = e.target as HTMLElement | null; + if (elementUnderMouse !== null && elementUnderMouse.classList.contains("tsel")) { + return; + } + e.preventDefault(); + containerElement.style.cursor = "grabbing"; + moved = false; + + document.addEventListener("mousemove", mouseMoveHandler); + document.addEventListener("mouseup", mouseUpHandler); + }; + document.addEventListener("DOMContentLoaded", () => { + containerElement = document.getElementById("typst-container"); + if (!containerElement) return; + containerElement.addEventListener("mousedown", mouseDownHandler); + }); }