snapshot of https://github.com/tauri-apps/tauri.git (dev, 2026-09-23; blobs > 131072B omitted)
Some checks failed
Audit / audit-js (push) Failing after 0s
bench / bench (map[os:ubuntu-latest runner:xvfb-run --auto-servernum target:x86_64-unknown-linux-gnu], nightly) (push) Failing after 0s
covector version or publish / run-integration-tests (ubuntu-latest) (push) Failing after 0s
Audit / audit-rust (push) Failing after 0s
test `@tauri-apps/cli` / test (ubuntu-latest) (push) Failing after 0s
test `tauri-cli` / test (map[os:ubuntu-latest target:x86_64-unknown-linux-gnu]) (push) Failing after 0s
test core / test (map[args:--all-features key:all], map[cargo:cargo command:test os:ubuntu-latest target:x86_64-unknown-linux-gnu toolchain:1.90]) (push) Failing after 0s
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:test os:ubuntu-latest target:x86_64-unknown-linux-gnu toolchain:1.90]) (push) Failing after 0s
test core / test (map[args:--no-default-features key:no-default], map[cargo:cross command:build os:ubuntu-latest target:aarch64-linux-android toolchain:1.90]) (push) Failing after 0s
deploy schema worker / deploy (push) Failing after 0s
lint rust / clippy (map[cargo:cargo include: os:ubuntu-latest target:x86_64-unknown-linux-gnu]) (push) Failing after 0s
lint rust / clippy (map[cargo:cross include:--package api os:ubuntu-latest target:aarch64-linux-android]) (push) Failing after 0s
supply chain health status / check rust dependencies with cargo vet (push) Failing after 0s
test `@tauri-apps/api` e2e (mobile) / android (push) Failing after 0s
test `@tauri-apps/api` e2e / test (map[name:Linux os:ubuntu-latest]) (push) Failing after 0s
test core / test (map[args:--all-features key:all], map[cargo:cross command:build os:ubuntu-latest target:aarch64-linux-android toolchain:1.90]) (push) Failing after 0s
Udeps / changes (push) Failing after 0s
Udeps / setup (push) Has been skipped
Udeps / udeps (push) Has been skipped
bench / bench (map[os:macos-latest runner: target:aarch64-apple-darwin], nightly) (push) Has been cancelled
bench / bench (map[os:windows-latest runner: target:x86_64-pc-windows-msvc], nightly) (push) Has been cancelled
covector version or publish / run-integration-tests (macos-latest) (push) Has been cancelled
covector version or publish / run-integration-tests (windows-latest) (push) Has been cancelled
covector version or publish / version-or-publish (push) Has been cancelled
test `@tauri-apps/cli` / test (macos-latest) (push) Has been cancelled
test `tauri-cli` / test (map[args:--no-default-features --features native-tls-vendored os:windows-latest restore-only:true target:aarch64-pc-windows-msvc]) (push) Has been cancelled
test `tauri-cli` / test (map[os:macos-latest target:x86_64-apple-darwin]) (push) Has been cancelled
test `tauri-cli` / test (map[os:windows-latest target:x86_64-pc-windows-msvc]) (push) Has been cancelled
test core / test (map[args:--all-features key:all], map[cargo:cargo command:build os:macos-latest target:aarch64-apple-ios toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--all-features key:all], map[cargo:cargo command:test os:macos-14 target:aarch64-apple-darwin toolchain:1.90]) (push) Has been cancelled
lint rust / clippy (map[cargo:cargo include: os:macos-latest target:aarch64-apple-darwin]) (push) Has been cancelled
lint rust / clippy (map[cargo:cargo include: os:windows-latest target:x86_64-pc-windows-msvc]) (push) Has been cancelled
lint rust / clippy (map[cargo:cargo include:--package api os:macos-latest target:aarch64-apple-ios]) (push) Has been cancelled
test `@tauri-apps/api` e2e (mobile) / ios (push) Has been cancelled
test `@tauri-apps/api` e2e / test (map[name:Windows os:windows-latest]) (push) Has been cancelled
test `@tauri-apps/api` e2e / test (map[name:macOS os:macos-latest]) (push) Has been cancelled
test `@tauri-apps/cli` / test (windows-latest) (push) Has been cancelled
test core / test (map[args:--all-features key:all], map[cargo:cargo command:test os:windows-latest target:x86_64-pc-windows-msvc toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:build os:macos-latest target:aarch64-apple-ios toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:test os:macos-14 target:aarch64-apple-darwin toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:test os:windows-latest target:x86_64-pc-windows-msvc toolchain:1.90]) (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-23 17:00:42 +05:00
commit feda81bf2f
1178 changed files with 156404 additions and 0 deletions

View File

@@ -0,0 +1,864 @@
# Changelog
## \[2.6.3]
### Dependencies
- Upgraded to `tauri-utils@2.9.3`
- Upgraded to `tauri-codegen@2.6.3`
## \[2.6.2]
### Dependencies
- Upgraded to `tauri-utils@2.9.2`
- Upgraded to `tauri-codegen@2.6.2`
## \[2.6.1]
### Dependencies
- Upgraded to `tauri-utils@2.9.1`
- Upgraded to `tauri-codegen@2.6.1`
## \[2.6.0]
### New Features
- [`c00a3dbff`](https://www.github.com/tauri-apps/tauri/commit/c00a3dbffccd6e051d3b7332f706b6c63759865d) ([#14473](https://www.github.com/tauri-apps/tauri/pull/14473)) Add support for the `rename` attribute in the `tauri::command` macro to allow renaming the command to something other than the function name.
### Dependencies
- Upgraded to `tauri-utils@2.9.0`
- Upgraded to `tauri-codegen@2.6.0`
## \[2.5.5]
### Dependencies
- Upgraded to `tauri-utils@2.8.3`
- Upgraded to `tauri-codegen@2.5.5`
## \[2.5.4]
### Dependencies
- Upgraded to `tauri-codegen@2.5.4`
## \[2.5.3]
### Dependencies
- Upgraded to `tauri-utils@2.8.2`
- Upgraded to `tauri-codegen@2.5.3`
## \[2.5.2]
### Dependencies
- Upgraded to `tauri-utils@2.8.1`
- Upgraded to `tauri-codegen@2.5.2`
## \[2.5.1]
### Bug Fixes
- [`4b00130b8`](https://www.github.com/tauri-apps/tauri/commit/4b00130b86a27b6f121bf57897b5e92d83bcc0fc) ([#14385](https://www.github.com/tauri-apps/tauri/pull/14385) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Fix iOS deadlock when running on the simulator from Xcode by properly piping stdout/stderr messages through the Xcode console and OSLog.
### Dependencies
- Upgraded to `tauri-codegen@2.5.1`
## \[2.5.0]
### Bug Fixes
- [`69476d8e2`](https://www.github.com/tauri-apps/tauri/commit/69476d8e2314b85bf46046140bc5495fe29b7d29) ([#14170](https://www.github.com/tauri-apps/tauri/pull/14170)) Fix the stack overflow when having too many commands in a single invoke handler in release build
### Dependencies
- Upgraded to `tauri-utils@2.8.0`
- Upgraded to `tauri-codegen@2.5.0`
- [`6aa7f2d85`](https://www.github.com/tauri-apps/tauri/commit/6aa7f2d852870aeba1d4dd0e07f8be2bc9b66286) Upgraded to `tauri-utils@2.8.0`
## \[2.4.0]
### Dependencies
- Upgraded to `tauri-utils@2.7.0`.
- Upgraded to `tauri-codegen@2.4.0`
## \[2.3.2]
### Dependencies
- Upgraded to `tauri-utils@2.6.0`
- Upgraded to `tauri-codegen@2.3.1`
## \[2.3.1]
### Performance Improvements
- [`0a552a868`](https://www.github.com/tauri-apps/tauri/commit/0a552a868c559d367d85c264bf052009b048bd8e) ([#13690](https://www.github.com/tauri-apps/tauri/pull/13690) by [@montyc1999](https://www.github.com/tauri-apps/tauri/../../montyc1999)) Cache `rustc -V` output in `#[tauri::command]` macros
## \[2.2.1]
### Dependencies
- Upgraded to `tauri-codegen@2.3.0`
- Upgraded to `tauri-utils@2.5.0`
## \[2.2.0]
### Dependencies
- Upgraded to `tauri-utils@2.4.0`
- Upgraded to `tauri-codegen@2.2.0`
- [`48b12b440`](https://www.github.com/tauri-apps/tauri/commit/48b12b440478937c46fdfef9f9d95194be117020) Update to `tauri-utils@2.4.0`
## \[2.1.1]
### Dependencies
- Upgraded to `tauri-utils@2.3.1`
- Upgraded to `tauri-codegen@2.1.1`
## \[2.1.0]
### New Features
- [`013f8f652`](https://www.github.com/tauri-apps/tauri/commit/013f8f652302f2d49c5ec0a075582033d8b074fb) ([#12890](https://www.github.com/tauri-apps/tauri/pull/12890) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Added `build > removeUnusedCommands` to trigger the build scripts and macros to remove unused commands based on the capabilities you defined. Note this won't be accounting for dynamically added ACLs so make sure to check it when using this.
### Dependencies
- Upgraded to `tauri-utils@2.3.0`
- Upgraded to `tauri-codegen@2.1.0`
## \[2.0.5]
### Dependencies
- Upgraded to `tauri-utils@2.2.0`
- Upgraded to `tauri-codegen@2.0.5`
## \[2.0.4]
### Dependencies
- Upgraded to `tauri-utils@2.1.1`
- Upgraded to `tauri-codegen@2.0.4`
## \[2.0.3]
### Enhancements
- [`17c6952ae`](https://www.github.com/tauri-apps/tauri/commit/17c6952aec965fa41e6695ad68461a218afc20f1) ([#11522](https://www.github.com/tauri-apps/tauri/pull/11522) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Enhance the error message when using `async` commands with a reference.
### Dependencies
- Upgraded to `tauri-utils@2.1.0`
- Upgraded to `tauri-codegen@2.0.3`
## \[2.0.1]
### What's Changed
- [`0ab2b3306`](https://www.github.com/tauri-apps/tauri/commit/0ab2b330644b6419f6cee1d5377bfb5cdda2ccf9) ([#11205](https://www.github.com/tauri-apps/tauri/pull/11205) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.
### Dependencies
- Upgraded to `tauri-utils@2.0.1`
- Upgraded to `tauri-codegen@2.0.1`
## \[2.0.0]
### What's Changed
- [`382ed482b`](https://www.github.com/tauri-apps/tauri/commit/382ed482bd08157c39e62f9a0aaad8802f1092cb) Bump MSRV to 1.78.
- [`637285790`](https://www.github.com/tauri-apps/tauri/commit/6372857905ae9c0aedb7f482ddf6cf9f9836c9f2) Promote to v2 stable!
### Dependencies
- Upgraded to `tauri-utils@2.0.0`
- Upgraded to `tauri-codegen@2.0.0`
## \[2.0.0-rc.12]
### New Features
- [`1d8b67b29`](https://www.github.com/tauri-apps/tauri/commit/1d8b67b2970a09ec478093e127612fac823de805) ([#11162](https://www.github.com/tauri-apps/tauri/pull/11162) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Support async functions for `mobile_entry_point` macro
### Dependencies
- Upgraded to `tauri-utils@2.0.0-rc.13`
- Upgraded to `tauri-codegen@2.0.0-rc.13`
## \[2.0.0-rc.11]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-rc.12`
- Upgraded to `tauri-codegen@2.0.0-rc.12`
## \[2.0.0-rc.10]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-rc.11`
- Upgraded to `tauri-codegen@2.0.0-rc.11`
## \[2.0.0-rc.9]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-rc.10`
- Upgraded to `tauri-codegen@2.0.0-rc.10`
## \[2.0.0-rc.8]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-rc.9`
- Upgraded to `tauri-codegen@2.0.0-rc.9`
## \[2.0.0-rc.7]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-rc.8`
- Upgraded to `tauri-codegen@2.0.0-rc.8`
## \[2.0.0-rc.6]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-rc.7`
- Upgraded to `tauri-codegen@2.0.0-rc.7`
## \[2.0.0-rc.6]
### What's Changed
- [`f4d5241b3`](https://www.github.com/tauri-apps/tauri/commit/f4d5241b377d0f7a1b58100ee19f7843384634ac) ([#10731](https://www.github.com/tauri-apps/tauri/pull/10731) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Update documentation icon path.
### Dependencies
- Upgraded to `tauri-utils@2.0.0-rc.6`
- Upgraded to `tauri-codegen@2.0.0-rc.6`
## \[2.0.0-rc.5]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-rc.5`
- Upgraded to `tauri-codegen@2.0.0-rc.5`
## \[2.0.0-rc.4]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-rc.4`
- Upgraded to `tauri-codegen@2.0.0-rc.4`
## \[2.0.0-rc.3]
### Dependencies
- Upgraded to `tauri-codegen@2.0.0-rc.3`
- Upgraded to `tauri-utils@2.0.0-rc.3`
## \[2.0.0-rc.2]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-rc.2`
- Upgraded to `tauri-codegen@2.0.0-rc.2`
## \[2.0.0-rc.1]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-rc.1`
- Upgraded to `tauri-codegen@2.0.0-rc.1`
## \[2.0.0-rc.0]
### Dependencies
- Upgraded to `tauri-codegen@2.0.0-rc.0`
- Upgraded to `tauri-utils@2.0.0-rc.0`
## \[2.0.0-beta.19]
### What's Changed
- [`4c239729c`](https://www.github.com/tauri-apps/tauri/commit/4c239729c3e1b899ecbc6793c3682848e8de1729) ([#10167](https://www.github.com/tauri-apps/tauri/pull/10167) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add support for `test = true` in `generate_context!` macro to skip some code generation that could affect some tests, for now it only skips empedding a plist on macOS.
### Dependencies
- Upgraded to `tauri-codegen@2.0.0-beta.19`
- Upgraded to `tauri-utils@2.0.0-beta.19`
## \[2.0.0-beta.18]
### New Features
- [`5b769948a`](https://www.github.com/tauri-apps/tauri/commit/5b769948a81cac333f64c870a470ba6525bd5cd3) ([#9959](https://www.github.com/tauri-apps/tauri/pull/9959)) Add `include_image` macro to help embedding instances of `Image` struct at compile-time in rust to be used with window, menu or tray icons.
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.18`
- Upgraded to `tauri-codegen@2.0.0-beta.18`
## \[2.0.0-beta.17]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.17`
- Upgraded to `tauri-codegen@2.0.0-beta.17`
### Breaking Changes
- [`1df5cdeb0`](https://www.github.com/tauri-apps/tauri/commit/1df5cdeb06f5464e0eec4055e21b7b7bc8739eed)([#9858](https://www.github.com/tauri-apps/tauri/pull/9858)) Use `tauri.conf.json > identifier` to set the `PackageName` in Android and `BundleId` in iOS.
## \[2.0.0-beta.16]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.16`
- Upgraded to `tauri-codegen@2.0.0-beta.16`
## \[2.0.0-beta.15]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.15`
- Upgraded to `tauri-codegen@2.0.0-beta.15`
## \[2.0.0-beta.14]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.14`
- Upgraded to `tauri-codegen@2.0.0-beta.14`
## \[2.0.0-beta.13]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.13`
- Upgraded to `tauri-codegen@2.0.0-beta.13`
## \[2.0.0-beta.12]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.12`
- Upgraded to `tauri-codegen@2.0.0-beta.12`
## \[2.0.0-beta.11]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.11`
- Upgraded to `tauri-codegen@2.0.0-beta.11`
## \[2.0.0-beta.10]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.10`
- Upgraded to `tauri-codegen@2.0.0-beta.10`
## \[2.0.0-beta.9]
### New Features
- [`ba0206d8a`](https://www.github.com/tauri-apps/tauri/commit/ba0206d8a30a9b43ec5090dcaabd1a23baa1420c)([#9141](https://www.github.com/tauri-apps/tauri/pull/9141)) The `Context` codegen now accepts a `assets` input to define a custom `tauri::Assets` implementation.
### Dependencies
- Upgraded to `tauri-codegen@2.0.0-beta.9`
- Upgraded to `tauri-utils@2.0.0-beta.9`
## \[2.0.0-beta.8]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.8`
- Upgraded to `tauri-codegen@2.0.0-beta.8`
## \[2.0.0-beta.7]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.7`
- Upgraded to `tauri-codegen@2.0.0-beta.7`
## \[2.0.0-beta.6]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.6`
- Upgraded to `tauri-codegen@2.0.0-beta.6`
## \[2.0.0-beta.5]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.5`
- Upgraded to `tauri-codegen@2.0.0-beta.5`
## \[2.0.0-beta.4]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.4`
- Upgraded to `tauri-codegen@2.0.0-beta.4`
## \[2.0.0-beta.3]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.3`
- Upgraded to `tauri-codegen@2.0.0-beta.3`
## \[2.0.0-beta.2]
### Enhancements
- [`8d16a80d`](https://www.github.com/tauri-apps/tauri/commit/8d16a80d2fb2468667e7987d0cc99dbc7e3b9d0a)([#8802](https://www.github.com/tauri-apps/tauri/pull/8802)) The `generate_context` proc macro now accepts a `capabilities` attribute where the value is an array of file paths that can be [conditionally compiled](https://doc.rust-lang.org/reference/conditional-compilation.html). These capabilities are added to the application along the capabilities defined in the Tauri configuration file.
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.2`
- Upgraded to `tauri-codegen@2.0.0-beta.2`
## \[2.0.0-beta.1]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.1`
- Upgraded to `tauri-codegen@2.0.0-beta.1`
## \[2.0.0-beta.0]
### New Features
- [`74a2a603`](https://www.github.com/tauri-apps/tauri/commit/74a2a6036a5e57462f161d728cbd8a6f121028ca)([#8661](https://www.github.com/tauri-apps/tauri/pull/8661)) Implement access control list for IPC usage.
### Dependencies
- Upgraded to `tauri-utils@2.0.0-beta.0`
- Upgraded to `tauri-codegen@2.0.0-beta.0`
## \[2.0.0-alpha.13]
### Enhancements
- [`d621d343`](https://www.github.com/tauri-apps/tauri/commit/d621d3437ce3947175eecf345b2c6d1c4c7ce020)([#8607](https://www.github.com/tauri-apps/tauri/pull/8607)) Added tracing for window startup, plugins, `Window::eval`, events, IPC, updater and custom protocol request handlers behind the `tracing` feature flag.
### Dependencies
- Upgraded to `tauri-utils@2.0.0-alpha.13`
- Upgraded to `tauri-codegen@2.0.0-alpha.13`
## \[2.0.0-alpha.12]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-alpha.12`
- Upgraded to `tauri-codegen@2.0.0-alpha.12`
## \[2.0.0-alpha.11]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-alpha.11`
- Upgraded to `tauri-codegen@2.0.0-alpha.11`
- [`b6ed4ecb`](https://www.github.com/tauri-apps/tauri/commit/b6ed4ecb3730c346c973f1b34aa0de1b7d43ac44)([#7634](https://www.github.com/tauri-apps/tauri/pull/7634)) Update to syn v2.
## \[2.0.0-alpha.10]
### Enhancements
- [`c6c59cf2`](https://www.github.com/tauri-apps/tauri/commit/c6c59cf2373258b626b00a26f4de4331765dd487) Pull changes from Tauri 1.5 release.
### Dependencies
- Upgraded to `tauri-codegen@2.0.0-alpha.10`
- Upgraded to `tauri-utils@2.0.0-alpha.10`
## \[2.0.0-alpha.9]
### New Features
- [`880266a7`](https://www.github.com/tauri-apps/tauri/commit/880266a7f697e1fe58d685de3bb6836ce5251e92)([#8031](https://www.github.com/tauri-apps/tauri/pull/8031)) Bump the MSRV to 1.70.
### Dependencies
- Upgraded to `tauri-utils@2.0.0-alpha.9`
- Upgraded to `tauri-codegen@2.0.0-alpha.9`
### Breaking Changes
- [`ebcc21e4`](https://www.github.com/tauri-apps/tauri/commit/ebcc21e4b95f4e8c27639fb1bca545b432f52d5e)([#8057](https://www.github.com/tauri-apps/tauri/pull/8057)) Renamed the beforeDevCommand, beforeBuildCommand and beforeBundleCommand hooks environment variables from `TAURI_PLATFORM, TAURI_ARCH, TAURI_FAMILY, TAURI_PLATFORM_VERSION, TAURI_PLATFORM_TYPE and TAURI_DEBUG` to `TAURI_ENV_PLATFORM, TAURI_ENV_ARCH, TAURI_ENV_FAMILY, TAURI_ENV_PLATFORM_VERSION, TAURI_ENV_PLATFORM_TYPE and TAURI_ENV_DEBUG` to differentiate the prefix with other CLI environment variables.
## \[2.0.0-alpha.8]
### Enhancements
- [`100d9ede`](https://www.github.com/tauri-apps/tauri/commit/100d9ede35995d9db21d2087dd5606adfafb89a5)([#7802](https://www.github.com/tauri-apps/tauri/pull/7802)) Use `Target` enum from `tauri_utils::platform`.
### Dependencies
- Upgraded to `tauri-codegen@2.0.0-alpha.8`
- Upgraded to `tauri-utils@2.0.0-alpha.8`
## \[2.0.0-alpha.7]
### Dependencies
- Upgraded to `tauri-utils@2.0.0-alpha.7`
- Upgraded to `tauri-codegen@2.0.0-alpha.7`
### Breaking Changes
- [`fbeb5b91`](https://www.github.com/tauri-apps/tauri/commit/fbeb5b9185baeda19e865228179e3e44c165f1d9)([#7170](https://www.github.com/tauri-apps/tauri/pull/7170)) Moved `tauri::api::ipc` to `tauri::ipc` and refactored all types.
## \[2.0.0-alpha.6]
### Dependencies
- Updated to latest `tauri-utils`
## \[2.0.0-alpha.5]
- [`7a4b1fb9`](https://www.github.com/tauri-apps/tauri/commit/7a4b1fb96da475053c61960f362bbecf18cd00d4)([#6839](https://www.github.com/tauri-apps/tauri/pull/6839)) Added support to attibutes for each command path in the `generate_handler` macro.
- [`96639ca2`](https://www.github.com/tauri-apps/tauri/commit/96639ca239c9e4f75142fc07868ac46822111cff)([#6749](https://www.github.com/tauri-apps/tauri/pull/6749)) Moved the `shell` functionality to its own plugin in the plugins-workspace repository.
- [`3188f376`](https://www.github.com/tauri-apps/tauri/commit/3188f3764978c6d1452ee31d5a91469691e95094)([#6883](https://www.github.com/tauri-apps/tauri/pull/6883)) Bump the MSRV to 1.65.
- [`9a79dc08`](https://www.github.com/tauri-apps/tauri/commit/9a79dc085870e0c1a5df13481ff271b8c6cc3b78)([#6947](https://www.github.com/tauri-apps/tauri/pull/6947)) Removed the module command macros.
## \[2.0.0-alpha.4]
- Added `android` configuration object under `tauri > bundle`.
- Bumped due to a bump in tauri-utils.
- [db4c9dc6](https://www.github.com/tauri-apps/tauri/commit/db4c9dc655e07ee2184fe04571f500f7910890cd) feat(core): add option to configure Android's minimum SDK version ([#6651](https://www.github.com/tauri-apps/tauri/pull/6651)) on 2023-04-07
## \[2.0.0-alpha.3]
- Pull changes from Tauri 1.3 release.
- [](https://www.github.com/tauri-apps/tauri/commit/undefined) on undefined
## \[2.0.0-alpha.2]
- Resolve Android package name from single word bundle identifiers.
- [60a8b07d](https://www.github.com/tauri-apps/tauri/commit/60a8b07dc7c56c9c45331cb57d9afb410e7eadf3) fix: handle single word bundle identifier when resolving Android domain ([#6313](https://www.github.com/tauri-apps/tauri/pull/6313)) on 2023-02-19
- Return `bool` in the invoke handler.
- [05dad087](https://www.github.com/tauri-apps/tauri/commit/05dad0876842e2a7334431247d49365cee835d3e) feat: initial work for iOS plugins ([#6205](https://www.github.com/tauri-apps/tauri/pull/6205)) on 2023-02-11
- Refactored the implementation of the `mobile_entry_point` macro.
- [9feab904](https://www.github.com/tauri-apps/tauri/commit/9feab904bf08b5c168d4779c21d0419409a68d30) feat(core): add API to call Android plugin ([#6239](https://www.github.com/tauri-apps/tauri/pull/6239)) on 2023-02-10
## \[2.0.0-alpha.1]
- Refactor mobile environment variables.
- [dee9460f](https://www.github.com/tauri-apps/tauri/commit/dee9460f9c9bc92e9c638e7691e616849ac2085b) feat: keep CLI alive when iOS app exits, show logs, closes [#5855](https://www.github.com/tauri-apps/tauri/pull/5855) ([#5902](https://www.github.com/tauri-apps/tauri/pull/5902)) on 2022-12-27
- Bump the MSRV to 1.64.
- [7eb9aa75](https://www.github.com/tauri-apps/tauri/commit/7eb9aa75cfd6a3176d3f566fdda02d88aa529b0f) Update gtk to 0.16 ([#6155](https://www.github.com/tauri-apps/tauri/pull/6155)) on 2023-01-30
- Removed mobile logging initialization, which will be handled by `tauri-plugin-log`.
- [](https://www.github.com/tauri-apps/tauri/commit/undefined) on undefined
## \[2.0.0-alpha.0]
- Added the `mobile_entry_point` macro.
- [98904863](https://www.github.com/tauri-apps/tauri/commit/9890486321c9c79ccfb7c547fafee85b5c3ffa71) feat(core): add `mobile_entry_point` macro ([#4983](https://www.github.com/tauri-apps/tauri/pull/4983)) on 2022-08-21
- First mobile alpha release!
- [fa3a1098](https://www.github.com/tauri-apps/tauri/commit/fa3a10988a03aed1b66fb17d893b1a9adb90f7cd) feat(ci): prepare 2.0.0-alpha.0 ([#5786](https://www.github.com/tauri-apps/tauri/pull/5786)) on 2022-12-08
## \[1.4.3]
### Dependencies
- Upgraded to `tauri-utils@1.5.2`
- Upgraded to `tauri-codegen@1.4.2`
## \[1.4.2]
### Enhancements
- [`5e05236b`](https://www.github.com/tauri-apps/tauri/commit/5e05236b4987346697c7caae0567d3c50714c198)([#8289](https://www.github.com/tauri-apps/tauri/pull/8289)) Added tracing for window startup, plugins, `Window::eval`, events, IPC, updater and custom protocol request handlers behind the `tracing` feature flag.
## \[1.4.1]
### Dependencies
- Upgraded to `tauri-utils@1.5.0`
- Upgraded to `tauri-codegen@1.4.1`
## \[1.4.0]
### Enhancements
- [`d68a25e3`](https://www.github.com/tauri-apps/tauri/commit/d68a25e32e012e57a9e5225b589b9ecbea70a887)([#6124](https://www.github.com/tauri-apps/tauri/pull/6124)) Improve compiler error message when generating an async command that has a reference input and don't return a Result.
## \[1.3.0]
- Bump minimum supported Rust version to 1.60.
- [5fdc616d](https://www.github.com/tauri-apps/tauri/commit/5fdc616df9bea633810dcb814ac615911d77222c) feat: Use the zbus-backed of notify-rust ([#6332](https://www.github.com/tauri-apps/tauri/pull/6332)) on 2023-03-31
## \[1.2.1]
- Fix `allowlist > app > show/hide` always disabled when `allowlist > app > all: false`.
- Bumped due to a bump in tauri-utils.
- [bb251087](https://www.github.com/tauri-apps/tauri/commit/bb2510876d0bdff736d36bf3a465cdbe4ad2b90c) fix(core): extend allowlist with `app`'s allowlist, closes [#5650](https://www.github.com/tauri-apps/tauri/pull/5650) ([#5652](https://www.github.com/tauri-apps/tauri/pull/5652)) on 2022-11-18
## \[1.2.0]
- - [7d9aa398](https://www.github.com/tauri-apps/tauri/commit/7d9aa3987efce2d697179ffc33646d086c68030c) feat: bump MSRV to 1.59 ([#5296](https://www.github.com/tauri-apps/tauri/pull/5296)) on 2022-09-28
## \[1.1.1]
- Add missing allowlist config for `set_cursor_grab`, `set_cursor_visible`, `set_cursor_icon` and `set_cursor_position` APIs.
- Bumped due to a bump in tauri-utils.
- [c764408d](https://www.github.com/tauri-apps/tauri/commit/c764408da7fae123edd41115bda42fa75a4731d2) fix: Add missing allowlist config for cursor apis, closes [#5207](https://www.github.com/tauri-apps/tauri/pull/5207) ([#5211](https://www.github.com/tauri-apps/tauri/pull/5211)) on 2022-09-16
## \[1.1.0]
- Added support to configuration files in TOML format (Tauri.toml file).
- [ae83d008](https://www.github.com/tauri-apps/tauri/commit/ae83d008f9e1b89bfc8dddaca42aa5c1fbc36f6d) feat: add support to TOML config file `Tauri.toml`, closes [#4806](https://www.github.com/tauri-apps/tauri/pull/4806) ([#4813](https://www.github.com/tauri-apps/tauri/pull/4813)) on 2022-08-02
## \[1.0.4]
- Adjust command imports to fix `items_after_statements` Clippy warning.
- [d3e19e34](https://www.github.com/tauri-apps/tauri/commit/d3e19e3420a023cddc46173a2d1f1e6c5a390a1b) fix(macros): `items_after_statements` Clippy warning, closes [#4639](https://www.github.com/tauri-apps/tauri/pull/4639) on 2022-07-11
- Remove raw identifier (`r#`) prefix from command arguments.
- [ac72800f](https://www.github.com/tauri-apps/tauri/commit/ac72800fb630738e2502569935ecdc83e3e78055) fix(macros): strip `r#` from command arguments, closes [#4654](https://www.github.com/tauri-apps/tauri/pull/4654) ([#4657](https://www.github.com/tauri-apps/tauri/pull/4657)) on 2022-07-12
## \[1.0.3]
- Add `#[doc(hidden)]` attribute to the `#[command]` generated macro.
- [d4cdf807](https://www.github.com/tauri-apps/tauri/commit/d4cdf80781a7955ac620fe6d394e82d067178c4d) feat(macros): hide command macro from docs, closes [#4550](https://www.github.com/tauri-apps/tauri/pull/4550) ([#4556](https://www.github.com/tauri-apps/tauri/pull/4556)) on 2022-07-01
## \[1.0.2]
- Expose `platform::windows_version` function.
- Bumped due to a bump in tauri-utils.
- [bf764e83](https://www.github.com/tauri-apps/tauri/commit/bf764e83e01e7443e6cc54572001e1c98c357465) feat(utils): expose `windows_version` function ([#4534](https://www.github.com/tauri-apps/tauri/pull/4534)) on 2022-06-30
## \[1.0.1]
- Set the bundle name and app metadata in the Info.plist file in development mode.
- [38f5db6e](https://www.github.com/tauri-apps/tauri/commit/38f5db6e6a8b496b50d486db6fd8204266de3a69) feat(codegen): fill app metadata in development Info.plist on 2022-06-21
- Set the application icon in development mode on macOS.
- [307c2ebf](https://www.github.com/tauri-apps/tauri/commit/307c2ebfb68238dacab6088f9c6ba310c727c68c) feat(core): set macOS app icon in development ([#4385](https://www.github.com/tauri-apps/tauri/pull/4385)) on 2022-06-19
## \[1.0.0]
- Upgrade to `stable`!
- [f4bb30cc](https://www.github.com/tauri-apps/tauri/commit/f4bb30cc73d6ba9b9ef19ef004dc5e8e6bb901d3) feat(covector): prepare for v1 ([#4351](https://www.github.com/tauri-apps/tauri/pull/4351)) on 2022-06-15
## \[1.0.0-rc.11]
- Read the tray icon path relatively to the config directory.
- Bumped due to a bump in tauri-codegen.
- [562e8ca2](https://www.github.com/tauri-apps/tauri/commit/562e8ca23facf1a8e5fa6c8cdf872357d3523a78) fix(codegen): tray icon path is relative to the config directory on 2022-06-15
## \[1.0.0-rc.10]
- **Breaking change:** The `TrayIcon` enum has been removed and now `Icon` is used instead.
This allows you to use more image formats and use embedded icons on Linux.
- Bumped due to a bump in tauri-codegen.
- [4ce8e228](https://www.github.com/tauri-apps/tauri/commit/4ce8e228134cd3f22973b74ef26ca0d165fbbbd9) refactor(core): use `Icon` for tray icons ([#4342](https://www.github.com/tauri-apps/tauri/pull/4342)) on 2022-06-14
## \[1.0.0-rc.9]
- Added a config flag to bundle the media framework used by webkit2gtk `tauri.conf.json > tauri > bundle > appimage > bundleMediaFramework`.
- Bumped due to a bump in tauri-utils.
- [d335fae9](https://www.github.com/tauri-apps/tauri/commit/d335fae92cdcbb0ee18aad4e54558914afa3e778) feat(bundler): bundle additional gstreamer files, closes [#4092](https://www.github.com/tauri-apps/tauri/pull/4092) ([#4271](https://www.github.com/tauri-apps/tauri/pull/4271)) on 2022-06-10
## \[1.0.0-rc.8]
- **Breaking change:** `PackageInfo::version` is now a `semver::Version` instead of a `String`.
- Bumped due to a bump in tauri-utils.
- [2badbd2d](https://www.github.com/tauri-apps/tauri/commit/2badbd2d7ed51bf33c1b547b4c837b600574bd4a) refactor: force semver versions, change updater `should_install` sig ([#4215](https://www.github.com/tauri-apps/tauri/pull/4215)) on 2022-05-25
- [a7388e23](https://www.github.com/tauri-apps/tauri/commit/a7388e23c3b9019d48b078cae00a75c74d74d11b) fix(ci): adjust change file to include tauri-utils and tauri-codegen on 2022-05-27
## \[1.0.0-rc.7]
- Allow configuring the display options for the MSI execution allowing quieter updates.
- Bumped due to a bump in tauri-utils.
- [9f2c3413](https://www.github.com/tauri-apps/tauri/commit/9f2c34131952ea83c3f8e383bc3cec7e1450429f) feat(core): configure msiexec display options, closes [#3951](https://www.github.com/tauri-apps/tauri/pull/3951) ([#4061](https://www.github.com/tauri-apps/tauri/pull/4061)) on 2022-05-15
## \[1.0.0-rc.6]
- Added `$schema` support to `tauri.conf.json`.
- Bumped due to a bump in tauri-utils.
- [715cbde3](https://www.github.com/tauri-apps/tauri/commit/715cbde3842a916c4ebeab2cab348e1774b5c192) feat(config): add `$schema` to `tauri.conf.json`, closes [#3464](https://www.github.com/tauri-apps/tauri/pull/3464) ([#4031](https://www.github.com/tauri-apps/tauri/pull/4031)) on 2022-05-03
- The `dangerous_allow_asset_csp_modification` configuration value has been changed to allow a list of CSP directives to disable.
- Bumped due to a bump in tauri-utils.
- [164078c0](https://www.github.com/tauri-apps/tauri/commit/164078c0b719ccbc12e956fecf8a7d4a3c5044e1) feat: allow limiting dangerousDisableAssetCspModification, closes [#3831](https://www.github.com/tauri-apps/tauri/pull/3831) ([#4021](https://www.github.com/tauri-apps/tauri/pull/4021)) on 2022-05-02
## \[1.0.0-rc.5]
- Read platform-specific configuration files when generating code without the `TAURI_CONFIG` env var.
- Bumped due to a bump in tauri-codegen.
- [edf85bc1](https://www.github.com/tauri-apps/tauri/commit/edf85bc1d18450c92aee17f7f99c163abe432ebd) fix(codegen): read platform-specific config file ([#3966](https://www.github.com/tauri-apps/tauri/pull/3966)) on 2022-04-25
## \[1.0.0-rc.4]
- Replace multiple dependencies who's C code compiled concurrently and caused
the other ones to bloat compile time significantly.
- `zstd` -> `brotli`
- `blake3` -> a vendored version of the blake3 reference
- `ring` -> `getrandom`
See <https://github.com/tauri-apps/tauri/pull/3773> for more information about
these specific choices.
- [8661e3e2](https://www.github.com/tauri-apps/tauri/commit/8661e3e24d96c399bfbcdee5d8e9d6beba2265a7) replace dependencies with long build times when used together (closes [#3571](https://www.github.com/tauri-apps/tauri/pull/3571)) ([#3773](https://www.github.com/tauri-apps/tauri/pull/3773)) on 2022-03-27
## \[1.0.0-rc.3]
- Parse window icons at compile time.
- Bumped due to a bump in tauri-codegen.
- [8c935872](https://www.github.com/tauri-apps/tauri/commit/8c9358725a17dcc2acaf4d10c3f654afdff586b0) refactor(core): move `png` and `ico` behind Cargo features ([#3588](https://www.github.com/tauri-apps/tauri/pull/3588)) on 2022-03-05
## \[1.0.0-rc.2]
- Changed the default value for `tauri > bundle > macOS > minimumSystemVersion` to `10.13`.
- Bumped due to a bump in tauri-utils.
- [fce344b9](https://www.github.com/tauri-apps/tauri/commit/fce344b90b7227f8f5514853c2f885fb24d3648e) feat(core): set default value for `minimum_system_version` to 10.13 ([#3497](https://www.github.com/tauri-apps/tauri/pull/3497)) on 2022-02-17
## \[1.0.0-rc.1]
- Change default value for the `freezePrototype` configuration to `false`.
- Bumped due to a bump in tauri-utils.
- [3a4c0160](https://www.github.com/tauri-apps/tauri/commit/3a4c01606184be762adee055ddac803de0d28527) fix(core): change default `freezePrototype` to false, closes [#3416](https://www.github.com/tauri-apps/tauri/pull/3416) [#3406](https://www.github.com/tauri-apps/tauri/pull/3406) ([#3423](https://www.github.com/tauri-apps/tauri/pull/3423)) on 2022-02-12
## \[1.0.0-rc.0]
- Adds support for using JSON5 format for the `tauri.conf.json` file, along with also supporting the `.json5` extension.
Here is the logic flow that determines if JSON or JSON5 will be used to parse the config:
1. Check if `tauri.conf.json` exists
a. Parse it with `serde_json`
b. Parse it with `json5` if `serde_json` fails
c. Return original `serde_json` error if all above steps failed
2. Check if `tauri.conf.json5` exists
a. Parse it with `json5`
b. Return error if all above steps failed
3. Return error if all above steps failed
- [995de57a](https://www.github.com/tauri-apps/tauri/commit/995de57a76cf51215277673e526d7ec32b86b564) Add seamless support for using JSON5 in the config file ([#47](https://www.github.com/tauri-apps/tauri/pull/47)) on 2022-02-03
- The minimum Rust version is now `1.56`.
- [a9dfc015](https://www.github.com/tauri-apps/tauri/commit/a9dfc015505afe91281c2027954ffcc588b1a59c) feat: update to edition 2021 and set minimum rust to 1.56 ([#2789](https://www.github.com/tauri-apps/tauri/pull/2789)) on 2021-10-22
## \[1.0.0-beta.5]
- Embed Info.plist file contents on binary on dev.
- Bumped due to a bump in tauri-codegen.
- [537ab1b6](https://www.github.com/tauri-apps/tauri/commit/537ab1b6d5a792c550a535619965c9e4126292e6) feat(core): inject src-tauri/Info.plist file on dev and merge on bundle, closes [#1570](https://www.github.com/tauri-apps/tauri/pull/1570) [#2338](https://www.github.com/tauri-apps/tauri/pull/2338) ([#2444](https://www.github.com/tauri-apps/tauri/pull/2444)) on 2021-08-15
- Fix ES Module detection for default imports with relative paths or scoped packages and exporting of async functions.
- Bumped due to a bump in tauri-codegen.
- [b2b36cfe](https://www.github.com/tauri-apps/tauri/commit/b2b36cfe8dfcccb341638a4cb6dc23a514c54148) fix(core): fixes ES Module detection for default imports with relative paths or scoped packages ([#2380](https://www.github.com/tauri-apps/tauri/pull/2380)) on 2021-08-10
- [fbf8caf5](https://www.github.com/tauri-apps/tauri/commit/fbf8caf5c419cb4fc3d123be910e094a8e8c4bef) fix(core): ESM detection when using `export async function` ([#2425](https://www.github.com/tauri-apps/tauri/pull/2425)) on 2021-08-14
## \[1.0.0-beta.4]
- `Params` has been removed, along with all the associated types on it. Functions that previously accepted those
associated types now accept strings instead. Type that used a generic parameter `Params` now use `Runtime` instead. If
you use the `wry` feature, then types with a `Runtime` generic parameter should default to `Wry`, letting you omit the
explicit type and let the compiler infer it instead.
`tauri`:
- See `Params` note
- If you were using `Params` inside a function parameter or definition, all references to it have been replaced with a
simple runtime that defaults to `Wry`. If you are not using a custom runtime, just remove `Params` from the definition
of functions/items that previously took it. If you are using a custom runtime, you *may* need to pass the runtime type
to these functions.
- If you were using custom types for `Params` (uncommon and if you don't understand you probably were not using it), all
methods that were previously taking the custom type now takes an `Into<String>` or a `&str`. The types were already
required to be string-able, so just make sure to convert it into a string before passing it in if this breaking change
affects you.
`tauri-macros`:
- (internal) Added private `default_runtime` proc macro to allow us to give item definitions a custom runtime only when
the specified feature is enabled.
`tauri-runtime`:
- See `Params` note
- Removed `Params`, `MenuId`, `Tag`, `TagRef`.
- Added `menu::{MenuHash, MenuId, MenuIdRef}` as type aliases for the internal type that menu types now use.
- All previous menu items that had a `MenuId` generic now use the underlying `MenuId` type without a generic.
- `Runtime`, `RuntimeHandle`, and `Dispatch` have no more generic parameter on `create_window(...)` and instead use the
`Runtime` type directly
- `Runtime::system_tray` has no more `MenuId` generic and uses the string based `SystemTray` type directly.
- (internal) `CustomMenuItem::id_value()` is now hashed on creation and exposed as the `id` field with type `MenuHash`.
`tauri-runtime-wry`:
- See `Params` note
- update menu and runtime related types to the ones changed in `tauri-runtime`.
`tauri-utils`:
- `Assets::get` signature has changed to take a `&AssetKey` instead of `impl Into<AssetKey>` to become trait object
safe.
- [fd8fab50](https://www.github.com/tauri-apps/tauri/commit/fd8fab507c8fa1b113b841af14c6693eb3955f6b) refactor(core): remove `Params` and replace with strings ([#2191](https://www.github.com/tauri-apps/tauri/pull/2191)) on 2021-07-15
## \[1.0.0-beta.3]
- Detect ESM scripts and inject the invoke key directly instead of using an IIFE.
- Bumped due to a bump in tauri-codegen.
- [7765c7fa](https://www.github.com/tauri-apps/tauri/commit/7765c7fa281853ddfb26b6b17534df95eaede804) fix(core): invoke key injection on ES module, improve performance ([#2094](https://www.github.com/tauri-apps/tauri/pull/2094)) on 2021-06-27
- Improve invoke key code injection performance time rewriting code at compile time.
- Bumped due to a bump in tauri-codegen.
- [7765c7fa](https://www.github.com/tauri-apps/tauri/commit/7765c7fa281853ddfb26b6b17534df95eaede804) fix(core): invoke key injection on ES module, improve performance ([#2094](https://www.github.com/tauri-apps/tauri/pull/2094)) on 2021-06-27
## \[1.0.0-beta.2]
- internal: Refactor all macro code that expects specific bindings to be passed Idents
- [39f8f269](https://www.github.com/tauri-apps/tauri/commit/39f8f269164d2fda3d5b614a193b12bb266e4b4b) refactor(macros): explicitly pass idents ([#1812](https://www.github.com/tauri-apps/tauri/pull/1812)) on 2021-05-13
## \[1.0.0-beta.1]
- Fixes a name collision when the command function is named `invoke`.
- [7862ec5](https://www.github.com/tauri-apps/tauri/commit/7862ec562fa70e3733263ce1f690d6cd2943c0b4) fix(macros): change invoke binding in generate handler ([#1804](https://www.github.com/tauri-apps/tauri/pull/1804)) on 2021-05-12
- Fixes a name collision when the command function is named `message` or `resolver`.
- [0b87532](https://www.github.com/tauri-apps/tauri/commit/0b875327067ca825ff6f6f26c9b2ce6fcb001e79) fix(macros): fix rest of command collisions ([#1805](https://www.github.com/tauri-apps/tauri/pull/1805)) on 2021-05-12
- Fixes a name collision when the command function is named `cmd`.
- [d36b726](https://www.github.com/tauri-apps/tauri/commit/d36b7269261d329dd7d7fcd4d5098f3fca167364) fix(macros): collision when command is named `cmd` ([#1802](https://www.github.com/tauri-apps/tauri/pull/1802)) on 2021-05-12
## \[1.0.0-beta.0]
- Only commands with a `async fn` are executed on a separate task. `#[command] fn command_name` runs on the main thread.
- [bb8dafb](https://www.github.com/tauri-apps/tauri/commit/bb8dafbe1ea6edde7385631d41ac05e96a3309ef) feat(core): #\[command] return with autoref specialization workaround fix [#1672](https://www.github.com/tauri-apps/tauri/pull/1672) ([#1734](https://www.github.com/tauri-apps/tauri/pull/1734)) on 2021-05-09
- `#[command]` now generates a macro instead of a function to allow passing through `Params` and other generics.
`generate_handler!` has been changed to consume the generated `#[command]` macro
- [1453d4b](https://www.github.com/tauri-apps/tauri/commit/1453d4bf842ed6891ec604e0635344c930282189) feat(core): support generics (especially Param) in #\[command] ([#1622](https://www.github.com/tauri-apps/tauri/pull/1622)) on 2021-05-05
- Improves support for commands returning `Result`.
- [bb8dafb](https://www.github.com/tauri-apps/tauri/commit/bb8dafbe1ea6edde7385631d41ac05e96a3309ef) feat(core): #\[command] return with autoref specialization workaround fix [#1672](https://www.github.com/tauri-apps/tauri/pull/1672) ([#1734](https://www.github.com/tauri-apps/tauri/pull/1734)) on 2021-05-09
- Adds support to command state, triggered when a command argument is `arg: State<'_, StateType>`.
- [8b6f3de](https://www.github.com/tauri-apps/tauri/commit/8b6f3de0ad47684e72a2ae5f884d8675acfaeeac) feat(core): add state management, closes [#1655](https://www.github.com/tauri-apps/tauri/pull/1655) ([#1665](https://www.github.com/tauri-apps/tauri/pull/1665)) on 2021-05-02
## \[1.0.0-beta-rc.1]
- Fixes the Message `command` name value on plugin invoke handler.
- [422dd5e](https://www.github.com/tauri-apps/tauri/commit/422dd5e2a0a03bb1556915c78f110bfab092c874) fix(core): command name on plugin invoke handler ([#1577](https://www.github.com/tauri-apps/tauri/pull/1577)) on 2021-04-21
- [f575aaa](https://www.github.com/tauri-apps/tauri/commit/f575aaad71f23d44b2f89cf9ee5d84817dc3bb7a) fix: change files not referencing core packages ([#1619](https://www.github.com/tauri-apps/tauri/pull/1619)) on 2021-04-25
## \[1.0.0-beta-rc.0]
- Update all code files to have our license header.
- [bf82136](https://www.github.com/tauri-apps/tauri/commit/bf8213646689175f8a158b956911f3a43e360690) feat(license): SPDX Headers ([#1449](https://www.github.com/tauri-apps/tauri/pull/1449)) on 2021-04-11
- [a6def70](https://www.github.com/tauri-apps/tauri/commit/a6def7066eec19c889b0f14cc1e475bf209a332e) Refactor(tauri): move tauri-api and tauri-updater to tauri ([#1455](https://www.github.com/tauri-apps/tauri/pull/1455)) on 2021-04-11
- [aea6145](https://www.github.com/tauri-apps/tauri/commit/aea614587bddab930d552512b54e18624fbf573e) refactor(repo): add /tooling folder ([#1457](https://www.github.com/tauri-apps/tauri/pull/1457)) on 2021-04-12
- Added new macros to simplify the creation of commands that can be called by the webview.
- [1f2e7a3](https://www.github.com/tauri-apps/tauri/commit/1f2e7a3226ccf0ee3e30ae0cba3c67f7e219d1f2) feat(core): improved command matching with macros, fixes [#1157](https://www.github.com/tauri-apps/tauri/pull/1157) ([#1301](https://www.github.com/tauri-apps/tauri/pull/1301)) on 2021-02-28

View File

@@ -0,0 +1,34 @@
[package]
name = "tauri-macros"
version = "2.6.3"
description = "Macros for the tauri crate."
exclude = ["CHANGELOG.md", "/target"]
authors.workspace = true
homepage.workspace = true
repository.workspace = true
categories.workspace = true
license.workspace = true
edition.workspace = true
rust-version.workspace = true
[lib]
proc-macro = true
[dependencies]
proc-macro2 = { version = "1", features = ["span-locations"] }
quote = "1"
syn = { version = "2", features = ["full"] }
heck = "0.5"
tauri-codegen = { workspace = true }
tauri-utils = { workspace = true }
[features]
custom-protocol = []
compression = ["tauri-codegen/compression"]
isolation = ["tauri-codegen/isolation"]
config-json5 = ["tauri-codegen/config-json5", "tauri-utils/config-json5"]
config-toml = ["tauri-codegen/config-toml", "tauri-utils/config-toml"]
tracing = []
[lints]
workspace = true

View File

@@ -0,0 +1,177 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 - Present Tauri Apps Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,42 @@
# tauri-macros
<img align="right" src="https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png" height="128" width="128">
[![status](https://img.shields.io/badge/status-stable-blue.svg)](https://github.com/tauri-apps/tauri/tree/dev)
[![License](https://img.shields.io/badge/License-MIT%20or%20Apache%202-green.svg)](https://opencollective.com/tauri)
[![test core](https://img.shields.io/github/actions/workflow/status/tauri-apps/tauri/test-core.yml?label=test%20core&logo=github)](https://github.com/tauri-apps/tauri/actions/workflows/test-core.yml)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri?ref=badge_shield)
[![Chat Server](https://img.shields.io/badge/chat-discord-7289da.svg)](https://discord.gg/SpmNs4S)
[![website](https://img.shields.io/badge/website-tauri.app-purple.svg)](https://tauri.app)
[![https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg](https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg)](https://good-labs.github.io/greater-good-affirmation)
[![support](https://img.shields.io/badge/sponsor-Open%20Collective-blue.svg)](https://opencollective.com/tauri)
| Component | Version |
| ------------ | ------------------------------------------------------------------------------------------------------------ |
| tauri-macros | [![](https://img.shields.io/crates/v/tauri-macros?style=flat-square)](https://crates.io/crates/tauri-macros) |
## About Tauri
Tauri is a polyglot and generic system that is very composable and allows engineers to make a wide variety of applications. It is used for building applications for Desktop Computers using a combination of Rust tools and HTML rendered in a Webview. Apps built with Tauri can ship with any number of pieces of an optional JS API / Rust API so that webviews can control the system via message passing. In fact, developers can extend the default API with their own functionality and bridge the Webview and Rust-based backend easily.
Tauri apps can have custom menus and have tray-type interfaces. They can be updated, and are managed by the user's operating system as expected. They are very small, because they use the system's webview. They do not ship a runtime, since the final binary is compiled from rust. This makes the reversing of Tauri apps not a trivial task.
## This module
Create macros for the context, handler, and commands by leveraging the `tauri-codegen` crate.
To learn more about the details of how all of these pieces fit together, please consult this [ARCHITECTURE.md](https://github.com/tauri-apps/tauri/blob/dev/ARCHITECTURE.md) document.
## Semver
**tauri** is following [Semantic Versioning 2.0](https://semver.org/).
## Licenses
Code: (c) 2021 - The Tauri Programme within The Commons Conservancy.
MIT or MIT/Apache 2.0 where applicable.
Logo: CC-BY-NC-ND
- Original Tauri Logo Designs by [Daniel Thompson-Yvetot](https://github.com/nothingismagick) and [Guillaume Chau](https://github.com/akryum)

View File

@@ -0,0 +1,185 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use quote::{format_ident, quote};
use syn::{
Attribute, Ident, Path, Token,
parse::{Parse, ParseBuffer, ParseStream},
};
struct CommandDef {
path: Path,
attrs: Vec<Attribute>,
}
impl Parse for CommandDef {
fn parse(input: ParseStream) -> syn::Result<Self> {
let attrs = input.call(Attribute::parse_outer)?;
let path = input.parse()?;
Ok(CommandDef { path, attrs })
}
}
/// The items parsed from [`generate_handle!`](crate::generate_handle).
pub struct Handler {
command_defs: Vec<CommandDef>,
commands: Vec<Ident>,
wrappers: Vec<Path>,
}
impl Parse for Handler {
fn parse(input: &ParseBuffer<'_>) -> syn::Result<Self> {
let plugin_name = try_get_plugin_name(input)?;
let mut command_defs = input
.parse_terminated(CommandDef::parse, Token![,])?
.into_iter()
.collect();
filter_unused_commands(plugin_name, &mut command_defs);
let mut commands = Vec::new();
let mut wrappers = Vec::new();
// parse the command names and wrappers from the passed paths
for command_def in &command_defs {
let mut wrapper = command_def.path.clone();
let last = super::path_to_command(&mut wrapper);
// the name of the actual command function
let command = last.ident.clone();
// set the path to the command function wrapper
last.ident = super::format_command_wrapper(&command);
commands.push(command);
wrappers.push(wrapper);
}
Ok(Self {
command_defs,
commands,
wrappers,
})
}
}
/// Try to get the plugin name by parsing the input for a `#![plugin(...)]` attribute,
/// if it's not present, try getting it from `CARGO_PKG_NAME` environment variable
fn try_get_plugin_name(input: &ParseBuffer<'_>) -> Result<Option<String>, syn::Error> {
if let Ok(attrs) = input.call(Attribute::parse_inner) {
for attr in attrs {
if attr.path().is_ident("plugin") {
// Parse the content inside #![plugin(...)]
let plugin_name = attr.parse_args::<Ident>()?.to_string();
return Ok(Some(if plugin_name == "__TAURI_CHANNEL__" {
// TODO: Remove this in v3
plugin_name
} else {
plugin_name.replace("_", "-")
}));
}
}
}
Ok(
std::env::var("CARGO_PKG_NAME")
.ok()
.and_then(|var| var.strip_prefix("tauri-plugin-").map(String::from)),
)
}
fn filter_unused_commands(plugin_name: Option<String>, command_defs: &mut Vec<CommandDef>) {
let allowed_commands = tauri_utils::acl::read_allowed_commands();
let Some(allowed_commands) = allowed_commands else {
return;
};
// TODO: Remove this in v3
if plugin_name.as_deref() == Some("__TAURI_CHANNEL__") {
// Always allowed
return;
}
if plugin_name.is_none() && !allowed_commands.has_app_acl {
// All application commands are allowed if we don't have an application ACL
//
// note that inline plugins without the #![plugin()] attribute would also get to this check
// which means inline plugins must have an app manifest to get proper unused command removal
return;
}
let mut unused_commands = Vec::new();
let command_prefix = if let Some(plugin_name) = &plugin_name {
format!("plugin:{plugin_name}|")
} else {
"".into()
};
command_defs.retain(|command_def| {
let mut wrapper = command_def.path.clone();
let last = super::path_to_command(&mut wrapper);
// the name of the actual command function
let command_name = &last.ident;
let command = format!("{command_prefix}{command_name}");
let is_allowed = allowed_commands.commands.contains(&command);
if !is_allowed {
unused_commands.push(command_name.to_string());
}
is_allowed
});
if !unused_commands.is_empty() {
let plugin_display_name = plugin_name.as_deref().unwrap_or("application");
let unused_commands_display = unused_commands.join(", ");
println!("Removed unused commands from {plugin_display_name}: {unused_commands_display}",);
}
}
impl From<Handler> for proc_macro::TokenStream {
fn from(
Handler {
command_defs,
commands,
wrappers,
}: Handler,
) -> Self {
let cmd = format_ident!("__tauri_cmd__");
let invoke = format_ident!("__tauri_invoke__");
let mut paths: Vec<Path> = Vec::new();
let mut attrs: Vec<Vec<Attribute>> = Vec::new();
let mut command_name_macros: Vec<proc_macro2::TokenStream> = Vec::new();
for (def, command) in command_defs.into_iter().zip(commands) {
let path = def.path;
let attrs_vec = def.attrs;
let mut command_name_macro_path = path.clone();
let last = command_name_macro_path
.segments
.last_mut()
.expect("path has at least one segment");
last.ident = format_ident!("__tauri_command_name_{command}");
paths.push(path);
attrs.push(attrs_vec);
// Call the macro to get the command name string literal
command_name_macros.push(quote!(#command_name_macro_path!()));
}
quote::quote!(move |#invoke| {
let #cmd = #invoke.message.command();
match #cmd {
#(#(#attrs)* #command_name_macros => #wrappers!(#paths, #invoke),)*
_ => {
return false;
},
}
})
.into()
}
}

View File

@@ -0,0 +1,24 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use proc_macro2::Ident;
use syn::{Path, PathSegment};
pub use self::{handler::Handler, wrapper::wrapper};
mod handler;
mod wrapper;
/// The autogenerated wrapper ident.
fn format_command_wrapper(function: &Ident) -> Ident {
quote::format_ident!("__cmd__{}", function)
}
/// This function will panic if the passed [`syn::Path`] does not have any segments.
fn path_to_command(path: &mut Path) -> &mut PathSegment {
path
.segments
.last_mut()
.expect("parsed syn::Path has no segment")
}

View File

@@ -0,0 +1,524 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use std::env::var;
use heck::{ToLowerCamelCase, ToSnakeCase};
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
use quote::{format_ident, quote, quote_spanned};
use syn::{
Expr, ExprLit, FnArg, ItemFn, Lit, Meta, Pat, Token, Visibility,
ext::IdentExt,
parse::{Parse, ParseStream},
parse_macro_input,
punctuated::Punctuated,
spanned::Spanned,
};
use tauri_utils::acl::REMOVE_UNUSED_COMMANDS_ENV_VAR;
#[allow(clippy::large_enum_variant)]
enum WrapperAttributeKind {
Meta(Meta),
Async,
}
impl Parse for WrapperAttributeKind {
fn parse(input: ParseStream) -> syn::Result<Self> {
match input.parse::<Meta>() {
Ok(m) => Ok(Self::Meta(m)),
Err(e) => match input.parse::<Token![async]>() {
Ok(_) => Ok(Self::Async),
Err(_) => Err(e),
},
}
}
}
struct WrapperAttributes {
root: TokenStream2,
execution_context: ExecutionContext,
argument_case: ArgumentCase,
rename: RenamePolicy,
}
impl Parse for WrapperAttributes {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut wrapper_attributes = WrapperAttributes {
root: quote!(::tauri),
execution_context: ExecutionContext::Blocking,
argument_case: ArgumentCase::Camel,
rename: RenamePolicy::Keep,
};
let attrs = Punctuated::<WrapperAttributeKind, Token![,]>::parse_terminated(input)?;
for attr in attrs {
match attr {
WrapperAttributeKind::Meta(Meta::List(_)) => {
return Err(syn::Error::new(input.span(), "unexpected list input"));
}
WrapperAttributeKind::Meta(Meta::NameValue(v)) => {
if v.path.is_ident("rename_all") {
if let Expr::Lit(ExprLit {
lit: Lit::Str(s),
attrs: _,
}) = v.value
{
wrapper_attributes.argument_case = match s.value().as_str() {
"snake_case" => ArgumentCase::Snake,
"camelCase" => ArgumentCase::Camel,
_ => {
return Err(syn::Error::new(
s.span(),
"expected \"camelCase\" or \"snake_case\"",
));
}
};
}
} else if v.path.is_ident("rename") {
if let Expr::Lit(ExprLit {
lit: Lit::Str(s), ..
}) = v.value
{
let lit = s.value();
wrapper_attributes.rename = RenamePolicy::Rename(quote!(#lit));
} else {
return Err(syn::Error::new(
v.span(),
"expected string literal for rename",
));
}
} else if v.path.is_ident("root") {
if let Expr::Lit(ExprLit {
lit: Lit::Str(s),
attrs: _,
}) = v.value
{
let lit = s.value();
wrapper_attributes.root = if lit == "crate" {
quote!($crate)
} else {
let ident = Ident::new(&lit, Span::call_site());
quote!(#ident)
};
}
}
}
WrapperAttributeKind::Meta(Meta::Path(_)) => {
return Err(syn::Error::new(
input.span(),
"unexpected input, expected one of `rename_all`, `rename`, `root`, `async`",
));
}
WrapperAttributeKind::Async => {
wrapper_attributes.execution_context = ExecutionContext::Async;
}
}
}
Ok(wrapper_attributes)
}
}
/// The execution context of the command.
enum ExecutionContext {
Async,
Blocking,
}
/// The case of each argument name.
#[derive(Copy, Clone)]
enum ArgumentCase {
Snake,
Camel,
}
/// The rename policy for the command.
enum RenamePolicy {
Keep,
Rename(TokenStream2),
}
/// The bindings we attach to `tauri::Invoke`.
struct Invoke {
message: Ident,
resolver: Ident,
acl: Ident,
}
/// Create a new [`Wrapper`] from the function and the generated code parsed from the function.
pub fn wrapper(attributes: TokenStream, item: TokenStream) -> TokenStream {
let mut attrs = parse_macro_input!(attributes as WrapperAttributes);
let function = parse_macro_input!(item as ItemFn);
let wrapper = super::format_command_wrapper(&function.sig.ident);
let visibility = &function.vis;
if function.sig.asyncness.is_some() {
attrs.execution_context = ExecutionContext::Async;
}
// macros used with `pub use my_macro;` need to be exported with `#[macro_export]`.
let maybe_macro_export = match &function.vis {
Visibility::Public(_) | Visibility::Restricted(_) => {
quote!(#[macro_export])
}
_ => TokenStream2::default(),
};
let invoke = Invoke {
message: format_ident!("__tauri_message__"),
resolver: format_ident!("__tauri_resolver__"),
acl: format_ident!("__tauri_acl__"),
};
// Tauri currently doesn't support async commands that take a reference as input and don't return
// a result. See: https://github.com/tauri-apps/tauri/issues/2533
//
// For now, we provide an informative error message to the user in that case. Once #2533 is
// resolved, this check can be removed.
let mut async_command_check = TokenStream2::new();
if function.sig.asyncness.is_some() {
// This check won't catch all possible problems but it should catch the most common ones.
let mut ref_argument_span = None;
for arg in &function.sig.inputs {
if let syn::FnArg::Typed(pat) = arg {
match &*pat.ty {
syn::Type::Reference(_) => {
ref_argument_span = Some(pat.span());
}
syn::Type::Path(path) => {
// Check if the type contains a lifetime argument
let last = path.path.segments.last().unwrap();
if let syn::PathArguments::AngleBracketed(args) = &last.arguments {
if args
.args
.iter()
.any(|arg| matches!(arg, syn::GenericArgument::Lifetime(_)))
{
ref_argument_span = Some(pat.span());
}
}
}
_ => {}
}
if let Some(span) = ref_argument_span {
if let syn::ReturnType::Type(_, return_type) = &function.sig.output {
// To check if the return type is `Result` we require it to check a trait that is
// only implemented by `Result`. That way we don't exclude renamed result types
// which we wouldn't otherwise be able to detect purely from the token stream.
// The "error message" displayed to the user is simply the trait name.
let diagnostic = quote!(#[diagnostic::on_unimplemented(message = "async commands that contain references as inputs must return a `Result`")]);
async_command_check = quote_spanned! {return_type.span() =>
#[allow(unreachable_code, clippy::diverging_sub_expression, clippy::used_underscore_binding)]
const _: () = if false {
#diagnostic
trait AsyncCommandMustReturnResult {}
impl<A, B> AsyncCommandMustReturnResult for ::std::result::Result<A, B> {}
let _check: #return_type = unreachable!();
let _: &dyn AsyncCommandMustReturnResult = &_check;
};
};
} else {
return quote_spanned! {
span => compile_error!("async commands that contain references as inputs must return a `Result`");
}.into();
}
}
}
}
}
let plugin_name = var("CARGO_PKG_NAME")
.expect("missing `CARGO_PKG_NAME` environment variable")
.strip_prefix("tauri-plugin-")
.map(|name| quote!(::core::option::Option::Some(#name)))
.unwrap_or_else(|| quote!(::core::option::Option::None));
let body = match attrs.execution_context {
ExecutionContext::Async => body_async(&plugin_name, &function, &invoke, &attrs)
.unwrap_or_else(syn::Error::into_compile_error),
ExecutionContext::Blocking => body_blocking(&plugin_name, &function, &invoke, &attrs)
.unwrap_or_else(syn::Error::into_compile_error),
};
let Invoke {
message,
resolver,
acl,
} = invoke;
let root = attrs.root;
let kind = match attrs.execution_context {
ExecutionContext::Async if function.sig.asyncness.is_none() => "sync_threadpool",
ExecutionContext::Async => "async",
ExecutionContext::Blocking => "sync",
};
let loc = function.span().start();
let line = loc.line;
let col = loc.column;
let maybe_span = if cfg!(feature = "tracing") {
quote!({
let _span = tracing::debug_span!(
"ipc::request::handler",
cmd = #message.command(),
kind = #kind,
loc.line = #line,
loc.col = #col,
is_internal = false,
)
.entered();
})
} else {
quote!()
};
// Allow this to be unused when we're building with `build > removeUnusedCommands` for dead code elimination
let maybe_allow_unused = if var(REMOVE_UNUSED_COMMANDS_ENV_VAR).is_ok() {
quote!(#[allow(unused)])
} else {
TokenStream2::default()
};
// Always define a hidden macro that returns the externally invoked command name.
// This lets the handler match on the renamed string while the original function
// identifier remains usable in `generate_handler![original_fn_name]`.
let command_name_macro_ident = format_ident!("__tauri_command_name_{}", function.sig.ident);
let command_name_value = if let RenamePolicy::Rename(ref rename) = attrs.rename {
quote!(#rename)
} else {
let ident = &function.sig.ident;
quote!(stringify!(#ident))
};
// Rely on rust 2018 edition to allow importing a macro from a path.
quote!(
#async_command_check
#maybe_allow_unused
#function
// Command name macro used by the handler for pattern matching.
// This macro returns the command name string literal (renamed or original).
#maybe_allow_unused
#maybe_macro_export
#[doc(hidden)]
macro_rules! #command_name_macro_ident {
() => {
#command_name_value
};
}
#maybe_allow_unused
#maybe_macro_export
#[doc(hidden)]
macro_rules! #wrapper {
// double braces because the item is expected to be a block expression
($path:path, $invoke:ident) => {
// The IIFE here is for preventing stack overflow on Windows,
// see https://github.com/tauri-apps/tauri/issues/12488
{
move || {
#[allow(unused_imports)]
use #root::ipc::private::*;
// prevent warnings when the body is a `compile_error!` or if the command has no arguments
#[allow(unused_variables)]
let #root::ipc::Invoke { message: #message, resolver: #resolver, acl: #acl } = $invoke;
#maybe_span
#body
}
}()
};
}
// allow the macro to be resolved with the same path as the command function
#[allow(unused_imports)]
#visibility use {#wrapper, #command_name_macro_ident};
)
.into()
}
/// Generates an asynchronous command response from the arguments and return value of a function.
///
/// See the [`tauri::command`] module for all the items and traits that make this possible.
///
/// [`tauri::command`]: https://docs.rs/tauri/*/tauri/runtime/index.html
fn body_async(
plugin_name: &TokenStream2,
function: &ItemFn,
invoke: &Invoke,
attributes: &WrapperAttributes,
) -> syn::Result<TokenStream2> {
let Invoke {
message,
resolver,
acl,
} = invoke;
parse_args(plugin_name, function, message, acl, attributes).map(|args| {
#[cfg(feature = "tracing")]
quote! {
use tracing::Instrument;
let span = tracing::debug_span!("ipc::request::run");
#resolver.respond_async_serialized(async move {
let result = $path(#(#args?),*);
let kind = (&result).async_kind();
kind.future(result).await
}
.instrument(span));
return true;
}
#[cfg(not(feature = "tracing"))]
quote! {
#resolver.respond_async_serialized(async move {
let result = $path(#(#args?),*);
let kind = (&result).async_kind();
kind.future(result).await
});
return true;
}
})
}
/// Generates a blocking command response from the arguments and return value of a function.
///
/// See the [`tauri::command`] module for all the items and traits that make this possible.
///
/// [`tauri::command`]: https://docs.rs/tauri/*/tauri/runtime/index.html
fn body_blocking(
plugin_name: &TokenStream2,
function: &ItemFn,
invoke: &Invoke,
attributes: &WrapperAttributes,
) -> syn::Result<TokenStream2> {
let Invoke {
message,
resolver,
acl,
} = invoke;
let args = parse_args(plugin_name, function, message, acl, attributes)?;
// the body of a `match` to early return any argument that wasn't successful in parsing.
let match_body = quote!({
Ok(arg) => arg,
Err(err) => { #resolver.invoke_error(err); return true },
});
let maybe_span = if cfg!(feature = "tracing") {
quote!(let _span = tracing::debug_span!("ipc::request::run").entered();)
} else {
quote!()
};
Ok(quote! {
#maybe_span
let result = $path(#(match #args #match_body),*);
let kind = (&result).blocking_kind();
kind.block(result, #resolver);
return true;
})
}
/// Parse all arguments for the command wrapper to use from the signature of the command function.
fn parse_args(
plugin_name: &TokenStream2,
function: &ItemFn,
message: &Ident,
acl: &Ident,
attributes: &WrapperAttributes,
) -> syn::Result<Vec<TokenStream2>> {
function
.sig
.inputs
.iter()
.map(|arg| {
parse_arg(
plugin_name,
&function.sig.ident,
arg,
message,
acl,
attributes,
)
})
.collect()
}
/// Transform a [`FnArg`] into a command argument.
fn parse_arg(
plugin_name: &TokenStream2,
command: &Ident,
arg: &FnArg,
message: &Ident,
acl: &Ident,
attributes: &WrapperAttributes,
) -> syn::Result<TokenStream2> {
// we have no use for self arguments
let mut arg = match arg {
FnArg::Typed(arg) => arg.pat.as_ref().clone(),
FnArg::Receiver(arg) => {
return Err(syn::Error::new(
arg.span(),
"unable to use self as a command function parameter",
));
}
};
// we only support patterns that allow us to extract some sort of keyed identifier
let mut key = match &mut arg {
Pat::Ident(arg) => arg.ident.unraw().to_string(),
Pat::Wild(_) => "".into(), // we always convert to camelCase, so "_" will end up empty anyways
Pat::Struct(s) => super::path_to_command(&mut s.path).ident.to_string(),
Pat::TupleStruct(s) => super::path_to_command(&mut s.path).ident.to_string(),
err => {
return Err(syn::Error::new(
err.span(),
"only named, wildcard, struct, and tuple struct arguments allowed",
));
}
};
// also catch self arguments that use FnArg::Typed syntax
if key == "self" {
return Err(syn::Error::new(
key.span(),
"unable to use self as a command function parameter",
));
}
match attributes.argument_case {
ArgumentCase::Camel => {
key = key.to_lower_camel_case();
}
ArgumentCase::Snake => {
key = key.to_snake_case();
}
}
let root = &attributes.root;
let command_name = if let RenamePolicy::Rename(r) = &attributes.rename {
quote!(stringify!(#r))
} else {
quote!(stringify!(#command))
};
Ok(quote!(#root::ipc::CommandArg::from_command(
#root::ipc::CommandItem {
plugin: #plugin_name,
name: #command_name,
key: #key,
message: &#message,
acl: &#acl,
}
)))
}

View File

@@ -0,0 +1,169 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use proc_macro2::{Ident, Span, TokenStream};
use quote::{ToTokens, quote};
use std::path::PathBuf;
use syn::{
Expr, ExprLit, Lit, LitBool, LitStr, Meta, PathArguments, PathSegment, Token,
parse::{Parse, ParseBuffer},
punctuated::Punctuated,
};
use tauri_codegen::{ContextData, context_codegen, get_config};
use tauri_utils::{config::parse::does_supported_file_name_exist, platform::Target};
pub(crate) struct ContextItems {
config_file: PathBuf,
root: syn::Path,
capabilities: Option<Vec<PathBuf>>,
assets: Option<Expr>,
test: bool,
}
impl Parse for ContextItems {
fn parse(input: &ParseBuffer<'_>) -> syn::parse::Result<Self> {
let target = std::env::var("TARGET")
.or_else(|_| std::env::var("TAURI_ENV_TARGET_TRIPLE"))
.as_deref()
.map(Target::from_triple)
.unwrap_or_else(|_| Target::current());
let mut root = None;
let mut capabilities = None;
let mut assets = None;
let mut test = false;
let config_file = input.parse::<LitStr>().ok().map(|raw| {
let _ = input.parse::<Token![,]>();
let path = PathBuf::from(raw.value());
if path.is_relative() {
std::env::var("CARGO_MANIFEST_DIR")
.map(|m| PathBuf::from(m).join(path))
.map_err(|e| e.to_string())
} else {
Ok(path)
}
.and_then(|path| {
if does_supported_file_name_exist(target, &path) {
Ok(path)
} else {
Err(format!(
"no file at path {} exists, expected tauri config file",
path.display()
))
}
})
});
while let Ok(meta) = input.parse::<Meta>() {
match meta {
Meta::Path(p) => {
root.replace(p);
}
Meta::NameValue(v) => {
let ident = v.path.require_ident()?;
match ident.to_string().as_str() {
"capabilities" => {
if let Expr::Array(array) = v.value {
capabilities.replace(
array
.elems
.into_iter()
.map(|e| {
if let Expr::Lit(ExprLit {
attrs: _,
lit: Lit::Str(s),
}) = e
{
Ok(s.value().into())
} else {
Err(syn::Error::new(
input.span(),
"unexpected expression for capability",
))
}
})
.collect::<Result<Vec<_>, syn::Error>>()?,
);
} else {
return Err(syn::Error::new(
input.span(),
"unexpected value for capabilities",
));
}
}
"assets" => {
assets.replace(v.value);
}
"test" => {
if let Expr::Lit(ExprLit {
lit: Lit::Bool(LitBool { value, .. }),
..
}) = v.value
{
test = value;
} else {
return Err(syn::Error::new(input.span(), "unexpected value for test"));
}
}
name => {
return Err(syn::Error::new(
input.span(),
format!("unknown attribute {name}"),
));
}
}
}
Meta::List(_) => {
return Err(syn::Error::new(input.span(), "unexpected list input"));
}
}
let _ = input.parse::<Token![,]>();
}
Ok(Self {
config_file: config_file
.unwrap_or_else(|| {
std::env::var("CARGO_MANIFEST_DIR")
.map(|m| PathBuf::from(m).join("tauri.conf.json"))
.map_err(|e| e.to_string())
})
.map_err(|e| input.error(e))?,
root: root.unwrap_or_else(|| {
let mut segments = Punctuated::new();
segments.push(PathSegment {
ident: Ident::new("tauri", Span::call_site()),
arguments: PathArguments::None,
});
syn::Path {
leading_colon: Some(Token![::](Span::call_site())),
segments,
}
}),
capabilities,
assets,
test,
})
}
}
pub(crate) fn generate_context(context: ContextItems) -> TokenStream {
let context = get_config(&context.config_file)
.map_err(|e| e.to_string())
.map(|(config, config_parent)| ContextData {
dev: cfg!(not(feature = "custom-protocol")),
config,
config_parent,
root: context.root.to_token_stream(),
capabilities: context.capabilities,
assets: context.assets,
test: context.test,
})
.and_then(|data| context_codegen(data).map_err(|e| e.to_string()));
match context {
Ok(code) => code,
Err(error) => quote!(compile_error!(#error)),
}
}

View File

@@ -0,0 +1,394 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
//! Create macros for `tauri::Context`, invoke handler and commands leveraging the `tauri-codegen` crate.
//!
//! Don't depend on this crate directly, use the re-exported types from tauri instead.
#![doc(
html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png",
html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png"
)]
use std::path::PathBuf;
use crate::context::ContextItems;
use proc_macro::TokenStream;
use quote::{ToTokens, quote};
use syn::{LitStr, parse_macro_input, parse2};
use tauri_codegen::image::CachedIcon;
mod command;
mod menu;
mod mobile;
mod runtime;
#[macro_use]
mod context;
/// Mark a function as a command handler. It creates a wrapper function with the necessary glue code.
///
/// The wrapped function can then be passed to [`generate_handler!`] so it can be called
/// from the frontend with `invoke()`.
///
/// ```rust,ignore
/// #[tauri::command]
/// fn greet(name: String) -> String {
/// format!("Hello, {name}!")
/// }
/// ```
///
/// # Options
///
/// The attribute accepts a comma separated list of the following options:
///
/// ## `async`
///
/// Runs the command on the async runtime instead of blocking the main thread.
///
/// `async fn` commands are always executed asynchronously, so this option is only needed
/// for synchronous functions that should not run on the main thread:
///
/// ```rust,ignore
/// #[tauri::command(async)]
/// fn expensive_computation() -> u64 {
/// // the body runs on the async runtime, so the main thread is not blocked
/// 42
/// }
/// ```
///
/// ## `rename_all`
///
/// Sets the case convention used to match the command arguments with the keys of the
/// payload sent by the frontend. Either `"camelCase"` (default) or `"snake_case"`.
///
/// ```rust,ignore
/// // called from JavaScript with `invoke("send_message", { messageBody: "Hello" })`
/// #[tauri::command]
/// fn send_message(message_body: String) {}
///
/// // called from JavaScript with `invoke("send_message", { message_body: "Hello" })`
/// #[tauri::command(rename_all = "snake_case")]
/// fn send_message_snake(message_body: String) {}
/// ```
///
/// ## `rename`
///
/// Changes the name used to call the command from the frontend.
/// By default it is the name of the function.
///
/// ```rust,ignore
/// // called from JavaScript with `invoke("greetUser")`
/// // and still registered as `generate_handler![greet_user]`
/// #[tauri::command(rename = "greetUser")]
/// fn greet_user() {}
/// ```
///
/// ## `root`
///
/// Path to the `tauri` crate, used when it is renamed in `Cargo.toml` or re-exported
/// by another crate. Defaults to `::tauri`, and the special value `"crate"` resolves
/// to `$crate` (used internally by Tauri itself).
///
/// ```rust,ignore
/// // Cargo.toml: tauri_framework = { package = "tauri", version = "2" }
/// #[tauri::command(root = "tauri_framework")]
/// fn my_command() {}
/// ```
///
/// # Inline plugins
///
/// When the command belongs to a plugin that is part of your application instead of a
/// standalone crate, annotate it in the [`generate_handler!`] list with the
/// `#![plugin(your_plugin_name)]` inner attribute so `build > removeUnusedCommands` can
/// match it against the plugin permissions.
///
/// # Stability
/// The output of this macro is managed internally by Tauri,
/// and should not be accessed directly on normal applications.
/// It may have breaking changes in the future.
#[proc_macro_attribute]
pub fn command(attributes: TokenStream, item: TokenStream) -> TokenStream {
command::wrapper(attributes, item)
}
/// Marks a function as the entry point of a mobile application.
///
/// It must be applied to the function that builds and runs your Tauri application on the
/// library target (`run()` on `src-tauri/src/lib.rs` for apps created by the Tauri CLI),
/// which is the function the generated Android and iOS projects call on startup.
///
/// The canonical usage only applies it on mobile targets, so the same function can be called
/// by the `main.rs` of the desktop binary:
///
/// ```rust,ignore
/// #[cfg_attr(mobile, tauri::mobile_entry_point)]
/// pub fn run() {
/// tauri::Builder::default()
/// .run(tauri::generate_context!())
/// .expect("error while running tauri application");
/// }
/// ```
///
/// The macro generates a `start_app` C symbol (checked by the Tauri CLI) that catches
/// panics instead of unwinding across the FFI boundary, blocks on the function when it is
/// `async`, sets up the stdout logger on iOS and the JNI bindings on Android using the
/// package name derived from the `identifier` in your Tauri configuration.
///
/// Because the Android package name is read from environment variables set by `tauri-build`,
/// your application must have a build script calling [`tauri_build::build`] - otherwise the
/// macro fails to compile with a `env var not set` error.
///
/// [`tauri_build::build`]: https://docs.rs/tauri-build/latest/tauri_build/fn.build.html
#[proc_macro_attribute]
pub fn mobile_entry_point(attributes: TokenStream, item: TokenStream) -> TokenStream {
mobile::entry_point(attributes, item)
}
/// Accepts a list of command functions. Creates a handler that allows commands to be called from JS with invoke().
///
/// You can optionally annotate the commands with a inner attribute tag `#![plugin(your_plugin_name)]`
/// for `build > removeUnusedCommands` to work for plugins not defined in a standalone crate like `tauri-plugin-fs`
///
/// # Examples
///
/// ```rust,ignore
/// use tauri_macros::{command, generate_handler};
/// #[command]
/// fn command_one() {
/// println!("command one called");
/// }
/// #[command]
/// fn command_two() {
/// println!("command two called");
/// }
/// fn main() {
/// let _handler = generate_handler![command_one, command_two];
/// }
/// ```
///
/// # Stability
///
/// The output of this macro is managed internally by Tauri,
/// and should not be accessed directly on normal applications.
/// It may have breaking changes in the future.
#[proc_macro]
pub fn generate_handler(item: TokenStream) -> TokenStream {
parse_macro_input!(item as command::Handler).into()
}
/// Reads a Tauri config file and generates a `::tauri::Context` based on the content.
///
/// The context embeds the frontend assets, the application icons, the resolved Access Control List
/// and the parsed configuration into the binary, and is passed to
/// `tauri::Builder::run`/`tauri::Builder::build`.
///
/// ```rust,ignore
/// tauri::Builder::default()
/// .run(tauri::generate_context!())
/// .expect("error while running tauri application");
/// ```
///
/// # Options
///
/// All options are optional and can be combined in a comma separated list.
///
/// ## Configuration file path
///
/// A string literal as the first argument sets the path of the Tauri configuration file to read,
/// relative to `CARGO_MANIFEST_DIR`. Defaults to `tauri.conf.json` on the crate directory.
/// Platform specific configuration files (e.g. `tauri.windows.conf.json`) that sit next to it are
/// merged as usual.
///
/// ```rust,ignore
/// tauri::generate_context!("../tauri.conf.json");
/// ```
///
/// ## Root path
///
/// A path (any item that is not a `key = value` pair) changes the crate path the generated code
/// refers to. Defaults to `::tauri`, and is only needed when the `tauri` crate is renamed,
/// re-exported by another crate, or is the crate being compiled (`crate`).
///
/// ```rust,ignore
/// tauri::generate_context!("../tauri.conf.json", ::my_framework::tauri);
/// ```
///
/// ## `capabilities`
///
/// A list of additional capability files to include in the generated Access Control List,
/// on top of the ones defined in the `capabilities` directory and in the
/// `app > security > capabilities` configuration value.
///
/// Each item is a path (relative to the current working directory of the compiler,
/// usually the crate directory) to a JSON or TOML file containing a capability,
/// a list of capabilities or a named list of capabilities.
///
/// ```rust,ignore
/// tauri::generate_context!(capabilities = ["./capabilities/extra.json"]);
/// ```
///
/// ## `assets`
///
/// An expression resolving to a custom [`tauri::Assets`] implementation, used instead of
/// embedding the files from `build > frontendDist`. Useful for serving the frontend from a
/// custom source, or for skipping asset embedding on tests.
///
/// ```rust,ignore
/// tauri::generate_context!(assets = tauri::test::noop_assets());
/// ```
///
/// ## `test`
///
/// When `true`, skips code generation that misbehaves when the context is created inside a
/// test binary - currently the `Info.plist` embedding performed on macOS development builds.
/// Defaults to `false`.
///
/// ```rust,ignore
/// let context = tauri::generate_context!("../tauri.conf.json", test = true);
/// ```
///
/// [`tauri::Assets`]: https://docs.rs/tauri/latest/tauri/trait.Assets.html
///
/// # Stability
/// The output of this macro is managed internally by Tauri,
/// and should not be accessed directly on normal applications.
/// It may have breaking changes in the future.
#[proc_macro]
pub fn generate_context(items: TokenStream) -> TokenStream {
// this macro is exported from the context module
let path = parse_macro_input!(items as ContextItems);
context::generate_context(path).into()
}
/// Adds the default type for the last parameter (assumed to be runtime) for a specific feature.
///
/// e.g. To default the runtime generic to type `crate::Wry` when the `wry` feature is enabled, the
/// syntax would look like `#[default_runtime(crate::Wry, wry)`. This is **always** set for the last
/// generic, so make sure the last generic is the runtime when using this macro.
#[doc(hidden)]
#[proc_macro_attribute]
pub fn default_runtime(attributes: TokenStream, input: TokenStream) -> TokenStream {
let attributes = parse_macro_input!(attributes as runtime::Attributes);
let input = parse_macro_input!(input as runtime::Input);
runtime::default_runtime(attributes, input).into()
}
/// Accepts a closure-like syntax to call arbitrary code on a menu item
/// after matching against `kind` and retrieving it from `resources_table` using `rid`.
///
/// You can optionally pass a 5th parameter to select which item kinds
/// to match against, by providing a `|` separated list of item kinds
/// ```ignore
/// do_menu_item!(resources_table, rid, kind, |i| i.set_text(text), Check | Submenu);
/// ```
/// You could also provide a negated list
/// ```ignore
/// do_menu_item!(resources_table, rid, kind, |i| i.set_text(text), !Check);
/// do_menu_item!(resources_table, rid, kind, |i| i.set_text(text), !Check | !Submenu);
/// ```
/// but you can't have mixed negations and positive kinds.
/// ```ignore
/// do_menu_item!(resources_table, rid, kind, |i| i.set_text(text), !Check | Submenu);
/// ```
///
/// ## Examples
///
/// ```ignore
/// let rid = 23;
/// let kind = ItemKind::Check;
/// let resources_table = app.resources_table();
/// do_menu_item!(resources_table, rid, kind, |i| i.set_text(text))
/// ```
/// which will expand into:
/// ```ignore
/// let rid = 23;
/// let kind = ItemKind::Check;
/// let resources_table = app.resources_table();
/// match kind {
/// ItemKind::Submenu => {
/// let i = resources_table.get::<Submenu<R>>(rid)?;
/// i.set_text(text)
/// }
/// ItemKind::MenuItem => {
/// let i = resources_table.get::<MenuItem<R>>(rid)?;
/// i.set_text(text)
/// }
/// ItemKind::Predefined => {
/// let i = resources_table.get::<PredefinedMenuItem<R>>(rid)?;
/// i.set_text(text)
/// }
/// ItemKind::Check => {
/// let i = resources_table.get::<CheckMenuItem<R>>(rid)?;
/// i.set_text(text)
/// }
/// ItemKind::Icon => {
/// let i = resources_table.get::<IconMenuItem<R>>(rid)?;
/// i.set_text(text)
/// }
/// _ => return Err(crate::Error::UnexpectedMenuKind),
/// }
/// ```
#[doc(hidden)]
#[proc_macro]
pub fn do_menu_item(input: TokenStream) -> TokenStream {
let tokens = parse_macro_input!(input as menu::DoMenuItemInput);
menu::do_menu_item(tokens).into()
}
/// Convert a .png or .ico icon to an Image
/// for things like `tauri::tray::TrayIconBuilder` to consume,
/// relative paths are resolved from `CARGO_MANIFEST_DIR`, not current file
///
/// ### Examples
///
/// ```ignore
/// const APP_ICON: Image<'_> = include_image!("./icons/32x32.png");
///
/// // then use it with tray
/// TrayIconBuilder::new().icon(APP_ICON).build().unwrap();
///
/// // or with window
/// WebviewWindowBuilder::new(app, "main", WebviewUrl::default())
/// .icon(APP_ICON)
/// .unwrap()
/// .build()
/// .unwrap();
///
/// // or with any other functions that takes `Image` struct
/// ```
///
/// Note: this stores the image in raw pixels to the final binary,
/// so keep the icon size (width and height) small
/// or else it's going to bloat your final executable
#[proc_macro]
pub fn include_image(tokens: TokenStream) -> TokenStream {
let path = match parse2::<LitStr>(tokens.into()) {
Ok(path) => path,
Err(err) => return err.into_compile_error().into(),
};
let path = PathBuf::from(path.value());
let resolved_path = if path.is_relative() {
if let Ok(base_dir) = std::env::var("CARGO_MANIFEST_DIR").map(PathBuf::from) {
base_dir.join(path)
} else {
return quote!(compile_error!("$CARGO_MANIFEST_DIR is not defined")).into();
}
} else {
path
};
if !resolved_path.exists() {
let error_string = format!(
"Provided Image path \"{}\" doesn't exists",
resolved_path.display()
);
return quote!(compile_error!(#error_string)).into();
}
match CachedIcon::new(&quote!(::tauri), &resolved_path).map_err(|error| error.to_string()) {
Ok(icon) => icon.into_token_stream(),
Err(error) => quote!(compile_error!(#error)),
}
.into()
}

View File

@@ -0,0 +1,136 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
use syn::{
Expr, Token,
parse::{Parse, ParseStream},
punctuated::Punctuated,
};
pub struct DoMenuItemInput {
resources_table: Ident,
rid: Ident,
kind: Ident,
var: Ident,
expr: Expr,
kinds: Vec<NegatedIdent>,
}
#[derive(Clone)]
struct NegatedIdent {
negated: bool,
ident: Ident,
}
impl NegatedIdent {
fn new(ident: &str) -> Self {
Self {
negated: false,
ident: Ident::new(ident, Span::call_site()),
}
}
fn is_negated(&self) -> bool {
self.negated
}
}
impl Parse for NegatedIdent {
fn parse(input: ParseStream) -> syn::Result<Self> {
let negated_token = input.parse::<Token![!]>();
let ident: Ident = input.parse()?;
Ok(NegatedIdent {
negated: negated_token.is_ok(),
ident,
})
}
}
impl Parse for DoMenuItemInput {
fn parse(input: ParseStream) -> syn::Result<Self> {
let resources_table: Ident = input.parse()?;
let _: Token![,] = input.parse()?;
let rid: Ident = input.parse()?;
let _: Token![,] = input.parse()?;
let kind: Ident = input.parse()?;
let _: Token![,] = input.parse()?;
let _: Token![|] = input.parse()?;
let var: Ident = input.parse()?;
let _: Token![|] = input.parse()?;
let expr: Expr = input.parse()?;
let _: syn::Result<Token![,]> = input.parse();
let kinds = Punctuated::<NegatedIdent, Token![|]>::parse_terminated(input)?;
Ok(Self {
resources_table,
rid,
kind,
var,
expr,
kinds: kinds.into_iter().collect(),
})
}
}
pub fn do_menu_item(input: DoMenuItemInput) -> TokenStream {
let DoMenuItemInput {
rid,
resources_table,
kind,
expr,
var,
mut kinds,
} = input;
let defaults = vec![
NegatedIdent::new("Submenu"),
NegatedIdent::new("MenuItem"),
NegatedIdent::new("Predefined"),
NegatedIdent::new("Check"),
NegatedIdent::new("Icon"),
];
if kinds.is_empty() {
kinds.extend(defaults.clone());
}
let has_negated = kinds.iter().any(|n| n.is_negated());
if has_negated {
kinds.extend(defaults);
kinds.sort_by(|a, b| a.ident.cmp(&b.ident));
kinds.dedup_by(|a, b| a.ident == b.ident);
}
let (kinds, types): (Vec<Ident>, Vec<Ident>) = kinds
.into_iter()
.filter_map(|nident| {
if nident.is_negated() {
None
} else {
match nident.ident {
i if i == "MenuItem" => Some((i, Ident::new("MenuItem", Span::call_site()))),
i if i == "Submenu" => Some((i, Ident::new("Submenu", Span::call_site()))),
i if i == "Predefined" => Some((i, Ident::new("PredefinedMenuItem", Span::call_site()))),
i if i == "Check" => Some((i, Ident::new("CheckMenuItem", Span::call_site()))),
i if i == "Icon" => Some((i, Ident::new("IconMenuItem", Span::call_site()))),
_ => None,
}
}
})
.unzip();
quote! {
match #kind {
#(
ItemKind::#kinds => {
let #var = #resources_table.get::<#types<R>>(#rid)?;
#expr
}
)*
_ => return Err(crate::Error::UnexpectedMenuKind),
}
}
}

View File

@@ -0,0 +1,95 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use std::env::var;
use syn::{ItemFn, parse_macro_input, spanned::Spanned};
fn get_env_var(name: &str, error: &mut Option<TokenStream2>, function: &ItemFn) -> TokenStream2 {
match var(name) {
Ok(value) => {
let ident = format_ident!("{value}");
quote!(#ident)
}
Err(_) => {
error.replace(
syn::Error::new(
function.span(),
format!("`{name}` env var not set, do you have a build script with tauri-build?",),
)
.into_compile_error(),
);
quote!()
}
}
}
pub fn entry_point(_attributes: TokenStream, item: TokenStream) -> TokenStream {
let function = parse_macro_input!(item as ItemFn);
let function_name = function.sig.ident.clone();
let mut error = None;
let domain = get_env_var("TAURI_ANDROID_PACKAGE_NAME_PREFIX", &mut error, &function);
let app_name = get_env_var("TAURI_ANDROID_PACKAGE_NAME_APP_NAME", &mut error, &function);
let (wrapper, wrapper_name) = if function.sig.asyncness.is_some() {
let wrapper_name = syn::Ident::new(&format!("{function_name}_wrapper"), function_name.span());
(
quote! {
#function
fn #wrapper_name() {
::tauri::async_runtime::block_on(#function_name());
}
},
wrapper_name,
)
} else {
(
quote! {
#function
},
function_name,
)
};
if let Some(e) = error {
quote!(#e).into()
} else {
quote!(
fn stop_unwind<F: FnOnce() -> T, T>(f: F) -> T {
match std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)) {
Ok(t) => t,
Err(err) => {
eprintln!("attempt to unwind out of `rust` with err: {:?}", err);
std::process::abort()
}
}
}
#wrapper
fn _start_app() {
#[cfg(target_os = "ios")]
::tauri::log_stdout();
#[cfg(target_os = "android")]
{
::tauri::android_binding!(#domain, #app_name, _start_app, ::tauri::wry);
}
stop_unwind(#wrapper_name);
}
// be careful when renaming this, the `start_app` symbol is checked by the CLI
#[cfg(not(target_os = "android"))]
#[unsafe(no_mangle)]
#[inline(never)]
pub extern "C" fn start_app() {
_start_app()
}
)
.into()
}
}

View File

@@ -0,0 +1,105 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
use proc_macro2::TokenStream;
use quote::{ToTokens, quote};
use syn::parse::{Parse, ParseStream};
use syn::{
DeriveInput, Error, GenericParam, Ident, ItemTrait, ItemType, Token, Type, TypeParam, parse_quote,
};
#[derive(Clone)]
pub(crate) enum Input {
Derive(DeriveInput),
Trait(ItemTrait),
Type(ItemType),
}
impl Parse for Input {
fn parse(input: ParseStream) -> syn::Result<Self> {
input
.parse::<DeriveInput>()
.map(Self::Derive)
.or_else(|_| input.parse().map(Self::Trait))
.or_else(|_| input.parse().map(Self::Type))
.map_err(|_| {
Error::new(
input.span(),
"default_runtime only supports `struct`, `enum`, `type`, or `trait` definitions",
)
})
}
}
impl Input {
fn last_param_mut(&mut self) -> Option<&mut GenericParam> {
match self {
Input::Derive(d) => d.generics.params.last_mut(),
Input::Trait(t) => t.generics.params.last_mut(),
Input::Type(t) => t.generics.params.last_mut(),
}
}
}
impl ToTokens for Input {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
Input::Derive(d) => d.to_tokens(tokens),
Input::Trait(t) => t.to_tokens(tokens),
Input::Type(t) => t.to_tokens(tokens),
}
}
}
/// The default runtime type to enable when the provided feature is enabled.
pub(crate) struct Attributes {
default_type: Type,
feature: Ident,
}
impl Parse for Attributes {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let default_type = input.parse()?;
input.parse::<Token![,]>()?;
Ok(Attributes {
default_type,
feature: input.parse()?,
})
}
}
pub(crate) fn default_runtime(attributes: Attributes, input: Input) -> TokenStream {
// create a new copy to manipulate for the wry feature flag
let mut wry = input.clone();
let wry_runtime = wry
.last_param_mut()
.expect("default_runtime requires the item to have at least 1 generic parameter");
// set the default value of the last generic parameter to the provided runtime type
match wry_runtime {
GenericParam::Type(
param @ TypeParam {
eq_token: None,
default: None,
..
},
) => {
param.eq_token = Some(parse_quote!(=));
param.default = Some(attributes.default_type);
}
_ => {
panic!("DefaultRuntime requires the last parameter to not have a default value")
}
};
let feature = attributes.feature.to_string();
quote!(
#[cfg(feature = #feature)]
#wry
#[cfg(not(feature = #feature))]
#input
)
}