diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 28565bb94..b7dbd5eea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,16 +19,12 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - profile: minimal + uses: dtolnay/rust-toolchain@stable - name: Rust cache uses: Swatinem/rust-cache@v2 @@ -49,16 +45,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - toolchain: 1.70.0 - override: true - profile: minimal + uses: dtolnay/rust-toolchain@1.70.0 - name: Rust cache uses: Swatinem/rust-cache@v2 @@ -76,15 +68,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - name: Install Rust - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@stable with: - toolchain: stable - override: true components: rustfmt, clippy - name: Rust cache diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5cc781b06..8219cd1cc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,26 +8,20 @@ jobs: create-release: name: Create Release runs-on: ubuntu-latest - outputs: - upload_url: ${{ steps.create_release.outputs.upload_url }} steps: + - uses: actions/checkout@v4 - name: Create Release - id: create_release - uses: actions/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: ${{ github.ref }} - draft: true - prerelease: false + run: | + gh release create ${{ github.ref_name }} --draft --verify-tag --title ${{ github.ref_name }} build-plugin: needs: ["create-release"] name: Build Roblox Studio Plugin runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true @@ -42,17 +36,13 @@ jobs: run: rojo build plugin --output Rojo.rbxm - name: Upload Plugin to Release - uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.create-release.outputs.upload_url }} - asset_path: Rojo.rbxm - asset_name: Rojo.rbxm - asset_content_type: application/octet-stream + run: | + gh release upload ${{ github.ref_name }} Rojo.rbxm - name: Upload Plugin to Artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Rojo.rbxm path: Rojo.rbxm @@ -89,24 +79,14 @@ jobs: env: BIN: rojo steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - - name: Get Version from Tag - shell: bash - # https://github.community/t/how-to-get-just-the-tag-name/16241/7#M1027 - run: | - echo "PROJECT_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV - echo "Version is: ${{ env.PROJECT_VERSION }}" - - name: Install Rust - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@stable with: - toolchain: stable - target: ${{ matrix.target }} - override: true - profile: minimal + targets: ${{ matrix.target }} - name: Setup Aftman uses: ok-nick/setup-aftman@v0.1.0 @@ -122,37 +102,34 @@ jobs: # easily. CARGO_TARGET_DIR: output - # On platforms that use OpenSSL, ensure it is statically linked to - # make binaries more portable. - OPENSSL_STATIC: 1 + - name: Generate Artifact Name + shell: bash + env: + TAG_NAME: ${{ github.ref_name }} + run: | + echo "ARTIFACT_NAME=$BIN-${TAG_NAME#v}-${{ matrix.label }}.zip" >> "$GITHUB_ENV" - - name: Create Release Archive + - name: Create Archive and Upload to Release shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | mkdir staging if [ "${{ matrix.host }}" = "windows" ]; then cp "output/${{ matrix.target }}/release/$BIN.exe" staging/ cd staging - 7z a ../release.zip * + 7z a ../$ARTIFACT_NAME * else cp "output/${{ matrix.target }}/release/$BIN" staging/ cd staging - zip ../release.zip * + zip ../$ARTIFACT_NAME * fi - - name: Upload Archive to Release - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.create-release.outputs.upload_url }} - asset_path: release.zip - asset_name: ${{ env.BIN }}-${{ env.PROJECT_VERSION }}-${{ matrix.label }}.zip - asset_content_type: application/octet-stream + gh release upload ${{ github.ref_name }} ../$ARTIFACT_NAME - name: Upload Archive to Artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: ${{ env.BIN }}-${{ env.PROJECT_VERSION }}-${{ matrix.label }}.zip - path: release.zip \ No newline at end of file + path: ${{ env.ARTIFACT_NAME }} + name: ${{ env.ARTIFACT_NAME }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 97ccb4053..ad9b44bbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,12 +20,15 @@ This is a very rough implementation and the usage will become more ergonomic over time. -* Rojo now converts any line endings to LF, preventing spurious diffs when syncing Lua files on Windows ([#854]) -* Fixed Rojo plugin failing to connect when project contains certain unreadable properties ([#848]) +* Updated Undo/Redo history to be more robust ([#915]) +* Fixed removing trailing newlines ([#903]) +* Added Never option to Confirmation ([#893]) * Added popout diff visualizer for table properties like Attributes and Tags ([#834]) * Updated Theme to use Studio colors ([#838]) +* Improved patch visualizer UX ([#883]) * Added experimental setting for Auto Connect in playtests ([#840]) -* Fixed http error handling so Rojo can be used in Github Codespaces ([#847]) +* Improved settings UI ([#886]) +* `Open Scripts Externally` option can now be changed while syncing ([#911]) * Projects may now specify rules for syncing files as if they had a different file extension. ([#813]) This is specified via a new field on project files, `syncRules`: @@ -77,10 +80,36 @@ [#834]: https://github.com/rojo-rbx/rojo/pull/834 [#838]: https://github.com/rojo-rbx/rojo/pull/838 [#840]: https://github.com/rojo-rbx/rojo/pull/840 -[#847]: https://github.com/rojo-rbx/rojo/pull/847 +[#843]: https://github.com/rojo-rbx/rojo/pull/843 +[#883]: https://github.com/rojo-rbx/rojo/pull/883 +[#886]: https://github.com/rojo-rbx/rojo/pull/886 +[#893]: https://github.com/rojo-rbx/rojo/pull/893 +[#903]: https://github.com/rojo-rbx/rojo/pull/903 +[#911]: https://github.com/rojo-rbx/rojo/pull/911 +[#915]: https://github.com/rojo-rbx/rojo/pull/915 + +## [7.4.1] - February 20, 2024 +* Made the `name` field optional on project files ([#870]) + + Files named `default.project.json` inherit the name of the folder they're in and all other projects + are named as expect (e.g. `foo.project.json` becomes an Instance named `foo`) + + There is no change in behavior if `name` is set. +* Fixed incorrect results when building model pivots ([#865]) +* Fixed incorrect results when serving model pivots ([#868]) +* Rojo now converts any line endings to LF, preventing spurious diffs when syncing Lua files on Windows ([#854]) +* Fixed Rojo plugin failing to connect when project contains certain unreadable properties ([#848]) +* Fixed various cases where patch visualizer would not display sync failures ([#845], [#844]) +* Fixed http error handling so Rojo can be used in Github Codespaces ([#847]) + [#848]: https://github.com/rojo-rbx/rojo/pull/848 +[#845]: https://github.com/rojo-rbx/rojo/pull/845 +[#844]: https://github.com/rojo-rbx/rojo/pull/844 +[#847]: https://github.com/rojo-rbx/rojo/pull/847 [#854]: https://github.com/rojo-rbx/rojo/pull/854 -[#843]: https://github.com/rojo-rbx/rojo/pull/843 +[#865]: https://github.com/rojo-rbx/rojo/pull/865 +[#868]: https://github.com/rojo-rbx/rojo/pull/868 +[#870]: https://github.com/rojo-rbx/rojo/pull/870 ## [7.4.0] - January 16, 2024 * Improved the visualization for array properties like Tags ([#829]) diff --git a/Cargo.lock b/Cargo.lock index 3e2556f20..1b2ae1809 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,18 +19,18 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "arrayref" @@ -84,9 +84,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bincode" @@ -105,9 +105,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "blake3" @@ -133,26 +133,26 @@ dependencies = [ [[package]] name = "bstr" -version = "1.6.2" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", - "regex-automata 0.3.9", + "regex-automata 0.4.6", "serde", ] [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -168,12 +168,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723" [[package]] name = "cfg-if" @@ -208,11 +205,11 @@ dependencies = [ "bitflags 1.3.2", "clap_derive", "clap_lex", - "indexmap", + "indexmap 1.9.3", "once_cell", "strsim", "termcolor", - "textwrap 0.16.0", + "textwrap 0.16.1", ] [[package]] @@ -223,8 +220,8 @@ checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck", "proc-macro-error", - "proc-macro2 1.0.67", - "quote 1.0.33", + "proc-macro2 1.0.78", + "quote 1.0.35", "syn 1.0.109", ] @@ -239,14 +236,14 @@ dependencies = [ [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] @@ -257,9 +254,9 @@ checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -267,15 +264,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -318,46 +315,37 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ - "cfg-if 1.0.0", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if 1.0.0", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if 1.0.0", "crossbeam-utils", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if 1.0.0", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crypto-common" @@ -429,9 +417,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "embed-resource" @@ -475,24 +463,19 @@ dependencies = [ ] [[package]] -name = "errno" -version = "0.3.4" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "errno" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] @@ -503,14 +486,14 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.3.5", - "windows-sys 0.48.0", + "redox_syscall", + "windows-sys 0.52.0", ] [[package]] @@ -519,35 +502,23 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "fs-err" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] [[package]] name = "fsevent" @@ -586,9 +557,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -601,9 +572,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -611,15 +582,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -628,38 +599,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ - "proc-macro2 1.0.67", - "quote 1.0.33", - "syn 2.0.37", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.52", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -698,9 +669,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if 1.0.0", "libc", @@ -709,28 +680,28 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "globset" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" dependencies = [ "aho-corasick", "bstr", - "fnv", "log", - "regex", + "regex-automata 0.4.6", + "regex-syntax 0.8.2", ] [[package]] name = "h2" -version = "0.3.21" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -738,7 +709,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 2.2.5", "slab", "tokio", "tokio-util", @@ -747,9 +718,9 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "hashbrown" @@ -757,6 +728,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "heck" version = "0.4.1" @@ -774,9 +751,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "htmlescape" @@ -786,9 +763,9 @@ checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" [[package]] name = "http" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -797,9 +774,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -826,9 +803,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -841,7 +818,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2", "tokio", "tower-service", "tracing", @@ -849,23 +826,24 @@ dependencies = [ ] [[package]] -name = "hyper-tls" -version = "0.5.0" +name = "hyper-rustls" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ - "bytes", + "futures-util", + "http", "hyper", - "native-tls", + "rustls", "tokio", - "tokio-native-tls", + "tokio-rustls", ] [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -878,7 +856,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", ] [[package]] @@ -903,9 +891,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.33.0" +version = "1.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aa511b2e298cd49b1856746f6bb73e17036bcd66b25f5e92cdcdbec9bd75686" +checksum = "0a7c22c4d34ef4788c351e971c52bfdfe7ea2766f8c5466bc175dd46e52ac22e" dependencies = [ "console", "lazy_static", @@ -928,9 +916,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itertools" @@ -943,9 +931,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jod-thread" @@ -955,9 +943,9 @@ checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -986,9 +974,20 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libredox" +version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall", +] [[package]] name = "linked-hash-map" @@ -998,21 +997,21 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.8" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "loom" -version = "0.5.6" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +checksum = "7e045d70ddfbc984eacfa964ded019534e8f6cbf36f6410aee0ed5cefa5a9175" dependencies = [ "cfg-if 1.0.0", "generator", @@ -1058,22 +1057,13 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "memoffset" -version = "0.9.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "memofs" -version = "0.2.0" +version = "0.3.0" dependencies = [ "crossbeam-channel", "fs-err", @@ -1089,9 +1079,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] @@ -1117,9 +1107,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi", @@ -1150,24 +1140,6 @@ dependencies = [ "ws2_32-sys", ] -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "net2" version = "0.2.39" @@ -1209,9 +1181,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] @@ -1222,24 +1194,24 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi 0.3.9", "libc", ] [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" @@ -1257,65 +1229,11 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "openssl" -version = "0.10.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" -dependencies = [ - "bitflags 2.4.0", - "cfg-if 1.0.0", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2 1.0.67", - "quote 1.0.33", - "syn 2.0.37", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "300.1.5+3.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559068e4c12950d7dcaa1857a61725c0d38d4fc03ff8e070ab31a75d6e316491" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - [[package]] name = "os_str_bytes" -version = "6.5.1" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "overload" @@ -1331,15 +1249,15 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.4" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" +checksum = "56f8023d0fb78c8e03784ea1c7f3fa36e68a723138990b8d5a47d916b651e7a8" dependencies = [ "memchr", "thiserror", @@ -1348,9 +1266,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.4" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8" +checksum = "b0d24f72393fd16ab6ac5738bc33cdb6a9aa73f8b902e8fe29cf4e67d7dd1026" dependencies = [ "pest", "pest_generator", @@ -1358,22 +1276,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.4" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a" +checksum = "fdc17e2a6c7d0a492f0158d7a4bd66cc17280308bbaff78d5bef566dca35ab80" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.67", - "quote 1.0.33", - "syn 2.0.37", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.52", ] [[package]] name = "pest_meta" -version = "2.7.4" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d" +checksum = "934cd7631c050f4674352a6e835d5f6711ffbfb9345c2fc0107155ac495ae293" dependencies = [ "once_cell", "pest", @@ -1392,12 +1310,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - [[package]] name = "plotters" version = "0.3.5" @@ -1449,8 +1361,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.67", - "quote 1.0.33", + "proc-macro2 1.0.78", + "quote 1.0.35", "syn 1.0.109", "version_check", ] @@ -1461,8 +1373,8 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.67", - "quote 1.0.33", + "proc-macro2 1.0.78", + "quote 1.0.35", "version_check", ] @@ -1489,31 +1401,31 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "profiling" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89dff0959d98c9758c88826cc002e2c3d0b9dfac4139711d1f30de442f1139b" +checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" dependencies = [ "profiling-procmacros", - "tracy-client 0.16.3", + "tracy-client", ] [[package]] name = "profiling-procmacros" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb156a45b6b9fe8027497422179fb65afc84d36707a7ca98297bf06bccb8d43f" +checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" dependencies = [ - "quote 1.0.33", - "syn 2.0.37", + "quote 1.0.35", + "syn 2.0.52", ] [[package]] @@ -1527,11 +1439,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ - "proc-macro2 1.0.67", + "proc-macro2 1.0.78", ] [[package]] @@ -1566,9 +1478,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", @@ -1576,9 +1488,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -1663,43 +1575,34 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] [[package]] name = "regex" -version = "1.9.6" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.9", - "regex-syntax 0.7.5", + "regex-automata 0.4.6", + "regex-syntax 0.8.2", ] [[package]] @@ -1713,13 +1616,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.9" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", + "regex-syntax 0.8.2", ] [[package]] @@ -1730,17 +1633,17 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" dependencies = [ - "base64 0.21.4", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -1749,29 +1652,47 @@ dependencies = [ "http", "http-body", "hyper", - "hyper-tls", + "hyper-rustls", "ipnet", "js-sys", "log", "mime", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", + "rustls", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", - "tokio-native-tls", + "tokio-rustls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots", "winreg 0.50.0", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if 1.0.0", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "ritz" version = "0.1.0" @@ -1876,7 +1797,6 @@ dependencies = [ "thiserror", "tokio", "toml", - "tracy-client 0.13.2", "uuid", "walkdir", "winreg 0.10.1", @@ -1907,15 +1827,46 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.20" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.2", "errno", "libc", "linux-raw-sys", - "windows-sys 0.48.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", ] [[package]] @@ -1926,9 +1877,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" @@ -1939,15 +1890,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" -dependencies = [ - "windows-sys 0.48.0", -] - [[package]] name = "scoped-tls" version = "1.0.1" @@ -1955,45 +1897,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" +name = "sct" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "core-foundation-sys", - "libc", + "ring", + "untrusted", ] [[package]] name = "semver" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.188" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -2010,20 +1933,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ - "proc-macro2 1.0.67", - "quote 1.0.33", - "syn 2.0.37", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.52", ] [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -2048,7 +1971,7 @@ version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" dependencies = [ - "indexmap", + "indexmap 1.9.3", "ryu", "serde", "yaml-rust", @@ -2067,18 +1990,18 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b21f559e07218024e7e9f90f96f601825397de0e25420135f7f952453fed0b" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] [[package]] name = "similar" -version = "2.2.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" +checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" [[package]] name = "slab" @@ -2091,9 +2014,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "snax" @@ -2106,23 +2029,19 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.9" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "winapi 0.3.9", + "windows-sys 0.52.0", ] [[package]] -name = "socket2" -version = "0.5.4" +name = "spin" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "strsim" @@ -2136,22 +2055,28 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.67", - "quote 1.0.33", + "proc-macro2 1.0.78", + "quote 1.0.35", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.37" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ - "proc-macro2 1.0.67", - "quote 1.0.33", + "proc-macro2 1.0.78", + "quote 1.0.35", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "system-configuration" version = "0.5.1" @@ -2175,22 +2100,21 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if 1.0.0", "fastrand", - "redox_syscall 0.3.5", "rustix", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -2206,35 +2130,35 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.49" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.49" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ - "proc-macro2 1.0.67", - "quote 1.0.33", - "syn 2.0.37", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.52", ] [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if 1.0.0", "once_cell", @@ -2267,35 +2191,35 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.32.0" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", "bytes", "libc", - "mio 0.8.8", + "mio 0.8.11", "num_cpus", "pin-project-lite", - "socket2 0.5.4", + "socket2", "windows-sys 0.48.0", ] [[package]] -name = "tokio-native-tls" -version = "0.3.1" +name = "tokio-rustls" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "native-tls", + "rustls", "tokio", ] [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -2322,11 +2246,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if 1.0.0", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2334,20 +2257,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.67", - "quote 1.0.33", - "syn 2.0.37", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.52", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -2355,20 +2278,20 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -2384,49 +2307,29 @@ dependencies = [ [[package]] name = "tracy-client" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ebfe7a24c18b5ba86d8920c124b41b942352f863fbe0c84d3d63428fa1860f" -dependencies = [ - "loom", - "once_cell", - "tracy-client-sys 0.17.1", -] - -[[package]] -name = "tracy-client" -version = "0.16.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03684af8fb393cc7903210d868e4cb9f5c1e156737be38f52c4217fb21b86bf6" +checksum = "59fb931a64ff88984f86d3e9bcd1ae8843aa7fe44dd0f8097527bc172351741d" dependencies = [ "loom", "once_cell", - "tracy-client-sys 0.21.2", + "tracy-client-sys", ] [[package]] name = "tracy-client-sys" -version = "0.17.1" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "178d021455e83078bb38c00b70046b95117ef0a0312cbef925f426d833d11c79" -dependencies = [ - "cc", -] - -[[package]] -name = "tracy-client-sys" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb915ea3af048554640d76dd6f1492589a6401a41a30d789b983c1ec280455a" +checksum = "9d104d610dfa9dd154535102cc9c6164ae1fa37842bc2d9e83f9ac82b0ae0882" dependencies = [ "cc", ] [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" @@ -2442,9 +2345,9 @@ checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -2454,9 +2357,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -2473,11 +2376,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -2486,9 +2395,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.4.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" dependencies = [ "getrandom", "serde", @@ -2500,12 +2409,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.4" @@ -2534,9 +2437,9 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -2559,9 +2462,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -2569,24 +2472,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.67", - "quote 1.0.33", - "syn 2.0.37", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.52", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -2596,43 +2499,49 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ - "quote 1.0.33", + "quote 1.0.35", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ - "proc-macro2 1.0.67", - "quote 1.0.33", - "syn 2.0.37", + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.52", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + [[package]] name = "winapi" version = "0.2.8" @@ -2685,15 +2594,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -2704,18 +2604,12 @@ dependencies = [ ] [[package]] -name = "windows-targets" -version = "0.42.2" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets 0.52.4", ] [[package]] @@ -2734,10 +2628,19 @@ dependencies = [ ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" +name = "windows-targets" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] [[package]] name = "windows_aarch64_gnullvm" @@ -2746,10 +2649,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" +name = "windows_aarch64_gnullvm" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -2758,10 +2661,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] -name = "windows_i686_gnu" -version = "0.42.2" +name = "windows_aarch64_msvc" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -2770,10 +2673,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] -name = "windows_i686_msvc" -version = "0.42.2" +name = "windows_i686_gnu" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -2782,10 +2685,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" +name = "windows_i686_msvc" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -2794,10 +2697,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" +name = "windows_x86_64_gnu" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -2806,10 +2709,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" +name = "windows_x86_64_gnullvm" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -2817,6 +2720,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + [[package]] name = "winreg" version = "0.6.2" diff --git a/Cargo.toml b/Cargo.toml index 0b5ae9e68..a35ccd942 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,9 @@ default = [] # Enable this feature to live-reload assets from the web UI. dev_live_assets = [] -profile-with-tracy = ["profiling/profile-with-tracy", "tracy-client"] +# Run Rojo with this feature to open a Tracy session. +# Currently uses protocol v63, last supported in Tracy 0.9.1. +profile-with-tracy = ["profiling/profile-with-tracy"] [workspace] members = ["crates/*"] @@ -40,7 +42,7 @@ name = "build" harness = false [dependencies] -memofs = { version = "0.2.0", path = "crates/memofs" } +memofs = { version = "0.3.0", path = "crates/memofs" } # These dependencies can be uncommented when working on rbx-dom simultaneously # rbx_binary = { path = "../rbx-dom/rbx_binary" } @@ -55,61 +57,60 @@ rbx_reflection = "4.5.0" rbx_reflection_database = "0.2.10" rbx_xml = "0.13.3" -anyhow = "1.0.44" -backtrace = "0.3.61" +anyhow = "1.0.80" +backtrace = "0.3.69" bincode = "1.3.3" -crossbeam-channel = "0.5.1" -csv = "1.1.6" -env_logger = "0.9.0" -fs-err = "2.6.0" -futures = "0.3.17" -globset = "0.4.8" +crossbeam-channel = "0.5.12" +csv = "1.3.0" +env_logger = "0.9.3" +fs-err = "2.11.0" +futures = "0.3.30" +globset = "0.4.14" humantime = "2.1.0" -hyper = { version = "0.14.13", features = ["server", "tcp", "http1"] } +hyper = { version = "0.14.28", features = ["server", "tcp", "http1"] } jod-thread = "0.1.2" -log = "0.4.14" +log = "0.4.21" maplit = "1.0.2" -num_cpus = "1.15.0" -opener = "0.5.0" -rayon = "1.7.0" -reqwest = { version = "0.11.10", features = [ +num_cpus = "1.16.0" +opener = "0.5.2" +rayon = "1.9.0" +reqwest = { version = "0.11.24", default-features = false, features = [ "blocking", "json", - "native-tls-vendored", + "rustls-tls", ] } ritz = "0.1.0" roblox_install = "1.0.0" -serde = { version = "1.0.130", features = ["derive", "rc"] } -serde_json = "1.0.68" -toml = "0.5.9" -termcolor = "1.1.2" -thiserror = "1.0.30" -tokio = { version = "1.12.0", features = ["rt", "rt-multi-thread"] } -uuid = { version = "1.0.0", features = ["v4", "serde"] } -clap = { version = "3.1.18", features = ["derive"] } -profiling = "1.0.6" -tracy-client = { version = "0.13.2", optional = true } +serde = { version = "1.0.197", features = ["derive", "rc"] } +serde_json = "1.0.114" +toml = "0.5.11" +termcolor = "1.4.1" +thiserror = "1.0.57" +tokio = { version = "1.36.0", features = ["rt", "rt-multi-thread"] } +uuid = { version = "1.7.0", features = ["v4", "serde"] } +clap = { version = "3.2.25", features = ["derive"] } +profiling = "1.0.15" [target.'cfg(windows)'.dependencies] winreg = "0.10.1" [build-dependencies] -memofs = { version = "0.2.0", path = "crates/memofs" } +memofs = { version = "0.3.0", path = "crates/memofs" } -embed-resource = "1.6.4" -anyhow = "1.0.44" +embed-resource = "1.8.0" +anyhow = "1.0.80" bincode = "1.3.3" -fs-err = "2.6.0" +fs-err = "2.11.0" maplit = "1.0.2" -semver = "1.0.19" +semver = "1.0.22" [dev-dependencies] rojo-insta-ext = { path = "crates/rojo-insta-ext" } -criterion = "0.3.5" -insta = { version = "1.8.0", features = ["redactions", "yaml"] } -paste = "1.0.5" -pretty_assertions = "1.2.1" -serde_yaml = "0.8.21" -tempfile = "3.2.0" -walkdir = "2.3.2" +criterion = "0.3.6" +insta = { version = "1.36.1", features = ["redactions", "yaml"] } +paste = "1.0.14" +pretty_assertions = "1.4.0" +serde_yaml = "0.8.26" +tempfile = "3.10.1" +walkdir = "2.5.0" diff --git a/README.md b/README.md index bbdeba30a..bb4effcf9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
- Rojo + Rojo
 
@@ -43,4 +43,4 @@ Pull requests are welcome! Rojo supports Rust 1.70.0 and newer. The minimum supported version of Rust is based on the latest versions of the dependencies that Rojo has. ## License -Rojo is available under the terms of the Mozilla Public License, Version 2.0. See [LICENSE.txt](LICENSE.txt) for details. \ No newline at end of file +Rojo is available under the terms of the Mozilla Public License, Version 2.0. See [LICENSE.txt](LICENSE.txt) for details. diff --git a/assets/icon-32.png b/assets/brand_images/icon-32.png similarity index 100% rename from assets/icon-32.png rename to assets/brand_images/icon-32.png diff --git a/assets/icon-link-32.png b/assets/brand_images/icon-link-32.png similarity index 100% rename from assets/icon-link-32.png rename to assets/brand_images/icon-link-32.png diff --git a/assets/icon-warn-32.png b/assets/brand_images/icon-warn-32.png similarity index 100% rename from assets/icon-warn-32.png rename to assets/brand_images/icon-warn-32.png diff --git a/assets/logo-512.png b/assets/brand_images/logo-512.png similarity index 100% rename from assets/logo-512.png rename to assets/brand_images/logo-512.png diff --git a/assets/images/back.png b/assets/images/icons/back.png similarity index 100% rename from assets/images/back.png rename to assets/images/icons/back.png diff --git a/assets/images/back.svg b/assets/images/icons/back.svg similarity index 100% rename from assets/images/back.svg rename to assets/images/icons/back.svg diff --git a/assets/images/close.png b/assets/images/icons/close.png similarity index 100% rename from assets/images/close.png rename to assets/images/icons/close.png diff --git a/assets/images/close.svg b/assets/images/icons/close.svg similarity index 100% rename from assets/images/close.svg rename to assets/images/icons/close.svg diff --git a/assets/images/icons/debug.png b/assets/images/icons/debug.png new file mode 100644 index 000000000..b2217f0cc Binary files /dev/null and b/assets/images/icons/debug.png differ diff --git a/assets/images/icons/expand.png b/assets/images/icons/expand.png new file mode 100644 index 000000000..fcf561dcd Binary files /dev/null and b/assets/images/icons/expand.png differ diff --git a/assets/images/icons/reset.png b/assets/images/icons/reset.png new file mode 100644 index 000000000..802e430a1 Binary files /dev/null and b/assets/images/icons/reset.png differ diff --git a/assets/images/icons/warning.png b/assets/images/icons/warning.png new file mode 100644 index 000000000..79d457df0 Binary files /dev/null and b/assets/images/icons/warning.png differ diff --git a/assets/round-rect-4px-radius.png b/assets/images/round-rect-4px-radius.png similarity index 100% rename from assets/round-rect-4px-radius.png rename to assets/images/round-rect-4px-radius.png diff --git a/assets/images/syncsuccess.png b/assets/images/syncsuccess.png new file mode 100644 index 000000000..74958cc13 Binary files /dev/null and b/assets/images/syncsuccess.png differ diff --git a/assets/images/syncwarning.png b/assets/images/syncwarning.png new file mode 100644 index 000000000..eafb93d36 Binary files /dev/null and b/assets/images/syncwarning.png differ diff --git a/crates/memofs/CHANGELOG.md b/crates/memofs/CHANGELOG.md index d678f8c9d..44c3aa507 100644 --- a/crates/memofs/CHANGELOG.md +++ b/crates/memofs/CHANGELOG.md @@ -1,6 +1,8 @@ # memofs Changelog ## Unreleased Changes + +## 0.3.0 (2024-03-15) * Changed `StdBackend` file watching component to use minimal recursive watches. [#830] * Added `Vfs::read_to_string` and `Vfs::read_to_string_lf_normalized` [#854] diff --git a/crates/memofs/Cargo.toml b/crates/memofs/Cargo.toml index 5cf5a7334..57633ae4f 100644 --- a/crates/memofs/Cargo.toml +++ b/crates/memofs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "memofs" description = "Virtual filesystem with configurable backends." -version = "0.2.0" +version = "0.3.0" authors = ["Lucien Greathouse "] edition = "2018" readme = "README.md" @@ -11,7 +11,7 @@ homepage = "https://github.com/rojo-rbx/rojo/tree/master/memofs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -crossbeam-channel = "0.5.1" -fs-err = "2.3.0" -notify = "4.0.15" -serde = { version = "1.0", features = ["derive"] } +crossbeam-channel = "0.5.12" +fs-err = "2.11.0" +notify = "4.0.17" +serde = { version = "1.0.197", features = ["derive"] } diff --git a/crates/memofs/src/lib.rs b/crates/memofs/src/lib.rs index 6d41c853b..7a348ff60 100644 --- a/crates/memofs/src/lib.rs +++ b/crates/memofs/src/lib.rs @@ -300,7 +300,7 @@ impl Vfs { let path = path.as_ref(); let contents = self.inner.lock().unwrap().read_to_string(path)?; - Ok(contents.lines().collect::>().join("\n").into()) + Ok(contents.replace("\r\n", "\n").into()) } /// Write a file to the VFS and the underlying backend. @@ -473,3 +473,23 @@ impl VfsLock<'_> { self.inner.commit_event(event) } } + +#[cfg(test)] +mod test { + use crate::{InMemoryFs, Vfs, VfsSnapshot}; + + /// https://github.com/rojo-rbx/rojo/issues/899 + #[test] + fn read_to_string_lf_normalized_keeps_trailing_newline() { + let mut imfs = InMemoryFs::new(); + imfs.load_snapshot("test", VfsSnapshot::file("bar\r\nfoo\r\n\r\n")) + .unwrap(); + + let vfs = Vfs::new(imfs); + + assert_eq!( + vfs.read_to_string_lf_normalized("test").unwrap().as_str(), + "bar\nfoo\n\n" + ); + } +} diff --git a/crates/rojo-insta-ext/Cargo.toml b/crates/rojo-insta-ext/Cargo.toml index 4471c4acc..55a864991 100644 --- a/crates/rojo-insta-ext/Cargo.toml +++ b/crates/rojo-insta-ext/Cargo.toml @@ -6,5 +6,5 @@ edition = "2018" publish = false [dependencies] -serde = "1.0.99" -serde_yaml = "0.8.9" +serde = "1.0.197" +serde_yaml = "0.8.26" diff --git a/plugin/rbx_dom_lua/EncodedValue.lua b/plugin/rbx_dom_lua/EncodedValue.lua index e9dd0edd4..f2e9e3434 100644 --- a/plugin/rbx_dom_lua/EncodedValue.lua +++ b/plugin/rbx_dom_lua/EncodedValue.lua @@ -493,9 +493,32 @@ types = { }, } +types.OptionalCFrame = { + fromPod = function(pod) + if pod == nil then + return nil + else + return types.CFrame.fromPod(pod) + end + end, + + toPod = function(roblox) + if roblox == nil then + return nil + else + return types.CFrame.toPod(roblox) + end + end, +} + function EncodedValue.decode(encodedValue) local ty, value = next(encodedValue) + if ty == nil then + -- If the encoded pair is empty, assume it is an unoccupied optional value + return true, nil + end + local typeImpl = types[ty] if typeImpl == nil then return false, "Couldn't decode value " .. tostring(ty) diff --git a/plugin/rbx_dom_lua/allValues.json b/plugin/rbx_dom_lua/allValues.json index b233ab25b..9b07d7bf0 100644 --- a/plugin/rbx_dom_lua/allValues.json +++ b/plugin/rbx_dom_lua/allValues.json @@ -370,6 +370,41 @@ }, "ty": "NumberSequence" }, + "OptionalCFrame-None": { + "value": { + "OptionalCFrame": null + }, + "ty": "OptionalCFrame" + }, + "OptionalCFrame-Some": { + "value": { + "OptionalCFrame": { + "position": [ + 0.0, + 0.0, + 0.0 + ], + "orientation": [ + [ + 1.0, + 0.0, + 0.0 + ], + [ + 0.0, + 1.0, + 0.0 + ], + [ + 0.0, + 0.0, + 1.0 + ] + ] + } + }, + "ty": "OptionalCFrame" + }, "PhysicalProperties-Custom": { "value": { "PhysicalProperties": { diff --git a/plugin/rbx_dom_lua/customProperties.lua b/plugin/rbx_dom_lua/customProperties.lua index 072db9ef0..f115f7c82 100644 --- a/plugin/rbx_dom_lua/customProperties.lua +++ b/plugin/rbx_dom_lua/customProperties.lua @@ -111,6 +111,18 @@ return { return true, instance:ScaleTo(value) end, }, + WorldPivotData = { + read = function(instance) + return true, instance:GetPivot() + end, + write = function(instance, _, value) + if value == nil then + return true, nil + else + return true, instance:PivotTo(value) + end + end, + }, }, Terrain = { MaterialColors = { diff --git a/plugin/rbx_dom_lua/database.json b/plugin/rbx_dom_lua/database.json index 81424b27e..34be08b46 100644 --- a/plugin/rbx_dom_lua/database.json +++ b/plugin/rbx_dom_lua/database.json @@ -1,9 +1,9 @@ { "Version": [ 0, - 607, + 612, 0, - 6070550 + 6120532 ], "Classes": { "Accessory": { @@ -345,6 +345,17 @@ } } }, + "ActivityHistoryService": { + "Name": "ActivityHistoryService", + "Tags": [ + "NotCreatable", + "NotReplicated", + "Service" + ], + "Superclass": "Instance", + "Properties": {}, + "DefaultProperties": {} + }, "Actor": { "Name": "Actor", "Tags": [], @@ -11172,10 +11183,12 @@ "DataType": { "Value": "CFrame" }, - "Tags": [], + "Tags": [ + "Hidden" + ], "Kind": { "Canonical": { - "Serialization": "Serializes" + "Serialization": "DoesNotSerialize" } } }, @@ -11185,10 +11198,12 @@ "DataType": { "Value": "Int32" }, - "Tags": [], + "Tags": [ + "Hidden" + ], "Kind": { "Canonical": { - "Serialization": "Serializes" + "Serialization": "DoesNotSerialize" } } }, @@ -11198,10 +11213,12 @@ "DataType": { "Value": "String" }, - "Tags": [], + "Tags": [ + "Hidden" + ], "Kind": { "Canonical": { - "Serialization": "Serializes" + "Serialization": "DoesNotSerialize" } } }, @@ -11211,22 +11228,38 @@ "DataType": { "Value": "Int32" }, - "Tags": [], + "Tags": [ + "Hidden" + ], "Kind": { "Canonical": { - "Serialization": "Serializes" + "Serialization": "DoesNotSerialize" + } + } + }, + "IsIdle": { + "Name": "IsIdle", + "Scriptability": "ReadWrite", + "DataType": { + "Value": "Bool" + }, + "Tags": [ + "Hidden" + ], + "Kind": { + "Canonical": { + "Serialization": "DoesNotSerialize" } } }, "Status": { "Name": "Status", - "Scriptability": "None", + "Scriptability": "ReadWrite", "DataType": { "Enum": "CollaboratorStatus" }, "Tags": [ - "Hidden", - "NotScriptable" + "Hidden" ], "Kind": { "Canonical": { @@ -11240,10 +11273,12 @@ "DataType": { "Value": "Int64" }, - "Tags": [], + "Tags": [ + "Hidden" + ], "Kind": { "Canonical": { - "Serialization": "Serializes" + "Serialization": "DoesNotSerialize" } } }, @@ -11253,10 +11288,12 @@ "DataType": { "Value": "String" }, - "Tags": [], + "Tags": [ + "Hidden" + ], "Kind": { "Canonical": { - "Serialization": "Serializes" + "Serialization": "DoesNotSerialize" } } } @@ -12224,6 +12261,19 @@ "Serialization": "Serializes" } } + }, + "UpDirection": { + "Name": "UpDirection", + "Scriptability": "ReadWrite", + "DataType": { + "Value": "Vector3" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } } }, "DefaultProperties": { @@ -12261,6 +12311,13 @@ }, "Tags": { "Tags": [] + }, + "UpDirection": { + "Vector3": [ + 0.0, + 1.0, + 0.0 + ] } } }, @@ -13286,7 +13343,9 @@ "DataType": { "Value": "Bool" }, - "Tags": [], + "Tags": [ + "Deprecated" + ], "Kind": { "Canonical": { "Serialization": "Serializes" @@ -15878,6 +15937,19 @@ } } }, + "PermissionPolicy": { + "Name": "PermissionPolicy", + "Scriptability": "ReadWrite", + "DataType": { + "Enum": "DragDetectorPermissionPolicy" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, "PhysicalDragClickedPart": { "Name": "PhysicalDragClickedPart", "Scriptability": "None", @@ -16168,10 +16240,13 @@ "Orientation": { "Vector3": [ -0.0, - 180.0, + 179.99998, 90.0 ] }, + "PermissionPolicy": { + "Enum": 1 + }, "ResponseStyle": { "Enum": 1 }, @@ -22285,7 +22360,9 @@ "DataType": { "Value": "Bool" }, - "Tags": [], + "Tags": [ + "Deprecated" + ], "Kind": { "Canonical": { "Serialization": "Serializes" @@ -31232,7 +31309,7 @@ }, "WorldPivotData": { "Name": "WorldPivotData", - "Scriptability": "None", + "Scriptability": "Custom", "DataType": { "Value": "OptionalCFrame" }, @@ -33071,7 +33148,7 @@ }, "SerializedDefaultAttributes": { "Name": "SerializedDefaultAttributes", - "Scriptability": "Read", + "Scriptability": "None", "DataType": { "Value": "BinaryString" }, @@ -35022,6 +35099,19 @@ "Serialization": "Serializes" } } + }, + "ZIndex": { + "Name": "ZIndex", + "Scriptability": "None", + "DataType": { + "Value": "Int32" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } } }, "DefaultProperties": {} @@ -35734,6 +35824,58 @@ } } }, + "DrawConstraintsNetForce": { + "Name": "DrawConstraintsNetForce", + "Scriptability": "None", + "DataType": { + "Value": "Bool" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, + "DrawContactsNetForce": { + "Name": "DrawContactsNetForce", + "Scriptability": "None", + "DataType": { + "Value": "Bool" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, + "DrawTotalNetForce": { + "Name": "DrawTotalNetForce", + "Scriptability": "None", + "DataType": { + "Value": "Bool" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, + "EnableForceVisualizationSmoothing": { + "Name": "EnableForceVisualizationSmoothing", + "Scriptability": "None", + "DataType": { + "Value": "Bool" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, "FluidForceDrawScale": { "Name": "FluidForceDrawScale", "Scriptability": "None", @@ -35776,6 +35918,19 @@ } } }, + "ForceVisualizationSmoothingSteps": { + "Name": "ForceVisualizationSmoothingSteps", + "Scriptability": "None", + "DataType": { + "Value": "Int32" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, "IsInterpolationThrottleShown": { "Name": "IsInterpolationThrottleShown", "Scriptability": "ReadWrite", @@ -35893,6 +36048,19 @@ } } }, + "TorqueDrawScale": { + "Name": "TorqueDrawScale", + "Scriptability": "None", + "DataType": { + "Value": "Float32" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, "UseCSGv2": { "Name": "UseCSGv2", "Scriptability": "ReadWrite", @@ -38337,6 +38505,17 @@ } } }, + "ProjectFolderService": { + "Name": "ProjectFolderService", + "Tags": [ + "NotCreatable", + "NotReplicated", + "Service" + ], + "Superclass": "Instance", + "Properties": {}, + "DefaultProperties": {} + }, "ProximityPrompt": { "Name": "ProximityPrompt", "Tags": [], @@ -40859,6 +41038,19 @@ } } }, + "PreferredUploadId": { + "Name": "PreferredUploadId", + "Scriptability": "ReadWrite", + "DataType": { + "Value": "Int64" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, "RestPose": { "Name": "RestPose", "Scriptability": "ReadWrite", @@ -44505,7 +44697,9 @@ "DataType": { "Value": "Bool" }, - "Tags": [], + "Tags": [ + "Deprecated" + ], "Kind": { "Canonical": { "Serialization": "Serializes" @@ -46931,21 +47125,6 @@ } } }, - "AnimationCompositorMode": { - "Name": "AnimationCompositorMode", - "Scriptability": "ReadWrite", - "DataType": { - "Enum": "AnimationCompositorMode" - }, - "Tags": [ - "NotBrowsable" - ], - "Kind": { - "Canonical": { - "Serialization": "Serializes" - } - } - }, "AutoJumpEnabled": { "Name": "AutoJumpEnabled", "Scriptability": "ReadWrite", @@ -47488,21 +47667,6 @@ } } }, - "HumanoidStateMachineMode": { - "Name": "HumanoidStateMachineMode", - "Scriptability": "ReadWrite", - "DataType": { - "Enum": "HumanoidStateMachineMode" - }, - "Tags": [ - "NotBrowsable" - ], - "Kind": { - "Canonical": { - "Serialization": "Serializes" - } - } - }, "LoadCharacterAppearance": { "Name": "LoadCharacterAppearance", "Scriptability": "ReadWrite", @@ -47594,9 +47758,6 @@ "AllowCustomAnimations": { "Bool": true }, - "AnimationCompositorMode": { - "Enum": 0 - }, "Attributes": { "Attributes": {} }, @@ -47729,9 +47890,6 @@ "HealthDisplayDistance": { "Float32": 100.0 }, - "HumanoidStateMachineMode": { - "Enum": 0 - }, "LoadCharacterAppearance": { "Bool": true }, @@ -48619,6 +48777,136 @@ } } }, + "DraggerActiveColor": { + "Name": "DraggerActiveColor", + "Scriptability": "None", + "DataType": { + "Value": "Color3" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, + "DraggerMajorGridIncrement": { + "Name": "DraggerMajorGridIncrement", + "Scriptability": "None", + "DataType": { + "Value": "Int32" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, + "DraggerMaxSoftSnaps": { + "Name": "DraggerMaxSoftSnaps", + "Scriptability": "None", + "DataType": { + "Value": "Int32" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, + "DraggerPassiveColor": { + "Name": "DraggerPassiveColor", + "Scriptability": "None", + "DataType": { + "Value": "Color3" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, + "DraggerShowHoverRuler": { + "Name": "DraggerShowHoverRuler", + "Scriptability": "None", + "DataType": { + "Value": "Bool" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, + "DraggerShowMeasurement": { + "Name": "DraggerShowMeasurement", + "Scriptability": "None", + "DataType": { + "Value": "Bool" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, + "DraggerShowTargetSnap": { + "Name": "DraggerShowTargetSnap", + "Scriptability": "None", + "DataType": { + "Value": "Bool" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, + "DraggerSoftSnapMarginFactor": { + "Name": "DraggerSoftSnapMarginFactor", + "Scriptability": "None", + "DataType": { + "Value": "Float32" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, + "DraggerSummonMarginFactor": { + "Name": "DraggerSummonMarginFactor", + "Scriptability": "None", + "DataType": { + "Value": "Float32" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, + "DraggerTiltRotateDuration": { + "Name": "DraggerTiltRotateDuration", + "Scriptability": "None", + "DataType": { + "Value": "Float32" + }, + "Tags": [], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, "Enable Autocomplete": { "Name": "Enable Autocomplete", "Scriptability": "ReadWrite", @@ -55907,6 +56195,17 @@ "Properties": {}, "DefaultProperties": {} }, + "TextureGenerationService": { + "Name": "TextureGenerationService", + "Tags": [ + "NotCreatable", + "NotReplicated", + "Service" + ], + "Superclass": "Instance", + "Properties": {}, + "DefaultProperties": {} + }, "ThirdPartyUserService": { "Name": "ThirdPartyUserService", "Tags": [ @@ -59590,6 +59889,22 @@ } } }, + "ChatTranslationLocale": { + "Name": "ChatTranslationLocale", + "Scriptability": "None", + "DataType": { + "Value": "String" + }, + "Tags": [ + "Hidden", + "NotReplicated" + ], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, "ChatTranslationToggleEnabled": { "Name": "ChatTranslationToggleEnabled", "Scriptability": "None", @@ -59724,6 +60039,22 @@ } } }, + "FramerateCap": { + "Name": "FramerateCap", + "Scriptability": "None", + "DataType": { + "Value": "Int32" + }, + "Tags": [ + "Hidden", + "NotReplicated" + ], + "Kind": { + "Canonical": { + "Serialization": "Serializes" + } + } + }, "Fullscreen": { "Name": "Fullscreen", "Scriptability": "None", @@ -61068,6 +61399,7 @@ "VRService": { "Name": "VRService", "Tags": [ + "NotBrowsable", "NotCreatable", "Service" ], @@ -61084,7 +61416,22 @@ ], "Kind": { "Canonical": { - "Serialization": "DoesNotSerialize" + "Serialization": "Serializes" + } + } + }, + "AvatarGestures": { + "Name": "AvatarGestures", + "Scriptability": "ReadWrite", + "DataType": { + "Value": "Bool" + }, + "Tags": [ + "NotBrowsable" + ], + "Kind": { + "Canonical": { + "Serialization": "Serializes" } } }, @@ -61111,10 +61458,12 @@ "DataType": { "Value": "Bool" }, - "Tags": [], + "Tags": [ + "NotReplicated" + ], "Kind": { "Canonical": { - "Serialization": "DoesNotSerialize" + "Serialization": "Serializes" } } }, @@ -61124,7 +61473,9 @@ "DataType": { "Enum": "UserCFrame" }, - "Tags": [], + "Tags": [ + "NotReplicated" + ], "Kind": { "Canonical": { "Serialization": "DoesNotSerialize" @@ -61283,12 +61634,21 @@ "Attributes": { "Attributes": {} }, + "AutomaticScaling": { + "Enum": 0 + }, + "AvatarGestures": { + "Bool": false + }, "Capabilities": { "SecurityCapabilities": 0 }, "DefinesCapabilities": { "Bool": false }, + "FadeOutViewOnCollision": { + "Bool": true + }, "SourceAssetId": { "Int64": -1 }, @@ -62839,16 +63199,6 @@ "Properties": {}, "DefaultProperties": {} }, - "VisibilityService": { - "Name": "VisibilityService", - "Tags": [ - "NotCreatable", - "Service" - ], - "Superclass": "Instance", - "Properties": {}, - "DefaultProperties": {} - }, "Visit": { "Name": "Visit", "Tags": [ @@ -62933,9 +63283,7 @@ "DataType": { "Enum": "AudioApiRollout" }, - "Tags": [ - "NotBrowsable" - ], + "Tags": [], "Kind": { "Canonical": { "Serialization": "Serializes" @@ -65214,14 +65562,6 @@ "Timeout": 10 } }, - "AnimationCompositorMode": { - "name": "AnimationCompositorMode", - "items": { - "Default": 0, - "Disabled": 2, - "Enabled": 1 - } - }, "AnimationPriority": { "name": "AnimationPriority", "items": { @@ -65835,10 +66175,10 @@ "CollaboratorStatus": { "name": "CollaboratorStatus", "items": { - "Editing3D": 0, - "None": 3, - "PrivateScripting": 2, - "Scripting": 1 + "Editing3D": 1, + "None": 0, + "PrivateScripting": 3, + "Scripting": 2 } }, "CollisionFidelity": { @@ -66307,6 +66647,14 @@ "TranslateViewPlane": 4 } }, + "DragDetectorPermissionPolicy": { + "name": "DragDetectorPermissionPolicy", + "items": { + "Everybody": 1, + "Nobody": 0, + "Scriptable": 2 + } + }, "DragDetectorResponseStyle": { "name": "DragDetectorResponseStyle", "items": { @@ -66810,15 +67158,6 @@ "R6": 0 } }, - "HumanoidStateMachineMode": { - "name": "HumanoidStateMachineMode", - "items": { - "Default": 0, - "Legacy": 1, - "LuaStateMachine": 3, - "NoStateMachine": 2 - } - }, "HumanoidStateType": { "name": "HumanoidStateType", "items": { @@ -67469,6 +67808,16 @@ "PersistentPerPlayer": 3 } }, + "ModerationStatus": { + "name": "ModerationStatus", + "items": { + "Invalid": 5, + "NotApplicable": 4, + "NotReviewed": 3, + "ReviewedApproved": 1, + "ReviewedRejected": 2 + } + }, "ModifierKey": { "name": "ModifierKey", "items": { diff --git a/plugin/src/App/Components/ClassIcon.lua b/plugin/src/App/Components/ClassIcon.lua new file mode 100644 index 000000000..c3e46e0d2 --- /dev/null +++ b/plugin/src/App/Components/ClassIcon.lua @@ -0,0 +1,126 @@ +local StudioService = game:GetService("StudioService") +local AssetService = game:GetService("AssetService") + +local Rojo = script:FindFirstAncestor("Rojo") +local Plugin = Rojo.Plugin +local Packages = Rojo.Packages + +local Roact = require(Packages.Roact) + +local e = Roact.createElement + +local EditableImage = require(Plugin.App.Components.EditableImage) + +local imageCache = {} +local function getImageSizeAndPixels(image) + if not imageCache[image] then + local editableImage = AssetService:CreateEditableImageAsync(image) + imageCache[image] = { + Size = editableImage.Size, + Pixels = editableImage:ReadPixels(Vector2.zero, editableImage.Size), + } + end + + return imageCache[image].Size, table.clone(imageCache[image].Pixels) +end + +local function getRecoloredClassIcon(className, color) + local iconProps = StudioService:GetClassIcon(className) + + if iconProps and color then + local success, editableImageSize, editableImagePixels = pcall(function() + local size, pixels = getImageSizeAndPixels(iconProps.Image) + + local minVal, maxVal = math.huge, -math.huge + for i = 1, #pixels, 4 do + if pixels[i + 3] == 0 then + continue + end + local pixelVal = math.max(pixels[i], pixels[i + 1], pixels[i + 2]) + + minVal = math.min(minVal, pixelVal) + maxVal = math.max(maxVal, pixelVal) + end + + local hue, sat, val = color:ToHSV() + for i = 1, #pixels, 4 do + if pixels[i + 3] == 0 then + continue + end + + local pixelVal = math.max(pixels[i], pixels[i + 1], pixels[i + 2]) + local newVal = val + if minVal < maxVal then + -- Remap minVal - maxVal to val*0.9 - val + newVal = val * (0.9 + 0.1 * (pixelVal - minVal) / (maxVal - minVal)) + end + + local newPixelColor = Color3.fromHSV(hue, sat, newVal) + pixels[i], pixels[i + 1], pixels[i + 2] = newPixelColor.R, newPixelColor.G, newPixelColor.B + end + return size, pixels + end) + if success then + iconProps.EditableImagePixels = editableImagePixels + iconProps.EditableImageSize = editableImageSize + end + end + + return iconProps +end + +local ClassIcon = Roact.PureComponent:extend("ClassIcon") + +function ClassIcon:init() + self.state = { + iconProps = nil, + } +end + +function ClassIcon:updateIcon() + local props = self.props + local iconProps = getRecoloredClassIcon(props.className, props.color) + self:setState({ + iconProps = iconProps, + }) +end + +function ClassIcon:didMount() + self:updateIcon() +end + +function ClassIcon:didUpdate(lastProps) + if lastProps.className ~= self.props.className or lastProps.color ~= self.props.color then + self:updateIcon() + end +end + +function ClassIcon:render() + local iconProps = self.state.iconProps + if not iconProps then + return nil + end + + return e( + "ImageLabel", + { + Size = self.props.size, + Position = self.props.position, + LayoutOrder = self.props.layoutOrder, + AnchorPoint = self.props.anchorPoint, + ImageTransparency = self.props.transparency, + Image = iconProps.Image, + ImageRectOffset = iconProps.ImageRectOffset, + ImageRectSize = iconProps.ImageRectSize, + BackgroundTransparency = 1, + }, + if iconProps.EditableImagePixels + then e(EditableImage, { + size = iconProps.EditableImageSize, + pixels = iconProps.EditableImagePixels, + }) + else nil + ) +end + +return ClassIcon diff --git a/plugin/src/App/Components/EditableImage.lua b/plugin/src/App/Components/EditableImage.lua new file mode 100644 index 000000000..501a37eee --- /dev/null +++ b/plugin/src/App/Components/EditableImage.lua @@ -0,0 +1,41 @@ +local Rojo = script:FindFirstAncestor("Rojo") +local Packages = Rojo.Packages + +local Roact = require(Packages.Roact) + +local e = Roact.createElement + +local EditableImage = Roact.PureComponent:extend("EditableImage") + +function EditableImage:init() + self.ref = Roact.createRef() +end + +function EditableImage:writePixels() + local image = self.ref.current + if not image then + return + end + if not self.props.pixels then + return + end + + image:WritePixels(Vector2.zero, self.props.size, self.props.pixels) +end + +function EditableImage:render() + return e("EditableImage", { + Size = self.props.size, + [Roact.Ref] = self.ref, + }) +end + +function EditableImage:didMount() + self:writePixels() +end + +function EditableImage:didUpdate() + self:writePixels() +end + +return EditableImage diff --git a/plugin/src/App/Components/PatchVisualizer/ChangeList.lua b/plugin/src/App/Components/PatchVisualizer/ChangeList.lua index ce01b8010..2f10d4587 100644 --- a/plugin/src/App/Components/PatchVisualizer/ChangeList.lua +++ b/plugin/src/App/Components/PatchVisualizer/ChangeList.lua @@ -155,7 +155,7 @@ function ChangeList:render() local headerRow = changes[1] local headers = e("Frame", { - Size = UDim2.new(1, 0, 0, 30), + Size = UDim2.new(1, 0, 0, 24), BackgroundTransparency = rowTransparency, BackgroundColor3 = theme.Diff.Row, LayoutOrder = 0, @@ -214,7 +214,7 @@ function ChangeList:render() local isWarning = metadata.isWarning rows[row] = e("Frame", { - Size = UDim2.new(1, 0, 0, 30), + Size = UDim2.new(1, 0, 0, 24), BackgroundTransparency = row % 2 ~= 0 and rowTransparency or 1, BackgroundColor3 = theme.Diff.Row, BorderSizePixel = 0, @@ -269,8 +269,8 @@ function ChangeList:render() }, { Headers = headers, Values = e(ScrollingFrame, { - size = UDim2.new(1, 0, 1, -30), - position = UDim2.new(0, 0, 0, 30), + size = UDim2.new(1, 0, 1, -24), + position = UDim2.new(0, 0, 0, 24), contentSize = self.contentSize, transparency = props.transparency, }, rows), diff --git a/plugin/src/App/Components/PatchVisualizer/DomLabel.lua b/plugin/src/App/Components/PatchVisualizer/DomLabel.lua index 41ec0b8e9..a842dcbc5 100644 --- a/plugin/src/App/Components/PatchVisualizer/DomLabel.lua +++ b/plugin/src/App/Components/PatchVisualizer/DomLabel.lua @@ -1,5 +1,4 @@ local SelectionService = game:GetService("Selection") -local StudioService = game:GetService("StudioService") local Rojo = script:FindFirstAncestor("Rojo") local Plugin = Rojo.Plugin @@ -15,7 +14,8 @@ local bindingUtil = require(Plugin.App.bindingUtil) local e = Roact.createElement local ChangeList = require(script.Parent.ChangeList) -local Tooltip = require(script.Parent.Parent.Tooltip) +local Tooltip = require(Plugin.App.Components.Tooltip) +local ClassIcon = require(Plugin.App.Components.ClassIcon) local Expansion = Roact.Component:extend("Expansion") @@ -28,8 +28,8 @@ function Expansion:render() return e("Frame", { BackgroundTransparency = 1, - Size = UDim2.new(1, -props.indent, 1, -30), - Position = UDim2.new(0, props.indent, 0, 30), + Size = UDim2.new(1, -props.indent, 1, -24), + Position = UDim2.new(0, props.indent, 0, 24), }, { ChangeList = e(ChangeList, { changes = props.changeList, @@ -44,7 +44,7 @@ local DomLabel = Roact.Component:extend("DomLabel") function DomLabel:init() local initHeight = self.props.elementHeight:getValue() - self.expanded = initHeight > 30 + self.expanded = initHeight > 24 self.motor = Flipper.SingleMotor.new(initHeight) self.binding = bindingUtil.fromMotor(self.motor) @@ -53,7 +53,7 @@ function DomLabel:init() renderExpansion = self.expanded, }) self.motor:onStep(function(value) - local renderExpansion = value > 30 + local renderExpansion = value > 24 self.props.setElementHeight(value) if self.props.updateEvent then @@ -81,7 +81,7 @@ function DomLabel:didUpdate(prevProps) then -- Close the expansion when the domlabel is changed to a different thing self.expanded = false - self.motor:setGoal(Flipper.Spring.new(30, { + self.motor:setGoal(Flipper.Spring.new(24, { frequency = 5, dampingRatio = 1, })) @@ -90,17 +90,49 @@ end function DomLabel:render() local props = self.props + local depth = props.depth or 1 return Theme.with(function(theme) - local iconProps = StudioService:GetClassIcon(props.className) - local indent = (props.depth or 0) * 20 + 25 + local color = if props.isWarning + then theme.Diff.Warning + elseif props.patchType then theme.Diff[props.patchType] + else theme.TextColor + + local indent = (depth - 1) * 12 + 15 -- Line guides help indent depth remain readable local lineGuides = {} - for i = 1, props.depth or 0 do - lineGuides["Line_" .. i] = e("Frame", { - Size = UDim2.new(0, 2, 1, 2), - Position = UDim2.new(0, (20 * i) + 15, 0, -1), + for i = 2, depth do + if props.depthsComplete[i] then + continue + end + if props.isFinalChild and i == depth then + -- This line stops halfway down to merge with our connector for the right angle + lineGuides["Line_" .. i] = e("Frame", { + Size = UDim2.new(0, 2, 0, 15), + Position = UDim2.new(0, (12 * (i - 1)) + 6, 0, -1), + BorderSizePixel = 0, + BackgroundTransparency = props.transparency, + BackgroundColor3 = theme.BorderedContainer.BorderColor, + }) + else + -- All other lines go all the way + -- with the exception of the final element, which stops halfway down + lineGuides["Line_" .. i] = e("Frame", { + Size = UDim2.new(0, 2, 1, if props.isFinalElement then -9 else 2), + Position = UDim2.new(0, (12 * (i - 1)) + 6, 0, -1), + BorderSizePixel = 0, + BackgroundTransparency = props.transparency, + BackgroundColor3 = theme.BorderedContainer.BorderColor, + }) + end + end + + if depth ~= 1 then + lineGuides["Connector"] = e("Frame", { + Size = UDim2.new(0, 8, 0, 2), + Position = UDim2.new(0, 2 + (12 * props.depth), 0, 12), + AnchorPoint = Vector2.xAxis, BorderSizePixel = 0, BackgroundTransparency = props.transparency, BackgroundColor3 = theme.BorderedContainer.BorderColor, @@ -109,9 +141,8 @@ function DomLabel:render() return e("Frame", { ClipsDescendants = true, - BackgroundColor3 = if props.patchType then theme.Diff[props.patchType] else nil, - BorderSizePixel = 0, - BackgroundTransparency = props.patchType and props.transparency or 1, + BackgroundTransparency = if props.elementIndex % 2 == 0 then 0.985 else 1, + BackgroundColor3 = theme.Diff.Row, Size = self.binding:map(function(expand) return UDim2.new(1, 0, 0, expand) end), @@ -141,8 +172,8 @@ function DomLabel:render() if props.changeList then self.expanded = not self.expanded - local goalHeight = 30 - + (if self.expanded then math.clamp(#props.changeList * 30, 30, 30 * 6) else 0) + local goalHeight = 24 + + (if self.expanded then math.clamp(#props.changeList * 24, 24, 24 * 6) else 0) self.motor:setGoal(Flipper.Spring.new(goalHeight, { frequency = 5, dampingRatio = 1, @@ -174,40 +205,74 @@ function DomLabel:render() DiffIcon = if props.patchType then e("ImageLabel", { Image = Assets.Images.Diff[props.patchType], - ImageColor3 = theme.AddressEntry.PlaceholderColor, + ImageColor3 = color, ImageTransparency = props.transparency, BackgroundTransparency = 1, - Size = UDim2.new(0, 20, 0, 20), - Position = UDim2.new(0, 0, 0, 15), + Size = UDim2.new(0, 14, 0, 14), + Position = UDim2.new(0, 0, 0, 12), AnchorPoint = Vector2.new(0, 0.5), }) else nil, - ClassIcon = e("ImageLabel", { - Image = iconProps.Image, - ImageTransparency = props.transparency, - ImageRectOffset = iconProps.ImageRectOffset, - ImageRectSize = iconProps.ImageRectSize, - BackgroundTransparency = 1, - Size = UDim2.new(0, 20, 0, 20), - Position = UDim2.new(0, indent, 0, 15), - AnchorPoint = Vector2.new(0, 0.5), + ClassIcon = e(ClassIcon, { + className = props.className, + color = color, + transparency = props.transparency, + size = UDim2.new(0, 16, 0, 16), + position = UDim2.new(0, indent + 2, 0, 12), + anchorPoint = Vector2.new(0, 0.5), }), InstanceName = e("TextLabel", { - Text = (if props.isWarning then "âš  " else "") .. props.name .. (props.hint and string.format( - ' %s', - theme.AddressEntry.PlaceholderColor:ToHex(), - props.hint - ) or ""), + Text = (if props.isWarning then "âš  " else "") .. props.name, RichText = true, BackgroundTransparency = 1, - Font = Enum.Font.GothamMedium, + Font = if props.patchType then Enum.Font.GothamBold else Enum.Font.GothamMedium, TextSize = 14, - TextColor3 = if props.isWarning then theme.Diff.Warning else theme.TextColor, + TextColor3 = color, TextXAlignment = Enum.TextXAlignment.Left, TextTransparency = props.transparency, TextTruncate = Enum.TextTruncate.AtEnd, - Size = UDim2.new(1, -indent - 50, 0, 30), - Position = UDim2.new(0, indent + 30, 0, 0), + Size = UDim2.new(1, -indent - 50, 0, 24), + Position = UDim2.new(0, indent + 22, 0, 0), + }), + ChangeInfo = e("Frame", { + BackgroundTransparency = 1, + Size = UDim2.new(1, -indent - 80, 0, 24), + Position = UDim2.new(1, -2, 0, 0), + AnchorPoint = Vector2.new(1, 0), + }, { + Layout = e("UIListLayout", { + FillDirection = Enum.FillDirection.Horizontal, + HorizontalAlignment = Enum.HorizontalAlignment.Right, + VerticalAlignment = Enum.VerticalAlignment.Center, + SortOrder = Enum.SortOrder.LayoutOrder, + Padding = UDim.new(0, 4), + }), + Edits = if props.changeInfo and props.changeInfo.edits + then e("TextLabel", { + Text = props.changeInfo.edits .. if props.changeInfo.failed then "," else "", + BackgroundTransparency = 1, + Font = Enum.Font.Gotham, + TextSize = 14, + TextColor3 = theme.SubTextColor, + TextTransparency = props.transparency, + Size = UDim2.new(0, 0, 0, 16), + AutomaticSize = Enum.AutomaticSize.X, + LayoutOrder = 2, + }) + else nil, + Failed = if props.changeInfo and props.changeInfo.failed + then e("TextLabel", { + Text = props.changeInfo.failed, + BackgroundTransparency = 1, + Font = Enum.Font.Gotham, + TextSize = 14, + TextColor3 = theme.Diff.Warning, + TextTransparency = props.transparency, + Size = UDim2.new(0, 0, 0, 16), + AutomaticSize = Enum.AutomaticSize.X, + LayoutOrder = 6, + }) + else nil, }), LineGuides = e("Folder", nil, lineGuides), }) diff --git a/plugin/src/App/Components/PatchVisualizer/init.lua b/plugin/src/App/Components/PatchVisualizer/init.lua index 67a4d7b20..a87d499bb 100644 --- a/plugin/src/App/Components/PatchVisualizer/init.lua +++ b/plugin/src/App/Components/PatchVisualizer/init.lua @@ -8,8 +8,8 @@ local PatchTree = require(Plugin.PatchTree) local PatchSet = require(Plugin.PatchSet) local Theme = require(Plugin.App.Theme) -local BorderedContainer = require(Plugin.App.Components.BorderedContainer) local VirtualScroller = require(Plugin.App.Components.VirtualScroller) +local BorderedContainer = require(Plugin.App.Components.BorderedContainer) local e = Roact.createElement @@ -55,34 +55,60 @@ function PatchVisualizer:render() end -- Recusively draw tree - local scrollElements, elementHeights = {}, {} + local scrollElements, elementHeights, elementIndex = {}, {}, 0 if patchTree then + local elementTotal = patchTree:getCount() + local depthsComplete = {} local function drawNode(node, depth) - local elementHeight, setElementHeight = Roact.createBinding(30) - table.insert(elementHeights, elementHeight) - table.insert( - scrollElements, - e(DomLabel, { - updateEvent = self.updateEvent, - elementHeight = elementHeight, - setElementHeight = setElementHeight, - patchType = node.patchType, - className = node.className, - isWarning = node.isWarning, - instance = node.instance, - name = node.name, - hint = node.hint, - changeList = node.changeList, - depth = depth, - transparency = self.props.transparency, - showStringDiff = self.props.showStringDiff, - showTableDiff = self.props.showTableDiff, - }) - ) + elementIndex += 1 + + local parentNode = patchTree:getNode(node.parentId) + local isFinalChild = true + if parentNode then + for _id, sibling in parentNode.children do + if type(sibling) == "table" and sibling.name and sibling.name > node.name then + isFinalChild = false + break + end + end + end + + local elementHeight, setElementHeight = Roact.createBinding(24) + elementHeights[elementIndex] = elementHeight + scrollElements[elementIndex] = e(DomLabel, { + transparency = self.props.transparency, + showStringDiff = self.props.showStringDiff, + showTableDiff = self.props.showTableDiff, + updateEvent = self.updateEvent, + elementHeight = elementHeight, + setElementHeight = setElementHeight, + elementIndex = elementIndex, + isFinalElement = elementIndex == elementTotal, + depth = depth, + depthsComplete = table.clone(depthsComplete), + hasChildren = (node.children ~= nil and next(node.children) ~= nil), + isFinalChild = isFinalChild, + patchType = node.patchType, + className = node.className, + isWarning = node.isWarning, + instance = node.instance, + name = node.name, + changeInfo = node.changeInfo, + changeList = node.changeList, + }) + + if isFinalChild then + depthsComplete[depth] = true + end end patchTree:forEach(function(node, depth) + depthsComplete[depth] = false + for i = depth + 1, #depthsComplete do + depthsComplete[i] = nil + end + drawNode(node, depth) end) end @@ -92,6 +118,7 @@ function PatchVisualizer:render() transparency = self.props.transparency, size = self.props.size, position = self.props.position, + anchorPoint = self.props.anchorPoint, layoutOrder = self.props.layoutOrder, }, { CleanMerge = e("TextLabel", { @@ -106,7 +133,8 @@ function PatchVisualizer:render() }), VirtualScroller = e(VirtualScroller, { - size = UDim2.new(1, 0, 1, 0), + size = UDim2.new(1, 0, 1, -2), + position = UDim2.new(0, 0, 0, 2), transparency = self.props.transparency, count = #scrollElements, updateEvent = self.updateEvent.Event, diff --git a/plugin/src/App/Components/SlicedImage.lua b/plugin/src/App/Components/SlicedImage.lua index 40279cc89..1dff9caa8 100644 --- a/plugin/src/App/Components/SlicedImage.lua +++ b/plugin/src/App/Components/SlicedImage.lua @@ -20,6 +20,7 @@ local function SlicedImage(props) Size = props.size, Position = props.position, AnchorPoint = props.anchorPoint, + AutomaticSize = props.automaticSize, ZIndex = props.zIndex, LayoutOrder = props.layoutOrder, diff --git a/plugin/src/App/Components/StringDiffVisualizer/init.lua b/plugin/src/App/Components/StringDiffVisualizer/init.lua index 60eb49a35..e4203c21c 100644 --- a/plugin/src/App/Components/StringDiffVisualizer/init.lua +++ b/plugin/src/App/Components/StringDiffVisualizer/init.lua @@ -9,6 +9,7 @@ local Log = require(Packages.Log) local Highlighter = require(Packages.Highlighter) local StringDiff = require(script:FindFirstChild("StringDiff")) +local Timer = require(Plugin.Timer) local Theme = require(Plugin.App.Theme) local CodeLabel = require(Plugin.App.Components.CodeLabel) @@ -74,6 +75,7 @@ function StringDiffVisualizer:calculateContentSize() end function StringDiffVisualizer:calculateDiffLines() + Timer.start("StringDiffVisualizer:calculateDiffLines") local oldString, newString = self.props.oldString, self.props.newString -- Diff the two texts @@ -133,6 +135,7 @@ function StringDiffVisualizer:calculateDiffLines() end end + Timer.stop() return add, remove end diff --git a/plugin/src/App/Components/TableDiffVisualizer/Array.lua b/plugin/src/App/Components/TableDiffVisualizer/Array.lua index 4fd56f3c7..febd07e97 100644 --- a/plugin/src/App/Components/TableDiffVisualizer/Array.lua +++ b/plugin/src/App/Components/TableDiffVisualizer/Array.lua @@ -4,6 +4,7 @@ local Packages = Rojo.Packages local Roact = require(Packages.Roact) +local Timer = require(Plugin.Timer) local Assets = require(Plugin.Assets) local Theme = require(Plugin.App.Theme) @@ -21,6 +22,7 @@ function Array:init() end function Array:calculateDiff() + Timer.start("Array:calculateDiff") --[[ Find the indexes that are added or removed from the array, and display them side by side with gaps for the indexes that @@ -63,6 +65,7 @@ function Array:calculateDiff() j += 1 end + Timer.stop() return diff end diff --git a/plugin/src/App/Components/TableDiffVisualizer/Dictionary.lua b/plugin/src/App/Components/TableDiffVisualizer/Dictionary.lua index d0c32d963..033956c30 100644 --- a/plugin/src/App/Components/TableDiffVisualizer/Dictionary.lua +++ b/plugin/src/App/Components/TableDiffVisualizer/Dictionary.lua @@ -4,6 +4,7 @@ local Packages = Rojo.Packages local Roact = require(Packages.Roact) +local Timer = require(Plugin.Timer) local Assets = require(Plugin.Assets) local Theme = require(Plugin.App.Theme) @@ -21,6 +22,7 @@ function Dictionary:init() end function Dictionary:calculateDiff() + Timer.start("Dictionary:calculateDiff") local oldTable, newTable = self.props.oldTable or {}, self.props.newTable or {} -- Diff the two tables and find the added keys, removed keys, and changed keys @@ -59,6 +61,7 @@ function Dictionary:calculateDiff() return a.key < b.key end) + Timer.stop() return diff end diff --git a/plugin/src/App/Components/Tag.lua b/plugin/src/App/Components/Tag.lua new file mode 100644 index 000000000..9fed3d33f --- /dev/null +++ b/plugin/src/App/Components/Tag.lua @@ -0,0 +1,56 @@ +local Rojo = script:FindFirstAncestor("Rojo") +local Plugin = Rojo.Plugin +local Packages = Rojo.Packages + +local Roact = require(Packages.Roact) + +local Assets = require(Plugin.Assets) + +local SlicedImage = require(Plugin.App.Components.SlicedImage) + +local e = Roact.createElement + +return function(props) + return e(SlicedImage, { + slice = Assets.Slices.RoundedBackground, + color = props.color, + transparency = props.transparency:map(function(transparency) + return 0.9 + (0.1 * transparency) + end), + layoutOrder = props.layoutOrder, + position = props.position, + anchorPoint = props.anchorPoint, + size = UDim2.new(0, 0, 0, 16), + automaticSize = Enum.AutomaticSize.X, + }, { + Padding = e("UIPadding", { + PaddingLeft = UDim.new(0, 4), + PaddingRight = UDim.new(0, 4), + PaddingTop = UDim.new(0, 2), + PaddingBottom = UDim.new(0, 2), + }), + Icon = if props.icon + then e("ImageLabel", { + Size = UDim2.new(0, 12, 0, 12), + Position = UDim2.new(0, 0, 0.5, 0), + AnchorPoint = Vector2.new(0, 0.5), + Image = props.icon, + BackgroundTransparency = 1, + ImageColor3 = props.color, + ImageTransparency = props.transparency, + }) + else nil, + Text = e("TextLabel", { + Text = props.text, + Font = Enum.Font.GothamMedium, + TextSize = 12, + TextColor3 = props.color, + TextXAlignment = Enum.TextXAlignment.Center, + TextTransparency = props.transparency, + Size = UDim2.new(0, 0, 1, 0), + Position = UDim2.new(0, if props.icon then 15 else 0, 0, 0), + AutomaticSize = Enum.AutomaticSize.X, + BackgroundTransparency = 1, + }), + }) +end diff --git a/plugin/src/App/Components/Tooltip.lua b/plugin/src/App/Components/Tooltip.lua index 278220958..2ab7e19a5 100644 --- a/plugin/src/App/Components/Tooltip.lua +++ b/plugin/src/App/Components/Tooltip.lua @@ -163,7 +163,6 @@ local Trigger = Roact.Component:extend("TooltipTrigger") function Trigger:init() self.id = HttpService:GenerateGUID(false) self.ref = Roact.createRef() - self.mousePos = Vector2.zero self.showingPopup = false self.destroy = function() @@ -195,18 +194,22 @@ end function Trigger:isHovering() local rbx = self.ref.current if rbx then - local pos = rbx.AbsolutePosition - local size = rbx.AbsoluteSize - local mousePos = self.mousePos - - return mousePos.X >= pos.X - and mousePos.X <= pos.X + size.X - and mousePos.Y >= pos.Y - and mousePos.Y <= pos.Y + size.Y + return rbx.GuiState == Enum.GuiState.Hover end return false end +function Trigger:getMousePos() + local rbx = self.ref.current + if rbx then + local widget = rbx:FindFirstAncestorOfClass("DockWidgetPluginGui") + if widget then + return widget:GetRelativeMousePosition() + end + end + return Vector2.zero +end + function Trigger:managePopup() if self:isHovering() then if self.showingPopup or self.showDelayThread then @@ -217,7 +220,7 @@ function Trigger:managePopup() self.showDelayThread = task.delay(DELAY, function() self.props.context.addTip(self.id, { Text = self.props.text, - Position = self.mousePos, + Position = self:getMousePos(), Trigger = self.ref, }) self.showDelayThread = nil @@ -234,13 +237,7 @@ function Trigger:managePopup() end function Trigger:render() - local function recalculate(rbx) - local widget = rbx:FindFirstAncestorOfClass("DockWidgetPluginGui") - if not widget then - return - end - self.mousePos = widget:GetRelativeMousePosition() - + local function recalculate() self:managePopup() end @@ -250,11 +247,9 @@ function Trigger:render() ZIndex = self.props.zIndex or 100, [Roact.Ref] = self.ref, + [Roact.Change.GuiState] = recalculate, [Roact.Change.AbsolutePosition] = recalculate, [Roact.Change.AbsoluteSize] = recalculate, - [Roact.Event.MouseMoved] = recalculate, - [Roact.Event.MouseLeave] = recalculate, - [Roact.Event.MouseEnter] = recalculate, }) end diff --git a/plugin/src/App/Components/VirtualScroller.lua b/plugin/src/App/Components/VirtualScroller.lua index 69bcf5f10..466da8a4f 100644 --- a/plugin/src/App/Components/VirtualScroller.lua +++ b/plugin/src/App/Components/VirtualScroller.lua @@ -131,8 +131,8 @@ function VirtualScroller:render() Position = props.position, AnchorPoint = props.anchorPoint, BackgroundTransparency = props.backgroundTransparency or 1, - BackgroundColor3 = props.backgroundColor3, - BorderColor3 = props.borderColor3, + BackgroundColor3 = props.backgroundColor3 or theme.BorderedContainer.BackgroundColor, + BorderColor3 = props.borderColor3 or theme.BorderedContainer.BorderColor, CanvasSize = self.totalCanvas:map(function(s) return UDim2.fromOffset(0, s) end), diff --git a/plugin/src/App/StatusPages/Confirming.lua b/plugin/src/App/StatusPages/Confirming.lua index d3b6baa2e..df8bf5b49 100644 --- a/plugin/src/App/StatusPages/Confirming.lua +++ b/plugin/src/App/StatusPages/Confirming.lua @@ -4,10 +4,11 @@ local Packages = Rojo.Packages local Roact = require(Packages.Roact) +local Timer = require(Plugin.Timer) +local PatchTree = require(Plugin.PatchTree) local Settings = require(Plugin.Settings) local Theme = require(Plugin.App.Theme) local TextButton = require(Plugin.App.Components.TextButton) -local Header = require(Plugin.App.Components.Header) local StudioPluginGui = require(Plugin.App.Components.Studio.StudioPluginGui) local Tooltip = require(Plugin.App.Components.Tooltip) local PatchVisualizer = require(Plugin.App.Components.PatchVisualizer) @@ -23,6 +24,7 @@ function ConfirmingPage:init() self.containerSize, self.setContainerSize = Roact.createBinding(Vector2.new(0, 0)) self:setState({ + patchTree = nil, showingStringDiff = false, oldString = "", newString = "", @@ -30,22 +32,38 @@ function ConfirmingPage:init() oldTable = {}, newTable = {}, }) + + if self.props.confirmData and self.props.confirmData.patch and self.props.confirmData.instanceMap then + self:buildPatchTree() + end +end + +function ConfirmingPage:didUpdate(prevProps) + if prevProps.confirmData ~= self.props.confirmData then + self:buildPatchTree() + end +end + +function ConfirmingPage:buildPatchTree() + Timer.start("ConfirmingPage:buildPatchTree") + self:setState({ + patchTree = PatchTree.build( + self.props.confirmData.patch, + self.props.confirmData.instanceMap, + { "Property", "Current", "Incoming" } + ), + }) + Timer.stop() end function ConfirmingPage:render() return Theme.with(function(theme) local pageContent = Roact.createFragment({ - Header = e(Header, { - transparency = self.props.transparency, - layoutOrder = 1, - }), - Title = e("TextLabel", { Text = string.format( "Sync changes for project '%s':", self.props.confirmData.serverInfo.projectName or "UNKNOWN" ), - LayoutOrder = 2, Font = Enum.Font.Gotham, LineHeight = 1.2, TextSize = 14, @@ -57,13 +75,11 @@ function ConfirmingPage:render() }), PatchVisualizer = e(PatchVisualizer, { - size = UDim2.new(1, 0, 1, -150), + size = UDim2.new(1, 0, 1, -100), transparency = self.props.transparency, layoutOrder = 3, - changeListHeaders = { "Property", "Current", "Incoming" }, - patch = self.props.confirmData.patch, - instanceMap = self.props.confirmData.instanceMap, + patchTree = self.state.patchTree, showStringDiff = function(oldString: string, newString: string) self:setState({ @@ -132,6 +148,11 @@ function ConfirmingPage:render() }), }), + Padding = e("UIPadding", { + PaddingLeft = UDim.new(0, 8), + PaddingRight = UDim.new(0, 8), + }), + Layout = e("UIListLayout", { HorizontalAlignment = Enum.HorizontalAlignment.Center, VerticalAlignment = Enum.VerticalAlignment.Center, @@ -140,11 +161,6 @@ function ConfirmingPage:render() Padding = UDim.new(0, 10), }), - Padding = e("UIPadding", { - PaddingLeft = UDim.new(0, 20), - PaddingRight = UDim.new(0, 20), - }), - StringDiff = e(StudioPluginGui, { id = "Rojo_ConfirmingStringDiff", title = "String diff", diff --git a/plugin/src/App/StatusPages/Connected.lua b/plugin/src/App/StatusPages/Connected.lua index d8055b3f3..3f84d15f4 100644 --- a/plugin/src/App/StatusPages/Connected.lua +++ b/plugin/src/App/StatusPages/Connected.lua @@ -3,9 +3,7 @@ local Plugin = Rojo.Plugin local Packages = Rojo.Packages local Roact = require(Packages.Roact) -local Flipper = require(Packages.Flipper) -local bindingUtil = require(Plugin.App.bindingUtil) local Theme = require(Plugin.App.Theme) local Assets = require(Plugin.Assets) local PatchSet = require(Plugin.PatchSet) @@ -23,28 +21,20 @@ local TableDiffVisualizer = require(Plugin.App.Components.TableDiffVisualizer) local e = Roact.createElement local AGE_UNITS = { - { 31556909, "year" }, - { 2629743, "month" }, - { 604800, "week" }, - { 86400, "day" }, - { 3600, "hour" }, - { - 60, - "minute", - }, + { 31556909, "y" }, + { 2629743, "mon" }, + { 604800, "w" }, + { 86400, "d" }, + { 3600, "h" }, + { 60, "m" }, } function timeSinceText(elapsed: number): string - if elapsed < 3 then - return "just now" - end - - local ageText = string.format("%d seconds ago", elapsed) + local ageText = string.format("%ds", elapsed) for _, UnitData in ipairs(AGE_UNITS) do local UnitSeconds, UnitName = UnitData[1], UnitData[2] if elapsed > UnitSeconds then - local c = math.floor(elapsed / UnitSeconds) - ageText = string.format("%d %s%s ago", c, UnitName, c > 1 and "s" or "") + ageText = elapsed // UnitSeconds .. UnitName break end end @@ -52,49 +42,179 @@ function timeSinceText(elapsed: number): string return ageText end -local ChangesDrawer = Roact.Component:extend("ChangesDrawer") +local ChangesViewer = Roact.Component:extend("ChangesViewer") -function ChangesDrawer:init() +function ChangesViewer:init() -- Hold onto the serve session during the lifecycle of this component -- so that it can still render during the fade out after disconnecting self.serveSession = self.props.serveSession end -function ChangesDrawer:render() - if self.props.rendered == false or self.serveSession == nil then +function ChangesViewer:render() + if self.props.rendered == false or self.serveSession == nil or self.props.patchData == nil then return nil end + local unapplied = PatchSet.countChanges(self.props.patchData.unapplied) + local applied = PatchSet.countChanges(self.props.patchData.patch) - unapplied + return Theme.with(function(theme) - return e(BorderedContainer, { - transparency = self.props.transparency, - size = self.props.height:map(function(y) - return UDim2.new(1, 0, y, -220 * y) - end), - position = UDim2.new(0, 0, 1, 0), - anchorPoint = Vector2.new(0, 1), - layoutOrder = self.props.layoutOrder, - }, { - Close = e(IconButton, { - icon = Assets.Images.Icons.Close, - iconSize = 24, - color = theme.ConnectionDetails.DisconnectColor, - transparency = self.props.transparency, + return Roact.createFragment({ + Navbar = e("Frame", { + Size = UDim2.new(1, 0, 0, 40), + BackgroundTransparency = 1, + }, { + Close = e(IconButton, { + icon = Assets.Images.Icons.Close, + iconSize = 24, + color = theme.Settings.Navbar.BackButtonColor, + transparency = self.props.transparency, - position = UDim2.new(1, 0, 0, 0), - anchorPoint = Vector2.new(1, 0), + position = UDim2.new(0, 0, 0.5, 0), + anchorPoint = Vector2.new(0, 0.5), - onClick = self.props.onClose, - }, { - Tip = e(Tooltip.Trigger, { - text = "Close the patch visualizer", + onClick = self.props.onBack, + }, { + Tip = e(Tooltip.Trigger, { + text = "Close", + }), + }), + + Title = e("TextLabel", { + Text = "Sync", + Font = Enum.Font.GothamMedium, + TextSize = 17, + TextXAlignment = Enum.TextXAlignment.Left, + TextColor3 = theme.TextColor, + TextTransparency = self.props.transparency, + Size = UDim2.new(1, -40, 0, 20), + Position = UDim2.new(0, 40, 0, 0), + BackgroundTransparency = 1, + }), + + Subtitle = e("TextLabel", { + Text = DateTime.fromUnixTimestamp(self.props.patchData.timestamp):FormatLocalTime("LTS", "en-us"), + TextXAlignment = Enum.TextXAlignment.Left, + Font = Enum.Font.Gotham, + TextSize = 15, + TextColor3 = theme.SubTextColor, + TextTruncate = Enum.TextTruncate.AtEnd, + TextTransparency = self.props.transparency, + Size = UDim2.new(1, -40, 0, 16), + Position = UDim2.new(0, 40, 0, 20), + BackgroundTransparency = 1, + }), + + Info = e("Frame", { + BackgroundTransparency = 1, + Size = UDim2.new(0, 10, 0, 24), + AutomaticSize = Enum.AutomaticSize.X, + Position = UDim2.new(1, -5, 0.5, 0), + AnchorPoint = Vector2.new(1, 0.5), + }, { + Tooltip = e(Tooltip.Trigger, { + text = `{applied} changes applied` + .. (if unapplied > 0 then `, {unapplied} changes failed` else ""), + }), + Content = e("Frame", { + BackgroundTransparency = 1, + Size = UDim2.new(0, 0, 1, 0), + AutomaticSize = Enum.AutomaticSize.X, + }, { + Layout = e("UIListLayout", { + FillDirection = Enum.FillDirection.Horizontal, + HorizontalAlignment = Enum.HorizontalAlignment.Right, + VerticalAlignment = Enum.VerticalAlignment.Center, + SortOrder = Enum.SortOrder.LayoutOrder, + Padding = UDim.new(0, 4), + }), + + StatusIcon = e("ImageLabel", { + BackgroundTransparency = 1, + Image = if unapplied > 0 + then Assets.Images.Icons.SyncWarning + else Assets.Images.Icons.SyncSuccess, + ImageColor3 = if unapplied > 0 then theme.Diff.Warning else theme.TextColor, + Size = UDim2.new(0, 24, 0, 24), + LayoutOrder = 10, + }), + StatusSpacer = e("Frame", { + BackgroundTransparency = 1, + Size = UDim2.new(0, 6, 0, 4), + LayoutOrder = 9, + }), + AppliedIcon = e("ImageLabel", { + BackgroundTransparency = 1, + Image = Assets.Images.Icons.Checkmark, + ImageColor3 = theme.TextColor, + Size = UDim2.new(0, 16, 0, 16), + LayoutOrder = 1, + }), + AppliedText = e("TextLabel", { + Text = applied, + Font = Enum.Font.Gotham, + TextSize = 15, + TextColor3 = theme.TextColor, + TextTransparency = self.props.transparency, + Size = UDim2.new(0, 0, 1, 0), + AutomaticSize = Enum.AutomaticSize.X, + BackgroundTransparency = 1, + LayoutOrder = 2, + }), + Warnings = if unapplied > 0 + then Roact.createFragment({ + WarningsSpacer = e("Frame", { + BackgroundTransparency = 1, + Size = UDim2.new(0, 4, 0, 4), + LayoutOrder = 3, + }), + UnappliedIcon = e("ImageLabel", { + BackgroundTransparency = 1, + Image = Assets.Images.Icons.Exclamation, + ImageColor3 = theme.Diff.Warning, + Size = UDim2.new(0, 4, 0, 16), + LayoutOrder = 4, + }), + UnappliedText = e("TextLabel", { + Text = unapplied, + Font = Enum.Font.Gotham, + TextSize = 15, + TextColor3 = theme.Diff.Warning, + TextTransparency = self.props.transparency, + Size = UDim2.new(0, 0, 1, 0), + AutomaticSize = Enum.AutomaticSize.X, + BackgroundTransparency = 1, + LayoutOrder = 5, + }), + }) + else nil, + }), + }), + + Divider = e("Frame", { + BackgroundColor3 = theme.Settings.DividerColor, + BackgroundTransparency = self.props.transparency, + Size = UDim2.new(1, 0, 0, 1), + Position = UDim2.new(0, 0, 1, 0), + BorderSizePixel = 0, + }, { + Gradient = e("UIGradient", { + Transparency = NumberSequence.new({ + NumberSequenceKeypoint.new(0, 1), + NumberSequenceKeypoint.new(0.1, 0), + NumberSequenceKeypoint.new(0.9, 0), + NumberSequenceKeypoint.new(1, 1), + }), + }), }), }), - PatchVisualizer = e(PatchVisualizer, { - size = UDim2.new(1, 0, 1, 0), + Patch = e(PatchVisualizer, { + size = UDim2.new(1, -10, 1, -65), + position = UDim2.new(0, 5, 1, -5), + anchorPoint = Vector2.new(0, 1), transparency = self.props.transparency, - layoutOrder = 3, + layoutOrder = self.props.layoutOrder, patchTree = self.props.patchTree, @@ -167,20 +287,7 @@ function ConnectedPage:getChangeInfoText() if patchData == nil then return "" end - - local elapsed = os.time() - patchData.timestamp - local unapplied = PatchSet.countChanges(patchData.unapplied) - - return "Synced " - .. timeSinceText(elapsed) - .. (if unapplied > 0 - then string.format( - ', but %d change%s failed to apply', - unapplied, - unapplied == 1 and "" or "s" - ) - else "") - .. "" + return timeSinceText(DateTime.now().UnixTimestamp - patchData.timestamp) end function ConnectedPage:startChangeInfoTextUpdater() @@ -190,13 +297,9 @@ function ConnectedPage:startChangeInfoTextUpdater() -- Start a new updater self.changeInfoTextUpdater = task.defer(function() while true do - if self.state.hoveringChangeInfo then - self.setChangeInfoText("" .. self:getChangeInfoText() .. "") - else - self.setChangeInfoText(self:getChangeInfoText()) - end + self.setChangeInfoText(self:getChangeInfoText()) - local elapsed = os.time() - self.props.patchData.timestamp + local elapsed = DateTime.now().UnixTimestamp - self.props.patchData.timestamp local updateInterval = 1 -- Update timestamp text as frequently as currently needed @@ -221,23 +324,6 @@ function ConnectedPage:stopChangeInfoTextUpdater() end function ConnectedPage:init() - self.changeDrawerMotor = Flipper.SingleMotor.new(0) - self.changeDrawerHeight = bindingUtil.fromMotor(self.changeDrawerMotor) - - self.changeDrawerMotor:onStep(function(value) - local renderChanges = value > 0.05 - - self:setState(function(state) - if state.renderChanges == renderChanges then - return nil - end - - return { - renderChanges = renderChanges, - } - end) - end) - self:setState({ renderChanges = false, hoveringChangeInfo = false, @@ -266,6 +352,10 @@ function ConnectedPage:didUpdate(previousProps) end function ConnectedPage:render() + local syncWarning = self.props.patchData + and self.props.patchData.unapplied + and PatchSet.countChanges(self.props.patchData.unapplied) > 0 + return Theme.with(function(theme) return Roact.createFragment({ Padding = e("UIPadding", { @@ -280,9 +370,88 @@ function ConnectedPage:render() Padding = UDim.new(0, 10), }), - Header = e(Header, { - transparency = self.props.transparency, - layoutOrder = 1, + Heading = e("Frame", { + BackgroundTransparency = 1, + Size = UDim2.new(1, 0, 0, 32), + }, { + Header = e(Header, { + transparency = self.props.transparency, + }), + + ChangeInfo = e("TextButton", { + Text = "", + Size = UDim2.new(0, 0, 1, 0), + AutomaticSize = Enum.AutomaticSize.X, + BackgroundColor3 = theme.BorderedContainer.BorderedColor, + BackgroundTransparency = if self.state.hoveringChangeInfo then 0.7 else 1, + BorderSizePixel = 0, + Position = UDim2.new(1, -5, 0.5, 0), + AnchorPoint = Vector2.new(1, 0.5), + [Roact.Event.MouseEnter] = function() + self:setState({ + hoveringChangeInfo = true, + }) + end, + [Roact.Event.MouseLeave] = function() + self:setState({ + hoveringChangeInfo = false, + }) + end, + [Roact.Event.Activated] = function() + self:setState(function(prevState) + prevState = prevState or {} + return { + renderChanges = not prevState.renderChanges, + } + end) + end, + }, { + Corner = e("UICorner", { + CornerRadius = UDim.new(0, 5), + }), + Tooltip = e(Tooltip.Trigger, { + text = if self.state.renderChanges then "Hide changes" else "View changes", + }), + Content = e("Frame", { + BackgroundTransparency = 1, + Size = UDim2.new(0, 0, 1, 0), + AutomaticSize = Enum.AutomaticSize.X, + }, { + Layout = e("UIListLayout", { + FillDirection = Enum.FillDirection.Horizontal, + HorizontalAlignment = Enum.HorizontalAlignment.Center, + VerticalAlignment = Enum.VerticalAlignment.Center, + SortOrder = Enum.SortOrder.LayoutOrder, + Padding = UDim.new(0, 5), + }), + Padding = e("UIPadding", { + PaddingLeft = UDim.new(0, 5), + PaddingRight = UDim.new(0, 5), + }), + Text = e("TextLabel", { + BackgroundTransparency = 1, + Text = self.changeInfoText, + Font = Enum.Font.Gotham, + TextSize = 15, + TextColor3 = if syncWarning then theme.Diff.Warning else theme.Header.VersionColor, + TextTransparency = self.props.transparency, + TextXAlignment = Enum.TextXAlignment.Right, + Size = UDim2.new(0, 0, 1, 0), + AutomaticSize = Enum.AutomaticSize.X, + LayoutOrder = 1, + }), + Icon = e("ImageLabel", { + BackgroundTransparency = 1, + Image = if syncWarning + then Assets.Images.Icons.SyncWarning + else Assets.Images.Icons.SyncSuccess, + ImageColor3 = if syncWarning then theme.Diff.Warning else theme.Header.VersionColor, + ImageTransparency = self.props.transparency, + Size = UDim2.new(0, 24, 0, 24), + LayoutOrder = 2, + }), + }), + }), }), ConnectionDetails = e(ConnectionDetails, { @@ -332,86 +501,61 @@ function ConnectedPage:render() }), }), - ChangeInfo = e("TextButton", { - Text = self.changeInfoText, - Font = Enum.Font.Gotham, - TextSize = 14, - TextWrapped = true, - RichText = true, - TextColor3 = theme.Header.VersionColor, - TextXAlignment = Enum.TextXAlignment.Left, - TextYAlignment = Enum.TextYAlignment.Top, - TextTransparency = self.props.transparency, - - Size = UDim2.new(1, 0, 0, 28), + ChangesViewer = e(StudioPluginGui, { + id = "Rojo_ChangesViewer", + title = "View changes", + active = self.state.renderChanges, + isEphemeral = true, - LayoutOrder = 4, - BackgroundTransparency = 1, + initDockState = Enum.InitialDockState.Float, + overridePreviousState = true, + floatingSize = Vector2.new(400, 500), + minimumSize = Vector2.new(300, 300), - [Roact.Event.MouseEnter] = function() - self:setState({ - hoveringChangeInfo = true, - }) - self.setChangeInfoText("" .. self:getChangeInfoText() .. "") - end, + zIndexBehavior = Enum.ZIndexBehavior.Sibling, - [Roact.Event.MouseLeave] = function() + onClose = function() self:setState({ - hoveringChangeInfo = false, + renderChanges = false, }) - self.setChangeInfoText(self:getChangeInfoText()) - end, - - [Roact.Event.Activated] = function() - if self.state.renderChanges then - self.changeDrawerMotor:setGoal(Flipper.Spring.new(0, { - frequency = 4, - dampingRatio = 1, - })) - else - self.changeDrawerMotor:setGoal(Flipper.Spring.new(1, { - frequency = 3, - dampingRatio = 1, - })) - end end, }, { - Tooltip = e(Tooltip.Trigger, { - text = if self.state.renderChanges then "Hide the changes" else "View the changes", + TooltipsProvider = e(Tooltip.Provider, nil, { + Tooltips = e(Tooltip.Container, nil), + Content = e("Frame", { + Size = UDim2.fromScale(1, 1), + BackgroundTransparency = 1, + }, { + Changes = e(ChangesViewer, { + transparency = self.props.transparency, + rendered = self.state.renderChanges, + patchData = self.props.patchData, + patchTree = self.props.patchTree, + serveSession = self.props.serveSession, + showStringDiff = function(oldString: string, newString: string) + self:setState({ + showingStringDiff = true, + oldString = oldString, + newString = newString, + }) + end, + showTableDiff = function(oldTable: { [any]: any? }, newTable: { [any]: any? }) + self:setState({ + showingTableDiff = true, + oldTable = oldTable, + newTable = newTable, + }) + end, + onBack = function() + self:setState({ + renderChanges = false, + }) + end, + }), + }), }), }), - ChangesDrawer = e(ChangesDrawer, { - rendered = self.state.renderChanges, - transparency = self.props.transparency, - patchTree = self.props.patchTree, - serveSession = self.props.serveSession, - height = self.changeDrawerHeight, - layoutOrder = 5, - - showStringDiff = function(oldString: string, newString: string) - self:setState({ - showingStringDiff = true, - oldString = oldString, - newString = newString, - }) - end, - showTableDiff = function(oldTable: { [any]: any? }, newTable: { [any]: any? }) - self:setState({ - showingTableDiff = true, - oldTable = oldTable, - newTable = newTable, - }) - end, - - onClose = function() - self.changeDrawerMotor:setGoal(Flipper.Spring.new(0, { - frequency = 4, - dampingRatio = 1, - })) - end, - }), - StringDiff = e(StudioPluginGui, { id = "Rojo_ConnectedStringDiff", title = "String diff", diff --git a/plugin/src/App/StatusPages/Settings/Setting.lua b/plugin/src/App/StatusPages/Settings/Setting.lua index 86adb6fcb..00c75d86d 100644 --- a/plugin/src/App/StatusPages/Settings/Setting.lua +++ b/plugin/src/App/StatusPages/Settings/Setting.lua @@ -13,10 +13,23 @@ local Theme = require(Plugin.App.Theme) local Checkbox = require(Plugin.App.Components.Checkbox) local Dropdown = require(Plugin.App.Components.Dropdown) local IconButton = require(Plugin.App.Components.IconButton) +local Tag = require(Plugin.App.Components.Tag) local e = Roact.createElement local DIVIDER_FADE_SIZE = 0.1 +local TAG_TYPES = { + unstable = { + text = "UNSTABLE", + icon = Assets.Images.Icons.Warning, + color = { "Settings", "Setting", "UnstableColor" }, + }, + debug = { + text = "DEBUG", + icon = Assets.Images.Icons.Debug, + color = { "Settings", "Setting", "DebugColor" }, + }, +} local function getTextBounds(text, textSize, font, lineHeight, bounds) local textBounds = TextService:GetTextSize(text, textSize, font, bounds) @@ -27,6 +40,17 @@ local function getTextBounds(text, textSize, font, lineHeight, bounds) return Vector2.new(textBounds.X, lineHeightAbsolute * lineCount - (lineHeightAbsolute - textSize)) end +local function getThemeColorFromPath(theme, path) + local color = theme + for _, key in path do + if color[key] == nil then + return theme.BrandColor + end + color = color[key] + end + return color +end + local Setting = Roact.Component:extend("Setting") function Setting:init() @@ -51,11 +75,11 @@ end function Setting:render() return Theme.with(function(theme) - theme = theme.Settings + local settingsTheme = theme.Settings return e("Frame", { Size = self.contentSize:map(function(value) - return UDim2.new(1, 0, 0, 20 + value.Y + 20) + return UDim2.new(1, 0, 0, value.Y + 20) end), LayoutOrder = self.props.layoutOrder, ZIndex = -self.props.layoutOrder, @@ -106,7 +130,7 @@ function Setting:render() then e(IconButton, { icon = Assets.Images.Icons.Reset, iconSize = 24, - color = theme.BackButtonColor, + color = settingsTheme.BackButtonColor, transparency = self.props.transparency, visible = self.props.showReset, layoutOrder = -1, @@ -120,29 +144,49 @@ function Setting:render() Size = UDim2.new(1, 0, 1, 0), BackgroundTransparency = 1, }, { - Name = e("TextLabel", { - Text = (if self.props.experimental then 'âš  ' else "") - .. self.props.name, - Font = Enum.Font.GothamBold, - TextSize = 17, - TextColor3 = theme.Setting.NameColor, - TextXAlignment = Enum.TextXAlignment.Left, - TextTransparency = self.props.transparency, - RichText = true, - - Size = UDim2.new(1, 0, 0, 17), - - LayoutOrder = 1, + Heading = e("Frame", { + Size = UDim2.new(1, 0, 0, 16), BackgroundTransparency = 1, + }, { + Layout = e("UIListLayout", { + VerticalAlignment = Enum.VerticalAlignment.Center, + FillDirection = Enum.FillDirection.Horizontal, + SortOrder = Enum.SortOrder.LayoutOrder, + Padding = UDim.new(0, 5), + }), + Tag = if self.props.tag and TAG_TYPES[self.props.tag] + then e(Tag, { + layoutOrder = 1, + transparency = self.props.transparency, + text = TAG_TYPES[self.props.tag].text, + icon = TAG_TYPES[self.props.tag].icon, + color = getThemeColorFromPath(theme, TAG_TYPES[self.props.tag].color), + }) + else nil, + Name = e("TextLabel", { + Text = self.props.name, + Font = Enum.Font.GothamBold, + TextSize = 16, + TextColor3 = if self.props.tag and TAG_TYPES[self.props.tag] + then getThemeColorFromPath(theme, TAG_TYPES[self.props.tag].color) + else settingsTheme.Setting.NameColor, + TextXAlignment = Enum.TextXAlignment.Left, + TextTransparency = self.props.transparency, + RichText = true, + + Size = UDim2.new(1, 0, 0, 16), + + LayoutOrder = 2, + BackgroundTransparency = 1, + }), }), Description = e("TextLabel", { - Text = (if self.props.experimental then '[Experimental] ' else "") - .. self.props.description, + Text = self.props.description, Font = Enum.Font.Gotham, LineHeight = 1.2, TextSize = 14, - TextColor3 = theme.Setting.DescriptionColor, + TextColor3 = settingsTheme.Setting.DescriptionColor, TextXAlignment = Enum.TextXAlignment.Left, TextTransparency = self.props.transparency, TextWrapped = true, @@ -152,11 +196,9 @@ function Setting:render() containerSize = self.containerSize, inputSize = self.inputSize, }):map(function(values) - local desc = (if self.props.experimental then "[Experimental] " else "") - .. self.props.description local offset = values.inputSize.X + 5 local textBounds = getTextBounds( - desc, + self.props.description, 14, Enum.Font.Gotham, 1.2, @@ -165,7 +207,7 @@ function Setting:render() return UDim2.new(1, -offset, 0, textBounds.Y) end), - LayoutOrder = 2, + LayoutOrder = 3, BackgroundTransparency = 1, }), @@ -173,21 +215,16 @@ function Setting:render() VerticalAlignment = Enum.VerticalAlignment.Center, FillDirection = Enum.FillDirection.Vertical, SortOrder = Enum.SortOrder.LayoutOrder, - Padding = UDim.new(0, 6), + Padding = UDim.new(0, 5), [Roact.Change.AbsoluteContentSize] = function(object) self.setContentSize(object.AbsoluteContentSize) end, }), - - Padding = e("UIPadding", { - PaddingTop = UDim.new(0, 20), - PaddingBottom = UDim.new(0, 20), - }), }), Divider = e("Frame", { - BackgroundColor3 = theme.DividerColor, + BackgroundColor3 = settingsTheme.DividerColor, BackgroundTransparency = self.props.transparency, Size = UDim2.new(1, 0, 0, 1), BorderSizePixel = 0, diff --git a/plugin/src/App/StatusPages/Settings/init.lua b/plugin/src/App/StatusPages/Settings/init.lua index a33eb1b54..70f835084 100644 --- a/plugin/src/App/StatusPages/Settings/init.lua +++ b/plugin/src/App/StatusPages/Settings/init.lua @@ -26,7 +26,7 @@ local function invertTbl(tbl) end local invertedLevels = invertTbl(Log.Level) -local confirmationBehaviors = { "Initial", "Always", "Large Changes", "Unlisted PlaceId" } +local confirmationBehaviors = { "Initial", "Always", "Large Changes", "Unlisted PlaceId", "Never" } local function Navbar(props) return Theme.with(function(theme) @@ -84,148 +84,160 @@ function SettingsPage:render() return Theme.with(function(theme) theme = theme.Settings - return e(ScrollingFrame, { - size = UDim2.new(1, 0, 1, 0), - contentSize = self.contentSize, - transparency = self.props.transparency, - }, { + return Roact.createFragment({ Navbar = e(Navbar, { onBack = self.props.onBack, transparency = self.props.transparency, layoutOrder = layoutIncrement(), }), - - ShowNotifications = e(Setting, { - id = "showNotifications", - name = "Show Notifications", - description = "Popup notifications in viewport", + Content = e(ScrollingFrame, { + size = UDim2.new(1, 0, 1, -47), + position = UDim2.new(0, 0, 0, 47), + contentSize = self.contentSize, transparency = self.props.transparency, - layoutOrder = layoutIncrement(), - }), + }, { + ShowNotifications = e(Setting, { + id = "showNotifications", + name = "Show Notifications", + description = "Popup notifications in viewport", + transparency = self.props.transparency, + layoutOrder = layoutIncrement(), + }), - SyncReminder = e(Setting, { - id = "syncReminder", - name = "Sync Reminder", - description = "Notify to sync when opening a place that has previously been synced", - transparency = self.props.transparency, - visible = Settings:getBinding("showNotifications"), - layoutOrder = layoutIncrement(), - }), + SyncReminder = e(Setting, { + id = "syncReminder", + name = "Sync Reminder", + description = "Notify to sync when opening a place that has previously been synced", + transparency = self.props.transparency, + visible = Settings:getBinding("showNotifications"), + layoutOrder = layoutIncrement(), + }), - ConfirmationBehavior = e(Setting, { - id = "confirmationBehavior", - name = "Confirmation Behavior", - description = "When to prompt for confirmation before syncing", - transparency = self.props.transparency, - layoutOrder = layoutIncrement(), + ConfirmationBehavior = e(Setting, { + id = "confirmationBehavior", + name = "Confirmation Behavior", + description = "When to prompt for confirmation before syncing", + transparency = self.props.transparency, + layoutOrder = layoutIncrement(), - options = confirmationBehaviors, - }), + options = confirmationBehaviors, + }), - LargeChangesConfirmationThreshold = e(Setting, { - id = "largeChangesConfirmationThreshold", - name = "Confirmation Threshold", - description = "How many modified instances to be considered a large change", - transparency = self.props.transparency, - layoutOrder = layoutIncrement(), - visible = Settings:getBinding("confirmationBehavior"):map(function(value) - return value == "Large Changes" - end), - input = e(TextInput, { - size = UDim2.new(0, 40, 0, 28), - text = Settings:getBinding("largeChangesConfirmationThreshold"):map(function(value) - return tostring(value) + LargeChangesConfirmationThreshold = e(Setting, { + id = "largeChangesConfirmationThreshold", + name = "Confirmation Threshold", + description = "How many modified instances to be considered a large change", + transparency = self.props.transparency, + layoutOrder = layoutIncrement(), + visible = Settings:getBinding("confirmationBehavior"):map(function(value) + return value == "Large Changes" end), + input = e(TextInput, { + size = UDim2.new(0, 40, 0, 28), + text = Settings:getBinding("largeChangesConfirmationThreshold"):map(function(value) + return tostring(value) + end), + transparency = self.props.transparency, + enabled = true, + onEntered = function(text) + local number = tonumber(string.match(text, "%d+")) + if number then + Settings:set("largeChangesConfirmationThreshold", math.clamp(number, 1, 999)) + else + -- Force text back to last valid value + Settings:set( + "largeChangesConfirmationThreshold", + Settings:get("largeChangesConfirmationThreshold") + ) + end + end, + }), + }), + + PlaySounds = e(Setting, { + id = "playSounds", + name = "Play Sounds", + description = "Toggle sound effects", transparency = self.props.transparency, - enabled = true, - onEntered = function(text) - local number = tonumber(string.match(text, "%d+")) - if number then - Settings:set("largeChangesConfirmationThreshold", math.clamp(number, 1, 999)) - else - -- Force text back to last valid value - Settings:set( - "largeChangesConfirmationThreshold", - Settings:get("largeChangesConfirmationThreshold") - ) - end - end, + layoutOrder = layoutIncrement(), }), - }), - PlaySounds = e(Setting, { - id = "playSounds", - name = "Play Sounds", - description = "Toggle sound effects", - transparency = self.props.transparency, - layoutOrder = layoutIncrement(), - }), + AutoConnectPlaytestServer = e(Setting, { + id = "autoConnectPlaytestServer", + name = "Auto Connect Playtest Server", + description = "Automatically connect game server to Rojo when playtesting while connected in Edit", + tag = "unstable", + transparency = self.props.transparency, + layoutOrder = layoutIncrement(), + }), - AutoConnectPlaytestServer = e(Setting, { - id = "autoConnectPlaytestServer", - name = "Auto Connect Playtest Server", - description = "Automatically connect game server to Rojo when playtesting while connected in Edit", - experimental = true, - transparency = self.props.transparency, - layoutOrder = layoutIncrement(), - }), + OpenScriptsExternally = e(Setting, { + id = "openScriptsExternally", + name = "Open Scripts Externally", + description = "Attempt to open scripts in an external editor", + tag = "unstable", + transparency = self.props.transparency, + layoutOrder = layoutIncrement(), + }), - OpenScriptsExternally = e(Setting, { - id = "openScriptsExternally", - name = "Open Scripts Externally", - description = "Attempt to open scripts in an external editor", - locked = self.props.syncActive, - experimental = true, - transparency = self.props.transparency, - layoutOrder = layoutIncrement(), - }), + TwoWaySync = e(Setting, { + id = "twoWaySync", + name = "Two-Way Sync", + description = "Editing files in Studio will sync them into the filesystem", + locked = self.props.syncActive, + tag = "unstable", + transparency = self.props.transparency, + layoutOrder = layoutIncrement(), + }), - TwoWaySync = e(Setting, { - id = "twoWaySync", - name = "Two-Way Sync", - description = "Editing files in Studio will sync them into the filesystem", - locked = self.props.syncActive, - experimental = true, - transparency = self.props.transparency, - layoutOrder = layoutIncrement(), - }), + LogLevel = e(Setting, { + id = "logLevel", + name = "Log Level", + description = "Plugin output verbosity level", + tag = "debug", + transparency = self.props.transparency, + layoutOrder = layoutIncrement(), - LogLevel = e(Setting, { - id = "logLevel", - name = "Log Level", - description = "Plugin output verbosity level", - transparency = self.props.transparency, - layoutOrder = layoutIncrement(), + options = invertedLevels, + showReset = Settings:getBinding("logLevel"):map(function(value) + return value ~= "Info" + end), + onReset = function() + Settings:set("logLevel", "Info") + end, + }), - options = invertedLevels, - showReset = Settings:getBinding("logLevel"):map(function(value) - return value ~= "Info" - end), - onReset = function() - Settings:set("logLevel", "Info") - end, - }), + TypecheckingEnabled = e(Setting, { + id = "typecheckingEnabled", + name = "Typechecking", + description = "Toggle typechecking on the API surface", + tag = "debug", + transparency = self.props.transparency, + layoutOrder = layoutIncrement(), + }), - TypecheckingEnabled = e(Setting, { - id = "typecheckingEnabled", - name = "Typechecking", - description = "Toggle typechecking on the API surface", - transparency = self.props.transparency, - layoutOrder = layoutIncrement(), - }), + TimingLogsEnabled = e(Setting, { + id = "timingLogsEnabled", + name = "Timing Logs", + description = "Toggle logging timing of internal actions for benchmarking Rojo performance", + tag = "debug", + transparency = self.props.transparency, + layoutOrder = layoutIncrement(), + }), - Layout = e("UIListLayout", { - FillDirection = Enum.FillDirection.Vertical, - SortOrder = Enum.SortOrder.LayoutOrder, + Layout = e("UIListLayout", { + FillDirection = Enum.FillDirection.Vertical, + SortOrder = Enum.SortOrder.LayoutOrder, - [Roact.Change.AbsoluteContentSize] = function(object) - self.setContentSize(object.AbsoluteContentSize) - end, - }), + [Roact.Change.AbsoluteContentSize] = function(object) + self.setContentSize(object.AbsoluteContentSize) + end, + }), - Padding = e("UIPadding", { - PaddingLeft = UDim.new(0, 20), - PaddingRight = UDim.new(0, 20), + Padding = e("UIPadding", { + PaddingLeft = UDim.new(0, 20), + PaddingRight = UDim.new(0, 20), + }), }), }) end) diff --git a/plugin/src/App/Theme.lua b/plugin/src/App/Theme.lua index f1e9c3971..42d619425 100644 --- a/plugin/src/App/Theme.lua +++ b/plugin/src/App/Theme.lua @@ -32,9 +32,13 @@ local StudioProvider = Roact.Component:extend("StudioProvider") function StudioProvider:updateTheme() local studioTheme = getStudio().Theme + local isDark = studioTheme.Name == "Dark" + local theme = strict(studioTheme.Name .. "Theme", { + BrandColor = BRAND_COLOR, BackgroundColor = studioTheme:GetColor(Enum.StudioStyleGuideColor.MainBackground), TextColor = studioTheme:GetColor(Enum.StudioStyleGuideColor.MainText), + SubTextColor = studioTheme:GetColor(Enum.StudioStyleGuideColor.SubText), Button = { Solid = { -- Solid uses brand theming, not Studio theming. @@ -139,9 +143,10 @@ function StudioProvider:updateTheme() BackgroundColor = studioTheme:GetColor(Enum.StudioStyleGuideColor.InputFieldBackground), }, Diff = { - Add = studioTheme:GetColor(Enum.StudioStyleGuideColor.DiffTextAdditionBackground), - Remove = studioTheme:GetColor(Enum.StudioStyleGuideColor.DiffTextDeletionBackground), - Edit = studioTheme:GetColor(Enum.StudioStyleGuideColor.DiffLineNumSeparatorBackground), + -- Studio doesn't have good colors since their diffs use backgrounds, not text + Add = if isDark then Color3.fromRGB(143, 227, 154) else Color3.fromRGB(41, 164, 45), + Remove = if isDark then Color3.fromRGB(242, 125, 125) else Color3.fromRGB(150, 29, 29), + Edit = if isDark then Color3.fromRGB(120, 154, 248) else Color3.fromRGB(0, 70, 160), Row = studioTheme:GetColor(Enum.StudioStyleGuideColor.BrightText), Warning = studioTheme:GetColor(Enum.StudioStyleGuideColor.WarningText), }, @@ -162,6 +167,8 @@ function StudioProvider:updateTheme() Setting = { NameColor = studioTheme:GetColor(Enum.StudioStyleGuideColor.BrightText), DescriptionColor = studioTheme:GetColor(Enum.StudioStyleGuideColor.MainText), + UnstableColor = studioTheme:GetColor(Enum.StudioStyleGuideColor.WarningText), + DebugColor = studioTheme:GetColor(Enum.StudioStyleGuideColor.InfoText), }, }, Header = { diff --git a/plugin/src/App/init.lua b/plugin/src/App/init.lua index ecb807f05..bd21765d0 100644 --- a/plugin/src/App/init.lua +++ b/plugin/src/App/init.lua @@ -425,11 +425,6 @@ function App:startSession() local host, port = self:getHostAndPort() - local sessionOptions = { - openScriptsExternally = Settings:get("openScriptsExternally"), - twoWaySync = Settings:get("twoWaySync"), - } - local baseUrl = if string.find(host, "^https?://") then string.format("%s:%s", host, port) else string.format("http://%s:%s", host, port) @@ -437,8 +432,7 @@ function App:startSession() local serveSession = ServeSession.new({ apiContext = apiContext, - openScriptsExternally = sessionOptions.openScriptsExternally, - twoWaySync = sessionOptions.twoWaySync, + twoWaySync = Settings:get("twoWaySync"), }) self.cleanupPrecommit = serveSession.__reconciler:hookPrecommit(function(patch, instanceMap) @@ -457,7 +451,7 @@ function App:startSession() end) serveSession:hookPostcommit(function(patch, _instanceMap, unapplied) - local now = os.time() + local now = DateTime.now().UnixTimestamp local old = self.state.patchData if PatchSet.isEmpty(patch) then @@ -582,6 +576,9 @@ function App:startSession() return "Accept" end end + elseif confirmationBehavior == "Never" then + Log.trace("Accepting patch without confirmation because behavior is set to Never") + return "Accept" end -- The datamodel name gets overwritten by Studio, making confirmation of it intrusive diff --git a/plugin/src/Assets.lua b/plugin/src/Assets.lua index dbc60a166..e48c1217e 100644 --- a/plugin/src/Assets.lua +++ b/plugin/src/Assets.lua @@ -25,6 +25,12 @@ local Assets = { Back = "rbxassetid://6017213752", Reset = "rbxassetid://10142422327", Expand = "rbxassetid://12045401097", + Warning = "rbxassetid://16571019891", + Debug = "rbxassetid://16588411361", + Checkmark = "rbxassetid://16571012729", + Exclamation = "rbxassetid://16571172190", + SyncSuccess = "rbxassetid://16565035221", + SyncWarning = "rbxassetid://16565325171", }, Diff = { Add = "rbxassetid://10434145835", diff --git a/plugin/src/Config.lua b/plugin/src/Config.lua index 0238b2cb6..5567efca2 100644 --- a/plugin/src/Config.lua +++ b/plugin/src/Config.lua @@ -3,7 +3,8 @@ local strict = require(script.Parent.strict) local isDevBuild = script.Parent.Parent:FindFirstChild("ROJO_DEV_BUILD") ~= nil local Version = script.Parent.Parent.Version -local major, minor, patch, metadata = Version.Value:match("^(%d+)%.(%d+)%.(%d+)(.*)$") +local trimmedVersionValue = Version.Value:gsub("^%s+", ""):gsub("%s+$", "") +local major, minor, patch, metadata = trimmedVersionValue:match("^(%d+)%.(%d+)%.(%d+)(.*)$") local realVersion = { major, minor, patch, metadata } for i = 1, 3 do diff --git a/plugin/src/InstanceMap.lua b/plugin/src/InstanceMap.lua index b035d423c..76754fef5 100644 --- a/plugin/src/InstanceMap.lua +++ b/plugin/src/InstanceMap.lua @@ -112,9 +112,12 @@ end function InstanceMap:destroyInstance(instance) local id = self.fromInstances[instance] - local descendants = instance:GetDescendants() - instance:Destroy() + + -- Because the user might want to Undo this change, we cannot use Destroy + -- since that locks that parent and prevents ChangeHistoryService from + -- ever bringing it back. Instead, we parent to nil. + instance.Parent = nil -- After the instance is successfully destroyed, -- we can remove all the id mappings diff --git a/plugin/src/PatchSet.lua b/plugin/src/PatchSet.lua index abbac0cbb..064def36c 100644 --- a/plugin/src/PatchSet.lua +++ b/plugin/src/PatchSet.lua @@ -211,9 +211,11 @@ end function PatchSet.countChanges(patch) local count = 0 - for _ in patch.added do - -- Adding an instance is 1 change - count += 1 + for _, add in patch.added do + -- Adding an instance is 1 change per property + for _ in add.Properties do + count += 1 + end end for _ in patch.removed do -- Removing an instance is 1 change diff --git a/plugin/src/PatchTree.lua b/plugin/src/PatchTree.lua index e469e2112..c1c5f91ca 100644 --- a/plugin/src/PatchTree.lua +++ b/plugin/src/PatchTree.lua @@ -11,6 +11,7 @@ local Packages = Rojo.Packages local Log = require(Packages.Log) +local Timer = require(Plugin.Timer) local Types = require(Plugin.Types) local decodeValue = require(Plugin.Reconciler.decodeValue) local getProperty = require(Plugin.Reconciler.getProperty) @@ -78,6 +79,15 @@ function Tree.new() return setmetatable(tree, Tree) end +-- Iterates over all nodes and counts them up +function Tree:getCount() + local count = 0 + self:forEach(function() + count += 1 + end) + return count +end + -- Iterates over all sub-nodes, depth first -- node is where to start from, defaults to root -- depth is used for recursion but can be used to set the starting depth @@ -122,6 +132,7 @@ end -- props must contain id, and cannot contain children or parentId -- other than those three, it can hold anything function Tree:addNode(parent, props) + Timer.start("Tree:addNode") assert(props.id, "props must contain id") parent = parent or "ROOT" @@ -132,6 +143,7 @@ function Tree:addNode(parent, props) for k, v in props do node[k] = v end + Timer.stop() return node end @@ -142,18 +154,21 @@ function Tree:addNode(parent, props) local parentNode = self:getNode(parent) if not parentNode then Log.warn("Failed to create node since parent doesnt exist: {}, {}", parent, props) + Timer.stop() return end parentNode.children[node.id] = node self.idToNode[node.id] = node + Timer.stop() return node end -- Given a list of ancestor ids in descending order, builds the nodes for them -- using the patch and instanceMap info function Tree:buildAncestryNodes(previousId: string?, ancestryIds: { string }, patch, instanceMap) + Timer.start("Tree:buildAncestryNodes") -- Build nodes for ancestry by going up the tree previousId = previousId or "ROOT" @@ -171,6 +186,8 @@ function Tree:buildAncestryNodes(previousId: string?, ancestryIds: { string }, p }) previousId = ancestorId end + + Timer.stop() end local PatchTree = {} @@ -178,10 +195,12 @@ local PatchTree = {} -- Builds a new tree from a patch and instanceMap -- uses changeListHeaders in node.changeList function PatchTree.build(patch, instanceMap, changeListHeaders) + Timer.start("PatchTree.build") local tree = Tree.new() local knownAncestors = {} + Timer.start("patch.updated") for _, change in patch.updated do local instance = instanceMap.fromIds[change.id] if not instance then @@ -209,15 +228,14 @@ function PatchTree.build(patch, instanceMap, changeListHeaders) tree:buildAncestryNodes(previousId, ancestryIds, patch, instanceMap) -- Gather detail text - local changeList, hint = nil, nil + local changeList, changeInfo = nil, nil if next(change.changedProperties) or change.changedName then changeList = {} - local hintBuffer, i = {}, 0 + local changeIndex = 0 local function addProp(prop: string, current: any?, incoming: any?, metadata: any?) - i += 1 - hintBuffer[i] = prop - changeList[i] = { prop, current, incoming, metadata } + changeIndex += 1 + changeList[changeIndex] = { prop, current, incoming, metadata } end -- Gather the changes @@ -237,19 +255,9 @@ function PatchTree.build(patch, instanceMap, changeListHeaders) ) end - -- Finalize detail values - - -- Trim hint to top 3 - table.sort(hintBuffer) - if #hintBuffer > 3 then - hintBuffer = { - hintBuffer[1], - hintBuffer[2], - hintBuffer[3], - i - 3 .. " more", - } - end - hint = table.concat(hintBuffer, ", ") + changeInfo = { + edits = changeIndex, + } -- Sort changes and add header table.sort(changeList, function(a, b) @@ -265,11 +273,13 @@ function PatchTree.build(patch, instanceMap, changeListHeaders) className = instance.ClassName, name = instance.Name, instance = instance, - hint = hint, + changeInfo = changeInfo, changeList = changeList, }) end + Timer.stop() + Timer.start("patch.removed") for _, idOrInstance in patch.removed do local instance = if Types.RbxId(idOrInstance) then instanceMap.fromIds[idOrInstance] else idOrInstance if not instance then @@ -311,7 +321,9 @@ function PatchTree.build(patch, instanceMap, changeListHeaders) instance = instance, }) end + Timer.stop() + Timer.start("patch.added") for id, change in patch.added do -- Gather ancestors from existing DOM or future additions local ancestryIds = {} @@ -346,36 +358,24 @@ function PatchTree.build(patch, instanceMap, changeListHeaders) tree:buildAncestryNodes(previousId, ancestryIds, patch, instanceMap) -- Gather detail text - local changeList, hint = nil, nil + local changeList, changeInfo = nil, nil if next(change.Properties) then changeList = {} - local hintBuffer, i = {}, 0 - for prop, incoming in change.Properties do - i += 1 - hintBuffer[i] = prop + local changeIndex = 0 + local function addProp(prop: string, incoming: any) + changeIndex += 1 + changeList[changeIndex] = { prop, "N/A", incoming } + end + for prop, incoming in change.Properties do local success, incomingValue = decodeValue(incoming, instanceMap) - if success then - table.insert(changeList, { prop, "N/A", incomingValue }) - else - table.insert(changeList, { prop, "N/A", select(2, next(incoming)) }) - end + addProp(prop, if success then incomingValue else select(2, next(incoming))) end - -- Finalize detail values - - -- Trim hint to top 3 - table.sort(hintBuffer) - if #hintBuffer > 3 then - hintBuffer = { - hintBuffer[1], - hintBuffer[2], - hintBuffer[3], - i - 3 .. " more", - } - end - hint = table.concat(hintBuffer, ", ") + changeInfo = { + edits = changeIndex, + } -- Sort changes and add header table.sort(changeList, function(a, b) @@ -390,40 +390,32 @@ function PatchTree.build(patch, instanceMap, changeListHeaders) patchType = "Add", className = change.ClassName, name = change.Name, - hint = hint, + changeInfo = changeInfo, changeList = changeList, instance = instanceMap.fromIds[id], }) end + Timer.stop() + Timer.stop() return tree end --- Creates a deep copy of a tree for immutability purposes in Roact -function PatchTree.clone(tree) - if not tree then - return - end - - local newTree = Tree.new() - tree:forEach(function(node) - newTree:addNode(node.parentId, table.clone(node)) - end) - - return newTree -end - -- Updates the metadata of a tree with the unapplied patch and currently existing instances -- Builds a new tree from the data if one isn't provided -- Always returns a new tree for immutability purposes in Roact function PatchTree.updateMetadata(tree, patch, instanceMap, unappliedPatch) + Timer.start("PatchTree.updateMetadata") if tree then - tree = PatchTree.clone(tree) + -- A shallow copy is enough for our purposes here since we really only need a new top-level object + -- for immutable comparison checks in Roact + tree = table.clone(tree) else tree = PatchTree.build(patch, instanceMap) end -- Update isWarning metadata + Timer.start("isWarning") for _, failedChange in unappliedPatch.updated do local node = tree:getNode(failedChange.id) if not node then @@ -436,6 +428,8 @@ function PatchTree.updateMetadata(tree, patch, instanceMap, unappliedPatch) if not node.changeList then continue end + + local warnings = 0 for _, change in node.changeList do local property = change[1] local propertyFailedToApply = if property == "Name" @@ -446,6 +440,8 @@ function PatchTree.updateMetadata(tree, patch, instanceMap, unappliedPatch) -- This change didn't fail, no need to mark continue end + + warnings += 1 if change[4] == nil then change[4] = { isWarning = true } else @@ -453,6 +449,11 @@ function PatchTree.updateMetadata(tree, patch, instanceMap, unappliedPatch) end Log.trace(" Marked property as warning: {}.{}", node.name, property) end + + node.changeInfo = { + edits = (node.changeInfo.edits or (#node.changeList - 1)) - warnings, + failed = if warnings > 0 then warnings else nil, + } end for failedAdditionId in unappliedPatch.added do local node = tree:getNode(failedAdditionId) @@ -466,6 +467,7 @@ function PatchTree.updateMetadata(tree, patch, instanceMap, unappliedPatch) if not node.changeList then continue end + for _, change in node.changeList do -- Failed addition means that all properties failed to be added if change[4] == nil then @@ -475,6 +477,10 @@ function PatchTree.updateMetadata(tree, patch, instanceMap, unappliedPatch) end Log.trace(" Marked property as warning: {}.{}", node.name, change[1]) end + + node.changeInfo = { + failed = node.changeInfo.edits or (#node.changeList - 1), + } end for _, failedRemovalIdOrInstance in unappliedPatch.removed do local failedRemovalId = if Types.RbxId(failedRemovalIdOrInstance) @@ -492,8 +498,10 @@ function PatchTree.updateMetadata(tree, patch, instanceMap, unappliedPatch) node.isWarning = true Log.trace("Marked node as warning: {} {}", node.id, node.name) end + Timer.stop() -- Update if instances exist + Timer.start("instanceAncestry") tree:forEach(function(node) if node.instance then if node.instance.Parent == nil and node.instance ~= game then @@ -509,7 +517,9 @@ function PatchTree.updateMetadata(tree, patch, instanceMap, unappliedPatch) end end end) + Timer.stop() + Timer.stop() return tree end diff --git a/plugin/src/Reconciler/applyPatch.lua b/plugin/src/Reconciler/applyPatch.lua index 5ee6ed5e4..05e7412a8 100644 --- a/plugin/src/Reconciler/applyPatch.lua +++ b/plugin/src/Reconciler/applyPatch.lua @@ -20,6 +20,11 @@ local setProperty = require(script.Parent.setProperty) local function applyPatch(instanceMap, patch) local patchTimestamp = DateTime.now():FormatLocalTime("LTS", "en-us") + local historyRecording = ChangeHistoryService:TryBeginRecording("Rojo: Patch " .. patchTimestamp) + if not historyRecording then + -- There can only be one recording at a time + Log.debug("Failed to begin history recording for " .. patchTimestamp .. ". Another recording is in progress.") + end -- Tracks any portions of the patch that could not be applied to the DOM. local unappliedPatch = PatchSet.newEmpty() @@ -62,6 +67,9 @@ local function applyPatch(instanceMap, patch) if parentInstance == nil then -- This would be peculiar. If you create an instance with no -- parent, were you supposed to create it at all? + if historyRecording then + ChangeHistoryService:FinishRecording(historyRecording, Enum.FinishRecordingOperation.Commit) + end invariant( "Cannot add an instance from a patch that has no parent.\nInstance {} with parent {}.\nState: {:#?}", id, @@ -164,10 +172,14 @@ local function applyPatch(instanceMap, patch) end -- See you later, original instance. - -- + + -- Because the user might want to Undo this change, we cannot use Destroy + -- since that locks that parent and prevents ChangeHistoryService from + -- ever bringing it back. Instead, we parent to nil. + -- TODO: Can this fail? Some kinds of instance may not appreciate - -- being destroyed, like services. - instance:Destroy() + -- being reparented, like services. + instance.Parent = nil -- This completes your rebuilding a plane mid-flight safety -- instruction. Please sit back, relax, and enjoy your flight. @@ -214,7 +226,9 @@ local function applyPatch(instanceMap, patch) end end - ChangeHistoryService:SetWaypoint("Rojo: Patch " .. patchTimestamp) + if historyRecording then + ChangeHistoryService:FinishRecording(historyRecording, Enum.FinishRecordingOperation.Commit) + end return unappliedPatch end diff --git a/plugin/src/Reconciler/applyPatch.spec.lua b/plugin/src/Reconciler/applyPatch.spec.lua index c561db751..b44e3eda6 100644 --- a/plugin/src/Reconciler/applyPatch.spec.lua +++ b/plugin/src/Reconciler/applyPatch.spec.lua @@ -4,25 +4,41 @@ return function() local InstanceMap = require(script.Parent.Parent.InstanceMap) local PatchSet = require(script.Parent.Parent.PatchSet) - local dummy = Instance.new("Folder") - local function wasDestroyed(instance) + local container = Instance.new("Folder") + + local tempContainer = Instance.new("Folder") + local function wasRemoved(instance) -- If an instance was destroyed, its parent property is locked. - local ok = pcall(function() + -- If an instance was removed, its parent property is nil. + -- We need to ensure we only remove, so that ChangeHistoryService can still Undo. + + local isParentUnlocked = pcall(function() local oldParent = instance.Parent - instance.Parent = dummy + instance.Parent = tempContainer instance.Parent = oldParent end) - return not ok + return instance.Parent == nil and isParentUnlocked end + beforeEach(function() + container:ClearAllChildren() + end) + + afterAll(function() + container:Destroy() + tempContainer:Destroy() + end) + it("should return an empty patch if given an empty patch", function() local patch = applyPatch(InstanceMap.new(), PatchSet.newEmpty()) assert(PatchSet.isEmpty(patch), "expected remaining patch to be empty") end) - it("should destroy instances listed for remove", function() + it("should remove instances listed for remove", function() local root = Instance.new("Folder") + root.Name = "ROOT" + root.Parent = container local child = Instance.new("Folder") child.Name = "Child" @@ -38,14 +54,16 @@ return function() local unapplied = applyPatch(instanceMap, patch) assert(PatchSet.isEmpty(unapplied), "expected remaining patch to be empty") - assert(not wasDestroyed(root), "expected root to be left alone") - assert(wasDestroyed(child), "expected child to be destroyed") + assert(not wasRemoved(root), "expected root to be left alone") + assert(wasRemoved(child), "expected child to be removed") instanceMap:stop() end) - it("should destroy IDs listed for remove", function() + it("should remove IDs listed for remove", function() local root = Instance.new("Folder") + root.Name = "ROOT" + root.Parent = container local child = Instance.new("Folder") child.Name = "Child" @@ -62,8 +80,8 @@ return function() assert(PatchSet.isEmpty(unapplied), "expected remaining patch to be empty") expect(instanceMap:size()).to.equal(1) - assert(not wasDestroyed(root), "expected root to be left alone") - assert(wasDestroyed(child), "expected child to be destroyed") + assert(not wasRemoved(root), "expected root to be left alone") + assert(wasRemoved(child), "expected child to be removed") instanceMap:stop() end) @@ -73,6 +91,8 @@ return function() -- tests on reify, not here. local root = Instance.new("Folder") + root.Name = "ROOT" + root.Parent = container local instanceMap = InstanceMap.new() instanceMap:insert("ROOT", root) @@ -113,6 +133,8 @@ return function() it("should return unapplied additions when instances cannot be created", function() local root = Instance.new("Folder") + root.Name = "ROOT" + root.Parent = container local instanceMap = InstanceMap.new() instanceMap:insert("ROOT", root) @@ -159,6 +181,7 @@ return function() it("should recreate instances when changedClassName is set, preserving children", function() local root = Instance.new("Folder") root.Name = "Initial Root Name" + root.Parent = container local child = Instance.new("Folder") child.Name = "Child" diff --git a/plugin/src/Reconciler/init.lua b/plugin/src/Reconciler/init.lua index 129457827..df7cd92f4 100644 --- a/plugin/src/Reconciler/init.lua +++ b/plugin/src/Reconciler/init.lua @@ -3,9 +3,14 @@ and mutating the Roblox DOM. ]] -local Packages = script.Parent.Parent.Packages +local Rojo = script:FindFirstAncestor("Rojo") +local Plugin = Rojo.Plugin +local Packages = Rojo.Packages + local Log = require(Packages.Log) +local Timer = require(Plugin.Timer) + local applyPatch = require(script.applyPatch) local hydrate = require(script.hydrate) local diff = require(script.diff) @@ -57,31 +62,55 @@ function Reconciler:hookPostcommit(callback: (patch: any, instanceMap: any, unap end function Reconciler:applyPatch(patch) + Timer.start("Reconciler:applyPatch") + + Timer.start("precommitCallbacks") + -- Precommit callbacks must be serial in order to obey the contract that + -- they execute before commit for _, callback in self.__precommitCallbacks do local success, err = pcall(callback, patch, self.__instanceMap) if not success then Log.warn("Precommit hook errored: {}", err) end end + Timer.stop() + Timer.start("apply") local unappliedPatch = applyPatch(self.__instanceMap, patch) + Timer.stop() + Timer.start("postcommitCallbacks") + -- Postcommit callbacks can be called with spawn since regardless of firing order, they are + -- guaranteed to be called after the commit for _, callback in self.__postcommitCallbacks do - local success, err = pcall(callback, patch, self.__instanceMap, unappliedPatch) - if not success then - Log.warn("Postcommit hook errored: {}", err) - end + task.spawn(function() + local success, err = pcall(callback, patch, self.__instanceMap, unappliedPatch) + if not success then + Log.warn("Postcommit hook errored: {}", err) + end + end) end + Timer.stop() + + Timer.stop() return unappliedPatch end function Reconciler:hydrate(virtualInstances, rootId, rootInstance) - return hydrate(self.__instanceMap, virtualInstances, rootId, rootInstance) + Timer.start("Reconciler:hydrate") + local result = hydrate(self.__instanceMap, virtualInstances, rootId, rootInstance) + Timer.stop() + + return result end function Reconciler:diff(virtualInstances, rootId) - return diff(self.__instanceMap, virtualInstances, rootId) + Timer.start("Reconciler:diff") + local success, result = diff(self.__instanceMap, virtualInstances, rootId) + Timer.stop() + + return success, result end return Reconciler diff --git a/plugin/src/ServeSession.lua b/plugin/src/ServeSession.lua index 82d8fd42f..bb844d062 100644 --- a/plugin/src/ServeSession.lua +++ b/plugin/src/ServeSession.lua @@ -13,6 +13,7 @@ local InstanceMap = require(script.Parent.InstanceMap) local PatchSet = require(script.Parent.PatchSet) local Reconciler = require(script.Parent.Reconciler) local strict = require(script.Parent.strict) +local Settings = require(script.Parent.Settings) local Status = strict("Session.Status", { NotStarted = "NotStarted", @@ -50,7 +51,6 @@ ServeSession.Status = Status local validateServeOptions = t.strictInterface({ apiContext = t.table, - openScriptsExternally = t.boolean, twoWaySync = t.boolean, }) @@ -89,7 +89,6 @@ function ServeSession.new(options) self = { __status = Status.NotStarted, __apiContext = options.apiContext, - __openScriptsExternally = options.openScriptsExternally, __twoWaySync = options.twoWaySync, __reconciler = reconciler, __instanceMap = instanceMap, @@ -170,7 +169,7 @@ function ServeSession:__applyGameAndPlaceId(serverInfo) end function ServeSession:__onActiveScriptChanged(activeScript) - if not self.__openScriptsExternally then + if not Settings:get("openScriptsExternally") then Log.trace("Not opening script {} because feature not enabled.", activeScript) return diff --git a/plugin/src/Settings.lua b/plugin/src/Settings.lua index b5be22a76..67f13ba21 100644 --- a/plugin/src/Settings.lua +++ b/plugin/src/Settings.lua @@ -20,6 +20,7 @@ local defaultSettings = { playSounds = true, typecheckingEnabled = false, logLevel = "Info", + timingLogsEnabled = false, priorEndpoints = {}, } diff --git a/plugin/src/Timer.lua b/plugin/src/Timer.lua new file mode 100644 index 000000000..9a5bbbd02 --- /dev/null +++ b/plugin/src/Timer.lua @@ -0,0 +1,57 @@ +local Settings = require(script.Parent.Settings) + +local clock = os.clock + +local Timer = { + _entries = {}, +} + +function Timer._start(label) + local start = clock() + if not label then + error("[Rojo-Timer] Timer.start: label is required", 2) + return + end + + table.insert(Timer._entries, { label, start }) +end + +function Timer._stop() + local stop = clock() + + local entry = table.remove(Timer._entries) + if not entry then + error("[Rojo-Timer] Timer.stop: no label to stop", 2) + return + end + + local label = entry[1] + if #Timer._entries > 0 then + local priorLabels = {} + for _, priorEntry in ipairs(Timer._entries) do + table.insert(priorLabels, priorEntry[1]) + end + label = table.concat(priorLabels, "/") .. "/" .. label + end + + local start = entry[2] + local duration = stop - start + print(string.format("[Rojo-Timer] %s took %.3f ms", label, duration * 1000)) +end + +-- Replace functions with no-op if not in debug mode +local function no_op() end +local function setFunctions(enabled) + if enabled then + Timer.start = Timer._start + Timer.stop = Timer._stop + else + Timer.start = no_op + Timer.stop = no_op + end +end + +Settings:onChanged("timingLogsEnabled", setFunctions) +setFunctions(Settings:get("timingLogsEnabled")) + +return Timer diff --git a/rojo-test/build-test-snapshots/end_to_end__tests__build__no_name_default_project.snap b/rojo-test/build-test-snapshots/end_to_end__tests__build__no_name_default_project.snap new file mode 100644 index 000000000..fbbd49116 --- /dev/null +++ b/rojo-test/build-test-snapshots/end_to_end__tests__build__no_name_default_project.snap @@ -0,0 +1,22 @@ +--- +source: tests/tests/build.rs +expression: contents +--- + + + + top-level + + + + second-level + + + + third-level + 1337 + + + + + diff --git a/rojo-test/build-test-snapshots/end_to_end__tests__build__no_name_project.snap b/rojo-test/build-test-snapshots/end_to_end__tests__build__no_name_project.snap new file mode 100644 index 000000000..588979334 --- /dev/null +++ b/rojo-test/build-test-snapshots/end_to_end__tests__build__no_name_project.snap @@ -0,0 +1,22 @@ +--- +source: tests/tests/build.rs +expression: contents +--- + + + + no_name_project + + + + second-level + + + + bool_value + true + + + + + diff --git a/rojo-test/build-test-snapshots/end_to_end__tests__build__no_name_top_level_project.snap b/rojo-test/build-test-snapshots/end_to_end__tests__build__no_name_top_level_project.snap new file mode 100644 index 000000000..2f2e3d6ad --- /dev/null +++ b/rojo-test/build-test-snapshots/end_to_end__tests__build__no_name_top_level_project.snap @@ -0,0 +1,13 @@ +--- +source: tests/tests/build.rs +assertion_line: 107 +expression: contents +--- + + + + no_name_top_level_project + If this isn't named `no_name_top_level_project`, something went wrong! + + + diff --git a/rojo-test/build-tests/no_name_default_project/default.project.json b/rojo-test/build-tests/no_name_default_project/default.project.json new file mode 100644 index 000000000..1c2a1400d --- /dev/null +++ b/rojo-test/build-tests/no_name_default_project/default.project.json @@ -0,0 +1,9 @@ +{ + "name": "top-level", + "tree": { + "$className": "Folder", + "second-level": { + "$path": "src" + } + } +} \ No newline at end of file diff --git a/rojo-test/build-tests/no_name_default_project/src/third-level/default.project.json b/rojo-test/build-tests/no_name_default_project/src/third-level/default.project.json new file mode 100644 index 000000000..e7b87be1c --- /dev/null +++ b/rojo-test/build-tests/no_name_default_project/src/third-level/default.project.json @@ -0,0 +1,8 @@ +{ + "tree": { + "$className": "IntValue", + "$properties": { + "Value": 1337 + } + } +} \ No newline at end of file diff --git a/rojo-test/build-tests/no_name_project/default.project.json b/rojo-test/build-tests/no_name_project/default.project.json new file mode 100644 index 000000000..93ef2e8ce --- /dev/null +++ b/rojo-test/build-tests/no_name_project/default.project.json @@ -0,0 +1,9 @@ +{ + "name": "no_name_project", + "tree": { + "$className": "Folder", + "second-level": { + "$path": "src" + } + } +} \ No newline at end of file diff --git a/rojo-test/build-tests/no_name_project/src/bool_value.project.json b/rojo-test/build-tests/no_name_project/src/bool_value.project.json new file mode 100644 index 000000000..6be58a3ce --- /dev/null +++ b/rojo-test/build-tests/no_name_project/src/bool_value.project.json @@ -0,0 +1,8 @@ +{ + "tree": { + "$className": "BoolValue", + "$properties": { + "Value": true + } + } +} \ No newline at end of file diff --git a/rojo-test/build-tests/no_name_top_level_project/default.project.json b/rojo-test/build-tests/no_name_top_level_project/default.project.json new file mode 100644 index 000000000..845ae3725 --- /dev/null +++ b/rojo-test/build-tests/no_name_top_level_project/default.project.json @@ -0,0 +1,8 @@ +{ + "tree": { + "$className": "StringValue", + "$properties": { + "Value": "If this isn't named `no_name_top_level_project`, something went wrong!" + } + } +} \ No newline at end of file diff --git a/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_default_project_all.snap b/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_default_project_all.snap new file mode 100644 index 000000000..a8179a919 --- /dev/null +++ b/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_default_project_all.snap @@ -0,0 +1,39 @@ +--- +source: tests/tests/serve.rs +expression: "read_response.intern_and_redact(&mut redactions, root_id)" +--- +instances: + id-2: + Children: + - id-3 + ClassName: Folder + Id: id-2 + Metadata: + ignoreUnknownInstances: true + Name: top-level + Parent: "00000000000000000000000000000000" + Properties: {} + id-3: + Children: + - id-4 + ClassName: Folder + Id: id-3 + Metadata: + ignoreUnknownInstances: false + Name: second-level + Parent: id-2 + Properties: {} + id-4: + Children: [] + ClassName: IntValue + Id: id-4 + Metadata: + ignoreUnknownInstances: true + Name: third-level + Parent: id-3 + Properties: + Value: + Int64: 1337 +messageCursor: 0 +sessionId: id-1 + diff --git a/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_default_project_info.snap b/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_default_project_info.snap new file mode 100644 index 000000000..954ba6229 --- /dev/null +++ b/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_default_project_info.snap @@ -0,0 +1,14 @@ +--- +source: tests/tests/serve.rs +assertion_line: 316 +expression: redactions.redacted_yaml(info) +--- +expectedPlaceIds: ~ +gameId: ~ +placeId: ~ +projectName: top-level +protocolVersion: 4 +rootInstanceId: id-2 +serverVersion: "[server-version]" +sessionId: id-1 + diff --git a/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_project_all.snap b/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_project_all.snap new file mode 100644 index 000000000..1b398a928 --- /dev/null +++ b/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_project_all.snap @@ -0,0 +1,40 @@ +--- +source: tests/tests/serve.rs +assertion_line: 338 +expression: "read_response.intern_and_redact(&mut redactions, root_id)" +--- +instances: + id-2: + Children: + - id-3 + ClassName: Folder + Id: id-2 + Metadata: + ignoreUnknownInstances: true + Name: no_name_project + Parent: "00000000000000000000000000000000" + Properties: {} + id-3: + Children: + - id-4 + ClassName: Folder + Id: id-3 + Metadata: + ignoreUnknownInstances: false + Name: second-level + Parent: id-2 + Properties: {} + id-4: + Children: [] + ClassName: BoolValue + Id: id-4 + Metadata: + ignoreUnknownInstances: true + Name: bool_value + Parent: id-3 + Properties: + Value: + Bool: true +messageCursor: 0 +sessionId: id-1 + diff --git a/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_project_info.snap b/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_project_info.snap new file mode 100644 index 000000000..d9772de1c --- /dev/null +++ b/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_project_info.snap @@ -0,0 +1,14 @@ +--- +source: tests/tests/serve.rs +assertion_line: 335 +expression: redactions.redacted_yaml(info) +--- +expectedPlaceIds: ~ +gameId: ~ +placeId: ~ +projectName: no_name_project +protocolVersion: 4 +rootInstanceId: id-2 +serverVersion: "[server-version]" +sessionId: id-1 + diff --git a/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_top_level_project_all.snap b/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_top_level_project_all.snap new file mode 100644 index 000000000..ea52fe4bf --- /dev/null +++ b/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_top_level_project_all.snap @@ -0,0 +1,20 @@ +--- +source: tests/tests/serve.rs +assertion_line: 357 +expression: "read_response.intern_and_redact(&mut redactions, root_id)" +--- +instances: + id-2: + Children: [] + ClassName: StringValue + Id: id-2 + Metadata: + ignoreUnknownInstances: true + Name: no_name_top_level_project + Parent: "00000000000000000000000000000000" + Properties: + Value: + String: "If this isn't named `no_name_top_level_project`, something went wrong!" +messageCursor: 0 +sessionId: id-1 + diff --git a/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_top_level_project_info.snap b/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_top_level_project_info.snap new file mode 100644 index 000000000..3ad79c37e --- /dev/null +++ b/rojo-test/serve-test-snapshots/end_to_end__tests__serve__no_name_top_level_project_info.snap @@ -0,0 +1,14 @@ +--- +source: tests/tests/serve.rs +assertion_line: 351 +expression: redactions.redacted_yaml(info) +--- +expectedPlaceIds: ~ +gameId: ~ +placeId: ~ +projectName: no_name_top_level_project +protocolVersion: 4 +rootInstanceId: id-2 +serverVersion: "[server-version]" +sessionId: id-1 + diff --git a/rojo-test/serve-tests/no_name_default_project/default.project.json b/rojo-test/serve-tests/no_name_default_project/default.project.json new file mode 100644 index 000000000..1c2a1400d --- /dev/null +++ b/rojo-test/serve-tests/no_name_default_project/default.project.json @@ -0,0 +1,9 @@ +{ + "name": "top-level", + "tree": { + "$className": "Folder", + "second-level": { + "$path": "src" + } + } +} \ No newline at end of file diff --git a/rojo-test/serve-tests/no_name_default_project/src/third-level/default.project.json b/rojo-test/serve-tests/no_name_default_project/src/third-level/default.project.json new file mode 100644 index 000000000..e7b87be1c --- /dev/null +++ b/rojo-test/serve-tests/no_name_default_project/src/third-level/default.project.json @@ -0,0 +1,8 @@ +{ + "tree": { + "$className": "IntValue", + "$properties": { + "Value": 1337 + } + } +} \ No newline at end of file diff --git a/rojo-test/serve-tests/no_name_project/default.project.json b/rojo-test/serve-tests/no_name_project/default.project.json new file mode 100644 index 000000000..93ef2e8ce --- /dev/null +++ b/rojo-test/serve-tests/no_name_project/default.project.json @@ -0,0 +1,9 @@ +{ + "name": "no_name_project", + "tree": { + "$className": "Folder", + "second-level": { + "$path": "src" + } + } +} \ No newline at end of file diff --git a/rojo-test/serve-tests/no_name_project/src/bool_value.project.json b/rojo-test/serve-tests/no_name_project/src/bool_value.project.json new file mode 100644 index 000000000..6be58a3ce --- /dev/null +++ b/rojo-test/serve-tests/no_name_project/src/bool_value.project.json @@ -0,0 +1,8 @@ +{ + "tree": { + "$className": "BoolValue", + "$properties": { + "Value": true + } + } +} \ No newline at end of file diff --git a/rojo-test/serve-tests/no_name_top_level_project/default.project.json b/rojo-test/serve-tests/no_name_top_level_project/default.project.json new file mode 100644 index 000000000..845ae3725 --- /dev/null +++ b/rojo-test/serve-tests/no_name_top_level_project/default.project.json @@ -0,0 +1,8 @@ +{ + "tree": { + "$className": "StringValue", + "$properties": { + "Value": "If this isn't named `no_name_top_level_project`, something went wrong!" + } + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 5bb9bc6c2..4e0fb507f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use librojo::cli::Options; fn main() { #[cfg(feature = "profile-with-tracy")] - tracy_client::Client::start(); + profiling::tracy_client::Client::start(); panic::set_hook(Box::new(|panic_info| { // PanicInfo's payload is usually a &'static str or String. diff --git a/src/project.rs b/src/project.rs index f09917025..6e503dd63 100644 --- a/src/project.rs +++ b/src/project.rs @@ -39,7 +39,7 @@ enum Error { #[serde(deny_unknown_fields, rename_all = "camelCase")] pub struct Project { /// The name of the top-level instance described by the project. - pub name: String, + pub name: Option, /// The tree of instances described by this project. Projects always /// describe at least one instance. diff --git a/src/serve_session.rs b/src/serve_session.rs index 85ae77934..dbc841d74 100644 --- a/src/serve_session.rs +++ b/src/serve_session.rs @@ -110,7 +110,7 @@ impl ServeSession { log::debug!("Loading project file from {}", project_path.display()); - let root_project = match vfs.read(&project_path).with_not_found()? { + let mut root_project = match vfs.read(&project_path).with_not_found()? { Some(contents) => Project::load_from_slice(&contents, &project_path)?, None => { return Err(ServeSessionError::NoProjectFound { @@ -118,6 +118,35 @@ impl ServeSession { }); } }; + if root_project.name.is_none() { + if let Some(file_name) = project_path.file_name().and_then(|s| s.to_str()) { + if file_name == "default.project.json" { + let folder_name = project_path + .parent() + .and_then(Path::file_name) + .and_then(|s| s.to_str()); + if let Some(folder_name) = folder_name { + root_project.name = Some(folder_name.to_string()); + } else { + return Err(ServeSessionError::FolderNameInvalid { + path: project_path.to_path_buf(), + }); + } + } else if let Some(trimmed) = file_name.strip_suffix(".project.json") { + root_project.name = Some(trimmed.to_string()); + } else { + return Err(ServeSessionError::ProjectNameInvalid { + path: project_path.to_path_buf(), + }); + } + } else { + return Err(ServeSessionError::ProjectNameInvalid { + path: project_path.to_path_buf(), + }); + } + } + // Rebind it to make it no longer mutable + let root_project = root_project; let mut tree = RojoTree::new(InstanceSnapshot::new()); @@ -190,7 +219,10 @@ impl ServeSession { } pub fn project_name(&self) -> &str { - &self.root_project.name + self.root_project + .name + .as_ref() + .expect("all top-level projects must have their name set") } pub fn project_port(&self) -> Option { @@ -231,6 +263,14 @@ pub enum ServeSessionError { )] NoProjectFound { path: PathBuf }, + #[error("The folder for the provided project cannot be used as a project name: {}\n\ + Consider setting the `name` field on this project.", .path.display())] + FolderNameInvalid { path: PathBuf }, + + #[error("The file name of the provided project cannot be used as a project name: {}.\n\ + Consider setting the `name` field on this project.", .path.display())] + ProjectNameInvalid { path: PathBuf }, + #[error(transparent)] Io { #[from] diff --git a/src/snapshot_middleware/mod.rs b/src/snapshot_middleware/mod.rs index 30ea57061..1c95154ef 100644 --- a/src/snapshot_middleware/mod.rs +++ b/src/snapshot_middleware/mod.rs @@ -66,7 +66,13 @@ pub fn snapshot_from_vfs( for rule in default_sync_rules() { if rule.matches(&init_path) { return match rule.middleware { - Middleware::Project => snapshot_project(context, vfs, &init_path), + Middleware::Project => { + let name = init_path + .parent() + .and_then(Path::file_name) + .and_then(|s| s.to_str()).expect("default.project.json should be inside a folder with a unicode name"); + snapshot_project(context, vfs, &init_path, name) + } Middleware::ModuleScript => { snapshot_lua_init(context, vfs, &init_path, ScriptType::Module) @@ -218,9 +224,7 @@ impl Middleware { Self::ServerScript => snapshot_lua(context, vfs, path, name, ScriptType::Server), Self::ClientScript => snapshot_lua(context, vfs, path, name, ScriptType::Client), Self::ModuleScript => snapshot_lua(context, vfs, path, name, ScriptType::Module), - // At the moment, snapshot_project does not use `name` so we - // don't provide it. - Self::Project => snapshot_project(context, vfs, path), + Self::Project => snapshot_project(context, vfs, path, name), Self::Rbxm => snapshot_rbxm(context, vfs, path, name), Self::Rbxmx => snapshot_rbxmx(context, vfs, path, name), Self::Toml => snapshot_toml(context, vfs, path, name), @@ -280,8 +284,7 @@ fn default_sync_rules() -> &'static [SyncRule] { sync_rule!("*.client.lua", ClientScript, ".client.lua"), sync_rule!("*.client.luau", ClientScript, ".client.luau"), sync_rule!("*.{lua,luau}", ModuleScript), - // Project middleware doesn't use the file name. - sync_rule!("*.project.json", Project), + sync_rule!("*.project.json", Project, ".project.json"), sync_rule!("*.model.json", JsonModel, ".model.json"), sync_rule!("*.json", Json, ".json", "*.meta.json"), sync_rule!("*.toml", Toml), diff --git a/src/snapshot_middleware/project.rs b/src/snapshot_middleware/project.rs index e5d279517..53e65251b 100644 --- a/src/snapshot_middleware/project.rs +++ b/src/snapshot_middleware/project.rs @@ -20,9 +20,11 @@ pub fn snapshot_project( context: &InstanceContext, vfs: &Vfs, path: &Path, + name: &str, ) -> anyhow::Result> { let project = Project::load_from_slice(&vfs.read(path)?, path) .with_context(|| format!("File was not a valid Rojo project: {}", path.display()))?; + let project_name = project.name.as_deref().unwrap_or(name); let mut context = context.clone(); context.clear_sync_rules(); @@ -46,7 +48,7 @@ pub fn snapshot_project( .unwrap(), ); - match snapshot_project_node(&context, path, &project.name, &project.tree, vfs, None)? { + match snapshot_project_node(&context, path, project_name, &project.tree, vfs, None)? { Some(found_snapshot) => { let mut snapshot = found_snapshot; // Setting the instigating source to the project file path is a little @@ -359,12 +361,16 @@ mod test { ) .unwrap(); - let mut vfs = Vfs::new(imfs); + let vfs = Vfs::new(imfs); - let instance_snapshot = - snapshot_project(&InstanceContext::default(), &mut vfs, Path::new("/foo")) - .expect("snapshot error") - .expect("snapshot returned no instances"); + let instance_snapshot = snapshot_project( + &InstanceContext::default(), + &vfs, + Path::new("/foo"), + "NOT_IN_SNAPSHOT", + ) + .expect("snapshot error") + .expect("snapshot returned no instances"); insta::assert_yaml_snapshot!(instance_snapshot); } @@ -389,12 +395,13 @@ mod test { ) .unwrap(); - let mut vfs = Vfs::new(imfs); + let vfs = Vfs::new(imfs); let instance_snapshot = snapshot_project( &InstanceContext::default(), - &mut vfs, + &vfs, Path::new("/foo/hello.project.json"), + "NOT_IN_SNAPSHOT", ) .expect("snapshot error") .expect("snapshot returned no instances"); @@ -427,12 +434,13 @@ mod test { ) .unwrap(); - let mut vfs = Vfs::new(imfs); + let vfs = Vfs::new(imfs); let instance_snapshot = snapshot_project( &InstanceContext::default(), - &mut vfs, + &vfs, Path::new("/foo.project.json"), + "NOT_IN_SNAPSHOT", ) .expect("snapshot error") .expect("snapshot returned no instances"); @@ -463,12 +471,13 @@ mod test { ) .unwrap(); - let mut vfs = Vfs::new(imfs); + let vfs = Vfs::new(imfs); let instance_snapshot = snapshot_project( &InstanceContext::default(), - &mut vfs, + &vfs, Path::new("/foo.project.json"), + "NOT_IN_SNAPSHOT", ) .expect("snapshot error") .expect("snapshot returned no instances"); @@ -500,12 +509,13 @@ mod test { ) .unwrap(); - let mut vfs = Vfs::new(imfs); + let vfs = Vfs::new(imfs); let instance_snapshot = snapshot_project( &InstanceContext::default(), - &mut vfs, + &vfs, Path::new("/foo.project.json"), + "NOT_IN_SNAPSHOT", ) .expect("snapshot error") .expect("snapshot returned no instances"); @@ -534,12 +544,13 @@ mod test { ) .unwrap(); - let mut vfs = Vfs::new(imfs); + let vfs = Vfs::new(imfs); let instance_snapshot = snapshot_project( &InstanceContext::default(), - &mut vfs, + &vfs, Path::new("/foo/default.project.json"), + "NOT_IN_SNAPSHOT", ) .expect("snapshot error") .expect("snapshot returned no instances"); @@ -575,12 +586,13 @@ mod test { ) .unwrap(); - let mut vfs = Vfs::new(imfs); + let vfs = Vfs::new(imfs); let instance_snapshot = snapshot_project( &InstanceContext::default(), - &mut vfs, + &vfs, Path::new("/foo/default.project.json"), + "NOT_IN_SNAPSHOT", ) .expect("snapshot error") .expect("snapshot returned no instances"); @@ -620,12 +632,13 @@ mod test { ) .unwrap(); - let mut vfs = Vfs::new(imfs); + let vfs = Vfs::new(imfs); let instance_snapshot = snapshot_project( &InstanceContext::default(), - &mut vfs, + &vfs, Path::new("/foo/default.project.json"), + "NOT_IN_SNAPSHOT", ) .expect("snapshot error") .expect("snapshot returned no instances"); @@ -670,12 +683,46 @@ mod test { ) .unwrap(); - let mut vfs = Vfs::new(imfs); + let vfs = Vfs::new(imfs); + + let instance_snapshot = snapshot_project( + &InstanceContext::default(), + &vfs, + Path::new("/foo/default.project.json"), + "NOT_IN_SNAPSHOT", + ) + .expect("snapshot error") + .expect("snapshot returned no instances"); + + insta::assert_yaml_snapshot!(instance_snapshot); + } + + #[test] + fn no_name_project() { + let _ = env_logger::try_init(); + + let mut imfs = InMemoryFs::new(); + imfs.load_snapshot( + "/foo", + VfsSnapshot::dir(hashmap! { + "default.project.json" => VfsSnapshot::file(r#" + { + "tree": { + "$className": "Model" + } + } + "#), + }), + ) + .unwrap(); + + let vfs = Vfs::new(imfs); let instance_snapshot = snapshot_project( &InstanceContext::default(), - &mut vfs, + &vfs, Path::new("/foo/default.project.json"), + "no_name_project", ) .expect("snapshot error") .expect("snapshot returned no instances"); diff --git a/src/snapshot_middleware/snapshots/librojo__snapshot_middleware__project__test__no_name_project.snap b/src/snapshot_middleware/snapshots/librojo__snapshot_middleware__project__test__no_name_project.snap new file mode 100644 index 000000000..289c292cb --- /dev/null +++ b/src/snapshot_middleware/snapshots/librojo__snapshot_middleware__project__test__no_name_project.snap @@ -0,0 +1,19 @@ +--- +source: src/snapshot_middleware/project.rs +assertion_line: 725 +expression: instance_snapshot +--- +snapshot_id: "00000000000000000000000000000000" +metadata: + ignore_unknown_instances: true + instigating_source: + Path: /foo/default.project.json + relevant_paths: + - /foo/default.project.json + context: + emit_legacy_scripts: true +name: no_name_project +class_name: Model +properties: {} +children: [] + diff --git a/src/web/assets.rs b/src/web/assets.rs index 37adbe137..39f0958b0 100644 --- a/src/web/assets.rs +++ b/src/web/assets.rs @@ -29,13 +29,13 @@ macro_rules! declare_asset { declare_asset!(css, "../../assets/index.css"); pub fn logo() -> &'static [u8] { - static LOGO: &[u8] = include_bytes!("../../assets/logo-512.png"); + static LOGO: &[u8] = include_bytes!("../../assets/brand_images/logo-512.png"); LOGO } pub fn icon() -> &'static [u8] { - static ICON: &[u8] = include_bytes!("../../assets/icon-32.png"); + static ICON: &[u8] = include_bytes!("../../assets/brand_images/icon-32.png"); ICON } diff --git a/tests/tests/build.rs b/tests/tests/build.rs index f23d4a4e4..8c533115d 100644 --- a/tests/tests/build.rs +++ b/tests/tests/build.rs @@ -62,6 +62,9 @@ gen_build_tests! { sync_rule_alone, sync_rule_complex, sync_rule_nested_projects, + no_name_default_project, + no_name_project, + no_name_top_level_project, } fn run_build_test(test_name: &str) { @@ -73,7 +76,7 @@ fn run_build_test(test_name: &str) { let output_path = output_dir.path().join(format!("{}.rbxmx", test_name)); let output = Command::new(ROJO_PATH) - .args(&[ + .args([ "build", input_path.to_str().unwrap(), "-o", diff --git a/tests/tests/serve.rs b/tests/tests/serve.rs index 80b0897cf..2e8d61b8e 100644 --- a/tests/tests/serve.rs +++ b/tests/tests/serve.rs @@ -307,6 +307,60 @@ fn sync_rule_no_extension() { }); } +#[test] +fn no_name_default_project() { + run_serve_test("no_name_default_project", |session, mut redactions| { + let info = session.get_api_rojo().unwrap(); + let root_id = info.root_instance_id; + + assert_yaml_snapshot!( + "no_name_default_project_info", + redactions.redacted_yaml(info) + ); + + let read_response = session.get_api_read(root_id).unwrap(); + assert_yaml_snapshot!( + "no_name_default_project_all", + read_response.intern_and_redact(&mut redactions, root_id) + ); + }); +} + +#[test] +fn no_name_project() { + run_serve_test("no_name_project", |session, mut redactions| { + let info = session.get_api_rojo().unwrap(); + let root_id = info.root_instance_id; + + assert_yaml_snapshot!("no_name_project_info", redactions.redacted_yaml(info)); + + let read_response = session.get_api_read(root_id).unwrap(); + assert_yaml_snapshot!( + "no_name_project_all", + read_response.intern_and_redact(&mut redactions, root_id) + ); + }); +} + +#[test] +fn no_name_top_level_project() { + run_serve_test("no_name_top_level_project", |session, mut redactions| { + let info = session.get_api_rojo().unwrap(); + let root_id = info.root_instance_id; + + assert_yaml_snapshot!( + "no_name_top_level_project_info", + redactions.redacted_yaml(info) + ); + + let read_response = session.get_api_read(root_id).unwrap(); + assert_yaml_snapshot!( + "no_name_top_level_project_all", + read_response.intern_and_redact(&mut redactions, root_id) + ); + }); +} + #[test] fn ref_properties() { run_serve_test("ref_properties", |session, mut redactions| {