commit 8853c614d730ed5b1396779b91d53c4e26844f08 Author: SirBlobby Date: Sat Jul 18 15:00:22 2026 -0400 Add Typst Desktop app diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6635cf5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +node_modules +/build +/.svelte-kit +/package +.env +.env.* +!.env.example +vite.config.js.timestamp-* +vite.config.ts.timestamp-* diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..61343e9 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "svelte.svelte-vscode", + "tauri-apps.tauri-vscode", + "rust-lang.rust-analyzer" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2f86c50 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "svelte.enable-ts-plugin": true +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..04f3e07 --- /dev/null +++ b/README.md @@ -0,0 +1,121 @@ +# Typst Desktop + +[![Typst Version](https://img.shields.io/badge/Typst-0.14.2-239dad?logo=typst&logoColor=white)](https://typst.app/) +[![Rust](https://img.shields.io/badge/Rust-1.82+-orange?logo=rust&logoColor=white)](https://www.rust-lang.org/) +[![Tauri](https://img.shields.io/badge/Tauri-2-24C8DB?logo=tauri&logoColor=white)](https://tauri.app/) +[![SvelteKit](https://img.shields.io/badge/SvelteKit-5-ff3e00?logo=svelte)](https://kit.svelte.dev/) +[![Tailwind CSS](https://img.shields.io/badge/Tailwind_CSS-06B6D4?logo=tailwindcss&logoColor=white)](https://tailwindcss.com/) +[![SQLite](https://img.shields.io/badge/SQLite-003B57?logo=sqlite&logoColor=white)](https://www.sqlite.org/) + +A desktop editor for Typst. Your documents stay as plain files on your own drive, and can optionally sync to a [TypstDrive](../typstdrive) server so the same notes open on any device. + +The Typst compiler is built into the app — there is nothing extra to install to write and export documents. + +## Features + +- **Local first**: Every document is an ordinary file in a folder you choose. Nothing is locked in a database, and any other editor can open the same files. +- **Two views**: A file viewer for browsing folders, projects, and documents, and an editor view for writing. +- **Single files or projects**: Open a lone `.typ` file, or a project folder with its own `typst.toml`, chapters, bibliography, and assets. +- **Live preview**: The preview recompiles as you type. Saving is not required to see changes. +- **Editor**: Typst syntax highlighting, snippet autocompletion, a formatting toolbar, inline diagnostics, and optional `tinymist` language server support. +- **Cloud sync**: Link a project to a TypstDrive Space to push and pull changes, with three-way merge and a conflict resolver for files edited in both places. +- **Images and fonts**: Import files from anywhere on disk, or drag and drop them in. A shared asset library makes images and fonts available to every project. +- **Thumbnails**: Documents show their first compiled page; images show a preview. +- **Image viewer**: Open images full screen with zoom and folder navigation. + +## Storage + +By default the workspace lives at `~/typst` (for example, `/home/blob/typst`). Change it in Settings. + +Inside the workspace: + +| Path | Contents | +|---|---| +| `/` | Your folders, projects, and documents. | +| `/.assets/` | Shared images and fonts available to every project. | + +Application data — settings, sync state, and the thumbnail cache — is kept in a SQLite database in the platform's app-data directory. Documents themselves are never stored there. + +## Fonts and Images + +Fonts and images work the same way as in TypstDrive. A file is available to the compiler by its name. + +### Fonts + +Import `.ttf`, `.otf`, `.ttc`, or `.otc` files through **Assets**, or place them in a folder beside your document. Typst Desktop reads the family name embedded in the file and registers every weight and style under it. + +```typst +#set text(font: "JetBrains Mono") +``` + +The toolbar's font dropdown lists every family available to the open document, including the fonts bundled with the app. If a family is not listed, it has not been picked up, and the name in your document will not resolve. + +### Images + +Reference an image by its file name: + +```typst +#image("logo.png", width: 50%) +``` + +Images in the shared asset library are available to every project. Images inside a project folder are available to that project and override an asset of the same name. + +## Cloud Sync + +Sync is optional. Without it the app is entirely local. + +1. Open **Settings**, enter your TypstDrive server URL, and sign in. +2. In the file viewer, choose **Upload to cloud** on a project to create a Space from it. +3. Use **Sync** in the editor to pull remote changes and push local ones. + +A project already in the cloud can be brought to another device from the **Cloud** tab in the file viewer. + +### Conflicts + +Sync pulls before it pushes. When a file changed both locally and in the cloud, a three-way merge is attempted against the version last synced. If the merge cannot be resolved automatically, a conflict resolver opens where you can keep either version or edit the merged result. Binary files cannot be merged and keep the cloud version. + +## Language Server + +Typst Desktop can use [`tinymist`](https://github.com/Myriad-Dreamin/tinymist) for hover documentation, go-to-definition, and richer diagnostics. It is not bundled — install it and make sure it is on your `PATH`: + +```bash +curl -L -o ~/.cargo/bin/tinymist \ + https://github.com/Myriad-Dreamin/tinymist/releases/latest/download/tinymist-linux-x64 \ + && chmod +x ~/.cargo/bin/tinymist +``` + +The editor header shows the language server status. Without `tinymist` the editor still has syntax highlighting, autocompletion, and compiler diagnostics. + +## Development + +The app compiles Typst from source, so clone the compiler into TypstDrive's `typst/` folder first — both projects share it: + +```bash +git clone https://github.com/typst/typst.git ../typstdrive/typst +``` + +Then: + +```bash +bun install +bun run tauri dev +``` + +To build a release bundle: + +```bash +bun run tauri build +``` + +### Layout + +| Path | Contents | +|---|---| +| `src/` | SvelteKit frontend. | +| `src/lib/components/` | Views, editor, modals. | +| `src/lib/ts/` | Tauri command bindings and app state. | +| `src-tauri/src/` | Rust backend. | +| `src-tauri/src/workspace.rs` | Workspace browsing and file access. | +| `src-tauri/src/compiler.rs` | Typst compilation and export. | +| `src-tauri/src/sync.rs` | TypstDrive sync and merging. | +| `src-tauri/src/db.rs` | Local SQLite storage. | diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..55f3723 --- /dev/null +++ b/bun.lock @@ -0,0 +1,449 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "typst-desktop", + "dependencies": { + "@codemirror/autocomplete": "^6.20.2", + "@codemirror/commands": "^6.10.3", + "@codemirror/language": "^6.10.8", + "@codemirror/legacy-modes": "^6.5.1", + "@codemirror/lint": "^6.9.6", + "@codemirror/lsp-client": "^6.2.4", + "@codemirror/state": "^6.6.0", + "@codemirror/view": "^6.43.0", + "@iconify/svelte": "^5.2.1", + "@lezer/highlight": "^1.2.1", + "@tauri-apps/api": "^2.11.1", + "@tauri-apps/plugin-dialog": "^2.4.1", + "@tauri-apps/plugin-opener": "^2.5.4", + "codemirror": "^6.0.2", + "codemirror-lang-typst": "^0.4.0", + }, + "devDependencies": { + "@sveltejs/adapter-static": "^3.0.10", + "@sveltejs/kit": "^2.70.0", + "@sveltejs/vite-plugin-svelte": "^5.1.1", + "@tailwindcss/vite": "^4.3.0", + "@tauri-apps/cli": "^2.11.4", + "svelte": "^5.56.6", + "svelte-check": "^4.7.3", + "tailwindcss": "^4.3.0", + "typescript": "~5.6.3", + "vite": "^6.4.3", + "vite-plugin-top-level-await": "^1.6.0", + "vite-plugin-wasm": "^3.6.0", + }, + }, + }, + "packages": { + "@codemirror/autocomplete": ["@codemirror/autocomplete@6.20.3", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0" } }, "sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g=="], + + "@codemirror/commands": ["@codemirror/commands@6.10.4", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.7.0", "@codemirror/view": "^6.27.0", "@lezer/common": "^1.1.0" } }, "sha512-Ryk9y9T0FFVF0cUGhAknveAyUOl/A1qReTFi+qPKtOh2Z9F4AUBz3XOrYD4ZEgZirdugVzHvd/2/Wcwy5OliTg=="], + + "@codemirror/language": ["@codemirror/language@6.12.4", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", "@lezer/common": "^1.5.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0", "style-mod": "^4.0.0" } }, "sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A=="], + + "@codemirror/legacy-modes": ["@codemirror/legacy-modes@6.5.3", "", { "dependencies": { "@codemirror/language": "^6.0.0" } }, "sha512-xCsmIzH78MyWkib9jlPaaun57XNkfbMIhagfaZVd0iLTqlpw3jXaIcbZm72MTmmn64eTZpBVNjbyYh+QXnxRsg=="], + + "@codemirror/lint": ["@codemirror/lint@6.9.7", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.42.0", "crelt": "^1.0.5" } }, "sha512-28/+iWLYxKxsvGYhSYL7zaCZqLz5+FFFDq9tVsvGv9kv8RY4fFAchJ5WX9M3YrrRlTIsECjsXPqeNgnSmNP2dg=="], + + "@codemirror/lsp-client": ["@codemirror/lsp-client@6.2.5", "", { "dependencies": { "@codemirror/autocomplete": "^6.20.0", "@codemirror/language": "^6.11.0", "@codemirror/lint": "^6.8.5", "@codemirror/state": "^6.5.2", "@codemirror/view": "^6.37.0", "@lezer/highlight": "^1.2.1", "marked": "^15.0.12", "vscode-languageserver-protocol": "^3.17.5" } }, "sha512-1EqhGRmCZOV7Me+rRuwwkTuvkNoD4Nz6UcE1yx5gdwTVTLD4D9xIy48MJc0LeBQGFLn/HNRW/pHmet4EAEkJFQ=="], + + "@codemirror/search": ["@codemirror/search@6.7.1", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.37.0", "crelt": "^1.0.5" } }, "sha512-uMe5UO6PamJtSHrXhhHOzSX3ReWtiJrva6GnPMwSOrZtiExb5X5eExhr2OUZQVvdxPsKpY3Ro2mFbQadpPWmHA=="], + + "@codemirror/state": ["@codemirror/state@6.7.1", "", { "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } }, "sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A=="], + + "@codemirror/view": ["@codemirror/view@6.43.6", "", { "dependencies": { "@codemirror/state": "^6.7.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-EVunGSYN1wz1p75WY1s3Xg7t3i8Yol0kGZGizNdX9BUFgMFILYVe8/u6EVpo7Ff5PwbZuILb4QAq7IZoKzIEQA=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], + + "@iconify/svelte": ["@iconify/svelte@5.2.2", "", { "dependencies": { "@iconify/types": "^2.0.0" }, "peerDependencies": { "svelte": ">5.0.0" } }, "sha512-XMXxD3nzH7yB68C3K4sNwzrJ1TBscODR0ZqCeNf0KGuEMCTSuCo0jHNDZ0o0iRXTylO41NSz/DWam/4atLG1yw=="], + + "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@lezer/common": ["@lezer/common@1.5.2", "", {}, "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ=="], + + "@lezer/highlight": ["@lezer/highlight@1.2.3", "", { "dependencies": { "@lezer/common": "^1.3.0" } }, "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g=="], + + "@lezer/lr": ["@lezer/lr@1.4.10", "", { "dependencies": { "@lezer/common": "^1.0.0" } }, "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A=="], + + "@marijn/find-cluster-break": ["@marijn/find-cluster-break@1.0.3", "", {}, "sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA=="], + + "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], + + "@rollup/plugin-virtual": ["@rollup/plugin-virtual@3.0.2", "", { "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-10monEYsBp3scM4/ND4LNH5Rxvh3e/cVeL3jWTgZ2SrQ+BmUoQcopVQvnaMcOnykb1VkxUFuDAN+0FnpTFRy2A=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.62.2", "", { "os": "android", "cpu": "arm" }, "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.62.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.62.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.62.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.62.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.62.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.62.2", "", { "os": "linux", "cpu": "arm" }, "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.62.2", "", { "os": "linux", "cpu": "arm" }, "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.62.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.62.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg=="], + + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.62.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.62.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.62.2", "", { "os": "linux", "cpu": "none" }, "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.62.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.62.2", "", { "os": "linux", "cpu": "x64" }, "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.62.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.62.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.62.2", "", { "os": "none", "cpu": "arm64" }, "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.62.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.62.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.62.2", "", { "os": "win32", "cpu": "x64" }, "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.62.2", "", { "os": "win32", "cpu": "x64" }, "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA=="], + + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + + "@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.11", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-LFuZUkjJ9iF7JZye/aG5XM0SFcQ5VyL0oVX4WJ9dc0Va3R3s0OauX1BESVCb+YN/ol8TAfqGDDAQsTG627Y5kw=="], + + "@sveltejs/adapter-static": ["@sveltejs/adapter-static@3.0.10", "", { "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "sha512-7D9lYFWJmB7zxZyTE/qxjksvMqzMuYrrsyh1f4AlZqeZeACPRySjbC3aFiY55wb1tWUaKOQG9PVbm74JcN2Iew=="], + + "@sveltejs/kit": ["@sveltejs/kit@2.70.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.9", "@types/cookie": "^0.6.0", "acorn": "^8.16.0", "cookie": "^0.6.0", "devalue": "^5.8.1", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "set-cookie-parser": "^3.0.0", "sirv": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": "^5.3.3 || ^6.0.0", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" }, "optionalPeers": ["@opentelemetry/api", "typescript"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-5pBnJwdNzxbrxp1TLK1NPMFF0Cx57iZUDKInznKcfifYR9m9poWfZI2Tfhw6BZIjYor5dXvcibt4EQgar3k6ww=="], + + "@sveltejs/load-config": ["@sveltejs/load-config@0.2.0", "", {}, "sha512-1LgZ/qUqSoq+QorD83lk2hka79Px0wXNW2q5V1nZlxGhQgw1jrsIbVz5YiCeucVLo4XvFLjXukUaQjIiqowkcg=="], + + "@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@5.1.1", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.1", "deepmerge": "^4.3.1", "kleur": "^4.1.5", "magic-string": "^0.30.17", "vitefu": "^1.0.6" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ=="], + + "@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@4.0.1", "", { "dependencies": { "debug": "^4.3.7" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^5.0.0", "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw=="], + + "@swc/core": ["@swc/core@1.15.43", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.27" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.15.43", "@swc/core-darwin-x64": "1.15.43", "@swc/core-linux-arm-gnueabihf": "1.15.43", "@swc/core-linux-arm64-gnu": "1.15.43", "@swc/core-linux-arm64-musl": "1.15.43", "@swc/core-linux-ppc64-gnu": "1.15.43", "@swc/core-linux-s390x-gnu": "1.15.43", "@swc/core-linux-x64-gnu": "1.15.43", "@swc/core-linux-x64-musl": "1.15.43", "@swc/core-win32-arm64-msvc": "1.15.43", "@swc/core-win32-ia32-msvc": "1.15.43", "@swc/core-win32-x64-msvc": "1.15.43" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-1CuKjFkPxIgGdeHVuNbkxmBxkcbdc08u0aiI43pFq6yY1tTVKmXT9hFEooyyKs/sJ3xf1GPHyEwTtk9Xl8dvQw=="], + + "@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.15.43", "", { "os": "darwin", "cpu": "arm64" }, "sha512-v1aVuvXdo/BHxJzco9V2xpHrvwWmhfS8t6gziY5wJxd+Z2h8AeJRnAwPD8itCDaGXVBwJ/CaKfxEzTkG0Va0OA=="], + + "@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.15.43", "", { "os": "darwin", "cpu": "x64" }, "sha512-lp3d4Lamc8dt5huYdGLSR+9hLxmfr1jb0l+4XXG2zPqZwYWRN9R0U2qYoTrggiU2RWW0oV9VbWM3kBnqIc2kdQ=="], + + "@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.15.43", "", { "os": "linux", "cpu": "arm" }, "sha512-JWTQQELtsG5GgphDrr/XqqmM2pDN3cZqbMS0Mrg+iTiXL3F74sn/S2IyYE/5u4h2KLkTf9qQ7dXyxsbx7YzkeA=="], + + "@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.15.43", "", { "os": "linux", "cpu": "arm64" }, "sha512-B4otJRdPWIsmiSBf0uG7Z/+vMWmkufjz5MmYxubwKuZazDW14Zd3symga1N62QR4RT+kEFeHEgsXfZGyn/w0hw=="], + + "@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.15.43", "", { "os": "linux", "cpu": "arm64" }, "sha512-6zB6OnpViBxYy4tgY3v2i6AZY9fwkcHZ032UOwtwUuW1d19sdT07qF0kZe6/3UR1tUaK6jjg2rmVcUIBCEYVjQ=="], + + "@swc/core-linux-ppc64-gnu": ["@swc/core-linux-ppc64-gnu@1.15.43", "", { "os": "linux", "cpu": "ppc64" }, "sha512-coxE1ZWdB3uSDVNoEtYNrRi/1epvckZx9cTJ8ICUxTMTxGk+yvQ/Twacp3ruZSaMPGCriUjP86C37VhaT6nyRg=="], + + "@swc/core-linux-s390x-gnu": ["@swc/core-linux-s390x-gnu@1.15.43", "", { "os": "linux", "cpu": "s390x" }, "sha512-lXfLhs+LpBsD5inuYx+YDH5WsPPBQ95KPUiy8P5wq9ob9xKDZFqwNfU2QW6bGO8NqRO/H9JQomTSt5Yyh+FGfA=="], + + "@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.15.43", "", { "os": "linux", "cpu": "x64" }, "sha512-07XnKwTmKy8TGOZG3D9fRnLWGynxPjwQnZLVmBFbo6F+7vHYzBIOuwXEhemrChBWb6yDNZsVCcMWCPX6FDD2xg=="], + + "@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.15.43", "", { "os": "linux", "cpu": "x64" }, "sha512-TJc+bsSIaBh+hZvZ5GRtW/K1bw66TJ9vsUwvVIsZdiWxU5ObLwZvfcnZ3UpgVfMnFibRes9uriJrQNBHEEogRQ=="], + + "@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.15.43", "", { "os": "win32", "cpu": "arm64" }, "sha512-jfd7s2/bUQYkOHLs+LWQNKZdmDa8+sufKLllhpWAhVQ2GDCwsHe3vR/j+OSiItZNtkzFuaawa3+SAKz9y5gYfw=="], + + "@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.15.43", "", { "os": "win32", "cpu": "ia32" }, "sha512-rLAE8JvucqEW1ZGohxPQrQWPBQeJG4+ypKbWfdlU/qmKScvCkxf9/Jxnzki1dkUQCQ7P5Enp13RlvqOlvx/32g=="], + + "@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.15.43", "", { "os": "win32", "cpu": "x64" }, "sha512-h8MLDHZcfIukwQWj03rIJZx1I0E81AYj2X7J/nGErG4nz+QAv6G1Z+peotvinL3lqpbo32tLYSMFo32/ySzxKg=="], + + "@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="], + + "@swc/types": ["@swc/types@0.1.27", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-K6h3iUlqeM946U4sXFYeahefR1YBbXJvko+hv8WS8/0BNJ4OHiHRywMnQUJCqkR7Y9+hqQ1TvEpiKqUhz7NEFg=="], + + "@swc/wasm": ["@swc/wasm@1.15.43", "", {}, "sha512-jYqeckrzZGAU+9OSfmL15MWfhkKWRCC8QMssL/MZu/MaIP76mU3VHjzqxlwKIz9DOSR/9jCqi1+QlWE0ILNehA=="], + + "@tailwindcss/node": ["@tailwindcss/node@4.3.3", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.24.1", "jiti": "^2.7.0", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.3" } }, "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg=="], + + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.3.3", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.3", "@tailwindcss/oxide-darwin-arm64": "4.3.3", "@tailwindcss/oxide-darwin-x64": "4.3.3", "@tailwindcss/oxide-freebsd-x64": "4.3.3", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", "@tailwindcss/oxide-linux-x64-musl": "4.3.3", "@tailwindcss/oxide-wasm32-wasi": "4.3.3", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" } }, "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA=="], + + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.3.3", "", { "os": "android", "cpu": "arm64" }, "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw=="], + + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw=="], + + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw=="], + + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.3.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw=="], + + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3", "", { "os": "linux", "cpu": "arm" }, "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ=="], + + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w=="], + + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA=="], + + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w=="], + + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img=="], + + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.3.3", "", { "dependencies": { "@emnapi/core": "^1.11.1", "@emnapi/runtime": "^1.11.1", "@emnapi/wasi-threads": "^1.2.2", "@napi-rs/wasm-runtime": "^1.1.4", "@tybys/wasm-util": "^0.10.2", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ=="], + + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.3.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ=="], + + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.3.3", "", { "os": "win32", "cpu": "x64" }, "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw=="], + + "@tailwindcss/vite": ["@tailwindcss/vite@4.3.3", "", { "dependencies": { "@tailwindcss/node": "4.3.3", "@tailwindcss/oxide": "4.3.3", "tailwindcss": "4.3.3" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw=="], + + "@tauri-apps/api": ["@tauri-apps/api@2.11.1", "", {}, "sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA=="], + + "@tauri-apps/cli": ["@tauri-apps/cli@2.11.4", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.11.4", "@tauri-apps/cli-darwin-x64": "2.11.4", "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.4", "@tauri-apps/cli-linux-arm64-gnu": "2.11.4", "@tauri-apps/cli-linux-arm64-musl": "2.11.4", "@tauri-apps/cli-linux-riscv64-gnu": "2.11.4", "@tauri-apps/cli-linux-x64-gnu": "2.11.4", "@tauri-apps/cli-linux-x64-musl": "2.11.4", "@tauri-apps/cli-win32-arm64-msvc": "2.11.4", "@tauri-apps/cli-win32-ia32-msvc": "2.11.4", "@tauri-apps/cli-win32-x64-msvc": "2.11.4" }, "bin": { "tauri": "tauri.js" } }, "sha512-R8xGtMpwyetawSqm9kYOuMmEqkhUbvcUy8n0aNXIxollKBLESUu5f4Fx+64hgASYm1H+jSWq6jCW6zqTnH6hqQ=="], + + "@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.11.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-1ryOF3ZhpZ/nemHV5zVwBQBz9jDGKmKPvWPADOhc83ig0P4bMc2iER4NbC6r9sjeIZ6RVQ4g3RZIYvezhcl4TQ=="], + + "@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.11.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-uFsGQAAfuyz1k/yGLmkWfkBlgKAqZfxqlHmLWx81QU27RJWfmbNHCIq8T8w1e+VClleIuZUjpHWfoE4E3DLo3A=="], + + "@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.11.4", "", { "os": "linux", "cpu": "arm" }, "sha512-IaHZn5CdBL21oUmjiVOS1ctw6Ip1O0pjp70FwOWmYz1myWe0SY96ZIj2FYf7pT0m8bI2h/hrs5ZbEXXh44/MkQ=="], + + "@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.11.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-N41/ukTRVe6XSuUTESuFdGeOW2i7k62tK+6gHK5Kd5/q5RPvvi19GaWAVPPb9u95HSGmTChSolBfzynUsssFaA=="], + + "@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.11.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v277UnT/fB64xAfSroL5N3Km3tLmvATWqJJw/wRI+g6o+HkeD0slyE7gOhNs1MbjE41R7bQOTxMVoL3aomUJmw=="], + + "@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.11.4", "", { "os": "linux", "cpu": "none" }, "sha512-qqgNkQ2u1yZHxjhxsZaxUtRDW8dIqIYm33rx/mzwQv0SfY9x1B+iraj8vWeFiXjjSVVhEMepXSOts1TqPzvXNQ=="], + + "@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.11.4", "", { "os": "linux", "cpu": "x64" }, "sha512-2VRNWl84FOH0m2giiDkO2h0QXlcMJeX+zJDpI5kDIQAx6s+geF3v48F4DXfJez4GS/FdoDGnPnw1C2iYGbQ7bQ=="], + + "@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.11.4", "", { "os": "linux", "cpu": "x64" }, "sha512-o9GyhYor/nc7xarmwDE3ka2szuW3uuZzXjHWh64Q8YX5AtSgxdQkFWzrY4O8KiGtVNvFBI14H3Q49Qj5TOIP/A=="], + + "@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.11.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-ld5Ehb598m0VkYyylRPNeCFsBe/km0jxis6KgMpl3IGY6I/i1RwQXO05I1AsXUXO2WC6AvB/Lw4qTf/asiuEiQ=="], + + "@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.11.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-12Hxi0XX/H5VFxO/bGgHkFWhml9VMgEOu9CidjeCeTNQ1l6fpUlbiGgSP7CLI3PFtW9/FfbeHieZ+kyWK5H7CA=="], + + "@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.11.4", "", { "os": "win32", "cpu": "x64" }, "sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw=="], + + "@tauri-apps/plugin-dialog": ["@tauri-apps/plugin-dialog@2.7.1", "", { "dependencies": { "@tauri-apps/api": "^2.11.0" } }, "sha512-OK1UBXYt+ojcmxMktzzuyonYIFta8CmAASpX+CA+DTGK24KlHjhYI6x2iOJ/TjZF4N7/ACK1oFmEOjIY9IhzOQ=="], + + "@tauri-apps/plugin-opener": ["@tauri-apps/plugin-opener@2.5.4", "", { "dependencies": { "@tauri-apps/api": "^2.11.0" } }, "sha512-1HnPkb+AmgO29HBazm4uPLKB+r7zzcTBW1d0fyYp1uP+jwtpoiNDGKMMzz58SFp49nOIrxdE3aUJtT57lfO9CQ=="], + + "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="], + + "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], + + "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="], + + "acorn": ["acorn@8.17.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg=="], + + "aria-query": ["aria-query@5.3.1", "", {}, "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g=="], + + "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], + + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + + "codemirror": ["codemirror@6.0.2", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/commands": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/lint": "^6.0.0", "@codemirror/search": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0" } }, "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw=="], + + "codemirror-lang-typst": ["codemirror-lang-typst@0.4.0", "", { "dependencies": { "@codemirror/language": "^6.11.2", "@codemirror/state": "^6.5.2", "@codemirror/view": "^6.38.1", "@lezer/common": "^1.2.3", "@lezer/highlight": "^1.2.1" } }, "sha512-jpHz5qQRC3LE48JH+C24qZJAEAhjqRzWA4MFodPaxriz7UwLVuTLCQ672rdDx9ziObBQ2BvHaRIm5/Upz4KoBQ=="], + + "cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="], + + "crelt": ["crelt@1.0.7", "", {}, "sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], + + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "devalue": ["devalue@5.8.1", "", {}, "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw=="], + + "enhanced-resolve": ["enhanced-resolve@5.24.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-rpsZEGT1jFuve6QlpyRp9ckQ+kN61hvF9BzCPyMdaKTm8UJce96KBn3sorXOFXlzjPrs3Vc4T1NsSroZ3PxlFw=="], + + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], + + "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="], + + "esrap": ["esrap@2.2.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" }, "peerDependencies": { "@typescript-eslint/types": "^8.2.0" }, "optionalPeers": ["@typescript-eslint/types"] }, "sha512-m8jH5hZgJE2RRUK/jjkGPcJEDAV+dYnZYFkosQaPTcE+Yw4xynXHOo6FUdwaWBtdR3b1MMa7wEDTSHeR2VWsGA=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="], + + "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], + + "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], + + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], + + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], + + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], + + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], + + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], + + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], + + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], + + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], + + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], + + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], + + "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="], + + "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], + + "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "nanoid": ["nanoid@3.3.16", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.5", "", {}, "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A=="], + + "postcss": ["postcss@8.5.19", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ=="], + + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + + "rollup": ["rollup@4.62.2", "", { "dependencies": { "@types/estree": "1.0.9" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.62.2", "@rollup/rollup-android-arm64": "4.62.2", "@rollup/rollup-darwin-arm64": "4.62.2", "@rollup/rollup-darwin-x64": "4.62.2", "@rollup/rollup-freebsd-arm64": "4.62.2", "@rollup/rollup-freebsd-x64": "4.62.2", "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", "@rollup/rollup-linux-arm-musleabihf": "4.62.2", "@rollup/rollup-linux-arm64-gnu": "4.62.2", "@rollup/rollup-linux-arm64-musl": "4.62.2", "@rollup/rollup-linux-loong64-gnu": "4.62.2", "@rollup/rollup-linux-loong64-musl": "4.62.2", "@rollup/rollup-linux-ppc64-gnu": "4.62.2", "@rollup/rollup-linux-ppc64-musl": "4.62.2", "@rollup/rollup-linux-riscv64-gnu": "4.62.2", "@rollup/rollup-linux-riscv64-musl": "4.62.2", "@rollup/rollup-linux-s390x-gnu": "4.62.2", "@rollup/rollup-linux-x64-gnu": "4.62.2", "@rollup/rollup-linux-x64-musl": "4.62.2", "@rollup/rollup-openbsd-x64": "4.62.2", "@rollup/rollup-openharmony-arm64": "4.62.2", "@rollup/rollup-win32-arm64-msvc": "4.62.2", "@rollup/rollup-win32-ia32-msvc": "4.62.2", "@rollup/rollup-win32-x64-gnu": "4.62.2", "@rollup/rollup-win32-x64-msvc": "4.62.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA=="], + + "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], + + "set-cookie-parser": ["set-cookie-parser@3.1.2", "", {}, "sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw=="], + + "sirv": ["sirv@3.0.2", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "style-mod": ["style-mod@4.1.3", "", {}, "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ=="], + + "svelte": ["svelte@5.56.6", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.10", "@types/estree": "^1.0.5", "@types/trusted-types": "^2.0.7", "acorn": "^8.12.1", "aria-query": "5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.8.1", "esm-env": "^1.2.1", "esrap": "^2.2.12", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-p4HDLDogGHKRKCrgckQHNs5PEfXkju6JI5jTywueaKJI5hAdjPohEhRtQ0M1SWC/+TA73SPln+r7srr+7e4nZA=="], + + "svelte-check": ["svelte-check@4.7.3", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "@sveltejs/load-config": "^0.2.0", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-DHdTCGX62R0fCxBEaT+USdASAnoaRBaaNczkRJl0K7o3WyoCeVUbVxo6fKqpOll/B+WMWCsiFK0eFrJSNBKZIg=="], + + "tailwindcss": ["tailwindcss@4.3.3", "", {}, "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ=="], + + "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], + + "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], + + "totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="], + + "typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="], + + "uuid": ["uuid@10.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ=="], + + "vite": ["vite@6.4.3", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A=="], + + "vite-plugin-top-level-await": ["vite-plugin-top-level-await@1.6.0", "", { "dependencies": { "@rollup/plugin-virtual": "^3.0.2", "@swc/core": "^1.12.14", "@swc/wasm": "^1.12.14", "uuid": "10.0.0" }, "peerDependencies": { "vite": ">=2.8" } }, "sha512-bNhUreLamTIkoulCR9aDXbTbhLk6n1YE8NJUTTxl5RYskNRtzOR0ASzSjBVRtNdjIfngDXo11qOsybGLNsrdww=="], + + "vite-plugin-wasm": ["vite-plugin-wasm@3.6.0", "", { "peerDependencies": { "vite": "^2 || ^3 || ^4 || ^5 || ^6 || ^7 || ^8" } }, "sha512-mL/QPziiIA4RAA6DkaZZzOstdwbW5jO4Vz7Zenj0wieKWBlNvIvX5L5ljum9lcUX0ShNfBgCNLKTjNkRVVqcsw=="], + + "vitefu": ["vitefu@1.1.3", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["vite"] }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="], + + "vscode-jsonrpc": ["vscode-jsonrpc@9.0.1", "", {}, "sha512-rfuA6T75H6m5EkbhtEPzre9pT0HPcDI2MMy4+nPFIBks5J8JBAUHD4tRYSgaBOijIEC7SRkC1kKyXTLqbmh9jw=="], + + "vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.18.2", "", { "dependencies": { "vscode-jsonrpc": "9.0.1", "vscode-languageserver-types": "3.18.0" } }, "sha512-XRyDbT0Pp3sSNti3JmxVEUMySWCSi1hhM+/KUlCy1hV1zmrqpM1OwO12EAki8blhmLuIMpaJrYbo0OzGVfK2Qg=="], + + "vscode-languageserver-types": ["vscode-languageserver-types@3.18.0", "", {}, "sha512-8TsGPNMIMiiBdkORgRSvLjuiEIiAFtO+KssmYWxQ+uSVvlf7RjK8YKCOjPzZ+YA04jXEV7+7LvkSmHkhpNS99g=="], + + "w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="], + + "zimmerframe": ["zimmerframe@1.1.4", "", {}, "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA=="], + + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="], + + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.6", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg=="], + + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg=="], + + "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..8492b70 --- /dev/null +++ b/package.json @@ -0,0 +1,46 @@ +{ + "name": "typst-desktop", + "version": "0.1.0", + "description": "", + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "tauri": "tauri" + }, + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.20.2", + "@codemirror/commands": "^6.10.3", + "@codemirror/language": "^6.10.8", + "@codemirror/legacy-modes": "^6.5.1", + "@codemirror/lint": "^6.9.6", + "@codemirror/lsp-client": "^6.2.4", + "@codemirror/state": "^6.6.0", + "@codemirror/view": "^6.43.0", + "@iconify/svelte": "^5.2.1", + "@lezer/highlight": "^1.2.1", + "@tauri-apps/api": "^2.11.1", + "@tauri-apps/plugin-dialog": "^2.4.1", + "@tauri-apps/plugin-opener": "^2.5.4", + "codemirror": "^6.0.2", + "codemirror-lang-typst": "^0.4.0" + }, + "devDependencies": { + "@sveltejs/adapter-static": "^3.0.10", + "@tailwindcss/vite": "^4.3.0", + "tailwindcss": "^4.3.0", + "@sveltejs/kit": "^2.70.0", + "@sveltejs/vite-plugin-svelte": "^5.1.1", + "svelte": "^5.56.6", + "svelte-check": "^4.7.3", + "typescript": "~5.6.3", + "vite": "^6.4.3", + "vite-plugin-wasm": "^3.6.0", + "vite-plugin-top-level-await": "^1.6.0", + "@tauri-apps/cli": "^2.11.4" + } +} diff --git a/src-tauri/.gitignore b/src-tauri/.gitignore new file mode 100644 index 0000000..b21bd68 --- /dev/null +++ b/src-tauri/.gitignore @@ -0,0 +1,7 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Generated by Tauri +# will have schema files for capabilities auto-completion +/gen/schemas diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock new file mode 100644 index 0000000..da3396f --- /dev/null +++ b/src-tauri/Cargo.lock @@ -0,0 +1,7521 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ar_archive_writer" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4087686b4b0a3427190bae57a1d9a478dbb2d40c5dc1bd6e2b6d797913bdd348" +dependencies = [ + "object", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "async-signal" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "atk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" +dependencies = [ + "atk-sys", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "az" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "biblatex" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d0c374feba1b9a59042a7c1cf00ce7c34b977b9134fe7c42b08e5183729f66" +dependencies = [ + "paste", + "roman-numerals-rs", + "strum", + "unic-langid", + "unicode-normalization", + "unscanny", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +dependencies = [ + "serde_core", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + +[[package]] +name = "blocking" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "brotli" +version = "8.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + +[[package]] +name = "bytemuck" +version = "1.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6aedf8ae72766347502cf3cb4f41cf5e9cc37d28bee90f1fdaaae15f9cf9424" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65693059b6b9c588b9f62fed1cedbf0a8b805631457ea162d68f0de186f3de5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +dependencies = [ + "serde", +] + +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags 2.13.1", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror 1.0.69", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "camino" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2d30e4173c4026932d51d31d6b0613b1fd3014bf3f9f8943d4ba139c437ba0" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "cargo_toml" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" +dependencies = [ + "serde", + "toml 0.9.12+spec-1.1.0", +] + +[[package]] +name = "cc" +version = "1.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chinese-number" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e964125508474a83c95eb935697abbeb446ff4e9d62c71ce880e3986d1c606b" +dependencies = [ + "chinese-variant", + "enum-ordinalize", + "num-bigint", + "num-traits", +] + +[[package]] +name = "chinese-variant" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d1275808335c5583ea45a4141d631dafcb36b79fa8a5e10b00e356b6af3e08a" + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link 0.2.1", +] + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "citationberg" +version = "0.6.1" +source = "git+https://github.com/typst/citationberg?rev=0999ab7#0999ab79842d79c7aae665cf1c6eece5a4b9ef2e" +dependencies = [ + "quick-xml 0.38.4", + "serde", +] + +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.18", +] + +[[package]] +name = "codex" +version = "0.2.0" +source = "git+https://github.com/typst/codex?rev=0426b6a#0426b6a97414064ad31d0b97d822566fe9df8b65" +dependencies = [ + "chinese-number", +] + +[[package]] +name = "color" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ec7c5eb7a16992b1904d76c517d170ab353b0e0b3d5a0c81a8a0cd1037893cf" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "comemo" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c963350b2b08aa4b725d7802593245380ab53dacfedcaa971385fc33306c0d4" +dependencies = [ + "comemo-macros", + "parking_lot", + "rustc-hash", + "siphasher", + "slab", +] + +[[package]] +name = "comemo-macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3c400139ba1389ef9e20ad2d87cda68b437a66483aa0da616bdf2cea7413853" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" +dependencies = [ + "bitflags 2.13.1", + "core-foundation", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.13.1", + "core-foundation", + "libc", +] + +[[package]] +name = "core_maths" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" +dependencies = [ + "libm", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "csv" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde_core", +] + +[[package]] +name = "csv-core" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +dependencies = [ + "memchr", +] + +[[package]] +name = "ctor" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98" +dependencies = [ + "ctor-proc-macro", + "dtor", +] + +[[package]] +name = "ctor-proc-macro" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "data-url" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" + +[[package]] +name = "dbus" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e" +dependencies = [ + "libc", + "libdbus-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "serde_core", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.119", +] + +[[package]] +name = "diffy" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b545b8c50194bdd008283985ab0b31dba153cfd5b3066a92770634fbc0d7d291" +dependencies = [ + "nu-ansi-term", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.13.1", + "block2", + "libc", + "objc2", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "dlopen2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "dom_query" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89" +dependencies = [ + "bit-set", + "cssparser", + "foldhash", + "html5ever", + "precomputed-hash", + "selectors", + "tendril", +] + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" +dependencies = [ + "serde", +] + +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dtor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "ecow" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78e4f79b296fbaab6ce2e22d52cb4c7f010fe0ebe7a32e34fa25885fd797bd02" +dependencies = [ + "serde", +] + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "embed-resource" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbfdaacccebec3b28e4866b8973543c7647797db5ada1bdab552e48fe665fbbd" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml 1.1.3+spec-1.1.0", + "vswhom", + "winreg", +] + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "endi" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" + +[[package]] +name = "enum-ordinalize" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07f808d588c10e464ea6f7d3eaed500049eff30aaac103460f61828c2d65b3eb" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e528e2d34ba8a67a1a650b86beae8ef69fc5fdb638016f386b973226590432" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "env_proxy" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a5019be18538406a43b5419a5501461f0c8b49ea7dfda0cfc32f4e51fc44be1" +dependencies = [ + "log", + "url", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "euclid" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" +dependencies = [ + "num-traits", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "fancy-regex" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f" +dependencies = [ + "bit-set", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "fast-srgb8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "fearless_simd" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97b65636e5b9ef369943878ac74335ba1c55c1cb6adbf1e2c293c624248d693" + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "font-types" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b38ad915f6dadd993ced50848a8291a543bd41ca62bc10740d5e64e2ab4cfd7" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "fontconfig-parser" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646" +dependencies = [ + "roxmltree 0.20.0", +] + +[[package]] +name = "fontdb" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2", + "slotmap", + "tinyvec", + "ttf-parser", +] + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" + +[[package]] +name = "futures-executor" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "futures-sink" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307" + +[[package]] +name = "futures-task" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" + +[[package]] +name = "futures-util" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "gdk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" +dependencies = [ + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +dependencies = [ + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", + "once_cell", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkx11" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" +dependencies = [ + "gdk", + "gdkx11-sys", + "gio", + "glib", + "libc", + "x11", +] + +[[package]] +name = "gdkx11-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps", + "x11", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + +[[package]] +name = "gif" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "gio" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "glib" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +dependencies = [ + "bitflags 2.13.1", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "glib-macros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate 2.0.2", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "glidesort" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2e102e6eb644d3e0b186fc161e4460417880a0a0b87d235f2e5b8fb30f2e9e0" + +[[package]] +name = "glifo" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d99fc21d493812643aae86d53b7bbd02f376434a90317e8a790bc209fdd6605e" +dependencies = [ + "bytemuck", + "foldhash", + "hashbrown 0.17.1", + "log", + "peniko", + "png 0.18.1", + "skrifa", + "smallvec", + "vello_common 0.0.9", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" +dependencies = [ + "atk", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk3-macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "guillotiere" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b17e70c989c36bad147b27a58d148c0741c51448aa5653436547323e524d0ab" +dependencies = [ + "euclid", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "hayagriva" +version = "0.9.1" +source = "git+https://github.com/typst/hayagriva?rev=292b880#292b88010d75e5fea8c8ff41fad250b2cd4d9a9a" +dependencies = [ + "biblatex", + "ciborium", + "citationberg", + "indexmap 2.14.0", + "paste", + "roman-numerals-rs", + "serde", + "serde_yaml", + "thiserror 2.0.18", + "unic-langid", + "unicode-segmentation", + "unscanny", + "url", +] + +[[package]] +name = "hayro" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4caa128ab87fd48ffb7490617cf93f77f606820dffbc9fd9ef6ab0ed077f56d" +dependencies = [ + "bytemuck", + "hayro-interpret", + "image", + "kurbo", + "pic-scale", + "vello_cpu", +] + +[[package]] +name = "hayro-ccitt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f4d0e94ddd48749f06bbe4e5389fb9799a0c45bcaf00495042076ef05e3241a" + +[[package]] +name = "hayro-cmap" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d285dc30731c8485de5fa732fbdf2b3affdf01e4da7c2135022ca6fa664bf6" +dependencies = [ + "hayro-postscript", +] + +[[package]] +name = "hayro-interpret" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2613d0406898995042d0794c4245b2f2fba1246490c8ac593769bba6551129d" +dependencies = [ + "bitflags 2.13.1", + "hayro-cmap", + "hayro-syntax", + "kurbo", + "moxcms", + "phf", + "rustc-hash", + "siphasher", + "skrifa", + "smallvec", + "yoke 0.8.3", +] + +[[package]] +name = "hayro-jbig2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69374b3668dd45aeb3d3145cda68f2c7b4f223aaa2511e67d076f1c7d741388d" +dependencies = [ + "fearless_simd", + "hayro-ccitt", +] + +[[package]] +name = "hayro-jpeg2000" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ab947623ef4ccaa7acf0579edf7cbb5a73838e3839a7be73335e522f433a1" +dependencies = [ + "fearless_simd", +] + +[[package]] +name = "hayro-postscript" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "885c5ef0654933139a9b9546fc2c69e18d37f38aa2520f079092b1be18f1fcaa" + +[[package]] +name = "hayro-svg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7434c89e920d84e077214a29e69b462a6518754610f732f1124af3948410cb8c" +dependencies = [ + "base64 0.22.1", + "hayro-interpret", + "image", + "kurbo", + "siphasher", + "xmlwriter", +] + +[[package]] +name = "hayro-syntax" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0edeafd70aa2db743de8ede8637d07ec87db05efe69cde371d03f1b185fcef27" +dependencies = [ + "flate2", + "hayro-ccitt", + "hayro-jbig2", + "hayro-jpeg2000", + "memchr", + "rustc-hash", + "smallvec", + "zune-jpeg", +] + +[[package]] +name = "hayro-write" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0b3db92c4917aad24ff30d61413a9a7509ae88b27aee1ae34eff881e1d2723a" +dependencies = [ + "flate2", + "hayro-syntax", + "pdf-writer", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "html5ever" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" +dependencies = [ + "log", + "markup5ever", +] + +[[package]] +name = "http" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "hypher" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef68590049bab63a464eee1a1158ac04c6f6613a546d8d90f78636b8b94f171" + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ico" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" +dependencies = [ + "byteorder", + "png 0.17.16", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "serde", + "yoke 0.7.5", + "zerofrom", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke 0.8.3", + "zerofrom", + "zerovec 0.11.6", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap 0.8.2", + "tinystr 0.8.3", + "writeable 0.6.3", + "zerovec 0.11.6", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap 0.7.5", + "tinystr 0.7.6", + "writeable 0.5.5", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider 1.5.0", + "tinystr 0.7.6", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections 2.2.0", + "icu_normalizer_data", + "icu_properties 2.2.0", + "icu_provider 2.2.0", + "smallvec", + "zerovec 0.11.6", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections 1.5.0", + "icu_locid_transform", + "icu_properties_data 1.5.1", + "icu_provider 1.5.0", + "serde", + "tinystr 0.7.6", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections 2.2.0", + "icu_locale_core", + "icu_properties_data 2.2.0", + "icu_provider 2.2.0", + "zerotrie 0.2.4", + "zerovec 0.11.6", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "postcard", + "serde", + "stable_deref_trait", + "tinystr 0.7.6", + "writeable 0.5.5", + "yoke 0.7.5", + "zerofrom", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable 0.6.3", + "yoke 0.8.3", + "zerofrom", + "zerotrie 0.2.4", + "zerovec 0.11.6", +] + +[[package]] +name = "icu_provider_adapters" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6324dfd08348a8e0374a447ebd334044d766b1839bb8d5ccf2482a99a77c0bc" +dependencies = [ + "icu_locid", + "icu_locid_transform", + "icu_provider 1.5.0", + "tinystr 0.7.6", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_provider_blob" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c24b98d1365f55d78186c205817631a4acf08d7a45bdf5dc9dcf9c5d54dccf51" +dependencies = [ + "icu_provider 1.5.0", + "postcard", + "serde", + "writeable 0.5.5", + "zerotrie 0.1.3", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "icu_segmenter" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a717725612346ffc2d7b42c94b820db6908048f39434504cb130e8b46256b0de" +dependencies = [ + "core_maths", + "displaydoc", + "icu_collections 1.5.0", + "icu_locid", + "icu_provider 1.5.0", + "icu_segmenter_data", + "serde", + "utf8_iter", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_segmenter_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e52775179941363cc594e49ce99284d13d6948928d8e72c755f55e98caa1eb" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties 2.2.0", +] + +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "gif", + "image-webp", + "moxcms", + "num-traits", + "png 0.18.1", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imagesize" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "rayon", + "serde", + "serde_core", +] + +[[package]] +name = "infer" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +dependencies = [ + "cfb", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "javascriptcore-rs" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" +dependencies = [ + "bitflags 1.3.2", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "js-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "jsonptr" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "kamadak-exif" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1130d80c7374efad55a117d715a3af9368f0fa7a2c54573afc15a188cd984837" +dependencies = [ + "mutate_once", +] + +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.13.1", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "krilla" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27da593198b20eeba65caeb73c2bbeec3e53ab08fa549898312ce81c4fce5e33" +dependencies = [ + "base64 0.22.1", + "bumpalo", + "comemo", + "flate2", + "float-cmp", + "gif", + "hayro-write", + "image-webp", + "imagesize", + "indexmap 2.14.0", + "pdf-writer", + "png 0.18.1", + "rayon", + "rustc-hash", + "rustybuzz", + "siphasher", + "skrifa", + "smallvec", + "subsetter", + "tiny-skia-path", + "xmp-writer", + "yoke 0.8.3", + "zune-jpeg", +] + +[[package]] +name = "krilla-svg" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1237d7c37b16ca9fbc2e72dde13a10d321f9a44aceee35c062bc0a43bfc7ce16" +dependencies = [ + "flate2", + "fontdb", + "krilla", + "resvg", + "skrifa", + "smallvec", + "tiny-skia", + "usvg", +] + +[[package]] +name = "kurbo" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b60dfc32f652b926df6192e55525b16d186c69d47876c3ead4da5cc9f8450e2" +dependencies = [ + "arrayvec", + "euclid", + "polycool", + "smallvec", +] + +[[package]] +name = "libappindicator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" +dependencies = [ + "gtk-sys", + "libloading", + "once_cell", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libdbus-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" +dependencies = [ + "libc", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linebender_resource_handle" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "lipsum" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "636860251af8963cc40f6b4baadee105f02e21b28131d76eba8e40ce84ab8064" +dependencies = [ + "rand", + "rand_chacha", +] + +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +dependencies = [ + "serde", +] + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "markup5ever" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862" +dependencies = [ + "log", + "tendril", + "web_atoms", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memmap2" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "muda" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd04e60bc0b07438a6771710ee1698f98f6ebbc7f89b61264af1563b8aeb878" +dependencies = [ + "crossbeam-channel", + "dpi", + "gtk", + "keyboard-types", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "once_cell", + "png 0.18.1", + "serde", + "thiserror 2.0.18", + "windows-sys 0.61.2", +] + +[[package]] +name = "mutate_once" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d2233c9842d08cfe13f9eac96e207ca6a2ea10b80259ebe8ad0268be27d2af" + +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.13.1", + "jni-sys 0.3.1", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys 0.3.1", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", + "objc2-exception-helper", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.13.1", + "block2", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" +dependencies = [ + "bitflags 2.13.1", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.13.1", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.13.1", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-location" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.13.1", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-exception-helper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" +dependencies = [ + "cc", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.13.1", + "block2", + "libc", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.13.1", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.13.1", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags 2.13.1", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-location", + "objc2-core-text", + "objc2-foundation", + "objc2-quartz-core", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-web-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" +dependencies = [ + "bitflags 2.13.1", + "block2", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "open" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0b3d059e795d52b8a72fef45658620edd4d9c359b338564aa14391ffa511ed5" +dependencies = [ + "dunce", + "is-wsl", + "libc", +] + +[[package]] +name = "openssl" +version = "0.10.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" +dependencies = [ + "bitflags 2.13.1", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "palette" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +dependencies = [ + "approx", + "fast-srgb8", + "libm", + "palette_derive", +] + +[[package]] +name = "palette_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +dependencies = [ + "by_address", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pango" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +dependencies = [ + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link 0.2.1", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pdf-writer" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e456864a7a304047bff84977dc6fb162bd956475d40ba50b2dcecaada7f753" +dependencies = [ + "bitflags 2.13.1", + "itoa", + "memchr", + "ryu", +] + +[[package]] +name = "peniko" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "839c8299360d2e998bdb106dc0a6cd71dcc5f4df51df1b620361bf50e283cca6" +dependencies = [ + "bytemuck", + "color", + "kurbo", + "linebender_resource_handle", + "smallvec", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_codegen" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pic-scale" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "694e82ac1a7d35d78dc5fdc6763ffa7c0025a65d4fea3e53ba24fc89f216fc06" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "piper" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] +name = "pixglyph" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47945e80a49d08350e4a007ac4294c6498d23956c18ea5e6ff480dc93d31643c" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plist" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da1d65da6dd5d1e44199ac0f58712d241c0f439f80adea8924d832384087f85" +dependencies = [ + "base64 0.22.1", + "indexmap 2.14.0", + "quick-xml 0.41.0", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.13.1", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "polycool" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50596ddc09eb5ad5f75cacd40209568e66df71baf86e1499a0e99c4cff12a5a6" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "portable-atomic" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3" + +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec 0.11.6", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit 0.25.13+spec-1.1.0", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645dbe486e346d9b5de3ef16ede18c26e6c70ad97418f4874b8b1889d6e761ea" +dependencies = [ + "ar_archive_writer", + "cc", +] + +[[package]] +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quick-xml" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "read-fonts" +version = "0.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4ed38b89c2c77ff968c524145ad65fb010f38af5c7a224b53b81d47ac2daa81" +dependencies = [ + "bytemuck", + "font-types", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.1", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "reqwest" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", +] + +[[package]] +name = "resvg" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be183ad6a216aa96f33e4c8033b0988b8b3ea6fd2359d19af5bac4643fd8e81" +dependencies = [ + "gif", + "image-webp", + "log", + "pico-args", + "rgb", + "svgtypes", + "tiny-skia", + "usvg", + "zune-jpeg", +] + +[[package]] +name = "rfd" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672" +dependencies = [ + "block2", + "dispatch2", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "log", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.60.2", +] + +[[package]] +name = "rgb" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "roman-numerals-rs" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85cd47a33a4510b1424fe796498e174c6a9cf94e606460ef022a19f3e4ff85e" + +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + +[[package]] +name = "roxmltree" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb" +dependencies = [ + "memchr", +] + +[[package]] +name = "rusqlite" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" +dependencies = [ + "bitflags 2.13.1", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + +[[package]] +name = "rust_decimal" +version = "1.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be2a24f50780bc85f09cc6ac299bdf1424302742d77221106859c9d8b102126a" +dependencies = [ + "arrayvec", + "num-traits", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.13.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "rustybuzz" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" +dependencies = [ + "bitflags 2.13.1", + "bytemuck", + "core_maths", + "log", + "smallvec", + "ttf-parser", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", + "url", + "uuid", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.119", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.13.1", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "selectors" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" +dependencies = [ + "bitflags 2.13.1", + "cssparser", + "derive_more", + "log", + "new_debug_unreachable", + "phf", + "phf_codegen", + "precomputed-hash", + "rustc-hash", + "servo_arc", + "smallvec", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-untagged" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +dependencies = [ + "erased-serde", + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_with" +version = "3.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" +dependencies = [ + "base64 0.22.1", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.14.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "serialize-to-javascript" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" +dependencies = [ + "serde", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "servo_arc" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "simplecss" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" +dependencies = [ + "log", +] + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "skrifa" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c34617370ae968efb7161bb2beb517d9084659aae19e24b89e3db25b46e4564" +dependencies = [ + "bytemuck", + "read-fonts", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "softbuffer" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" +dependencies = [ + "bytemuck", + "js-sys", + "ndk", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "objc2-quartz-core", + "raw-window-handle", + "redox_syscall", + "tracing", + "wasm-bindgen", + "web-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "soup3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +dependencies = [ + "futures-channel", + "gio", + "glib", + "libc", + "soup3-sys", +] + +[[package]] +name = "soup3-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stacker" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "640c8cdd92b6b12f5bcb1803ca3bbf5ab96e5e6b6b96b9ab77dabe9e880b3190" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.61.2", +] + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] + +[[package]] +name = "string_cache" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "string_cache_codegen" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "subsetter" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38803281d1c23166c5ebcb455439a5d2afe711cc909cf88af72448c297756ad6" +dependencies = [ + "kurbo", + "rustc-hash", + "skrifa", + "write-fonts", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "svgtypes" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "695b5790b3131dafa99b3bbfd25a216edb3d216dad9ca208d4657bfb8f2abc3d" +dependencies = [ + "kurbo", + "siphasher", +] + +[[package]] +name = "swift-rs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "syntect" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "656b45c05d95a5704399aeef6bd0ddec7b2b3531b7c9e900abbf7c4d2190c925" +dependencies = [ + "bincode", + "fancy-regex", + "flate2", + "fnv", + "once_cell", + "plist", + "regex-syntax", + "serde", + "serde_derive", + "serde_json", + "thiserror 2.0.18", + "walkdir", + "yaml-rust", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml 0.8.2", + "version-compare", +] + +[[package]] +name = "tao" +version = "0.35.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9" +dependencies = [ + "bitflags 2.13.1", + "block2", + "core-foundation", + "core-graphics", + "crossbeam-channel", + "dbus", + "dispatch2", + "dlopen2", + "dpi", + "gdkwayland-sys", + "gdkx11-sys", + "gtk", + "jni", + "libc", + "log", + "ndk", + "ndk-sys", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "once_cell", + "parking_lot", + "percent-encoding", + "raw-window-handle", + "tao-macros", + "unicode-segmentation", + "url", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tauri" +version = "2.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "667b20e2726d572dea2de7370da16e188eb06008faf9a92fab7cdc46791190b5" +dependencies = [ + "anyhow", + "bytes", + "cookie", + "dirs", + "dunce", + "embed_plist", + "getrandom 0.3.4", + "glob", + "gtk", + "heck 0.5.0", + "http", + "jni", + "libc", + "log", + "mime", + "muda", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "percent-encoding", + "plist", + "raw-window-handle", + "reqwest", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "swift-rs", + "tauri-build", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils", + "thiserror 2.0.18", + "tokio", + "tray-icon", + "url", + "webkit2gtk", + "webview2-com", + "window-vibrancy", + "windows", +] + +[[package]] +name = "tauri-build" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc9ce40b16101cb6ea63d3e221567affd1c3a9205f95d7bc574941a10636b632" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs", + "glob", + "heck 0.5.0", + "json-patch", + "schemars 0.8.22", + "semver", + "serde", + "serde_json", + "tauri-utils", + "tauri-winres", + "walkdir", +] + +[[package]] +name = "tauri-codegen" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08279169ff42f8fc45a1dbc9dcae888893ba95288142e5880c59b93a26d2cfc5" +dependencies = [ + "base64 0.22.1", + "brotli", + "ico", + "json-patch", + "plist", + "png 0.17.16", + "proc-macro2", + "quote", + "semver", + "serde", + "serde_json", + "sha2", + "syn 2.0.119", + "tauri-utils", + "thiserror 2.0.18", + "time", + "url", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-macros" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", + "tauri-codegen", + "tauri-utils", +] + +[[package]] +name = "tauri-plugin" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74be5dd4bed9afbd145e5716b5fa2ec28cbc29c34ffa61c258c9273d896c8020" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri-utils", + "walkdir", +] + +[[package]] +name = "tauri-plugin-dialog" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65981abb771e74e571a38196c3baa11c459379164791eba0e67abc1a5fac9884" +dependencies = [ + "log", + "raw-window-handle", + "rfd", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror 2.0.18", + "url", +] + +[[package]] +name = "tauri-plugin-fs" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ecc274121aca0c036a2b42d1cbe83d368d348f54e0bb8a735c2b1548e8f371" +dependencies = [ + "anyhow", + "dunce", + "glob", + "log", + "objc2-foundation", + "percent-encoding", + "schemars 0.8.22", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "tauri-utils", + "thiserror 2.0.18", + "toml 1.1.3+spec-1.1.0", + "url", +] + +[[package]] +name = "tauri-plugin-opener" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17e1bea14edce6b793a04e2417e3fd924b9bc4faae83cdee7d714156cceeed29" +dependencies = [ + "dunce", + "glob", + "objc2-app-kit", + "objc2-foundation", + "open", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.18", + "url", + "windows", + "zbus", +] + +[[package]] +name = "tauri-runtime" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0b4bc95aed361b0019067d189a1174a603d460d0f6c72606512d59fc9c12ec8" +dependencies = [ + "cookie", + "dpi", + "gtk", + "http", + "jni", + "objc2", + "objc2-ui-kit", + "objc2-web-kit", + "raw-window-handle", + "serde", + "serde_json", + "tauri-utils", + "thiserror 2.0.18", + "url", + "webkit2gtk", + "webview2-com", + "windows", +] + +[[package]] +name = "tauri-runtime-wry" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e6fac707727b7a2f48e4ded90976324267371073edbb415ffb73bb0458d203f" +dependencies = [ + "gtk", + "http", + "jni", + "log", + "objc2", + "objc2-app-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "softbuffer", + "tao", + "tauri-runtime", + "tauri-utils", + "url", + "webkit2gtk", + "webview2-com", + "windows", + "wry", +] + +[[package]] +name = "tauri-utils" +version = "2.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887" +dependencies = [ + "anyhow", + "brotli", + "cargo_metadata", + "ctor", + "dom_query", + "dunce", + "glob", + "http", + "infer", + "json-patch", + "log", + "memchr", + "phf", + "plist", + "proc-macro2", + "quote", + "regex", + "schemars 0.8.22", + "semver", + "serde", + "serde-untagged", + "serde_json", + "serde_with", + "swift-rs", + "thiserror 2.0.18", + "toml 1.1.3+spec-1.1.0", + "url", + "urlpattern", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-winres" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6" +dependencies = [ + "dunce", + "embed-resource", + "toml 1.1.3+spec-1.1.0", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "tendril" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08" +dependencies = [ + "new_debug_unreachable", +] + +[[package]] +name = "thin-vec" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0f7e269b48f0a7dd0146680fa24b50cc67fc0373f086a5b2f99bd084639b482" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "time" +version = "0.3.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-skia" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47ffee5eaaf5527f630fb0e356b90ebdec84d5d18d937c5e440350f88c5a91ea" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "png 0.18.1", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca365c3faccca67d06593c5980fa6c57687de727a03131735bb85f01fdeeb9" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "serde", + "zerovec 0.10.4", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "serde_core", + "zerovec 0.11.6", +] + +[[package]] +name = "tinyvec" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d988bcd52dbe076d3d46903332f58c912b87a2c49b1428419a5845154762ffee" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap 2.14.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c96ecdfa941c8fc4fcaed14f99ada8ebed502eef533015095a07e3301d4c3c" +dependencies = [ + "indexmap 2.14.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.4", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap 2.14.0", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.25.13+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.4", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow 1.0.4", +] + +[[package]] +name = "toml_writer" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags 2.13.1", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tray-icon" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65ba1e5f6b9ef9fd87e21b9c6f351554dbd717960089168fcfdef854686961dc" +dependencies = [ + "crossbeam-channel", + "dirs", + "libappindicator", + "muda", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "once_cell", + "png 0.18.1", + "serde", + "thiserror 2.0.18", + "windows-sys 0.61.2", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +dependencies = [ + "core_maths", +] + +[[package]] +name = "two-face" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e51b6e60e545cfdae5a4639ff423818f52372211a8d9a3e892b4b0761f76b2" +dependencies = [ + "serde", + "serde_derive", + "syntect", +] + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "typst" +version = "0.14.2" +dependencies = [ + "arrayvec", + "comemo", + "ecow", + "rustc-hash", + "typst-eval", + "typst-html", + "typst-layout", + "typst-library", + "typst-macros", + "typst-realize", + "typst-syntax", + "typst-timing", + "typst-utils", +] + +[[package]] +name = "typst-assets" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5613cb719a6222fe9b74027c3625d107767ec187bff26b8fc931cf58942c834f" + +[[package]] +name = "typst-assets" +version = "0.14.2" +source = "git+https://github.com/typst/typst-assets?rev=3284e80#3284e80cc102b402e4e3db1aa071f1eadae5e7ca" +dependencies = [ + "bitflags 2.13.1", +] + +[[package]] +name = "typst-desktop" +version = "0.1.0" +dependencies = [ + "base64 0.22.1", + "chrono", + "diffy", + "rusqlite", + "serde", + "serde_json", + "sha2", + "tauri", + "tauri-build", + "tauri-plugin-dialog", + "tauri-plugin-opener", + "typst", + "typst-assets 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", + "typst-html", + "typst-kit", + "typst-layout", + "typst-pdf", + "typst-render", + "typst-svg", + "ureq", + "walkdir", +] + +[[package]] +name = "typst-eval" +version = "0.14.2" +dependencies = [ + "comemo", + "ecow", + "indexmap 2.14.0", + "rustc-hash", + "stacker", + "toml 0.8.2", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-segmentation", +] + +[[package]] +name = "typst-html" +version = "0.14.2" +dependencies = [ + "az", + "bumpalo", + "comemo", + "ecow", + "palette", + "rustc-hash", + "time", + "typst-assets 0.14.2 (git+https://github.com/typst/typst-assets?rev=3284e80)", + "typst-library", + "typst-macros", + "typst-svg", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-math-class", +] + +[[package]] +name = "typst-kit" +version = "0.14.2" +dependencies = [ + "dirs", + "ecow", + "env_proxy", + "fastrand", + "flate2", + "native-tls", + "once_cell", + "openssl", + "parking_lot", + "rustc-hash", + "serde", + "serde_json", + "tar", + "typst-assets 0.14.2 (git+https://github.com/typst/typst-assets?rev=3284e80)", + "typst-library", + "typst-syntax", + "typst-timing", + "typst-utils", + "ureq", + "url", +] + +[[package]] +name = "typst-layout" +version = "0.14.2" +dependencies = [ + "az", + "bumpalo", + "codex", + "comemo", + "ecow", + "either", + "hypher", + "icu_properties 1.5.1", + "icu_provider 1.5.0", + "icu_provider_adapters", + "icu_provider_blob", + "icu_segmenter", + "kurbo", + "libm", + "memchr", + "rustc-hash", + "rustybuzz", + "smallvec", + "ttf-parser", + "typst-assets 0.14.2 (git+https://github.com/typst/typst-assets?rev=3284e80)", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-bidi", + "unicode-math-class", + "unicode-script", + "unicode-segmentation", +] + +[[package]] +name = "typst-library" +version = "0.14.2" +dependencies = [ + "arrayvec", + "az", + "bitflags 2.13.1", + "bumpalo", + "ciborium", + "codex", + "comemo", + "csv", + "ecow", + "either", + "flate2", + "fontdb", + "glidesort", + "hayagriva", + "hayro-syntax", + "icu_properties 1.5.1", + "icu_provider 1.5.0", + "icu_provider_blob", + "image", + "indexmap 2.14.0", + "kamadak-exif", + "kurbo", + "libm", + "lipsum", + "memchr", + "moxcms", + "palette", + "phf", + "png 0.18.1", + "rayon", + "regex", + "regex-syntax", + "roxmltree 0.21.1", + "rust_decimal", + "rustc-hash", + "rustybuzz", + "serde", + "serde_json", + "serde_yaml", + "siphasher", + "smallvec", + "syntect", + "time", + "toml 0.8.2", + "ttf-parser", + "two-face", + "typed-arena", + "typst-assets 0.14.2 (git+https://github.com/typst/typst-assets?rev=3284e80)", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-math-class", + "unicode-normalization", + "unicode-segmentation", + "unscanny", + "usvg", + "utf8_iter", + "wasmi", + "xmlwriter", +] + +[[package]] +name = "typst-macros" +version = "0.14.2" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "typst-pdf" +version = "0.14.2" +dependencies = [ + "az", + "bytemuck", + "codex", + "comemo", + "ecow", + "flate2", + "image", + "indexmap 2.14.0", + "infer", + "krilla", + "krilla-svg", + "rustc-hash", + "serde", + "smallvec", + "typst-assets 0.14.2 (git+https://github.com/typst/typst-assets?rev=3284e80)", + "typst-layout", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", +] + +[[package]] +name = "typst-realize" +version = "0.14.2" +dependencies = [ + "arrayvec", + "bumpalo", + "comemo", + "ecow", + "regex", + "typst-html", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", +] + +[[package]] +name = "typst-render" +version = "0.14.2" +dependencies = [ + "bytemuck", + "comemo", + "hayro", + "image", + "libm", + "pixglyph", + "resvg", + "tiny-skia", + "ttf-parser", + "typst-assets 0.14.2 (git+https://github.com/typst/typst-assets?rev=3284e80)", + "typst-layout", + "typst-library", + "typst-macros", + "typst-timing", +] + +[[package]] +name = "typst-svg" +version = "0.14.2" +dependencies = [ + "base64 0.22.1", + "comemo", + "ecow", + "flate2", + "hayro", + "hayro-svg", + "image", + "indexmap 2.14.0", + "itoa", + "rustc-hash", + "ryu", + "ttf-parser", + "typst-assets 0.14.2 (git+https://github.com/typst/typst-assets?rev=3284e80)", + "typst-layout", + "typst-library", + "typst-macros", + "typst-timing", + "typst-utils", + "xmlwriter", +] + +[[package]] +name = "typst-syntax" +version = "0.14.2" +dependencies = [ + "ecow", + "rustc-hash", + "serde", + "toml 0.8.2", + "typst-timing", + "typst-utils", + "unicode-ident", + "unicode-math-class", + "unicode-script", + "unicode-segmentation", + "unscanny", +] + +[[package]] +name = "typst-timing" +version = "0.14.2" +dependencies = [ + "parking_lot", + "serde", + "serde_json", +] + +[[package]] +name = "typst-utils" +version = "0.14.2" +dependencies = [ + "libm", + "once_cell", + "portable-atomic", + "rayon", + "rustc-hash", + "semver", + "siphasher", + "thin-vec", + "unicode-math-class", +] + +[[package]] +name = "uds_windows" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" +dependencies = [ + "memoffset", + "tempfile", + "windows-sys 0.61.2", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-langid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05" +dependencies = [ + "unic-langid-impl", + "unic-langid-macros", +] + +[[package]] +name = "unic-langid-impl" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658" +dependencies = [ + "serde", + "tinystr 0.8.3", +] + +[[package]] +name = "unic-langid-macros" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5957eb82e346d7add14182a3315a7e298f04e1ba4baac36f7f0dbfedba5fc25" +dependencies = [ + "proc-macro-hack", + "tinystr 0.8.3", + "unic-langid-impl", + "unic-langid-macros-impl", +] + +[[package]] +name = "unic-langid-macros-impl" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1249a628de3ad34b821ecb1001355bca3940bcb2f88558f1a8bd82e977f75b5" +dependencies = [ + "proc-macro-hack", + "quote", + "syn 2.0.119", + "unic-langid-impl", +] + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-bidi-mirroring" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe" + +[[package]] +name = "unicode-ccc" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-math-class" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d246cf599d5fae3c8d56e04b20eb519adb89a8af8d0b0fbcded369aa3647d65" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unicode-script" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "unscanny" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9df2af067a7953e9c3831320f35c1cc0600c30d44d9f7a12b01db1cd88d6b47" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +dependencies = [ + "base64 0.22.1", + "flate2", + "log", + "native-tls", + "once_cell", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "url", + "webpki-roots 0.26.11", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "urlpattern" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +dependencies = [ + "regex", + "serde", + "unic-ucd-ident", + "url", +] + +[[package]] +name = "usvg" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d46cf96c5f498d36b7a9693bc6a7075c0bb9303189d61b2249b0dc3d309c07de" +dependencies = [ + "base64 0.22.1", + "data-url", + "flate2", + "fontdb", + "imagesize", + "kurbo", + "log", + "pico-args", + "roxmltree 0.21.1", + "rustybuzz", + "simplecss", + "siphasher", + "strict-num", + "svgtypes", + "tiny-skia-path", + "ttf-parser", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "xmlwriter", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" +dependencies = [ + "getrandom 0.4.3", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vello_common" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3361bff7f7d82c0c496b92048db83846691f0e844cc28dee92b1c824291b55ee" +dependencies = [ + "bytemuck", + "fearless_simd", + "guillotiere", + "hashbrown 0.17.1", + "log", + "peniko", + "png 0.18.1", + "smallvec", + "thiserror 2.0.18", +] + +[[package]] +name = "vello_common" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d672facaa2d697285a786cd9d44d614cd2ce54cdc022504bf339f8fff3b750" +dependencies = [ + "bytemuck", + "fearless_simd", + "guillotiere", + "hashbrown 0.17.1", + "log", + "peniko", + "png 0.18.1", + "smallvec", + "thiserror 2.0.18", +] + +[[package]] +name = "vello_cpu" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d8ded630e8316bb94a55881256506d1f3b9947b5f66db8a7d32ca7ba02decd0" +dependencies = [ + "bytemuck", + "glifo", + "hashbrown 0.17.1", + "png 0.18.1", + "vello_common 0.0.8", +] + +[[package]] +name = "version-compare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.119", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasmi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2300d0f78cba12f14e29e8dd157ea64050c0a688179aefdb2050105805594a0c" +dependencies = [ + "spin", + "wasmi_collections", + "wasmi_core", + "wasmi_ir", + "wasmparser", +] + +[[package]] +name = "wasmi_collections" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a8c42a2a76148d43097b1d7cc2a5bf33d5c23bd4dd69015fc887e311767884" + +[[package]] +name = "wasmi_core" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9013136083d988725953390bf668b64b7a218fabf26f8b913bbc59546b97ee27" +dependencies = [ + "libm", +] + +[[package]] +name = "wasmi_ir" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1fa003f79156f406d62ef0e1464dc03e11ace37170e9fa7524299a75ad8f68" +dependencies = [ + "wasmi_core", +] + +[[package]] +name = "wasmparser" +version = "0.239.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" +dependencies = [ + "bitflags 2.13.1", +] + +[[package]] +name = "web-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web_atoms" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "075474b12bcb3d2e3d4546580e9de478eeeead668a1761e2a8860c836b7ef297" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + +[[package]] +name = "webkit2gtk" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup3", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pkg-config", + "soup3-sys", + "system-deps", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.9", +] + +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webview2-com" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows", + "windows-core 0.61.2", + "windows-implement", + "windows-interface", +] + +[[package]] +name = "webview2-com-macros" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "webview2-com-sys" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" +dependencies = [ + "thiserror 2.0.18", + "windows", + "windows-core 0.61.2", +] + +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "window-vibrancy" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" +dependencies = [ + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "windows-sys 0.59.0", + "windows-version", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +dependencies = [ + "cfg-if", + "windows-sys 0.59.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "write-fonts" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb731d4c4d93eacc69a1ad2f270f905788a98e4a3438267bcafbe08d3431c8d8" +dependencies = [ + "font-types", + "indexmap 2.14.0", + "kurbo", + "log", + "read-fonts", +] + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "wry" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186f9871daa55fd9c016578b810d149de58367113db7fb72b462d2323ce19514" +dependencies = [ + "base64 0.22.1", + "block2", + "cookie", + "crossbeam-channel", + "dirs", + "dom_query", + "dpi", + "dunce", + "gdkx11", + "gtk", + "http", + "javascriptcore-rs", + "jni", + "libc", + "ndk", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "sha2", + "soup3", + "tao-macros", + "thiserror 2.0.18", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + +[[package]] +name = "xmp-writer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9440ea3e5aeabb0ac63af70daf835274065238cdd0cec83418f417eae38bacee" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive 0.7.5", + "zerofrom", +] + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive 0.8.2", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zbus" +version = "5.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe18fb60dc696039e738717b76eaea21e7a4489bbb1885020b43c94236d7e98a" +dependencies = [ + "async-broadcast", + "async-executor", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-lite", + "hex", + "libc", + "ordered-stream", + "rustix", + "serde", + "serde_repr", + "tracing", + "uds_windows", + "uuid", + "windows-sys 0.61.2", + "winnow 1.0.4", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "5.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe96480bed92df2b442a1a30df364e12d08eed03aeb061f2b8dc6afb2be91119" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", + "zbus_names", + "zvariant", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "4.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bf88b4a3ff53e883001e0e0115b297a9d53c31b9c1edd2bfdd853e3428624e" +dependencies = [ + "serde", + "winnow 1.0.4", + "zvariant", +] + +[[package]] +name = "zerocopy" +version = "0.8.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + +[[package]] +name = "zerotrie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb594dd55d87335c5f60177cee24f19457a5ec10a065e0a3014722ad252d0a1f" +dependencies = [ + "displaydoc", + "litemap 0.7.5", + "serde", + "zerovec 0.10.4", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke 0.8.3", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "serde", + "yoke 0.7.5", + "zerofrom", + "zerovec-derive 0.10.3", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "serde", + "yoke 0.8.3", + "zerofrom", + "zerovec-derive 0.11.3", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zlib-rs" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b142a20ec14a91d5bc708c1dc21b080c550113d8aa77afa29635673a65dd02c5" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zune-core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] + +[[package]] +name = "zvariant" +version = "5.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee2a0bcd2a907786a456fff45aaaaf54c9ba5f50b71ae9ec1a4edd200c94911" +dependencies = [ + "endi", + "enumflags2", + "serde", + "winnow 1.0.4", + "zvariant_derive", + "zvariant_utils", +] + +[[package]] +name = "zvariant_derive" +version = "5.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38a708216a18780796770bfe3f4739c7c83a3e8f789b755534bbbc06e4e23e12" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90cb9383f9b45290407a1258b202d3f8f01db719eb60b4e4055c6375af4fc7c7" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 2.0.119", + "winnow 1.0.4", +] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml new file mode 100644 index 0000000..56c9c7e --- /dev/null +++ b/src-tauri/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "typst-desktop" +version = "0.1.0" +description = "A Tauri App" +authors = ["you"] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +# The `_lib` suffix may seem redundant but it is necessary +# to make the lib name unique and wouldn't conflict with the bin name. +# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 +name = "typst_desktop_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[build-dependencies] +tauri-build = { version = "2", features = [] } + +[dependencies] +tauri = { version = "2", features = [] } +tauri-plugin-opener = "2" +tauri-plugin-dialog = "2" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +rusqlite = { version = "0.32", features = ["bundled"] } + +typst = { version = "0.14.2", path = "../../typstdrive/typst/crates/typst" } +typst-kit = { path = "../../typstdrive/typst/crates/typst-kit", features = ["system-downloader", "system-packages", "embedded-fonts"] } +typst-pdf = { path = "../../typstdrive/typst/crates/typst-pdf" } +typst-render = { path = "../../typstdrive/typst/crates/typst-render" } +typst-svg = { path = "../../typstdrive/typst/crates/typst-svg" } +typst-html = { path = "../../typstdrive/typst/crates/typst-html" } +typst-layout = { path = "../../typstdrive/typst/crates/typst-layout" } +typst-assets = { version = "0.14.2", features = ["fonts"] } + +chrono = { version = "0.4", features = ["serde"] } +sha2 = "0.10" +base64 = "0.22" +diffy = "0.4" +walkdir = "2" +ureq = { version = "2.12", features = ["json"] } + diff --git a/src-tauri/build.rs b/src-tauri/build.rs new file mode 100644 index 0000000..d860e1e --- /dev/null +++ b/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json new file mode 100644 index 0000000..078e41e --- /dev/null +++ b/src-tauri/capabilities/default.json @@ -0,0 +1,21 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "Capability for the main window", + "windows": ["main"], + "permissions": [ + "core:default", + "core:window:allow-minimize", + "core:window:allow-maximize", + "core:window:allow-unmaximize", + "core:window:allow-toggle-maximize", + "core:window:allow-internal-toggle-maximize", + "core:window:allow-is-maximized", + "core:window:allow-start-dragging", + "core:window:allow-close", + "opener:default", + "dialog:default", + "dialog:allow-open", + "dialog:allow-save" + ] +} diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png new file mode 100644 index 0000000..6be5e50 Binary files /dev/null and b/src-tauri/icons/128x128.png differ diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png new file mode 100644 index 0000000..e81bece Binary files /dev/null and b/src-tauri/icons/128x128@2x.png differ diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png new file mode 100644 index 0000000..a437dd5 Binary files /dev/null and b/src-tauri/icons/32x32.png differ diff --git a/src-tauri/icons/Square107x107Logo.png b/src-tauri/icons/Square107x107Logo.png new file mode 100644 index 0000000..0ca4f27 Binary files /dev/null and b/src-tauri/icons/Square107x107Logo.png differ diff --git a/src-tauri/icons/Square142x142Logo.png b/src-tauri/icons/Square142x142Logo.png new file mode 100644 index 0000000..b81f820 Binary files /dev/null and b/src-tauri/icons/Square142x142Logo.png differ diff --git a/src-tauri/icons/Square150x150Logo.png b/src-tauri/icons/Square150x150Logo.png new file mode 100644 index 0000000..624c7bf Binary files /dev/null and b/src-tauri/icons/Square150x150Logo.png differ diff --git a/src-tauri/icons/Square284x284Logo.png b/src-tauri/icons/Square284x284Logo.png new file mode 100644 index 0000000..c021d2b Binary files /dev/null and b/src-tauri/icons/Square284x284Logo.png differ diff --git a/src-tauri/icons/Square30x30Logo.png b/src-tauri/icons/Square30x30Logo.png new file mode 100644 index 0000000..6219700 Binary files /dev/null and b/src-tauri/icons/Square30x30Logo.png differ diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png new file mode 100644 index 0000000..f9bc048 Binary files /dev/null and b/src-tauri/icons/Square310x310Logo.png differ diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png new file mode 100644 index 0000000..d5fbfb2 Binary files /dev/null and b/src-tauri/icons/Square44x44Logo.png differ diff --git a/src-tauri/icons/Square71x71Logo.png b/src-tauri/icons/Square71x71Logo.png new file mode 100644 index 0000000..63440d7 Binary files /dev/null and b/src-tauri/icons/Square71x71Logo.png differ diff --git a/src-tauri/icons/Square89x89Logo.png b/src-tauri/icons/Square89x89Logo.png new file mode 100644 index 0000000..f3f705a Binary files /dev/null and b/src-tauri/icons/Square89x89Logo.png differ diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png new file mode 100644 index 0000000..4556388 Binary files /dev/null and b/src-tauri/icons/StoreLogo.png differ diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns new file mode 100644 index 0000000..12a5bce Binary files /dev/null and b/src-tauri/icons/icon.icns differ diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico new file mode 100644 index 0000000..b3636e4 Binary files /dev/null and b/src-tauri/icons/icon.ico differ diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png new file mode 100644 index 0000000..e1cd261 Binary files /dev/null and b/src-tauri/icons/icon.png differ diff --git a/src-tauri/src/assets.rs b/src-tauri/src/assets.rs new file mode 100644 index 0000000..ec04db6 --- /dev/null +++ b/src-tauri/src/assets.rs @@ -0,0 +1,254 @@ +use serde::Serialize; +use std::collections::{BTreeSet, HashMap}; +use std::path::{Path, PathBuf}; +use tauri::AppHandle; + +use crate::db::Store; +use crate::workspace::workspace_root; + +pub const ASSETS_DIR: &str = ".assets"; + +const FONT_EXTENSIONS: [&str; 4] = ["ttf", "otf", "ttc", "otc"]; +const IMAGE_EXTENSIONS: [&str; 6] = ["png", "jpg", "jpeg", "gif", "svg", "webp"]; + +fn extension_of(name: &str) -> String { + Path::new(name) + .extension() + .and_then(|ext| ext.to_str()) + .unwrap_or("") + .to_lowercase() +} + +pub fn is_font(name: &str) -> bool { + FONT_EXTENSIONS.contains(&extension_of(name).as_str()) +} + +pub fn is_image(name: &str) -> bool { + IMAGE_EXTENSIONS.contains(&extension_of(name).as_str()) +} + +pub fn assets_dir(app: &AppHandle, store: &Store) -> Result { + let dir = workspace_root(app, store)?.join(ASSETS_DIR); + std::fs::create_dir_all(&dir) + .map_err(|e| format!("Cannot create assets folder: {}", e))?; + Ok(dir) +} + +fn families_in(data: &[u8]) -> Vec { + let mut families = BTreeSet::new(); + for font in typst::text::Font::iter(typst::foundations::Bytes::new(data.to_vec())) { + families.insert(font.info().family.clone()); + } + families.into_iter().collect() +} + +#[derive(Serialize)] +pub struct Asset { + pub name: String, + pub kind: String, + pub size: u64, + pub font_families: Vec, +} + +pub fn list_assets(app: &AppHandle, store: &Store) -> Result, String> { + let dir = assets_dir(app, store)?; + let mut assets = Vec::new(); + + for entry in std::fs::read_dir(&dir).map_err(|e| e.to_string())? { + let entry = entry.map_err(|e| e.to_string())?; + if !entry.path().is_file() { + continue; + } + + let name = entry.file_name().to_string_lossy().to_string(); + if name.starts_with('.') { + continue; + } + + let size = entry.metadata().map(|m| m.len()).unwrap_or(0); + let font_families = if is_font(&name) { + std::fs::read(entry.path()) + .map(|data| families_in(&data)) + .unwrap_or_default() + } else { + Vec::new() + }; + + assets.push(Asset { + kind: if is_font(&name) { + "font" + } else if is_image(&name) { + "image" + } else { + "file" + } + .to_string(), + name, + size, + font_families, + }); + } + + assets.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase())); + Ok(assets) +} + +pub fn font_families(files: &HashMap>) -> Vec { + let mut families = BTreeSet::new(); + + for data in typst_assets::fonts() { + for font in typst::text::Font::iter(typst::foundations::Bytes::new(data)) { + families.insert(font.info().family.clone()); + } + } + + for (name, data) in files { + if is_font(name) { + for family in families_in(data) { + families.insert(family); + } + } + } + + families.into_iter().collect() +} + +fn unique_destination(dir: &Path, name: &str) -> PathBuf { + let candidate = dir.join(name); + if !candidate.exists() { + return candidate; + } + + let stem = Path::new(name) + .file_stem() + .and_then(|s| s.to_str()) + .unwrap_or("file") + .to_string(); + let extension = Path::new(name) + .extension() + .and_then(|e| e.to_str()) + .map(|e| format!(".{}", e)) + .unwrap_or_default(); + + for index in 2..1000 { + let candidate = dir.join(format!("{}-{}{}", stem, index, extension)); + if !candidate.exists() { + return candidate; + } + } + + dir.join(name) +} + +fn copy_tree(source: &Path, destination: &Path) -> Result<(), String> { + std::fs::create_dir_all(destination).map_err(|e| e.to_string())?; + + for entry in std::fs::read_dir(source).map_err(|e| e.to_string())? { + let entry = entry.map_err(|e| e.to_string())?; + let name = entry.file_name(); + let from = entry.path(); + let to = destination.join(&name); + + if from.is_dir() { + copy_tree(&from, &to)?; + } else { + std::fs::copy(&from, &to).map_err(|e| e.to_string())?; + } + } + + Ok(()) +} + +pub fn import_paths(sources: &[String], destination: &Path) -> Result, String> { + std::fs::create_dir_all(destination).map_err(|e| e.to_string())?; + + let mut imported = Vec::new(); + + for source in sources { + let source_path = Path::new(source); + let name = source_path + .file_name() + .map(|n| n.to_string_lossy().to_string()) + .ok_or_else(|| format!("'{}' has no name", source))?; + + if source_path.is_dir() { + let target = unique_destination(destination, &name); + copy_tree(source_path, &target)?; + } else if source_path.is_file() { + let target = unique_destination(destination, &name); + std::fs::copy(source_path, &target) + .map_err(|e| format!("Could not import '{}': {}", name, e))?; + } else { + return Err(format!("'{}' could not be read", source)); + } + + imported.push(name); + } + + Ok(imported) +} + +pub fn import_files(sources: &[String], destination: &Path) -> Result, String> { + std::fs::create_dir_all(destination).map_err(|e| e.to_string())?; + + let mut imported = Vec::new(); + + for source in sources { + let source_path = Path::new(source); + if !source_path.is_file() { + return Err(format!("'{}' is not a file", source)); + } + + let name = source_path + .file_name() + .map(|n| n.to_string_lossy().to_string()) + .ok_or_else(|| format!("'{}' has no file name", source))?; + + let target = unique_destination(destination, &name); + std::fs::copy(source_path, &target) + .map_err(|e| format!("Could not import '{}': {}", name, e))?; + + imported.push( + target + .file_name() + .map(|n| n.to_string_lossy().to_string()) + .unwrap_or(name), + ); + } + + Ok(imported) +} + +pub fn delete_asset(app: &AppHandle, store: &Store, name: &str) -> Result<(), String> { + if name.contains('/') || name.contains('\\') || name.contains("..") { + return Err("Invalid asset name".to_string()); + } + let path = assets_dir(app, store)?.join(name); + std::fs::remove_file(path).map_err(|e| e.to_string()) +} + +pub fn asset_files(app: &AppHandle, store: &Store) -> HashMap> { + let Ok(dir) = assets_dir(app, store) else { + return HashMap::new(); + }; + + let mut files = HashMap::new(); + let Ok(entries) = std::fs::read_dir(&dir) else { + return files; + }; + + for entry in entries.filter_map(|entry| entry.ok()) { + if !entry.path().is_file() { + continue; + } + let name = entry.file_name().to_string_lossy().to_string(); + if name.starts_with('.') { + continue; + } + if let Ok(data) = std::fs::read(entry.path()) { + files.insert(name, data); + } + } + + files +} diff --git a/src-tauri/src/compiler.rs b/src-tauri/src/compiler.rs new file mode 100644 index 0000000..80f1133 --- /dev/null +++ b/src-tauri/src/compiler.rs @@ -0,0 +1,213 @@ +use serde::Serialize; +use std::collections::HashMap; +use typst::diag::Warned; +use typst::layout::{Frame, FrameItem}; +use typst::WorldExt; +use typst_html::HtmlDocument; +use typst_layout::PagedDocument; +use typst_pdf::{pdf, PdfOptions}; +use typst_render::{render, RenderOptions}; +use typst_svg::SvgOptions; + +use crate::world::ProjectWorld; + +#[derive(Serialize, Clone)] +pub struct DocumentStats { + pub pages: usize, + pub words: usize, + pub characters: usize, +} + +#[derive(Serialize, Clone)] +pub struct Diagnostic { + pub message: String, + pub severity: String, + pub line: Option, + pub column: Option, +} + +#[derive(Serialize)] +pub struct CompileResult { + pub pages: Vec, + pub stats: DocumentStats, + pub diagnostics: Vec, +} + +fn extract_frame_text(frame: &Frame, text: &mut String) { + for (_, item) in frame.items() { + match item { + FrameItem::Text(text_item) => { + text.push_str(&text_item.text); + text.push(' '); + } + FrameItem::Group(group) => extract_frame_text(&group.frame, text), + _ => {} + } + } +} + +fn extract_stats(document: &PagedDocument) -> DocumentStats { + let mut text = String::new(); + for page in document.pages() { + extract_frame_text(&page.frame, &mut text); + } + + DocumentStats { + pages: document.pages().len(), + words: text.split_whitespace().count(), + characters: text.chars().filter(|c| !c.is_whitespace()).count(), + } +} + +fn line_and_column(source: &str, offset: usize) -> (usize, usize) { + let mut line = 1; + let mut column = 1; + for (index, character) in source.char_indices() { + if index >= offset { + break; + } + if character == '\n' { + line += 1; + column = 1; + } else { + column += 1; + } + } + (line, column) +} + +fn collect_diagnostics( + world: &ProjectWorld, + entrypoint_source: &str, + errors: impl IntoIterator, +) -> Vec { + errors + .into_iter() + .map(|diagnostic| { + let (line, column) = match world.range(diagnostic.span) { + Some(range) => { + let (line, column) = line_and_column(entrypoint_source, range.start); + (Some(line), Some(column)) + } + None => (None, None), + }; + Diagnostic { + message: diagnostic.message.to_string(), + severity: format!("{:?}", diagnostic.severity).to_lowercase(), + line, + column, + } + }) + .collect() +} + +fn entrypoint_text(files: &HashMap>, entrypoint: &str) -> String { + files + .get(entrypoint) + .map(|bytes| String::from_utf8_lossy(bytes).to_string()) + .unwrap_or_default() +} + +pub fn compile_to_svg( + entrypoint: String, + files: HashMap>, +) -> Result> { + let source_text = entrypoint_text(&files, &entrypoint); + let world = ProjectWorld::new(entrypoint, files, false); + + match typst::compile::(&world) { + Warned { + output: Ok(document), + warnings, + } => { + let options = SvgOptions::default(); + let pages = document + .pages() + .iter() + .map(|page| typst_svg::svg(page, &options)) + .collect(); + + Ok(CompileResult { + pages, + stats: extract_stats(&document), + diagnostics: collect_diagnostics(&world, &source_text, warnings), + }) + } + Warned { + output: Err(errors), + warnings: _, + } => Err(collect_diagnostics(&world, &source_text, errors)), + } +} + +pub fn export_pdf( + entrypoint: String, + files: HashMap>, +) -> Result, Vec> { + let source_text = entrypoint_text(&files, &entrypoint); + let world = ProjectWorld::new(entrypoint, files, false); + + match typst::compile::(&world) { + Warned { + output: Ok(document), + warnings: _, + } => pdf(&document, &PdfOptions::default()).map_err(|errors| { + collect_diagnostics(&world, &source_text, errors) + }), + Warned { + output: Err(errors), + warnings: _, + } => Err(collect_diagnostics(&world, &source_text, errors)), + } +} + +pub fn export_png( + entrypoint: String, + files: HashMap>, +) -> Result, Vec> { + let source_text = entrypoint_text(&files, &entrypoint); + let world = ProjectWorld::new(entrypoint, files, false); + + match typst::compile::(&world) { + Warned { + output: Ok(document), + warnings: _, + } => { + let options = RenderOptions { + pixel_per_pt: 2.0, + ..RenderOptions::default() + }; + match document.pages().first() { + Some(page) => Ok(render(page, &options).encode_png().unwrap_or_default()), + None => Ok(Vec::new()), + } + } + Warned { + output: Err(errors), + warnings: _, + } => Err(collect_diagnostics(&world, &source_text, errors)), + } +} + +pub fn export_html( + entrypoint: String, + files: HashMap>, +) -> Result, Vec> { + let source_text = entrypoint_text(&files, &entrypoint); + let world = ProjectWorld::new(entrypoint, files, true); + + let document = match typst::compile::(&world) { + Warned { + output: Ok(document), + warnings: _, + } => document, + Warned { + output: Err(errors), + warnings: _, + } => return Err(collect_diagnostics(&world, &source_text, errors)), + }; + + typst_html::html(&document) + .map(|html| html.into_bytes()) + .map_err(|errors| collect_diagnostics(&world, &source_text, errors)) +} diff --git a/src-tauri/src/db.rs b/src-tauri/src/db.rs new file mode 100644 index 0000000..72541b0 --- /dev/null +++ b/src-tauri/src/db.rs @@ -0,0 +1,300 @@ +use rusqlite::{params, Connection, OptionalExtension}; +use std::collections::HashMap; +use std::sync::Mutex; +use tauri::{AppHandle, Manager}; + +use crate::workspace::{ProjectMeta, Settings}; + +pub struct Store { + connection: Mutex, +} + +const SCHEMA: [&str; 4] = [ + "CREATE TABLE IF NOT EXISTS settings ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL + )", + "CREATE TABLE IF NOT EXISTS projects ( + path TEXT PRIMARY KEY, + entrypoint TEXT NOT NULL DEFAULT 'main.typ', + space_id TEXT, + last_synced_at TEXT + )", + "CREATE TABLE IF NOT EXISTS base_files ( + project_path TEXT NOT NULL, + file_path TEXT NOT NULL, + hash TEXT NOT NULL, + content BLOB, + PRIMARY KEY (project_path, file_path) + )", + "CREATE TABLE IF NOT EXISTS thumbnails ( + path TEXT PRIMARY KEY, + kind TEXT NOT NULL, + data TEXT NOT NULL, + source_modified INTEGER NOT NULL + )", +]; + +impl Store { + pub fn open(app: &AppHandle) -> Result { + let dir = app + .path() + .app_data_dir() + .map_err(|e| format!("Cannot resolve data directory: {}", e))?; + std::fs::create_dir_all(&dir).map_err(|e| e.to_string())?; + + let connection = + Connection::open(dir.join("typst-desktop.db")).map_err(|e| e.to_string())?; + + connection + .pragma_update(None, "journal_mode", "WAL") + .map_err(|e| e.to_string())?; + connection + .pragma_update(None, "foreign_keys", "ON") + .map_err(|e| e.to_string())?; + + for statement in SCHEMA { + connection.execute(statement, []).map_err(|e| e.to_string())?; + } + + Ok(Store { + connection: Mutex::new(connection), + }) + } + + fn with(&self, run: impl FnOnce(&Connection) -> rusqlite::Result) -> Result { + let connection = self + .connection + .lock() + .map_err(|_| "Local database lock poisoned".to_string())?; + run(&connection).map_err(|e| e.to_string()) + } + + pub fn settings(&self) -> Result, String> { + let raw: Option = self.with(|connection| { + connection + .query_row( + "SELECT value FROM settings WHERE key = 'settings'", + [], + |row| row.get(0), + ) + .optional() + })?; + + match raw { + Some(raw) => serde_json::from_str(&raw) + .map(Some) + .map_err(|e| format!("Stored settings are invalid: {}", e)), + None => Ok(None), + } + } + + pub fn save_settings(&self, settings: &Settings) -> Result<(), String> { + let raw = serde_json::to_string(settings).map_err(|e| e.to_string())?; + self.with(|connection| { + connection.execute( + "INSERT INTO settings (key, value) VALUES ('settings', ?1) + ON CONFLICT(key) DO UPDATE SET value = excluded.value", + params![raw], + ) + })?; + Ok(()) + } + + pub fn meta(&self, project: &str) -> Result { + let row: Option<(String, Option, Option)> = self.with(|connection| { + connection + .query_row( + "SELECT entrypoint, space_id, last_synced_at FROM projects WHERE path = ?1", + params![project], + |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), + ) + .optional() + })?; + + let Some((entrypoint, space_id, last_synced_at)) = row else { + return Ok(ProjectMeta::default()); + }; + + let base_hashes = self.with(|connection| { + let mut statement = connection + .prepare("SELECT file_path, hash FROM base_files WHERE project_path = ?1")?; + let rows = statement.query_map(params![project], |row| { + Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?)) + })?; + + let mut map = HashMap::new(); + for row in rows { + let (path, hash) = row?; + map.insert(path, hash); + } + Ok(map) + })?; + + Ok(ProjectMeta { + entrypoint, + space_id, + last_synced_at, + base_hashes, + }) + } + + pub fn has_project(&self, project: &str) -> Result { + let found: Option = self.with(|connection| { + connection + .query_row( + "SELECT 1 FROM projects WHERE path = ?1", + params![project], + |row| row.get(0), + ) + .optional() + })?; + Ok(found.is_some()) + } + + pub fn save_meta(&self, project: &str, meta: &ProjectMeta) -> Result<(), String> { + self.with(|connection| { + connection.execute( + "INSERT INTO projects (path, entrypoint, space_id, last_synced_at) + VALUES (?1, ?2, ?3, ?4) + ON CONFLICT(path) DO UPDATE SET + entrypoint = excluded.entrypoint, + space_id = excluded.space_id, + last_synced_at = excluded.last_synced_at", + params![ + project, + meta.entrypoint, + meta.space_id, + meta.last_synced_at + ], + )?; + + let mut keep: Vec = Vec::new(); + for (file, hash) in &meta.base_hashes { + connection.execute( + "INSERT INTO base_files (project_path, file_path, hash) + VALUES (?1, ?2, ?3) + ON CONFLICT(project_path, file_path) DO UPDATE SET hash = excluded.hash", + params![project, file, hash], + )?; + keep.push(file.clone()); + } + + let mut statement = connection + .prepare("SELECT file_path FROM base_files WHERE project_path = ?1")?; + let existing: Vec = statement + .query_map(params![project], |row| row.get::<_, String>(0))? + .collect::>>()?; + + for file in existing { + if !keep.contains(&file) { + connection.execute( + "DELETE FROM base_files WHERE project_path = ?1 AND file_path = ?2", + params![project, file], + )?; + } + } + + Ok(()) + }) + } + + pub fn forget_project(&self, project: &str) -> Result<(), String> { + self.with(|connection| { + connection.execute( + "DELETE FROM base_files WHERE project_path = ?1", + params![project], + )?; + connection.execute("DELETE FROM projects WHERE path = ?1", params![project])?; + Ok(()) + }) + } + + pub fn rename_project(&self, from: &str, to: &str) -> Result<(), String> { + self.with(|connection| { + connection.execute( + "UPDATE projects SET path = ?2 WHERE path = ?1", + params![from, to], + )?; + connection.execute( + "UPDATE base_files SET project_path = ?2 WHERE project_path = ?1", + params![from, to], + )?; + Ok(()) + }) + } + + pub fn base_snapshot(&self, project: &str, file: &str) -> Result>, String> { + self.with(|connection| { + connection + .query_row( + "SELECT content FROM base_files WHERE project_path = ?1 AND file_path = ?2", + params![project, file], + |row| row.get::<_, Option>>(0), + ) + .optional() + .map(|value| value.flatten()) + }) + } + + pub fn save_base_snapshot( + &self, + project: &str, + file: &str, + hash: &str, + content: &[u8], + ) -> Result<(), String> { + self.with(|connection| { + connection.execute( + "INSERT INTO base_files (project_path, file_path, hash, content) + VALUES (?1, ?2, ?3, ?4) + ON CONFLICT(project_path, file_path) DO UPDATE SET + hash = excluded.hash, + content = excluded.content", + params![project, file, hash, content], + )?; + Ok(()) + }) + } + + pub fn thumbnail(&self, path: &str, modified: i64) -> Result, String> { + self.with(|connection| { + connection + .query_row( + "SELECT kind, data FROM thumbnails + WHERE path = ?1 AND source_modified >= ?2", + params![path, modified], + |row| Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?)), + ) + .optional() + }) + } + + pub fn save_thumbnail( + &self, + path: &str, + kind: &str, + data: &str, + modified: i64, + ) -> Result<(), String> { + self.with(|connection| { + connection.execute( + "INSERT INTO thumbnails (path, kind, data, source_modified) + VALUES (?1, ?2, ?3, ?4) + ON CONFLICT(path) DO UPDATE SET + kind = excluded.kind, + data = excluded.data, + source_modified = excluded.source_modified", + params![path, kind, data, modified], + )?; + Ok(()) + }) + } + + pub fn clear_thumbnails(&self) -> Result<(), String> { + self.with(|connection| { + connection.execute("DELETE FROM thumbnails", [])?; + Ok(()) + }) + } +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs new file mode 100644 index 0000000..7018681 --- /dev/null +++ b/src-tauri/src/lib.rs @@ -0,0 +1,714 @@ +mod assets; +mod compiler; +mod db; +mod lsp; +mod sync; +mod thumbnails; +mod workspace; +mod world; + +use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _}; +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; +use tauri::{AppHandle, Manager, State}; + +use assets::Asset; +use db::Store; +use compiler::{CompileResult, Diagnostic}; +use lsp::{LspHandle, LspState}; +use sync::{Account, SpaceSummary, SyncReport}; +use workspace::{ + browse, is_project_dir, is_text_file, list_files, load_settings, project_file_path, + read_target_files, resolve_target, save_settings, workspace_path, BrowseEntry, + FileEntry, ProjectMeta, Settings, NEW_PROJECT_MAIN, +}; + +#[derive(Serialize)] +pub struct CompileFailure { + pub diagnostics: Vec, +} + +fn failure(message: String) -> CompileFailure { + CompileFailure { + diagnostics: vec![Diagnostic { + message, + severity: "error".to_string(), + line: None, + column: None, + }], + } +} + +fn cloud_credentials(app: &AppHandle, store: &Store) -> Result<(String, String), String> { + let settings = load_settings(app, store)?; + let token = settings.device_token.ok_or("Not signed in to TypstDrive")?; + Ok((settings.server_url, token)) +} + +fn load_project( + app: &AppHandle, + store: &Store, + project: &str, +) -> Result<(PathBuf, ProjectMeta), String> { + let dir = workspace_path(app, store, project)?; + if !dir.is_dir() { + return Err(format!("Project '{}' not found", project)); + } + Ok((dir, store.meta(project)?)) +} + +#[tauri::command] +fn get_settings(app: AppHandle, store: State<'_, Store>) -> Result { + load_settings(&app, &store) +} + +#[tauri::command] +fn update_settings( + app: AppHandle, + store: State<'_, Store>, + workspace_root: Option, + server_url: Option, +) -> Result { + let mut settings = load_settings(&app, &store)?; + if let Some(root) = workspace_root { + if root.trim().is_empty() { + return Err("Workspace folder cannot be empty".to_string()); + } + settings.workspace_root = root; + } + if let Some(url) = server_url { + settings.server_url = url.trim_end_matches('/').to_string(); + } + save_settings(&store, &settings)?; + Ok(settings) +} + +#[tauri::command] +fn browse_workspace(app: AppHandle, store: State<'_, Store>, path: String) -> Result, String> { + browse(&app, &store, &path) +} + +fn parent_of(path: &str) -> String { + match path.rsplit_once('/') { + Some((parent, _)) => parent.to_string(), + None => String::new(), + } +} + +fn join_path(parent: &str, name: &str) -> String { + if parent.is_empty() { + name.to_string() + } else { + format!("{}/{}", parent.trim_end_matches('/'), name) + } +} + +#[tauri::command] +fn create_folder_entry(app: AppHandle, store: State<'_, Store>, parent: String, name: String) -> Result { + let path = join_path(&parent, name.trim()); + let full = workspace_path(&app, &store, &path)?; + if full.exists() { + return Err(format!("'{}' already exists", name)); + } + std::fs::create_dir_all(&full).map_err(|e| e.to_string())?; + Ok(path) +} + +#[tauri::command] +fn create_document_entry(app: AppHandle, store: State<'_, Store>, parent: String, name: String) -> Result { + let mut name = name.trim().to_string(); + if name.is_empty() { + return Err("Document name cannot be empty".to_string()); + } + if !name.to_lowercase().ends_with(".typ") { + name.push_str(".typ"); + } + + let path = join_path(&parent, &name); + let full = workspace_path(&app, &store, &path)?; + if full.exists() { + return Err(format!("'{}' already exists", name)); + } + if let Some(dir) = full.parent() { + std::fs::create_dir_all(dir).map_err(|e| e.to_string())?; + } + + let title = name.trim_end_matches(".typ").trim_end_matches(".TYP"); + std::fs::write(&full, format!("= {}\n\nStart writing here.\n", title)) + .map_err(|e| e.to_string())?; + + Ok(path) +} + +#[tauri::command] +fn create_project_entry(app: AppHandle, store: State<'_, Store>, parent: String, name: String) -> Result { + let name = name.trim().to_string(); + if name.is_empty() { + return Err("Project name cannot be empty".to_string()); + } + + let path = join_path(&parent, &name); + let full = workspace_path(&app, &store, &path)?; + if full.exists() { + return Err(format!("'{}' already exists", name)); + } + + std::fs::create_dir_all(&full).map_err(|e| e.to_string())?; + std::fs::write(full.join("main.typ"), NEW_PROJECT_MAIN).map_err(|e| e.to_string())?; + std::fs::write(full.join("typst.toml"), workspace::manifest_for(&name)) + .map_err(|e| e.to_string())?; + + store.save_meta( + &path, + &ProjectMeta { + entrypoint: "main.typ".to_string(), + ..Default::default() + }, + )?; + + Ok(path) +} + +#[tauri::command] +fn rename_entry(app: AppHandle, store: State<'_, Store>, path: String, new_name: String) -> Result { + let new_name = new_name.trim(); + if new_name.is_empty() || new_name.contains('/') || new_name.contains('\\') { + return Err("Invalid name".to_string()); + } + + let from = workspace_path(&app, &store, &path)?; + let target_path = join_path(&parent_of(&path), new_name); + let to = workspace_path(&app, &store, &target_path)?; + + if to.exists() { + return Err(format!("'{}' already exists", new_name)); + } + std::fs::rename(&from, &to).map_err(|e| e.to_string())?; + store.rename_project(&path, &target_path)?; + Ok(target_path) +} + +#[tauri::command] +fn delete_entry(app: AppHandle, store: State<'_, Store>, path: String) -> Result<(), String> { + let full = workspace_path(&app, &store, &path)?; + if full.is_dir() { + std::fs::remove_dir_all(&full).map_err(|e| e.to_string())?; + store.forget_project(&path)?; + Ok(()) + } else { + std::fs::remove_file(&full).map_err(|e| e.to_string()) + } +} + +#[tauri::command] +fn upload_entry( + app: AppHandle, + store: State<'_, Store>, + parent: String, + name: String, + base64_content: String, +) -> Result { + let path = join_path(&parent, &name); + let full = workspace_path(&app, &store, &path)?; + let bytes = BASE64 + .decode(base64_content.as_bytes()) + .map_err(|e| format!("Invalid file data: {}", e))?; + if let Some(dir) = full.parent() { + std::fs::create_dir_all(dir).map_err(|e| e.to_string())?; + } + std::fs::write(&full, bytes).map_err(|e| e.to_string())?; + Ok(path) +} + +#[derive(Serialize)] +pub struct FilePayload { + pub path: String, + pub is_text: bool, + pub content: String, +} + +#[derive(Serialize)] +pub struct TargetInfo { + pub path: String, + pub entrypoint: String, + pub standalone: bool, + pub is_project: bool, + pub space_id: Option, + pub files: Vec, +} + +#[tauri::command] +fn target_info(app: AppHandle, store: State<'_, Store>, path: String) -> Result { + let target = resolve_target(&app, &store, &path)?; + + if target.standalone { + let size = std::fs::metadata(target.root.join(&target.entrypoint)) + .map(|m| m.len()) + .unwrap_or(0); + return Ok(TargetInfo { + path, + entrypoint: target.entrypoint.clone(), + standalone: true, + is_project: false, + space_id: None, + files: vec![FileEntry { + path: target.entrypoint.clone(), + name: target.entrypoint, + is_text: true, + size, + }], + }); + } + + let meta = store.meta(&path)?; + Ok(TargetInfo { + path, + entrypoint: target.entrypoint, + standalone: false, + is_project: is_project_dir(&target.root), + space_id: meta.space_id, + files: list_files(&target.root)?, + }) +} + +#[tauri::command] +fn read_target_file( + app: AppHandle, + store: State<'_, Store>, + path: String, + file: String, +) -> Result { + let target = resolve_target(&app, &store, &path)?; + let full = project_file_path(&target.root, &file)?; + let bytes = std::fs::read(&full).map_err(|e| e.to_string())?; + + let is_text = is_text_file(&file); + Ok(FilePayload { + path: file, + is_text, + content: if is_text { + String::from_utf8_lossy(&bytes).to_string() + } else { + BASE64.encode(&bytes) + }, + }) +} + +#[tauri::command] +fn write_target_file( + app: AppHandle, + store: State<'_, Store>, + path: String, + file: String, + content: String, +) -> Result<(), String> { + let target = resolve_target(&app, &store, &path)?; + let full = project_file_path(&target.root, &file)?; + if let Some(dir) = full.parent() { + std::fs::create_dir_all(dir).map_err(|e| e.to_string())?; + } + std::fs::write(&full, content).map_err(|e| e.to_string()) +} + +#[tauri::command] +fn set_target_entrypoint( + app: AppHandle, + store: State<'_, Store>, + path: String, + entrypoint: String, +) -> Result<(), String> { + let target = resolve_target(&app, &store, &path)?; + if target.standalone { + return Err("A standalone document is its own entrypoint".to_string()); + } + let mut meta = store.meta(&path)?; + meta.entrypoint = entrypoint; + store.save_meta(&path, &meta) +} + +#[tauri::command] +fn compile_target( + app: AppHandle, + store: State<'_, Store>, + path: String, + overrides: Option>, +) -> Result { + let target = resolve_target(&app, &store, &path).map_err(failure)?; + let mut files = read_target_files(&app, &store, &target).map_err(failure)?; + + for (file, content) in overrides.unwrap_or_default() { + files.insert(file, content.into_bytes()); + } + + compiler::compile_to_svg(target.entrypoint, files) + .map_err(|diagnostics| CompileFailure { diagnostics }) +} + +#[tauri::command] +fn export_target( + app: AppHandle, + store: State<'_, Store>, + path: String, + format: String, + destination: String, +) -> Result { + let target = resolve_target(&app, &store, &path)?; + let files = read_target_files(&app, &store, &target)?; + + let bytes = match format.as_str() { + "pdf" => compiler::export_pdf(target.entrypoint, files), + "png" => compiler::export_png(target.entrypoint, files), + "html" => compiler::export_html(target.entrypoint, files), + other => return Err(format!("Unsupported export format '{}'", other)), + } + .map_err(|diagnostics| { + diagnostics + .into_iter() + .map(|d| d.message) + .collect::>() + .join("; ") + })?; + + std::fs::write(&destination, bytes).map_err(|e| e.to_string())?; + Ok(destination) +} + +#[tauri::command] +fn thumbnail(app: AppHandle, store: State<'_, Store>, path: String) -> Result { + thumbnails::thumbnail(&app, &store, &path) +} + +#[tauri::command] +fn read_image( + app: AppHandle, + store: State<'_, Store>, + path: String, +) -> Result { + thumbnails::read_image(&app, &store, &path) +} + +#[tauri::command] +fn clear_thumbnails(store: State<'_, Store>) -> Result<(), String> { + store.clear_thumbnails() +} + +#[tauri::command] +fn list_assets(app: AppHandle, store: State<'_, Store>) -> Result, String> { + assets::list_assets(&app, &store) +} + +#[tauri::command] +fn list_font_families(app: AppHandle, store: State<'_, Store>, path: Option) -> Result, String> { + let files = match path { + Some(path) if !path.is_empty() => { + let target = resolve_target(&app, &store, &path)?; + read_target_files(&app, &store, &target)? + } + _ => assets::asset_files(&app, &store), + }; + + Ok(assets::font_families(&files)) +} + +#[tauri::command] +fn import_assets(app: AppHandle, store: State<'_, Store>, sources: Vec) -> Result, String> { + let destination = assets::assets_dir(&app, &store)?; + assets::import_files(&sources, &destination) +} + +#[tauri::command] +fn delete_asset(app: AppHandle, store: State<'_, Store>, name: String) -> Result<(), String> { + assets::delete_asset(&app, &store, &name) +} + +#[tauri::command] +fn import_into_target( + app: AppHandle, + store: State<'_, Store>, + path: String, + sources: Vec, +) -> Result, String> { + let target = resolve_target(&app, &store, &path)?; + assets::import_paths(&sources, &target.root) +} + +#[tauri::command] +fn import_into_folder( + app: AppHandle, + store: State<'_, Store>, + parent: String, + sources: Vec, +) -> Result, String> { + let destination = workspace_path(&app, &store, &parent)?; + assets::import_paths(&sources, &destination) +} + +#[tauri::command] +fn lsp_start( + app: AppHandle, + store: State<'_, Store>, + state: State<'_, LspState>, + path: String, +) -> Result { + let target = resolve_target(&app, &store, &path)?; + state.start(&app, &target.root, &target.entrypoint) +} + +#[tauri::command] +fn lsp_send(state: State<'_, LspState>, message: String) -> Result<(), String> { + state.send(&message) +} + +#[tauri::command] +fn lsp_stop(state: State<'_, LspState>) { + state.stop(); +} + +#[tauri::command] +fn lsp_running(state: State<'_, LspState>) -> bool { + state.is_running() +} + +#[tauri::command] +fn cloud_login( + app: AppHandle, + store: State<'_, Store>, + server_url: String, + email: String, + password: String, +) -> Result { + let server_url = server_url.trim_end_matches('/').to_string(); + let device_name = format!("Typst Desktop ({})", std::env::consts::OS); + let response = sync::login(&server_url, &email, &password, &device_name)?; + + let mut settings = load_settings(&app, &store)?; + settings.server_url = server_url; + settings.device_token = Some(response.token); + settings.account_email = Some(response.email.clone()); + settings.account_username = Some(response.username.clone()); + save_settings(&store, &settings)?; + + Ok(Account { + user_id: response.user_id, + username: response.username, + email: response.email, + }) +} + +#[tauri::command] +fn cloud_logout(app: AppHandle, store: State<'_, Store>) -> Result<(), String> { + let mut settings = load_settings(&app, &store)?; + if let Some(token) = &settings.device_token { + let _ = sync::logout(&settings.server_url, token); + } + + settings.device_token = None; + settings.account_email = None; + settings.account_username = None; + save_settings(&store, &settings) +} + +#[tauri::command] +fn cloud_account(app: AppHandle, store: State<'_, Store>) -> Result, String> { + let settings = load_settings(&app, &store)?; + let Some(token) = settings.device_token else { + return Ok(None); + }; + + Ok(sync::me(&settings.server_url, &token).ok()) +} + +#[tauri::command] +fn cloud_list_spaces(app: AppHandle, store: State<'_, Store>) -> Result, String> { + let (server_url, token) = cloud_credentials(&app, &store)?; + sync::list_spaces(&server_url, &token) +} + +#[tauri::command] +fn cloud_create_space(app: AppHandle, store: State<'_, Store>, name: String) -> Result { + let (server_url, token) = cloud_credentials(&app, &store)?; + sync::create_space(&server_url, &token, name.trim()) +} + +#[tauri::command] +fn cloud_delete_space(app: AppHandle, store: State<'_, Store>, space_id: String) -> Result<(), String> { + let (server_url, token) = cloud_credentials(&app, &store)?; + sync::delete_space(&server_url, &token, &space_id) +} + +#[tauri::command] +fn cloud_clone_space( + app: AppHandle, + store: State<'_, Store>, + space_id: String, + project_name: String, +) -> Result { + let (server_url, token) = cloud_credentials(&app, &store)?; + let project = project_name.trim().to_string(); + let dir = workspace_path(&app, &store, &project)?; + if dir.exists() { + return Err(format!("A project named '{}' already exists", project_name)); + } + sync::clone_space(&server_url, &token, &store, &project, &dir, &space_id) +} + +#[tauri::command] +fn cloud_link_project( + app: AppHandle, + store: State<'_, Store>, + project: String, + space_id: Option, +) -> Result { + let (server_url, token) = cloud_credentials(&app, &store)?; + let (dir, mut meta) = load_project(&app, &store, &project)?; + + let space_id = match space_id { + Some(id) if !id.trim().is_empty() => id, + _ => sync::create_space(&server_url, &token, &project)?.id, + }; + + meta.space_id = Some(space_id); + meta.base_hashes.clear(); + store.save_meta(&project, &meta)?; + + sync::push_project(&server_url, &token, &store, &project, &dir, &mut meta) +} + +#[tauri::command] +fn cloud_unlink_project(app: AppHandle, store: State<'_, Store>, project: String) -> Result<(), String> { + let (dir, mut meta) = load_project(&app, &store, &project)?; + meta.space_id = None; + meta.base_hashes.clear(); + meta.last_synced_at = None; + let _ = dir; + store.forget_project(&project) +} + +#[tauri::command] +fn cloud_push(app: AppHandle, store: State<'_, Store>, project: String) -> Result { + let (server_url, token) = cloud_credentials(&app, &store)?; + let (dir, mut meta) = load_project(&app, &store, &project)?; + sync::push_project(&server_url, &token, &store, &project, &dir, &mut meta) +} + +#[tauri::command] +fn cloud_pull(app: AppHandle, store: State<'_, Store>, project: String) -> Result { + let (server_url, token) = cloud_credentials(&app, &store)?; + let (dir, mut meta) = load_project(&app, &store, &project)?; + sync::pull_project(&server_url, &token, &store, &project, &dir, &mut meta) +} + +#[tauri::command] +fn cloud_sync(app: AppHandle, store: State<'_, Store>, project: String) -> Result { + let (server_url, token) = cloud_credentials(&app, &store)?; + let (dir, mut meta) = load_project(&app, &store, &project)?; + + let mut report = sync::pull_project(&server_url, &token, &store, &project, &dir, &mut meta)?; + if !report.conflicts.is_empty() { + return Ok(report); + } + + let pushed = sync::push_project(&server_url, &token, &store, &project, &dir, &mut meta)?; + report.pushed = pushed.pushed; + report.deleted_remote = pushed.deleted_remote; + report.conflicts = pushed.conflicts; + + Ok(report) +} + +#[derive(Deserialize)] +pub struct ResolutionRequest { + pub path: String, + pub content: String, + pub server_hash: String, +} + +#[tauri::command] +fn cloud_resolve_conflicts( + app: AppHandle, + store: State<'_, Store>, + project: String, + resolutions: Vec, +) -> Result { + let (server_url, token) = cloud_credentials(&app, &store)?; + let (dir, mut meta) = load_project(&app, &store, &project)?; + + for resolution in &resolutions { + sync::resolve_conflict( + &store, + &project, + &dir, + &mut meta, + &resolution.path, + &resolution.content, + &resolution.server_hash, + )?; + } + + sync::push_project(&server_url, &token, &store, &project, &dir, &mut meta) +} + +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .plugin(tauri_plugin_opener::init()) + .plugin(tauri_plugin_dialog::init()) + .setup(|app| { + let store = Store::open(&app.handle())?; + app.manage(store); + Ok(()) + }) + .manage(LspState::default()) + .on_window_event(|window, event| { + if matches!(event, tauri::WindowEvent::Destroyed) { + if let Some(state) = window.app_handle().try_state::() { + state.stop(); + } + } + }) + .invoke_handler(tauri::generate_handler![ + get_settings, + update_settings, + browse_workspace, + create_folder_entry, + create_document_entry, + create_project_entry, + rename_entry, + delete_entry, + upload_entry, + target_info, + read_target_file, + write_target_file, + set_target_entrypoint, + compile_target, + export_target, + thumbnail, + read_image, + clear_thumbnails, + list_assets, + list_font_families, + import_assets, + delete_asset, + import_into_target, + import_into_folder, + lsp_start, + lsp_send, + lsp_stop, + lsp_running, + cloud_login, + cloud_logout, + cloud_account, + cloud_list_spaces, + cloud_create_space, + cloud_delete_space, + cloud_clone_space, + cloud_link_project, + cloud_unlink_project, + cloud_push, + cloud_pull, + cloud_sync, + cloud_resolve_conflicts, + ]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/src-tauri/src/lsp.rs b/src-tauri/src/lsp.rs new file mode 100644 index 0000000..249d22b --- /dev/null +++ b/src-tauri/src/lsp.rs @@ -0,0 +1,153 @@ +use serde::Serialize; +use std::io::{BufReader, Read, Write}; +use std::path::Path; +use std::process::{Child, ChildStdin, Command, Stdio}; +use std::sync::Mutex; +use tauri::{AppHandle, Emitter}; + +pub const MESSAGE_EVENT: &str = "lsp://message"; +pub const CLOSED_EVENT: &str = "lsp://closed"; + +#[derive(Default)] +pub struct LspState { + inner: Mutex>, +} + +struct Session { + child: Child, + stdin: ChildStdin, +} + +#[derive(Serialize, Clone)] +pub struct LspHandle { + pub root_uri: String, + pub document_uri: String, +} + +fn file_uri(path: &Path) -> String { + let text = path.to_string_lossy().replace('\\', "/"); + if text.starts_with('/') { + format!("file://{}", text) + } else { + format!("file:///{}", text) + } +} + +impl LspState { + pub fn is_running(&self) -> bool { + self.inner.lock().map(|slot| slot.is_some()).unwrap_or(false) + } + + pub fn start( + &self, + app: &AppHandle, + root: &Path, + entrypoint: &str, + ) -> Result { + self.stop(); + + let mut child = Command::new("tinymist") + .arg("lsp") + .current_dir(root) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::null()) + .spawn() + .map_err(|e| { + format!( + "Could not start the Typst language server (tinymist): {}. \ + Install tinymist and make sure it is on your PATH.", + e + ) + })?; + + let stdin = child.stdin.take().ok_or("Language server has no stdin")?; + let stdout = child.stdout.take().ok_or("Language server has no stdout")?; + + let emitter = app.clone(); + std::thread::spawn(move || { + let mut reader = BufReader::new(stdout); + loop { + match read_message(&mut reader) { + Some(message) => { + let _ = emitter.emit(MESSAGE_EVENT, message); + } + None => { + let _ = emitter.emit(CLOSED_EVENT, ()); + break; + } + } + } + }); + + let handle = LspHandle { + root_uri: file_uri(root), + document_uri: file_uri(&root.join(entrypoint)), + }; + + let mut slot = self.inner.lock().map_err(|_| "Language server lock poisoned")?; + *slot = Some(Session { child, stdin }); + + Ok(handle) + } + + pub fn send(&self, message: &str) -> Result<(), String> { + let mut slot = self.inner.lock().map_err(|_| "Language server lock poisoned")?; + let session = slot.as_mut().ok_or("Language server is not running")?; + + session + .stdin + .write_all(format!("Content-Length: {}\r\n\r\n", message.len()).as_bytes()) + .map_err(|e| e.to_string())?; + session + .stdin + .write_all(message.as_bytes()) + .map_err(|e| e.to_string())?; + session.stdin.flush().map_err(|e| e.to_string()) + } + + pub fn stop(&self) { + if let Ok(mut slot) = self.inner.lock() { + if let Some(mut session) = slot.take() { + let _ = session.child.kill(); + let _ = session.child.wait(); + } + } + } +} + +fn read_message(reader: &mut BufReader) -> Option { + let mut header = String::new(); + + loop { + let mut byte = [0u8; 1]; + if reader.read_exact(&mut byte).is_err() { + return None; + } + header.push(byte[0] as char); + if header.ends_with("\r\n\r\n") { + break; + } + if header.len() > 8192 { + return None; + } + } + + let mut content_length = 0usize; + for line in header.split("\r\n") { + if let Some(value) = line.strip_prefix("Content-Length: ") { + content_length = value.trim().parse().unwrap_or(0); + } + } + + if content_length == 0 { + return Some(String::new()); + } + + let mut body = vec![0u8; content_length]; + if reader.read_exact(&mut body).is_err() { + return None; + } + + String::from_utf8(body).ok() +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs new file mode 100644 index 0000000..bc1ea6d --- /dev/null +++ b/src-tauri/src/main.rs @@ -0,0 +1,6 @@ +// Prevents additional console window on Windows in release, DO NOT REMOVE!! +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + typst_desktop_lib::run() +} diff --git a/src-tauri/src/sync.rs b/src-tauri/src/sync.rs new file mode 100644 index 0000000..f19e38f --- /dev/null +++ b/src-tauri/src/sync.rs @@ -0,0 +1,572 @@ +use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _}; +use serde::{Deserialize, Serialize}; +use std::collections::HashSet; +use std::path::Path; + +use crate::workspace::{ + collect_files, content_hash, is_text_file, project_file_path, ProjectMeta, +}; +use crate::db::Store; + +const REQUEST_TIMEOUT_SECS: u64 = 30; + +fn agent() -> ureq::Agent { + ureq::AgentBuilder::new() + .timeout(std::time::Duration::from_secs(REQUEST_TIMEOUT_SECS)) + .build() +} + +fn endpoint(server_url: &str, path: &str) -> String { + format!("{}/api/desktop{}", server_url.trim_end_matches('/'), path) +} + +fn describe(error: ureq::Error) -> String { + match error { + ureq::Error::Status(code, response) => { + let body = response.into_string().unwrap_or_default(); + if body.is_empty() { + format!("Server returned {}", code) + } else { + body + } + } + other => other.to_string(), + } +} + +#[derive(Deserialize, Serialize, Clone)] +pub struct Account { + pub user_id: String, + pub username: String, + pub email: String, +} + +#[derive(Deserialize)] +pub struct LoginResponse { + pub token: String, + pub user_id: String, + pub username: String, + pub email: String, +} + +pub fn login( + server_url: &str, + email: &str, + password: &str, + device_name: &str, +) -> Result { + agent() + .post(&endpoint(server_url, "/auth/login")) + .send_json(ureq::json!({ + "email": email, + "password": password, + "device_name": device_name, + })) + .map_err(describe)? + .into_json::() + .map_err(|e| e.to_string()) +} + +pub fn logout(server_url: &str, token: &str) -> Result<(), String> { + agent() + .post(&endpoint(server_url, "/auth/logout")) + .set("Authorization", &format!("Bearer {}", token)) + .call() + .map_err(describe)?; + Ok(()) +} + +pub fn me(server_url: &str, token: &str) -> Result { + agent() + .get(&endpoint(server_url, "/auth/me")) + .set("Authorization", &format!("Bearer {}", token)) + .call() + .map_err(describe)? + .into_json::() + .map_err(|e| e.to_string()) +} + +#[derive(Deserialize, Serialize, Clone)] +pub struct SpaceSummary { + pub id: String, + pub name: String, + pub entrypoint: String, + pub role: String, + pub updated_at: String, +} + +pub fn list_spaces(server_url: &str, token: &str) -> Result, String> { + agent() + .get(&endpoint(server_url, "/spaces")) + .set("Authorization", &format!("Bearer {}", token)) + .call() + .map_err(describe)? + .into_json::>() + .map_err(|e| e.to_string()) +} + +pub fn create_space(server_url: &str, token: &str, name: &str) -> Result { + agent() + .post(&endpoint(server_url, "/spaces")) + .set("Authorization", &format!("Bearer {}", token)) + .send_json(ureq::json!({ "name": name })) + .map_err(describe)? + .into_json::() + .map_err(|e| e.to_string()) +} + +pub fn delete_space(server_url: &str, token: &str, space_id: &str) -> Result<(), String> { + agent() + .delete(&endpoint(server_url, &format!("/spaces/{}", space_id))) + .set("Authorization", &format!("Bearer {}", token)) + .call() + .map_err(describe)?; + Ok(()) +} + +#[derive(Deserialize)] +pub struct ManifestEntry { + pub path: String, + pub kind: String, + pub hash: String, +} + +#[derive(Deserialize)] +pub struct SpaceManifest { + pub space_id: String, + pub name: String, + pub entrypoint: String, + pub files: Vec, +} + +pub fn get_manifest( + server_url: &str, + token: &str, + space_id: &str, +) -> Result { + agent() + .get(&endpoint( + server_url, + &format!("/spaces/{}/manifest", space_id), + )) + .set("Authorization", &format!("Bearer {}", token)) + .call() + .map_err(describe)? + .into_json::() + .map_err(|e| e.to_string()) +} + +#[derive(Deserialize)] +pub struct FileContent { + pub path: String, + pub kind: String, + pub hash: String, + pub encoding: String, + pub content: String, +} + +impl FileContent { + pub fn bytes(&self) -> Result, String> { + if self.encoding == "base64" { + BASE64 + .decode(self.content.as_bytes()) + .map_err(|e| format!("Invalid base64 from server: {}", e)) + } else { + Ok(self.content.clone().into_bytes()) + } + } +} + +pub fn pull_file( + server_url: &str, + token: &str, + space_id: &str, + path: &str, +) -> Result { + agent() + .get(&endpoint(server_url, &format!("/spaces/{}/file", space_id))) + .query("path", path) + .set("Authorization", &format!("Bearer {}", token)) + .call() + .map_err(describe)? + .into_json::() + .map_err(|e| e.to_string()) +} + +#[derive(Deserialize)] +struct ConflictBody { + server_hash: String, + encoding: String, + server_content: String, +} + +pub enum PushResult { + Applied, + Conflict { server_hash: String, server_text: String }, +} + +pub fn push_file( + server_url: &str, + token: &str, + space_id: &str, + path: &str, + bytes: &[u8], + base_hash: Option<&str>, +) -> Result { + let (encoding, content) = if is_text_file(path) { + ("utf8", String::from_utf8_lossy(bytes).to_string()) + } else { + ("base64", BASE64.encode(bytes)) + }; + + let response = agent() + .put(&endpoint(server_url, &format!("/spaces/{}/file", space_id))) + .set("Authorization", &format!("Bearer {}", token)) + .send_json(ureq::json!({ + "path": path, + "content": content, + "encoding": encoding, + "base_hash": base_hash, + })); + + match response { + Ok(_) => Ok(PushResult::Applied), + Err(ureq::Error::Status(409, body)) => { + let conflict = body + .into_json::() + .map_err(|e| format!("Malformed conflict response: {}", e))?; + let server_text = if conflict.encoding == "base64" { + String::new() + } else { + conflict.server_content + }; + Ok(PushResult::Conflict { + server_hash: conflict.server_hash, + server_text, + }) + } + Err(other) => Err(describe(other)), + } +} + +pub fn delete_remote_file( + server_url: &str, + token: &str, + space_id: &str, + path: &str, +) -> Result<(), String> { + let response = agent() + .delete(&endpoint(server_url, &format!("/spaces/{}/file", space_id))) + .query("path", path) + .set("Authorization", &format!("Bearer {}", token)) + .call(); + + match response { + Ok(_) => Ok(()), + Err(ureq::Error::Status(404, _)) => Ok(()), + Err(other) => Err(describe(other)), + } +} + +#[derive(Serialize, Clone)] +pub struct Conflict { + pub path: String, + pub local_text: String, + pub remote_text: String, + pub merged_text: String, + pub server_hash: String, + pub auto_merged: bool, + pub binary: bool, +} + +#[derive(Serialize, Default)] +pub struct SyncReport { + pub pushed: Vec, + pub pulled: Vec, + pub deleted_local: Vec, + pub deleted_remote: Vec, + pub merged: Vec, + pub conflicts: Vec, +} + +fn read_local(project_dir: &Path, relative: &str) -> Result, String> { + let full = project_file_path(project_dir, relative)?; + std::fs::read(&full).map_err(|e| e.to_string()) +} + +fn write_local(project_dir: &Path, relative: &str, bytes: &[u8]) -> Result<(), String> { + let full = project_file_path(project_dir, relative)?; + if let Some(parent) = full.parent() { + std::fs::create_dir_all(parent).map_err(|e| e.to_string())?; + } + std::fs::write(&full, bytes).map_err(|e| e.to_string()) +} + +pub fn pull_project( + server_url: &str, + token: &str, + store: &Store, + project: &str, + project_dir: &Path, + meta: &mut ProjectMeta, +) -> Result { + let space_id = meta + .space_id + .clone() + .ok_or("Project is not linked to a cloud space")?; + + let manifest = get_manifest(server_url, token, &space_id)?; + let mut report = SyncReport::default(); + + let local_files: HashSet = collect_files(project_dir)?.into_iter().collect(); + let mut remote_paths = HashSet::new(); + + for entry in &manifest.files { + remote_paths.insert(entry.path.clone()); + + let base = meta.base_hashes.get(&entry.path).cloned(); + let local_exists = local_files.contains(&entry.path); + + if !local_exists { + if base.is_some() { + continue; + } + let remote = pull_file(server_url, token, &space_id, &entry.path)?; + write_local(project_dir, &entry.path, &remote.bytes()?)?; + meta.base_hashes.insert(entry.path.clone(), remote.hash); + report.pulled.push(entry.path.clone()); + continue; + } + + let local_bytes = read_local(project_dir, &entry.path)?; + let local_hash = content_hash(&local_bytes); + + if local_hash == entry.hash { + meta.base_hashes.insert(entry.path.clone(), entry.hash.clone()); + continue; + } + + if base.as_deref() == Some(entry.hash.as_str()) { + continue; + } + + let remote = pull_file(server_url, token, &space_id, &entry.path)?; + let remote_bytes = remote.bytes()?; + + if base.as_deref() == Some(local_hash.as_str()) { + write_local(project_dir, &entry.path, &remote_bytes)?; + meta.base_hashes.insert(entry.path.clone(), remote.hash); + report.pulled.push(entry.path.clone()); + continue; + } + + if !is_text_file(&entry.path) || remote.kind == "binary" { + report.conflicts.push(Conflict { + path: entry.path.clone(), + local_text: String::new(), + remote_text: String::new(), + merged_text: String::new(), + server_hash: remote.hash, + auto_merged: false, + binary: true, + }); + continue; + } + + let local_text = String::from_utf8_lossy(&local_bytes).to_string(); + let remote_text = String::from_utf8_lossy(&remote_bytes).to_string(); + let base_text = read_base_snapshot(store, project, &entry.path); + + match diffy::merge(&base_text, &local_text, &remote_text) { + Ok(merged) => { + write_local(project_dir, &entry.path, merged.as_bytes())?; + meta.base_hashes + .insert(entry.path.clone(), content_hash(merged.as_bytes())); + report.merged.push(entry.path.clone()); + } + Err(conflicted) => { + report.conflicts.push(Conflict { + path: entry.path.clone(), + local_text, + remote_text, + merged_text: conflicted, + server_hash: remote.hash, + auto_merged: false, + binary: false, + }); + } + } + } + + let vanished: Vec = meta + .base_hashes + .keys() + .filter(|path| !remote_paths.contains(*path) && local_files.contains(*path)) + .cloned() + .collect(); + + for path in vanished { + let local_bytes = read_local(project_dir, &path)?; + let base = meta.base_hashes.get(&path).cloned().unwrap_or_default(); + if content_hash(&local_bytes) == base { + let full = project_file_path(project_dir, &path)?; + let _ = std::fs::remove_file(full); + meta.base_hashes.remove(&path); + report.deleted_local.push(path); + } + } + + meta.entrypoint = manifest.entrypoint; + meta.last_synced_at = Some(chrono::Utc::now().to_rfc3339()); + store.save_meta(project, meta)?; + save_base_snapshots(store, project, project_dir, meta)?; + + Ok(report) +} + +pub fn push_project( + server_url: &str, + token: &str, + store: &Store, + project: &str, + project_dir: &Path, + meta: &mut ProjectMeta, +) -> Result { + let space_id = meta + .space_id + .clone() + .ok_or("Project is not linked to a cloud space")?; + + let mut report = SyncReport::default(); + let local_files = collect_files(project_dir)?; + let local_set: HashSet = local_files.iter().cloned().collect(); + + for path in &local_files { + let bytes = read_local(project_dir, path)?; + let hash = content_hash(&bytes); + let base = meta.base_hashes.get(path).cloned(); + + if base.as_deref() == Some(hash.as_str()) { + continue; + } + + match push_file(server_url, token, &space_id, path, &bytes, base.as_deref())? { + PushResult::Applied => { + meta.base_hashes.insert(path.clone(), hash); + report.pushed.push(path.clone()); + } + PushResult::Conflict { + server_hash, + server_text, + } => { + let binary = !is_text_file(path); + report.conflicts.push(Conflict { + path: path.clone(), + local_text: if binary { + String::new() + } else { + String::from_utf8_lossy(&bytes).to_string() + }, + remote_text: server_text.clone(), + merged_text: server_text, + server_hash, + auto_merged: false, + binary, + }); + } + } + } + + let removed: Vec = meta + .base_hashes + .keys() + .filter(|path| !local_set.contains(*path)) + .cloned() + .collect(); + + for path in removed { + delete_remote_file(server_url, token, &space_id, &path)?; + meta.base_hashes.remove(&path); + report.deleted_remote.push(path); + } + + meta.last_synced_at = Some(chrono::Utc::now().to_rfc3339()); + store.save_meta(project, meta)?; + save_base_snapshots(store, project, project_dir, meta)?; + + Ok(report) +} + +pub fn clone_space( + server_url: &str, + token: &str, + store: &Store, + project: &str, + project_dir: &Path, + space_id: &str, +) -> Result { + std::fs::create_dir_all(project_dir).map_err(|e| e.to_string())?; + + let manifest = get_manifest(server_url, token, space_id)?; + let mut meta = store.meta(project)?; + meta.space_id = Some(space_id.to_string()); + meta.entrypoint = manifest.entrypoint.clone(); + + let mut report = SyncReport::default(); + + for entry in &manifest.files { + let remote = pull_file(server_url, token, space_id, &entry.path)?; + write_local(project_dir, &entry.path, &remote.bytes()?)?; + meta.base_hashes.insert(entry.path.clone(), remote.hash); + report.pulled.push(entry.path.clone()); + } + + meta.last_synced_at = Some(chrono::Utc::now().to_rfc3339()); + store.save_meta(project, &meta)?; + save_base_snapshots(store, project, project_dir, &meta)?; + + Ok(report) +} + +pub fn save_base_snapshots( + store: &Store, + project: &str, + project_dir: &Path, + meta: &ProjectMeta, +) -> Result<(), String> { + for (path, base) in &meta.base_hashes { + let full = project_file_path(project_dir, path)?; + let Ok(bytes) = std::fs::read(&full) else { + continue; + }; + if content_hash(&bytes) == *base { + store.save_base_snapshot(project, path, base, &bytes)?; + } + } + + Ok(()) +} + +fn read_base_snapshot(store: &Store, project: &str, relative: &str) -> String { + store + .base_snapshot(project, relative) + .ok() + .flatten() + .map(|bytes| String::from_utf8_lossy(&bytes).to_string()) + .unwrap_or_default() +} + +pub fn resolve_conflict( + store: &Store, + project: &str, + project_dir: &Path, + meta: &mut ProjectMeta, + path: &str, + content: &str, + server_hash: &str, +) -> Result<(), String> { + write_local(project_dir, path, content.as_bytes())?; + meta.base_hashes + .insert(path.to_string(), server_hash.to_string()); + store.save_meta(project, meta) +} diff --git a/src-tauri/src/thumbnails.rs b/src-tauri/src/thumbnails.rs new file mode 100644 index 0000000..b8af184 --- /dev/null +++ b/src-tauri/src/thumbnails.rs @@ -0,0 +1,160 @@ +use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _}; +use serde::Serialize; +use std::path::Path; +use std::time::UNIX_EPOCH; +use tauri::AppHandle; + +use crate::assets::is_image; +use crate::compiler; +use crate::db::Store; +use crate::workspace::{read_target_files, resolve_target, workspace_path}; + +const MAX_IMAGE_BYTES: u64 = 8 * 1024 * 1024; +const MAX_VIEWER_BYTES: u64 = 64 * 1024 * 1024; + +#[derive(Serialize)] +pub struct Thumbnail { + pub kind: String, + pub data: String, +} + +fn modified_seconds(path: &Path) -> i64 { + std::fs::metadata(path) + .and_then(|meta| meta.modified()) + .ok() + .and_then(|time| time.duration_since(UNIX_EPOCH).ok()) + .map(|elapsed| elapsed.as_secs() as i64) + .unwrap_or(0) +} + +fn mime_for(name: &str) -> &'static str { + let lower = name.to_lowercase(); + if lower.ends_with(".png") { + "image/png" + } else if lower.ends_with(".gif") { + "image/gif" + } else if lower.ends_with(".svg") { + "image/svg+xml" + } else if lower.ends_with(".webp") { + "image/webp" + } else { + "image/jpeg" + } +} + +#[derive(Serialize)] +pub struct ImageData { + pub name: String, + pub data: String, + pub size: u64, + pub width: Option, + pub height: Option, +} + +pub fn read_image(app: &AppHandle, store: &Store, path: &str) -> Result { + let full = workspace_path(app, store, path)?; + let name = full + .file_name() + .map(|n| n.to_string_lossy().to_string()) + .unwrap_or_default(); + + if !is_image(&name) { + return Err("Not an image file".to_string()); + } + + let size = std::fs::metadata(&full).map(|m| m.len()).unwrap_or(0); + if size > MAX_VIEWER_BYTES { + return Err("Image is too large to open".to_string()); + } + + let bytes = std::fs::read(&full).map_err(|e| e.to_string())?; + let (width, height) = image_dimensions(&bytes); + + Ok(ImageData { + data: format!("data:{};base64,{}", mime_for(&name), BASE64.encode(&bytes)), + name, + size, + width, + height, + }) +} + +fn image_dimensions(bytes: &[u8]) -> (Option, Option) { + if bytes.len() > 24 && bytes.starts_with(&[0x89, b'P', b'N', b'G']) { + let width = u32::from_be_bytes([bytes[16], bytes[17], bytes[18], bytes[19]]); + let height = u32::from_be_bytes([bytes[20], bytes[21], bytes[22], bytes[23]]); + return (Some(width), Some(height)); + } + + if bytes.len() > 10 && bytes.starts_with(&[0xFF, 0xD8]) { + let mut index = 2usize; + while index + 9 < bytes.len() { + if bytes[index] != 0xFF { + index += 1; + continue; + } + let marker = bytes[index + 1]; + if (0xC0..=0xCF).contains(&marker) && marker != 0xC4 && marker != 0xC8 && marker != 0xCC + { + let height = u16::from_be_bytes([bytes[index + 5], bytes[index + 6]]) as u32; + let width = u16::from_be_bytes([bytes[index + 7], bytes[index + 8]]) as u32; + return (Some(width), Some(height)); + } + let length = u16::from_be_bytes([bytes[index + 2], bytes[index + 3]]) as usize; + index += 2 + length; + } + } + + (None, None) +} + +pub fn thumbnail(app: &AppHandle, store: &Store, path: &str) -> Result { + let full = workspace_path(app, store, path)?; + let name = full + .file_name() + .map(|n| n.to_string_lossy().to_string()) + .unwrap_or_default(); + + let image = is_image(&name); + if !image && !name.to_lowercase().ends_with(".typ") { + return Err("No preview available".to_string()); + } + + let modified = modified_seconds(&full); + + if let Some((kind, data)) = store.thumbnail(path, modified)? { + return Ok(Thumbnail { kind, data }); + } + + let thumbnail = if image { + let size = std::fs::metadata(&full).map(|m| m.len()).unwrap_or(0); + if size > MAX_IMAGE_BYTES { + return Err("Image is too large to preview".to_string()); + } + let bytes = std::fs::read(&full).map_err(|e| e.to_string())?; + Thumbnail { + kind: "image".to_string(), + data: format!("data:{};base64,{}", mime_for(&name), BASE64.encode(&bytes)), + } + } else { + let target = resolve_target(app, store, path)?; + let files = read_target_files(app, store, &target)?; + + let result = compiler::compile_to_svg(target.entrypoint, files) + .map_err(|_| "Document does not compile".to_string())?; + + let svg = result + .pages + .into_iter() + .next() + .ok_or("Document has no pages")?; + + Thumbnail { + kind: "svg".to_string(), + data: svg, + } + }; + + store.save_thumbnail(path, &thumbnail.kind, &thumbnail.data, modified)?; + Ok(thumbnail) +} diff --git a/src-tauri/src/workspace.rs b/src-tauri/src/workspace.rs new file mode 100644 index 0000000..258d0bb --- /dev/null +++ b/src-tauri/src/workspace.rs @@ -0,0 +1,407 @@ +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use std::collections::HashMap; +use std::path::{Path, PathBuf}; +use tauri::{AppHandle, Manager}; + +use crate::db::Store; +use walkdir::WalkDir; + +pub const PROJECT_META_FILE: &str = ".typst-desktop.json"; + +const TEXT_EXTENSIONS: [&str; 10] = [ + "typ", "toml", "bib", "csl", "yml", "yaml", "json", "md", "txt", "csv", +]; + +pub fn is_text_file(path: &str) -> bool { + Path::new(path) + .extension() + .and_then(|ext| ext.to_str()) + .map(|ext| TEXT_EXTENSIONS.contains(&ext.to_lowercase().as_str())) + .unwrap_or(false) +} + +pub fn content_hash(bytes: &[u8]) -> String { + format!("{:x}", Sha256::digest(bytes)) +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct Settings { + pub workspace_root: String, + pub server_url: String, + #[serde(default)] + pub device_token: Option, + #[serde(default)] + pub account_email: Option, + #[serde(default)] + pub account_username: Option, +} + +impl Settings { + pub fn fallback(app: &AppHandle) -> Self { + let home = app + .path() + .home_dir() + .unwrap_or_else(|_| PathBuf::from(".")); + Settings { + workspace_root: home.join("typst").to_string_lossy().to_string(), + server_url: "http://localhost:3000".to_string(), + device_token: None, + account_email: None, + account_username: None, + } + } +} + +pub fn load_settings(app: &AppHandle, store: &Store) -> Result { + match store.settings()? { + Some(settings) => Ok(settings), + None => { + let settings = Settings::fallback(app); + store.save_settings(&settings)?; + Ok(settings) + } + } +} + +pub fn save_settings(store: &Store, settings: &Settings) -> Result<(), String> { + store.save_settings(settings) +} + +pub fn workspace_root(app: &AppHandle, store: &Store) -> Result { + let settings = load_settings(app, store)?; + let root = PathBuf::from(&settings.workspace_root); + std::fs::create_dir_all(&root) + .map_err(|e| format!("Cannot create workspace directory: {}", e))?; + Ok(root) +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct ProjectMeta { + pub entrypoint: String, + pub space_id: Option, + pub last_synced_at: Option, + pub base_hashes: HashMap, +} + +impl Default for ProjectMeta { + fn default() -> Self { + ProjectMeta { + entrypoint: "main.typ".to_string(), + space_id: None, + last_synced_at: None, + base_hashes: HashMap::new(), + } + } +} + +pub fn workspace_path(app: &AppHandle, store: &Store, relative: &str) -> Result { + let root = workspace_root(app, store)?; + if relative.is_empty() { + return Ok(root); + } + project_file_path(&root, relative) +} + +pub fn is_project_dir(path: &Path) -> bool { + path.join(PROJECT_META_FILE).exists() || path.join("typst.toml").exists() +} + +pub fn is_typst_file(path: &str) -> bool { + path.to_lowercase().ends_with(".typ") +} + +#[derive(Serialize)] +pub struct BrowseEntry { + pub name: String, + pub path: String, + pub kind: String, + pub size: u64, + pub modified: Option, + pub space_id: Option, + pub last_synced_at: Option, + pub child_count: usize, +} + +fn modified_at(path: &Path) -> Option { + let modified = std::fs::metadata(path).ok()?.modified().ok()?; + let datetime: chrono::DateTime = modified.into(); + Some(datetime.to_rfc3339()) +} + +pub fn browse(app: &AppHandle, store: &Store, relative: &str) -> Result, String> { + let dir = workspace_path(app, store, relative)?; + if !dir.is_dir() { + return Err(format!("'{}' is not a folder", relative)); + } + + let prefix = if relative.is_empty() { + String::new() + } else { + format!("{}/", relative.trim_end_matches('/')) + }; + + let mut entries = Vec::new(); + + for entry in std::fs::read_dir(&dir).map_err(|e| e.to_string())? { + let entry = entry.map_err(|e| e.to_string())?; + let name = entry.file_name().to_string_lossy().to_string(); + if name.starts_with('.') { + continue; + } + + let path = format!("{}{}", prefix, name); + let full = entry.path(); + + if full.is_dir() { + let project = is_project_dir(&full) || store.has_project(&path)?; + let meta = if project { + Some(store.meta(&path)?) + } else { + None + }; + let child_count = std::fs::read_dir(&full) + .map(|children| { + children + .filter_map(|child| child.ok()) + .filter(|child| { + !child.file_name().to_string_lossy().starts_with('.') + }) + .count() + }) + .unwrap_or(0); + + entries.push(BrowseEntry { + name, + path, + kind: if project { "project" } else { "folder" }.to_string(), + size: 0, + modified: modified_at(&full), + space_id: meta.as_ref().and_then(|m| m.space_id.clone()), + last_synced_at: meta.as_ref().and_then(|m| m.last_synced_at.clone()), + child_count, + }); + } else { + let kind = if is_typst_file(&name) { "document" } else { "file" }; + entries.push(BrowseEntry { + name, + path, + kind: kind.to_string(), + size: std::fs::metadata(&full).map(|m| m.len()).unwrap_or(0), + modified: modified_at(&full), + space_id: None, + last_synced_at: None, + child_count: 0, + }); + } + } + + entries.sort_by(|a, b| { + let rank = |kind: &str| match kind { + "project" => 0, + "folder" => 1, + "document" => 2, + _ => 3, + }; + rank(&a.kind) + .cmp(&rank(&b.kind)) + .then_with(|| a.name.to_lowercase().cmp(&b.name.to_lowercase())) + }); + + Ok(entries) +} + +pub struct Target { + pub root: PathBuf, + pub entrypoint: String, + pub standalone: bool, +} + +pub fn resolve_target(app: &AppHandle, store: &Store, path: &str) -> Result { + let full = workspace_path(app, store, path)?; + + if full.is_dir() { + let meta = store.meta(path)?; + return Ok(Target { + root: full, + entrypoint: meta.entrypoint, + standalone: false, + }); + } + + if !full.is_file() { + return Err(format!("'{}' does not exist", path)); + } + + let parent = full + .parent() + .ok_or("File has no parent folder")? + .to_path_buf(); + let name = full + .file_name() + .map(|n| n.to_string_lossy().to_string()) + .ok_or("File has no name")?; + + Ok(Target { + root: parent, + entrypoint: name, + standalone: true, + }) +} + +pub fn read_target_files( + app: &AppHandle, + store: &Store, + target: &Target, +) -> Result>, String> { + let mut map = crate::assets::asset_files(app, store); + + if !target.standalone { + for (path, bytes) in read_all_files(&target.root)? { + map.insert(path, bytes); + } + return Ok(map); + } + + collect_loose_files(&target.root, "", &mut map)?; + Ok(map) +} + +fn collect_loose_files( + dir: &Path, + prefix: &str, + map: &mut HashMap>, +) -> Result<(), String> { + for entry in std::fs::read_dir(dir).map_err(|e| e.to_string())? { + let entry = entry.map_err(|e| e.to_string())?; + let name = entry.file_name().to_string_lossy().to_string(); + if name.starts_with('.') { + continue; + } + + let path = entry.path(); + let key = if prefix.is_empty() { + name + } else { + format!("{}/{}", prefix, name) + }; + + if path.is_dir() { + if is_project_dir(&path) { + continue; + } + collect_loose_files(&path, &key, map)?; + } else if let Ok(bytes) = std::fs::read(&path) { + map.insert(key, bytes); + } + } + + Ok(()) +} + +pub fn project_file_path(project_dir: &Path, relative: &str) -> Result { + if relative.is_empty() { + return Err("Path cannot be empty".to_string()); + } + + let mut resolved = project_dir.to_path_buf(); + for component in relative.replace('\\', "/").split('/') { + if component.is_empty() || component == "." { + continue; + } + if component == ".." { + return Err("Path cannot escape the project".to_string()); + } + resolved.push(component); + } + + if !resolved.starts_with(project_dir) { + return Err("Path cannot escape the project".to_string()); + } + + Ok(resolved) +} + +pub fn relative_path(project_dir: &Path, path: &Path) -> Option { + path.strip_prefix(project_dir) + .ok() + .map(|rest| rest.to_string_lossy().replace('\\', "/")) +} + +pub fn collect_files(project_dir: &Path) -> Result, String> { + let mut files = Vec::new(); + + for entry in WalkDir::new(project_dir).into_iter().filter_map(|e| e.ok()) { + if !entry.file_type().is_file() { + continue; + } + let Some(relative) = relative_path(project_dir, entry.path()) else { + continue; + }; + if relative == PROJECT_META_FILE || relative.starts_with('.') { + continue; + } + files.push(relative); + } + + files.sort(); + Ok(files) +} + +pub fn read_all_files(project_dir: &Path) -> Result>, String> { + let mut map = HashMap::new(); + for relative in collect_files(project_dir)? { + let full = project_file_path(project_dir, &relative)?; + let bytes = std::fs::read(&full).map_err(|e| e.to_string())?; + map.insert(relative, bytes); + } + Ok(map) +} + +#[derive(Serialize)] +pub struct FileEntry { + pub path: String, + pub name: String, + pub is_text: bool, + pub size: u64, +} + +pub fn list_files(project_dir: &Path) -> Result, String> { + let mut entries = Vec::new(); + for relative in collect_files(project_dir)? { + let full = project_file_path(project_dir, &relative)?; + let size = std::fs::metadata(&full).map(|m| m.len()).unwrap_or(0); + let name = relative + .rsplit('/') + .next() + .unwrap_or(&relative) + .to_string(); + entries.push(FileEntry { + is_text: is_text_file(&relative), + path: relative, + name, + size, + }); + } + Ok(entries) +} + +pub const NEW_PROJECT_MAIN: &str = "= New Project\n\nStart writing here.\n"; + +pub fn manifest_for(name: &str) -> String { + let slug: String = name + .to_lowercase() + .chars() + .map(|c| if c.is_ascii_alphanumeric() { c } else { '-' }) + .collect(); + let slug = slug.trim_matches('-').to_string(); + let slug = if slug.is_empty() { + "my-project".to_string() + } else { + slug + }; + + format!( + "[package]\nname = \"{slug}\"\nversion = \"0.1.0\"\nentrypoint = \"main.typ\"\nauthors = [\"Anonymous\"]\nlicense = \"MIT\"\ndescription = \"\"\n" + ) +} diff --git a/src-tauri/src/world.rs b/src-tauri/src/world.rs new file mode 100644 index 0000000..50a4421 --- /dev/null +++ b/src-tauri/src/world.rs @@ -0,0 +1,138 @@ +use chrono::Datelike; +use std::collections::HashMap; + +use typst::diag::{FileError, FileResult}; +use typst::foundations::{Bytes, Datetime, Duration}; +use typst::syntax::{FileId, RootedPath, Source, VirtualPath, VirtualRoot}; +use typst::text::{Font, FontBook}; +use typst::World; +use typst::{Library, LibraryExt}; +use typst_kit::downloader::SystemDownloader; +use typst_kit::packages::SystemPackages; + +pub struct ProjectWorld { + library: typst::utils::LazyHash, + main: FileId, + files: HashMap>, + book: typst::utils::LazyHash, + fonts: Vec, + packages: SystemPackages, +} + +fn normalize_path(path: &str) -> String { + path.trim_start_matches('/').replace('\\', "/") +} + +impl ProjectWorld { + pub fn new(entrypoint: String, files: HashMap>, enable_html: bool) -> Self { + let main = FileId::new(RootedPath::new( + VirtualRoot::Project, + VirtualPath::new(&entrypoint).unwrap_or_else(|_| VirtualPath::new("main.typ").unwrap()), + )); + + let downloader = SystemDownloader::new("TypstDesktop (typst-kit)"); + let packages = SystemPackages::new(downloader); + + let mut book = FontBook::new(); + let mut fonts = Vec::new(); + + for data in typst_assets::fonts() { + let buffer = Bytes::new(data); + for font in Font::iter(buffer) { + book.push(font.info().clone()); + fonts.push(font); + } + } + + for (name, data) in &files { + let lower = name.to_lowercase(); + if [".ttf", ".otf", ".ttc", ".otc"] + .iter() + .any(|ext| lower.ends_with(ext)) + { + for font in Font::iter(Bytes::new(data.clone())) { + book.push(font.info().clone()); + fonts.push(font); + } + } + } + + let library = if enable_html { + Library::builder() + .with_features([typst::Feature::Html].into_iter().collect()) + .build() + } else { + Library::builder().build() + }; + + Self { + library: typst::utils::LazyHash::new(library), + main, + files, + book: typst::utils::LazyHash::new(book), + fonts, + packages, + } + } + + fn load_bytes(&self, id: FileId) -> FileResult> { + let path = normalize_path(id.vpath().get_without_slash()); + + if let VirtualRoot::Package(package) = id.root() { + let root = self + .packages + .obtain(package) + .map_err(|e| FileError::Other(Some(e.to_string().into())))?; + return root.load(id.vpath()).map(|bytes| bytes.to_vec()); + } + + self.files + .get(&path) + .cloned() + .ok_or_else(|| FileError::NotFound(path.into())) + } +} + +impl World for ProjectWorld { + fn library(&self) -> &typst::utils::LazyHash { + &self.library + } + + fn book(&self) -> &typst::utils::LazyHash { + &self.book + } + + fn main(&self) -> FileId { + self.main + } + + fn source(&self, id: FileId) -> FileResult { + let data = self.load_bytes(id)?; + let text = std::str::from_utf8(&data) + .map_err(|_| FileError::InvalidUtf8)? + .to_owned(); + Ok(Source::new(id, text)) + } + + fn file(&self, id: FileId) -> FileResult { + let data = self.load_bytes(id)?; + Ok(Bytes::new(data)) + } + + fn font(&self, index: usize) -> Option { + self.fonts.get(index).cloned() + } + + fn today(&self, offset: Option) -> Option { + let now = chrono::Local::now(); + let date = if let Some(offset) = offset { + let offset_secs = offset.hours() as i32 * 3600; + let offset_chrono = chrono::FixedOffset::east_opt(offset_secs)?; + now.with_timezone(&offset_chrono).date_naive() + } else { + now.date_naive() + }; + + Datetime::from_ymd(date.year(), date.month() as u8, date.day() as u8) + } +} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json new file mode 100644 index 0000000..639d76f --- /dev/null +++ b/src-tauri/tauri.conf.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://schema.tauri.app/config/2", + "productName": "typst-desktop", + "version": "0.1.0", + "identifier": "co.sirblob.typst-desktop", + "build": { + "beforeDevCommand": "bun run dev", + "devUrl": "http://localhost:1420", + "beforeBuildCommand": "bun run build", + "frontendDist": "../build" + }, + "app": { + "windows": [ + { + "title": "Typst Desktop", + "width": 1280, + "height": 800, + "minWidth": 900, + "minHeight": 600, + "decorations": false + } + ], + "security": { + "csp": null + } + }, + "bundle": { + "active": true, + "targets": "all", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ] + } +} diff --git a/src/app.css b/src/app.css new file mode 100644 index 0000000..501c045 --- /dev/null +++ b/src/app.css @@ -0,0 +1,73 @@ +@import "tailwindcss"; + +@theme { + --color-surface: #ffffff; + --color-surface-muted: #f6f7f9; + --color-surface-sunken: #eceef1; + --color-line: #dfe2e7; + --color-ink: #14161a; + --color-ink-muted: #5f6672; + --color-accent: #3b6cf6; + --color-accent-soft: #e8eefe; + --color-danger: #d5382f; + --color-success: #1f8a4c; +} + +:root { + color-scheme: light; +} + +:root[data-theme="dark"] { + color-scheme: dark; + --color-surface: #16181d; + --color-surface-muted: #1d2026; + --color-surface-sunken: #24282f; + --color-line: #2f343d; + --color-ink: #eef0f4; + --color-ink-muted: #969ead; + --color-accent: #6b93ff; + --color-accent-soft: #1e2a45; + --color-danger: #f4736a; + --color-success: #4cc47f; +} + +html, +body { + height: 100%; +} + +body { + background-color: var(--color-surface-muted); + color: var(--color-ink); + font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; + overflow: hidden; +} + +button { + cursor: pointer; +} + +.scroll-thin { + scrollbar-width: thin; + scrollbar-color: var(--color-line) transparent; +} + +.cm-editor { + height: 100%; + font-size: 13px; +} + +.cm-editor .cm-scroller { + font-family: ui-monospace, "SF Mono", "JetBrains Mono", monospace; + line-height: 1.6; +} + +.cm-editor.cm-focused { + outline: none; +} + +.preview-page svg { + width: 100%; + height: auto; + display: block; +} diff --git a/src/app.html b/src/app.html new file mode 100644 index 0000000..d850437 --- /dev/null +++ b/src/app.html @@ -0,0 +1,13 @@ + + + + + + + Typst Desktop + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/src/lib/components/AssetsModal.svelte b/src/lib/components/AssetsModal.svelte new file mode 100644 index 0000000..0e7c04f --- /dev/null +++ b/src/lib/components/AssetsModal.svelte @@ -0,0 +1,177 @@ + + + +
+

+ Files imported here are available to every project. Reference an image by + its file name, and a font by its family name. +

+ + {#if error} +

{error}

+ {/if} + + {#if assets.length === 0} +
+ +

+ No images or fonts imported yet. +

+
+ {:else} +
+ {#each assets as asset (asset.name)} +
+ + +
+

{asset.name}

+ {#if asset.font_families.length > 0} +
+ {#each asset.font_families as family} + + {/each} +
+ {:else} +

+ {formatSize(asset.size)} +

+ {/if} +
+ + {#if oninsert && (asset.kind === "image" || asset.font_families.length > 0)} + + {/if} + + +
+ {/each} +
+ {/if} +
+ + {#snippet footer()} + + + {/snippet} +
diff --git a/src/lib/components/ConfirmModal.svelte b/src/lib/components/ConfirmModal.svelte new file mode 100644 index 0000000..0395f41 --- /dev/null +++ b/src/lib/components/ConfirmModal.svelte @@ -0,0 +1,38 @@ + + + +

{message}

+ + {#snippet footer()} + + + {/snippet} +
diff --git a/src/lib/components/ConflictModal.svelte b/src/lib/components/ConflictModal.svelte new file mode 100644 index 0000000..bbb90cc --- /dev/null +++ b/src/lib/components/ConflictModal.svelte @@ -0,0 +1,147 @@ + + + +
+

+ These files changed both on this device and in the cloud. Pick a version or + edit the merged result, then save to upload your resolution. +

+ +
+ {#each conflicts as conflict, position} + + {/each} +
+ + {#if current} + {#if current.binary} +
+

{current.path}

+

+ This is a binary file and cannot be merged automatically. The cloud + version will be kept. +

+
+ {:else} +
+ {#each [["merged", "Merged"], ["local", "This device"], ["remote", "Cloud"]] as [option, label]} + + {/each} + + {#if unresolvedMarkers} + + + Conflict markers still present + + {/if} +
+ + + {/if} + {/if} +
+ + {#snippet footer()} + + + {/snippet} +
diff --git a/src/lib/components/Editor.svelte b/src/lib/components/Editor.svelte new file mode 100644 index 0000000..d95128e --- /dev/null +++ b/src/lib/components/Editor.svelte @@ -0,0 +1,230 @@ + + +
diff --git a/src/lib/components/EditorToolbar.svelte b/src/lib/components/EditorToolbar.svelte new file mode 100644 index 0000000..420c131 --- /dev/null +++ b/src/lib/components/EditorToolbar.svelte @@ -0,0 +1,141 @@ + + +{#snippet action( + icon: string, + label: string, + run: () => void, + size = "text-base", +)} + +{/snippet} + +{#snippet divider()} +
+{/snippet} + +
+ {@render action("ph:arrow-counter-clockwise", "Undo", () => undoEdit(view))} + {@render action("ph:arrow-clockwise", "Redo", () => redoEdit(view))} + + {@render divider()} + + {@render action("ph:text-h", "Heading", () => prefixLines(view, "= ", "Heading"))} + {@render action("ph:text-b", "Bold", () => wrapSelection(view, "*", "*", "bold"))} + {@render action("ph:text-italic", "Italic", () => + wrapSelection(view, "_", "_", "italic"), + )} + {@render action("ph:code", "Raw", () => wrapSelection(view, "`", "`", "code"))} + + {@render divider()} + + {@render action("ph:sigma", "Inline math", () => + wrapSelection(view, "$", "$", "x = y"), + )} + {@render action("ph:function", "Block math", () => + wrapSelection(view, "$ \n ", "\n$", "x = y"), + )} + + {@render divider()} + + {@render action("ph:list-bullets", "Bullet list", () => + prefixLines(view, "- ", "List item"), + )} + {@render action("ph:list-numbers", "Numbered list", () => + prefixLines(view, "+ ", "Numbered item"), + )} + + {@render divider()} + + {@render action("ph:link", "Link", () => + insertText(view, '#link("https://")[text]'), + )} + {@render action("ph:table", "Table", () => + insertText(view, "#table(\n columns: 2,\n [a], [b],\n)"), + )} + {@render action("ph:image-square", "Figure", () => + insertText(view, '#figure(\n image("file.png"),\n caption: [Caption],\n)'), + )} + {@render action("ph:images", "Images and fonts", onassets)} + + {@render divider()} + + + + + +
+ + {#if stats} + + {stats.pages} pages · {stats.words} words · {stats.characters} chars + + {/if} +
diff --git a/src/lib/components/FileTree.svelte b/src/lib/components/FileTree.svelte new file mode 100644 index 0000000..2515fdf --- /dev/null +++ b/src/lib/components/FileTree.svelte @@ -0,0 +1,182 @@ + + +{#snippet branch(nodes: TreeNode[], depth: number)} + {#each nodes as node (node.path)} +
+
+ + + {#if node.file} + + {/if} +
+ + {#if node.file && menuPath === node.path} +
+ {#if node.name.endsWith(".typ")} + + {/if} + + +
+ {/if} + + {#if node.children.length > 0 && !collapsed[node.path]} + {@render branch(node.children, depth + 1)} + {/if} +
+ {/each} +{/snippet} + +
+ {#if files.length === 0} +

No files yet

+ {:else} + {@render branch(tree, 0)} + {/if} +
diff --git a/src/lib/components/FileViewer.svelte b/src/lib/components/FileViewer.svelte new file mode 100644 index 0000000..5cb8480 --- /dev/null +++ b/src/lib/components/FileViewer.svelte @@ -0,0 +1,513 @@ + + +{#snippet actions(entry: BrowseEntry, offset: string)} + + + {#if menuFor === entry.path} +
+ {#if entry.kind === "project" || entry.kind === "document"} + + {:else if api.isImagePath(entry.path)} + + {/if} + {#if entry.kind === "project" && !entry.space_id && app.account} + + {/if} + + +
+ {/if} +{/snippet} + +
+
+
+ {#each [["local", "Local", "ph:hard-drives"], ["cloud", "Cloud", "ph:cloud"]] as [value, label, icon]} + + {/each} +
+ +
+ + {#if app.scope === "local"} + + + + + + {:else if app.account} + + {/if} +
+ + {#if app.scope === "local"} +
+ + + {#each trail as crumb, index} + + + {/each} +
+ +
+ {#if app.entries.length === 0} +
+ +

This folder is empty.

+
+ + +
+
+ {:else} +
+ {#if containers.length > 0} +
+

+ Folders +

+
+ {#each containers as entry (entry.path)} +
+ + + {@render actions(entry, "top-2")} +
+ {/each} +
+
+ {/if} + + {#if documents.length > 0} +
+

+ Documents +

+
+ {#each documents as entry (entry.path)} +
+ + + {@render actions(entry, "top-2")} +
+ {/each} +
+
+ {/if} +
+ {/if} +
+ {:else} +
+ {#if !app.account} +
+ +

+ Connect a TypstDrive account to sync your projects across devices. +

+ +
+ {:else if app.spaces.length === 0} +
+ +

No cloud spaces yet.

+
+ {:else} +
+ {#each app.spaces as space (space.id)} +
+
+ + {#if localSpaceIds.has(space.id)} + + + + {/if} +
+ + {space.name} + + {space.role} · {formatDate(space.updated_at)} + + +
+ {#if !localSpaceIds.has(space.id)} + + {/if} + {#if space.role === "owner"} + + {/if} +
+
+ {/each} +
+ {/if} +
+ {/if} +
diff --git a/src/lib/components/ImageViewer.svelte b/src/lib/components/ImageViewer.svelte new file mode 100644 index 0000000..56f6a16 --- /dev/null +++ b/src/lib/components/ImageViewer.svelte @@ -0,0 +1,172 @@ + + + + + diff --git a/src/lib/components/LoginModal.svelte b/src/lib/components/LoginModal.svelte new file mode 100644 index 0000000..a155ea0 --- /dev/null +++ b/src/lib/components/LoginModal.svelte @@ -0,0 +1,89 @@ + + + +
+ + + + + + + {#if error} +

{error}

+ {/if} +
+ + {#snippet footer()} + + + {/snippet} +
diff --git a/src/lib/components/Modal.svelte b/src/lib/components/Modal.svelte new file mode 100644 index 0000000..871e0df --- /dev/null +++ b/src/lib/components/Modal.svelte @@ -0,0 +1,69 @@ + + + + + diff --git a/src/lib/components/PageSettingsModal.svelte b/src/lib/components/PageSettingsModal.svelte new file mode 100644 index 0000000..e51f18f --- /dev/null +++ b/src/lib/components/PageSettingsModal.svelte @@ -0,0 +1,113 @@ + + + +
+ + + + + + + + + +
+ + {#snippet footer()} + + + {/snippet} +
diff --git a/src/lib/components/Preview.svelte b/src/lib/components/Preview.svelte new file mode 100644 index 0000000..1bcbf00 --- /dev/null +++ b/src/lib/components/Preview.svelte @@ -0,0 +1,99 @@ + + +
+
+ + + {#if compiled} + {compiled.stats.pages} pages, {compiled.stats.words} words + {:else} + Preview + {/if} + + +
+ + {#if compiling} + + {/if} + + + + {Math.round(zoom * 100)}% + + +
+ + {#if errors.length > 0} +
+ {#each errors as diagnostic} +
+ + + {#if diagnostic.line} + Line {diagnostic.line}: + {/if} + {diagnostic.message} + +
+ {/each} +
+ {/if} + +
+ {#if compiled && compiled.pages.length > 0} +
+ {#each compiled.pages as page} +
+ {@html page} +
+ {/each} +
+ {:else} +
+ +

+ {errors.length > 0 ? "Fix the errors above to see a preview" : "Nothing to preview yet"} +

+
+ {/if} +
+
diff --git a/src/lib/components/PromptModal.svelte b/src/lib/components/PromptModal.svelte new file mode 100644 index 0000000..1ecc73e --- /dev/null +++ b/src/lib/components/PromptModal.svelte @@ -0,0 +1,81 @@ + + + +
+ +
+ + {#snippet footer()} + + + {/snippet} +
diff --git a/src/lib/components/SettingsModal.svelte b/src/lib/components/SettingsModal.svelte new file mode 100644 index 0000000..4601b62 --- /dev/null +++ b/src/lib/components/SettingsModal.svelte @@ -0,0 +1,153 @@ + + + +
+
+ Workspace folder +
+ + +
+ + Projects are stored as plain folders here. + +
+ +
+ TypstDrive server + +
+ +
+ +
+ {#if app.account} +

{app.account.username}

+

{app.account.email}

+ {:else} +

Not connected

+

+ Sign in to sync projects to the cloud. +

+ {/if} +
+ {#if app.account} + + {:else} + + {/if} +
+ +
+ Appearance +
+ {#each [["light", "ph:sun"], ["dark", "ph:moon"]] as [value, icon]} + + {/each} +
+
+
+ + {#snippet footer()} + + + {/snippet} +
diff --git a/src/lib/components/WindowControls.svelte b/src/lib/components/WindowControls.svelte new file mode 100644 index 0000000..94df7f5 --- /dev/null +++ b/src/lib/components/WindowControls.svelte @@ -0,0 +1,54 @@ + + +
+ + + + + +
diff --git a/src/lib/ts/api.ts b/src/lib/ts/api.ts new file mode 100644 index 0000000..7549484 --- /dev/null +++ b/src/lib/ts/api.ts @@ -0,0 +1,268 @@ +import { invoke } from "@tauri-apps/api/core"; + +export interface Settings { + workspace_root: string; + server_url: string; + device_token: string | null; + account_email: string | null; + account_username: string | null; +} + +export interface FileEntry { + path: string; + name: string; + is_text: boolean; + size: number; +} + +export interface FilePayload { + path: string; + is_text: boolean; + content: string; +} + +export interface Diagnostic { + message: string; + severity: string; + line: number | null; + column: number | null; +} + +export interface DocumentStats { + pages: number; + words: number; + characters: number; +} + +export interface CompileResult { + pages: string[]; + stats: DocumentStats; + diagnostics: Diagnostic[]; +} + +export interface CompileFailure { + diagnostics: Diagnostic[]; +} + +export interface Account { + user_id: string; + username: string; + email: string; +} + +export interface SpaceSummary { + id: string; + name: string; + entrypoint: string; + role: string; + updated_at: string; +} + +export interface Conflict { + path: string; + local_text: string; + remote_text: string; + merged_text: string; + server_hash: string; + auto_merged: boolean; + binary: boolean; +} + +export interface SyncReport { + pushed: string[]; + pulled: string[]; + deleted_local: string[]; + deleted_remote: string[]; + merged: string[]; + conflicts: Conflict[]; +} + +export interface Resolution { + path: string; + content: string; + server_hash: string; +} + +export type EntryKind = "folder" | "project" | "document" | "file"; + +export interface BrowseEntry { + name: string; + path: string; + kind: EntryKind; + size: number; + modified: string | null; + space_id: string | null; + last_synced_at: string | null; + child_count: number; +} + +export interface TargetInfo { + path: string; + entrypoint: string; + standalone: boolean; + is_project: boolean; + space_id: string | null; + files: FileEntry[]; +} + +export const browseWorkspace = (path: string) => + invoke("browse_workspace", { path }); + +export const createFolderEntry = (parent: string, name: string) => + invoke("create_folder_entry", { parent, name }); + +export const createDocumentEntry = (parent: string, name: string) => + invoke("create_document_entry", { parent, name }); + +export const createProjectEntry = (parent: string, name: string) => + invoke("create_project_entry", { parent, name }); + +export const renameEntry = (path: string, newName: string) => + invoke("rename_entry", { path, newName }); + +export const deleteEntry = (path: string) => + invoke("delete_entry", { path }); + +export const uploadEntry = ( + parent: string, + name: string, + base64Content: string, +) => invoke("upload_entry", { parent, name, base64Content }); + +export const targetInfo = (path: string) => + invoke("target_info", { path }); + +export const readTargetFile = (path: string, file: string) => + invoke("read_target_file", { path, file }); + +export const writeTargetFile = (path: string, file: string, content: string) => + invoke("write_target_file", { path, file, content }); + +export const setTargetEntrypoint = (path: string, entrypoint: string) => + invoke("set_target_entrypoint", { path, entrypoint }); + +export const compileTarget = ( + path: string, + overrides?: Record, +) => invoke("compile_target", { path, overrides }); + +export const exportTarget = ( + path: string, + format: string, + destination: string, +) => invoke("export_target", { path, format, destination }); + +export interface Asset { + name: string; + kind: "font" | "image" | "file"; + size: number; + font_families: string[]; +} + +export const listAssets = () => invoke("list_assets"); + +export interface Thumbnail { + kind: "svg" | "image"; + data: string; +} + +export const thumbnail = (path: string) => + invoke("thumbnail", { path }); + +export const clearThumbnails = () => invoke("clear_thumbnails"); + +export interface ImageData { + name: string; + data: string; + size: number; + width: number | null; + height: number | null; +} + +export const readImage = (path: string) => + invoke("read_image", { path }); + +export const IMAGE_EXTENSIONS = ["png", "jpg", "jpeg", "gif", "svg", "webp"]; + +export function isImagePath(path: string): boolean { + const extension = path.split(".").pop()?.toLowerCase() ?? ""; + return IMAGE_EXTENSIONS.includes(extension); +} + +export const listFontFamilies = (path?: string) => + invoke("list_font_families", { path: path ?? null }); + +export const importAssets = (sources: string[]) => + invoke("import_assets", { sources }); + +export const deleteAsset = (name: string) => + invoke("delete_asset", { name }); + +export const importIntoTarget = (path: string, sources: string[]) => + invoke("import_into_target", { path, sources }); + +export const importIntoFolder = (parent: string, sources: string[]) => + invoke("import_into_folder", { parent, sources }); + +export const getSettings = () => invoke("get_settings"); + +export const updateSettings = (changes: { + workspaceRoot?: string; + serverUrl?: string; +}) => invoke("update_settings", changes); + +export const cloudLogin = ( + serverUrl: string, + email: string, + password: string, +) => invoke("cloud_login", { serverUrl, email, password }); + +export const cloudLogout = () => invoke("cloud_logout"); + +export const cloudAccount = () => invoke("cloud_account"); + +export const cloudListSpaces = () => + invoke("cloud_list_spaces"); + +export const cloudCreateSpace = (name: string) => + invoke("cloud_create_space", { name }); + +export const cloudDeleteSpace = (spaceId: string) => + invoke("cloud_delete_space", { spaceId }); + +export const cloudCloneSpace = (spaceId: string, projectName: string) => + invoke("cloud_clone_space", { spaceId, projectName }); + +export const cloudLinkProject = (project: string, spaceId?: string) => + invoke("cloud_link_project", { project, spaceId: spaceId ?? null }); + +export const cloudUnlinkProject = (project: string) => + invoke("cloud_unlink_project", { project }); + +export const cloudPush = (project: string) => + invoke("cloud_push", { project }); + +export const cloudPull = (project: string) => + invoke("cloud_pull", { project }); + +export const cloudSync = (project: string) => + invoke("cloud_sync", { project }); + +export const cloudResolveConflicts = ( + project: string, + resolutions: Resolution[], +) => invoke("cloud_resolve_conflicts", { project, resolutions }); + +export function errorMessage(error: unknown): string { + if (typeof error === "string") return error; + if (error && typeof error === "object" && "diagnostics" in error) { + const failure = error as CompileFailure; + return failure.diagnostics.map((d) => d.message).join("; "); + } + if (error instanceof Error) return error.message; + return String(error); +} + +export function isCompileFailure(error: unknown): error is CompileFailure { + return Boolean(error && typeof error === "object" && "diagnostics" in error); +} diff --git a/src/lib/ts/completions.ts b/src/lib/ts/completions.ts new file mode 100644 index 0000000..014aaf8 --- /dev/null +++ b/src/lib/ts/completions.ts @@ -0,0 +1,106 @@ +import { + snippetCompletion, + type CompletionContext, +} from "@codemirror/autocomplete"; + +const typstOptions = [ + + snippetCompletion("let ${name} = ${value}", { label: "let", type: "keyword", info: "Variable declaration" }), + snippetCompletion("set ${rule}(${value})", { label: "set", type: "keyword", info: "Set rule" }), + snippetCompletion("show ${selector}: ${rule}", { label: "show", type: "keyword", info: "Show rule" }), + snippetCompletion("import \"${module}\": ${items}", { label: "import", type: "keyword", info: "Import module" }), + snippetCompletion("include \"${file}\"", { label: "include", type: "keyword", info: "Include file" }), + snippetCompletion("if ${condition} {\n\t${}\n}", { label: "if", type: "keyword", info: "If statement" }), + snippetCompletion("else {\n\t${}\n}", { label: "else", type: "keyword", info: "Else statement" }), + snippetCompletion("for ${item} in ${collection} {\n\t${}\n}", { label: "for", type: "keyword", info: "For loop" }), + snippetCompletion("while ${condition} {\n\t${}\n}", { label: "while", type: "keyword", info: "While loop" }), + snippetCompletion("break", { label: "break", type: "keyword", info: "Break loop" }), + snippetCompletion("continue", { label: "continue", type: "keyword", info: "Continue loop" }), + snippetCompletion("return ${value}", { label: "return", type: "keyword", info: "Return value" }), + snippetCompletion("context", { label: "context", type: "keyword", info: "Context expression" }), + snippetCompletion("align(${alignment})[${content}]", { label: "align", type: "function", info: "Align content" }), + snippetCompletion("page(${content})", { label: "page", type: "function", info: "Page configuration" }), + snippetCompletion("pagebreak()", { label: "pagebreak", type: "function", info: "Break page" }), + snippetCompletion("colbreak()", { label: "colbreak", type: "function", info: "Break column" }), + snippetCompletion("place(${alignment})[${content}]", { label: "place", type: "function", info: "Place content" }), + snippetCompletion("columns(${2})[${content}]", { label: "columns", type: "function", info: "Multiple columns" }), + snippetCompletion("pad(${10pt})[${content}]", { label: "pad", type: "function", info: "Pad content" }), + snippetCompletion("stack(dir: ${ttb}, spacing: ${10pt}, ${items})", { label: "stack", type: "function", info: "Stack items" }), + snippetCompletion("grid(columns: ${2}, gutter: ${10pt}, ${items})", { label: "grid", type: "function", info: "Grid layout" }), + snippetCompletion("table(columns: ${2}, ${items})", { label: "table", type: "function", info: "Table layout" }), + snippetCompletion("rect(width: ${100%}, height: ${100%})[${content}]", { label: "rect", type: "function", info: "Draw rectangle" }), + snippetCompletion("square(size: ${10pt})[${content}]", { label: "square", type: "function", info: "Draw square" }), + snippetCompletion("circle(radius: ${10pt})[${content}]", { label: "circle", type: "function", info: "Draw circle" }), + snippetCompletion("ellipse(width: ${20pt}, height: ${10pt})[${content}]", { label: "ellipse", type: "function", info: "Draw ellipse" }), + snippetCompletion("line(length: ${100%})", { label: "line", type: "function", info: "Draw line" }), + snippetCompletion("polygon(${vertices})", { label: "polygon", type: "function", info: "Draw polygon" }), + snippetCompletion("path(${vertices})", { label: "path", type: "function", info: "Draw path" }), + snippetCompletion("image(\"${path}\", width: ${100%})", { label: "image", type: "function", info: "Insert image" }), + snippetCompletion("box[${content}]", { label: "box", type: "function", info: "Box inline content" }), + snippetCompletion("block[${content}]", { label: "block", type: "function", info: "Block content" }), + snippetCompletion("figure(${content}, caption: [${caption}])", { label: "figure", type: "function", info: "Figure with caption" }), + snippetCompletion("text(size: ${11pt}, font: \"${Arial}\")[${content}]", { label: "text", type: "function", info: "Text styling" }), + snippetCompletion("heading(level: ${1})[${title}]", { label: "heading", type: "function", info: "Heading" }), + snippetCompletion("par[${content}]", { label: "par", type: "function", info: "Paragraph" }), + snippetCompletion("list([${item}])", { label: "list", type: "function", info: "Bullet list" }), + snippetCompletion("enum([${item}])", { label: "enum", type: "function", info: "Numbered list" }), + snippetCompletion("terms([${term}], [${description}])", { label: "terms", type: "function", info: "Terms list" }), + snippetCompletion("strong[${content}]", { label: "strong", type: "function", info: "Bold text" }), + snippetCompletion("emph[${content}]", { label: "emph", type: "function", info: "Italic text" }), + snippetCompletion("underline[${content}]", { label: "underline", type: "function", info: "Underline text" }), + snippetCompletion("strike[${content}]", { label: "strike", type: "function", info: "Strikethrough text" }), + snippetCompletion("overline[${content}]", { label: "overline", type: "function", info: "Overline text" }), + snippetCompletion("sub[${content}]", { label: "sub", type: "function", info: "Subscript text" }), + snippetCompletion("super[${content}]", { label: "super", type: "function", info: "Superscript text" }), + snippetCompletion("raw(\"${code}\", block: ${true})", { label: "raw", type: "function", info: "Raw code block" }), + snippetCompletion("link(\"${url}\")[${text}]", { label: "link", type: "function", info: "Hyperlink" }), + snippetCompletion("ref(<${label}>)", { label: "ref", type: "function", info: "Reference" }), + snippetCompletion("cite(<${label}>)", { label: "cite", type: "function", info: "Citation" }), + snippetCompletion("bibliography(\"${file.bib}\")", { label: "bibliography", type: "function", info: "Bibliography" }), + snippetCompletion("outline(title: [${Contents}])", { label: "outline", type: "function", info: "Table of contents" }), + snippetCompletion("rgb(\"${#000000}\")", { label: "rgb", type: "function", info: "RGB Color" }), + snippetCompletion("cmyk(${0%}, ${0%}, ${0%}, ${100%})", { label: "cmyk", type: "function", info: "CMYK Color" }), + snippetCompletion("luma(${0%})", { label: "luma", type: "function", info: "Luma (Grayscale) Color" }), + snippetCompletion("color", { label: "color", type: "variable" }), + snippetCompletion("gradient", { label: "gradient", type: "variable" }), + snippetCompletion("pattern(size: (${10pt}, ${10pt}))[${content}]", { label: "pattern", type: "function", info: "Fill pattern" }), + snippetCompletion("type(${value})", { label: "type", type: "function", info: "Get type of value" }), + snippetCompletion("repr(${value})", { label: "repr", type: "function", info: "String representation" }), + snippetCompletion("str(${value})", { label: "str", type: "function", info: "Convert to string" }), + snippetCompletion("int(${value})", { label: "int", type: "function", info: "Convert to integer" }), + snippetCompletion("float(${value})", { label: "float", type: "function", info: "Convert to float" }), + snippetCompletion("datetime(year: ${2024}, month: ${1}, day: ${1})", { label: "datetime", type: "function", info: "Date and time" }), + snippetCompletion("math", { label: "math", type: "variable", info: "Math module" }), + snippetCompletion("calc", { label: "calc", type: "variable", info: "Calc module" }), + snippetCompletion("sys", { label: "sys", type: "variable", info: "System module" }), + snippetCompletion("frac(${num}, ${denom})", { label: "frac", type: "function", info: "Fraction (Math)" }), + snippetCompletion("binom(${n}, ${k})", { label: "binom", type: "function", info: "Binomial (Math)" }), + snippetCompletion("mat(${1}, ${2}; ${3}, ${4})", { label: "mat", type: "function", info: "Matrix (Math)" }), + snippetCompletion("vec(${1}, ${2})", { label: "vec", type: "function", info: "Vector (Math)" }), + snippetCompletion("cases(${a}, ${b})", { label: "cases", type: "function", info: "Cases (Math)" }), + snippetCompletion("sqrt(${x})", { label: "sqrt", type: "function", info: "Square root (Math)" }), + snippetCompletion("root(${3}, ${x})", { label: "root", type: "function", info: "N-th root (Math)" }), + snippetCompletion("abs(${x})", { label: "abs", type: "function", info: "Absolute value (Math)" }), + snippetCompletion("norm(${x})", { label: "norm", type: "function", info: "Norm (Math)" }), + snippetCompletion("floor(${x})", { label: "floor", type: "function", info: "Floor (Math)" }), + snippetCompletion("ceil(${x})", { label: "ceil", type: "function", info: "Ceiling (Math)" }), + snippetCompletion("round(${x})", { label: "round", type: "function", info: "Round (Math)" }), + snippetCompletion("cancel(${x})", { label: "cancel", type: "function", info: "Cancel/strike (Math)" }), + snippetCompletion("attach(${base}, t: ${top}, b: ${bottom})", { label: "attach", type: "function", info: "Attach scripts (Math)" }), + snippetCompletion("scripts(${expr})", { label: "scripts", type: "function", info: "Scripts (Math)" }), + snippetCompletion("limits(${expr})", { label: "limits", type: "function", info: "Limits (Math)" }), + snippetCompletion("op(\"${name}\")", { label: "op", type: "function", info: "Operator (Math)" }), + snippetCompletion("lr(${expr})", { label: "lr", type: "function", info: "Left/Right scales (Math)" }), + snippetCompletion("mid(${|})", { label: "mid", type: "function", info: "Mid delimiter (Math)" }) +]; + +export function typstCompletions(context: CompletionContext) { + const word = context.matchBefore(/[\w#]*/); + if (!word || (word.from === word.to && !context.explicit)) return null; + + return { + from: word.text.startsWith("#") ? word.from + 1 : word.from, + options: typstOptions, + validFor: /^[\w]*$/, + }; +} diff --git a/src/lib/ts/editor-actions.ts b/src/lib/ts/editor-actions.ts new file mode 100644 index 0000000..ccc36b5 --- /dev/null +++ b/src/lib/ts/editor-actions.ts @@ -0,0 +1,112 @@ +import type { EditorView } from "@codemirror/view"; +import { undo, redo } from "@codemirror/commands"; + +export function insertText(view: EditorView | null, text: string) { + if (!view) return; + const { from, to } = view.state.selection.main; + view.dispatch({ + changes: { from, to, insert: text }, + selection: { anchor: from + text.length }, + }); + view.focus(); +} + +export function wrapSelection( + view: EditorView | null, + prefix: string, + suffix: string, + placeholder = "", +) { + if (!view) return; + const selection = view.state.selection.main; + const selected = view.state.doc.sliceString(selection.from, selection.to); + const body = selected || placeholder; + + view.dispatch({ + changes: { from: selection.from, to: selection.to, insert: prefix + body + suffix }, + selection: { + anchor: selection.from + prefix.length, + head: selection.from + prefix.length + body.length, + }, + }); + view.focus(); +} + +export function prefixLines( + view: EditorView | null, + prefix: string, + placeholder = "", +) { + if (!view) return; + const selection = view.state.selection.main; + const startLine = view.state.doc.lineAt(selection.from); + const endLine = view.state.doc.lineAt(selection.to); + + if (selection.empty && startLine.text.trim() === "") { + insertText(view, prefix + placeholder); + return; + } + + const changes = []; + for (let number = startLine.number; number <= endLine.number; number += 1) { + const line = view.state.doc.line(number); + if (line.text.startsWith(prefix)) continue; + changes.push({ from: line.from, insert: prefix }); + } + + view.dispatch({ changes }); + view.focus(); +} + +export function undoEdit(view: EditorView | null) { + if (!view) return; + undo(view); + view.focus(); +} + +export function redoEdit(view: EditorView | null) { + if (!view) return; + redo(view); + view.focus(); +} + +export function setTypstConfig( + view: EditorView | null, + setting: string, + property: string, + value: string, +) { + if (!view) return; + + const content = view.state.doc.toString(); + const rule = new RegExp(`^#set\\s+${setting}\\s*\\(([^)]*)\\)`, "m"); + const match = content.match(rule); + + if (!match || match.index === undefined) { + view.dispatch({ + changes: { from: 0, insert: `#set ${setting}(${property}: ${value})\n` }, + }); + view.focus(); + return; + } + + const existing = match[1]; + const property_rule = new RegExp( + `${property}\\s*:\\s*(?:\\([^)]*\\)|"[^"]*"|[^,)]+)`, + ); + + const next = property_rule.test(existing) + ? existing.replace(property_rule, `${property}: ${value}`) + : existing.trim() + ? `${existing}, ${property}: ${value}` + : `${property}: ${value}`; + + view.dispatch({ + changes: { + from: match.index, + to: match.index + match[0].length, + insert: `#set ${setting}(${next})`, + }, + }); + view.focus(); +} diff --git a/src/lib/ts/editor-theme.ts b/src/lib/ts/editor-theme.ts new file mode 100644 index 0000000..13f0d69 --- /dev/null +++ b/src/lib/ts/editor-theme.ts @@ -0,0 +1,210 @@ +import { EditorView } from "@codemirror/view"; +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { tags as t } from "@lezer/highlight"; + +interface ThemeColors { + background: string; + surface: string; + text: string; + selection: string; + activeLine: string; + cursor: string; + border: string; + keyword: string; + string: string; + number: string; + comment: string; + variable: string; + function: string; + heading: string; +} + +const palette: Record<"light" | "dark", ThemeColors> = { + light: { + background: "#ffffff", + surface: "#f6f7f9", + text: "#14161a", + selection: "#dbe6fe", + activeLine: "#f6f7f9", + cursor: "#3b6cf6", + border: "#dfe2e7", + keyword: "#7c3aed", + string: "#0f766e", + number: "#b45309", + comment: "#6b7280", + variable: "#14161a", + function: "#2563eb", + heading: "#1d4ed8", + }, + dark: { + background: "#16181d", + surface: "#1d2026", + text: "#eef0f4", + selection: "#2f3a52", + activeLine: "#1d2026", + cursor: "#6b93ff", + border: "#2f343d", + keyword: "#c4a7f7", + string: "#8ddba4", + number: "#f0b37e", + comment: "#7b8496", + variable: "#eef0f4", + function: "#7aa2ff", + heading: "#8fb3ff", + }, +}; + +export function editorTheme(isDark: boolean) { + const colors = palette[isDark ? "dark" : "light"]; + + const theme = EditorView.theme( + { + "&": { + color: colors.text, + backgroundColor: colors.background, + height: "100%", + fontSize: "13px", + }, + ".cm-content": { + caretColor: colors.cursor, + padding: "12px 0", + }, + ".cm-cursor, .cm-dropCursor": { borderLeftColor: colors.cursor }, + "&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": + { backgroundColor: colors.selection }, + ".cm-activeLine": { backgroundColor: colors.activeLine }, + ".cm-gutters": { + backgroundColor: colors.background, + color: colors.comment, + border: "none", + }, + ".cm-activeLineGutter": { backgroundColor: colors.activeLine }, + "&.cm-focused .cm-matchingBracket": { + backgroundColor: colors.selection, + outline: `1px solid ${colors.border}`, + }, + + ".cm-tooltip": { + backgroundColor: colors.surface, + color: colors.text, + border: `1px solid ${colors.border}`, + borderRadius: "6px", + maxWidth: "500px", + }, + ".cm-tooltip-hover": { maxHeight: "300px", overflow: "auto" }, + ".cm-tooltip .cm-tooltip-arrow:before": { + borderTopColor: colors.border, + borderBottomColor: colors.border, + }, + ".cm-tooltip .cm-tooltip-arrow:after": { + borderTopColor: colors.surface, + borderBottomColor: colors.surface, + }, + + ".cm-tooltip.cm-tooltip-autocomplete": { + backgroundColor: colors.surface, + border: `1px solid ${colors.border}`, + padding: "4px", + }, + ".cm-tooltip.cm-tooltip-autocomplete > ul": { + fontFamily: "inherit", + maxHeight: "16em", + }, + ".cm-tooltip.cm-tooltip-autocomplete > ul > li": { + color: colors.text, + padding: "3px 8px", + borderRadius: "4px", + display: "flex", + alignItems: "center", + gap: "6px", + }, + ".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": { + backgroundColor: colors.cursor, + color: "#ffffff", + }, + ".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected] .cm-completionDetail": + { color: "#ffffff" }, + ".cm-completionLabel": { color: "inherit" }, + ".cm-completionMatchedText": { + textDecoration: "none", + fontWeight: "600", + color: "inherit", + }, + ".cm-completionDetail": { + color: colors.comment, + fontStyle: "normal", + marginLeft: "auto", + fontSize: "0.85em", + }, + ".cm-completionIcon": { + color: colors.comment, + opacity: "1", + width: "1.1em", + }, + ".cm-completionInfo": { + backgroundColor: colors.surface, + color: colors.text, + border: `1px solid ${colors.border}`, + borderRadius: "6px", + padding: "6px 8px", + }, + + ".cm-panels": { backgroundColor: colors.surface, color: colors.text }, + ".cm-searchMatch": { backgroundColor: "#72a1ff59" }, + ".cm-selectionMatch": { backgroundColor: "#aafe661a" }, + }, + { dark: isDark }, + ); + + const highlightStyle = HighlightStyle.define([ + { tag: t.keyword, color: colors.keyword }, + { + tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName], + color: colors.variable, + }, + { tag: [t.function(t.variableName), t.labelName], color: colors.function }, + { + tag: [t.color, t.constant(t.name), t.standard(t.name)], + color: colors.function, + }, + { tag: [t.definition(t.name), t.separator], color: colors.variable }, + { + tag: [ + t.typeName, + t.className, + t.number, + t.changed, + t.annotation, + t.modifier, + t.self, + t.namespace, + ], + color: colors.number, + }, + { + tag: [ + t.operator, + t.operatorKeyword, + t.url, + t.escape, + t.regexp, + t.special(t.string), + ], + color: colors.keyword, + }, + { tag: [t.meta, t.comment], color: colors.comment, fontStyle: "italic" }, + { tag: t.strong, fontWeight: "bold" }, + { tag: t.emphasis, fontStyle: "italic" }, + { tag: t.strikethrough, textDecoration: "line-through" }, + { tag: t.link, color: colors.function, textDecoration: "underline" }, + { tag: t.heading, fontWeight: "bold", color: colors.heading }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: colors.number }, + { + tag: [t.processingInstruction, t.string, t.inserted], + color: colors.string, + }, + { tag: t.invalid, color: "#ff5c57" }, + ]); + + return [theme, syntaxHighlighting(highlightStyle, { fallback: true })]; +} diff --git a/src/lib/ts/import.ts b/src/lib/ts/import.ts new file mode 100644 index 0000000..1244479 --- /dev/null +++ b/src/lib/ts/import.ts @@ -0,0 +1,35 @@ +import { open } from "@tauri-apps/plugin-dialog"; + +export const IMAGE_EXTENSIONS = ["png", "jpg", "jpeg", "gif", "svg", "webp"]; +export const FONT_EXTENSIONS = ["ttf", "otf", "ttc", "otc"]; +export const DATA_EXTENSIONS = ["bib", "csl", "json", "yaml", "yml", "csv", "toml"]; + +export type PickKind = "all" | "assets" | "images" | "fonts"; + +export async function pickFiles(kind: PickKind = "all"): Promise { + const filters = + kind === "images" + ? [{ name: "Images", extensions: IMAGE_EXTENSIONS }] + : kind === "fonts" + ? [{ name: "Fonts", extensions: FONT_EXTENSIONS }] + : kind === "assets" + ? [ + { + name: "Images and fonts", + extensions: [...IMAGE_EXTENSIONS, ...FONT_EXTENSIONS], + }, + { name: "Images", extensions: IMAGE_EXTENSIONS }, + { name: "Fonts", extensions: FONT_EXTENSIONS }, + ] + : [ + { + name: "Typst files", + extensions: ["typ", ...DATA_EXTENSIONS, ...IMAGE_EXTENSIONS, ...FONT_EXTENSIONS], + }, + ]; + + const selected = await open({ multiple: true, filters }); + + if (!selected) return []; + return Array.isArray(selected) ? selected : [selected]; +} diff --git a/src/lib/ts/lsp.ts b/src/lib/ts/lsp.ts new file mode 100644 index 0000000..b6b0207 --- /dev/null +++ b/src/lib/ts/lsp.ts @@ -0,0 +1,74 @@ +import { invoke } from "@tauri-apps/api/core"; +import { listen, type UnlistenFn } from "@tauri-apps/api/event"; + +export interface LspHandle { + root_uri: string; + document_uri: string; +} + +type Handler = (value: string) => void; + +export class LspBridge { + private handlers: Handler[] = []; + private unlistenMessage: UnlistenFn | null = null; + private unlistenClosed: UnlistenFn | null = null; + + handle: LspHandle | null = null; + + readonly transport = { + send: (message: string) => { + invoke("lsp_send", { message }).catch(() => {}); + }, + subscribe: (handler: Handler) => { + this.handlers.push(handler); + }, + unsubscribe: (handler: Handler) => { + this.handlers = this.handlers.filter((existing) => existing !== handler); + }, + }; + + async start(path: string, onClosed?: () => void): Promise { + await this.stop(); + + this.unlistenMessage = await listen("lsp://message", (event) => { + const message = this.filterDiagnostics(event.payload); + for (const handler of this.handlers) handler(message); + }); + + this.unlistenClosed = await listen("lsp://closed", () => { + onClosed?.(); + }); + + this.handle = await invoke("lsp_start", { path }); + return this.handle; + } + + private filterDiagnostics(message: string): string { + if (!message.includes("publishDiagnostics")) return message; + try { + const parsed = JSON.parse(message); + if (parsed.method === "textDocument/publishDiagnostics") { + parsed.params.diagnostics = parsed.params.diagnostics.filter( + (diagnostic: { message: string }) => + !diagnostic.message.toLowerCase().includes("unknown font family"), + ); + return JSON.stringify(parsed); + } + } catch { + return message; + } + return message; + } + + async stop() { + this.unlistenMessage?.(); + this.unlistenClosed?.(); + this.unlistenMessage = null; + this.unlistenClosed = null; + this.handlers = []; + this.handle = null; + await invoke("lsp_stop").catch(() => {}); + } +} + +export const lspAvailable = () => invoke("lsp_running"); diff --git a/src/lib/ts/state.svelte.ts b/src/lib/ts/state.svelte.ts new file mode 100644 index 0000000..87fb131 --- /dev/null +++ b/src/lib/ts/state.svelte.ts @@ -0,0 +1,348 @@ +import * as api from "./api"; +import type { + Account, + BrowseEntry, + CompileResult, + Conflict, + Diagnostic, + Settings, + SpaceSummary, + TargetInfo, +} from "./api"; + +export type Scope = "local" | "cloud"; +export type View = "files" | "editor"; +export type LspStatus = "off" | "starting" | "on" | "unavailable"; + +interface AppState { + view: View; + scope: Scope; + settings: Settings | null; + account: Account | null; + + currentDir: string; + entries: BrowseEntry[]; + spaces: SpaceSummary[]; + + target: TargetInfo | null; + activePath: string | null; + editorContent: string; + dirty: boolean; + compiled: CompileResult | null; + diagnostics: Diagnostic[]; + compiling: boolean; + lspStatus: LspStatus; + + syncing: boolean; + conflicts: Conflict[]; + status: string; + error: string; + theme: "light" | "dark"; +} + +export const app = $state({ + view: "files", + scope: "local", + settings: null, + account: null, + + currentDir: "", + entries: [], + spaces: [], + + target: null, + activePath: null, + editorContent: "", + dirty: false, + compiled: null, + diagnostics: [], + compiling: false, + lspStatus: "off", + + syncing: false, + conflicts: [], + status: "", + error: "", + theme: "light", +}); + +export function setError(error: unknown) { + app.error = api.errorMessage(error); + app.status = ""; +} + +export function setStatus(message: string) { + app.status = message; + app.error = ""; +} + +export function clearMessages() { + app.status = ""; + app.error = ""; +} + +export function applyTheme(theme: "light" | "dark") { + app.theme = theme; + document.documentElement.dataset.theme = theme; + localStorage.setItem("typst-desktop-theme", theme); +} + +export function breadcrumbs(): { name: string; path: string }[] { + if (!app.currentDir) return []; + const segments = app.currentDir.split("/"); + return segments.map((name, index) => ({ + name, + path: segments.slice(0, index + 1).join("/"), + })); +} + +export async function bootstrap() { + const stored = localStorage.getItem("typst-desktop-theme"); + applyTheme(stored === "dark" ? "dark" : "light"); + + try { + app.settings = await api.getSettings(); + await browseTo(""); + await refreshAccount(); + } catch (error) { + setError(error); + } +} + +export async function browseTo(path: string) { + try { + app.entries = await api.browseWorkspace(path); + app.currentDir = path; + clearMessages(); + } catch (error) { + setError(error); + } +} + +export async function refreshEntries() { + await browseTo(app.currentDir); +} + +export async function refreshAccount() { + try { + app.account = await api.cloudAccount(); + if (app.account) { + await refreshSpaces(); + } else { + app.spaces = []; + } + } catch { + app.account = null; + } +} + +export async function refreshSpaces() { + try { + app.spaces = await api.cloudListSpaces(); + } catch (error) { + setError(error); + } +} + +export async function openTarget(path: string) { + try { + const target = await api.targetInfo(path); + app.target = target; + app.view = "editor"; + app.activePath = null; + app.editorContent = ""; + app.dirty = false; + app.compiled = null; + app.diagnostics = []; + app.lspStatus = "off"; + clearMessages(); + + const preferred = + target.files.find((file) => file.path === target.entrypoint) ?? + target.files.find((file) => file.path.endsWith(".typ")) ?? + target.files[0]; + + if (preferred) await openFile(preferred.path); + } catch (error) { + setError(error); + } +} + +export async function closeTarget() { + cancelScheduledCompile(); + if (app.dirty) await saveActiveFile(); + app.view = "files"; + app.target = null; + app.activePath = null; + app.editorContent = ""; + app.compiled = null; + app.diagnostics = []; + app.lspStatus = "off"; + await refreshEntries(); +} + +export async function refreshTarget() { + if (!app.target) return; + try { + app.target = await api.targetInfo(app.target.path); + } catch (error) { + setError(error); + } +} + +export async function openFile(file: string) { + if (!app.target) return; + + cancelScheduledCompile(); + + if (app.dirty && app.activePath) await saveActiveFile(); + + try { + const payload = await api.readTargetFile(app.target.path, file); + app.activePath = file; + app.editorContent = payload.is_text ? payload.content : ""; + app.dirty = false; + if (payload.is_text) await compile(); + } catch (error) { + setError(error); + } +} + +export async function saveActiveFile() { + if (!app.target || !app.activePath) return; + try { + await api.writeTargetFile( + app.target.path, + app.activePath, + app.editorContent, + ); + app.dirty = false; + } catch (error) { + setError(error); + } +} + +function liveOverrides(): Record | undefined { + if (!app.dirty || !app.activePath) return undefined; + return { [app.activePath]: app.editorContent }; +} + +let compileRunning = false; +let compileQueued = false; + +export async function compile() { + if (!app.target) return; + + if (compileRunning) { + compileQueued = true; + return; + } + + compileRunning = true; + app.compiling = true; + + try { + const result = await api.compileTarget(app.target.path, liveOverrides()); + app.compiled = result; + app.diagnostics = result.diagnostics; + } catch (error) { + if (api.isCompileFailure(error)) { + app.diagnostics = error.diagnostics; + } else { + setError(error); + } + } finally { + compileRunning = false; + app.compiling = false; + + if (compileQueued) { + compileQueued = false; + await compile(); + } + } +} + +const COMPILE_DEBOUNCE_MS = 400; +let compileTimer: ReturnType | null = null; + +export function scheduleCompile() { + if (compileTimer) clearTimeout(compileTimer); + compileTimer = setTimeout(() => { + compileTimer = null; + compile(); + }, COMPILE_DEBOUNCE_MS); +} + +export function cancelScheduledCompile() { + if (compileTimer) { + clearTimeout(compileTimer); + compileTimer = null; + } +} + +export async function saveAndCompile() { + cancelScheduledCompile(); + await saveActiveFile(); + await compile(); +} + +export async function runSync( + action: "sync" | "push" | "pull", + project = app.target?.path, +) { + if (!project) return; + + app.syncing = true; + clearMessages(); + + try { + const report = + action === "push" + ? await api.cloudPush(project) + : action === "pull" + ? await api.cloudPull(project) + : await api.cloudSync(project); + + app.conflicts = report.conflicts; + + if (report.conflicts.length > 0) { + setError(`${report.conflicts.length} file(s) need conflict resolution`); + } else { + setStatus(summarize(report)); + } + + await refreshTarget(); + if (app.activePath) { + const payload = await api.readTargetFile(project, app.activePath); + if (payload.is_text) { + app.editorContent = payload.content; + app.dirty = false; + } + } + await compile(); + } catch (error) { + setError(error); + } finally { + app.syncing = false; + } +} + +function summarize(report: { + pushed: string[]; + pulled: string[]; + merged: string[]; + deleted_local: string[]; + deleted_remote: string[]; +}): string { + const parts: string[] = []; + if (report.pushed.length) parts.push(`${report.pushed.length} uploaded`); + if (report.pulled.length) parts.push(`${report.pulled.length} downloaded`); + if (report.merged.length) parts.push(`${report.merged.length} merged`); + if (report.deleted_local.length) + parts.push(`${report.deleted_local.length} removed locally`); + if (report.deleted_remote.length) + parts.push(`${report.deleted_remote.length} removed in cloud`); + return parts.length + ? `Sync complete: ${parts.join(", ")}` + : "Already up to date"; +} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte new file mode 100644 index 0000000..2c738ea --- /dev/null +++ b/src/routes/+layout.svelte @@ -0,0 +1,11 @@ + + +{@render children()} diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts new file mode 100644 index 0000000..9d24899 --- /dev/null +++ b/src/routes/+layout.ts @@ -0,0 +1,5 @@ +// Tauri doesn't have a Node.js server to do proper SSR +// so we use adapter-static with a fallback to index.html to put the site in SPA mode +// See: https://svelte.dev/docs/kit/single-page-apps +// See: https://v2.tauri.app/start/frontend/sveltekit/ for more info +export const ssr = false; diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte new file mode 100644 index 0000000..6ba2856 --- /dev/null +++ b/src/routes/+page.svelte @@ -0,0 +1,768 @@ + + + + +
+
+ {#if app.view === "editor"} + + + {app.target?.path.split("/").pop()} + + {#if app.target?.standalone} + + single file + + {/if} + {#if app.dirty} + + {/if} + {:else} + + + Typst Desktop + + {/if} + +
+ + {#if app.view === "editor"} + + + {lspLabel[app.lspStatus]} + + + + + + +
+ + +
+ + {#if app.target?.space_id} + + {/if} + {/if} + + + +
+ + +
+ + {#if app.status || app.error} +
+ + {app.error || app.status} + {#if app.conflicts.length > 0} + + {/if} + +
+ {/if} + +
+ {#if app.view === "files"} +
+ (dialog = { kind: "new-project" })} + onnewfolder={() => (dialog = { kind: "new-folder" })} + onnewdocument={() => (dialog = { kind: "new-document" })} + onupload={importFiles} + onassets={() => (dialog = { kind: "assets" })} + onrename={(entry) => (dialog = { kind: "rename-entry", entry })} + ondelete={(entry) => (dialog = { kind: "delete-entry", entry })} + onlink={(entry) => (dialog = { kind: "link-entry", entry })} + onviewimage={(paths, index) => (imageViewer = { paths, index })} + onnewspace={() => (dialog = { kind: "new-space" })} + onclonespace={(id, name) => (dialog = { kind: "clone-space", id, name })} + ondeletespace={(id) => (dialog = { kind: "delete-space", id })} + onsignin={() => (dialog = { kind: "login" })} + /> +
+ {:else} + {#if !app.target?.standalone} +
+
+ + Files + +
+ + + +
+
+ + (dialog = { kind: "rename-file", path })} + ondelete={(path) => (dialog = { kind: "delete-file", path })} + onsetentry={setEntrypoint} + /> +
+ {/if} + +
+
+ {#if app.activePath && activeFile?.is_text} + (dialog = { kind: "assets" })} + onpagesettings={() => (dialog = { kind: "page-settings" })} + /> + +
+ + {app.activePath} + {#if app.dirty} + edited + {/if} +
+ + {#key app.target?.path + ":" + app.activePath} +
+ { + app.editorContent = value; + app.dirty = true; + scheduleCompile(); + }} + onsave={saveAndCompile} + onlspstatus={(status) => (app.lspStatus = status)} + onready={(view) => (editorView = view)} + /> +
+ {/key} + {:else} +
+ +

+ {app.activePath + ? "This file cannot be edited as text" + : "Select a file to edit"} +

+
+ {/if} +
+ +
+ +
+
+ {/if} +
+
+ +{#if imageViewer} + (imageViewer = null)} + /> +{/if} + +{#if dropActive} +
+
+ +

+ {app.view === "editor" + ? `Drop to add files to ${app.target?.path.split("/").pop()}` + : app.currentDir + ? `Drop to add files to ${app.currentDir.split("/").pop()}` + : "Drop to add files to your workspace"} +

+

+ Images, fonts, and Typst files are copied in. +

+
+
+{/if} + +{#if dialog.kind === "new-project"} + +{:else if dialog.kind === "new-folder"} + +{:else if dialog.kind === "new-document"} + +{:else if dialog.kind === "rename-entry"} + {@const target = dialog} + renameEntry(target.entry, name)} + onclose={close} + /> +{:else if dialog.kind === "delete-entry"} + {@const target = dialog} + deleteEntry(target.entry)} + onclose={close} + /> +{:else if dialog.kind === "link-entry"} + {@const target = dialog} + linkEntry(target.entry)} + onclose={close} + /> +{:else if dialog.kind === "new-space"} + +{:else if dialog.kind === "delete-space"} + {@const target = dialog} + deleteSpace(target.id)} + onclose={close} + /> +{:else if dialog.kind === "clone-space"} + {@const target = dialog} + cloneSpace(target.id, name)} + onclose={close} + /> +{:else if dialog.kind === "new-file"} + +{:else if dialog.kind === "new-subfolder"} + +{:else if dialog.kind === "rename-file"} + {@const target = dialog} + renameFile(target.path, next)} + onclose={close} + /> +{:else if dialog.kind === "delete-file"} + {@const target = dialog} + deleteFile(target.path)} + onclose={close} + /> +{:else if dialog.kind === "login"} + { + close(); + await refreshAccount(); + app.scope = "cloud"; + setStatus("Connected to TypstDrive"); + }} + onclose={close} + /> +{:else if dialog.kind === "settings"} + (dialog = { kind: "login" })} /> +{:else if dialog.kind === "assets"} + { + insertText(editorView, snippet); + close(); + } + : undefined} + onchanged={compile} + onclose={close} + /> +{:else if dialog.kind === "page-settings"} + +{:else if dialog.kind === "conflicts"} + +{/if} diff --git a/static/favicon.png b/static/favicon.png new file mode 100644 index 0000000..825b9e6 Binary files /dev/null and b/static/favicon.png differ diff --git a/static/svelte.svg b/static/svelte.svg new file mode 100644 index 0000000..c5e0848 --- /dev/null +++ b/static/svelte.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/tauri.svg b/static/tauri.svg new file mode 100644 index 0000000..31b62c9 --- /dev/null +++ b/static/tauri.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/static/vite.svg b/static/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/static/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svelte.config.js b/svelte.config.js new file mode 100644 index 0000000..a7830ea --- /dev/null +++ b/svelte.config.js @@ -0,0 +1,18 @@ +// Tauri doesn't have a Node.js server to do proper SSR +// so we use adapter-static with a fallback to index.html to put the site in SPA mode +// See: https://svelte.dev/docs/kit/single-page-apps +// See: https://v2.tauri.app/start/frontend/sveltekit/ for more info +import adapter from "@sveltejs/adapter-static"; +import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + preprocess: vitePreprocess(), + kit: { + adapter: adapter({ + fallback: "index.html", + }), + }, +}; + +export default config; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..f4d0a0e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } + // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias + // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files + // + // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes + // from the referenced tsconfig.json - TypeScript does not merge them in +} diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..afb0aab --- /dev/null +++ b/vite.config.js @@ -0,0 +1,36 @@ +import { defineConfig } from "vite"; +import { sveltekit } from "@sveltejs/kit/vite"; +import tailwindcss from "@tailwindcss/vite"; +import wasm from "vite-plugin-wasm"; +import topLevelAwait from "vite-plugin-top-level-await"; + +// @ts-expect-error process is a nodejs global +const host = process.env.TAURI_DEV_HOST; + +export default defineConfig(async () => ({ + plugins: [tailwindcss(), sveltekit(), wasm(), topLevelAwait()], + + optimizeDeps: { + exclude: ["codemirror-lang-typst"], + }, + build: { + target: "esnext", + }, + + clearScreen: false, + server: { + port: 1420, + strictPort: true, + host: host || false, + hmr: host + ? { + protocol: "ws", + host, + port: 1421, + } + : undefined, + watch: { + ignored: ["**/src-tauri/**"], + }, + }, +}));