diff --git a/examples/statistics-output/page/.bun-version b/.bun-version similarity index 100% rename from examples/statistics-output/page/.bun-version rename to .bun-version diff --git a/.github/actions/prepare-resources/action.yml b/.github/actions/prepare-resources/action.yml new file mode 100644 index 00000000..ee382674 --- /dev/null +++ b/.github/actions/prepare-resources/action.yml @@ -0,0 +1,24 @@ +name: Prepare Resources +description: ページのレンダリングなど必要なリソースを準備する + +runs: + using: "composite" + steps: + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version-file: ".bun-version" + + - name: Build Page (Statistics Output) + shell: bash + working-directory: examples/statistics-output/page + run: | + bun install --frozen-lockfile + bun run build + + - name: Build Page (Local Alias Plugin) + shell: bash + working-directory: examples/local-alias-plugin/page + run: | + bun install --frozen-lockfile + bun run build diff --git a/.github/actions/render-statistics-page/action.yml b/.github/actions/render-statistics-page/action.yml deleted file mode 100644 index ab827103..00000000 --- a/.github/actions/render-statistics-page/action.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Render Statistics Plugin's page -description: statistics-outputのページをレンダリングする - -runs: - using: "composite" - steps: - - name: Restore cache - uses: actions/cache@v4 - id: cache - with: - path: examples/statistics-output/page/dist - key: statistics-${{ hashFiles('examples/statistics-output/src/**/*', 'examples/statistics-output/page/.bun-version', 'examples/statistics-output/page/bun.lock') }} - - - name: Setup Bun - if: steps.cache.outputs.cache-hit != 'true' - uses: oven-sh/setup-bun@v2 - with: - bun-version-file: "examples/statistics-output/page/.bun-version" - - - name: Install dependencies - shell: bash - if: steps.cache.outputs.cache-hit != 'true' - working-directory: examples/statistics-output/page - run: | - bun install --frozen-lockfile - - - name: Build - shell: bash - if: steps.cache.outputs.cache-hit != 'true' - working-directory: examples/statistics-output/page - run: | - bun run build diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 00b8c732..98eb69be 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,7 +35,7 @@ jobs: cargo update --workspace - name: Build Page - uses: ./.github/actions/render-statistics-page + uses: ./.github/actions/prepare-resources - name: Build project run: | diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index f8766b43..65e8e84b 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -23,7 +23,7 @@ jobs: uses: ./.github/actions/setup-environment - name: Build Page - uses: ./.github/actions/render-statistics-page + uses: ./.github/actions/prepare-resources - name: Run format run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 64a0a1df..4d0dee03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - **Breaking:** module: IntoScriptModuleReturnValue traitの返り値をanyhow::Errorから変更 - **Breaking:** module: `&[T]`、`[T]`はVecとして返すように変更 - **Breaking:** `odbg!`、`oprintln!`を削除 +- 汎用プラグインを追加 - `log`クレートで本体のログに出力できるように - aviutl2-aliasを追加 - filter: effect_idを追加 diff --git a/Cargo.lock b/Cargo.lock index e5be37c4..9d8d1780 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -140,9 +140,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -153,6 +153,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" +[[package]] +name = "aligned" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "377e4c0ba83e4431b10df45c1d4666f178ea9c552cac93e60c3a88bf32785923" +dependencies = [ + "as-slice", +] + [[package]] name = "aligned-vec" version = "0.6.4" @@ -210,12 +219,56 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + [[package]] name = "anstyle" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + [[package]] name = "anyhow" version = "1.0.100" @@ -259,7 +312,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -280,6 +333,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" +[[package]] +name = "as-slice" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" +dependencies = [ + "stable_deref_trait", +] + [[package]] name = "ascii" version = "1.1.0" @@ -388,7 +450,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -423,7 +485,30 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", +] + +[[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]] @@ -488,16 +573,36 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "av-scenechange" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394" +dependencies = [ + "aligned", + "anyhow", + "arg_enum_proc_macro", + "arrayvec", + "log", + "num-rational", + "num-traits", + "pastey", + "rayon", + "thiserror 2.0.17", + "v_frame", + "y4m", +] + [[package]] name = "av1-grain" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" dependencies = [ "anyhow", "arrayvec", "log", - "nom 7.1.3", + "nom", "num-rational", "v_frame", ] @@ -526,9 +631,13 @@ dependencies = [ "log", "native-dialog", "num-rational", + "pastey", "raw-window-handle", + "rmp-serde", + "serde", "thiserror 2.0.17", "zerocopy", + "zstd", ] [[package]] @@ -554,7 +663,7 @@ dependencies = [ "proc-macro2", "quote", "rustfmt-wrapper", - "syn", + "syn 2.0.111", ] [[package]] @@ -617,9 +726,12 @@ dependencies = [ [[package]] name = "bitstream-io" -version = "2.6.0" +version = "4.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" +checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757" +dependencies = [ + "core2", +] [[package]] name = "block" @@ -669,9 +781,9 @@ dependencies = [ [[package]] name = "built" -version = "0.7.7" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" +checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" [[package]] name = "bumpalo" @@ -696,7 +808,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -713,19 +825,44 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "bzip2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea8dcd42434048e4f7a304411d9273a411f647446c1234a65ce0554923f4cff" +checksum = "f3a53fac24f34a81bc9954b5d6cfce0c21e18ec6959f44f56e8e90e4bb7c346c" dependencies = [ "libbz2-rs-sys", ] +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags 2.10.0", + "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 = "calloop" version = "0.13.0" @@ -740,18 +877,43 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "calloop" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb9f6e1368bd4621d2c86baa7e37de77a938adf5221e5dd3d6133340101b309e" +dependencies = [ + "bitflags 2.10.0", + "polling", + "rustix 1.1.2", + "slab", + "tracing", +] + [[package]] name = "calloop-wayland-source" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" dependencies = [ - "calloop", + "calloop 0.13.0", "rustix 0.38.44", "wayland-backend", "wayland-client", ] +[[package]] +name = "calloop-wayland-source" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa" +dependencies = [ + "calloop 0.14.3", + "rustix 1.1.2", + "wayland-backend", + "wayland-client", +] + [[package]] name = "cast" version = "0.3.0" @@ -760,9 +922,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.41" +version = "1.2.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" +checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a" dependencies = [ "find-msvc-tools", "jobserver", @@ -794,9 +956,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -865,18 +1027,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.49" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.49" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" dependencies = [ "anstyle", "clap_lex", @@ -914,6 +1076,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + [[package]] name = "combine" version = "4.6.7" @@ -951,6 +1119,22 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[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.9.4" @@ -990,6 +1174,19 @@ dependencies = [ "libc", ] +[[package]] +name = "core-graphics" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" +dependencies = [ + "bitflags 2.10.0", + "core-foundation 0.10.1", + "core-graphics-types 0.2.0", + "foreign-types", + "libc", +] + [[package]] name = "core-graphics-types" version = "0.1.3" @@ -1012,6 +1209,15 @@ dependencies = [ "libc", ] +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -1023,9 +1229,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] @@ -1078,6 +1284,15 @@ dependencies = [ "itertools 0.13.0", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -1111,14 +1326,41 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", ] +[[package]] +name = "cssparser" +version = "0.29.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "matches", + "phf 0.10.1", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", +] + +[[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.111", +] + [[package]] name = "cursor-icon" version = "1.2.0" @@ -1156,7 +1398,7 @@ checksum = "a8a3dee4e932355439992a45dc631b0979abf9c677958674bd94298bf9002870" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -1167,9 +1409,9 @@ checksum = "26bf8fc351c5ed29b5c2f0cbbac1b209b74f60ecd62e675a998df72c49af5204" [[package]] name = "deranged" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -1182,7 +1424,20 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", +] + +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.111", ] [[package]] @@ -1243,7 +1498,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -1255,11 +1510,34 @@ dependencies = [ "libloading", ] +[[package]] +name = "dlopen2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d65cde5fb0c42a3d5882d99807698b459f5928de035fa7f547c784fb7b34219" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95f4a04e1bfbfa4835a6073177aafb95ead4de0722dbb339195fdc7e0a09599b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "document-features" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" dependencies = [ "litrs", ] @@ -1276,6 +1554,27 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" +[[package]] +name = "dtoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "duplicate" version = "2.0.1" @@ -1287,6 +1586,12 @@ dependencies = [ "proc-macro2-diagnostics", ] +[[package]] +name = "easy-ext" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc5d6d6a8504f8caedd7de14576464383900cd3840b7033a7a3dce5ac00121ca" + [[package]] name = "ecolor" version = "0.32.3" @@ -1423,11 +1728,11 @@ checksum = "89d8b097288a2021b2c5a26f36c8badccb44817d960668137acd5661be49eafa" dependencies = [ "egui", "egui_commonmark_backend", - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "pulldown-cmark", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -1484,11 +1789,20 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "endi" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" +checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" [[package]] name = "enum-map" @@ -1507,7 +1821,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -1528,7 +1842,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -1547,6 +1861,19 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + [[package]] name = "epaint" version = "0.32.3" @@ -1588,7 +1915,7 @@ checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -1697,7 +2024,7 @@ dependencies = [ "anyhow", "aviutl2", "duplicate", - "gif", + "gif 0.13.3", "image", "insta", "ordered-float 5.1.0", @@ -1716,6 +2043,27 @@ dependencies = [ "regex", ] +[[package]] +name = "example-local-alias-plugin" +version = "0.10.0" +dependencies = [ + "anyhow", + "aviutl2", + "dirs", + "env_logger", + "include_dir", + "log", + "mime_guess", + "open", + "raw-window-handle", + "serde", + "serde_json", + "tao", + "tap", + "windows 0.58.0", + "wry", +] + [[package]] name = "example-midi-player-input" version = "0.10.0" @@ -1751,6 +2099,17 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "example-srt-file-plugin" +version = "0.10.0" +dependencies = [ + "anyhow", + "aviutl2", + "easy-ext", + "native-dialog", + "srtlib", +] + [[package]] name = "example-statistics-output" version = "0.10.0" @@ -1787,9 +2146,9 @@ dependencies = [ [[package]] name = "exr" -version = "1.73.0" +version = "1.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" dependencies = [ "bit_field", "half", @@ -1823,7 +2182,7 @@ checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -1835,29 +2194,33 @@ dependencies = [ "simd-adler32", ] +[[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 = "find-msvc-tools" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "flate2" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "libz-rs-sys", "miniz_oxide", ] -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "foldhash" version = "0.1.5" @@ -1888,7 +2251,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -1914,19 +2277,49 @@ checksum = "d8866fac38f53fc87fa3ae1b09ddd723e0482f8fa74323518b4c59df2c55a00a" [[package]] name = "fs-err" -version = "3.1.3" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad492b2cf1d89d568a43508ab24f98501fe03f2f31c01e1d0fe7366a71745d2" +checksum = "62d91fd049c123429b018c47887d3f75a265540dd3c30ba9cb7bae9197edb03a" dependencies = [ "autocfg", ] +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.31" @@ -1954,7 +2347,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -1983,11 +2376,119 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[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.9" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -2003,6 +2504,17 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.16" @@ -2011,7 +2523,7 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] @@ -2036,6 +2548,48 @@ dependencies = [ "weezl", ] +[[package]] +name = "gif" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f954a9e9159ec994f73a30a12b96a702dde78f5547bcb561174597924f7d4162" +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 = "gl_generator" version = "0.14.0" @@ -2047,6 +2601,53 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "glib" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +dependencies = [ + "bitflags 2.10.0", + "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.111", +] + +[[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 = "glob" version = "0.3.3" @@ -2131,6 +2732,17 @@ dependencies = [ "gl_generator", ] +[[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 = "gpu-alloc" version = "0.6.0" @@ -2182,6 +2794,58 @@ dependencies = [ "bitflags 2.10.0", ] +[[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.111", +] + [[package]] name = "half" version = "2.7.1" @@ -2211,9 +2875,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", @@ -2261,11 +2925,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2279,14 +2943,25 @@ dependencies = [ "rustfft", ] +[[package]] +name = "html5ever" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" +dependencies = [ + "log", + "mac", + "markup5ever", + "match_token", +] + [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -2322,9 +2997,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -2335,9 +3010,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -2348,11 +3023,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -2363,42 +3037,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -2429,15 +3099,15 @@ dependencies = [ [[package]] name = "image" -version = "0.25.8" +version = "0.25.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7" +checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" dependencies = [ "bytemuck", "byteorder-lite", "color_quant", "exr", - "gif", + "gif 0.14.0", "image-webp", "moxcms", "num-traits", @@ -2447,8 +3117,8 @@ dependencies = [ "rayon", "rgb", "tiff", - "zune-core", - "zune-jpeg", + "zune-core 0.5.0", + "zune-jpeg 0.5.5", ] [[package]] @@ -2467,14 +3137,33 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "indexmap" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown 0.16.1", ] [[package]] @@ -2488,9 +3177,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.43.2" +version = "1.44.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fdb647ebde000f43b5b53f773c30cf9b0cb4300453208713fa38b2c70935a0" +checksum = "b5c943d4415edd8153251b6f197de5eb1640e56d84e8d9159bea190421c73698" dependencies = [ "console", "once_cell", @@ -2505,7 +3194,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -2528,13 +3217,10 @@ dependencies = [ ] [[package]] -name = "itertools" -version = "0.12.1" +name = "is_terminal_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -2560,6 +3246,53 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[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 = "jiff" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "jni" version = "0.21.1" @@ -2594,9 +3327,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -2619,11 +3352,23 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" +[[package]] +name = "kuchikiki" +version = "0.8.8-speedreader" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" +dependencies = [ + "cssparser", + "html5ever", + "indexmap", + "selectors", +] + [[package]] name = "lazy-regex" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60c7310b93682b36b98fa7ea4de998d3463ccbebd94d935d6b48ba5b6ffa7126" +checksum = "191898e17ddee19e60bccb3945aa02339e81edd4a8c50e21fd4d48cdecda7b29" dependencies = [ "lazy-regex-proc_macros", "once_cell", @@ -2632,16 +3377,22 @@ dependencies = [ [[package]] name = "lazy-regex-proc_macros" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ba01db5ef81e17eb10a5e0f2109d1b3a3e29bac3070fdbd7d156bf7dbd206a1" +checksum = "c35dc8b0da83d1a9507e12122c80dea71a9c7c613014347392483a83ea593e04" dependencies = [ "proc-macro2", "quote", "regex", - "syn", + "syn 2.0.111", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "lebe" version = "0.5.3" @@ -2720,15 +3471,15 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "litrs" -version = "0.4.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "lock_api" @@ -2760,7 +3511,7 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96051b46fc183dc9cd4a223960ef37b9af631b55191852a8274bfef064cda20f" dependencies = [ - "hashbrown 0.16.0", + "hashbrown 0.16.1", ] [[package]] @@ -2773,6 +3524,12 @@ dependencies = [ "sha2", ] +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + [[package]] name = "malloc_buf" version = "0.0.6" @@ -2782,6 +3539,37 @@ dependencies = [ "libc", ] +[[package]] +name = "markup5ever" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" +dependencies = [ + "log", + "phf 0.11.3", + "phf_codegen 0.11.3", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "match_token" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + [[package]] name = "maybe-rayon" version = "0.1.1" @@ -2800,9 +3588,9 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memmap2" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" dependencies = [ "libc", ] @@ -2862,22 +3650,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] -name = "mime_guess2" -version = "2.3.1" +name = "mime_guess" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1706dc14a2e140dec0a7a07109d9a3d5890b81e85bd6c60b906b249a77adf0ca" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", - "phf", - "phf_shared", "unicase", ] [[package]] -name = "minimal-lexical" -version = "0.2.1" +name = "mime_guess2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +checksum = "1706dc14a2e140dec0a7a07109d9a3d5890b81e85bd6c60b906b249a77adf0ca" +dependencies = [ + "mime", + "phf 0.11.3", + "phf_shared 0.11.3", + "unicase", +] [[package]] name = "miniz_oxide" @@ -2891,9 +3683,9 @@ dependencies = [ [[package]] name = "moxcms" -version = "0.7.7" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c588e11a3082784af229e23e8e4ecf5bcc6fbe4f69101e0421ce8d79da7f0b40" +checksum = "80986bbbcf925ebd3be54c26613d861255284584501595cf418320c078945608" dependencies = [ "num-traits", "pxfm", @@ -2926,9 +3718,9 @@ dependencies = [ [[package]] name = "naga" -version = "27.0.0" +version = "27.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b2e757b11b47345d44e7760e45458339bc490463d9548cd8651c53ae523153" +checksum = "066cf25f0e8b11ee0df221219010f213ad429855f57c494f995590c861a9a7d8" dependencies = [ "arrayvec", "bit-set", @@ -2937,7 +3729,7 @@ dependencies = [ "cfg_aliases", "codespan-reporting", "half", - "hashbrown 0.16.0", + "hashbrown 0.16.1", "hexf-parse", "indexmap", "libm", @@ -2952,9 +3744,9 @@ dependencies = [ [[package]] name = "native-dialog" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1657b63bf0e60ee0eca886b5df70269240b6197b6ee46ec37da9a7d28d8e8e24" +checksum = "89853bb05334e192e6646290ea94ca31bcb80443f25ad40ebf478b6dafb08d6c" dependencies = [ "ascii", "block2 0.6.2", @@ -3033,20 +3825,16 @@ dependencies = [ ] [[package]] -name = "nohash-hasher" -version = "0.2.0" +name = "nodrop" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" [[package]] -name = "nom" -version = "7.1.3" +name = "nohash-hasher" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "nom" @@ -3096,7 +3884,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -3131,9 +3919,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -3141,14 +3929,14 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -3183,6 +3971,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" dependencies = [ "objc2-encode", + "objc2-exception-helper", ] [[package]] @@ -3305,6 +4094,15 @@ 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.2.2" @@ -3408,6 +4206,18 @@ dependencies = [ "objc2-user-notifications", ] +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags 2.10.0", + "objc2 0.6.3", + "objc2-core-foundation", + "objc2-foundation 0.3.2", +] + [[package]] name = "objc2-uniform-type-identifiers" version = "0.2.2" @@ -3432,12 +4242,32 @@ dependencies = [ "objc2-foundation 0.2.2", ] +[[package]] +name = "objc2-web-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" +dependencies = [ + "bitflags 2.10.0", + "block2 0.6.2", + "objc2 0.6.3", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", +] + [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "oorandom" version = "11.1.5" @@ -3446,9 +4276,9 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "open" -version = "5.3.2" +version = "5.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95" +checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" dependencies = [ "is-wsl", "libc", @@ -3463,9 +4293,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "orbclient" -version = "0.3.48" +version = "0.3.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba0b26cec2e24f08ed8bb31519a9333140a6599b867dac464bb150bdb796fd43" +checksum = "247ad146e19b9437f8604c21f8652423595cf710ad108af40e77d3ae6e96b827" dependencies = [ "libredox", ] @@ -3519,7 +4349,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -3531,6 +4361,31 @@ dependencies = [ "ttf-parser", ] +[[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" @@ -3564,38 +4419,104 @@ dependencies = [ name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pastey" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[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.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_shared 0.8.0", +] + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_macros 0.10.0", + "phf_shared 0.10.0", + "proc-macro-hack", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros 0.11.3", + "phf_shared 0.11.3", +] [[package]] -name = "pathdiff" -version = "0.2.3" +name = "phf_codegen" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", +] [[package]] -name = "pbkdf2" -version = "0.12.2" +name = "phf_codegen" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ - "digest", - "hmac", + "phf_generator 0.11.3", + "phf_shared 0.11.3", ] [[package]] -name = "percent-encoding" -version = "2.3.2" +name = "phf_generator" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared 0.8.0", + "rand 0.7.3", +] [[package]] -name = "phf" -version = "0.11.3" +name = "phf_generator" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" dependencies = [ - "phf_macros", - "phf_shared", + "phf_shared 0.10.0", + "rand 0.8.5", ] [[package]] @@ -3604,31 +4525,63 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ - "phf_shared", + "phf_shared 0.11.3", "rand 0.8.5", ] +[[package]] +name = "phf_macros" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "phf_macros" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.11.3", + "phf_shared 0.11.3", "proc-macro2", "quote", - "syn", + "syn 2.0.111", "unicase", ] +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher 0.3.11", +] + [[package]] name = "phf_shared" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ - "siphasher", + "siphasher 1.0.1", "unicase", ] @@ -3649,7 +4602,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -3759,9 +4712,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -3774,9 +4727,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppmd-rust" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c834641d8ad1b348c9ee86dec3b9840d805acd5f24daa5f90c788951a52ff59b" +checksum = "d558c559f0450f16f2a27a1f017ef38468c1090c9ce63c8e51366232d53717b4" [[package]] name = "ppv-lite86" @@ -3787,6 +4740,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + [[package]] name = "presser" version = "0.3.1" @@ -3802,6 +4761,26 @@ dependencies = [ "num-integer", ] +[[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.4.0" @@ -3811,11 +4790,41 @@ dependencies = [ "toml_edit 0.23.7", ] +[[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.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -3828,7 +4837,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", "version_check", "yansi", ] @@ -3859,7 +4868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" dependencies = [ "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -3875,9 +4884,9 @@ dependencies = [ [[package]] name = "pxfm" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cbdf373972bf78df4d3b518d07003938e2c7d1fb5891e55f9cb6df57009d84" +checksum = "b3502d6155304a4173a5f2c34b52b7ed0dd085890326cb50fd625fdf39e86b3b" dependencies = [ "num-traits", ] @@ -3918,9 +4927,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -3931,6 +4940,20 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + [[package]] name = "rand" version = "0.8.5" @@ -3952,6 +4975,16 @@ dependencies = [ "rand_core 0.9.3", ] +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -3972,6 +5005,15 @@ dependencies = [ "rand_core 0.9.3", ] +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + [[package]] name = "rand_core" version = "0.6.4" @@ -3990,6 +5032,24 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + [[package]] name = "range-alloc" version = "0.1.4" @@ -3998,19 +5058,21 @@ checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde" [[package]] name = "rav1e" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b" dependencies = [ + "aligned-vec", "arbitrary", "arg_enum_proc_macro", "arrayvec", + "av-scenechange", "av1-grain", "bitstream-io", "built", "cfg-if", "interpolate_name", - "itertools 0.12.1", + "itertools 0.14.0", "libc", "libfuzzer-sys", "log", @@ -4019,23 +5081,21 @@ dependencies = [ "noop_proc_macro", "num-derive", "num-traits", - "once_cell", "paste", "profiling", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand 0.9.2", + "rand_chacha 0.9.0", "simd_helpers", - "system-deps", - "thiserror 1.0.69", + "thiserror 2.0.17", "v_frame", "wasm-bindgen", ] [[package]] name = "ravif" -version = "0.11.20" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b" +checksum = "ef69c1990ceef18a116855938e74793a5f7496ee907562bd0857b6ac734ab285" dependencies = [ "avif-serialize", "imgref", @@ -4177,6 +5237,28 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57b0b88a509053cbfd535726dcaaceee631313cef981266119527a1d110f6d2b" +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + [[package]] name = "rstest" version = "0.26.1" @@ -4196,13 +5278,13 @@ checksum = "9c845311f0ff7951c5506121a9ad75aec44d083c31583b2ea5a30bcb0b0abba0" dependencies = [ "cfg-if", "glob", - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", "regex", "relative-path", "rustc_version", - "syn", + "syn 2.0.111", "unicode-ident", ] @@ -4294,9 +5376,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.32" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "log", "once_cell", @@ -4307,29 +5389,20 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.7" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "ring", "rustls-pki-types", @@ -4356,9 +5429,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "safe_arch" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb5032219cc30e5bb98749b19a18ceb2cf15e24ba8d517a7e64dff4f1f1eca5" +checksum = "629516c85c29fe757770fa03f2074cf1eac43d44c02a3de9fc2ef7b0e207dfdd" dependencies = [ "bytemuck", ] @@ -4393,10 +5466,28 @@ dependencies = [ "ab_glyph", "log", "memmap2", - "smithay-client-toolkit", + "smithay-client-toolkit 0.19.2", "tiny-skia", ] +[[package]] +name = "selectors" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" +dependencies = [ + "bitflags 1.3.2", + "cssparser", + "derive_more", + "fxhash", + "log", + "phf 0.8.0", + "phf_codegen 0.8.0", + "precomputed-hash", + "servo_arc", + "smallvec", +] + [[package]] name = "semver" version = "1.0.27" @@ -4430,7 +5521,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -4454,7 +5545,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -4466,6 +5557,16 @@ dependencies = [ "serde", ] +[[package]] +name = "servo_arc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" +dependencies = [ + "nodrop", + "stable_deref_trait", +] + [[package]] name = "sha1" version = "0.10.6" @@ -4496,9 +5597,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" dependencies = [ "libc", ] @@ -4524,6 +5625,12 @@ version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "siphasher" version = "1.0.1" @@ -4558,8 +5665,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ "bitflags 2.10.0", - "calloop", - "calloop-wayland-source", + "calloop 0.13.0", + "calloop-wayland-source 0.3.0", "cursor-icon", "libc", "log", @@ -4576,14 +5683,41 @@ dependencies = [ "xkeysym", ] +[[package]] +name = "smithay-client-toolkit" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" +dependencies = [ + "bitflags 2.10.0", + "calloop 0.14.3", + "calloop-wayland-source 0.4.1", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 1.1.2", + "thiserror 2.0.17", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-experimental", + "wayland-protocols-misc", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + [[package]] name = "smithay-clipboard" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc8216eec463674a0e90f29e0ae41a4db573ec5b56b1c6c1c71615d249b6d846" +checksum = "71704c03f739f7745053bde45fa203a46c58d25bc5c4efba1d9a60e9dba81226" dependencies = [ "libc", - "smithay-client-toolkit", + "smithay-client-toolkit 0.20.0", "wayland-backend", ] @@ -4596,6 +5730,32 @@ dependencies = [ "serde", ] +[[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 = "spirv" version = "0.3.0+sdk-1.3.268.0" @@ -4605,6 +5765,15 @@ dependencies = [ "bitflags 2.10.0", ] +[[package]] +name = "srtlib" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf36f30c19e578c5390523c7b676c2297c51012f153d2f9bf76ebf4f51c40ffa" +dependencies = [ + "encoding_rs", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -4635,6 +5804,31 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +[[package]] +name = "string_cache" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared 0.11.3", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", +] + [[package]] name = "strum" version = "0.26.3" @@ -4654,7 +5848,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn", + "syn 2.0.111", ] [[package]] @@ -4665,9 +5859,20 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.106" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -4682,7 +5887,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -4698,6 +5903,63 @@ dependencies = [ "version-compare", ] +[[package]] +name = "tao" +version = "0.34.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a753bdc39c07b192151523a3f77cd0394aa75413802c883a0f6f6a0e5ee2e7" +dependencies = [ + "bitflags 2.10.0", + "block2 0.6.2", + "core-foundation 0.10.1", + "core-graphics 0.24.0", + "crossbeam-channel", + "dispatch", + "dlopen2", + "dpi", + "gdkwayland-sys", + "gdkx11-sys", + "gtk", + "jni", + "lazy_static", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys 0.6.0+11769913", + "objc2 0.6.3", + "objc2-app-kit 0.3.2", + "objc2-foundation 0.3.2", + "once_cell", + "parking_lot", + "raw-window-handle", + "scopeguard", + "tao-macros", + "unicode-segmentation", + "url", + "windows 0.61.3", + "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.111", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "target-lexicon" version = "0.12.16" @@ -4717,6 +5979,17 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + [[package]] name = "termcolor" version = "1.4.1" @@ -4752,7 +6025,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -4763,7 +6036,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -4777,7 +6050,7 @@ dependencies = [ "half", "quick-error", "weezl", - "zune-jpeg", + "zune-jpeg 0.4.21", ] [[package]] @@ -4787,10 +6060,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", + "itoa", "num-conv", "powerfmt", "serde", "time-core", + "time-macros", ] [[package]] @@ -4799,6 +6074,16 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +[[package]] +name = "time-macros" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tiny-skia" version = "0.11.4" @@ -4826,9 +6111,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -4846,21 +6131,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.23" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" dependencies = [ "serde", "serde_spanned", - "toml_datetime 0.6.11", - "toml_edit 0.22.27", + "toml_datetime 0.6.3", + "toml_edit 0.20.2", ] [[package]] name = "toml_datetime" -version = "0.6.11" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] @@ -4876,16 +6161,26 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.27" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "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 = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ "indexmap", "serde", "serde_spanned", - "toml_datetime 0.6.11", - "toml_write", - "winnow", + "toml_datetime 0.6.3", + "winnow 0.5.40", ] [[package]] @@ -4897,7 +6192,7 @@ dependencies = [ "indexmap", "toml_datetime 0.7.3", "toml_parser", - "winnow", + "winnow 0.7.14", ] [[package]] @@ -4906,15 +6201,9 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ - "winnow", + "winnow 0.7.14", ] -[[package]] -name = "toml_write" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" - [[package]] name = "toolchain_find" version = "0.4.0" @@ -4930,10 +6219,11 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4941,20 +6231,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" dependencies = [ "once_cell", ] @@ -5009,9 +6299,9 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" @@ -5033,16 +6323,15 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "3.1.2" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99ba1025f18a4a3fc3e9b48c868e9beb4f24f4b4b1a325bada26bd4119f46537" +checksum = "d39cb1dbab692d82a977c0392ffac19e188bd9186a9f32806f0aaa859d75585a" dependencies = [ "base64", "flate2", "log", "percent-encoding", "rustls", - "rustls-pemfile", "rustls-pki-types", "ureq-proto", "utf-8", @@ -5051,9 +6340,9 @@ dependencies = [ [[package]] name = "ureq-proto" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b4531c118335662134346048ddb0e54cc86bd7e81866757873055f0e38f5d2" +checksum = "d81f9efa9df032be5934a46a068815a10a042b494b6a58cb0a1a97bb5467ed6f" dependencies = [ "base64", "http", @@ -5085,14 +6374,21 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" -version = "1.18.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" dependencies = [ "getrandom 0.3.4", "js-sys", + "serde_core", "wasm-bindgen", ] @@ -5109,9 +6405,9 @@ dependencies = [ [[package]] name = "version-compare" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" [[package]] name = "version_check" @@ -5126,7 +6422,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80a7e511ce1795821207a837b7b1c8d8aca0c648810966ad200446ae58f6667f" dependencies = [ "itertools 0.14.0", - "nom 8.0.0", + "nom", ] [[package]] @@ -5139,6 +6435,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -5162,9 +6464,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", @@ -5173,25 +6475,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.54" +version = "0.4.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" dependencies = [ "cfg-if", "js-sys", @@ -5202,9 +6490,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5212,22 +6500,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn", - "wasm-bindgen-backend", + "syn 2.0.111", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] @@ -5292,6 +6580,32 @@ dependencies = [ "wayland-scanner", ] +[[package]] +name = "wayland-protocols-experimental" +version = "20250721.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1" +dependencies = [ + "bitflags 2.10.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-misc" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfe33d551eb8bffd03ff067a8b44bb963919157841a99957151299a6307d19c" +dependencies = [ + "bitflags 2.10.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + [[package]] name = "wayland-protocols-plasma" version = "0.3.9" @@ -5343,9 +6657,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" dependencies = [ "js-sys", "wasm-bindgen", @@ -5363,9 +6677,9 @@ dependencies = [ [[package]] name = "webbrowser" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf4f3c0ba838e82b4e5ccc4157003fb8c324ee24c058470ffb82820becbde98" +checksum = "00f1243ef785213e3a32fa0396093424a3a6ea566f9948497e5a2309261a4c97" dependencies = [ "core-foundation 0.10.1", "jni", @@ -5377,20 +6691,100 @@ dependencies = [ "web-sys", ] +[[package]] +name = "webkit2gtk" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" +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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" +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 = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webview2-com" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows 0.61.3", + "windows-core 0.61.2", + "windows-implement 0.60.2", + "windows-interface 0.59.3", +] + +[[package]] +name = "webview2-com-macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "webview2-com-sys" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" +dependencies = [ + "thiserror 2.0.17", + "windows 0.61.3", + "windows-core 0.61.2", +] + [[package]] name = "weezl" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "wfd" @@ -5441,10 +6835,10 @@ dependencies = [ "cfg-if", "cfg_aliases", "document-features", - "hashbrown 0.16.0", + "hashbrown 0.16.1", "js-sys", "log", - "naga 27.0.0", + "naga 27.0.3", "parking_lot", "portable-atomic", "profiling", @@ -5454,8 +6848,8 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "wgpu-core 27.0.1", - "wgpu-hal 27.0.2", + "wgpu-core 27.0.3", + "wgpu-hal 27.0.4", "wgpu-types 27.0.1", ] @@ -5492,9 +6886,9 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "27.0.1" +version = "27.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d654c0b6c6335edfca18c11bdaed964def641b8e9997d3a495a2ff4077c922" +checksum = "27a75de515543b1897b26119f93731b385a19aea165a1ec5f0e3acecc229cae7" dependencies = [ "arrayvec", "bit-set", @@ -5503,10 +6897,10 @@ dependencies = [ "bytemuck", "cfg_aliases", "document-features", - "hashbrown 0.16.0", + "hashbrown 0.16.1", "indexmap", "log", - "naga 27.0.0", + "naga 27.0.3", "once_cell", "parking_lot", "portable-atomic", @@ -5518,7 +6912,7 @@ dependencies = [ "wgpu-core-deps-apple 27.0.0", "wgpu-core-deps-emscripten 27.0.0", "wgpu-core-deps-windows-linux-android 27.0.0", - "wgpu-hal 27.0.2", + "wgpu-hal 27.0.4", "wgpu-types 27.0.1", ] @@ -5537,7 +6931,7 @@ version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0772ae958e9be0c729561d5e3fd9a19679bcdfb945b8b1a1969d9bfe8056d233" dependencies = [ - "wgpu-hal 27.0.2", + "wgpu-hal 27.0.4", ] [[package]] @@ -5555,7 +6949,7 @@ version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b06ac3444a95b0813ecfd81ddb2774b66220b264b3e2031152a4a29fda4da6b5" dependencies = [ - "wgpu-hal 27.0.2", + "wgpu-hal 27.0.4", ] [[package]] @@ -5573,7 +6967,7 @@ version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71197027d61a71748e4120f05a9242b2ad142e3c01f8c1b47707945a879a03c3" dependencies = [ - "wgpu-hal 27.0.2", + "wgpu-hal 27.0.4", ] [[package]] @@ -5625,9 +7019,9 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "27.0.2" +version = "27.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2618a2d6b8a5964ecc1ac32a5db56cb3b1e518725fcd773fd9a782e023453f2b" +checksum = "5b21cb61c57ee198bc4aff71aeadff4cbb80b927beb912506af9c780d64313ce" dependencies = [ "android_system_properties", "arrayvec", @@ -5644,18 +7038,18 @@ dependencies = [ "gpu-alloc", "gpu-allocator", "gpu-descriptor", - "hashbrown 0.16.0", + "hashbrown 0.16.1", "js-sys", "khronos-egl", "libc", "libloading", "log", "metal 0.32.0", - "naga 27.0.0", + "naga 27.0.3", "ndk-sys 0.6.0+11769913", "objc", "once_cell", - "ordered-float 4.6.0", + "ordered-float 5.1.0", "parking_lot", "portable-atomic", "portable-atomic-util", @@ -5725,9 +7119,9 @@ dependencies = [ [[package]] name = "wide" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e9aba2ca45c04ecbf5c516b21b4a16ddb2cc43f69c10adb08956c2fe1ec081" +checksum = "13ca908d26e4786149c48efcf6c0ea09ab0e06d1fe3c17dc1b4b0f1ca4a7e788" dependencies = [ "bytemuck", "safe_arch", @@ -5854,7 +7248,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -5865,7 +7259,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -5876,7 +7270,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -5887,7 +7281,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -6069,6 +7463,15 @@ 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" @@ -6219,11 +7622,11 @@ dependencies = [ "bitflags 2.10.0", "block2 0.5.1", "bytemuck", - "calloop", + "calloop 0.13.0", "cfg_aliases", "concurrent-queue", "core-foundation 0.9.4", - "core-graphics", + "core-graphics 0.23.2", "cursor-icon", "dpi", "js-sys", @@ -6233,7 +7636,7 @@ dependencies = [ "objc2 0.5.2", "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", - "objc2-ui-kit", + "objc2-ui-kit 0.2.2", "orbclient", "percent-encoding", "pin-project", @@ -6241,7 +7644,7 @@ dependencies = [ "redox_syscall 0.4.1", "rustix 0.38.44", "sctk-adwaita", - "smithay-client-toolkit", + "smithay-client-toolkit 0.19.2", "smol_str", "tracing", "unicode-segmentation", @@ -6261,9 +7664,18 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.13" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] @@ -6282,9 +7694,64 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wry" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728b7d4c8ec8d81cab295e0b5b8a4c263c0d41a785fb8f8c4df284e5411140a2" +dependencies = [ + "base64", + "block2 0.6.2", + "cookie", + "crossbeam-channel", + "dirs", + "dpi", + "dunce", + "gdkx11", + "gtk", + "html5ever", + "http", + "javascriptcore-rs", + "jni", + "kuchikiki", + "libc", + "ndk", + "objc2 0.6.3", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-ui-kit 0.3.2", + "objc2-web-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "sha2", + "soup3", + "tao-macros", + "thiserror 2.0.17", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows 0.61.3", + "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 = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] [[package]] name = "x11-dl" @@ -6345,9 +7812,15 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "xml-rs" -version = "0.8.27" +version = "0.8.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" + +[[package]] +name = "y4m" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7" +checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" [[package]] name = "yansi" @@ -6357,11 +7830,10 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -6369,21 +7841,21 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", "synstructure", ] [[package]] name = "zbus" -version = "5.11.0" +version = "5.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d07e46d035fb8e375b2ce63ba4e4ff90a7f73cf2ffb0138b29e1158d2eaadf7" +checksum = "b622b18155f7a93d1cd2dc8c01d2d6a44e08fb9ebb7b3f9e6ed101488bad6c91" dependencies = [ "async-broadcast", "async-executor", @@ -6405,8 +7877,9 @@ dependencies = [ "serde_repr", "tracing", "uds_windows", - "windows-sys 0.60.2", - "winnow", + "uuid", + "windows-sys 0.61.2", + "winnow 0.7.14", "zbus_macros", "zbus_names", "zvariant", @@ -6414,9 +7887,9 @@ dependencies = [ [[package]] name = "zbus-lockstep" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29e96e38ded30eeab90b6ba88cb888d70aef4e7489b6cd212c5e5b5ec38045b6" +checksum = "6998de05217a084b7578728a9443d04ea4cd80f2a0839b8d78770b76ccd45863" dependencies = [ "zbus_xml", "zvariant", @@ -6424,13 +7897,13 @@ dependencies = [ [[package]] name = "zbus-lockstep-macros" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6821851fa840b708b4cbbaf6241868cabc85a2dc22f426361b0292bfc0b836" +checksum = "10da05367f3a7b7553c8cdf8fa91aee6b64afebe32b51c95177957efc47ca3a0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", "zbus-lockstep", "zbus_xml", "zvariant", @@ -6438,14 +7911,14 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.11.0" +version = "5.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e797a9c847ed3ccc5b6254e8bcce056494b375b511b3d6edcec0aeb4defaca" +checksum = "1cdb94821ca8a87ca9c298b5d1cbd80e2a8b67115d99f6e4551ac49e42b6a314" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn", + "syn 2.0.111", "zbus_names", "zvariant", "zvariant_utils", @@ -6459,7 +7932,7 @@ checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" dependencies = [ "serde", "static_assertions", - "winnow", + "winnow 0.7.14", "zvariant", ] @@ -6478,22 +7951,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -6513,7 +7986,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", "synstructure", ] @@ -6534,14 +8007,14 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -6550,9 +8023,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -6561,13 +8034,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -6605,9 +8078,9 @@ checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2" [[package]] name = "zopfli" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" dependencies = [ "bumpalo", "crc32fast", @@ -6649,6 +8122,12 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" +[[package]] +name = "zune-core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "111f7d9820f05fd715df3144e254d6fc02ee4088b0644c0ffd0efc9e6d9d2773" + [[package]] name = "zune-inflate" version = "0.2.54" @@ -6664,33 +8143,42 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" dependencies = [ - "zune-core", + "zune-core 0.4.12", +] + +[[package]] +name = "zune-jpeg" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fb7703e32e9a07fb3f757360338b3a567a5054f21b5f52a666752e333d58e" +dependencies = [ + "zune-core 0.5.0", ] [[package]] name = "zvariant" -version = "5.7.0" +version = "5.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db" +checksum = "2be61892e4f2b1772727be11630a62664a1826b62efa43a6fe7449521cb8744c" dependencies = [ "endi", "enumflags2", "serde", - "winnow", + "winnow 0.7.14", "zvariant_derive", "zvariant_utils", ] [[package]] name = "zvariant_derive" -version = "5.7.0" +version = "5.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e" +checksum = "da58575a1b2b20766513b1ec59d8e2e68db2745379f961f86650655e862d2006" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn", + "syn 2.0.111", "zvariant_utils", ] @@ -6703,6 +8191,6 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn", - "winnow", + "syn 2.0.111", + "winnow 0.7.14", ] diff --git a/README.md b/README.md index 20b96582..b8ef688b 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,9 @@ AviUtl2 SDKのRust版です。 - `./examples/wgpu-filter`:wgpuクレートを使用してGPUで画像を生成するフィルタのサンプル。 - スクリプトモジュール: - `./examples/username-module`:ユーザー名を取得するスクリプトモジュールのサンプル。 + - 汎用プラグイン: + - `./examples/local-alias-plugin`:プロジェクトローカルにオブジェクトを保存する汎用プラグインのサンプル。 + - `./examples/srt-file-plugin`:SRTファイルをインポート/エクスポートする汎用プラグインのサンプル。 ## ライセンス diff --git a/Rakefile b/Rakefile index 817f8381..7c63e999 100644 --- a/Rakefile +++ b/Rakefile @@ -14,7 +14,8 @@ suffixes = { "_input" => ".aui2", "_output" => ".auo2", "_filter" => ".auf2", - "_module" => ".mod2" + "_module" => ".mod2", + "_plugin" => ".aux2" } main_crates = %w[aviutl2 aviutl2-sys aviutl2-macros aviutl2-alias] diff --git a/crates/aviutl2-macros/src/generic_menus.rs b/crates/aviutl2-macros/src/generic_menus.rs new file mode 100644 index 00000000..ffbfe2fa --- /dev/null +++ b/crates/aviutl2-macros/src/generic_menus.rs @@ -0,0 +1,263 @@ +use quote::ToTokens; + +#[derive(Clone, Copy, PartialEq, Eq)] +enum ErrorMode { + Ignore, + Log, + Alert, +} + +#[derive(Clone, Copy, PartialEq, Eq)] +enum EntryType { + Import, + Export, + Layer, + Object, +} + +struct Entry { + entry_type: EntryType, + menu_name: String, + method_ident: syn::Ident, + wrapper_ident: syn::Ident, + has_self: bool, + self_is_mut: bool, + error_mode: ErrorMode, +} + +fn parse_menu_attr( + attr: syn::Attribute, + default_name: &str, +) -> Result<(String, ErrorMode), proc_macro2::TokenStream> { + let mut name: Option = None; + let mut error_mode = ErrorMode::Alert; + attr.parse_nested_meta(|m| { + if m.path.is_ident("name") { + let value: syn::LitStr = m.value()?.parse()?; + name = Some(value.value()); + Ok(()) + } else if m.path.is_ident("error") { + let value: syn::LitStr = m.value()?.parse()?; + match value.value().as_str() { + "alert" => error_mode = ErrorMode::Alert, + "log" => error_mode = ErrorMode::Log, + "ignore" => error_mode = ErrorMode::Ignore, + _ => return Err(m.error("expected \"alert\", \"log\", or \"ignore\"")), + } + Ok(()) + } else { + Err(m.error("expected `name` or `error`")) + } + }) + .map_err(|e| e.to_compile_error())?; + Ok((name.unwrap_or_else(|| default_name.to_string()), error_mode)) +} + +fn analyze_receiver(sig: &syn::Signature) -> Result<(bool, bool), proc_macro2::TokenStream> { + let mut has_self = false; + let mut self_is_mut = false; + for p in sig.inputs.iter() { + if let syn::FnArg::Receiver(r) = p { + if r.reference.is_none() { + return Err( + syn::Error::new_spanned(r, "method receiver must be a reference") + .to_compile_error(), + ); + } + has_self = true; + self_is_mut = r.mutability.is_some(); + } + } + Ok((has_self, self_is_mut)) +} + +pub fn generic_menus( + item: proc_macro2::TokenStream, +) -> Result { + let mut item: syn::ItemImpl = syn::parse2(item).map_err(|e| e.to_compile_error())?; + + // Validate impl target + if item.trait_.is_some() { + return Err(syn::Error::new_spanned( + &item, + "`generic_menus` macro can only be applied to inherent impl blocks", + ) + .to_compile_error()); + } + if !item.generics.params.is_empty() { + return Err(syn::Error::new_spanned( + &item.generics, + "`generic_menus` macro does not support generic impl blocks", + ) + .to_compile_error()); + } + if has_generic_args_in_type(&item.self_ty) { + return Err(syn::Error::new_spanned( + &item.self_ty, + "`generic_menus` macro does not support generic types", + ) + .to_compile_error()); + } + + let impl_token = item.self_ty.to_token_stream(); + + let mut entries: Vec = Vec::new(); + for it in item.items.iter_mut() { + let syn::ImplItem::Fn(method) = it else { + continue; + }; + + let method_ident = method.sig.ident.clone(); + let (attr_idx, entry_type) = match find_menu_attr(&method.attrs) { + Ok(Some(v)) => v, + Ok(None) => { + return Err(syn::Error::new_spanned( + &method.sig.ident, + "method must have one of #[import], #[export], #[layer], or #[object]", + ) + .to_compile_error()); + } + Err(e) => return Err(e), + }; + + // Take and parse attribute + let attr = method.attrs.remove(attr_idx); + let (menu_name, error_mode) = parse_menu_attr(attr, &method_ident.to_string())?; + + // Analyze receiver + let (has_self, self_is_mut) = analyze_receiver(&method.sig)?; + let wrapper_ident = + syn::Ident::new(&format!("bridge_{}", method_ident), method_ident.span()); + + entries.push(Entry { + entry_type, + menu_name, + method_ident, + wrapper_ident, + has_self, + self_is_mut, + error_mode, + }); + } + + // Build registration lines and wrapper fn bodies + let mut register_lines: Vec = Vec::new(); + let mut wrappers: Vec = Vec::new(); + for e in entries.iter() { + let name_str = &e.menu_name; + let method_ident = &e.method_ident; + let wrapper_ident = &e.wrapper_ident; + + let reg = match e.entry_type { + EntryType::Export => { + quote::quote! { host.register_export_menu(#name_str, #wrapper_ident); } + } + EntryType::Import => { + quote::quote! { host.register_import_menu(#name_str, #wrapper_ident); } + } + EntryType::Layer => { + quote::quote! { host.register_layer_menu(#name_str, #wrapper_ident); } + } + EntryType::Object => { + quote::quote! { host.register_object_menu(#name_str, #wrapper_ident); } + } + }; + register_lines.push(reg); + + let call_on_error = match e.error_mode { + ErrorMode::Ignore => quote::quote! { let _ = ret; }, + ErrorMode::Log => quote::quote! { edit.__output_log_if_error(ret); }, + ErrorMode::Alert => quote::quote! { edit.__alert_if_error(ret); }, + }; + + let wrapper = if e.has_self { + let with_fn = if e.self_is_mut { + quote::quote!(with_instance_mut) + } else { + quote::quote!(with_instance) + }; + quote::quote! { + extern "C" fn #wrapper_ident(edit: *mut ::aviutl2::sys::plugin2::EDIT_SECTION) { + let mut edit = unsafe { ::aviutl2::generic::EditSection::from_ptr(edit) }; + <#impl_token as ::aviutl2::generic::GenericPlugin>::#with_fn(|__self| { + let ret = <#impl_token>::#method_ident(__self, &mut edit); + #call_on_error + }); + } + } + } else { + quote::quote! { + extern "C" fn #wrapper_ident(edit: *mut ::aviutl2::sys::plugin2::EDIT_SECTION) { + let mut edit = unsafe { ::aviutl2::generic::EditSection::from_ptr(edit) }; + let ret = <#impl_token>::#method_ident(&mut edit); + #call_on_error + } + } + }; + wrappers.push(wrapper); + } + + Ok(quote::quote! { + #item + + ::aviutl2::__internal_module! { + impl ::aviutl2::generic::GenericPluginMenus for #impl_token { + fn register_menus(host: &mut ::aviutl2::generic::HostAppHandle) { + #(#register_lines)* + return; + + #(#wrappers)* + } + } + } + }) +} + +fn has_generic_args_in_type(ty: &syn::Type) -> bool { + use syn::{PathArguments, Type}; + match ty { + Type::Path(p) => p + .path + .segments + .iter() + .any(|seg| !matches!(seg.arguments, PathArguments::None)), + Type::Reference(r) => has_generic_args_in_type(&r.elem), + Type::Ptr(p) => has_generic_args_in_type(&p.elem), + _ => false, + } +} + +fn find_menu_attr( + attrs: &[syn::Attribute], +) -> Result, proc_macro2::TokenStream> { + let mut import: Option = None; + let mut export: Option = None; + let mut layer: Option = None; + let mut object: Option = None; + for (idx, attr) in attrs.iter().enumerate() { + if attr.path().is_ident("import") { + import = Some(idx); + } + if attr.path().is_ident("export") { + export = Some(idx); + } + if attr.path().is_ident("layer") { + layer = Some(idx); + } + if attr.path().is_ident("object") { + object = Some(idx); + } + } + match (import, export, layer, object) { + (Some(i), None, None, None) => Ok(Some((i, EntryType::Import))), + (None, Some(e), None, None) => Ok(Some((e, EntryType::Export))), + (None, None, Some(l), None) => Ok(Some((l, EntryType::Layer))), + (None, None, None, Some(o)) => Ok(Some((o, EntryType::Object))), + (None, None, None, None) => Ok(None), + _ => Err(syn::Error::new_spanned( + &attrs[0], + "method can have only one of #[import], #[export], #[layer], or #[object]", + ) + .to_compile_error()), + } +} diff --git a/crates/aviutl2-macros/src/lib.rs b/crates/aviutl2-macros/src/lib.rs index b41b5b8d..f8c72cce 100644 --- a/crates/aviutl2-macros/src/lib.rs +++ b/crates/aviutl2-macros/src/lib.rs @@ -6,6 +6,7 @@ mod filter_config_items; mod filter_config_select_items; mod from_script_module_param; +mod generic_menus; mod into_script_module_return_value; mod module_functions; mod plugin; @@ -220,7 +221,25 @@ pub fn filter_config_select_items(item: proc_macro::TokenStream) -> proc_macro:: /// 関数のシグネチャは以下のようになります。 /// /// ```rust -/// fn function_name(params: &mut aviutl2::module::ScriptModuleCallHandle) { /* ... */ } +/// # use aviutl2::module::IntoScriptModuleReturnValue; +/// # #[aviutl2::plugin(ScriptModule)] +/// # struct MyModule { +/// # counter: std::sync::atomic::AtomicI32, +/// # } +/// # impl aviutl2::module::ScriptModule for MyModule { +/// # fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult { +/// # unimplemented!() +/// # } +/// # fn plugin_info(&self) -> aviutl2::module::ScriptModuleTable { +/// # unimplemented!() +/// # } +/// # } +/// # #[aviutl2::module::functions] +/// # impl MyModule { +/// # #[direct] +/// fn function_name(params: &mut aviutl2::module::ScriptModuleCallHandle) -> () +/// # {} +/// # } /// ``` /// /// # Example @@ -352,7 +371,7 @@ pub fn into_script_module_return_value(item: proc_macro::TokenStream) -> proc_ma /// /// # Attributes /// -/// - 引数には`InputPlugin`、`OutputPlugin`、`FilterPlugin`、`ScriptModule`のいずれかを指定します。 +/// - 引数には`InputPlugin`、`OutputPlugin`、`FilterPlugin`、`ScriptModule`、`GenericPlugin`のいずれかを指定します。 /// /// # Example /// @@ -388,3 +407,114 @@ pub fn plugin( .unwrap_or_else(|e| e) .into() } + +/// 汎用プラグインのメニュー登録実装を生成するマクロ。 +/// +/// このマクロは`impl`ブロックに対して適用されます。 +/// `impl`ブロック内で定義された関数が汎用プラグインのメニューとして登録されます。 +/// +/// ブロック内の関数はすべて以下のシグネチャのうちいずれかを持つ必要があります: +/// ```rust +/// # #[aviutl2::plugin(GenericPlugin)] +/// # struct MyGenericPlugin; +/// # impl aviutl2::generic::GenericPlugin for MyGenericPlugin { +/// # fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult { +/// # unimplemented!() +/// # } +/// # fn register(&mut self, _handle: &mut aviutl2::generic::HostAppHandle<'_>) { +/// # unimplemented!() +/// # } +/// # } +/// # type E = aviutl2::anyhow::Error; +/// # #[aviutl2::generic::menus] +/// # impl MyGenericPlugin { +/// # #[import(name = "")] +/// fn func1(edit_handle: &mut aviutl2::generic::EditSection) -> () +/// # {} +/// # #[export(name = "")] +/// fn func2(edit_handle: &mut aviutl2::generic::EditSection) -> Result<(), E> +/// # { unimplemented!() } +/// # } +/// # fn test() -> Result<(), E> +/// where +/// Box: From, +/// # { unimplemented!() } +/// ``` +/// +/// # Attributes +/// +/// ### `import` +/// +/// 汎用プラグインのインポートメニューとして登録します。 +/// +/// - `name`: メニューに表示される名前を指定します。 +/// - `error`: エラー発生時のハンドリング方法を指定します。`"alert"`、`"log"`、`"ignore"`のいずれかを指定します。 +/// - `"alert"`: エラー発生時にアラートダイアログを表示します。(デフォルト) +/// - `"log"`: エラー発生時にログにエラーメッセージを出力します。 +/// - `"ignore"`: エラー発生時に何も行いません。 +/// +/// +/// ### `export` +/// +/// 汎用プラグインのエクスポートメニューとして登録します。 +/// パラメーターは`import`属性と同様です。 +/// +/// ### `layer` +/// +/// 汎用プラグインのレイヤーメニューとして登録します。 +/// パラメーターは`import`属性と同様です。 +/// +/// ### `object` +/// +/// 汎用プラグインのオブジェクトメニューとして登録します。 +/// パラメーターは`import`属性と同様です。 +/// +/// # Example +/// +/// ```rust +/// #[aviutl2::plugin(GenericPlugin)] +/// struct MyGenericPlugin; +/// # impl aviutl2::generic::GenericPlugin for MyGenericPlugin { +/// # fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult { +/// # unimplemented!() +/// # } +/// # fn register(&mut self, _handle: &mut aviutl2::generic::HostAppHandle<'_>) { +/// # unimplemented!() +/// # } +/// # } +/// +/// #[aviutl2::generic::menus] +/// impl MyGenericPlugin { +/// #[import(name = ".txtファイルをインポート")] +/// fn import_text(edit_handle: &mut aviutl2::generic::EditSection) -> aviutl2::AnyResult<()> { +/// // ... +/// # Ok(()) +/// } +/// +/// #[export(name = ".txtファイルをエクスポート")] +/// fn export_text(edit_handle: &mut aviutl2::generic::EditSection) -> aviutl2::AnyResult<()> { +/// // ... +/// # Ok(()) +/// } +/// +/// #[layer(name = "レイヤーを複製")] +/// fn duplicate_layer(edit_handle: &mut aviutl2::generic::EditSection) -> aviutl2::AnyResult<()> { +/// // ... +/// # Ok(()) +/// } +/// +/// #[object(name = "オブジェクトを削除")] +/// fn delete_object(edit_handle: &mut aviutl2::generic::EditSection) -> aviutl2::AnyResult<()> { +/// // ... +/// # Ok(()) +/// } +/// } +#[proc_macro_attribute] +pub fn generic_menus( + _attr: proc_macro::TokenStream, + item: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + generic_menus::generic_menus(item.into()) + .unwrap_or_else(|e| e) + .into() +} diff --git a/crates/aviutl2-macros/src/module_functions.rs b/crates/aviutl2-macros/src/module_functions.rs index 411ba316..21f0e99b 100644 --- a/crates/aviutl2-macros/src/module_functions.rs +++ b/crates/aviutl2-macros/src/module_functions.rs @@ -83,25 +83,40 @@ fn create_bridge( .inputs .iter() .any(|param| matches!(param, syn::FnArg::Receiver(_))); + // detect if receiver is &mut self + let mut_self = method + .sig + .inputs + .iter() + .find_map(|param| match param { + syn::FnArg::Receiver(r) => Some(r.mutability.is_some()), + _ => None, + }) + .unwrap_or(false); if has_self { - quote::quote! { - extern "C" fn #internal_method_name(smp: *mut ::aviutl2::sys::module2::SCRIPT_MODULE_PARAM) { - let mut params = ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp); - let __internal_self = <#impl_token as ::aviutl2::module::__bridge::ScriptModuleSingleton>::__get_singleton_state(); - let __internal_self = __internal_self - .read() - .expect("Plugin handle is not initialized"); - let __internal_self = &__internal_self - .as_ref() - .expect("Plugin instance is not initialized") - .instance; - let () = <#impl_token>::#method_name(__internal_self, &mut params); + if mut_self { + quote::quote! { + extern "C" fn #internal_method_name(smp: *mut ::aviutl2::sys::module2::SCRIPT_MODULE_PARAM) { + let mut params = unsafe { ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp) }; + <#impl_token as ::aviutl2::module::ScriptModule>::with_instance_mut(|__internal_self| { + let () = <#impl_token>::#method_name(__internal_self, &mut params); + }); + } + } + } else { + quote::quote! { + extern "C" fn #internal_method_name(smp: *mut ::aviutl2::sys::module2::SCRIPT_MODULE_PARAM) { + let mut params = unsafe { ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp) }; + <#impl_token as ::aviutl2::module::ScriptModule>::with_instance(|__internal_self| { + let () = <#impl_token>::#method_name(__internal_self, &mut params); + }); + } } } } else { quote::quote! { extern "C" fn #internal_method_name(smp: *mut ::aviutl2::sys::module2::SCRIPT_MODULE_PARAM) { - let mut params = ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp); + let mut params = unsafe { ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp) }; let () = <#impl_token>::#method_name(&mut params); } } @@ -111,6 +126,8 @@ fn create_bridge( // Separate receiver and non-receiver parameters let mut param_bridges = Vec::new(); let mut param_index: usize = 0; + let mut has_self = false; + let mut self_is_mut = false; for param in params.iter() { match param { syn::FnArg::Receiver(r) => { @@ -121,24 +138,8 @@ fn create_bridge( ) .to_compile_error()); } - if r.mutability.is_some() { - return Err(syn::Error::new_spanned( - r, - "method receiver must be an immutable reference", - ) - .to_compile_error()); - } - - param_bridges.push(quote::quote! { - let __internal_self = <#impl_token as ::aviutl2::module::__bridge::ScriptModuleSingleton>::__get_singleton_state(); - let __internal_self = __internal_self - .read() - .expect("Plugin handle is not initialized"); - let __internal_self = &__internal_self - .as_ref() - .expect("Plugin instance is not initialized") - .instance; - }); + has_self = true; + self_is_mut = r.mutability.is_some(); } syn::FnArg::Typed(pat_type) => { let ty = &pat_type.ty; @@ -159,19 +160,48 @@ fn create_bridge( } } } - let param_names = params.iter().map(|param| match param { - syn::FnArg::Receiver(_) => quote::quote! { __internal_self }, - syn::FnArg::Typed(pat_type) => { - let pat = &pat_type.pat; - quote::quote! { #pat } + let param_names_vec: Vec = params + .iter() + .map(|param| match param { + syn::FnArg::Receiver(_) => quote::quote! { __internal_self }, + syn::FnArg::Typed(pat_type) => { + let pat = &pat_type.pat; + quote::quote! { #pat } + } + }) + .collect(); + if has_self { + if self_is_mut { + quote::quote! { + extern "C" fn #internal_method_name(smp: *mut ::aviutl2::sys::module2::SCRIPT_MODULE_PARAM) { + let mut params = unsafe { ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp) }; + <#impl_token as ::aviutl2::module::ScriptModule>::with_instance_mut(|__internal_self| { + #(#param_bridges)* + let fn_result = <#impl_token>::#method_name(#(#param_names_vec),*); + ::aviutl2::module::__push_return_value(&mut params, fn_result); + }); + } + } + } else { + quote::quote! { + extern "C" fn #internal_method_name(smp: *mut ::aviutl2::sys::module2::SCRIPT_MODULE_PARAM) { + let mut params = unsafe { ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp) }; + <#impl_token as ::aviutl2::module::ScriptModule>::with_instance(|__internal_self| { + #(#param_bridges)* + let fn_result = <#impl_token>::#method_name(#(#param_names_vec),*); + ::aviutl2::module::__push_return_value(&mut params, fn_result); + }); + } + } } - }); - quote::quote! { - extern "C" fn #internal_method_name(smp: *mut ::aviutl2::sys::module2::SCRIPT_MODULE_PARAM) { - let mut params = ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp); - #(#param_bridges)* - let fn_result = <#impl_token>::#method_name(#(#param_names),*); - ::aviutl2::module::__push_return_value(&mut params, fn_result); + } else { + quote::quote! { + extern "C" fn #internal_method_name(smp: *mut ::aviutl2::sys::module2::SCRIPT_MODULE_PARAM) { + let mut params = unsafe { ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp) }; + #(#param_bridges)* + let fn_result = <#impl_token>::#method_name(#(#param_names_vec),*); + ::aviutl2::module::__push_return_value(&mut params, fn_result); + } } } }; diff --git a/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__direct.snap b/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__direct.snap index d4745a6a..26bc58d9 100644 --- a/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__direct.snap +++ b/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__direct.snap @@ -17,16 +17,11 @@ impl MyModule { extern "C" fn bridge_my_function( smp: *mut ::aviutl2::sys::module2::SCRIPT_MODULE_PARAM, ) { - let mut params = ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp); - let __internal_self = < MyModule as :: aviutl2 :: module :: __bridge :: ScriptModuleSingleton > :: __get_singleton_state () ; - let __internal_self = __internal_self - .read() - .expect("Plugin handle is not initialized"); - let __internal_self = &__internal_self - .as_ref() - .expect("Plugin instance is not initialized") - .instance; - let () = ::my_function(__internal_self, &mut params); + let mut params = + unsafe { ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp) }; + ::with_instance(|__internal_self| { + let () = ::my_function(__internal_self, &mut params); + }); } } } diff --git a/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__direct_no_self.snap b/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__direct_no_self.snap index b603a320..5a76dcdf 100644 --- a/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__direct_no_self.snap +++ b/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__direct_no_self.snap @@ -17,7 +17,8 @@ impl MyModule { extern "C" fn bridge_my_function( smp: *mut ::aviutl2::sys::module2::SCRIPT_MODULE_PARAM, ) { - let mut params = ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp); + let mut params = + unsafe { ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp) }; let () = ::my_function(&mut params); } } diff --git a/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__no_self.snap b/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__no_self.snap index 6ae20cb4..2da42440 100644 --- a/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__no_self.snap +++ b/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__no_self.snap @@ -19,7 +19,8 @@ impl MyModule { extern "C" fn bridge_my_function( smp: *mut ::aviutl2::sys::module2::SCRIPT_MODULE_PARAM, ) { - let mut params = ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp); + let mut params = + unsafe { ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp) }; let hoge: i32 = match ::from_param( ¶ms, 0usize, ) { diff --git a/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__with_self.snap b/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__with_self.snap index 565bbab7..f396daca 100644 --- a/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__with_self.snap +++ b/crates/aviutl2-macros/src/snapshots/aviutl2_macros__module_functions__tests__with_self.snap @@ -19,30 +19,26 @@ impl MyModule { extern "C" fn bridge_my_function( smp: *mut ::aviutl2::sys::module2::SCRIPT_MODULE_PARAM, ) { - let mut params = ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp); - let __internal_self = < MyModule as :: aviutl2 :: module :: __bridge :: ScriptModuleSingleton > :: __get_singleton_state () ; - let __internal_self = __internal_self - .read() - .expect("Plugin handle is not initialized"); - let __internal_self = &__internal_self - .as_ref() - .expect("Plugin instance is not initialized") - .instance; - let fuga: f64 = match ::from_param( - ¶ms, 0usize, - ) { - ::std::option::Option::Some(value) => value, - ::std::option::Option::None => { - let _ = params.set_error(&format!( - "Failed to convert parameter #{} to {}", - 0usize, - stringify!(f64) - )); - return; - } - }; - let fn_result = ::my_function(__internal_self, fuga); - ::aviutl2::module::__push_return_value(&mut params, fn_result); + let mut params = + unsafe { ::aviutl2::module::ScriptModuleCallHandle::from_ptr(smp) }; + ::with_instance(|__internal_self| { + let fuga: f64 = + match ::from_param( + ¶ms, 0usize, + ) { + ::std::option::Option::Some(value) => value, + ::std::option::Option::None => { + let _ = params.set_error(&format!( + "Failed to convert parameter #{} to {}", + 0usize, + stringify!(f64) + )); + return; + } + }; + let fn_result = ::my_function(__internal_self, fuga); + ::aviutl2::module::__push_return_value(&mut params, fn_result); + }); } } } diff --git a/crates/aviutl2-sys/src/lib.rs b/crates/aviutl2-sys/src/lib.rs index 2e95e642..4783c423 100644 --- a/crates/aviutl2-sys/src/lib.rs +++ b/crates/aviutl2-sys/src/lib.rs @@ -6,6 +6,7 @@ //! - [`output2`][]:`output2.h`相当。 //! - [`filter2`][]:`filter2.h`相当。 //! - [`module2`][]:`module2.h`相当。 +//! - [`plugin2`][]:`plugin2.h`相当。 //! - [`logger2`][]:`logger2.h`相当。 //! //! - [`common`][]:共通定義。 @@ -18,3 +19,4 @@ pub mod input2; pub mod logger2; pub mod module2; pub mod output2; +pub mod plugin2; diff --git a/crates/aviutl2-sys/src/plugin2.rs b/crates/aviutl2-sys/src/plugin2.rs new file mode 100644 index 00000000..f4a027b7 --- /dev/null +++ b/crates/aviutl2-sys/src/plugin2.rs @@ -0,0 +1,274 @@ +#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] + +use crate::common::LPCWSTR; +use crate::{ + filter2::FILTER_PLUGIN_TABLE, input2::INPUT_PLUGIN_TABLE, module2::SCRIPT_MODULE_TABLE, + output2::OUTPUT_PLUGIN_TABLE, +}; +use std::ffi::c_void; +use std::os::raw::c_char; + +pub use windows_sys::Win32::Foundation::HWND; + +pub type LPCSTR = *const c_char; + +/// オブジェクトハンドル +pub type OBJECT_HANDLE = *mut c_void; + +/// レイヤー・フレーム情報構造体 +/// フレーム番号、レイヤー番号が0からの番号になります ※UI表示と異なります +#[repr(C)] +pub struct OBJECT_LAYER_FRAME { + /// レイヤー番号 + pub layer: i32, + /// 開始フレーム番号 + pub start: i32, + /// 終了フレーム番号 + pub end: i32, +} + +/// 編集情報構造体 +/// フレーム番号、レイヤー番号が0からの番号になります ※UI表示と異なります +#[repr(C)] +pub struct EDIT_INFO { + /// シーンの解像度 + pub width: i32, + /// シーンの解像度 + pub height: i32, + /// シーンのフレームレート + pub rate: i32, + /// シーンのフレームレート + pub scale: i32, + /// シーンのサンプリングレート + pub sample_rate: i32, + /// 現在のカーソルのフレーム番号 + pub frame: i32, + /// 現在の選択レイヤー番号 + pub layer: i32, + /// オブジェクトが存在する最大のフレーム番号 + pub frame_max: i32, + /// オブジェクトが存在する最大のレイヤー番号 + pub layer_max: i32, +} + +/// 編集セクション構造体 +/// メニュー選択やプロジェクト編集のコールバック関数内で利用出来ます +/// フレーム番号、レイヤー番号が0からの番号になります ※UI表示と異なります +#[repr(C)] +pub struct EDIT_SECTION { + /// 編集情報 + pub info: *mut EDIT_INFO, + + /// 指定の位置にオブジェクトエイリアスを作成します + /// alias : オブジェクトエイリアスデータ(UTF-8)へのポインタ + /// オブジェクトエイリアスファイルと同じフォーマットになります + /// layer : 作成するレイヤー番号 + /// frame : 作成するフレーム番号 + /// length : オブジェクトのフレーム数 ※エイリアスデータにフレーム情報が無い場合に利用します + /// 戻り値 : 作成したオブジェクトのハンドル (失敗した場合はnullptrを返却) + /// 既に存在するオブジェクトに重なったり、エイリアスデータが不正な場合に失敗します + pub create_object_from_alias: + unsafe extern "C" fn(alias: LPCSTR, layer: i32, frame: i32, length: i32) -> OBJECT_HANDLE, + + /// 指定のフレーム番号以降にあるオブジェクトを検索します + /// layer : 検索対象のレイヤー番号 + /// frame : 検索を開始するフレーム番号 + /// 戻り値 : 検索したオブジェクトのハンドル (見つからない場合はnullptrを返却) + pub find_object: unsafe extern "C" fn(layer: i32, frame: i32) -> OBJECT_HANDLE, + + /// オブジェクトに対象エフェクトが何個存在するかを取得します + /// object : オブジェクトのハンドル + /// effect : 対象のエフェクト名 (エイリアスファイルのeffect.nameの値) + /// 戻り値 : 対象エフェクトの数 ※存在しない場合は0 + pub count_object_effect: unsafe extern "C" fn(object: OBJECT_HANDLE, effect: LPCWSTR) -> i32, + + /// オブジェクトのレイヤー・フレーム情報を取得します + /// object : オブジェクトのハンドル + /// 戻り値 : オブジェクトのレイヤー・フレーム情報 + pub get_object_layer_frame: unsafe extern "C" fn(object: OBJECT_HANDLE) -> OBJECT_LAYER_FRAME, + + /// オブジェクトのエイリアスデータを取得します + /// object : オブジェクトのハンドル + /// 戻り値 : オブジェクトエイリアスデータ(UTF-8)へのポインタ (取得出来ない場合はnullptrを返却) + /// オブジェクトエイリアスファイルと同じフォーマットになります + /// ※次に文字列返却の関数を使うかコールバック処理の終了まで有効 + pub get_object_alias: unsafe extern "C" fn(object: OBJECT_HANDLE) -> LPCSTR, + + /// オブジェクトの設定項目の値を文字列で取得します + /// object : オブジェクトのハンドル + /// effect : 対象のエフェクト名 (エイリアスファイルのeffect.nameの値) + /// 同じエフェクトが複数ある場合は":n"のサフィックスでインデックス指定出来ます (nは0からの番号) + /// get_object_item_value(object, L"ぼかし:1", L"範囲"); // 2個目のぼかしを対象とする + /// item : 対象の設定項目の名称 (エイリアスファイルのキーの名称) + /// 戻り値 : 取得した設定値(UTF8)へのポインタ (取得出来ない場合はnullptrを返却) + /// エイリアスファイルの設定値と同じフォーマットになります + /// ※次に文字列返却の関数を使うかコールバック処理の終了まで有効 + pub get_object_item_value: + unsafe extern "C" fn(object: OBJECT_HANDLE, effect: LPCWSTR, item: LPCWSTR) -> LPCSTR, + + /// オブジェクトの設定項目の値を文字列で設定します + /// object : オブジェクトのハンドル + /// effect : 対象のエフェクト名 (エイリアスファイルのeffect.nameの値) + /// 同じエフェクトが複数ある場合は":n"のサフィックスでインデックス指定出来ます (nは0からの番号) + /// get_object_item_value(object, L"ぼかし:1", L"範囲"); // 2個目のぼかしを対象とする + /// item : 対象の設定項目の名称 (エイリアスファイルのキーの名称) + /// value : 設定値(UTF8) + /// エイリアスファイルの設定値と同じフォーマットになります + /// 戻り値 : 設定出来た場合はtrue (対象が見つからない場合は失敗します) + pub set_object_item_value: unsafe extern "C" fn( + object: OBJECT_HANDLE, + effect: LPCWSTR, + item: LPCWSTR, + value: LPCSTR, + ) -> bool, + + /// オブジェクトを移動します + /// object : オブジェクトのハンドル + /// layer : 移動先のレイヤー番号 + /// frame : 移動先のフレーム番号 + /// 戻り値 : 移動した場合はtrue (移動先にオブジェクトが存在する場合は失敗します) + pub move_object: unsafe extern "C" fn(object: OBJECT_HANDLE, layer: i32, frame: i32) -> bool, + + /// オブジェクトを削除します + /// object : オブジェクトのハンドル + pub delete_object: unsafe extern "C" fn(object: OBJECT_HANDLE), + + /// オブジェクト設定ウィンドウで選択されているオブジェクトのハンドルを取得します + /// 戻り値 : オブジェクトのハンドル (未選択の場合はnullptrを返却) + pub get_focus_object: unsafe extern "C" fn() -> OBJECT_HANDLE, + + /// オブジェクト設定ウィンドウで選択するオブジェクトを設定します (コールバック処理の終了時に設定されます) + /// object : オブジェクトのハンドル + pub set_focus_object: unsafe extern "C" fn(object: OBJECT_HANDLE), + + /// 冗長なので後で廃止します + pub deprecated_output_log: unsafe extern "C" fn(message: LPCWSTR), + + /// 選択中オブジェクトのハンドルを取得します + /// index : 選択中オブジェクトのインデックス(0〜) + /// 戻り値 : 指定インデックスのオブジェクトのハンドル (インデックスが範囲外の場合はnullptrを返却) + pub get_selected_object: unsafe extern "C" fn(index: i32) -> OBJECT_HANDLE, + + /// 選択中オブジェクトの数を取得します + /// 戻り値 : 選択中オブジェクトの数 + pub get_selected_object_num: unsafe extern "C" fn() -> i32, +} + +/// 編集ハンドル構造体 +#[repr(C)] +pub struct EDIT_HANDLE { + /// プロジェクトデータの編集をする為のコールバック関数(func_proc_edit)を呼び出します + /// 編集情報を排他制御する為にコールバック関数内で編集処理をする形になります + /// コールバック関数内で編集したオブジェクトは纏めてUndoに登録されます + /// コールバック関数はメインスレッドから呼ばれます + /// func_proc_edit : 編集処理のコールバック関数 + /// 戻り値 : trueなら成功 + /// 編集が出来ない場合(出力中等)に失敗します + pub call_edit_section: + unsafe extern "C" fn(func_proc_edit: unsafe extern "C" fn(edit: *mut EDIT_SECTION)) -> bool, + + /// call_edit_section()に引数paramを渡せるようにした関数です + pub call_edit_section_param: unsafe extern "C" fn( + param: *mut c_void, + func_proc_edit: unsafe extern "C" fn(param: *mut c_void, edit: *mut EDIT_SECTION), + ) -> bool, +} + +/// プロジェクトファイル構造体 +/// プロジェクトファイルのロード、セーブ時のコールバック関数内で利用出来ます +/// プロジェクトの保存データはプラグイン毎のデータ領域になります +#[repr(C)] +pub struct PROJECT_FILE { + /// プロジェクトに保存されている文字列(UTF-8)を取得します + /// key : キー名(UTF-8) + /// 戻り値 : 取得した文字列へのポインタ (未設定の場合はnullptr) + pub get_param_string: unsafe extern "C" fn(key: LPCSTR) -> LPCSTR, + /// プロジェクトに文字列(UTF-8)を保存します + /// key : キー名(UTF-8) + /// value : 保存する文字列(UTF-8) + pub set_param_string: unsafe extern "C" fn(key: LPCSTR, value: LPCSTR), + /// プロジェクトに保存されているバイナリデータを取得します + /// key : キー名(UTF-8) + /// data : 取得するデータの格納先へのポインタ + /// size : 取得するデータのサイズ (保存されているサイズと異なる場合は失敗します) + /// 戻り値 : 正しく取得出来た場合はtrue + pub get_param_binary: unsafe extern "C" fn(key: LPCSTR, data: *mut c_void, size: i32) -> bool, + /// プロジェクトにバイナリデータを保存します + /// key : キー名(UTF-8) + /// data : 保存するデータへのポインタ + /// size : 保存するデータのサイズ (4096バイト以下) + pub set_param_binary: unsafe extern "C" fn(key: LPCSTR, data: *mut c_void, size: i32), + /// プロジェクトに保存されているデータを全て削除します + pub clear_params: unsafe extern "C" fn(), +} + +/// ホストアプリケーション構造体 +#[repr(C)] +pub struct HOST_APP_TABLE { + /// プラグインの情報を設定する + /// information : プラグインの情報 + pub set_plugin_information: unsafe extern "C" fn(information: LPCWSTR), + + /// 入力プラグインを登録する + /// input_plugin_table : 入力プラグイン構造体 + pub register_input_plugin: unsafe extern "C" fn(input_plugin_table: *mut INPUT_PLUGIN_TABLE), + /// 出力プラグインを登録する + /// output_plugin_table : 出力プラグイン構造体 + pub register_output_plugin: unsafe extern "C" fn(output_plugin_table: *mut OUTPUT_PLUGIN_TABLE), + /// フィルタプラグインを登録する + /// filter_plugin_table : フィルタプラグイン構造体 + pub register_filter_plugin: unsafe extern "C" fn(filter_plugin_table: *mut FILTER_PLUGIN_TABLE), + /// スクリプトモジュールを登録する + /// script_module_table : スクリプトモジュール構造体 + pub register_script_module: unsafe extern "C" fn(script_module_table: *mut SCRIPT_MODULE_TABLE), + + /// インポートメニューを登録する + /// name : インポートメニューの名称 + /// func_proc_import : インポートメニュー選択時のコールバック関数 + pub register_import_menu: unsafe extern "C" fn( + name: LPCWSTR, + func_proc_import: unsafe extern "C" fn(*mut EDIT_SECTION), + ), + /// エクスポートメニューを登録する + /// name : エクスポートメニューの名称 + /// func_proc_export : エクスポートメニュー選択時のコールバック関数 + pub register_export_menu: unsafe extern "C" fn( + name: LPCWSTR, + func_proc_export: unsafe extern "C" fn(*mut EDIT_SECTION), + ), + + /// ウィンドウクライアントを登録する + /// name : ウィンドウの名称 + /// hwnd : ウィンドウハンドル + /// ウィンドウにはWS_CHILDが追加され親ウィンドウが設定されます ※WS_POPUPは削除されます + pub register_window_client: unsafe extern "C" fn(name: LPCWSTR, hwnd: HWND), + + /// プロジェクトデータ編集用のハンドルを取得します + /// 戻り値 : 編集ハンドル + pub create_edit_handle: unsafe extern "C" fn() -> *mut EDIT_HANDLE, + + /// プロジェクトファイルをロードした直後に呼ばれる関数を登録する ※プロジェクトの初期化時にも呼ばれます + /// func_project_load : プロジェクトファイルのロード時のコールバック関数 + pub register_project_load_handler: + unsafe extern "C" fn(func_project_load: unsafe extern "C" fn(*mut PROJECT_FILE)), + /// プロジェクトファイルをセーブする直前に呼ばれる関数を登録する + /// func_project_save : プロジェクトファイルのセーブ時のコールバック関数 + pub register_project_save_handler: + unsafe extern "C" fn(func_project_save: unsafe extern "C" fn(*mut PROJECT_FILE)), + + /// レイヤーメニューを登録する (レイヤー編集でオブジェクト未選択時の右クリックメニューに追加されます) + /// name : レイヤーメニューの名称 + /// func_proc_layer_menu : レイヤーメニュー選択時のコールバック関数 + pub register_layer_menu: unsafe extern "C" fn( + name: LPCWSTR, + func_proc_layer_menu: unsafe extern "C" fn(*mut EDIT_SECTION), + ), + + /// オブジェクトメニューを登録する (レイヤー編集でオブジェクト選択時の右クリックメニューに追加されます) + /// name : オブジェクトメニューの名称 + /// func_proc_object_menu : オブジェクトメニュー選択時のコールバック関数 + pub register_object_menu: unsafe extern "C" fn( + name: LPCWSTR, + func_proc_object_menu: unsafe extern "C" fn(*mut EDIT_SECTION), + ), +} diff --git a/crates/aviutl2/Cargo.toml b/crates/aviutl2/Cargo.toml index a4621a4f..9e0e1d49 100644 --- a/crates/aviutl2/Cargo.toml +++ b/crates/aviutl2/Cargo.toml @@ -15,19 +15,21 @@ targets = [] all-features = true [features] -default = ["input", "output", "filter", "module", "aviutl2-alias"] +default = ["input", "output", "filter", "module", "generic", "aviutl2-alias"] input = [] output = [] filter = [] module = [] +generic = [] image = ["dep:image"] +serde = ["dep:serde", "dep:rmp-serde", "dep:zstd"] aviutl2-alias = ["dep:aviutl2-alias"] [dependencies] anyhow = "1.0.98" -aviutl2-alias = { workspace = true, optional = true } aviutl2-macros.workspace = true aviutl2-sys.workspace = true +aviutl2-alias = { workspace = true, optional = true } duplicate = "2.0.0" env_filter = "0.1.4" half = { version = "2.6.0", features = ["zerocopy"] } @@ -35,6 +37,10 @@ image = { version = "0.25.6", optional = true } log = "0.4.27" native-dialog = "0.9.0" num-rational = "0.4.2" +pastey = "0.1.1" raw-window-handle = "0.6.2" +rmp-serde = { version = "1.3.0", optional = true } +serde = { version = "1.0.228", optional = true } thiserror = "2.0.12" zerocopy = { version = "0.8.26", features = ["std"] } +zstd = { version = "0.13.3", optional = true } diff --git a/crates/aviutl2/src/common.rs b/crates/aviutl2/src/common.rs index 8dc821b6..fc653727 100644 --- a/crates/aviutl2/src/common.rs +++ b/crates/aviutl2/src/common.rs @@ -80,8 +80,8 @@ impl aviutl2_alias::FromTableValue for AviUtl2Version { type Err = std::num::ParseIntError; fn from_table_value(value: &str) -> Result { - let v = value.parse::()?; - Ok(AviUtl2Version::from(v)) + let v: u32 = value.parse()?; + Ok(Self::from(v)) } } diff --git a/crates/aviutl2/src/filter/binding.rs b/crates/aviutl2/src/filter/binding.rs index abb73943..812e002c 100644 --- a/crates/aviutl2/src/filter/binding.rs +++ b/crates/aviutl2/src/filter/binding.rs @@ -77,6 +77,30 @@ pub trait FilterPlugin: Send + Sync + Sized { ) -> AnyResult<()> { anyhow::bail!("proc_audio is not implemented"); } + + /// シングルトンインスタンスを参照するためのヘルパーメソッド。 + /// + /// # Panics + /// + /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。 + fn with_instance(f: impl FnOnce(&Self) -> R) -> R + where + Self: crate::filter::__bridge::FilterSingleton, + { + ::with_instance(f) + } + + /// シングルトンインスタンスを可変参照するためのヘルパーメソッド。 + /// + /// # Panics + /// + /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。 + fn with_instance_mut(f: impl FnOnce(&mut Self) -> R) -> R + where + Self: crate::filter::__bridge::FilterSingleton, + { + ::with_instance_mut(f) + } } /// シーン情報。 diff --git a/crates/aviutl2/src/filter/bridge.rs b/crates/aviutl2/src/filter/bridge.rs index 645a9a88..71f07560 100644 --- a/crates/aviutl2/src/filter/bridge.rs +++ b/crates/aviutl2/src/filter/bridge.rs @@ -1,5 +1,5 @@ use crate::{ - common::{LeakManager, alert_error}, + common::{AnyResult, LeakManager, alert_error}, filter::{ AudioObjectInfo, FilterConfigItem, FilterPlugin, FilterPluginTable, FilterProcAudio, FilterProcVideo, ObjectInfo, SceneInfo, VideoObjectInfo, @@ -145,32 +145,48 @@ where Self: 'static + Send + Sync + FilterPlugin, { fn __get_singleton_state() -> &'static std::sync::RwLock>>; + fn with_instance(f: impl FnOnce(&Self) -> R) -> R { + let lock = Self::__get_singleton_state(); + let guard = lock.read().unwrap(); + let state = guard.as_ref().expect("Plugin not initialized"); + f(&state.instance) + } + fn with_instance_mut(f: impl FnOnce(&mut Self) -> R) -> R { + let lock = Self::__get_singleton_state(); + let mut guard = lock.write().unwrap(); + let state = guard.as_mut().expect("Plugin not initialized"); + f(&mut state.instance) + } } -pub fn initialize_plugin(version: u32) -> bool { - let plugin_state = T::__get_singleton_state(); - let info = crate::common::AviUtl2Info { - version: version.into(), - }; - let internal = match T::new(info) { - Ok(plugin) => plugin, +pub unsafe fn initialize_plugin_c(version: u32) -> bool { + match initialize_plugin::(version) { + Ok(_) => true, Err(e) => { log::error!("Failed to initialize plugin: {}", e); alert_error(&e); - return false; + false } + } +} + +pub(crate) fn initialize_plugin(version: u32) -> AnyResult<()> { + let plugin_state = T::__get_singleton_state(); + let info = crate::common::AviUtl2Info { + version: version.into(), }; + let internal = T::new(info)?; let plugin = InternalFilterPluginState::new(internal); *plugin_state.write().unwrap() = Some(plugin); - true + Ok(()) } -pub fn uninitialize_plugin() { +pub unsafe fn uninitialize_plugin() { let plugin_state = T::__get_singleton_state(); let mut plugin_state = plugin_state.write().unwrap(); *plugin_state = None; } -pub fn create_table() -> *mut aviutl2_sys::filter2::FILTER_PLUGIN_TABLE { +pub unsafe fn create_table() -> *mut aviutl2_sys::filter2::FILTER_PLUGIN_TABLE { let plugin_state = T::__get_singleton_state(); let mut plugin_state = plugin_state.write().unwrap(); let plugin_state = plugin_state.as_mut().expect("Plugin not initialized"); @@ -280,18 +296,18 @@ macro_rules! register_filter_plugin { #[unsafe(no_mangle)] unsafe extern "C" fn InitializePlugin(version: u32) -> bool { - $crate::filter::__bridge::initialize_plugin::<$struct>(version) + unsafe { $crate::filter::__bridge::initialize_plugin_c::<$struct>(version) } } #[unsafe(no_mangle)] unsafe extern "C" fn UninitializePlugin() { - $crate::filter::__bridge::uninitialize_plugin::<$struct>() + unsafe { $crate::filter::__bridge::uninitialize_plugin::<$struct>() } } #[unsafe(no_mangle)] unsafe extern "C" fn GetFilterPluginTable() -> *mut aviutl2::sys::filter2::FILTER_PLUGIN_TABLE { - $crate::filter::__bridge::create_table::<$struct>() + unsafe { $crate::filter::__bridge::create_table::<$struct>() } } } }; diff --git a/crates/aviutl2/src/generic/binding/edit_section.rs b/crates/aviutl2/src/generic/binding/edit_section.rs new file mode 100644 index 00000000..ccf24875 --- /dev/null +++ b/crates/aviutl2/src/generic/binding/edit_section.rs @@ -0,0 +1,654 @@ +use crate::common::Rational32; + +/// オブジェクトへのハンドル。 +#[derive(Debug, Clone, Copy)] +pub struct ObjectHandle { + pub(crate) internal: aviutl2_sys::plugin2::OBJECT_HANDLE, +} +impl From for ObjectHandle { + fn from(value: aviutl2_sys::plugin2::OBJECT_HANDLE) -> Self { + Self { internal: value } + } +} +impl From for aviutl2_sys::plugin2::OBJECT_HANDLE { + fn from(value: ObjectHandle) -> Self { + value.internal + } +} + +// 動いたし、このObjectHandleをグローバルに持っておくことも想定されてそうなので多分大丈夫なはず +unsafe impl Send for ObjectHandle {} +unsafe impl Sync for ObjectHandle {} + +/// 編集情報構造体。 +/// +/// # Note +/// +/// UI表示と異なり、フレーム番号・レイヤー番号は0始まりです。 +#[derive(Debug, Clone, Copy)] +pub struct EditInfo { + /// シーンの幅。 + pub width: usize, + /// シーンの高さ。 + pub height: usize, + /// フレームレート。 + pub fps: Rational32, + /// サンプルレート。 + pub sample_rate: usize, + /// 現在のカーソルのフレーム番号。 + pub frame: usize, + /// 現在の選択レイヤー番号。 + pub layer: usize, + /// オブジェクトが存在する最大のフレーム番号。 + pub frame_max: usize, + /// オブジェクトが存在する最大のレイヤー番号。 + pub layer_max: usize, +} + +impl EditInfo { + /// # Safety + /// + /// `ptr`は有効な`EDIT_INFO`ポインタである必要があります。 + pub unsafe fn from_ptr(ptr: *const aviutl2_sys::plugin2::EDIT_INFO) -> Self { + let raw = unsafe { &*ptr }; + Self { + width: raw.width as usize, + height: raw.height as usize, + fps: Rational32::new(raw.rate, raw.scale), + sample_rate: raw.sample_rate as usize, + frame: raw.frame as usize, + layer: raw.layer as usize, + frame_max: raw.frame_max as usize, + layer_max: raw.layer_max as usize, + } + } +} + +/// オブジェクトのレイヤーとフレーム情報。 +#[derive(Debug, Clone, Copy)] +pub struct ObjectLayerFrame { + pub layer: usize, + pub start: usize, + pub end: usize, +} + +/// [`EditSection`] 関連のエラー。 +#[derive(thiserror::Error, Debug)] +pub enum EditSectionError { + #[error("api call failed")] + ApiCallFailed, + #[error("object does not exist")] + ObjectDoesNotExist, + #[error("input utf-8 string contains null byte")] + InputCstrContainsNull(#[from] std::ffi::NulError), + #[error("input utf-16 string contains null byte")] + InputCwstrContainsNull(#[from] crate::common::NullByteError), + #[error("value is out of range")] + ValueOutOfRange(#[from] std::num::TryFromIntError), + #[error("api returned non-utf8 data")] + NonUtf8Data(#[from] std::str::Utf8Error), + + #[cfg(feature = "aviutl2-alias")] + #[error("alias parse error: {0}")] + ParseFailed(#[from] aviutl2_alias::TableParseError), +} + +pub type EditSectionResult = Result; + +/// 編集セクションのハンドル。 +#[derive(Debug)] +pub struct EditSection { + /// 編集情報。 + pub info: EditInfo, + + pub(crate) internal: *mut aviutl2_sys::plugin2::EDIT_SECTION, +} + +impl EditSection { + /// 生ポインタから `EditSection` を作成します。 + /// + /// # Safety + /// + /// 有効な `EDIT_SECTION` ポインタである必要があります。 + pub unsafe fn from_ptr(ptr: *mut aviutl2_sys::plugin2::EDIT_SECTION) -> Self { + Self { + internal: ptr, + info: unsafe { EditInfo::from_ptr((*ptr).info) }, + } + } + + /// オブジェクトエイリアスから指定の位置にオブジェクトを作成します。 + /// + /// # Arguments + /// + /// - `alias`:オブジェクトエイリアスのデータ。オブジェクトエイリアスと同じフォーマットで指定します。 + /// - `layer`:作成するオブジェクトのレイヤー番号(0始まり)。 + /// - `frame`:作成するオブジェクトのフレーム番号(0始まり)。 + /// - `length`:作成するオブジェクトの長さ(フレーム数)。 + /// + /// lengthはエイリアスデータにフレーム情報が無い場合に利用されます。 + /// + /// # Errors + /// + /// エイリアスの変換に失敗した場合、またはオブジェクトが既存のオブジェクトに重なる場合にエラー + /// + pub fn create_object_from_alias( + &self, + alias: &str, + layer: usize, + frame: usize, + length: usize, + ) -> EditSectionResult { + let c_alias = std::ffi::CString::new(alias)?; + let object_handle = unsafe { + ((*self.internal).create_object_from_alias)( + c_alias.as_ptr(), + layer.try_into()?, + frame.try_into()?, + length.try_into()?, + ) + }; + if object_handle.is_null() { + return Err(EditSectionError::ApiCallFailed); + } + Ok(ObjectHandle { + internal: object_handle, + }) + } + + /// 指定のフレーム番号以降にあるオブジェクトを検索します。 + /// + /// # Arguments + /// + /// - `layer`:検索するレイヤー番号(0始まり)。 + /// - `frame`:検索を開始するフレーム番号(0始まり)。 + pub fn find_object_after( + &self, + layer: usize, + frame: usize, + ) -> EditSectionResult> { + let object_handle = + unsafe { ((*self.internal).find_object)(layer.try_into()?, frame.try_into()?) }; + if object_handle.is_null() { + Ok(None) + } else { + Ok(Some(ObjectHandle { + internal: object_handle, + })) + } + } + + /// オブジェクトに対象エフェクトが何個存在するかを取得します。 + /// + /// # Arguments + /// + /// - `object`:対象のオブジェクトハンドル。 + /// - `effect`:対象のエフェクト名。(エイリアスファイルの effect.name の値) + /// + /// # Returns + /// + /// 対象エフェクトの数。存在しない場合は0を返します。 + pub fn count_object_effect( + &self, + object: &ObjectHandle, + effect: &str, + ) -> EditSectionResult { + self.ensure_object_exists(object)?; + let c_effect = crate::common::CWString::new(effect)?; + let count = + unsafe { ((*self.internal).count_object_effect)(object.internal, c_effect.as_ptr()) }; + Ok(count.try_into()?) + } + + /// 指定のオブジェクトのレイヤーとフレーム情報を取得します。 + pub fn get_object_layer_frame( + &self, + object: &ObjectHandle, + ) -> EditSectionResult { + self.ensure_object_exists(object)?; + let object = unsafe { ((*self.internal).get_object_layer_frame)(object.internal) }; + Ok(ObjectLayerFrame { + layer: object.layer.try_into()?, + start: object.start.try_into()?, + end: object.end.try_into()?, + }) + } + + /// オブジェクトの情報をエイリアスデータとして取得します。 + pub fn get_object_alias(&self, object: &ObjectHandle) -> EditSectionResult { + self.ensure_object_exists(object)?; + let alias_ptr = unsafe { ((*self.internal).get_object_alias)(object.internal) }; + if alias_ptr.is_null() { + return Err(EditSectionError::ApiCallFailed); + } + let c_str = unsafe { std::ffi::CStr::from_ptr(alias_ptr) }; + let alias = c_str.to_str()?.to_owned(); + Ok(alias) + } + + /// オブジェクトの設定項目の値を文字列で取得します。 + /// + /// # Arguments + /// + /// - `object`:対象のオブジェクトハンドル。 + /// - `effect_name`:設定項目の名前。 + /// - `effect_index`:同じ名前の設定項目が複数ある場合のインデックス(0始まり)。 + /// - `item`:設定項目の名前。(エイリアスファイルのキーの名前) + pub fn get_object_effect_item( + &self, + object: &ObjectHandle, + effect_name: &str, + effect_index: usize, + item: &str, + ) -> EditSectionResult { + self.ensure_object_exists(object)?; + let c_effect_name = crate::common::CWString::new(&format!("{effect_name}:{effect_index}"))?; + let c_item = crate::common::CWString::new(item)?; + let value_ptr = unsafe { + ((*self.internal).get_object_item_value)( + object.internal, + c_effect_name.as_ptr(), + c_item.as_ptr(), + ) + }; + if value_ptr.is_null() { + return Err(EditSectionError::ApiCallFailed); + } + let c_str = unsafe { std::ffi::CStr::from_ptr(value_ptr) }; + let value = c_str.to_str()?.to_owned(); + Ok(value) + } + + /// オブジェクトの設定項目の値を文字列で設定します。 + /// + /// # Arguments + /// + /// - `object`:対象のオブジェクトハンドル。 + /// - `effect_name`:設定項目の名前。 + /// - `effect_index`:同じ名前の設定項目が複数ある場合のインデックス(0始まり)。 + /// - `item`:設定項目の名前。(エイリアスファイルのキーの名前) + /// - `value`:設定する値。 + pub fn set_object_effect_item( + &self, + object: &ObjectHandle, + effect_name: &str, + effect_index: usize, + item: &str, + value: &str, + ) -> EditSectionResult<()> { + self.ensure_object_exists(object)?; + let c_effect_name = crate::common::CWString::new(&format!("{effect_name}:{effect_index}"))?; + let c_item = crate::common::CWString::new(item)?; + let c_value = std::ffi::CString::new(value)?; + let success = unsafe { + ((*self.internal).set_object_item_value)( + object.internal, + c_effect_name.as_ptr(), + c_item.as_ptr(), + c_value.as_ptr(), + ) + }; + if !success { + return Err(EditSectionError::ApiCallFailed); + } + Ok(()) + } + + /// オブジェクトを移動します。 + pub fn move_object( + &self, + object: &ObjectHandle, + new_layer: usize, + new_start_frame: usize, + ) -> EditSectionResult<()> { + self.ensure_object_exists(object)?; + let success = unsafe { + ((*self.internal).move_object)( + object.internal, + new_layer.try_into()?, + new_start_frame.try_into()?, + ) + }; + if !success { + return Err(EditSectionError::ApiCallFailed); + } + Ok(()) + } + + /// オブジェクトを削除します。 + pub fn delete_object(&self, object: &ObjectHandle) -> EditSectionResult<()> { + self.ensure_object_exists(object)?; + unsafe { ((*self.internal).delete_object)(object.internal) }; + Ok(()) + } + + /// 現在、オブジェクト設定ウィンドウで選択されているオブジェクトを取得します。 + pub fn get_focused_object(&self) -> EditSectionResult> { + let object_handle = unsafe { ((*self.internal).get_focus_object)() }; + if object_handle.is_null() { + Ok(None) + } else { + Ok(Some(ObjectHandle { + internal: object_handle, + })) + } + } + + /// 現在選択されているオブジェクトの一覧を取得します。 + pub fn get_selected_objects(&self) -> EditSectionResult> { + let mut handles = Vec::new(); + let num_objects = unsafe { ((*self.internal).get_selected_object_num)() }; + for i in 0..num_objects { + let object_handle = unsafe { ((*self.internal).get_selected_object)(i) }; + if object_handle.is_null() { + return Err(EditSectionError::ApiCallFailed); + } + handles.push(ObjectHandle { + internal: object_handle, + }); + } + Ok(handles) + } + + /// オブジェクト設定ウィンドウで指定のオブジェクトを選択状態にします。 + /// + /// # Note + /// + /// コールバック処理の終了時に設定されます。 + pub fn focus_object(&self, object: &ObjectHandle) -> EditSectionResult<()> { + self.ensure_object_exists(object)?; + unsafe { ((*self.internal).set_focus_object)(object.internal) }; + Ok(()) + } + + /// オブジェクトが存在するかどうか調べます。 + /// + /// # Note + /// + /// 内部的には、get_object_layer_frame を呼び出してレイヤー番号が -1 でないかを確認しています。 + pub fn object_exists(&self, object: &ObjectHandle) -> bool { + let object = unsafe { ((*self.internal).get_object_layer_frame)(object.internal) }; + object.layer != -1 + } + + fn ensure_object_exists(&self, object: &ObjectHandle) -> EditSectionResult<()> { + if !self.object_exists(object) { + return Err(EditSectionError::ObjectDoesNotExist); + } + Ok(()) + } + + #[doc(hidden)] + #[expect(private_bounds)] + pub fn __output_log_if_error(&self, result: T) { + if let Some(err_msg) = result.into_optional_error() { + let _ = crate::logger::write_error_log(&err_msg); + } + } + + #[doc(hidden)] + #[expect(private_bounds)] + pub fn __alert_if_error(&self, result: T) { + if let Some(err_msg) = result.into_optional_error() { + crate::common::alert_error(&anyhow::anyhow!(err_msg)); + } + } + + /// すべてのレイヤーをイテレータで取得します。 + pub fn layers(&self) -> EditSectionLayersIterator<'_> { + EditSectionLayersIterator::new(self) + } + + /// [EditSectionLayerCaller] を作成します。 + pub fn layer<'a>(&'a self, layer: usize) -> EditSectionLayerCaller<'a> { + EditSectionLayerCaller::new(self, layer) + } + /// [EditSectionObjectCaller] を作成します。 + pub fn object<'a>(&'a self, object: &'a ObjectHandle) -> EditSectionObjectCaller<'a> { + EditSectionObjectCaller::new(self, object) + } +} + +/// オブジェクト主体で関数を呼び出すための構造体。 +/// EditSection と ObjectHandle の組をまとめ、対象オブジェクトに対する +/// 操作を簡潔に呼び出せるようにします。 +pub struct EditSectionObjectCaller<'a> { + edit_section: &'a EditSection, + pub handle: &'a ObjectHandle, +} +impl<'a> EditSectionObjectCaller<'a> { + pub fn new(edit_section: &'a EditSection, object: &'a ObjectHandle) -> Self { + Self { + edit_section, + handle: object, + } + } + + /// オブジェクトのレイヤーとフレーム情報を取得します。 + pub fn get_layer_frame(&self) -> EditSectionResult { + self.edit_section.get_object_layer_frame(self.handle) + } + /// オブジェクトの情報をエイリアスデータとして取得します。 + pub fn get_alias(&self) -> EditSectionResult { + self.edit_section.get_object_alias(self.handle) + } + /// オブジェクトの情報をエイリアスデータとして取得し、パースします。 + #[cfg(feature = "aviutl2-alias")] + pub fn get_alias_parsed(&self) -> EditSectionResult { + self.edit_section + .get_object_alias(self.handle)? + .parse() + .map_err(Into::into) + } + + /// オブジェクトに対象エフェクトが何個存在するかを取得します。 + /// + /// # Arguments + /// + /// - `effect`:対象のエフェクト名。(エイリアスファイルの effect.name の値) + /// + /// # Returns + /// + /// 対象エフェクトの数。存在しない場合は0を返します。 + pub fn count_effect(&self, effect: &str) -> EditSectionResult { + self.edit_section.count_object_effect(self.handle, effect) + } + + /// オブジェクトの設定項目の値を文字列で取得します。 + /// + /// # Arguments + /// + /// - `effect_name`:設定項目の名前。 + /// - `effect_index`:同じ名前の設定項目が複数ある場合のインデックス(0始まり)。 + /// - `item`:設定項目の名前。(エイリアスファイルのキーの名前) + pub fn get_effect_item( + &self, + effect_name: &str, + effect_index: usize, + item: &str, + ) -> EditSectionResult { + self.edit_section + .get_object_effect_item(self.handle, effect_name, effect_index, item) + } + + /// オブジェクトの設定項目の値を文字列で設定します。 + /// + /// # Arguments + /// + /// - `effect_name`:設定項目の名前。 + /// - `effect_index`:同じ名前の設定項目が複数ある場合のインデックス(0始まり)。 + /// - `item`:設定項目の名前。(エイリアスファイルのキーの名前) + /// - `value`:設定する値。 + pub fn set_effect_item( + &self, + effect_name: &str, + effect_index: usize, + item: &str, + value: &str, + ) -> EditSectionResult<()> { + self.edit_section.set_object_effect_item( + self.handle, + effect_name, + effect_index, + item, + value, + ) + } + + /// オブジェクトを移動します。 + /// + /// # Arguments + /// + /// - `new_layer`:移動先のレイヤー番号(0始まり)。 + /// - `new_start_frame`:移動先の開始フレーム番号(0始まり)。 + pub fn move_object(&self, new_layer: usize, new_start_frame: usize) -> EditSectionResult<()> { + self.edit_section + .move_object(self.handle, new_layer, new_start_frame) + } + + /// オブジェクトを削除します。 + pub fn delete_object(&self) -> EditSectionResult<()> { + self.edit_section.delete_object(self.handle) + } + + /// オブジェクト設定ウィンドウでこのオブジェクトを選択状態にします。 + /// + /// # Note + /// + /// コールバック処理の終了時に設定されます。 + pub fn focus_object(&self) -> EditSectionResult<()> { + self.edit_section.focus_object(self.handle) + } + + /// このオブジェクトが存在するかどうか調べます。 + pub fn exists(&self) -> bool { + self.edit_section.object_exists(self.handle) + } +} + +/// レイヤー主体で関数を呼び出すための構造体。 +/// EditSection と レイヤー番号 の組をまとめ、対象レイヤーに対する +/// 操作を簡潔に呼び出せるようにします。 +pub struct EditSectionLayerCaller<'a> { + edit_section: &'a EditSection, + pub index: usize, +} +impl<'a> EditSectionLayerCaller<'a> { + pub fn new(edit_section: &'a EditSection, layer: usize) -> Self { + Self { + edit_section, + index: layer, + } + } + /// 指定のフレーム番号以降にあるオブジェクトを検索します。 + /// + /// # Arguments + /// + /// - `frame`:検索を開始するフレーム番号(0始まり)。 + pub fn find_object_after(&self, frame: usize) -> EditSectionResult> { + self.edit_section.find_object_after(self.index, frame) + } + + /// このレイヤーに存在するすべてのオブジェクトを、 + /// 開始フレームの昇順で走査するイテレータを返します。 + pub fn objects(&self) -> EditSectionLayerObjectsIterator<'a> { + EditSectionLayerObjectsIterator::new(self.edit_section, self.index) + } +} + +/// レイヤーのイテレータ。 +#[derive(Debug, Clone)] +pub struct EditSectionLayersIterator<'a> { + edit_section: &'a EditSection, + current: usize, + total: usize, +} + +impl<'a> EditSectionLayersIterator<'a> { + fn new(edit_section: &'a EditSection) -> Self { + Self { + edit_section, + current: 0, + total: edit_section.info.layer_max, + } + } +} + +impl<'a> Iterator for EditSectionLayersIterator<'a> { + type Item = EditSectionLayerCaller<'a>; + + fn next(&mut self) -> Option { + if self.current > self.total { + return None; + } + let layer = self.current; + self.current += 1; + Some(EditSectionLayerCaller::new(self.edit_section, layer)) + } +} + +/// レイヤー内のオブジェクトを走査するイテレータ。 +/// アイテムは `(オブジェクトのレイヤー・フレーム情報, ハンドル)` の組です。 +#[derive(Debug, Clone)] +pub struct EditSectionLayerObjectsIterator<'a> { + edit_section: &'a EditSection, + layer: usize, + next_frame: usize, +} + +impl<'a> EditSectionLayerObjectsIterator<'a> { + fn new(edit_section: &'a EditSection, layer: usize) -> Self { + Self { + edit_section, + layer, + next_frame: 0, + } + } +} + +impl<'a> Iterator for EditSectionLayerObjectsIterator<'a> { + type Item = (ObjectLayerFrame, ObjectHandle); + + fn next(&mut self) -> Option { + // 検索・取得でエラーが出た場合は None を返して終了する。 + let Ok(Some(handle)) = self + .edit_section + .find_object_after(self.layer, self.next_frame) + else { + return None; + }; + + let lf = match self.edit_section.get_object_layer_frame(&handle) { + Ok(lf) => lf, + Err(_) => return None, + }; + + // 次の検索開始位置を、いま見つかったオブジェクトの末尾+1 に進める。 + self.next_frame = lf.end.saturating_add(1); + + Some((lf, handle)) + } +} + +trait MenuCallbackReturn { + fn into_optional_error(self) -> Option; +} +impl MenuCallbackReturn for Result<(), E> +where + Box: From, +{ + fn into_optional_error(self) -> Option { + match self { + Ok(_) => None, + Err(e) => { + let boxed: Box = e.into(); + Some(format!("{}", boxed)) + } + } + } +} +impl MenuCallbackReturn for () { + fn into_optional_error(self) -> Option { + None + } +} diff --git a/crates/aviutl2/src/generic/binding/host_app.rs b/crates/aviutl2/src/generic/binding/host_app.rs new file mode 100644 index 00000000..ae3f1b44 --- /dev/null +++ b/crates/aviutl2/src/generic/binding/host_app.rs @@ -0,0 +1,463 @@ +use crate::{AviUtl2Info, generic::EditSection}; +use pastey::paste; + +/// ホストアプリケーションのハンドル。 +/// プラグインの初期化処理で使用します。 +/// +/// # Panics +/// +/// この方がプラグインの初期化処理の外で使用された場合はPanicします。 +pub struct HostAppHandle<'a> { + internal: *mut aviutl2_sys::plugin2::HOST_APP_TABLE, + global_leak_manager: &'a mut crate::common::LeakManager, + kill_switch: std::sync::Arc, + plugin_registry: &'a mut crate::generic::PluginRegistry, +} + +/// プラグインの初期化状態を管理するためのハンドル。 +pub struct SubPlugin { + plugin: std::marker::PhantomData, + internal: std::sync::Arc, +} +struct InternalReferenceHandle { + uninitialize_fn: fn(), +} +impl Drop for InternalReferenceHandle { + fn drop(&mut self) { + (self.uninitialize_fn)(); + } +} + +impl<'a> HostAppHandle<'a> { + pub(crate) unsafe fn new( + internal: *mut aviutl2_sys::plugin2::HOST_APP_TABLE, + global_leak_manager: &'a mut crate::common::LeakManager, + kill_switch: std::sync::Arc, + plugin_registry: &'a mut crate::generic::PluginRegistry, + ) -> Self { + Self { + internal, + global_leak_manager, + kill_switch, + plugin_registry, + } + } + + fn assert_not_killed(&self) { + if self.kill_switch.load(std::sync::atomic::Ordering::SeqCst) { + panic!("This HostAppHandle is no longer valid."); + } + } + + /// プラグインの情報を設定します。 + /// 「プラグイン情報」ダイアログで表示されます。 + pub fn set_plugin_information(&mut self, information: &str) { + self.assert_not_killed(); + let information = if cfg!(debug_assertions) { + format!("{information} (Debug Build)") + } else { + information.to_string() + }; + unsafe { + ((*self.internal).set_plugin_information)( + self.global_leak_manager.leak_as_wide_string(&information), + ) + } + } + + /// プロジェクトデータ編集用のハンドルを登録します。 + pub fn create_edit_handle(&mut self) -> crate::generic::EditHandle { + self.assert_not_killed(); + let raw_handle = unsafe { ((*self.internal).create_edit_handle)() }; + unsafe { crate::generic::EditHandle::new(raw_handle) } + } + + /// インポートメニューを登録します。 + /// + /// # See Also + /// + /// - [`crate::generic::menus`] + pub fn register_import_menu( + &mut self, + name: &str, + callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION), + ) { + self.assert_not_killed(); + unsafe { + ((*self.internal).register_import_menu)( + self.global_leak_manager.leak_as_wide_string(name), + callback, + ) + } + } + + /// エクスポートメニューを登録します。 + /// + /// # See Also + /// + /// - [`crate::generic::menus`] + pub fn register_export_menu( + &mut self, + name: &str, + callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION), + ) { + self.assert_not_killed(); + unsafe { + ((*self.internal).register_export_menu)( + self.global_leak_manager.leak_as_wide_string(name), + callback, + ) + } + } + + /// レイヤーメニューを登録します。 + /// レイヤー編集でオブジェクト未選択時の右クリックメニューに追加されます。 + /// + /// # See Also + /// + /// - [`crate::generic::menus`] + pub fn register_layer_menu( + &mut self, + name: &str, + callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION), + ) { + self.assert_not_killed(); + unsafe { + ((*self.internal).register_layer_menu)( + self.global_leak_manager.leak_as_wide_string(name), + callback, + ) + } + } + + /// オブジェクトメニューを登録します。 + /// レイヤー編集でオブジェクト選択時の右クリックメニューに追加されます。 + /// + /// # See Also + /// + /// - [`crate::generic::menus`] + pub fn register_object_menu( + &mut self, + name: &str, + callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION), + ) { + self.assert_not_killed(); + unsafe { + ((*self.internal).register_object_menu)( + self.global_leak_manager.leak_as_wide_string(name), + callback, + ) + } + } + + /// ウィンドウクライアントを登録します。 + /// + /// # Panics + /// + /// Win32のウィンドウハンドル以外が渡された場合はPanicします。 + pub fn register_window_client( + &mut self, + name: &str, + instance: &T, + ) -> Result<(), raw_window_handle::HandleError> { + self.assert_not_killed(); + let raw_handle = instance.window_handle()?; + let hwnd = match raw_handle.as_raw() { + raw_window_handle::RawWindowHandle::Win32(handle) => handle.hwnd, + _ => panic!("Only Win32WindowHandle is supported"), + }; + unsafe { + ((*self.internal).register_window_client)( + self.global_leak_manager.leak_as_wide_string(name), + hwnd.get() as *mut std::ffi::c_void, + ); + } + Ok(()) + } + + /// メニューを一括登録します。 + /// + /// # See Also + /// + /// - [`crate::generic::menus`] + pub fn register_menus(&mut self) { + self.assert_not_killed(); + T::register_menus(self); + } + + /// プロジェクトファイルをロードした直後に呼ばれる関数を登録します。 + /// また、プロジェクトの初期化時にも呼ばれます。 + /// + /// # Note + /// + /// [`crate::generic::GenericPlugin::on_project_load`] が自動的に登録されるため、 + /// 通常はこの関数を直接使用する必要はありません。 + pub fn register_project_load_handler( + &mut self, + callback: extern "C" fn(*mut aviutl2_sys::plugin2::PROJECT_FILE), + ) { + self.assert_not_killed(); + unsafe { + ((*self.internal).register_project_load_handler)(callback); + } + } + + /// プロジェクトファイルを保存する直前に呼ばれる関数を登録します。 + /// + /// # Note + /// + /// [`crate::generic::GenericPlugin::on_project_save`] が自動的に登録されるため、 + /// 通常はこの関数を直接使用する必要はありません。 + pub fn register_project_save_handler( + &mut self, + callback: extern "C" fn(*mut aviutl2_sys::plugin2::PROJECT_FILE), + ) { + self.assert_not_killed(); + unsafe { + ((*self.internal).register_project_save_handler)(callback); + } + } +} + +/// 汎用プラグインのメニュー登録用トレイト。 +pub trait GenericPluginMenus { + fn register_menus(host: &mut HostAppHandle); +} + +#[doc(inline)] +pub use aviutl2_macros::generic_menus as menus; + +#[derive(Default)] +pub(crate) struct PluginRegistry { + #[cfg(feature = "input")] + input_plugins: Vec>, + #[cfg(feature = "output")] + output_plugins: Vec>, + #[cfg(feature = "filter")] + filter_plugins: Vec>, + #[cfg(feature = "module")] + script_modules: Vec>, +} +impl PluginRegistry { + pub(crate) fn new() -> Self { + Self::default() + } +} + +macro_rules! impl_plugin_registry { + ( + $description:literal, + $feature:literal, + $module:ident, + $name:ident, + $register_method:ident, + $PluginTrait:path, + $SingletonTrait:path, + $TableType:ty + ) => { + paste! { + impl SubPlugin { + #[cfg(feature = $feature)] + #[doc = concat!($description, "の新しいインスタンスを作成します。")] + pub fn [](info: AviUtl2Info) -> crate::AnyResult + where + T: $PluginTrait + $SingletonTrait + 'static + { + crate::$module::__bridge::initialize_plugin::(info.version.into())?; + let internal = std::sync::Arc::new(InternalReferenceHandle { + uninitialize_fn: || { + unsafe { + crate::$module::__bridge::uninitialize_plugin::(); + } + }, + }); + Ok(Self { + plugin: std::marker::PhantomData, + internal, + }) + } + } + #[cfg(feature = $feature)] + impl<'a> HostAppHandle<'a> { + #[doc = concat!($description, "を登録します。")] + pub fn []( + &mut self, + handle: &SubPlugin, + ) { + self.assert_not_killed(); + unsafe { ((*self.internal).$register_method)(crate::$module::__bridge::create_table::()) }; + self.plugin_registry + .[<$name s>] + .push(std::sync::Arc::clone(&handle.internal)); + } + } + } + }; +} + +impl_plugin_registry!( + "入力プラグイン", + "input", + input, + input_plugin, + register_input_plugin, + crate::input::InputPlugin, + crate::input::__bridge::InputSingleton, + aviutl2_sys::input2::INPUT_PLUGIN_TABLE +); +impl_plugin_registry!( + "出力プラグイン", + "output", + output, + output_plugin, + register_output_plugin, + crate::output::OutputPlugin, + crate::output::__bridge::OutputSingleton, + aviutl2_sys::output2::OUTPUT_PLUGIN_TABLE +); +impl_plugin_registry!( + "フィルタープラグイン", + "filter", + filter, + filter_plugin, + register_filter_plugin, + crate::filter::FilterPlugin, + crate::filter::__bridge::FilterSingleton, + aviutl2_sys::filter2::FILTER_PLUGIN_TABLE +); +impl_plugin_registry!( + "スクリプトモジュール", + "module", + module, + script_module, + register_script_module, + crate::module::ScriptModule, + crate::module::__bridge::ScriptModuleSingleton, + aviutl2_sys::module2::SCRIPT_MODULE_TABLE +); + +/// 編集ハンドル。 +#[derive(Debug)] +pub struct EditHandle { + pub(crate) internal: *mut aviutl2_sys::plugin2::EDIT_HANDLE, +} + +unsafe impl Send for EditHandle {} +unsafe impl Sync for EditHandle {} + +/// [`EditHandle`] 関連のエラー。 +#[derive(thiserror::Error, Debug)] +pub enum EditHandleError { + #[error("api call failed")] + ApiCallFailed, +} + +impl EditHandle { + pub(crate) unsafe fn new(internal: *mut aviutl2_sys::plugin2::EDIT_HANDLE) -> Self { + Self { internal } + } + + /// プロジェクトデータの編集を開始します。 + /// + /// # Note + /// + /// 内部では call_edit_section_param を使用しています。 + pub fn call_edit_section<'a, T, F>(&self, callback: F) -> Result + where + T: Send + 'static, + F: FnOnce(&mut EditSection) -> T + Send + 'a, + { + type CallbackParam<'a, F, T> = (ChildKillablePointer>, &'a mut Option); + + let closure = Some(callback); + let param = KillablePointer::new(closure); + let child_param = param.create_child(); + + extern "C" fn trampoline( + param: *mut std::ffi::c_void, + edit_section: *mut aviutl2_sys::plugin2::EDIT_SECTION, + ) where + T: Send + 'static, + F: FnOnce(&mut EditSection) -> T, + { + unsafe { + let (child_param, result_ptr) = &mut *(param as *mut CallbackParam); + let callback = child_param + .as_mut() + .take() + .expect("Callback has already been called"); + let mut edit_section = EditSection::from_ptr(edit_section); + let res = callback(&mut edit_section); + + result_ptr.replace(res); + } + } + + let trampoline_static = trampoline:: + as extern "C" fn(*mut std::ffi::c_void, *mut aviutl2_sys::plugin2::EDIT_SECTION); + + let mut result = None; + let param = Box::>::new((child_param, &mut result)); + let param_ptr = Box::into_raw(param); + + let success = unsafe { + ((*self.internal).call_edit_section_param)( + param_ptr as *mut std::ffi::c_void, + trampoline_static, + ) + }; + + if success { + Ok(result.expect("Callback did not set result")) + } else { + Err(EditHandleError::ApiCallFailed) + } + } +} + +struct KillablePointer { + kill_switch: std::sync::Arc, + inner: *mut T, +} +unsafe impl Send for KillablePointer {} +unsafe impl Sync for KillablePointer {} +impl Drop for KillablePointer { + fn drop(&mut self) { + self.kill_switch + .store(true, std::sync::atomic::Ordering::SeqCst); + } +} +impl KillablePointer { + pub fn new(inner: T) -> Self { + Self { + kill_switch: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)), + inner: Box::into_raw(Box::new(inner)), + } + } + + pub fn create_child(&self) -> ChildKillablePointer { + ChildKillablePointer { + kill_switch: std::sync::Arc::clone(&self.kill_switch), + inner: self.inner, + } + } +} + +struct ChildKillablePointer { + kill_switch: std::sync::Arc, + inner: *mut T, +} +unsafe impl Send for ChildKillablePointer {} +unsafe impl Sync for ChildKillablePointer {} +impl ChildKillablePointer { + pub fn is_killed(&self) -> bool { + self.kill_switch.load(std::sync::atomic::Ordering::SeqCst) + } + + pub unsafe fn as_mut(&mut self) -> &mut T { + if self.is_killed() { + panic!("parent KillablePointer has been dropped"); + } + unsafe { &mut *self.inner } + } +} diff --git a/crates/aviutl2/src/generic/binding/mod.rs b/crates/aviutl2/src/generic/binding/mod.rs new file mode 100644 index 00000000..661175b9 --- /dev/null +++ b/crates/aviutl2/src/generic/binding/mod.rs @@ -0,0 +1,58 @@ +use crate::common::{AnyResult, AviUtl2Info}; + +/// 汎用プラグインの情報を表す構造体。 +#[derive(Debug, Clone)] +pub struct FilterPluginTable { + /// プラグインの情報。 + /// 「プラグイン情報」ダイアログで表示されます。 + pub information: String, +} + +/// 汎用プラグインのトレイト。 +/// このトレイトを実装し、[`crate::register_generic_plugin!`] マクロを使用してプラグインを登録します。 +pub trait GenericPlugin: Send + Sync + Sized { + /// プラグインを初期化する。 + fn new(info: AviUtl2Info) -> AnyResult; + + /// プラグインをホストに登録する。 + fn register(&mut self, registry: &mut self::host_app::HostAppHandle); + + /// プロジェクトファイルのロードを処理する。 + /// + /// プロジェクトの初期化時にも呼ばれます。 + fn on_project_load(&mut self, _project: &mut crate::generic::ProjectFile) {} + + /// プロジェクトファイルをセーブする直前に呼ばれる。 + fn on_project_save(&mut self, _project: &mut crate::generic::ProjectFile) {} + + /// シングルトンインスタンスを参照するためのヘルパーメソッド。 + /// + /// # Panics + /// + /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。 + fn with_instance(f: impl FnOnce(&Self) -> R) -> R + where + Self: crate::generic::__bridge::GenericSingleton, + { + ::with_instance(f) + } + + /// シングルトンインスタンスを可変参照するためのヘルパーメソッド。 + /// + /// # Panics + /// + /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。 + fn with_instance_mut(f: impl FnOnce(&mut Self) -> R) -> R + where + Self: crate::generic::__bridge::GenericSingleton, + { + ::with_instance_mut(f) + } +} + +mod project; +pub use project::*; +mod edit_section; +pub use edit_section::*; +mod host_app; +pub use host_app::*; diff --git a/crates/aviutl2/src/generic/binding/project.rs b/crates/aviutl2/src/generic/binding/project.rs new file mode 100644 index 00000000..b4d8325e --- /dev/null +++ b/crates/aviutl2/src/generic/binding/project.rs @@ -0,0 +1,179 @@ +/// プロジェクトファイルにデータを保存・取得するための構造体。 +pub struct ProjectFile { + pub(crate) internal: *mut aviutl2_sys::plugin2::PROJECT_FILE, +} + +/// プロジェクトファイルのデータ取得・保存に関するエラー。 +#[derive(thiserror::Error, Debug)] +pub enum ProjectFileError { + #[error("key contains null byte: {0}")] + KeyContainsNull(std::ffi::NulError), + #[error("data retrieval failed for key {0}")] + RetrievalFailed(String), + #[error("data length exceeds 4096 bytes, got {0} bytes")] + DataTooLarge(usize), + #[error("value contains null byte: {0}")] + ValueContainsNull(std::ffi::NulError), +} + +impl ProjectFile { + /// 生ポインタから`ProjectFile`を作成します。 + /// + /// # Safety + /// + /// - `raw`は有効な`PROJECT_FILE`ポインタである必要があります。 + pub unsafe fn from_raw(raw: *mut aviutl2_sys::plugin2::PROJECT_FILE) -> Self { + Self { internal: raw } + } + + /// プロジェクトに保存されている文字列を取得します。 + /// + /// # Errors + /// + /// - `key`にヌル文字が含まれている場合、失敗します。 + /// - 文字列が見つからなかった場合は失敗します。 + pub fn get_param_string(&self, key: &str) -> Result { + let c_key = std::ffi::CString::new(key).map_err(ProjectFileError::KeyContainsNull)?; + unsafe { + let raw_str = ((*self.internal).get_param_string)(c_key.as_ptr() as _); + if raw_str.is_null() { + return Err(ProjectFileError::RetrievalFailed(key.to_string())); + } + Ok(std::ffi::CStr::from_ptr(raw_str) + .to_string_lossy() + .into_owned()) + } + } + + /// プロジェクトに保存されているバイナリデータを取得します。 + /// + /// # Errors + /// + /// - `key`にヌル文字が含まれている場合、失敗します。 + /// - `data` の長さが保存されているデータの長さと一致しない場合、失敗します。 + /// - 指定されたキーに対応するデータが存在しない場合、失敗します。 + pub fn get_param_binary(&self, key: &str, data: &mut [u8]) -> Result<(), ProjectFileError> { + let success = unsafe { + let key = std::ffi::CString::new(key).map_err(ProjectFileError::KeyContainsNull)?; + ((*self.internal).get_param_binary)( + key.as_ptr() as _, + data.as_mut_ptr() as _, + data.len() as _, + ) + }; + if !success { + return Err(ProjectFileError::RetrievalFailed(key.to_string())); + } + Ok(()) + } + + /// プロジェクトに文字列を保存します。 + /// + /// # Errors + /// + /// key、valueにヌル文字が含まれている場合、失敗します。 + pub fn set_param_string(&mut self, key: &str, value: &str) -> Result<(), ProjectFileError> { + let key_cstr = std::ffi::CString::new(key).map_err(ProjectFileError::KeyContainsNull)?; + let value_cstr = + std::ffi::CString::new(value).map_err(ProjectFileError::ValueContainsNull)?; + unsafe { + ((*self.internal).set_param_string)(key_cstr.as_ptr() as _, value_cstr.as_ptr() as _); + } + Ok(()) + } + + /// プロジェクトにバイナリデータを保存します。 + /// + /// # Errors + /// + /// - `data` の長さが4096バイトを超える場合、失敗します。 + /// - `key`にヌル文字が含まれている場合、失敗します。 + pub fn set_param_binary(&mut self, key: &str, data: &[u8]) -> Result<(), ProjectFileError> { + if data.len() > 4096 { + return Err(ProjectFileError::DataTooLarge(data.len())); + } + unsafe { + let key = std::ffi::CString::new(key).map_err(ProjectFileError::KeyContainsNull)?; + ((*self.internal).set_param_binary)( + key.as_ptr() as _, + data.as_ptr() as _, + data.len() as _, + ); + } + Ok(()) + } + + /// プロジェクトに保存されているデータをすべて削除します。 + pub fn clear_params(&mut self) { + unsafe { ((*self.internal).clear_params)() } + } +} + +#[cfg(feature = "serde")] +static NAMESPACE: &str = "--aviutl2-rs"; + +#[cfg(feature = "serde")] +impl ProjectFile { + /// プロジェクトにデータをシリアライズして保存します。 + /// + /// # Note + /// + /// 今現在の実装ではデータはMessagePackにシリアライズされた後にZstdで圧縮されています。 + /// + /// # Errors + /// + /// - シリアライズに失敗した場合。 + /// - 圧縮に失敗した場合。 + pub fn serialize(&mut self, key: &str, value: &T) -> crate::AnyResult<()> { + let bytes = rmp_serde::to_vec_named(value)?; + let bytes = zstd::encode_all(&bytes[..], 0)?; + let num_bytes = bytes.len(); + self.set_param_string(key, &format!("{NAMESPACE}:serde-zstd-v1:{}", num_bytes))?; + for (i, chunk) in bytes.chunks(4096).enumerate() { + let chunk_key = format!("{NAMESPACE}:serde-zstd-v1:chunk:{}:{}", key, i); + self.set_param_binary(&chunk_key, chunk)?; + } + Ok(()) + } + + /// プロジェクトからデータをデシリアライズして取得します。 + pub fn deserialize(&self, key: &str) -> crate::AnyResult { + let header = self.get_param_string(key)?; + let header_prefix = format!("{NAMESPACE}:serde-zstd-v1:"); + let num_bytes = header + .strip_prefix(&header_prefix) + .ok_or_else(|| anyhow::anyhow!("invalid header for key {}", key))?; + let num_bytes: usize = num_bytes.parse()?; + if num_bytes == 0 { + anyhow::bail!("invalid data length 0 for key {}", key); + } + let mut bytes = Vec::with_capacity(num_bytes); + let mut read_bytes = 0; + let mut chunk = vec![0u8; 4096]; + for i in 0.. { + let chunk_key = format!("{NAMESPACE}:serde-zstd-v1:chunk:{}:{}", key, i); + let to_read = std::cmp::min(4096, num_bytes - read_bytes); + chunk.resize(to_read, 0); + match self.get_param_binary(&chunk_key, &mut chunk) { + Ok(()) => { + bytes.extend_from_slice(&chunk); + read_bytes += to_read; + if read_bytes >= num_bytes { + break; + } + } + Err(_) => break, + } + } + anyhow::ensure!( + read_bytes == num_bytes, + "incomplete data for key {}, expected {} bytes, got {} bytes", + key, + num_bytes, + read_bytes + ); + let decompressed_bytes = zstd::decode_all(&bytes[..])?; + let value: T = rmp_serde::from_slice(&decompressed_bytes)?; + Ok(value) + } +} diff --git a/crates/aviutl2/src/generic/bridge.rs b/crates/aviutl2/src/generic/bridge.rs new file mode 100644 index 00000000..76130c14 --- /dev/null +++ b/crates/aviutl2/src/generic/bridge.rs @@ -0,0 +1,141 @@ +use crate::{ + common::{AnyResult, LeakManager, alert_error}, + generic::{ + GenericPlugin, ProjectFile, + binding::{HostAppHandle, PluginRegistry}, + }, +}; + +#[doc(hidden)] +pub struct InternalGenericPluginState { + plugin_registry: PluginRegistry, + + kill_switch: std::sync::Arc, + global_leak_manager: LeakManager, + + instance: T, +} + +impl InternalGenericPluginState { + pub fn new(instance: T) -> Self { + Self { + plugin_registry: PluginRegistry::new(), + kill_switch: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)), + global_leak_manager: LeakManager::new(), + instance, + } + } +} + +pub trait GenericSingleton +where + Self: 'static + Send + Sync + GenericPlugin, +{ + fn __get_singleton_state() + -> &'static std::sync::RwLock>>; + fn with_instance(f: impl FnOnce(&Self) -> R) -> R { + let lock = Self::__get_singleton_state(); + let guard = lock.read().unwrap(); + let state = guard.as_ref().expect("Plugin not initialized"); + f(&state.instance) + } + fn with_instance_mut(f: impl FnOnce(&mut Self) -> R) -> R { + let lock = Self::__get_singleton_state(); + let mut guard = lock.write().unwrap(); + let state = guard.as_mut().expect("Plugin not initialized"); + f(&mut state.instance) + } +} + +pub unsafe fn initialize_plugin_c(version: u32) -> bool { + match initialize_plugin::(version) { + Ok(_) => true, + Err(e) => { + log::error!("Failed to initialize plugin: {}", e); + alert_error(&e); + false + } + } +} + +pub(crate) fn initialize_plugin(version: u32) -> AnyResult<()> { + let plugin_state = T::__get_singleton_state(); + let info = crate::common::AviUtl2Info { + version: version.into(), + }; + let internal = T::new(info)?; + let plugin = InternalGenericPluginState::new(internal); + *plugin_state.write().unwrap() = Some(plugin); + + Ok(()) +} +pub unsafe fn register_plugin( + host: *mut aviutl2_sys::plugin2::HOST_APP_TABLE, +) { + let plugin_state = T::__get_singleton_state(); + let mut plugin_state = plugin_state.write().unwrap(); + let plugin_state = plugin_state.as_mut().expect("Plugin not initialized"); + + let kill_switch = plugin_state.kill_switch.clone(); + let mut handle = unsafe { + HostAppHandle::new( + host, + &mut plugin_state.global_leak_manager, + kill_switch, + &mut plugin_state.plugin_registry, + ) + }; + handle.register_project_load_handler(on_project_load::); + handle.register_project_save_handler(on_project_save::); + T::register(&mut plugin_state.instance, &mut handle); + + extern "C" fn on_project_load( + project: *mut aviutl2_sys::plugin2::PROJECT_FILE, + ) { + ::with_instance_mut(|instance| unsafe { + let mut project = ProjectFile::from_raw(project); + instance.on_project_load(&mut project); + }); + } + + extern "C" fn on_project_save( + project: *mut aviutl2_sys::plugin2::PROJECT_FILE, + ) { + ::with_instance_mut(|instance| unsafe { + let mut project = ProjectFile::from_raw(project); + instance.on_project_save(&mut project); + }); + } +} +pub unsafe fn uninitialize_plugin() { + let plugin_state = T::__get_singleton_state(); + *plugin_state.write().unwrap() = None; +} + +/// 汎用プラグインを登録するマクロ。 +#[macro_export] +macro_rules! register_generic_plugin { + ($struct:ident) => { + ::aviutl2::__internal_module! { + #[unsafe(no_mangle)] + unsafe extern "C" fn InitializeLogger(logger: *mut $crate::sys::logger2::LOG_HANDLE) { + $crate::logger::__initialize_logger(logger) + } + + #[unsafe(no_mangle)] + unsafe extern "C" fn InitializePlugin(version: u32) -> bool { + unsafe { $crate::generic::__bridge::initialize_plugin_c::<$struct>(version) } + } + + #[unsafe(no_mangle)] + unsafe extern "C" fn UninitializePlugin() { + unsafe { $crate::generic::__bridge::uninitialize_plugin::<$struct>() }; + } + + #[unsafe(no_mangle)] + unsafe extern "C" fn RegisterPlugin(host: *mut aviutl2::sys::plugin2::HOST_APP_TABLE) { + unsafe { $crate::generic::__bridge::register_plugin::<$struct>(host) }; + } + } + }; +} diff --git a/crates/aviutl2/src/generic/mod.rs b/crates/aviutl2/src/generic/mod.rs new file mode 100644 index 00000000..c7e12f5a --- /dev/null +++ b/crates/aviutl2/src/generic/mod.rs @@ -0,0 +1,22 @@ +//! # aviutl2-rs / generic +//! +//! AviUtl2の汎用プラグインを実装するためのモジュール。 +//! 大まかな流れ: +//! 1. [`GenericPlugin`]トレイトを実装し、かつ +//! [`#[aviutl2::plugin(GenericPlugin)]`][crate::plugin]属性を付与した構造体を定義する +//! 2. [`crate::register_generic_plugin!`]マクロを使用してプラグインを登録する +//! +//! サンプルはを参照してください。 +//! +//! ## Note +//! +//! これは公式SDKの`plugin2.h`に相当します。が、わかりづらいので`generic`と命名しています。 + +mod binding; + +pub use super::common::*; +pub use binding::*; + +#[doc(hidden)] +#[path = "bridge.rs"] +pub mod __bridge; diff --git a/crates/aviutl2/src/input/binding.rs b/crates/aviutl2/src/input/binding.rs index 7d615017..583375a4 100644 --- a/crates/aviutl2/src/input/binding.rs +++ b/crates/aviutl2/src/input/binding.rs @@ -522,4 +522,28 @@ pub trait InputPlugin: Send + Sync + Sized { fn config(&self, _hwnd: Win32WindowHandle) -> AnyResult<()> { Ok(()) } + + /// シングルトンインスタンスを参照するためのヘルパーメソッド。 + /// + /// # Panics + /// + /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。 + fn with_instance(f: impl FnOnce(&Self) -> R) -> R + where + Self: crate::input::__bridge::InputSingleton, + { + ::with_instance(f) + } + + /// シングルトンインスタンスを可変参照するためのヘルパーメソッド。 + /// + /// # Panics + /// + /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。 + fn with_instance_mut(f: impl FnOnce(&mut Self) -> R) -> R + where + Self: crate::input::__bridge::InputSingleton, + { + ::with_instance_mut(f) + } } diff --git a/crates/aviutl2/src/input/bridge.rs b/crates/aviutl2/src/input/bridge.rs index 4dec13f5..a361edd7 100644 --- a/crates/aviutl2/src/input/bridge.rs +++ b/crates/aviutl2/src/input/bridge.rs @@ -110,32 +110,36 @@ struct InternalInputHandle { handle: T, } -pub fn initialize_plugin(version: u32) -> bool { - let plugin_state = T::__get_singleton_state(); - let info = crate::common::AviUtl2Info { - version: version.into(), - }; - let internal = match T::new(info) { - Ok(plugin) => plugin, +pub unsafe fn initialize_plugin_c(version: u32) -> bool { + match initialize_plugin::(version) { + Ok(_) => true, Err(e) => { log::error!("Failed to initialize plugin: {}", e); alert_error(&e); - return false; + false } + } +} + +pub(crate) fn initialize_plugin(version: u32) -> AnyResult<()> { + let plugin_state = T::__get_singleton_state(); + let info = crate::common::AviUtl2Info { + version: version.into(), }; + let internal = T::new(info)?; let plugin = InternalInputPluginState::new(internal); *plugin_state.write().unwrap() = Some(plugin); - true + Ok(()) } -pub fn uninitialize_plugin() { +pub unsafe fn uninitialize_plugin() { let plugin_state = T::__get_singleton_state(); let mut plugin_state = plugin_state.write().unwrap(); *plugin_state = None; } -pub fn create_table() -> *mut aviutl2_sys::input2::INPUT_PLUGIN_TABLE { +pub unsafe fn create_table() -> *mut aviutl2_sys::input2::INPUT_PLUGIN_TABLE { let plugin_state = T::__get_singleton_state(); let mut plugin_state = plugin_state.write().unwrap(); let plugin_state = plugin_state.as_mut().expect("Plugin not initialized"); @@ -527,6 +531,18 @@ where Self: 'static + Send + Sync + InputPlugin, { fn __get_singleton_state() -> &'static std::sync::RwLock>>; + fn with_instance(f: impl FnOnce(&Self) -> R) -> R { + let lock = Self::__get_singleton_state(); + let guard = lock.read().unwrap(); + let state = guard.as_ref().expect("Plugin not initialized"); + f(&state.instance) + } + fn with_instance_mut(f: impl FnOnce(&mut Self) -> R) -> R { + let lock = Self::__get_singleton_state(); + let mut guard = lock.write().unwrap(); + let state = guard.as_mut().expect("Plugin not initialized"); + f(&mut state.instance) + } } /// 入力プラグインを登録するマクロ。 @@ -541,18 +557,18 @@ macro_rules! register_input_plugin { #[unsafe(no_mangle)] unsafe extern "C" fn InitializePlugin(version: u32) -> bool { - $crate::input::__bridge::initialize_plugin::<$struct>(version) + unsafe { $crate::input::__bridge::initialize_plugin_c::<$struct>(version) } } #[unsafe(no_mangle)] unsafe extern "C" fn UninitializePlugin() { - $crate::input::__bridge::uninitialize_plugin::<$struct>() + unsafe { $crate::input::__bridge::uninitialize_plugin::<$struct>() } } #[unsafe(no_mangle)] unsafe extern "C" fn GetInputPluginTable() -> *mut aviutl2::sys::input2::INPUT_PLUGIN_TABLE { - $crate::input::__bridge::create_table::<$struct>() + unsafe { $crate::input::__bridge::create_table::<$struct>() } } } }; diff --git a/crates/aviutl2/src/internal_base.rs b/crates/aviutl2/src/internal_base.rs index c3f2089b..e436c2a2 100644 --- a/crates/aviutl2/src/internal_base.rs +++ b/crates/aviutl2/src/internal_base.rs @@ -10,6 +10,9 @@ pub mod singleton_traits { #[cfg(feature = "module")] pub use crate::module::__bridge::ScriptModuleSingleton as ScriptModule; + + #[cfg(feature = "generic")] + pub use crate::generic::__bridge::GenericSingleton as GenericPlugin; } pub mod state { @@ -24,4 +27,7 @@ pub mod state { #[cfg(feature = "module")] pub use crate::module::__bridge::InternalScriptModuleState as ScriptModule; + + #[cfg(feature = "generic")] + pub use crate::generic::__bridge::InternalGenericPluginState as GenericPlugin; } diff --git a/crates/aviutl2/src/lib.rs b/crates/aviutl2/src/lib.rs index 28a12380..4601790a 100644 --- a/crates/aviutl2/src/lib.rs +++ b/crates/aviutl2/src/lib.rs @@ -9,6 +9,7 @@ //! - [`output`][]:AviUtl2の出力プラグインを実装するためのモジュール。 //! - [`filter`][]:AviUtl2のフィルタプラグインを実装するためのモジュール。 //! - [`module`][]:AviUtl2のスクリプトモジュールプラグインを実装するためのモジュール。 +//! - [`generic`][]:AviUtl2の汎用プラグインを実装するためのモジュール。 //! - [`logger`][]:AviUtl2のロガーへのインターフェースを提供するモジュール。 //! - [`common`][]:共通の型や関数を提供するモジュール。(トップレベルに再エクスポートされています) //! - [`utils`][]:ユーティリティ関数を提供するモジュール。 @@ -21,7 +22,11 @@ //! - `output`(デフォルト):出力プラグイン機能を有効にします。 //! - `filter`(デフォルト):フィルタプラグイン機能を有効にします。 //! - `module`(デフォルト):スクリプトモジュールプラグイン機能を有効にします。 +//! - `generic`(デフォルト):汎用プラグイン機能を有効にします。 //! - `image`:`image`クレートを使用して画像の読み書きをサポートします。 +//! - `serde`:`serde`を使用してプロジェクトファイルへのデータの保存と読み込みをサポートします。 +//! +//! ## Note //! //! ### 内部アイテムについて //! @@ -30,18 +35,18 @@ //! これらのアイテムはsemverの保証対象外であり、予告なく変更または削除される可能性があります。 #![cfg_attr(docsrs, feature(doc_cfg))] -#[cfg(feature = "aviutl2-alias")] -pub use aviutl2_alias as alias; pub use aviutl2_sys as sys; pub use anyhow; pub use half; pub use log; -pub use num_rational; -pub use raw_window_handle; +#[cfg(feature = "aviutl2-alias")] +pub use aviutl2_alias as alias; #[cfg(feature = "image")] pub use image; +pub use num_rational; +pub use raw_window_handle; #[doc(inline)] pub use aviutl2_macros::plugin; @@ -58,6 +63,9 @@ pub mod filter; #[cfg(feature = "module")] pub mod module; +#[cfg(feature = "generic")] +pub mod generic; + #[doc(hidden)] #[path = "internal_base.rs"] pub mod __internal_base; diff --git a/crates/aviutl2/src/module/binding.rs b/crates/aviutl2/src/module/binding.rs index 97d82c22..868b5af0 100644 --- a/crates/aviutl2/src/module/binding.rs +++ b/crates/aviutl2/src/module/binding.rs @@ -37,4 +37,28 @@ pub trait ScriptModule: Sized + Send + Sync + 'static + ScriptModuleFunctions { /// プラグインの情報を返す。 fn plugin_info(&self) -> ScriptModuleTable; + + /// シングルトンインスタンスを参照するためのヘルパーメソッド。 + /// + /// # Panics + /// + /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。 + fn with_instance(f: impl FnOnce(&Self) -> R) -> R + where + Self: crate::module::__bridge::ScriptModuleSingleton, + { + ::with_instance(f) + } + + /// シングルトンインスタンスを可変参照するためのヘルパーメソッド。 + /// + /// # Panics + /// + /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。 + fn with_instance_mut(f: impl FnOnce(&mut Self) -> R) -> R + where + Self: crate::module::__bridge::ScriptModuleSingleton, + { + ::with_instance_mut(f) + } } diff --git a/crates/aviutl2/src/module/bridge.rs b/crates/aviutl2/src/module/bridge.rs index fe7fe02e..02b3979f 100644 --- a/crates/aviutl2/src/module/bridge.rs +++ b/crates/aviutl2/src/module/bridge.rs @@ -1,5 +1,5 @@ use crate::{ - common::{LeakManager, alert_error}, + common::{AnyResult, LeakManager, alert_error}, module::{ScriptModule, ScriptModuleTable}, }; @@ -27,25 +27,43 @@ where Self: ScriptModule + Sized + Send + Sync + 'static, { fn __get_singleton_state() -> &'static std::sync::RwLock>>; + + fn with_instance(f: impl FnOnce(&Self) -> R) -> R { + let lock = Self::__get_singleton_state(); + let guard = lock.read().unwrap(); + let state = guard.as_ref().expect("Plugin not initialized"); + f(&state.instance) + } + + fn with_instance_mut(f: impl FnOnce(&mut Self) -> R) -> R { + let lock = Self::__get_singleton_state(); + let mut guard = lock.write().unwrap(); + let state = guard.as_mut().expect("Plugin not initialized"); + f(&mut state.instance) + } } -pub unsafe fn initialize_plugin(version: u32) -> bool { - let plugin_state = T::__get_singleton_state(); - let info = crate::common::AviUtl2Info { - version: version.into(), - }; - let internal = match T::new(info) { - Ok(plugin) => plugin, +pub unsafe fn initialize_plugin_c(version: u32) -> bool { + match initialize_plugin::(version) { + Ok(_) => true, Err(e) => { log::error!("Failed to initialize plugin: {}", e); alert_error(&e); - return false; + false } + } +} + +pub(crate) fn initialize_plugin(version: u32) -> AnyResult<()> { + let plugin_state = T::__get_singleton_state(); + let info = crate::common::AviUtl2Info { + version: version.into(), }; + let internal = T::new(info)?; let plugin = InternalScriptModuleState::new(internal); *plugin_state.write().unwrap() = Some(plugin); - true + Ok(()) } pub unsafe fn uninitialize_plugin() { let plugin_state = T::__get_singleton_state(); @@ -111,7 +129,7 @@ macro_rules! register_script_module { #[unsafe(no_mangle)] unsafe extern "C" fn InitializePlugin(version: u32) -> bool { - unsafe { $crate::module::__bridge::initialize_plugin::<$struct>(version) } + unsafe { $crate::module::__bridge::initialize_plugin_c::<$struct>(version) } } #[unsafe(no_mangle)] diff --git a/crates/aviutl2/src/module/param.rs b/crates/aviutl2/src/module/param.rs index 785b1248..f266ea92 100644 --- a/crates/aviutl2/src/module/param.rs +++ b/crates/aviutl2/src/module/param.rs @@ -25,7 +25,9 @@ impl ScriptModuleCallHandle { /// # Safety /// /// `ptr`は有効な`SCRIPT_MODULE_PARAM`へのポインタである必要があります。 - pub fn from_ptr(ptr: *mut aviutl2_sys::module2::SCRIPT_MODULE_PARAM) -> ScriptModuleCallHandle { + pub unsafe fn from_ptr( + ptr: *mut aviutl2_sys::module2::SCRIPT_MODULE_PARAM, + ) -> ScriptModuleCallHandle { ScriptModuleCallHandle { internal: ptr } } diff --git a/crates/aviutl2/src/output/binding.rs b/crates/aviutl2/src/output/binding.rs index 542f7a58..1902a583 100644 --- a/crates/aviutl2/src/output/binding.rs +++ b/crates/aviutl2/src/output/binding.rs @@ -111,6 +111,30 @@ pub trait OutputPlugin: Send + Sync + Sized { fn config_text(&self) -> AnyResult { Ok(String::new()) } + + /// シングルトンインスタンスを参照するためのヘルパーメソッド。 + /// + /// # Panics + /// + /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。 + fn with_instance(f: impl FnOnce(&Self) -> R) -> R + where + Self: crate::output::__bridge::OutputSingleton, + { + ::with_instance(f) + } + + /// シングルトンインスタンスを可変参照するためのヘルパーメソッド。 + /// + /// # Panics + /// + /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。 + fn with_instance_mut(f: impl FnOnce(&mut Self) -> R) -> R + where + Self: crate::output::__bridge::OutputSingleton, + { + ::with_instance_mut(f) + } } /// 音声サンプルを表すトレイト。 diff --git a/crates/aviutl2/src/output/bridge.rs b/crates/aviutl2/src/output/bridge.rs index d839067c..95b7ecf8 100644 --- a/crates/aviutl2/src/output/bridge.rs +++ b/crates/aviutl2/src/output/bridge.rs @@ -1,7 +1,7 @@ use std::num::NonZeroIsize; use crate::{ - common::{LeakManager, alert_error, format_file_filters}, + common::{AnyResult, LeakManager, alert_error, format_file_filters}, output::{FromRawAudioSamples, OutputInfo, OutputPlugin}, }; @@ -51,32 +51,36 @@ impl FromRawAudioSamples for i16 { } } -pub fn initialize_plugin(version: u32) -> bool { - let plugin_state = T::__get_singleton_state(); - let info = crate::common::AviUtl2Info { - version: version.into(), - }; - let internal = match T::new(info) { - Ok(plugin) => plugin, +pub unsafe fn initialize_plugin_c(version: u32) -> bool { + match initialize_plugin::(version) { + Ok(_) => true, Err(e) => { log::error!("Failed to initialize plugin: {}", e); alert_error(&e); - return false; + false } + } +} + +pub(crate) fn initialize_plugin(version: u32) -> AnyResult<()> { + let plugin_state = T::__get_singleton_state(); + let info = crate::common::AviUtl2Info { + version: version.into(), }; + let internal = T::new(info)?; let plugin = InternalOutputPluginState::new(internal); *plugin_state.write().unwrap() = Some(plugin); - true + Ok(()) } -pub fn uninitialize_plugin() { +pub unsafe fn uninitialize_plugin() { let plugin_state = T::__get_singleton_state(); let mut plugin_state = plugin_state.write().unwrap(); *plugin_state = None; } -pub fn create_table() -> *mut aviutl2_sys::output2::OUTPUT_PLUGIN_TABLE { +pub unsafe fn create_table() -> *mut aviutl2_sys::output2::OUTPUT_PLUGIN_TABLE { let plugin_state = T::__get_singleton_state(); let mut plugin_state = plugin_state.write().unwrap(); let plugin_state = plugin_state.as_mut().expect("Plugin not initialized"); @@ -178,6 +182,18 @@ where Self: 'static + Send + Sync + OutputPlugin, { fn __get_singleton_state() -> &'static std::sync::RwLock>>; + fn with_instance(f: impl FnOnce(&Self) -> R) -> R { + let lock = Self::__get_singleton_state(); + let guard = lock.read().unwrap(); + let state = guard.as_ref().expect("Plugin not initialized"); + f(&state.instance) + } + fn with_instance_mut(f: impl FnOnce(&mut Self) -> R) -> R { + let lock = Self::__get_singleton_state(); + let mut guard = lock.write().unwrap(); + let state = guard.as_mut().expect("Plugin not initialized"); + f(&mut state.instance) + } } /// 出力プラグインを登録するマクロ。 @@ -192,7 +208,7 @@ macro_rules! register_output_plugin { #[unsafe(no_mangle)] unsafe extern "C" fn InitializePlugin(version: u32) -> bool { - $crate::output::__bridge::initialize_plugin::<$struct>(version) + $crate::output::__bridge::initialize_plugin_c::<$struct>(version) } #[unsafe(no_mangle)] diff --git a/examples/ffmpeg-output/src/lib.rs b/examples/ffmpeg-output/src/lib.rs index d4ef8f4f..f0216aef 100644 --- a/examples/ffmpeg-output/src/lib.rs +++ b/examples/ffmpeg-output/src/lib.rs @@ -200,7 +200,7 @@ impl OutputPlugin for FfmpegOutputPlugin { ] }, information: format!( - "FFmpeg for AviUtl, written in Rust / v{version} / https://github.com/sevenc-nanashi/aviutl2-rs/tree/main/examples/ffmpeg-output", + "FFmpeg for AviUtl2, written in Rust / v{version} / https://github.com/sevenc-nanashi/aviutl2-rs/tree/main/examples/ffmpeg-output", version = env!("CARGO_PKG_VERSION") ), can_config: true, diff --git a/examples/image-rs-input/src/lib.rs b/examples/image-rs-input/src/lib.rs index aa9309f8..e503c987 100644 --- a/examples/image-rs-input/src/lib.rs +++ b/examples/image-rs-input/src/lib.rs @@ -71,7 +71,7 @@ impl InputPlugin for ImageInputPlugin { ], }, information: format!( - "image-rs Input for AviUtl, written in Rust / v{version} / https://github.com/sevenc-nanashi/aviutl2-rs/tree/main/examples/image-rs-input", + "image-rs Input for AviUtl2, written in Rust / v{version} / https://github.com/sevenc-nanashi/aviutl2-rs/tree/main/examples/image-rs-input", version = env!("CARGO_PKG_VERSION") ), can_config: false, diff --git a/examples/image-rs-output/src/lib.rs b/examples/image-rs-output/src/lib.rs index 6e7e2912..b5ac7586 100644 --- a/examples/image-rs-output/src/lib.rs +++ b/examples/image-rs-output/src/lib.rs @@ -47,7 +47,7 @@ impl OutputPlugin for ImageRsOutputPlugin { }, information: format!( - "image-rs Output for AviUtl, written in Rust / v{version} / https://github.com/sevenc-nanashi/aviutl2-rs/tree/main/examples/image-rs-output", + "image-rs Output for AviUtl2, written in Rust / v{version} / https://github.com/sevenc-nanashi/aviutl2-rs/tree/main/examples/image-rs-output", version = env!("CARGO_PKG_VERSION") ), can_config: false, diff --git a/examples/local-alias-plugin/Cargo.toml b/examples/local-alias-plugin/Cargo.toml new file mode 100644 index 00000000..708af228 --- /dev/null +++ b/examples/local-alias-plugin/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "example-local-alias-plugin" +version.workspace = true +edition.workspace = true +license.workspace = true +authors.workspace = true +repository.workspace = true +publish = false + +[lib] +name = "rusty_local_alias_plugin" +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1.0.98" +aviutl2 = { workspace = true, features = ["serde"] } +dirs = "6.0.0" +raw-window-handle = "0.6.2" +tao = "0.34.5" +wry = "0.53.5" +windows = { version = "0.58.0", features = [ + "Win32_Foundation", + "Win32_UI_WindowsAndMessaging", + "Win32_System_LibraryLoader", + "Win32_Graphics_Gdi", +] } +include_dir = "0.7.4" +tap = "1.0.1" +mime_guess = "2.0.5" +serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.145" +env_logger = "0.11.8" +log = "0.4.28" +open = "5.3.2" diff --git a/examples/local-alias-plugin/README.md b/examples/local-alias-plugin/README.md new file mode 100644 index 00000000..c8559a91 --- /dev/null +++ b/examples/local-alias-plugin/README.md @@ -0,0 +1,8 @@ +# Rusty Local Alias Plugin + +汎用プラグインのサンプルです。 +プロジェクトファイル内にエイリアスを登録する機能を提供します。 + +## インストール + +`C:\ProgramData\aviutl2\Script` に `rusty_local_alias.aux2` を配置してください。 diff --git a/examples/local-alias-plugin/page/.gitignore b/examples/local-alias-plugin/page/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/examples/local-alias-plugin/page/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/examples/local-alias-plugin/page/biome.json b/examples/local-alias-plugin/page/biome.json new file mode 100644 index 00000000..e5f859da --- /dev/null +++ b/examples/local-alias-plugin/page/biome.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.2/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "includes": ["**", "!!**/dist"] + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2 + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "html": { + "experimentalFullSupportEnabled": true + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "on" + } + } + } +} diff --git a/examples/local-alias-plugin/page/bun.lock b/examples/local-alias-plugin/page/bun.lock new file mode 100644 index 00000000..9e4463ed --- /dev/null +++ b/examples/local-alias-plugin/page/bun.lock @@ -0,0 +1,336 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "page", + "dependencies": { + "vue": "^3.5.22", + }, + "devDependencies": { + "@biomejs/biome": "^2.3.2", + "@vitejs/plugin-vue": "^6.0.1", + "@vue/tsconfig": "^0.7.0", + "prettier": "^3.6.2", + "sass-embedded": "^1.93.3", + "typescript": "~5.8.3", + "vite": "^7.1.12", + "vue-tsc": "^3.1.2", + }, + }, + }, + "packages": { + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + + "@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], + + "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], + + "@biomejs/biome": ["@biomejs/biome@2.3.2", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.2", "@biomejs/cli-darwin-x64": "2.3.2", "@biomejs/cli-linux-arm64": "2.3.2", "@biomejs/cli-linux-arm64-musl": "2.3.2", "@biomejs/cli-linux-x64": "2.3.2", "@biomejs/cli-linux-x64-musl": "2.3.2", "@biomejs/cli-win32-arm64": "2.3.2", "@biomejs/cli-win32-x64": "2.3.2" }, "bin": { "biome": "bin/biome" } }, "sha512-8e9tzamuDycx7fdrcJ/F/GDZ8SYukc5ud6tDicjjFqURKYFSWMl0H0iXNXZEGmcmNUmABgGuHThPykcM41INgg=="], + + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4LECm4kc3If0JISai4c3KWQzukoUdpxy4fRzlrPcrdMSRFksR9ZoXK7JBcPuLBmd2SoT4/d7CQS33VnZpgBjew=="], + + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-jNMnfwHT4N3wi+ypRfMTjLGnDmKYGzxVr1EYAPBcauRcDnICFXN81wD6wxJcSUrLynoyyYCdfW6vJHS/IAoTDA=="], + + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-amnqvk+gWybbQleRRq8TMe0rIv7GHss8mFJEaGuEZYWg1Tw14YKOkeo8h6pf1c+d3qR+JU4iT9KXnBKGON4klw=="], + + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-2Zz4usDG1GTTPQnliIeNx6eVGGP2ry5vE/v39nT73a3cKN6t5H5XxjcEoZZh62uVZvED7hXXikclvI64vZkYqw=="], + + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.2", "", { "os": "linux", "cpu": "x64" }, "sha512-8BG/vRAhFz1pmuyd24FQPhNeueLqPtwvZk6yblABY2gzL2H8fLQAF/Z2OPIc+BPIVPld+8cSiKY/KFh6k81xfA=="], + + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.2", "", { "os": "linux", "cpu": "x64" }, "sha512-gzB19MpRdTuOuLtPpFBGrV3Lq424gHyq2lFj8wfX9tvLMLdmA/R9C7k/mqBp/spcbWuHeIEKgEs3RviOPcWGBA=="], + + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-lCruqQlfWjhMlOdyf5pDHOxoNm4WoyY2vZ4YN33/nuZBRstVDuqPPjS0yBkbUlLEte11FbpW+wWSlfnZfSIZvg=="], + + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.2", "", { "os": "win32", "cpu": "x64" }, "sha512-6Ee9P26DTb4D8sN9nXxgbi9Dw5vSOfH98M7UlmkjKB2vtUbrRqCbZiNfryGiwnPIpd6YUoTl7rLVD2/x1CyEHQ=="], + + "@bufbuild/protobuf": ["@bufbuild/protobuf@2.10.0", "", {}, "sha512-fdRs9PSrBF7QUntpZpq6BTw58fhgGJojgg39m9oFOJGZT+nip9b0so5cYY1oWl5pvemDLr0cPPsH46vwThEbpQ=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.9", "", { "os": "aix", "cpu": "ppc64" }, "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.9", "", { "os": "android", "cpu": "arm" }, "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.9", "", { "os": "android", "cpu": "arm64" }, "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.9", "", { "os": "android", "cpu": "x64" }, "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.9", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.9", "", { "os": "freebsd", "cpu": "x64" }, "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.9", "", { "os": "linux", "cpu": "arm" }, "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.9", "", { "os": "linux", "cpu": "ia32" }, "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.9", "", { "os": "linux", "cpu": "ppc64" }, "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.9", "", { "os": "linux", "cpu": "s390x" }, "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.9", "", { "os": "linux", "cpu": "x64" }, "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.9", "", { "os": "none", "cpu": "arm64" }, "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.9", "", { "os": "none", "cpu": "x64" }, "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.9", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.9", "", { "os": "openbsd", "cpu": "x64" }, "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.9", "", { "os": "none", "cpu": "arm64" }, "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.9", "", { "os": "sunos", "cpu": "x64" }, "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.9", "", { "os": "win32", "cpu": "ia32" }, "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.9", "", { "os": "win32", "cpu": "x64" }, "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="], + + "@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.1", "", { "os": "android", "cpu": "arm64" }, "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA=="], + + "@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw=="], + + "@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.5.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg=="], + + "@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ=="], + + "@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA=="], + + "@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q=="], + + "@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w=="], + + "@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg=="], + + "@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A=="], + + "@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg=="], + + "@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw=="], + + "@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ=="], + + "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="], + + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.29", "", {}, "sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.46.4", "", { "os": "android", "cpu": "arm" }, "sha512-B2wfzCJ+ps/OBzRjeds7DlJumCU3rXMxJJS1vzURyj7+KBHGONm7c9q1TfdBl4vCuNMkDvARn3PBl2wZzuR5mw=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.46.4", "", { "os": "android", "cpu": "arm64" }, "sha512-FGJYXvYdn8Bs6lAlBZYT5n+4x0ciEp4cmttsvKAZc/c8/JiPaQK8u0c/86vKX8lA7OY/+37lIQSe0YoAImvBAA=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.46.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/9qwE/BM7ATw/W/OFEMTm3dmywbJyLQb4f4v5nmOjgYxPIGpw7HaxRi6LnD4Pjn/q7k55FGeHe1/OD02w63apA=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.46.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-QkWfNbeRuzFnv2d0aPlrzcA3Ebq2mE8kX/5Pl7VdRShbPBjSnom7dbT8E3Jmhxo2RL784hyqGvR5KHavCJQciw=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.46.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-+ToyOMYnSfV8D+ckxO6NthPln/PDNp1P6INcNypfZ7muLmEvPKXqduUiD8DlJpMMT8LxHcE5W0dK9kXfJke9Zw=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.46.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-cGT6ey/W+sje6zywbLiqmkfkO210FgRz7tepWAzzEVgQU8Hn91JJmQWNqs55IuglG8sJdzk7XfNgmGRtcYlo1w=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.46.4", "", { "os": "linux", "cpu": "arm" }, "sha512-9fhTJyOb275w5RofPSl8lpr4jFowd+H4oQKJ9XTYzD1JWgxdZKE8bA6d4npuiMemkecQOcigX01FNZNCYnQBdA=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.46.4", "", { "os": "linux", "cpu": "arm" }, "sha512-+6kCIM5Zjvz2HwPl/udgVs07tPMIp1VU2Y0c72ezjOvSvEfAIWsUgpcSDvnC7g9NrjYR6X9bZT92mZZ90TfvXw=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.46.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-SWuXdnsayCZL4lXoo6jn0yyAj7TTjWE4NwDVt9s7cmu6poMhtiras5c8h6Ih6Y0Zk6Z+8t/mLumvpdSPTWub2Q=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.46.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-vDknMDqtMhrrroa5kyX6tuC0aRZZlQ+ipDfbXd2YGz5HeV2t8HOl/FDAd2ynhs7Ki5VooWiiZcCtxiZ4IjqZwQ=="], + + "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.46.4", "", { "os": "linux", "cpu": "none" }, "sha512-mCBkjRZWhvjtl/x+Bd4fQkWZT8canStKDxGrHlBiTnZmJnWygGcvBylzLVCZXka4dco5ymkWhZlLwKCGFF4ivw=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.46.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-YMdz2phOTFF+Z66dQfGf0gmeDSi5DJzY5bpZyeg9CPBkV9QDzJ1yFRlmi/j7WWRf3hYIWrOaJj5jsfwgc8GTHQ=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.46.4", "", { "os": "linux", "cpu": "none" }, "sha512-r0WKLSfFAK8ucG024v2yiLSJMedoWvk8yWqfNICX28NHDGeu3F/wBf8KG6mclghx4FsLePxJr/9N8rIj1PtCnw=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.46.4", "", { "os": "linux", "cpu": "none" }, "sha512-IaizpPP2UQU3MNyPH1u0Xxbm73D+4OupL0bjo4Hm0496e2wg3zuvoAIhubkD1NGy9fXILEExPQy87mweujEatA=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.46.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-aCM29orANR0a8wk896p6UEgIfupReupnmISz6SUwMIwTGaTI8MuKdE0OD2LvEg8ondDyZdMvnaN3bW4nFbATPA=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.46.4", "", { "os": "linux", "cpu": "x64" }, "sha512-0Xj1vZE3cbr/wda8d/m+UeuSL+TDpuozzdD4QaSzu/xSOMK0Su5RhIkF7KVHFQsobemUNHPLEcYllL7ZTCP/Cg=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.46.4", "", { "os": "linux", "cpu": "x64" }, "sha512-kM/orjpolfA5yxsx84kI6bnK47AAZuWxglGKcNmokw2yy9i5eHY5UAjcX45jemTJnfHAWo3/hOoRqEeeTdL5hw=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.46.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-cNLH4psMEsWKILW0isbpQA2OvjXLbKvnkcJFmqAptPQbtLrobiapBJVj6RoIvg6UXVp5w0wnIfd/Q56cNpF+Ew=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.46.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-OiEa5lRhiANpv4SfwYVgQ3opYWi/QmPDC5ve21m8G9pf6ZO+aX1g2EEF1/IFaM1xPSP7mK0msTRXlPs6mIagkg=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.46.4", "", { "os": "win32", "cpu": "x64" }, "sha512-IKL9mewGZ5UuuX4NQlwOmxPyqielvkAPUS2s1cl6yWjjQvyN3h5JTdVFGD5Jr5xMjRC8setOfGQDVgX8V+dkjg=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@vitejs/plugin-vue": ["@vitejs/plugin-vue@6.0.1", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-beta.29" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0 || ^7.0.0", "vue": "^3.2.25" } }, "sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw=="], + + "@volar/language-core": ["@volar/language-core@2.4.23", "", { "dependencies": { "@volar/source-map": "2.4.23" } }, "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ=="], + + "@volar/source-map": ["@volar/source-map@2.4.23", "", {}, "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q=="], + + "@volar/typescript": ["@volar/typescript@2.4.23", "", { "dependencies": { "@volar/language-core": "2.4.23", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag=="], + + "@vue/compiler-core": ["@vue/compiler-core@3.5.22", "", { "dependencies": { "@babel/parser": "^7.28.4", "@vue/shared": "3.5.22", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ=="], + + "@vue/compiler-dom": ["@vue/compiler-dom@3.5.22", "", { "dependencies": { "@vue/compiler-core": "3.5.22", "@vue/shared": "3.5.22" } }, "sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA=="], + + "@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.22", "", { "dependencies": { "@babel/parser": "^7.28.4", "@vue/compiler-core": "3.5.22", "@vue/compiler-dom": "3.5.22", "@vue/compiler-ssr": "3.5.22", "@vue/shared": "3.5.22", "estree-walker": "^2.0.2", "magic-string": "^0.30.19", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-tbTR1zKGce4Lj+JLzFXDq36K4vcSZbJ1RBu8FxcDv1IGRz//Dh2EBqksyGVypz3kXpshIfWKGOCcqpSbyGWRJQ=="], + + "@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.22", "", { "dependencies": { "@vue/compiler-dom": "3.5.22", "@vue/shared": "3.5.22" } }, "sha512-GdgyLvg4R+7T8Nk2Mlighx7XGxq/fJf9jaVofc3IL0EPesTE86cP/8DD1lT3h1JeZr2ySBvyqKQJgbS54IX1Ww=="], + + "@vue/language-core": ["@vue/language-core@3.1.2", "", { "dependencies": { "@volar/language-core": "2.4.23", "@vue/compiler-dom": "^3.5.0", "@vue/shared": "^3.5.0", "alien-signals": "^3.0.0", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", "picomatch": "^4.0.2" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-PyFDCqpdfYUT+oMLqcc61oHfJlC6yjhybaefwQjRdkchIihToOEpJ2Wu/Ebq2yrnJdd1EsaAvZaXVAqcxtnDxQ=="], + + "@vue/reactivity": ["@vue/reactivity@3.5.22", "", { "dependencies": { "@vue/shared": "3.5.22" } }, "sha512-f2Wux4v/Z2pqc9+4SmgZC1p73Z53fyD90NFWXiX9AKVnVBEvLFOWCEgJD3GdGnlxPZt01PSlfmLqbLYzY/Fw4A=="], + + "@vue/runtime-core": ["@vue/runtime-core@3.5.22", "", { "dependencies": { "@vue/reactivity": "3.5.22", "@vue/shared": "3.5.22" } }, "sha512-EHo4W/eiYeAzRTN5PCextDUZ0dMs9I8mQ2Fy+OkzvRPUYQEyK9yAjbasrMCXbLNhF7P0OUyivLjIy0yc6VrLJQ=="], + + "@vue/runtime-dom": ["@vue/runtime-dom@3.5.22", "", { "dependencies": { "@vue/reactivity": "3.5.22", "@vue/runtime-core": "3.5.22", "@vue/shared": "3.5.22", "csstype": "^3.1.3" } }, "sha512-Av60jsryAkI023PlN7LsqrfPvwfxOd2yAwtReCjeuugTJTkgrksYJJstg1e12qle0NarkfhfFu1ox2D+cQotww=="], + + "@vue/server-renderer": ["@vue/server-renderer@3.5.22", "", { "dependencies": { "@vue/compiler-ssr": "3.5.22", "@vue/shared": "3.5.22" }, "peerDependencies": { "vue": "3.5.22" } }, "sha512-gXjo+ao0oHYTSswF+a3KRHZ1WszxIqO7u6XwNHqcqb9JfyIL/pbWrrh/xLv7jeDqla9u+LK7yfZKHih1e1RKAQ=="], + + "@vue/shared": ["@vue/shared@3.5.22", "", {}, "sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w=="], + + "@vue/tsconfig": ["@vue/tsconfig@0.7.0", "", { "peerDependencies": { "typescript": "5.x", "vue": "^3.4.0" }, "optionalPeers": ["typescript", "vue"] }, "sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg=="], + + "alien-signals": ["alien-signals@3.0.5", "", {}, "sha512-+2bRQFO1f9GLeIabDQWJlluL1NspZlLjpjaSSwwpl+9Tz5tS/3KrceHdwjNvIMEbYWSpoqtOPuXLTSoPgvIEWw=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "buffer-builder": ["buffer-builder@0.2.0", "", {}, "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg=="], + + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + + "colorjs.io": ["colorjs.io@0.5.2", "", {}, "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw=="], + + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + + "detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], + + "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + + "esbuild": ["esbuild@0.25.9", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.9", "@esbuild/android-arm": "0.25.9", "@esbuild/android-arm64": "0.25.9", "@esbuild/android-x64": "0.25.9", "@esbuild/darwin-arm64": "0.25.9", "@esbuild/darwin-x64": "0.25.9", "@esbuild/freebsd-arm64": "0.25.9", "@esbuild/freebsd-x64": "0.25.9", "@esbuild/linux-arm": "0.25.9", "@esbuild/linux-arm64": "0.25.9", "@esbuild/linux-ia32": "0.25.9", "@esbuild/linux-loong64": "0.25.9", "@esbuild/linux-mips64el": "0.25.9", "@esbuild/linux-ppc64": "0.25.9", "@esbuild/linux-riscv64": "0.25.9", "@esbuild/linux-s390x": "0.25.9", "@esbuild/linux-x64": "0.25.9", "@esbuild/netbsd-arm64": "0.25.9", "@esbuild/netbsd-x64": "0.25.9", "@esbuild/openbsd-arm64": "0.25.9", "@esbuild/openbsd-x64": "0.25.9", "@esbuild/openharmony-arm64": "0.25.9", "@esbuild/sunos-x64": "0.25.9", "@esbuild/win32-arm64": "0.25.9", "@esbuild/win32-ia32": "0.25.9", "@esbuild/win32-x64": "0.25.9" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g=="], + + "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "immutable": ["immutable@5.1.4", "", {}, "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], + + "path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + + "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], + + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + + "rollup": ["rollup@4.46.4", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.46.4", "@rollup/rollup-android-arm64": "4.46.4", "@rollup/rollup-darwin-arm64": "4.46.4", "@rollup/rollup-darwin-x64": "4.46.4", "@rollup/rollup-freebsd-arm64": "4.46.4", "@rollup/rollup-freebsd-x64": "4.46.4", "@rollup/rollup-linux-arm-gnueabihf": "4.46.4", "@rollup/rollup-linux-arm-musleabihf": "4.46.4", "@rollup/rollup-linux-arm64-gnu": "4.46.4", "@rollup/rollup-linux-arm64-musl": "4.46.4", "@rollup/rollup-linux-loongarch64-gnu": "4.46.4", "@rollup/rollup-linux-ppc64-gnu": "4.46.4", "@rollup/rollup-linux-riscv64-gnu": "4.46.4", "@rollup/rollup-linux-riscv64-musl": "4.46.4", "@rollup/rollup-linux-s390x-gnu": "4.46.4", "@rollup/rollup-linux-x64-gnu": "4.46.4", "@rollup/rollup-linux-x64-musl": "4.46.4", "@rollup/rollup-win32-arm64-msvc": "4.46.4", "@rollup/rollup-win32-ia32-msvc": "4.46.4", "@rollup/rollup-win32-x64-msvc": "4.46.4", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-YbxoxvoqNg9zAmw4+vzh1FkGAiZRK+LhnSrbSrSXMdZYsRPDWoshcSd/pldKRO6lWzv/e9TiJAVQyirYIeSIPQ=="], + + "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], + + "sass": ["sass@1.93.3", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-elOcIZRTM76dvxNAjqYrucTSI0teAF/L2Lv0s6f6b7FOwcwIuA357bIE871580AjHJuSvLIRUosgV+lIWx6Rgg=="], + + "sass-embedded": ["sass-embedded@1.93.3", "", { "dependencies": { "@bufbuild/protobuf": "^2.5.0", "buffer-builder": "^0.2.0", "colorjs.io": "^0.5.0", "immutable": "^5.0.2", "rxjs": "^7.4.0", "supports-color": "^8.1.1", "sync-child-process": "^1.0.2", "varint": "^6.0.0" }, "optionalDependencies": { "sass-embedded-all-unknown": "1.93.3", "sass-embedded-android-arm": "1.93.3", "sass-embedded-android-arm64": "1.93.3", "sass-embedded-android-riscv64": "1.93.3", "sass-embedded-android-x64": "1.93.3", "sass-embedded-darwin-arm64": "1.93.3", "sass-embedded-darwin-x64": "1.93.3", "sass-embedded-linux-arm": "1.93.3", "sass-embedded-linux-arm64": "1.93.3", "sass-embedded-linux-musl-arm": "1.93.3", "sass-embedded-linux-musl-arm64": "1.93.3", "sass-embedded-linux-musl-riscv64": "1.93.3", "sass-embedded-linux-musl-x64": "1.93.3", "sass-embedded-linux-riscv64": "1.93.3", "sass-embedded-linux-x64": "1.93.3", "sass-embedded-unknown-all": "1.93.3", "sass-embedded-win32-arm64": "1.93.3", "sass-embedded-win32-x64": "1.93.3" }, "bin": { "sass": "dist/bin/sass.js" } }, "sha512-+VUy01yfDqNmIVMd/LLKl2TTtY0ovZN0rTonh+FhKr65mFwIYgU9WzgIZKS7U9/SPCQvWTsTGx9jyt+qRm/XFw=="], + + "sass-embedded-all-unknown": ["sass-embedded-all-unknown@1.93.3", "", { "dependencies": { "sass": "1.93.3" }, "cpu": [ "!arm", "!x64", "!arm64", ] }, "sha512-3okGgnE41eg+CPLtAPletu6nQ4N0ij7AeW+Sl5Km4j29XcmqZQeFwYjHe1AlKTEgLi/UAONk1O8i8/lupeKMbw=="], + + "sass-embedded-android-arm": ["sass-embedded-android-arm@1.93.3", "", { "os": "android", "cpu": "arm" }, "sha512-8xOw9bywfOD6Wv24BgCmgjkk6tMrsOTTHcb28KDxeJtFtoxiUyMbxo0vChpPAfp2Hyg2tFFKS60s0s4JYk+Raw=="], + + "sass-embedded-android-arm64": ["sass-embedded-android-arm64@1.93.3", "", { "os": "android", "cpu": "arm64" }, "sha512-uqUl3Kt1IqdGVAcAdbmC+NwuUJy8tM+2ZnB7/zrt6WxWVShVCRdFnWR9LT8HJr7eJN7AU8kSXxaVX/gedanPsg=="], + + "sass-embedded-android-riscv64": ["sass-embedded-android-riscv64@1.93.3", "", { "os": "android", "cpu": "none" }, "sha512-2jNJDmo+3qLocjWqYbXiBDnfgwrUeZgZFHJIwAefU7Fn66Ot7rsXl+XPwlokaCbTpj7eMFIqsRAZ/uDueXNCJg=="], + + "sass-embedded-android-x64": ["sass-embedded-android-x64@1.93.3", "", { "os": "android", "cpu": "x64" }, "sha512-y0RoAU6ZenQFcjM9PjQd3cRqRTjqwSbtWLL/p68y2oFyh0QGN0+LQ826fc0ZvU/AbqCsAizkqjzOn6cRZJxTTQ=="], + + "sass-embedded-darwin-arm64": ["sass-embedded-darwin-arm64@1.93.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-7zb/hpdMOdKteK17BOyyypemglVURd1Hdz6QGsggy60aUFfptTLQftLRg8r/xh1RbQAUKWFbYTNaM47J9yPxYg=="], + + "sass-embedded-darwin-x64": ["sass-embedded-darwin-x64@1.93.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ek1Vp8ZDQEe327Lz0b7h3hjvWH3u9XjJiQzveq74RPpJQ2q6d9LfWpjiRRohM4qK6o4XOHw1X10OMWPXJtdtWg=="], + + "sass-embedded-linux-arm": ["sass-embedded-linux-arm@1.93.3", "", { "os": "linux", "cpu": "arm" }, "sha512-yeiv2y+dp8B4wNpd3+JsHYD0mvpXSfov7IGyQ1tMIR40qv+ROkRqYiqQvAOXf76Qwh4Y9OaYZtLpnsPjfeq6mA=="], + + "sass-embedded-linux-arm64": ["sass-embedded-linux-arm64@1.93.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-RBrHWgfd8Dd8w4fbmdRVXRrhh8oBAPyeWDTKAWw8ZEmuXfVl4ytjDuyxaVilh6rR1xTRTNpbaA/YWApBlLrrNw=="], + + "sass-embedded-linux-musl-arm": ["sass-embedded-linux-musl-arm@1.93.3", "", { "os": "linux", "cpu": "arm" }, "sha512-fU0fwAwbp7sBE3h5DVU5UPzvaLg7a4yONfFWkkcCp6ZrOiPuGRHXXYriWQ0TUnWy4wE+svsVuWhwWgvlb/tkKg=="], + + "sass-embedded-linux-musl-arm64": ["sass-embedded-linux-musl-arm64@1.93.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-PS829l+eUng+9W4PFclXGb4uA2+965NHV3/Sa5U7qTywjeeUUYTZg70dJHSqvhrBEfCc2XJABeW3adLJbyQYkw=="], + + "sass-embedded-linux-musl-riscv64": ["sass-embedded-linux-musl-riscv64@1.93.3", "", { "os": "linux", "cpu": "none" }, "sha512-cK1oBY+FWQquaIGEeQ5H74KTO8cWsSWwXb/WaildOO9U6wmUypTgUYKQ0o5o/29nZbWWlM1PHuwVYTSnT23Jjg=="], + + "sass-embedded-linux-musl-x64": ["sass-embedded-linux-musl-x64@1.93.3", "", { "os": "linux", "cpu": "x64" }, "sha512-A7wkrsHu2/I4Zpa0NMuPGkWDVV7QGGytxGyUq3opSXgAexHo/vBPlGoDXoRlSdex0cV+aTMRPjoGIfdmNlHwyg=="], + + "sass-embedded-linux-riscv64": ["sass-embedded-linux-riscv64@1.93.3", "", { "os": "linux", "cpu": "none" }, "sha512-vWkW1+HTF5qcaHa6hO80gx/QfB6GGjJUP0xLbnAoY4pwEnw5ulGv6RM8qYr8IDhWfVt/KH+lhJ2ZFxnJareisQ=="], + + "sass-embedded-linux-x64": ["sass-embedded-linux-x64@1.93.3", "", { "os": "linux", "cpu": "x64" }, "sha512-k6uFxs+e5jSuk1Y0niCwuq42F9ZC5UEP7P+RIOurIm8w/5QFa0+YqeW+BPWEW5M1FqVOsNZH3qGn4ahqvAEjPA=="], + + "sass-embedded-unknown-all": ["sass-embedded-unknown-all@1.93.3", "", { "dependencies": { "sass": "1.93.3" }, "os": [ "!linux", "!win32", "!darwin", "!android", ] }, "sha512-o5wj2rLpXH0C+GJKt/VpWp6AnMsCCbfFmnMAttcrsa+U3yrs/guhZ3x55KAqqUsE8F47e3frbsDL+1OuQM5DAA=="], + + "sass-embedded-win32-arm64": ["sass-embedded-win32-arm64@1.93.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-0dOfT9moy9YmBolodwYYXtLwNr4jL4HQC9rBfv6mVrD7ud8ue2kDbn+GVzj1hEJxvEexVSmDCf7MHUTLcGs9xQ=="], + + "sass-embedded-win32-x64": ["sass-embedded-win32-x64@1.93.3", "", { "os": "win32", "cpu": "x64" }, "sha512-wHFVfxiS9hU/sNk7KReD+lJWRp3R0SLQEX4zfOnRP2zlvI2X4IQR5aZr9GNcuMP6TmNpX0nQPZTegS8+h9RrEg=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "sync-child-process": ["sync-child-process@1.0.2", "", { "dependencies": { "sync-message-port": "^1.0.0" } }, "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA=="], + + "sync-message-port": ["sync-message-port@1.1.3", "", {}, "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg=="], + + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], + + "varint": ["varint@6.0.0", "", {}, "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg=="], + + "vite": ["vite@7.1.12", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "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-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug=="], + + "vscode-uri": ["vscode-uri@3.1.0", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="], + + "vue": ["vue@3.5.22", "", { "dependencies": { "@vue/compiler-dom": "3.5.22", "@vue/compiler-sfc": "3.5.22", "@vue/runtime-dom": "3.5.22", "@vue/server-renderer": "3.5.22", "@vue/shared": "3.5.22" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ=="], + + "vue-tsc": ["vue-tsc@3.1.2", "", { "dependencies": { "@volar/typescript": "2.4.23", "@vue/language-core": "3.1.2" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-3fd4DY0rFczs5f+VB3OhcLU83V6+3Puj2yLBe0Ak65k7ERk+STVNKaOAi0EBo6Lc15UiJB6LzU6Mxy4+h/pKew=="], + + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + } +} diff --git a/examples/local-alias-plugin/page/bunfig.toml b/examples/local-alias-plugin/page/bunfig.toml new file mode 100644 index 00000000..641e878f --- /dev/null +++ b/examples/local-alias-plugin/page/bunfig.toml @@ -0,0 +1,2 @@ +[install] +linker = "isolated" diff --git a/examples/local-alias-plugin/page/index.html b/examples/local-alias-plugin/page/index.html new file mode 100644 index 00000000..1abce2df --- /dev/null +++ b/examples/local-alias-plugin/page/index.html @@ -0,0 +1,12 @@ + + + + + + Rusty Local Alias Plugin + + +
+ + + diff --git a/examples/local-alias-plugin/page/package.json b/examples/local-alias-plugin/page/package.json new file mode 100644 index 00000000..3fff6557 --- /dev/null +++ b/examples/local-alias-plugin/page/package.json @@ -0,0 +1,26 @@ +{ + "name": "page", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc -b && vite build", + "preview": "vite preview", + "lint": "biome check .", + "lint:fix": "biome write ." + }, + "dependencies": { + "vue": "^3.5.22" + }, + "devDependencies": { + "@biomejs/biome": "^2.3.2", + "@vitejs/plugin-vue": "^6.0.1", + "@vue/tsconfig": "^0.7.0", + "prettier": "^3.6.2", + "sass-embedded": "^1.93.3", + "typescript": "~5.8.3", + "vite": "^7.1.12", + "vue-tsc": "^3.1.2" + } +} diff --git a/examples/local-alias-plugin/page/src/App.vue b/examples/local-alias-plugin/page/src/App.vue new file mode 100644 index 00000000..2fd06836 --- /dev/null +++ b/examples/local-alias-plugin/page/src/App.vue @@ -0,0 +1,349 @@ + + + + + diff --git a/examples/local-alias-plugin/page/src/assets/vue.svg b/examples/local-alias-plugin/page/src/assets/vue.svg new file mode 100644 index 00000000..770e9d33 --- /dev/null +++ b/examples/local-alias-plugin/page/src/assets/vue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/local-alias-plugin/page/src/lib/bridge.ts b/examples/local-alias-plugin/page/src/lib/bridge.ts new file mode 100644 index 00000000..dd50a6cf --- /dev/null +++ b/examples/local-alias-plugin/page/src/lib/bridge.ts @@ -0,0 +1,47 @@ +type Bridge = { + send: (type: string, data: unknown) => void; + onMessage: (cb: (type: string, data: unknown) => void) => void; + _emit: (msg: { type: string; data: unknown }) => void; +}; + +const windowPatched = window as unknown as Window & { + bridge?: Bridge; + ipc: { postMessage: (msg: string) => void }; +}; + +if (!windowPatched.bridge) { + const listeners: Array<(type: string, data: unknown) => void> = []; + windowPatched.bridge = { + send: (name, data) => { + try { + windowPatched.ipc.postMessage( + JSON.stringify({ type: name, data: data }), + ); + } catch (e) { + console.error(e); + } + }, + onMessage: (cb) => { + if (typeof cb === "function") listeners.push(cb); + }, + _emit: (msg) => { + console.debug("[bridge] IPC message received", msg); + for (const cb of listeners) { + try { + cb(msg.type, msg.data); + } catch (e) { + console.error(e); + } + } + }, + }; + console.debug("[bridge] IPC bridge initialized"); +} + +export function getBridge(): Bridge { + const b = windowPatched.bridge; + if (!b) { + throw new Error("IPC bridge (window.bridge) not ready"); + } + return b; +} diff --git a/examples/local-alias-plugin/page/src/lib/ipc.ts b/examples/local-alias-plugin/page/src/lib/ipc.ts new file mode 100644 index 00000000..acb8a646 --- /dev/null +++ b/examples/local-alias-plugin/page/src/lib/ipc.ts @@ -0,0 +1,74 @@ +import { getBridge } from "./bridge.ts"; + +export type AliasEntry = { name: string; alias: string }; + +const bridge = getBridge(); + +const onceWaiters = new Map void>>(); +const subscribers = new Map void>>(); + +bridge.onMessage((type, data) => { + const onceList = onceWaiters.get(type); + if (onceList && onceList.length) { + const callbacks = onceList.splice(0, onceList.length); + onceWaiters.delete(type); + for (const cb of callbacks) { + try { + cb(data); + } catch (e) { + console.error(e); + } + } + } + + const subs = subscribers.get(type); + if (subs && subs.length) { + for (const cb of subs) { + try { + cb(data); + } catch (e) { + console.error(e); + } + } + } +}); + +function waitFor(type: string): Promise { + return new Promise((resolve) => { + const list = onceWaiters.get(type) ?? []; + list.push((data) => resolve(data as T)); + onceWaiters.set(type, list); + }); +} + +export const ipc = { + async getVersion(): Promise { + bridge.send("get_version", undefined); + const res = await waitFor<{ version: string }>("version_response"); + return res.version ?? ""; + }, + + async getAliases(): Promise { + bridge.send("get_aliases", undefined); + const res = await waitFor("aliases_response"); + return Array.isArray(res) ? res : []; + }, + + setAliases(aliases: AliasEntry[]): void { + bridge.send("set_aliases", aliases); + }, + + addAlias(): void { + bridge.send("add_alias", undefined); + }, + + setCurrentAlias(alias: AliasEntry): void { + bridge.send("set_current_alias", alias); + }, + + on(type: string, cb: (data: unknown) => void): void { + const list = subscribers.get(type) ?? []; + list.push(cb); + subscribers.set(type, list); + }, +}; diff --git a/examples/local-alias-plugin/page/src/lib/store.ts b/examples/local-alias-plugin/page/src/lib/store.ts new file mode 100644 index 00000000..e81832f0 --- /dev/null +++ b/examples/local-alias-plugin/page/src/lib/store.ts @@ -0,0 +1,51 @@ +import { reactive, readonly } from "vue"; +import { ipc, type AliasEntry } from "./ipc.ts"; + +export type State = { + aliases: AliasEntry[]; + selectedIndex: number | null; +}; + +const state = reactive({ + aliases: [], + selectedIndex: null, +}); + +function setAliases(aliases: AliasEntry[]) { + state.aliases = Array.isArray(aliases) ? aliases : []; + // 長さ変化による選択インデックスのはみ出しを補正 + if (state.selectedIndex != null) { + if (state.selectedIndex < 0 || state.selectedIndex >= state.aliases.length) { + state.selectedIndex = null; + } + } +} + +function setSelectedIndex(index: number | null) { + state.selectedIndex = index; + ipc.setCurrentAlias(state.aliases[index ?? -1] ?? null); +} + +// Rust 側からの push 通知を受け取る +ipc.on("update_aliases", (data) => { + try { + setAliases((data as AliasEntry[]) ?? []); + } catch (e) { + console.error(e); + } +}); + +// 初期化時、必要なら取得(開発時など) +ipc + .getAliases() + .then((aliases) => setAliases(aliases)) + .catch(() => void 0); + +export function useGlobalStore() { + return { + state: readonly(state), + setAliases, + saveAliases: (aliases: AliasEntry[]) => ipc.setAliases(aliases), + setSelectedIndex, + }; +} diff --git a/examples/local-alias-plugin/page/src/main.ts b/examples/local-alias-plugin/page/src/main.ts new file mode 100644 index 00000000..86ec3ebb --- /dev/null +++ b/examples/local-alias-plugin/page/src/main.ts @@ -0,0 +1,5 @@ +import { createApp } from "vue"; +import "./style.scss"; +import App from "./App.vue"; + +createApp(App).mount("#app"); diff --git a/examples/local-alias-plugin/page/src/style.scss b/examples/local-alias-plugin/page/src/style.scss new file mode 100644 index 00000000..cca57b36 --- /dev/null +++ b/examples/local-alias-plugin/page/src/style.scss @@ -0,0 +1,5 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} diff --git a/examples/local-alias-plugin/page/src/vite-env.d.ts b/examples/local-alias-plugin/page/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/examples/local-alias-plugin/page/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/local-alias-plugin/page/tsconfig.app.json b/examples/local-alias-plugin/page/tsconfig.app.json new file mode 100644 index 00000000..3dbbc453 --- /dev/null +++ b/examples/local-alias-plugin/page/tsconfig.app.json @@ -0,0 +1,15 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/examples/local-alias-plugin/page/tsconfig.json b/examples/local-alias-plugin/page/tsconfig.json new file mode 100644 index 00000000..1ffef600 --- /dev/null +++ b/examples/local-alias-plugin/page/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/examples/local-alias-plugin/page/tsconfig.node.json b/examples/local-alias-plugin/page/tsconfig.node.json new file mode 100644 index 00000000..f85a3990 --- /dev/null +++ b/examples/local-alias-plugin/page/tsconfig.node.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/examples/local-alias-plugin/page/vite.config.ts b/examples/local-alias-plugin/page/vite.config.ts new file mode 100644 index 00000000..e3d98906 --- /dev/null +++ b/examples/local-alias-plugin/page/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [vue()], +}); diff --git a/examples/local-alias-plugin/src/entry.rs b/examples/local-alias-plugin/src/entry.rs new file mode 100644 index 00000000..f279d72c --- /dev/null +++ b/examples/local-alias-plugin/src/entry.rs @@ -0,0 +1,45 @@ +use aviutl2::{filter::FilterConfigItems, generic::GenericPlugin}; + +use crate::LocalAliasPlugin; + +#[aviutl2::plugin(FilterPlugin)] +pub struct DummyObject {} + +#[derive(aviutl2::filter::FilterConfigItems)] +struct DummyConfig { + #[track( + name = "Marker", + default = 0, + range = 0..=1, + step = 1.0, + )] + _marker: u32, +} + +impl aviutl2::filter::FilterPlugin for DummyObject { + fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult { + Ok(DummyObject {}) + } + + fn plugin_info(&self) -> aviutl2::filter::FilterPluginTable { + aviutl2::filter::FilterPluginTable { + name: "Rusty Local Alias".to_string(), + label: None, + information: "A dummy filter plugin that does nothing.".to_string(), + filter_type: aviutl2::filter::FilterType::Video, + as_object: true, + config_items: DummyConfig::to_config_items(), + } + } + + fn proc_video( + &self, + _config: &[aviutl2::filter::FilterConfigItem], + _video: &mut aviutl2::filter::FilterProcVideo, + ) -> anyhow::Result<()> { + LocalAliasPlugin::with_instance(|plugin| { + let _ = plugin.replace_flag.send(()); + }); + Ok(()) + } +} diff --git a/examples/local-alias-plugin/src/lib.rs b/examples/local-alias-plugin/src/lib.rs new file mode 100644 index 00000000..af57ce8d --- /dev/null +++ b/examples/local-alias-plugin/src/lib.rs @@ -0,0 +1,307 @@ +mod entry; +mod ws_popup; + +use crate::entry::DummyObject; +use aviutl2::{ + AnyResult, + generic::{GenericPlugin, SubPlugin}, + ldbg, +}; +use std::sync::{Arc, Mutex, OnceLock}; +use tap::Pipe; +use ws_popup::WsPopup; + +#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] +pub struct AliasEntry { + name: String, + alias: String, +} + +#[aviutl2::plugin(GenericPlugin)] +pub struct LocalAliasPlugin { + webview: wry::WebView, + window: WsPopup, + + dummy: SubPlugin, + + edit_handle: Arc>, + _replace_thread: std::thread::JoinHandle<()>, + replace_flag: std::sync::mpsc::Sender<()>, + + aliases: Vec, +} +unsafe impl Send for LocalAliasPlugin {} +unsafe impl Sync for LocalAliasPlugin {} + +static WEB_CONTENT: include_dir::Dir = include_dir::include_dir!("$CARGO_MANIFEST_DIR/page/dist"); + +pub static CURRENT_ALIAS: Mutex> = Mutex::new(None); + +impl aviutl2::generic::GenericPlugin for LocalAliasPlugin { + fn new(info: aviutl2::AviUtl2Info) -> AnyResult { + Self::init_logging(); + log::info!("Initializing Rusty Local Alias Plugin..."); + let edit_handle = Arc::new(OnceLock::::new()); + + let window = WsPopup::new("Rusty Local Alias Plugin", (800, 600))?; + let cache_dir = dirs::cache_dir() + .unwrap_or_else(std::env::temp_dir) + .join("rusty-local-alias-plugin"); + let mut web_context = wry::WebContext::new(Some(cache_dir)); + let webview = wry::WebViewBuilder::new_with_web_context(&mut web_context) + // JS -> Rust 受信 + .with_ipc_handler(|payload| { + let message_str = payload.into_body(); + LocalAliasPlugin::ipc_handler(message_str); + }) + .pipe(|builder| { + if cfg!(debug_assertions) { + log::info!("Running in development mode, loading from localhost:5173"); + builder.with_url("http://localhost:5173") + } else { + log::info!("Running in production mode, loading from embedded assets"); + builder + .with_custom_protocol("app".to_string(), move |_id, request| { + let path = request.uri().path().trim_start_matches('/'); + ldbg!(path); + if let Some(file) = WEB_CONTENT.get_file(path) { + let mime = mime_guess::from_path(path).first_or_octet_stream(); + wry::http::Response::builder() + .header("Content-Type", mime.as_ref()) + .body(file.contents().to_vec().into()) + .unwrap() + } else { + wry::http::Response::builder() + .status(404) + .body(Vec::new().into()) + .unwrap() + } + }) + .with_url("app://index.html") + } + }) + .build(&window)?; + + let (replace_flag_tx, replace_flag_rx) = std::sync::mpsc::channel(); + let replace_thread = Self::spawn_replace_thread(Arc::clone(&edit_handle), replace_flag_rx); + + Ok(LocalAliasPlugin { + webview, + window, + edit_handle, + + dummy: SubPlugin::new_filter_plugin(info)?, + + _replace_thread: replace_thread, + replace_flag: replace_flag_tx, + + aliases: Vec::new(), + }) + } + + fn register(&mut self, registry: &mut aviutl2::generic::HostAppHandle) { + registry.set_plugin_information(&format!( + "Project Local Alias for AviUtl2, written in Rust / v{version} / https://github.com/sevenc-nanashi/aviutl2-rs/tree/main/examples/local-alias-plugin", + version = env!("CARGO_PKG_VERSION") + )); + let handle = registry.create_edit_handle(); + let _ = self.edit_handle.set(handle); + registry + .register_window_client("Rusty Local Alias Plugin", &self.window) + .unwrap(); + registry.register_filter_plugin(&self.dummy); + } + + fn on_project_load(&mut self, project: &mut aviutl2::generic::ProjectFile) { + self.aliases = project.deserialize("alias_entries").unwrap_or_else(|e| { + log::warn!("Failed to load alias entries from project: {}", e); + Vec::new() + }); + self.send_to_webview("update_aliases", &self.aliases); + } + + fn on_project_save(&mut self, project: &mut aviutl2::generic::ProjectFile) { + let _ = project.serialize("alias_entries", &self.aliases); + } +} + +impl LocalAliasPlugin { + fn init_logging() { + aviutl2::logger::LogBuilder::new() + .filter_level(if cfg!(debug_assertions) { + log::LevelFilter::Debug + } else { + log::LevelFilter::Info + }) + .init(); + } + + fn spawn_replace_thread( + edit_handle: Arc>, + replace_flag_rx: std::sync::mpsc::Receiver<()>, + ) -> std::thread::JoinHandle<()> { + std::thread::spawn(move || { + loop { + // Wait for a replace signal + if replace_flag_rx.recv().is_err() { + break; + } + + let current_alias = CURRENT_ALIAS.lock().unwrap().clone(); + if let Some(alias) = current_alias { + let _ = edit_handle.wait().call_edit_section(move |section| { + for layer in section.layers() { + for (_, obj) in layer.objects() { + let obj = section.object(&obj); + let res = obj.get_effect_item( + if cfg!(debug_assertions) { + "Rusty Local Alias (Debug)" + } else { + "Rusty Local Alias" + }, + 0, + "Marker", + ); + if res.is_ok() { + let position = obj.get_layer_frame()?; + obj.delete_object()?; + + section.create_object_from_alias( + &alias.alias, + position.layer, + position.start, + position.end - position.start + 1, + )?; + } + } + } + + anyhow::Ok(()) + }); + } + } + }) + } + + fn send_to_webview(&self, name: &str, data: &T) { + log::debug!("Sending to webview: {}", name); + match serde_json::to_value(data) { + Ok(json) => { + let json = serde_json::json!({ "type": name, "data": json }).to_string(); + let script = format!( + "try {{ window.bridge && window.bridge._emit({json}); }} catch(e) {{ console.error(e); }}" + ); + let _ = self.webview.evaluate_script(&script); + log::debug!("Sent to webview: {}", name); + } + Err(e) => { + log::error!("Failed to serialize data for webview: {}", e); + } + } + } + + fn ipc_handler(message_str: String) { + #[derive(serde::Deserialize, Debug)] + #[serde(tag = "type", content = "data", rename_all = "snake_case")] + enum IpcMessage { + GetVersion, + GetAliases, + SetAliases(Vec), + AddAlias, + SetCurrentAlias(AliasEntry), + } + + match serde_json::from_str::(&message_str) { + Ok(msg) => { + log::debug!("IPC message received: {:?}", msg); + match msg { + IpcMessage::GetVersion => { + let version = env!("CARGO_PKG_VERSION"); + let response = serde_json::json!({ "version": version }); + LocalAliasPlugin::with_instance(|instance| { + instance.send_to_webview("version_response", &response); + }); + } + IpcMessage::GetAliases => { + LocalAliasPlugin::with_instance(|instance| { + let aliases = instance.aliases.clone(); + instance.send_to_webview("aliases_response", &aliases); + }); + } + IpcMessage::SetAliases(new_aliases) => { + LocalAliasPlugin::with_instance_mut(|instance| { + instance.aliases = new_aliases; + instance.send_to_webview("update_aliases", &instance.aliases); + }); + } + IpcMessage::AddAlias => { + let new_alias = LocalAliasPlugin::with_instance(|instance| { + let handle = instance.edit_handle.get().unwrap(); + handle + .call_edit_section(|section| { + let alias = section + .get_focused_object()? + .map(|obj| section.get_object_alias(&obj)) + .transpose()?; + let entry = alias.map(|alias| AliasEntry { + name: "New Alias".to_string(), + alias, + }); + anyhow::Ok(entry) + }) + .map_err(anyhow::Error::from) + }) + .flatten(); + match new_alias { + Ok(Some(entry)) => { + LocalAliasPlugin::with_instance_mut(|instance| { + instance.aliases.push(entry.clone()); + instance.send_to_webview("update_aliases", &instance.aliases); + }); + } + Ok(None) => { + log::warn!("No focused object to create alias from in add_alias"); + } + Err(e) => { + log::error!("Failed to add alias: {}", e); + } + } + } + IpcMessage::SetCurrentAlias(entry) => { + let mut current = CURRENT_ALIAS.lock().unwrap(); + *current = Some(entry); + } + } + } + Err(error) => { + if let Ok(value) = serde_json::from_str::(&message_str) { + if let Some(ty) = value.get("type").and_then(|v| v.as_str()) { + match ty { + "set_aliases" => { + log::error!( + "Failed to parse aliases from IPC message data: {:?}", + value.get("data") + ); + } + "set_current_alias" => { + log::error!( + "Failed to parse current alias from IPC message data: {:?}", + value.get("data") + ); + } + other => { + log::warn!("Unknown IPC message type: {}", other); + } + } + } else { + log::error!("Failed to parse IPC message: {}", error); + } + } else { + log::error!("Failed to parse IPC message: {}", error); + } + } + } + } +} + +aviutl2::register_generic_plugin!(LocalAliasPlugin); diff --git a/examples/local-alias-plugin/src/ws_popup.rs b/examples/local-alias-plugin/src/ws_popup.rs new file mode 100644 index 00000000..03a156dc --- /dev/null +++ b/examples/local-alias-plugin/src/ws_popup.rs @@ -0,0 +1,95 @@ +use aviutl2::AnyResult; +use std::{ffi::OsStr, iter, os::windows::ffi::OsStrExt, sync::Once}; +use windows::{ + Win32::{ + Foundation::{HINSTANCE, HWND, LPARAM, LRESULT, WPARAM}, + System::LibraryLoader::GetModuleHandleW, + UI::WindowsAndMessaging::{ + CS_HREDRAW, CS_VREDRAW, CW_USEDEFAULT, CreateWindowExW, DefWindowProcW, DestroyWindow, + RegisterClassW, WNDCLASSW, WS_CLIPCHILDREN, WS_CLIPSIBLINGS, WS_EX_TOOLWINDOW, + WS_POPUP, + }, + }, + core::PCWSTR, +}; + +const CLASS_NAME: &str = "WsPopupWindow"; +static REGISTER_ONCE: Once = Once::new(); + +pub struct WsPopup { + hwnd: HWND, +} + +impl WsPopup { + pub fn new(title: &str, size: (i32, i32)) -> AnyResult { + register_class(); + + let hmodule = unsafe { GetModuleHandleW(None).map_err(|e| anyhow::anyhow!("{e}"))? }; + let hinstance = HINSTANCE(hmodule.0); + let title_w = to_wide(title); + let class_w = to_wide(CLASS_NAME); + + let hwnd = unsafe { + CreateWindowExW( + WS_EX_TOOLWINDOW, + PCWSTR(class_w.as_ptr()), + PCWSTR(title_w.as_ptr()), + WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + CW_USEDEFAULT, + CW_USEDEFAULT, + size.0, + size.1, + None, + None, + hinstance, + None, + ) + }?; + + Ok(Self { hwnd }) + } +} + +impl Drop for WsPopup { + fn drop(&mut self) { + unsafe { + let _ = DestroyWindow(self.hwnd); + } + } +} + +impl raw_window_handle::HasWindowHandle for WsPopup { + fn window_handle( + &self, + ) -> Result, raw_window_handle::HandleError> { + let raw = + raw_window_handle::RawWindowHandle::Win32(raw_window_handle::Win32WindowHandle::new( + std::num::NonZero::::new(self.hwnd.0 as isize) + .ok_or(raw_window_handle::HandleError::Unavailable)?, + )); + Ok(unsafe { raw_window_handle::WindowHandle::borrow_raw(raw) }) + } +} + +fn register_class() { + REGISTER_ONCE.call_once(|| unsafe { + let class_w = to_wide(CLASS_NAME); + let hmodule = GetModuleHandleW(None).unwrap(); + let wc = WNDCLASSW { + style: CS_HREDRAW | CS_VREDRAW, + lpfnWndProc: Some(wnd_proc), + hInstance: HINSTANCE(hmodule.0), + lpszClassName: PCWSTR(class_w.as_ptr()), + ..Default::default() + }; + let _ = RegisterClassW(&wc); + }); +} + +extern "system" fn wnd_proc(hwnd: HWND, msg: u32, w: WPARAM, l: LPARAM) -> LRESULT { + unsafe { DefWindowProcW(hwnd, msg, w, l) } +} + +fn to_wide(s: &str) -> Vec { + OsStr::new(s).encode_wide().chain(iter::once(0)).collect() +} diff --git a/examples/midi-player-input/src/lib.rs b/examples/midi-player-input/src/lib.rs index b1a5bb57..b2b71d28 100644 --- a/examples/midi-player-input/src/lib.rs +++ b/examples/midi-player-input/src/lib.rs @@ -54,7 +54,7 @@ impl InputPlugin for MidiPlayerPlugin { "MIDI Files" => ["mid"] }, information: format!( - "Midi Piano Player for AviUtl, written in Rust / v{version} / https://github.com/sevenc-nanashi/aviutl2-rs/tree/main/examples/midi-player-input", + "Midi Piano Player for AviUtl2, written in Rust / v{version} / https://github.com/sevenc-nanashi/aviutl2-rs/tree/main/examples/midi-player-input", version = env!("CARGO_PKG_VERSION") ), concurrent: false, diff --git a/examples/srt-file-plugin/Cargo.toml b/examples/srt-file-plugin/Cargo.toml new file mode 100644 index 00000000..f3433e89 --- /dev/null +++ b/examples/srt-file-plugin/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "example-srt-file-plugin" +version.workspace = true +edition.workspace = true +license.workspace = true +authors.workspace = true +repository.workspace = true +publish = false + +[lib] +name = "rusty_srt_file_plugin" +crate-type = ["cdylib"] + +[dependencies] +anyhow = "1.0.98" +aviutl2.workspace = true +easy-ext = "1.0.2" +native-dialog = "0.9.2" +srtlib = "0.2.0" diff --git a/examples/srt-file-plugin/README.md b/examples/srt-file-plugin/README.md new file mode 100644 index 00000000..0bcc7ebe --- /dev/null +++ b/examples/srt-file-plugin/README.md @@ -0,0 +1,8 @@ +# Rusty SRT File Plugin + +汎用プラグインのサンプルです。 +SRTファイルのインポート/エクスポートを行います。 + +## インストール + +`C:\ProgramData\aviutl2\Script` に `rusty_srt_file.aux2` を配置してください。 diff --git a/examples/srt-file-plugin/src/lib.rs b/examples/srt-file-plugin/src/lib.rs new file mode 100644 index 00000000..8f942e9e --- /dev/null +++ b/examples/srt-file-plugin/src/lib.rs @@ -0,0 +1,173 @@ +use aviutl2::{AnyResult, lprintln}; + +#[easy_ext::ext] +impl srtlib::Timestamp { + fn to_milliseconds(&self) -> u32 { + let (h, m, s, ms) = self.get(); + srtlib::Timestamp::convert_to_milliseconds(h, m, s, ms) + } +} + +#[aviutl2::plugin(GenericPlugin)] +struct SrtImportPlugin {} + +impl aviutl2::generic::GenericPlugin for SrtImportPlugin { + fn new(_info: aviutl2::AviUtl2Info) -> AnyResult { + Ok(SrtImportPlugin {}) + } + + fn register(&mut self, registry: &mut aviutl2::generic::HostAppHandle) { + registry.register_menus::(); + } +} + +#[aviutl2::generic::menus] +impl SrtImportPlugin { + #[import(name = "SRTファイル(*.srt)")] + fn import_menu(&mut self, edit_section: &mut aviutl2::generic::EditSection) -> AnyResult<()> { + let current_object = edit_section.get_focused_object()?; + let Some(obj) = current_object else { + anyhow::bail!("オブジェクトが選択されていません。"); + }; + let obj = edit_section.object(&obj); + if obj.get_effect_item("テキスト", 0, "テキスト").is_err() { + anyhow::bail!("選択されたオブジェクトはテキストオブジェクトではありません。"); + } + + let file_path = native_dialog::FileDialogBuilder::default() + .add_filter("SRTファイル", ["srt"]) + .set_title("SRTファイルを選択") + .open_single_file() + .show()?; + let Some(file_path) = file_path else { + return Ok(()); + }; + + let srt = srtlib::Subtitles::parse_from_file(&file_path, None) + .map_err(|e| anyhow::anyhow!("SRTファイルの解析に失敗しました: {}", e))?; + + let aviutl2::generic::ObjectLayerFrame { + layer, + start: existing_start_frame, + end: existing_end_frame, + } = obj.get_layer_frame()?; + let layer = edit_section.layer(layer); + let fps = edit_section.info.fps; + let fps = *fps.numer() as f64 / *fps.denom() as f64; + + let mut subtitles = srt.to_vec(); + subtitles.sort_by_key(|s| (s.start_time, s.end_time)); + let Some(last_subtitle) = subtitles.last() else { + anyhow::bail!("SRTファイルに字幕が含まれていません。"); + }; + let last_subtitle_ms = last_subtitle.end_time.to_milliseconds(); + let total_frames = (last_subtitle_ms as f64 / 1000.0 * fps).ceil() as u32; + let next_object = layer.find_object_after(existing_end_frame + 1)?; + let existing_next_frame = if let Some(next_object) = next_object.as_ref() { + let next_obj = edit_section.object(next_object); + let next_layer_frame = next_obj.get_layer_frame()?; + next_layer_frame.start + } else { + usize::MAX + }; + if existing_start_frame + total_frames as usize > existing_next_frame { + edit_section.focus_object(obj.handle)?; + anyhow::bail!("字幕を追加すると既存のオブジェクトと重なってしまいます。"); + } + + let alias = obj.get_alias()?; + let mut alias = alias.lines().collect::>(); + if alias.len() < 2 || !alias.remove(1).starts_with("frame=") { + anyhow::bail!("オブジェクトの編集に失敗しました。"); + } + let alias = alias.join("\n"); + obj.delete_object()?; + let mut next_frame = existing_start_frame; + for subtitle in subtitles { + let start_ms = subtitle.start_time.to_milliseconds(); + let end_ms = subtitle.end_time.to_milliseconds(); + let mut start_frame = + existing_start_frame + (start_ms as f64 / 1000.0 * fps).round() as usize; + let end_frame = existing_start_frame + (end_ms as f64 / 1000.0 * fps).round() as usize; + if start_frame >= end_frame { + continue; + } + if start_frame < next_frame { + start_frame = next_frame; + } + lprintln!( + "Adding subtitle: {} --> {} (frames {} to {})", + subtitle.start_time, + subtitle.end_time, + start_frame, + end_frame + ); + let new_obj = edit_section.create_object_from_alias( + &alias, + layer.index, + start_frame, + end_frame - start_frame + 1, + )?; + let new_obj = edit_section.object(&new_obj); + new_obj.set_effect_item("テキスト", 0, "テキスト", &subtitle.text)?; + next_frame = end_frame + 1; + } + + Ok(()) + } + + #[export(name = "SRTファイル(*.srt)")] + fn export_menu(edit_section: &mut aviutl2::generic::EditSection) -> AnyResult<()> { + let focused_object = edit_section.get_focused_object()?; + let Some(obj) = focused_object else { + anyhow::bail!("オブジェクトが選択されていません。"); + }; + let layer = edit_section.object(&obj).get_layer_frame()?.layer; + let layer = edit_section.layer(layer); + let fps = edit_section.info.fps; + let fps = *fps.numer() as f64 / *fps.denom() as f64; + let objects = layer.objects(); + let mut subtitles = Vec::new(); + let mut num = 0; + for (layer_frame, object) in objects { + let obj = edit_section.object(&object); + let start_frame = layer_frame.start; + let end_frame = layer_frame.end; + let start_ms = ((start_frame as f64) / fps * 1000.0).round() as u32; + let end_ms = ((end_frame as f64) / fps * 1000.0).round() as u32; + let Some(text) = obj.get_effect_item("テキスト", 0, "テキスト").ok() else { + continue; + }; + num += 1; + subtitles.push(srtlib::Subtitle { + num, + start_time: srtlib::Timestamp::from_milliseconds(start_ms), + end_time: srtlib::Timestamp::from_milliseconds(end_ms), + text, + }); + } + + let save_path = native_dialog::FileDialogBuilder::default() + .add_filter("SRTファイル", ["srt"]) + .set_title("SRTファイルを保存") + .set_filename("subtitles.srt") + .save_single_file() + .show()?; + let Some(save_path) = save_path else { + return Ok(()); + }; + let srt = srtlib::Subtitles::new_from_vec(subtitles); + srt.write_to_file(&save_path, None)?; + + native_dialog::MessageDialogBuilder::default() + .set_level(native_dialog::MessageLevel::Info) + .set_title("SRTファイルの書き出し完了") + .set_text("SRTファイルの書き出しが完了しました。") + .alert() + .show()?; + + Ok(()) + } +} + +aviutl2::register_generic_plugin!(SrtImportPlugin); diff --git a/examples/statistics-output/src/lib.rs b/examples/statistics-output/src/lib.rs index 5d2a2aaa..40632fd0 100644 --- a/examples/statistics-output/src/lib.rs +++ b/examples/statistics-output/src/lib.rs @@ -28,7 +28,7 @@ impl OutputPlugin for StatisticsPlugin { aviutl2::output::OutputPluginTable { name: "Rusty Statistics Output".to_string(), information: format!( - "Statistics Output for AviUtl, written in Rust / v{version} / https://github.com/sevenc-nanashi/aviutl2-rs/tree/main/examples/statistics-output", + "Statistics Output for AviUtl2, written in Rust / v{version} / https://github.com/sevenc-nanashi/aviutl2-rs/tree/main/examples/statistics-output", version = env!("CARGO_PKG_VERSION") ), output_type: aviutl2::output::OutputType::Video, diff --git a/examples/username-module/src/lib.rs b/examples/username-module/src/lib.rs index 808dcd77..443c0326 100644 --- a/examples/username-module/src/lib.rs +++ b/examples/username-module/src/lib.rs @@ -11,7 +11,7 @@ impl aviutl2::module::ScriptModule for UsernameModule { fn plugin_info(&self) -> aviutl2::module::ScriptModuleTable { aviutl2::module::ScriptModuleTable { information: format!( - "User name query for AviUtl, written in Rust / v{version} / https://github.com/sevenc-nanashi/aviutl2-rs/tree/main/examples/username-module", + "User name query for AviUtl2, written in Rust / v{version} / https://github.com/sevenc-nanashi/aviutl2-rs/tree/main/examples/username-module", version = env!("CARGO_PKG_VERSION") ), functions: Self::functions(), diff --git a/sdk b/sdk index 7fd59af9..5b029dfe 160000 --- a/sdk +++ b/sdk @@ -1 +1 @@ -Subproject commit 7fd59af9fba517faec66e2014eb976d7b0c92c7b +Subproject commit 5b029dfeda705224fa1f6926fdf3fabb639cc454