Compare commits

..

1 Commits

Author SHA1 Message Date
Micah
6688bcb488 Build aarch64 windows and linux builds for releases 2024-08-28 16:36:29 -07:00
130 changed files with 3232 additions and 11059 deletions

View File

@@ -1,2 +0,0 @@
((nil . ((eglot-luau-rojo-project-path . "plugin.project.json")
(eglot-luau-rojo-sourcemap-enabled . 't))))

View File

@@ -11,12 +11,12 @@ jobs:
name: Check Actions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Changelog check
uses: Zomzog/changelog-checker@v1.3.0
with:
fileName: CHANGELOG.md
fileName: CHANGELOG.md
noChangelogLabel: skip changelog
checkNotification: Simple
env:

View File

@@ -30,9 +30,9 @@ jobs:
uses: Swatinem/rust-cache@v2
- name: Setup Aftman
uses: ok-nick/setup-aftman@v0.4.2
uses: ok-nick/setup-aftman@v0.3.0
with:
version: 'v0.3.0'
version: 'v0.2.7'
- name: Build
run: cargo build --locked --verbose
@@ -56,9 +56,9 @@ jobs:
uses: Swatinem/rust-cache@v2
- name: Setup Aftman
uses: ok-nick/setup-aftman@v0.4.2
uses: ok-nick/setup-aftman@v0.3.0
with:
version: 'v0.3.0'
version: 'v0.2.7'
- name: Build
run: cargo build --locked --verbose
@@ -81,9 +81,9 @@ jobs:
uses: Swatinem/rust-cache@v2
- name: Setup Aftman
uses: ok-nick/setup-aftman@v0.4.2
uses: ok-nick/setup-aftman@v0.3.0
with:
version: 'v0.3.0'
version: 'v0.2.7'
- name: Stylua
run: stylua --check plugin/src

View File

@@ -26,12 +26,14 @@ jobs:
submodules: true
- name: Setup Aftman
uses: ok-nick/setup-aftman@v0.4.2
uses: ok-nick/setup-aftman@v0.1.0
with:
version: 'v0.3.0'
token: ${{ secrets.GITHUB_TOKEN }}
trust-check: false
version: 'v0.2.6'
- name: Build Plugin
run: rojo build plugin.project.json --output Rojo.rbxm
run: rojo build plugin --output Rojo.rbxm
- name: Upload Plugin to Release
env:
@@ -53,15 +55,25 @@ jobs:
# https://doc.rust-lang.org/rustc/platform-support.html
include:
- host: linux
os: ubuntu-latest
os: ubuntu-20.04
target: x86_64-unknown-linux-gnu
label: linux-x86_64
- host: linux
os: ubuntu-20.04
target: aarch64-unknown-linux-gnu
label: linux-aarch64
- host: windows
os: windows-latest
target: x86_64-pc-windows-msvc
label: windows-x86_64
- host: windows
os: windows-latest
target: aarch64-pc-windows-msvc
label: windows-aarch64
- host: macos
os: macos-latest
target: x86_64-apple-darwin
@@ -87,9 +99,11 @@ jobs:
targets: ${{ matrix.target }}
- name: Setup Aftman
uses: ok-nick/setup-aftman@v0.4.2
uses: ok-nick/setup-aftman@v0.1.0
with:
version: 'v0.3.0'
token: ${{ secrets.GITHUB_TOKEN }}
trust-check: false
version: 'v0.2.6'
- name: Build Release
run: cargo build --release --locked --verbose --target ${{ matrix.target }}

8
.gitignore vendored
View File

@@ -10,8 +10,8 @@
/*.rbxl
/*.rbxlx
# Sourcemap for the Rojo plugin (for better intellisense)
/sourcemap.json
# Test places for the Roblox Studio Plugin
/plugin/*.rbxlx
# Roblox Studio holds 'lock' files on places
*.rbxl.lock
@@ -19,7 +19,3 @@
# Snapshot files from the 'insta' Rust crate
**/*.snap.new
# Macos file system junk
._*
.DS_STORE

View File

@@ -1,8 +0,0 @@
{
"recommendations": [
"JohnnyMorganz.luau-lsp",
"JohnnyMorganz.stylua",
"Kampfkarren.selene-vscode",
"rust-lang.rust-analyzer"
]
}

View File

@@ -1,4 +0,0 @@
{
"luau-lsp.sourcemap.rojoProjectFile": "plugin.project.json",
"luau-lsp.sourcemap.autogenerate": true
}

View File

@@ -1,17 +1,6 @@
# Rojo Changelog
## 7.5.1 - April 25th, 2025
* Fixed output spam related to `Instance.Capabilities` in the plugin
## 7.5.0 - April 25th, 2025
* Fixed an edge case that caused model pivots to not be built correctly in some cases ([#1027])
* Add `blockedPlaceIds` project config field to allow blocking place ids from being live synced ([#1021])
* Adds support for `.plugin.lua(u)` files - this applies the `Plugin` RunContext. ([#1008])
* Added support for Roblox's `Content` type. This replaces the old `Content` type with `ContentId` to reflect Roblox's change.
If you were previously using the fully-qualified syntax for `Content` you will need to switch it to `ContentId`.
* Added support for `Enum` attributes
* Significantly improved performance of `.rbxm` parsing
* Support for a `$schema` field in all special JSON files (`.project.json`, `.model.json`, and `.meta.json`) ([#974])
## Unreleased Changes
* Projects may now manually link `Ref` properties together using `Attributes`. ([#843])
This has two parts: using `id` or `$id` in JSON files or a `Rojo_Target` attribute, an Instance
is given an ID. Then, that ID may be used elsewhere in the project to point to an Instance
@@ -39,8 +28,6 @@
* Added experimental setting for Auto Connect in playtests ([#840])
* Improved settings UI ([#886])
* `Open Scripts Externally` option can now be changed while syncing ([#911])
* The sync reminder notification will now tell you what was last synced and when ([#987])
* Fixed notification and tooltip text sometimes getting cut off ([#988])
* 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`:
@@ -69,7 +56,7 @@
Additionally, the `exclude` field allows files to be excluded from the sync rule if they match a pattern specified by it. If it's not present, all files that match `pattern` will be modified using the sync rule.
The `use` field corresponds to one of the potential file type that Rojo will currently include in a project. Files that match the provided pattern will be treated as if they had the file extension for that file type.
The `use` field corresponds to one of the potential file type that Rojo will currently include in a project. Files that match the provided pattern will be treated as if they had the file extension for that file type. A full list is below:
| `use` value | file extension |
|:---------------|:----------------|
@@ -86,16 +73,6 @@
| `project` | `.project.json` |
| `ignore` | None! |
Additionally, there are `use` values for specific script types ([#909]):
| `use` value | script type |
|:-------------------------|:---------------------------------------|
| `legacyServerScript` | `Script` with `Enum.RunContext.Legacy` |
| `legacyClientScript` | `LocalScript` |
| `runContextServerScript` | `Script` with `Enum.RunContext.Server` |
| `runContextClientScript` | `Script` with `Enum.RunContext.Client` |
| `pluginScript` | `Script` with `Enum.RunContext.Plugin` |
**All** sync rules are reset between project files, so they must be specified in each one when nesting them. This is to ensure that nothing can break other projects by changing how files are synced!
[#813]: https://github.com/rojo-rbx/rojo/pull/813
@@ -106,19 +83,8 @@
[#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
[#909]: https://github.com/rojo-rbx/rojo/pull/909
[#911]: https://github.com/rojo-rbx/rojo/pull/911
[#915]: https://github.com/rojo-rbx/rojo/pull/915
[#974]: https://github.com/rojo-rbx/rojo/pull/974
[#987]: https://github.com/rojo-rbx/rojo/pull/987
[#988]: https://github.com/rojo-rbx/rojo/pull/988
[#1008]: https://github.com/rojo-rbx/rojo/pull/1008
[#1021]: https://github.com/rojo-rbx/rojo/pull/1021
[#1027]: https://github.com/rojo-rbx/rojo/pull/1027
## [7.4.4] - August 22nd, 2024
* Fixed issue with reading attributes from `Lighting` in new place files
* `Instance.Archivable` will now default to `true` when building a project into a binary (`rbxm`/`rbxl`) file rather than `false`.
## [7.4.3] - August 6th, 2024
* Fixed issue with building binary files introduced in 7.4.2

View File

@@ -16,23 +16,6 @@ You'll want these tools to work on Rojo:
* Latest stable Rust compiler
* Latest stable [Rojo](https://github.com/rojo-rbx/rojo)
* [Foreman](https://github.com/Roblox/foreman)
* [Luau Language Server](https://github.com/JohnnyMorganz/luau-lsp) (Only needed if working on the Studio plugin.)
When working on the Studio plugin, we recommend using this command to automatically rebuild the plugin when you save a change:
*(Make sure you've enabled the Studio setting to reload plugins on file change!)*
```bash
bash scripts/watch-build-plugin.sh
```
You can also run the plugin's unit tests with the following:
*(Make sure you have `run-in-roblox` installed first!)*
```bash
bash scripts/unit-test-plugin.sh
```
## Documentation
Documentation impacts way more people than the individual lines of code we write.

180
Cargo.lock generated
View File

@@ -17,19 +17,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if 1.0.0",
"getrandom",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.2"
@@ -184,10 +171,6 @@ name = "cc"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723"
dependencies = [
"jobserver",
"libc",
]
[[package]]
name = "cfg-if"
@@ -509,7 +492,7 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall 0.4.1",
"redox_syscall",
"windows-sys 0.52.0",
]
@@ -952,15 +935,6 @@ version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "jobserver"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
dependencies = [
"libc",
]
[[package]]
name = "jod-thread"
version = "0.1.2"
@@ -988,9 +962,9 @@ dependencies = [
[[package]]
name = "lazy_static"
version = "1.5.0"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
@@ -1012,7 +986,7 @@ checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
dependencies = [
"bitflags 2.4.2",
"libc",
"redox_syscall 0.4.1",
"redox_syscall",
]
[[package]]
@@ -1027,16 +1001,6 @@ version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.21"
@@ -1277,29 +1241,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "parking_lot"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall 0.5.10",
"smallvec",
"windows-targets 0.52.4",
]
[[package]]
name = "paste"
version = "1.0.14"
@@ -1369,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.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "plotters"
version = "0.3.5"
@@ -1563,11 +1498,10 @@ dependencies = [
[[package]]
name = "rbx_binary"
version = "1.0.0"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9573fee5e073d7b303f475c285197fdc8179468de66ca60ee115a58fbac99296"
checksum = "7b85057e8ff75a1ce99248200c4b3c7b481a3d52f921f1053ecd67921dcc7930"
dependencies = [
"ahash",
"log",
"lz4",
"profiling",
@@ -1575,26 +1509,23 @@ dependencies = [
"rbx_reflection",
"rbx_reflection_database",
"thiserror",
"zstd",
]
[[package]]
name = "rbx_dom_weak"
version = "3.0.0"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04425cf6e9376e5486f4fb35906c120d1b1b45618a490318cf563fab1fa230a9"
checksum = "fcd2a17d09e46af0805f8b311a926402172b97e8d9388745c9adf8f448901841"
dependencies = [
"ahash",
"rbx_types",
"serde",
"ustr",
]
[[package]]
name = "rbx_reflection"
version = "5.0.0"
version = "4.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b6d0d62baa613556b058a5f94a53b01cf0ccde0ea327ce03056e335b982e77e"
checksum = "8118ac6021d700e8debe324af6b40ecfd2cef270a00247849dbdfeebb0802677"
dependencies = [
"rbx_types",
"serde",
@@ -1603,9 +1534,9 @@ dependencies = [
[[package]]
name = "rbx_reflection_database"
version = "1.0.3+roblox-670"
version = "0.2.12+roblox-638"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e22c05ef92528c0fb0cc580592a65ca178d3ea9beb07a1d9ca0a2503c4f3721c"
checksum = "0e29381d675420e841f8c02db5755cbb2545ed3e13f56c539546dc58702b512a"
dependencies = [
"lazy_static",
"rbx_reflection",
@@ -1615,9 +1546,9 @@ dependencies = [
[[package]]
name = "rbx_types"
version = "2.0.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78e4fdde46493def107e5f923d82e813dec9b3eef52c2f75fbad3a716023eda2"
checksum = "e30f49b2a3bb667e4074ba73c2dfb8ca0873f610b448ccf318a240acfdec6c73"
dependencies = [
"base64 0.13.1",
"bitflags 1.3.2",
@@ -1630,11 +1561,10 @@ dependencies = [
[[package]]
name = "rbx_xml"
version = "1.0.0"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb623833c31cc43bbdaeb32f5e91db8ecd63fc46e438d0d268baf9e61539cf1c"
checksum = "2b14b3027bc9ccd82e2fc854c8bcd25ed58318e570c355bf2cf63df9cdbd5ba8"
dependencies = [
"ahash",
"base64 0.13.1",
"log",
"rbx_dom_weak",
@@ -1652,15 +1582,6 @@ dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "redox_syscall"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
dependencies = [
"bitflags 2.4.2",
]
[[package]]
name = "redox_users"
version = "0.4.4"
@@ -1831,7 +1752,7 @@ dependencies = [
[[package]]
name = "rojo"
version = "7.5.1"
version = "7.4.0"
dependencies = [
"anyhow",
"backtrace",
@@ -1975,12 +1896,6 @@ version = "1.0.1"
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 = "sct"
version = "0.7.1"
@@ -2478,19 +2393,6 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "ustr"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18b19e258aa08450f93369cf56dd78063586adf19e92a75b338a800f799a0208"
dependencies = [
"ahash",
"byteorder",
"lazy_static",
"parking_lot",
"serde",
]
[[package]]
name = "uuid"
version = "1.7.0"
@@ -2882,51 +2784,3 @@ name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2 1.0.78",
"quote 1.0.35",
"syn 2.0.52",
]
[[package]]
name = "zstd"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "7.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.15+zstd.1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
dependencies = [
"cc",
"pkg-config",
]

View File

@@ -1,6 +1,6 @@
[package]
name = "rojo"
version = "7.5.1"
version = "7.4.0"
rust-version = "1.70.0"
authors = ["Lucien Greathouse <me@lpghatguy.com>"]
description = "Enables professional-grade development tools for Roblox developers"
@@ -51,11 +51,11 @@ memofs = { version = "0.3.0", path = "crates/memofs" }
# rbx_reflection_database = { path = "../rbx-dom/rbx_reflection_database" }
# rbx_xml = { path = "../rbx-dom/rbx_xml" }
rbx_binary = "1.0.0"
rbx_dom_weak = "3.0.0"
rbx_reflection = "5.0.0"
rbx_reflection_database = "1.0.3"
rbx_xml = "1.0.0"
rbx_binary = "0.7.7"
rbx_dom_weak = "2.9.0"
rbx_reflection = "4.7.0"
rbx_reflection_database = "0.2.12"
rbx_xml = "0.13.5"
anyhow = "1.0.80"
backtrace = "0.3.69"
@@ -70,6 +70,7 @@ humantime = "2.1.0"
hyper = { version = "0.14.28", features = ["server", "tcp", "http1"] }
jod-thread = "0.1.2"
log = "0.4.21"
maplit = "1.0.2"
num_cpus = "1.16.0"
opener = "0.5.2"
rayon = "1.9.0"

View File

@@ -1,5 +1,5 @@
[tools]
rojo = "rojo-rbx/rojo@7.4.1"
selene = "Kampfkarren/selene@0.27.1"
stylua = "JohnnyMorganz/stylua@0.20.0"
rojo = "rojo-rbx/rojo@7.3.0"
selene = "Kampfkarren/selene@0.26.1"
stylua = "JohnnyMorganz/stylua@0.18.2"
run-in-roblox = "rojo-rbx/run-in-roblox@0.3.0"

View File

@@ -20,10 +20,6 @@ fn snapshot_from_fs_path(path: &Path) -> io::Result<VfsSnapshot> {
let file_name = entry.file_name().to_str().unwrap().to_owned();
if file_name.starts_with(".git") {
continue;
}
// We can skip any TestEZ test files since they aren't necessary for
// the plugin to run.
if file_name.ends_with(".spec.lua") || file_name.ends_with(".spec.luau") {
@@ -45,12 +41,12 @@ fn snapshot_from_fs_path(path: &Path) -> io::Result<VfsSnapshot> {
fn main() -> Result<(), anyhow::Error> {
let out_dir = env::var_os("OUT_DIR").unwrap();
let root_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let plugin_dir = root_dir.join("plugin");
let root_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap();
let plugin_root = PathBuf::from(root_dir).join("plugin");
let our_version = Version::parse(env::var_os("CARGO_PKG_VERSION").unwrap().to_str().unwrap())?;
let plugin_version =
Version::parse(fs::read_to_string(plugin_dir.join("Version.txt"))?.trim())?;
Version::parse(fs::read_to_string(plugin_root.join("Version.txt"))?.trim())?;
assert_eq!(
our_version, plugin_version,
@@ -58,16 +54,14 @@ fn main() -> Result<(), anyhow::Error> {
);
let snapshot = VfsSnapshot::dir(hashmap! {
"default.project.json" => snapshot_from_fs_path(&root_dir.join("plugin.project.json"))?,
"plugin" => VfsSnapshot::dir(hashmap! {
"fmt" => snapshot_from_fs_path(&plugin_dir.join("fmt"))?,
"http" => snapshot_from_fs_path(&plugin_dir.join("http"))?,
"log" => snapshot_from_fs_path(&plugin_dir.join("log"))?,
"rbx_dom_lua" => snapshot_from_fs_path(&plugin_dir.join("rbx_dom_lua"))?,
"src" => snapshot_from_fs_path(&plugin_dir.join("src"))?,
"Packages" => snapshot_from_fs_path(&plugin_dir.join("Packages"))?,
"Version.txt" => snapshot_from_fs_path(&plugin_dir.join("Version.txt"))?,
}),
"default.project.json" => snapshot_from_fs_path(&plugin_root.join("default.project.json"))?,
"fmt" => snapshot_from_fs_path(&plugin_root.join("fmt"))?,
"http" => snapshot_from_fs_path(&plugin_root.join("http"))?,
"log" => snapshot_from_fs_path(&plugin_root.join("log"))?,
"rbx_dom_lua" => snapshot_from_fs_path(&plugin_root.join("rbx_dom_lua"))?,
"src" => snapshot_from_fs_path(&plugin_root.join("src"))?,
"Packages" => snapshot_from_fs_path(&plugin_root.join("Packages"))?,
"Version.txt" => snapshot_from_fs_path(&plugin_root.join("Version.txt"))?,
});
let out_path = Path::new(&out_dir).join("plugin.bincode");

View File

@@ -5,13 +5,19 @@ use serde::Serialize;
/// Enables redacting any value that serializes as a string.
///
/// Used for transforming Rojo instance IDs into something deterministic.
#[derive(Default)]
pub struct RedactionMap {
ids: HashMap<String, usize>,
last_id: usize,
}
impl RedactionMap {
pub fn new() -> Self {
Self {
ids: HashMap::new(),
last_id: 0,
}
}
pub fn get_redacted_value(&self, id: impl ToString) -> Option<String> {
let id = id.to_string();

View File

@@ -1 +1 @@
7.5.1
7.4.0

View File

@@ -3,25 +3,25 @@
"tree": {
"$className": "Folder",
"Plugin": {
"$path": "plugin/src"
"$path": "src"
},
"Packages": {
"$path": "plugin/Packages",
"$path": "Packages",
"Log": {
"$path": "plugin/log"
"$path": "log"
},
"Http": {
"$path": "plugin/http"
"$path": "http"
},
"Fmt": {
"$path": "plugin/fmt"
"$path": "fmt"
},
"RbxDom": {
"$path": "plugin/rbx_dom_lua"
"$path": "rbx_dom_lua"
}
},
"Version": {
"$path": "plugin/Version.txt"
"$path": "Version.txt"
}
}
}
}

View File

@@ -70,7 +70,7 @@ local function debugImpl(buffer, value, extendedForm)
elseif valueType == "table" then
local valueMeta = getmetatable(value)
if valueMeta ~= nil and valueMeta.__fmtDebug ~= nil then
if valueMeta ~= nil and valueMeta.__fmtDebug ~= nil then
-- This type implement's the metamethod we made up to line up with
-- Rust's 'Debug' trait.
@@ -242,4 +242,4 @@ return {
debugOutputBuffer = debugOutputBuffer,
fmt = fmt,
debugify = debugify,
}
}

View File

@@ -31,4 +31,4 @@ function Response:json()
return HttpService:JSONDecode(self.body)
end
return Response
return Response

View File

@@ -2,4 +2,4 @@ return function()
it("should load", function()
require(script.Parent)
end)
end
end

View File

@@ -57,4 +57,4 @@ function Log.error(template, ...)
error(Fmt.fmt(template, ...))
end
return Log
return Log

View File

@@ -2,4 +2,4 @@ return function()
it("should load", function()
require(script.Parent)
end)
end
end

View File

@@ -188,38 +188,6 @@ types = {
},
Content = {
fromPod = function(pod): Content
if type(pod) == "string" then
if pod == "None" then
return Content.none
else
error(`unexpected Content value '{pod}'`)
end
else
local ty, value = next(pod)
if ty == "Uri" then
return Content.fromUri(value)
elseif ty == "Object" then
error("Object deserializing is not currently implemented")
else
error(`Unknown Content type '{ty}' (could not deserialize)`)
end
end
end,
toPod = function(roblox: Content)
if roblox.SourceType == Enum.ContentSourceType.None then
return "None"
elseif roblox.SourceType == Enum.ContentSourceType.Uri then
return { Uri = roblox.Uri }
elseif roblox.SourceType == Enum.ContentSourceType.Object then
error("Object serializing is not currently implemented")
else
error(`Unknown Content type '{roblox.SourceType} (could not serialize)`)
end
end,
},
ContentId = {
fromPod = identity,
toPod = identity,
},
@@ -237,19 +205,6 @@ types = {
end,
},
EnumItem = {
fromPod = function(pod)
return Enum[pod.type]:FromValue(pod.value)
end,
toPod = function(roblox)
return {
type = tostring(roblox.EnumType),
value = roblox.Value,
}
end,
},
Faces = {
fromPod = function(pod)
local faces = {}
@@ -345,12 +300,7 @@ types = {
local keypoints = {}
for index, keypoint in ipairs(pod.keypoints) do
-- TODO: Add a test for NaN or Infinity values and envelopes
-- Right now it isn't possible because it'd fail the roundtrip.
-- It's more important that it works right now, though.
local value = keypoint.value or 0
local envelope = keypoint.envelope or 0
keypoints[index] = NumberSequenceKeypoint.new(keypoint.time, value, envelope)
keypoints[index] = NumberSequenceKeypoint.new(keypoint.time, keypoint.value, keypoint.envelope)
end
return NumberSequence.new(keypoints)

View File

@@ -5,7 +5,6 @@ Error.Kind = {
UnknownProperty = "UnknownProperty",
PropertyNotReadable = "PropertyNotReadable",
PropertyNotWritable = "PropertyNotWritable",
CannotParseBinaryString = "CannotParseBinaryString",
Roblox = "Roblox",
}

View File

@@ -15,12 +15,6 @@
0.0
]
},
"TestEnumItem": {
"EnumItem": {
"type": "Material",
"value": 256
}
},
"TestNumber": {
"Float64": 1337.0
},
@@ -176,23 +170,9 @@
},
"ty": "ColorSequence"
},
"ContentId": {
"Content": {
"value": {
"ContentId": "rbxassetid://12345"
},
"ty": "ContentId"
},
"Content_None": {
"value": {
"Content": "None"
},
"ty": "Content"
},
"Content_Uri": {
"value": {
"Content": {
"Uri": "rbxasset://abc/123.rojo"
}
"Content": "rbxassetid://12345"
},
"ty": "Content"
},
@@ -202,15 +182,6 @@
},
"ty": "Enum"
},
"EnumItem": {
"value": {
"EnumItem": {
"type": "Material",
"value": 256
}
},
"ty": "EnumItem"
},
"Faces": {
"value": {
"Faces": [

View File

@@ -1,8 +1,6 @@
local CollectionService = game:GetService("CollectionService")
local ScriptEditorService = game:GetService("ScriptEditorService")
local Error = require(script.Parent.Error)
--- A list of `Enum.Material` values that are used for Terrain.MaterialColors
local TERRAIN_MATERIAL_COLORS = {
Enum.Material.Grass,
@@ -53,10 +51,6 @@ return {
return true, instance:GetAttributes()
end,
write = function(instance, _, value)
if typeof(value) ~= "table" then
return false, Error.new(Error.Kind.CannotParseBinaryString)
end
local existing = instance:GetAttributes()
local didAllWritesSucceed = true
@@ -166,14 +160,9 @@ return {
return true, colors
end,
write = function(instance: Terrain, _, value: { [Enum.Material]: Color3 })
if typeof(value) ~= "table" then
return false, Error.new(Error.Kind.CannotParseBinaryString)
end
for material, color in value do
instance:SetMaterialColor(material, color)
end
return true
end,
},

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TestEZ = require(ReplicatedStorage.Packages:WaitForChild("TestEZ", 10))
local TestEZ = require(ReplicatedStorage.Packages.TestEZ)
local Rojo = ReplicatedStorage.Rojo

View File

@@ -45,7 +45,14 @@ end
local function rejectWrongPlaceId(infoResponseBody)
if infoResponseBody.expectedPlaceIds ~= nil then
local foundId = table.find(infoResponseBody.expectedPlaceIds, game.PlaceId)
local foundId = false
for _, id in ipairs(infoResponseBody.expectedPlaceIds) do
if id == game.PlaceId then
foundId = true
break
end
end
if not foundId then
local idList = {}
@@ -55,30 +62,10 @@ local function rejectWrongPlaceId(infoResponseBody)
local message = (
"Found a Rojo server, but its project is set to only be used with a specific list of places."
.. "\nYour place ID is %u, but needs to be one of these:"
.. "\nYour place ID is %s, but needs to be one of these:"
.. "\n%s"
.. "\n\nTo change this list, edit 'servePlaceIds' in your .project.json file."
):format(game.PlaceId, table.concat(idList, "\n"))
return Promise.reject(message)
end
end
if infoResponseBody.unexpectedPlaceIds ~= nil then
local foundId = table.find(infoResponseBody.unexpectedPlaceIds, game.PlaceId)
if foundId then
local idList = {}
for _, id in ipairs(infoResponseBody.unexpectedPlaceIds) do
table.insert(idList, "- " .. tostring(id))
end
local message = (
"Found a Rojo server, but its project is set to not be used with a specific list of places."
.. "\nYour place ID is %u, but needs to not be one of these:"
.. "\n%s"
.. "\n\nTo change this list, edit 'blockedPlaceIds' in your .project.json file."
):format(game.PlaceId, table.concat(idList, "\n"))
):format(tostring(game.PlaceId), table.concat(idList, "\n"))
return Promise.reject(message)
end

View File

@@ -32,7 +32,7 @@ end
function Checkbox:render()
return Theme.with(function(theme)
local checkboxTheme = theme.Checkbox
theme = theme.Checkbox
local activeTransparency = Roact.joinBindings({
self.binding:map(function(value)
@@ -57,21 +57,20 @@ function Checkbox:render()
end,
}, {
StateTip = e(Tooltip.Trigger, {
text = (if self.props.locked
then (self.props.lockedTooltip or "(Cannot be changed right now)") .. "\n"
else "") .. (if self.props.active then "Enabled" else "Disabled"),
text = (if self.props.locked then "[LOCKED] " else "")
.. (if self.props.active then "Enabled" else "Disabled"),
}),
Active = e(SlicedImage, {
slice = Assets.Slices.RoundedBackground,
color = checkboxTheme.Active.BackgroundColor,
color = theme.Active.BackgroundColor,
transparency = activeTransparency,
size = UDim2.new(1, 0, 1, 0),
zIndex = 2,
}, {
Icon = e("ImageLabel", {
Image = if self.props.locked then Assets.Images.Checkbox.Locked else Assets.Images.Checkbox.Active,
ImageColor3 = checkboxTheme.Active.IconColor,
ImageColor3 = theme.Active.IconColor,
ImageTransparency = activeTransparency,
Size = UDim2.new(0, 16, 0, 16),
@@ -84,7 +83,7 @@ function Checkbox:render()
Inactive = e(SlicedImage, {
slice = Assets.Slices.RoundedBorder,
color = checkboxTheme.Inactive.BorderColor,
color = theme.Inactive.BorderColor,
transparency = self.props.transparency,
size = UDim2.new(1, 0, 1, 0),
}, {
@@ -92,7 +91,7 @@ function Checkbox:render()
Image = if self.props.locked
then Assets.Images.Checkbox.Locked
else Assets.Images.Checkbox.Inactive,
ImageColor3 = checkboxTheme.Inactive.IconColor,
ImageColor3 = theme.Inactive.IconColor,
ImageTransparency = self.props.transparency,
Size = UDim2.new(0, 16, 0, 16),

View File

@@ -1,5 +1,4 @@
local Rojo = script:FindFirstAncestor("Rojo")
local Plugin = Rojo.Plugin
local Packages = Rojo.Packages
local Roact = require(Packages.Roact)
@@ -8,8 +7,6 @@ Highlighter.matchStudioSettings()
local e = Roact.createElement
local Theme = require(Plugin.App.Theme)
local CodeLabel = Roact.PureComponent:extend("CodeLabel")
function CodeLabel:init()
@@ -43,24 +40,22 @@ function CodeLabel:updateHighlights()
end
function CodeLabel:render()
return Theme.with(function(theme)
return e("TextLabel", {
Size = self.props.size,
Position = self.props.position,
Text = self.props.text,
BackgroundTransparency = 1,
FontFace = theme.Font.Code,
TextSize = theme.TextSize.Code,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
TextColor3 = Color3.fromRGB(255, 255, 255),
[Roact.Ref] = self.labelRef,
}, {
SyntaxHighlights = e("Folder", {
[Roact.Ref] = self.highlightsRef,
}),
})
end)
return e("TextLabel", {
Size = self.props.size,
Position = self.props.position,
Text = self.props.text,
BackgroundTransparency = 1,
Font = Enum.Font.RobotoMono,
TextSize = 16,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
TextColor3 = Color3.fromRGB(255, 255, 255),
[Roact.Ref] = self.labelRef,
}, {
SyntaxHighlights = e("Folder", {
[Roact.Ref] = self.highlightsRef,
}),
})
end
return CodeLabel

View File

@@ -1,3 +1,5 @@
local TextService = game:GetService("TextService")
local Rojo = script:FindFirstAncestor("Rojo")
local Plugin = Rojo.Plugin
local Packages = Rojo.Packages
@@ -8,11 +10,9 @@ local Flipper = require(Packages.Flipper)
local Assets = require(Plugin.Assets)
local Theme = require(Plugin.App.Theme)
local bindingUtil = require(Plugin.App.bindingUtil)
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)
local SlicedImage = require(script.Parent.SlicedImage)
local ScrollingFrame = require(script.Parent.ScrollingFrame)
local Tooltip = require(script.Parent.Tooltip)
local e = Roact.createElement
@@ -44,29 +44,29 @@ end
function Dropdown:render()
return Theme.with(function(theme)
local dropdownTheme = theme.Dropdown
theme = theme.Dropdown
local optionButtons = {}
local width = -1
for i, option in self.props.options do
local text = tostring(option or "")
local textBounds = getTextBoundsAsync(text, theme.Font.Main, theme.TextSize.Body, math.huge)
if textBounds.X > width then
width = textBounds.X
local textSize = TextService:GetTextSize(text, 15, Enum.Font.GothamMedium, Vector2.new(math.huge, 20))
if textSize.X > width then
width = textSize.X
end
optionButtons[text] = e("TextButton", {
Text = text,
LayoutOrder = i,
Size = UDim2.new(1, 0, 0, 24),
BackgroundColor3 = dropdownTheme.BackgroundColor,
BackgroundColor3 = theme.BackgroundColor,
TextTransparency = self.props.transparency,
BackgroundTransparency = self.props.transparency,
BorderSizePixel = 0,
TextColor3 = dropdownTheme.TextColor,
TextColor3 = theme.TextColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextSize = theme.TextSize.Body,
FontFace = theme.Font.Main,
TextSize = 15,
Font = Enum.Font.GothamMedium,
[Roact.Event.Activated] = function()
if self.props.locked then
@@ -103,13 +103,13 @@ function Dropdown:render()
}, {
Border = e(SlicedImage, {
slice = Assets.Slices.RoundedBorder,
color = dropdownTheme.BorderColor,
color = theme.BorderColor,
transparency = self.props.transparency,
size = UDim2.new(1, 0, 1, 0),
}, {
DropArrow = e("ImageLabel", {
Image = if self.props.locked then Assets.Images.Dropdown.Locked else Assets.Images.Dropdown.Arrow,
ImageColor3 = dropdownTheme.IconColor,
ImageColor3 = theme.IconColor,
ImageTransparency = self.props.transparency,
Size = UDim2.new(0, 18, 0, 18),
@@ -120,21 +120,15 @@ function Dropdown:render()
end),
BackgroundTransparency = 1,
}, {
StateTip = if self.props.locked
then e(Tooltip.Trigger, {
text = self.props.lockedTooltip or "(Cannot be changed right now)",
})
else nil,
}),
Active = e("TextLabel", {
Size = UDim2.new(1, -30, 1, 0),
Position = UDim2.new(0, 6, 0, 0),
BackgroundTransparency = 1,
Text = self.props.active,
FontFace = theme.Font.Main,
TextSize = theme.TextSize.Body,
TextColor3 = dropdownTheme.TextColor,
Font = Enum.Font.GothamMedium,
TextSize = 15,
TextColor3 = theme.TextColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextTransparency = self.props.transparency,
}),
@@ -142,7 +136,7 @@ function Dropdown:render()
Options = if self.state.open
then e(SlicedImage, {
slice = Assets.Slices.RoundedBackground,
color = dropdownTheme.BackgroundColor,
color = theme.BackgroundColor,
position = UDim2.new(1, 0, 1, 3),
size = self.openBinding:map(function(a)
return UDim2.new(1, 0, a * math.min(3, #self.props.options), 0)
@@ -151,7 +145,7 @@ function Dropdown:render()
}, {
Border = e(SlicedImage, {
slice = Assets.Slices.RoundedBorder,
color = dropdownTheme.BorderColor,
color = theme.BorderColor,
transparency = self.props.transparency,
size = UDim2.new(1, 0, 1, 0),
}),

View File

@@ -31,13 +31,13 @@ local function Header(props)
Version = e("TextLabel", {
Text = Version.display(Config.version),
FontFace = theme.Font.Thin,
TextSize = theme.TextSize.Body,
Font = Enum.Font.Gotham,
TextSize = 14,
TextColor3 = theme.Header.VersionColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextTransparency = props.transparency,
Size = UDim2.new(1, 0, 0, theme.TextSize.Body),
Size = UDim2.new(1, 0, 0, 14),
LayoutOrder = 2,
BackgroundTransparency = 1,

View File

@@ -39,8 +39,8 @@ local function ViewDiffButton(props)
Label = e("TextLabel", {
Text = "View Diff",
BackgroundTransparency = 1,
FontFace = theme.Font.Main,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamMedium,
TextSize = 14,
TextColor3 = theme.Settings.Setting.DescriptionColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextTransparency = props.transparency,
@@ -170,8 +170,8 @@ function ChangeList:render()
ColumnA = e("TextLabel", {
Text = tostring(headerRow[1]),
BackgroundTransparency = 1,
FontFace = theme.Font.Bold,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamBold,
TextSize = 14,
TextColor3 = theme.TextColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextTransparency = props.transparency,
@@ -182,8 +182,8 @@ function ChangeList:render()
ColumnB = e("TextLabel", {
Text = tostring(headerRow[2]),
BackgroundTransparency = 1,
FontFace = theme.Font.Bold,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamBold,
TextSize = 14,
TextColor3 = theme.TextColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextTransparency = props.transparency,
@@ -194,8 +194,8 @@ function ChangeList:render()
ColumnC = e("TextLabel", {
Text = tostring(headerRow[3]),
BackgroundTransparency = 1,
FontFace = theme.Font.Bold,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamBold,
TextSize = 14,
TextColor3 = theme.TextColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextTransparency = props.transparency,
@@ -230,8 +230,8 @@ function ChangeList:render()
ColumnA = e("TextLabel", {
Text = (if isWarning then "" else "") .. tostring(values[1]),
BackgroundTransparency = 1,
FontFace = theme.Font.Main,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamMedium,
TextSize = 14,
TextColor3 = if isWarning then theme.Diff.Warning else theme.TextColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextTransparency = props.transparency,

View File

@@ -32,8 +32,8 @@ local function DisplayValue(props)
Label = e("TextLabel", {
Text = string.format("%d, %d, %d", props.value.R * 255, props.value.G * 255, props.value.B * 255),
BackgroundTransparency = 1,
FontFace = theme.Font.Main,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamMedium,
TextSize = 14,
TextColor3 = props.textColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextTransparency = props.transparency,
@@ -90,8 +90,8 @@ local function DisplayValue(props)
return e("TextLabel", {
Text = textRepresentation,
BackgroundTransparency = 1,
FontFace = theme.Font.Main,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamMedium,
TextSize = 14,
TextColor3 = props.textColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextTransparency = props.transparency,
@@ -112,8 +112,8 @@ local function DisplayValue(props)
return e("TextLabel", {
Text = textRepresentation,
BackgroundTransparency = 1,
FontFace = theme.Font.Main,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamMedium,
TextSize = 14,
TextColor3 = props.textColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextTransparency = props.transparency,

View File

@@ -225,8 +225,8 @@ function DomLabel:render()
Text = (if props.isWarning then "" else "") .. props.name,
RichText = true,
BackgroundTransparency = 1,
FontFace = if props.patchType then theme.Font.Bold else theme.Font.Main,
TextSize = theme.TextSize.Body,
Font = if props.patchType then Enum.Font.GothamBold else Enum.Font.GothamMedium,
TextSize = 14,
TextColor3 = color,
TextXAlignment = Enum.TextXAlignment.Left,
TextTransparency = props.transparency,
@@ -251,11 +251,11 @@ function DomLabel:render()
then e("TextLabel", {
Text = props.changeInfo.edits .. if props.changeInfo.failed then "," else "",
BackgroundTransparency = 1,
FontFace = theme.Font.Thin,
TextSize = theme.TextSize.Body,
Font = Enum.Font.Gotham,
TextSize = 14,
TextColor3 = theme.SubTextColor,
TextTransparency = props.transparency,
Size = UDim2.new(0, 0, 0, theme.TextSize.Body),
Size = UDim2.new(0, 0, 0, 16),
AutomaticSize = Enum.AutomaticSize.X,
LayoutOrder = 2,
})
@@ -264,11 +264,11 @@ function DomLabel:render()
then e("TextLabel", {
Text = props.changeInfo.failed,
BackgroundTransparency = 1,
FontFace = theme.Font.Thin,
TextSize = theme.TextSize.Body,
Font = Enum.Font.Gotham,
TextSize = 14,
TextColor3 = theme.Diff.Warning,
TextTransparency = props.transparency,
Size = UDim2.new(0, 0, 0, theme.TextSize.Body),
Size = UDim2.new(0, 0, 0, 16),
AutomaticSize = Enum.AutomaticSize.X,
LayoutOrder = 6,
})

View File

@@ -124,8 +124,8 @@ function PatchVisualizer:render()
CleanMerge = e("TextLabel", {
Visible = #scrollElements == 0,
Text = "No changes to sync, project is up to date.",
FontFace = theme.Font.Main,
TextSize = theme.TextSize.Medium,
Font = Enum.Font.GothamMedium,
TextSize = 15,
TextColor3 = theme.TextColor,
TextWrapped = true,
Size = UDim2.new(1, 0, 1, 0),

View File

@@ -1,3 +1,5 @@
local TextService = game:GetService("TextService")
local Rojo = script:FindFirstAncestor("Rojo")
local Plugin = Rojo.Plugin
local Packages = Rojo.Packages
@@ -9,7 +11,6 @@ local StringDiff = require(script:FindFirstChild("StringDiff"))
local Timer = require(Plugin.Timer)
local Theme = require(Plugin.App.Theme)
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)
local CodeLabel = require(Plugin.App.Components.CodeLabel)
local BorderedContainer = require(Plugin.App.Components.BorderedContainer)
@@ -31,6 +32,7 @@ function StringDiffVisualizer:init()
end)
end)
self:calculateContentSize()
self:updateScriptBackground()
self:setState({
@@ -52,6 +54,7 @@ end
function StringDiffVisualizer:didUpdate(previousProps)
if previousProps.oldString ~= self.props.oldString or previousProps.newString ~= self.props.newString then
self:calculateContentSize()
local add, remove = self:calculateDiffLines()
self:setState({
add = add,
@@ -60,11 +63,11 @@ function StringDiffVisualizer:didUpdate(previousProps)
end
end
function StringDiffVisualizer:calculateContentSize(theme)
function StringDiffVisualizer:calculateContentSize()
local oldString, newString = self.props.oldString, self.props.newString
local oldStringBounds = getTextBoundsAsync(oldString, theme.Font.Code, theme.TextSize.Code, math.huge)
local newStringBounds = getTextBoundsAsync(newString, theme.Font.Code, theme.TextSize.Code, math.huge)
local oldStringBounds = TextService:GetTextSize(oldString, 16, Enum.Font.RobotoMono, Vector2.new(99999, 99999))
local newStringBounds = TextService:GetTextSize(newString, 16, Enum.Font.RobotoMono, Vector2.new(99999, 99999))
self.setContentSize(
Vector2.new(math.max(oldStringBounds.X, newStringBounds.X), math.max(oldStringBounds.Y, newStringBounds.Y))
@@ -140,8 +143,6 @@ function StringDiffVisualizer:render()
local oldString, newString = self.props.oldString, self.props.newString
return Theme.with(function(theme)
self:calculateContentSize(theme)
return e(BorderedContainer, {
size = self.props.size,
position = self.props.position,

View File

@@ -152,8 +152,8 @@ function Array:render()
BackgroundTransparency = 1,
Text = "Old",
TextXAlignment = Enum.TextXAlignment.Left,
FontFace = theme.Font.Bold,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamBold,
TextSize = 14,
TextColor3 = theme.Settings.Setting.DescriptionColor,
TextTruncate = Enum.TextTruncate.AtEnd,
}),
@@ -163,8 +163,8 @@ function Array:render()
BackgroundTransparency = 1,
Text = "New",
TextXAlignment = Enum.TextXAlignment.Left,
FontFace = theme.Font.Bold,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamBold,
TextSize = 14,
TextColor3 = theme.Settings.Setting.DescriptionColor,
TextTruncate = Enum.TextTruncate.AtEnd,
}),

View File

@@ -112,8 +112,8 @@ function Dictionary:render()
BackgroundTransparency = 1,
Text = key,
TextXAlignment = Enum.TextXAlignment.Left,
FontFace = theme.Font.Main,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamMedium,
TextSize = 14,
TextColor3 = theme.Settings.Setting.DescriptionColor,
TextTruncate = Enum.TextTruncate.AtEnd,
}),
@@ -157,8 +157,8 @@ function Dictionary:render()
BackgroundTransparency = 1,
Text = "Key",
TextXAlignment = Enum.TextXAlignment.Left,
FontFace = theme.Font.Bold,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamBold,
TextSize = 14,
TextColor3 = theme.Settings.Setting.DescriptionColor,
TextTruncate = Enum.TextTruncate.AtEnd,
}),
@@ -168,8 +168,8 @@ function Dictionary:render()
BackgroundTransparency = 1,
Text = "Old",
TextXAlignment = Enum.TextXAlignment.Left,
FontFace = theme.Font.Bold,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamBold,
TextSize = 14,
TextColor3 = theme.Settings.Setting.DescriptionColor,
TextTruncate = Enum.TextTruncate.AtEnd,
}),
@@ -179,8 +179,8 @@ function Dictionary:render()
BackgroundTransparency = 1,
Text = "New",
TextXAlignment = Enum.TextXAlignment.Left,
FontFace = theme.Font.Bold,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamBold,
TextSize = 14,
TextColor3 = theme.Settings.Setting.DescriptionColor,
TextTruncate = Enum.TextTruncate.AtEnd,
}),

View File

@@ -4,7 +4,6 @@ local Packages = Rojo.Packages
local Roact = require(Packages.Roact)
local Theme = require(Plugin.App.Theme)
local Assets = require(Plugin.Assets)
local SlicedImage = require(Plugin.App.Components.SlicedImage)
@@ -12,48 +11,46 @@ local SlicedImage = require(Plugin.App.Components.SlicedImage)
local e = Roact.createElement
return function(props)
return Theme.with(function(theme)
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, theme.TextSize.Medium),
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,
FontFace = theme.Font.Main,
TextSize = theme.TextSize.Small,
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,
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,
}),
})
end)
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

View File

@@ -1,3 +1,5 @@
local TextService = game:GetService("TextService")
local Rojo = script:FindFirstAncestor("Rojo")
local Plugin = Rojo.Plugin
local Packages = Rojo.Packages
@@ -8,7 +10,6 @@ local Flipper = require(Packages.Flipper)
local Theme = require(Plugin.App.Theme)
local Assets = require(Plugin.Assets)
local bindingUtil = require(Plugin.App.bindingUtil)
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)
local SlicedImage = require(script.Parent.SlicedImage)
local TouchRipple = require(script.Parent.TouchRipple)
@@ -40,17 +41,18 @@ end
function TextButton:render()
return Theme.with(function(theme)
local textBounds = getTextBoundsAsync(self.props.text, theme.Font.Main, theme.TextSize.Large, math.huge)
local textSize =
TextService:GetTextSize(self.props.text, 18, Enum.Font.GothamMedium, Vector2.new(math.huge, math.huge))
local style = self.props.style
local buttonTheme = theme.Button[style]
theme = theme.Button[style]
local bindingHover = bindingUtil.deriveProperty(self.binding, "hover")
local bindingEnabled = bindingUtil.deriveProperty(self.binding, "enabled")
return e("ImageButton", {
Size = UDim2.new(0, (theme.TextSize.Body * 2) + textBounds.X, 0, 34),
Size = UDim2.new(0, 15 + textSize.X + 15, 0, 34),
Position = self.props.position,
AnchorPoint = self.props.anchorPoint,
@@ -72,22 +74,18 @@ function TextButton:render()
end,
}, {
TouchRipple = e(TouchRipple, {
color = buttonTheme.ActionFillColor,
color = theme.ActionFillColor,
transparency = self.props.transparency:map(function(value)
return bindingUtil.blendAlpha({ buttonTheme.ActionFillTransparency, value })
return bindingUtil.blendAlpha({ theme.ActionFillTransparency, value })
end),
zIndex = 2,
}),
Text = e("TextLabel", {
Text = self.props.text,
FontFace = theme.Font.Main,
TextSize = theme.TextSize.Large,
TextColor3 = bindingUtil.mapLerp(
bindingEnabled,
buttonTheme.Enabled.TextColor,
buttonTheme.Disabled.TextColor
),
Font = Enum.Font.GothamMedium,
TextSize = 18,
TextColor3 = bindingUtil.mapLerp(bindingEnabled, theme.Enabled.TextColor, theme.Disabled.TextColor),
TextTransparency = self.props.transparency,
Size = UDim2.new(1, 0, 1, 0),
@@ -97,11 +95,7 @@ function TextButton:render()
Border = style == "Bordered" and e(SlicedImage, {
slice = Assets.Slices.RoundedBorder,
color = bindingUtil.mapLerp(
bindingEnabled,
buttonTheme.Enabled.BorderColor,
buttonTheme.Disabled.BorderColor
),
color = bindingUtil.mapLerp(bindingEnabled, theme.Enabled.BorderColor, theme.Disabled.BorderColor),
transparency = self.props.transparency,
size = UDim2.new(1, 0, 1, 0),
@@ -111,18 +105,14 @@ function TextButton:render()
HoverOverlay = e(SlicedImage, {
slice = Assets.Slices.RoundedBackground,
color = buttonTheme.ActionFillColor,
color = theme.ActionFillColor,
transparency = Roact.joinBindings({
hover = bindingHover:map(function(value)
return 1 - value
end),
transparency = self.props.transparency,
}):map(function(values)
return bindingUtil.blendAlpha({
buttonTheme.ActionFillTransparency,
values.hover,
values.transparency,
})
return bindingUtil.blendAlpha({ theme.ActionFillTransparency, values.hover, values.transparency })
end),
size = UDim2.new(1, 0, 1, 0),
@@ -134,8 +124,8 @@ function TextButton:render()
slice = Assets.Slices.RoundedBackground,
color = bindingUtil.mapLerp(
bindingEnabled,
buttonTheme.Enabled.BackgroundColor,
buttonTheme.Disabled.BackgroundColor
theme.Enabled.BackgroundColor,
theme.Disabled.BackgroundColor
),
transparency = self.props.transparency,

View File

@@ -38,18 +38,14 @@ end
function TextInput:render()
return Theme.with(function(theme)
local textInputTheme = theme.TextInput
theme = theme.TextInput
local bindingHover = bindingUtil.deriveProperty(self.binding, "hover")
local bindingEnabled = bindingUtil.deriveProperty(self.binding, "enabled")
return e(SlicedImage, {
slice = Assets.Slices.RoundedBorder,
color = bindingUtil.mapLerp(
bindingEnabled,
textInputTheme.Enabled.BorderColor,
textInputTheme.Disabled.BorderColor
),
color = bindingUtil.mapLerp(bindingEnabled, theme.Enabled.BorderColor, theme.Disabled.BorderColor),
transparency = self.props.transparency,
size = self.props.size or UDim2.new(1, 0, 1, 0),
@@ -59,18 +55,14 @@ function TextInput:render()
}, {
HoverOverlay = e(SlicedImage, {
slice = Assets.Slices.RoundedBackground,
color = textInputTheme.ActionFillColor,
color = theme.ActionFillColor,
transparency = Roact.joinBindings({
hover = bindingHover:map(function(value)
return 1 - value
end),
transparency = self.props.transparency,
}):map(function(values)
return bindingUtil.blendAlpha({
textInputTheme.ActionFillTransparency,
values.hover,
values.transparency,
})
return bindingUtil.blendAlpha({ theme.ActionFillTransparency, values.hover, values.transparency })
end),
size = UDim2.new(1, 0, 1, 0),
zIndex = -1,
@@ -80,18 +72,14 @@ function TextInput:render()
Size = UDim2.fromScale(1, 1),
Text = self.props.text,
PlaceholderText = self.props.placeholder,
FontFace = theme.Font.Main,
TextColor3 = bindingUtil.mapLerp(
bindingEnabled,
textInputTheme.Disabled.TextColor,
textInputTheme.Enabled.TextColor
),
Font = Enum.Font.GothamMedium,
TextColor3 = bindingUtil.mapLerp(bindingEnabled, theme.Disabled.TextColor, theme.Enabled.TextColor),
PlaceholderColor3 = bindingUtil.mapLerp(
bindingEnabled,
textInputTheme.Disabled.PlaceholderColor,
textInputTheme.Enabled.PlaceholderColor
theme.Disabled.PlaceholderColor,
theme.Enabled.PlaceholderColor
),
TextSize = theme.TextSize.Large,
TextSize = 18,
TextEditable = self.props.enabled,
ClearTextOnFocus = self.props.clearTextOnFocus,

View File

@@ -1,3 +1,4 @@
local TextService = game:GetService("TextService")
local HttpService = game:GetService("HttpService")
local Rojo = script:FindFirstAncestor("Rojo")
@@ -7,8 +8,6 @@ local Packages = Rojo.Packages
local Roact = require(Packages.Roact)
local Theme = require(Plugin.App.Theme)
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)
local BorderedContainer = require(Plugin.App.Components.BorderedContainer)
local e = Roact.createElement
@@ -22,48 +21,50 @@ local Y_OVERLAP = 10 -- Let the triangle tail piece overlap the target a bit to
local TooltipContext = Roact.createContext({})
local function Popup(props)
local textSize = TextService:GetTextSize(
props.Text,
16,
Enum.Font.GothamMedium,
Vector2.new(math.min(props.parentSize.X, 160), math.huge)
) + TEXT_PADDING + (Vector2.one * 2)
local trigger = props.Trigger:getValue()
local spaceBelow = props.parentSize.Y
- (trigger.AbsolutePosition.Y + trigger.AbsoluteSize.Y - Y_OVERLAP + TAIL_SIZE)
local spaceAbove = trigger.AbsolutePosition.Y + Y_OVERLAP - TAIL_SIZE
-- If there's not enough space below, and there's more space above, then show the tooltip above the trigger
local displayAbove = spaceBelow < textSize.Y and spaceAbove > spaceBelow
local X = math.clamp(props.Position.X - X_OFFSET, 0, props.parentSize.X - textSize.X)
local Y = 0
if displayAbove then
Y = math.max(trigger.AbsolutePosition.Y - TAIL_SIZE - textSize.Y + Y_OVERLAP, 0)
else
Y = math.min(
trigger.AbsolutePosition.Y + trigger.AbsoluteSize.Y + TAIL_SIZE - Y_OVERLAP,
props.parentSize.Y - textSize.Y
)
end
return Theme.with(function(theme)
local textXSpace = math.min(props.parentSize.X, 250) - TEXT_PADDING.X
local textBounds = getTextBoundsAsync(props.Text, theme.Font.Main, theme.TextSize.Medium, textXSpace)
local contentSize = textBounds + TEXT_PADDING + (Vector2.one * 2)
local trigger = props.Trigger:getValue()
local spaceBelow = props.parentSize.Y
- (trigger.AbsolutePosition.Y + trigger.AbsoluteSize.Y - Y_OVERLAP + TAIL_SIZE)
local spaceAbove = trigger.AbsolutePosition.Y + Y_OVERLAP - TAIL_SIZE
-- If there's not enough space below, and there's more space above, then show the tooltip above the trigger
local displayAbove = spaceBelow < contentSize.Y and spaceAbove > spaceBelow
local X = math.clamp(props.Position.X - X_OFFSET, 0, math.max(props.parentSize.X - contentSize.X, 1))
local Y = 0
if displayAbove then
Y = math.max(trigger.AbsolutePosition.Y - TAIL_SIZE - contentSize.Y + Y_OVERLAP, 0)
else
Y = math.min(
trigger.AbsolutePosition.Y + trigger.AbsoluteSize.Y + TAIL_SIZE - Y_OVERLAP,
props.parentSize.Y - contentSize.Y
)
end
return e(BorderedContainer, {
position = UDim2.fromOffset(X, Y),
size = UDim2.fromOffset(contentSize.X, contentSize.Y),
size = UDim2.fromOffset(textSize.X, textSize.Y),
transparency = props.transparency,
}, {
Label = e("TextLabel", {
BackgroundTransparency = 1,
Position = UDim2.fromScale(0.5, 0.5),
Size = UDim2.new(1, -TEXT_PADDING.X, 1, -TEXT_PADDING.Y),
AnchorPoint = Vector2.new(0.5, 0.5),
Size = UDim2.fromOffset(textBounds.X, textBounds.Y),
Text = props.Text,
TextSize = theme.TextSize.Medium,
FontFace = theme.Font.Main,
TextSize = 16,
Font = Enum.Font.GothamMedium,
TextWrapped = true,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Center,
TextColor3 = theme.Button.Bordered.Enabled.TextColor,
TextTransparency = props.transparency,
}),
@@ -71,8 +72,8 @@ local function Popup(props)
Tail = e("ImageLabel", {
ZIndex = 100,
Position = if displayAbove
then UDim2.new(0, math.clamp(props.Position.X - X, 6, contentSize.X - 6), 1, -1)
else UDim2.new(0, math.clamp(props.Position.X - X, 6, contentSize.X - 6), 0, -TAIL_SIZE + 1),
then UDim2.new(0, math.clamp(props.Position.X - X, 6, textSize.X - 6), 1, -1)
else UDim2.new(0, math.clamp(props.Position.X - X, 6, textSize.X - 6), 0, -TAIL_SIZE + 1),
Size = UDim2.fromOffset(TAIL_SIZE, TAIL_SIZE),
AnchorPoint = Vector2.new(0.5, 0),
Rotation = if displayAbove then 180 else 0,

View File

@@ -1,3 +1,4 @@
local TextService = game:GetService("TextService")
local StudioService = game:GetService("StudioService")
local Rojo = script:FindFirstAncestor("Rojo")
@@ -8,10 +9,10 @@ local Roact = require(Packages.Roact)
local Flipper = require(Packages.Flipper)
local Log = require(Packages.Log)
local bindingUtil = require(script.Parent.bindingUtil)
local Theme = require(Plugin.App.Theme)
local Assets = require(Plugin.Assets)
local bindingUtil = require(Plugin.App.bindingUtil)
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)
local BorderedContainer = require(Plugin.App.Components.BorderedContainer)
local TextButton = require(Plugin.App.Components.TextButton)
@@ -85,46 +86,51 @@ function Notification:render()
return 1 - value
end)
return Theme.with(function(theme)
local actionButtons = {}
local buttonsX = 0
if self.props.actions then
local count = 0
for key, action in self.props.actions do
actionButtons[key] = e(TextButton, {
text = action.text,
style = action.style,
onClick = function()
local success, err = pcall(action.onClick, self)
if not success then
Log.warn("Error in notification action: " .. tostring(err))
end
end,
layoutOrder = -action.layoutOrder,
transparency = transparency,
})
local textBounds = TextService:GetTextSize(self.props.text, 15, Enum.Font.GothamMedium, Vector2.new(350, 700))
buttonsX += getTextBoundsAsync(action.text, theme.Font.Main, theme.TextSize.Large, math.huge).X + (theme.TextSize.Body * 2)
local actionButtons = {}
local buttonsX = 0
if self.props.actions then
local count = 0
for key, action in self.props.actions do
actionButtons[key] = e(TextButton, {
text = action.text,
style = action.style,
onClick = function()
local success, err = pcall(action.onClick, self)
if not success then
Log.warn("Error in notification action: " .. tostring(err))
end
end,
layoutOrder = -action.layoutOrder,
transparency = transparency,
})
count += 1
end
buttonsX += TextService:GetTextSize(
action.text,
18,
Enum.Font.GothamMedium,
Vector2.new(math.huge, math.huge)
).X + 30
buttonsX += (count - 1) * 5
count += 1
end
local paddingY, logoSize = 20, 32
local actionsY = if self.props.actions then 37 else 0
local textXSpace = math.max(250, buttonsX) + 35
local textBounds = getTextBoundsAsync(self.props.text, theme.Font.Main, theme.TextSize.Body, textXSpace)
local contentX = math.max(textBounds.X, buttonsX)
buttonsX += (count - 1) * 5
end
local size = self.binding:map(function(value)
return UDim2.fromOffset(
(35 + 40 + contentX) * value,
5 + actionsY + paddingY + math.max(logoSize, textBounds.Y)
)
end)
local paddingY, logoSize = 20, 32
local actionsY = if self.props.actions then 35 else 0
local contentX = math.max(textBounds.X, buttonsX)
local size = self.binding:map(function(value)
return UDim2.fromOffset(
(35 + 40 + contentX) * value,
5 + actionsY + paddingY + math.max(logoSize, textBounds.Y)
)
end)
return Theme.with(function(theme)
return e("TextButton", {
BackgroundTransparency = 1,
Size = size,
@@ -141,7 +147,8 @@ function Notification:render()
size = UDim2.new(1, 0, 1, 0),
}, {
Contents = e("Frame", {
Size = UDim2.new(1, 0, 1, 0),
Size = UDim2.new(0, 35 + contentX, 1, -paddingY),
Position = UDim2.new(0, 0, 0, paddingY / 2),
BackgroundTransparency = 1,
}, {
Logo = e("ImageLabel", {
@@ -154,15 +161,14 @@ function Notification:render()
}),
Info = e("TextLabel", {
Text = self.props.text,
FontFace = theme.Font.Main,
TextSize = theme.TextSize.Body,
Font = Enum.Font.GothamMedium,
TextSize = 15,
TextColor3 = theme.Notification.InfoColor,
TextTransparency = transparency,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Center,
TextWrapped = true,
Size = UDim2.new(0, textBounds.X, 1, -actionsY),
Size = UDim2.new(0, textBounds.X, 0, textBounds.Y),
Position = UDim2.fromOffset(35, 0),
LayoutOrder = 1,
@@ -170,7 +176,7 @@ function Notification:render()
}),
Actions = if self.props.actions
then e("Frame", {
Size = UDim2.new(1, -40, 0, actionsY),
Size = UDim2.new(1, -40, 0, 35),
Position = UDim2.new(1, 0, 1, 0),
AnchorPoint = Vector2.new(1, 1),
BackgroundTransparency = 1,
@@ -190,8 +196,6 @@ function Notification:render()
Padding = e("UIPadding", {
PaddingLeft = UDim.new(0, 17),
PaddingRight = UDim.new(0, 15),
PaddingTop = UDim.new(0, paddingY / 2),
PaddingBottom = UDim.new(0, paddingY / 2),
}),
}),
})

View File

@@ -64,13 +64,13 @@ function ConfirmingPage:render()
"Sync changes for project '%s':",
self.props.confirmData.serverInfo.projectName or "UNKNOWN"
),
FontFace = theme.Font.Thin,
Font = Enum.Font.Gotham,
LineHeight = 1.2,
TextSize = theme.TextSize.Body,
TextSize = 14,
TextColor3 = theme.TextColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextTransparency = self.props.transparency,
Size = UDim2.new(1, 0, 0, theme.TextSize.Large + 2),
Size = UDim2.new(1, 0, 0, 20),
BackgroundTransparency = 1,
}),

View File

@@ -61,12 +61,12 @@ function ChangesViewer:render()
Title = e("TextLabel", {
Text = "Sync",
FontFace = theme.Font.Main,
TextSize = theme.TextSize.Large,
Font = Enum.Font.GothamMedium,
TextSize = 17,
TextXAlignment = Enum.TextXAlignment.Left,
TextColor3 = theme.TextColor,
TextTransparency = self.props.transparency,
Size = UDim2.new(1, -40, 0, theme.TextSize.Large + 2),
Size = UDim2.new(1, -40, 0, 20),
Position = UDim2.new(0, 40, 0, 0),
BackgroundTransparency = 1,
}),
@@ -74,13 +74,13 @@ function ChangesViewer:render()
Subtitle = e("TextLabel", {
Text = DateTime.fromUnixTimestamp(self.props.patchData.timestamp):FormatLocalTime("LTS", "en-us"),
TextXAlignment = Enum.TextXAlignment.Left,
FontFace = theme.Font.Thin,
TextSize = theme.TextSize.Medium,
Font = Enum.Font.Gotham,
TextSize = 15,
TextColor3 = theme.SubTextColor,
TextTruncate = Enum.TextTruncate.AtEnd,
TextTransparency = self.props.transparency,
Size = UDim2.new(1, -40, 0, theme.TextSize.Medium),
Position = UDim2.new(0, 40, 0, theme.TextSize.Large + 2),
Size = UDim2.new(1, -40, 0, 16),
Position = UDim2.new(0, 40, 0, 20),
BackgroundTransparency = 1,
}),
@@ -131,8 +131,8 @@ function ChangesViewer:render()
}),
AppliedText = e("TextLabel", {
Text = applied,
FontFace = theme.Font.Thin,
TextSize = theme.TextSize.Body,
Font = Enum.Font.Gotham,
TextSize = 15,
TextColor3 = theme.TextColor,
TextTransparency = self.props.transparency,
Size = UDim2.new(0, 0, 1, 0),
@@ -156,8 +156,8 @@ function ChangesViewer:render()
}),
UnappliedText = e("TextLabel", {
Text = unapplied,
FontFace = theme.Font.Thin,
TextSize = theme.TextSize.Body,
Font = Enum.Font.Gotham,
TextSize = 15,
TextColor3 = theme.Diff.Warning,
TextTransparency = self.props.transparency,
Size = UDim2.new(0, 0, 1, 0),
@@ -217,13 +217,13 @@ local function ConnectionDetails(props)
}, {
ProjectName = e("TextLabel", {
Text = props.projectName,
FontFace = theme.Font.Bold,
TextSize = theme.TextSize.Large,
Font = Enum.Font.GothamBold,
TextSize = 20,
TextColor3 = theme.ConnectionDetails.ProjectNameColor,
TextTransparency = props.transparency,
TextXAlignment = Enum.TextXAlignment.Left,
Size = UDim2.new(1, 0, 0, theme.TextSize.Large),
Size = UDim2.new(1, 0, 0, 20),
LayoutOrder = 1,
BackgroundTransparency = 1,
@@ -231,13 +231,13 @@ local function ConnectionDetails(props)
Address = e("TextLabel", {
Text = props.address,
FontFace = theme.Font.Code,
TextSize = theme.TextSize.Medium,
Font = Enum.Font.Code,
TextSize = 15,
TextColor3 = theme.ConnectionDetails.AddressColor,
TextTransparency = props.transparency,
TextXAlignment = Enum.TextXAlignment.Left,
Size = UDim2.new(1, 0, 0, theme.TextSize.Medium),
Size = UDim2.new(1, 0, 0, 15),
LayoutOrder = 2,
BackgroundTransparency = 1,
@@ -410,8 +410,8 @@ function ConnectedPage:render()
Text = e("TextLabel", {
BackgroundTransparency = 1,
Text = self.changeInfoText,
FontFace = theme.Font.Thin,
TextSize = theme.TextSize.Body,
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,

View File

@@ -1,3 +1,5 @@
local TextService = game:GetService("TextService")
local Rojo = script:FindFirstAncestor("Rojo")
local Plugin = Rojo.Plugin
local Packages = Rojo.Packages
@@ -5,7 +7,6 @@ local Packages = Rojo.Packages
local Roact = require(Packages.Roact)
local Theme = require(Plugin.App.Theme)
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)
local TextButton = require(Plugin.App.Components.TextButton)
local BorderedContainer = require(Plugin.App.Components.BorderedContainer)
@@ -23,43 +24,43 @@ function Error:init()
end
function Error:render()
return Theme.with(function(theme)
return e(BorderedContainer, {
size = Roact.joinBindings({
containerSize = self.props.containerSize,
contentSize = self.contentSize,
}):map(function(values)
local maximumSize = values.containerSize
maximumSize -= Vector2.new(14, 14) * 2 -- Page padding
maximumSize -= Vector2.new(0, 34 + 10) -- Buttons and spacing
return e(BorderedContainer, {
size = Roact.joinBindings({
containerSize = self.props.containerSize,
contentSize = self.contentSize,
}):map(function(values)
local maximumSize = values.containerSize
maximumSize -= Vector2.new(14, 14) * 2 -- Page padding
maximumSize -= Vector2.new(0, 34 + 10) -- Buttons and spacing
local outerSize = values.contentSize + ERROR_PADDING * 2
local outerSize = values.contentSize + ERROR_PADDING * 2
return UDim2.new(1, 0, 0, math.min(outerSize.Y, maximumSize.Y))
return UDim2.new(1, 0, 0, math.min(outerSize.Y, maximumSize.Y))
end),
transparency = self.props.transparency,
}, {
ScrollingFrame = e(ScrollingFrame, {
size = UDim2.new(1, 0, 1, 0),
contentSize = self.contentSize:map(function(value)
return value + ERROR_PADDING * 2
end),
transparency = self.props.transparency,
[Roact.Change.AbsoluteSize] = function(object)
local containerSize = object.AbsoluteSize - ERROR_PADDING * 2
local textBounds = TextService:GetTextSize(
self.props.errorMessage,
16,
Enum.Font.Code,
Vector2.new(containerSize.X, math.huge)
)
self.setContentSize(Vector2.new(containerSize.X, textBounds.Y))
end,
}, {
ScrollingFrame = e(ScrollingFrame, {
size = UDim2.new(1, 0, 1, 0),
contentSize = self.contentSize:map(function(value)
return value + ERROR_PADDING * 2
end),
transparency = self.props.transparency,
[Roact.Change.AbsoluteSize] = function(object)
local containerSize = object.AbsoluteSize - ERROR_PADDING * 2
local textBounds = getTextBoundsAsync(
self.props.errorMessage,
theme.Font.Code,
theme.TextSize.Code,
containerSize.X
)
self.setContentSize(Vector2.new(containerSize.X, textBounds.Y))
end,
}, {
ErrorMessage = e("TextBox", {
ErrorMessage = Theme.with(function(theme)
return e("TextBox", {
[Roact.Event.InputBegan] = function(rbx, input)
if input.UserInputType ~= Enum.UserInputType.MouseButton1 then
return
@@ -70,8 +71,8 @@ function Error:render()
Text = self.props.errorMessage,
TextEditable = false,
FontFace = theme.Font.Code,
TextSize = theme.TextSize.Code,
Font = Enum.Font.Code,
TextSize = 16,
TextColor3 = theme.ErrorColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
@@ -80,17 +81,17 @@ function Error:render()
ClearTextOnFocus = false,
BackgroundTransparency = 1,
Size = UDim2.new(1, 0, 1, 0),
}),
})
end),
Padding = e("UIPadding", {
PaddingLeft = UDim.new(0, ERROR_PADDING.X),
PaddingRight = UDim.new(0, ERROR_PADDING.X),
PaddingTop = UDim.new(0, ERROR_PADDING.Y),
PaddingBottom = UDim.new(0, ERROR_PADDING.Y),
}),
Padding = e("UIPadding", {
PaddingLeft = UDim.new(0, ERROR_PADDING.X),
PaddingRight = UDim.new(0, ERROR_PADDING.X),
PaddingTop = UDim.new(0, ERROR_PADDING.Y),
PaddingBottom = UDim.new(0, ERROR_PADDING.Y),
}),
})
end)
}),
})
end
local ErrorPage = Roact.Component:extend("ErrorPage")

View File

@@ -27,8 +27,8 @@ local function AddressEntry(props)
}, {
Host = e("TextBox", {
Text = props.host or "",
FontFace = theme.Font.Code,
TextSize = theme.TextSize.Large,
Font = Enum.Font.Code,
TextSize = 18,
TextColor3 = theme.AddressEntry.TextColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextTransparency = props.transparency,
@@ -51,8 +51,8 @@ local function AddressEntry(props)
Port = e("TextBox", {
Text = props.port or "",
FontFace = theme.Font.Code,
TextSize = theme.TextSize.Large,
Font = Enum.Font.Code,
TextSize = 18,
TextColor3 = theme.AddressEntry.TextColor,
TextTransparency = props.transparency,
PlaceholderText = Config.defaultPort,

View File

@@ -1,3 +1,5 @@
local TextService = game:GetService("TextService")
local Rojo = script:FindFirstAncestor("Rojo")
local Plugin = Rojo.Plugin
local Packages = Rojo.Packages
@@ -7,7 +9,6 @@ local Roact = require(Packages.Roact)
local Settings = require(Plugin.Settings)
local Assets = require(Plugin.Assets)
local Theme = require(Plugin.App.Theme)
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)
local Checkbox = require(Plugin.App.Components.Checkbox)
local Dropdown = require(Plugin.App.Components.Dropdown)
@@ -30,16 +31,10 @@ local TAG_TYPES = {
},
}
local function getTextBoundsWithLineHeight(
text: string,
font: Font,
textSize: number,
width: number,
lineHeight: number
)
local textBounds = getTextBoundsAsync(text, font, textSize, width)
local function getTextBounds(text, textSize, font, lineHeight, bounds)
local textBounds = TextService:GetTextSize(text, textSize, font, bounds)
local lineCount = math.ceil(textBounds.Y / textSize)
local lineCount = textBounds.Y / textSize
local lineHeightAbsolute = textSize * lineHeight
return Vector2.new(textBounds.X, lineHeightAbsolute * lineCount - (lineHeightAbsolute - textSize))
@@ -114,7 +109,6 @@ function Setting:render()
then self.props.input
elseif self.props.options ~= nil then e(Dropdown, {
locked = self.props.locked,
lockedTooltip = self.props.lockedTooltip,
options = self.props.options,
active = self.state.setting,
transparency = self.props.transparency,
@@ -124,7 +118,6 @@ function Setting:render()
})
else e(Checkbox, {
locked = self.props.locked,
lockedTooltip = self.props.lockedTooltip,
active = self.state.setting,
transparency = self.props.transparency,
onClick = function()
@@ -152,7 +145,7 @@ function Setting:render()
BackgroundTransparency = 1,
}, {
Heading = e("Frame", {
Size = UDim2.new(1, 0, 0, theme.TextSize.Medium),
Size = UDim2.new(1, 0, 0, 16),
BackgroundTransparency = 1,
}, {
Layout = e("UIListLayout", {
@@ -172,8 +165,8 @@ function Setting:render()
else nil,
Name = e("TextLabel", {
Text = self.props.name,
FontFace = theme.Font.Bold,
TextSize = theme.TextSize.Medium,
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,
@@ -181,7 +174,7 @@ function Setting:render()
TextTransparency = self.props.transparency,
RichText = true,
Size = UDim2.new(1, 0, 0, theme.TextSize.Medium),
Size = UDim2.new(1, 0, 0, 16),
LayoutOrder = 2,
BackgroundTransparency = 1,
@@ -190,9 +183,9 @@ function Setting:render()
Description = e("TextLabel", {
Text = self.props.description,
FontFace = theme.Font.Main,
Font = Enum.Font.Gotham,
LineHeight = 1.2,
TextSize = theme.TextSize.Body,
TextSize = 14,
TextColor3 = settingsTheme.Setting.DescriptionColor,
TextXAlignment = Enum.TextXAlignment.Left,
TextTransparency = self.props.transparency,
@@ -204,12 +197,12 @@ function Setting:render()
inputSize = self.inputSize,
}):map(function(values)
local offset = values.inputSize.X + 5
local textBounds = getTextBoundsWithLineHeight(
local textBounds = getTextBounds(
self.props.description,
theme.Font.Main,
theme.TextSize.Body,
values.containerSize.X - offset,
1.2
14,
Enum.Font.Gotham,
1.2,
Vector2.new(values.containerSize.X - offset, math.huge)
)
return UDim2.new(1, -offset, 0, textBounds.Y)
end),

View File

@@ -30,7 +30,7 @@ local confirmationBehaviors = { "Initial", "Always", "Large Changes", "Unlisted
local function Navbar(props)
return Theme.with(function(theme)
local navbarTheme = theme.Settings.Navbar
theme = theme.Settings.Navbar
return e("Frame", {
Size = UDim2.new(1, 0, 0, 46),
@@ -40,7 +40,7 @@ local function Navbar(props)
Back = e(IconButton, {
icon = Assets.Images.Icons.Back,
iconSize = 24,
color = navbarTheme.BackButtonColor,
color = theme.BackButtonColor,
transparency = props.transparency,
position = UDim2.new(0, 0, 0.5, 0),
@@ -55,9 +55,9 @@ local function Navbar(props)
Text = e("TextLabel", {
Text = "Settings",
FontFace = theme.Font.Thin,
TextSize = theme.TextSize.Large,
TextColor3 = navbarTheme.TextColor,
Font = Enum.Font.Gotham,
TextSize = 18,
TextColor3 = theme.TextColor,
TextTransparency = props.transparency,
Size = UDim2.new(1, 0, 1, 0),
@@ -81,182 +81,185 @@ function SettingsPage:render()
return layoutOrder
end
return Roact.createFragment({
Navbar = e(Navbar, {
onBack = self.props.onBack,
transparency = self.props.transparency,
layoutOrder = layoutIncrement(),
}),
Content = e(ScrollingFrame, {
size = UDim2.new(1, 0, 1, -47),
position = UDim2.new(0, 0, 0, 47),
contentSize = self.contentSize,
transparency = self.props.transparency,
}, {
ShowNotifications = e(Setting, {
id = "showNotifications",
name = "Show Notifications",
description = "Popup notifications in viewport",
return Theme.with(function(theme)
theme = theme.Settings
return Roact.createFragment({
Navbar = e(Navbar, {
onBack = self.props.onBack,
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",
Content = e(ScrollingFrame, {
size = UDim2.new(1, 0, 1, -47),
position = UDim2.new(0, 0, 0, 47),
contentSize = self.contentSize,
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(),
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)
end),
}, {
ShowNotifications = e(Setting, {
id = "showNotifications",
name = "Show Notifications",
description = "Popup notifications in viewport",
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
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(),
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)
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,
layoutOrder = layoutIncrement(),
}),
CheckForUpdates = e(Setting, {
id = "checkForUpdates",
name = "Check For Updates",
description = "Notify about newer compatible Rojo releases",
transparency = self.props.transparency,
layoutOrder = layoutIncrement(),
}),
CheckForPreleases = e(Setting, {
id = "checkForPrereleases",
name = "Include Prerelease Updates",
description = "Include prereleases when checking for updates",
transparency = self.props.transparency,
layoutOrder = layoutIncrement(),
visible = if string.find(debug.traceback(), "\n[^\n]-user_.-$") == nil
then false -- Must be a local install to allow prerelease checks
else Settings:getBinding("checkForUpdates"),
}),
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(),
}),
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(),
}),
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(),
}),
LogLevel = e(Setting, {
id = "logLevel",
name = "Log Level",
description = "Plugin output verbosity level",
tag = "debug",
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,
}),
TypecheckingEnabled = e(Setting, {
id = "typecheckingEnabled",
name = "Typechecking",
description = "Toggle typechecking on the API surface",
tag = "debug",
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,
[Roact.Change.AbsoluteContentSize] = function(object)
self.setContentSize(object.AbsoluteContentSize)
end,
}),
Padding = e("UIPadding", {
PaddingLeft = UDim.new(0, 20),
PaddingRight = UDim.new(0, 20),
}),
}),
PlaySounds = e(Setting, {
id = "playSounds",
name = "Play Sounds",
description = "Toggle sound effects",
transparency = self.props.transparency,
layoutOrder = layoutIncrement(),
}),
CheckForUpdates = e(Setting, {
id = "checkForUpdates",
name = "Check For Updates",
description = "Notify about newer compatible Rojo releases",
transparency = self.props.transparency,
layoutOrder = layoutIncrement(),
}),
CheckForPreleases = e(Setting, {
id = "checkForPrereleases",
name = "Include Prerelease Updates",
description = "Include prereleases when checking for updates",
transparency = self.props.transparency,
layoutOrder = layoutIncrement(),
visible = if string.find(debug.traceback(), "\n[^\n]-user_.-$") == nil
then false -- Must be a local install to allow prerelease checks
else Settings:getBinding("checkForUpdates"),
}),
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(),
}),
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(),
}),
TwoWaySync = e(Setting, {
id = "twoWaySync",
name = "Two-Way Sync",
description = "Editing files in Studio will sync them into the filesystem",
locked = self.props.syncActive,
lockedTooltip = "(Cannot change while currently syncing. Disconnect first.)",
tag = "unstable",
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(),
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(),
}),
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,
[Roact.Change.AbsoluteContentSize] = function(object)
self.setContentSize(object.AbsoluteContentSize)
end,
}),
Padding = e("UIPadding", {
PaddingLeft = UDim.new(0, 20),
PaddingRight = UDim.new(0, 20),
}),
}),
})
})
end)
end
return SettingsPage

View File

@@ -1,6 +1,7 @@
--[[
Theming system provided through Roact's context.
Uses Studio colors when possible.
Theming system taking advantage of Roact's new context API.
Doesn't use colors provided by Studio and instead just branches on theme
name. This isn't exactly best practice.
]]
-- Studio does not exist outside Roblox Studio, so we'll lazily initialize it
@@ -14,8 +15,6 @@ local function getStudio()
return _Studio
end
local ContentProvider = game:GetService("ContentProvider")
local Rojo = script:FindFirstAncestor("Rojo")
local Packages = Rojo.Packages
@@ -36,27 +35,6 @@ function StudioProvider:updateTheme()
local isDark = studioTheme.Name == "Dark"
local theme = strict(studioTheme.Name .. "Theme", {
Font = {
Main = Font.new("rbxasset://fonts/families/Montserrat.json", Enum.FontWeight.Medium, Enum.FontStyle.Normal),
Bold = Font.new("rbxasset://fonts/families/Montserrat.json", Enum.FontWeight.Bold, Enum.FontStyle.Normal),
Thin = Font.new(
"rbxasset://fonts/families/Montserrat.json",
Enum.FontWeight.Regular,
Enum.FontStyle.Normal
),
Code = Font.new(
"rbxasset://fonts/families/Inconsolata.json",
Enum.FontWeight.Regular,
Enum.FontStyle.Normal
),
},
TextSize = {
Body = 15,
Small = 13,
Medium = 16,
Large = 18,
Code = 16,
},
BrandColor = BRAND_COLOR,
BackgroundColor = studioTheme:GetColor(Enum.StudioStyleGuideColor.MainBackground),
TextColor = studioTheme:GetColor(Enum.StudioStyleGuideColor.MainText),
@@ -212,13 +190,6 @@ end
function StudioProvider:init()
self:updateTheme()
-- Preload the Fonts so that getTextBoundsAsync won't yield
local fontAssetIds = {}
for _, font in self.state.theme.Font do
table.insert(fontAssetIds, font.Family)
end
pcall(ContentProvider.PreloadAsync, ContentProvider, fontAssetIds)
end
function StudioProvider:render()

View File

@@ -1,41 +0,0 @@
local TextService = game:GetService("TextService")
local Rojo = script:FindFirstAncestor("Rojo")
local Packages = Rojo.Packages
local Log = require(Packages.Log)
local params = Instance.new("GetTextBoundsParams")
local function getTextBoundsAsync(
text: string,
font: Font,
textSize: number,
width: number,
richText: boolean?
): Vector2
if type(text) ~= "string" then
Log.warn(`Invalid text. Expected string, received {type(text)} instead`)
return Vector2.zero
end
if #text >= 200_000 then
Log.warn(`Invalid text. Exceeds the 199,999 character limit`)
return Vector2.zero
end
params.Text = text
params.Font = font
params.Size = textSize
params.Width = width
params.RichText = not not richText
local success, bounds = pcall(TextService.GetTextBoundsAsync, TextService, params)
if not success then
Log.warn(`Failed to get text bounds: {bounds}`)
return Vector2.zero
end
return bounds
end
return getTextBoundsAsync

View File

@@ -52,9 +52,9 @@ local App = Roact.Component:extend("App")
function App:init()
preloadAssets()
local priorSyncInfo = self:getPriorSyncInfo()
self.host, self.setHost = Roact.createBinding(priorSyncInfo.host or "")
self.port, self.setPort = Roact.createBinding(priorSyncInfo.port or "")
local priorHost, priorPort = self:getPriorEndpoint()
self.host, self.setHost = Roact.createBinding(priorHost or "")
self.port, self.setPort = Roact.createBinding(priorPort or "")
self.confirmationBindable = Instance.new("BindableEvent")
self.confirmationEvent = self.confirmationBindable.Event
@@ -145,38 +145,28 @@ function App:init()
if
Settings:get("syncReminder")
and self.serveSession == nil
and self:getPriorSyncInfo().timestamp ~= nil
and self:getLastSyncTimestamp()
and (self:isSyncLockAvailable())
then
local syncInfo = self:getPriorSyncInfo()
local timeSinceSync = timeUtil.elapsedToText(os.time() - syncInfo.timestamp)
local syncDetail = if syncInfo.projectName
then `project '{syncInfo.projectName}'`
else `{syncInfo.host or Config.defaultHost}:{syncInfo.port or Config.defaultPort}`
self:addNotification(
`You synced {syncDetail} to this place {timeSinceSync}. Would you like to reconnect?`,
300,
{
Connect = {
text = "Connect",
style = "Solid",
layoutOrder = 1,
onClick = function(notification)
notification:dismiss()
self:startSession()
end,
},
Dismiss = {
text = "Dismiss",
style = "Bordered",
layoutOrder = 2,
onClick = function(notification)
notification:dismiss()
end,
},
}
)
self:addNotification("You've previously synced this place. Would you like to reconnect?", 300, {
Connect = {
text = "Connect",
style = "Solid",
layoutOrder = 1,
onClick = function(notification)
notification:dismiss()
self:startSession()
end,
},
Dismiss = {
text = "Dismiss",
style = "Bordered",
layoutOrder = 2,
onClick = function(notification)
notification:dismiss()
end,
},
})
end
end
@@ -284,32 +274,54 @@ function App:checkForUpdates()
)
end
function App:getPriorSyncInfo(): { host: string?, port: string?, projectName: string?, timestamp: number? }
local priorSyncInfos = Settings:get("priorEndpoints")
if not priorSyncInfos then
return {}
function App:getPriorEndpoint()
local priorEndpoints = Settings:get("priorEndpoints")
if not priorEndpoints then
return
end
local id = tostring(game.PlaceId)
if ignorePlaceIds[id] then
return {}
return
end
return priorSyncInfos[id] or {}
local place = priorEndpoints[id]
if not place then
return
end
return place.host, place.port
end
function App:setPriorSyncInfo(host: string, port: string, projectName: string)
local priorSyncInfos = Settings:get("priorEndpoints")
if not priorSyncInfos then
priorSyncInfos = {}
function App:getLastSyncTimestamp()
local priorEndpoints = Settings:get("priorEndpoints")
if not priorEndpoints then
return
end
local now = os.time()
local id = tostring(game.PlaceId)
if ignorePlaceIds[id] then
return
end
local place = priorEndpoints[id]
if not place then
return
end
return place.timestamp
end
function App:setPriorEndpoint(host: string, port: string)
local priorEndpoints = Settings:get("priorEndpoints")
if not priorEndpoints then
priorEndpoints = {}
end
-- Clear any stale saves to avoid disc bloat
for placeId, syncInfo in priorSyncInfos do
if now - (syncInfo.timestamp or now) > 12_960_000 then
priorSyncInfos[placeId] = nil
for placeId, endpoint in priorEndpoints do
if os.time() - endpoint.timestamp > 12_960_000 then
priorEndpoints[placeId] = nil
Log.trace("Cleared stale saved endpoint for {}", placeId)
end
end
@@ -319,15 +331,14 @@ function App:setPriorSyncInfo(host: string, port: string, projectName: string)
return
end
priorSyncInfos[id] = {
priorEndpoints[id] = {
host = if host ~= Config.defaultHost then host else nil,
port = if port ~= Config.defaultPort then port else nil,
projectName = projectName,
timestamp = now,
timestamp = os.time(),
}
Log.trace("Saved last used endpoint for {}", game.PlaceId)
Settings:set("priorEndpoints", priorSyncInfos)
Settings:set("priorEndpoints", priorEndpoints)
end
function App:getHostAndPort()
@@ -522,6 +533,8 @@ function App:startSession()
serveSession:onStatusChanged(function(status, details)
if status == ServeSession.Status.Connecting then
self:setPriorEndpoint(host, port)
self:setState({
appStatus = AppStatus.Connecting,
toolbarIcon = Assets.Images.PluginButton,
@@ -529,7 +542,6 @@ function App:startSession()
self:addNotification("Connecting to session...")
elseif status == ServeSession.Status.Connected then
self.knownProjects[details] = true
self:setPriorSyncInfo(host, port, details)
self:setRunningConnectionInfo(baseUrl)
local address = ("%s:%s"):format(host, port)

View File

@@ -16,7 +16,6 @@ local invariant = require(script.Parent.Parent.invariant)
local decodeValue = require(script.Parent.decodeValue)
local reify = require(script.Parent.reify)
local reifyInstance, applyDeferredRefs = reify.reifyInstance, reify.applyDeferredRefs
local setProperty = require(script.Parent.setProperty)
local function applyPatch(instanceMap, patch)
@@ -30,11 +29,6 @@ local function applyPatch(instanceMap, patch)
-- Tracks any portions of the patch that could not be applied to the DOM.
local unappliedPatch = PatchSet.newEmpty()
-- Contains a list of all of the ref properties that we'll need to assign.
-- It is imperative that refs are assigned after all instances are created
-- to ensure that referents can be mapped to instances correctly.
local deferredRefs = {}
for _, removedIdOrInstance in ipairs(patch.removed) do
local removeInstanceSuccess = pcall(function()
if Types.RbxId(removedIdOrInstance) then
@@ -84,7 +78,7 @@ local function applyPatch(instanceMap, patch)
)
end
local failedToReify = reifyInstance(deferredRefs, instanceMap, patch.added, id, parentInstance)
local failedToReify = reify(instanceMap, patch.added, id, parentInstance)
if not PatchSet.isEmpty(failedToReify) then
Log.debug("Failed to reify as part of applying a patch: {:#?}", failedToReify)
@@ -149,7 +143,7 @@ local function applyPatch(instanceMap, patch)
[update.id] = mockVirtualInstance,
}
local failedToReify = reifyInstance(deferredRefs, instanceMap, mockAdded, update.id, instance.Parent)
local failedToReify = reify(instanceMap, mockAdded, update.id, instance.Parent)
local newInstance = instanceMap.fromIds[update.id]
@@ -212,18 +206,6 @@ local function applyPatch(instanceMap, patch)
if update.changedProperties ~= nil then
for propertyName, propertyValue in pairs(update.changedProperties) do
-- Because refs may refer to instances that we haven't constructed yet,
-- we defer applying any ref properties until all instances are created.
if next(propertyValue) == "Ref" then
table.insert(deferredRefs, {
id = update.id,
instance = instance,
propertyName = propertyName,
virtualValue = propertyValue,
})
continue
end
local decodeSuccess, decodedValue = decodeValue(propertyValue, instanceMap)
if not decodeSuccess then
unappliedUpdate.changedProperties[propertyName] = propertyValue
@@ -248,8 +230,6 @@ local function applyPatch(instanceMap, patch)
ChangeHistoryService:FinishRecording(historyRecording, Enum.FinishRecordingOperation.Commit)
end
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
return unappliedPatch
end

View File

@@ -151,24 +151,7 @@ local function diff(instanceMap, virtualInstances, rootId)
if getProperySuccess then
local existingValue = existingValueOrErr
local decodeSuccess, decodedValue
-- If `virtualValue` is a ref then instead of decoding it to an instance,
-- we change `existingValue` to be a ref. This is because `virtualValue`
-- may point to an Instance which doesn't exist yet and therefore
-- decoding it may throw an error.
if next(virtualValue) == "Ref" then
decodeSuccess, decodedValue = true, virtualValue
if existingValue and typeof(existingValue) == "Instance" then
local existingValueRef = instanceMap.fromInstances[existingValue]
if existingValueRef then
existingValue = { Ref = existingValueRef }
end
end
else
decodeSuccess, decodedValue = decodeValue(virtualValue, instanceMap)
end
local decodeSuccess, decodedValue = decodeValue(virtualValue, instanceMap)
if decodeSuccess then
if not trueEquals(existingValue, decodedValue) then

View File

@@ -7,6 +7,26 @@ local PatchSet = require(script.Parent.Parent.PatchSet)
local setProperty = require(script.Parent.setProperty)
local decodeValue = require(script.Parent.decodeValue)
local reifyInner, applyDeferredRefs
local function reify(instanceMap, virtualInstances, rootId, parentInstance)
-- Create an empty patch that will be populated with any parts of this reify
-- that could not happen, like instances that couldn't be created and
-- properties that could not be assigned.
local unappliedPatch = PatchSet.newEmpty()
-- Contains a list of all of the ref properties that we'll need to assign
-- after all instances are created. We apply refs in a second pass, after
-- we create as many instances as we can, so that we ensure that referents
-- can be mapped to instances correctly.
local deferredRefs = {}
reifyInner(instanceMap, virtualInstances, rootId, parentInstance, unappliedPatch, deferredRefs)
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
return unappliedPatch
end
--[[
Add the given ID and all of its descendants in virtualInstances to the given
PatchSet, marked for addition.
@@ -20,21 +40,10 @@ local function addAllToPatch(patchSet, virtualInstances, id)
end
end
function reifyInstance(deferredRefs, instanceMap, virtualInstances, rootId, parentInstance)
-- Create an empty patch that will be populated with any parts of this reify
-- that could not happen, like instances that couldn't be created and
-- properties that could not be assigned.
local unappliedPatch = PatchSet.newEmpty()
reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualInstances, rootId, parentInstance)
return unappliedPatch
end
--[[
Inner function that defines the core routine.
]]
function reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualInstances, id, parentInstance)
function reifyInner(instanceMap, virtualInstances, id, parentInstance, unappliedPatch, deferredRefs)
local virtualInstance = virtualInstances[id]
if virtualInstance == nil then
@@ -93,7 +102,7 @@ function reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualIn
end
for _, childId in ipairs(virtualInstance.Children) do
reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualInstances, childId, instance)
reifyInner(instanceMap, virtualInstances, childId, instance, unappliedPatch, deferredRefs)
end
instance.Parent = parentInstance
@@ -134,7 +143,6 @@ function applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
end
local targetInstance = instanceMap.fromIds[refId]
if targetInstance == nil then
markFailed(entry.id, entry.propertyName, entry.virtualValue)
continue
@@ -147,7 +155,4 @@ function applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
end
end
return {
reifyInstance = reifyInstance,
applyDeferredRefs = applyDeferredRefs,
}
return reify

View File

@@ -1,6 +1,5 @@
return function()
local reify = require(script.Parent.reify)
local reifyInstance, applyDeferredRefs = reify.reifyInstance, reify.applyDeferredRefs
local PatchSet = require(script.Parent.Parent.PatchSet)
local InstanceMap = require(script.Parent.Parent.InstanceMap)
@@ -21,11 +20,7 @@ return function()
it("should throw when given a bogus ID", function()
expect(function()
local deferredRefs = {}
local instanceMap = InstanceMap.new()
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, {}, "Hi, mom!", game)
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
reify(InstanceMap.new(), {}, "Hi, mom!", game)
end).to.throw()
end)
@@ -39,11 +34,8 @@ return function()
},
}
local deferredRefs = {}
local instanceMap = InstanceMap.new()
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT", nil)
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT", nil)
assert(instanceMap:size() == 0, "expected instanceMap to be empty")
@@ -68,11 +60,8 @@ return function()
},
}
local deferredRefs = {}
local instanceMap = InstanceMap.new()
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
@@ -101,11 +90,8 @@ return function()
},
}
local deferredRefs = {}
local instanceMap = InstanceMap.new()
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
@@ -136,11 +122,8 @@ return function()
},
}
local deferredRefs = {}
local instanceMap = InstanceMap.new()
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
expect(size(unappliedPatch.added)).to.equal(1)
expect(unappliedPatch.added["CHILD"]).to.equal(virtualInstances["CHILD"])
@@ -170,11 +153,8 @@ return function()
},
}
local deferredRefs = {}
local instanceMap = InstanceMap.new()
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
local instance = instanceMap.fromIds["ROOT"]
expect(instance.ClassName).to.equal("StringValue")
@@ -216,11 +196,8 @@ return function()
},
}
local deferredRefs = {}
local instanceMap = InstanceMap.new()
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
@@ -246,16 +223,13 @@ return function()
},
}
local deferredRefs = {}
local instanceMap = InstanceMap.new()
local existing = Instance.new("Folder")
existing.Name = "Existing"
instanceMap:insert("EXISTING", existing)
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
@@ -294,11 +268,8 @@ return function()
},
}
local deferredRefs = {}
local instanceMap = InstanceMap.new()
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
@@ -336,11 +307,8 @@ return function()
},
}
local deferredRefs = {}
local instanceMap = InstanceMap.new()
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
assert(PatchSet.isEmpty(unappliedPatch), "expected remaining patch to be empty")
@@ -364,11 +332,8 @@ return function()
},
}
local deferredRefs = {}
local instanceMap = InstanceMap.new()
local unappliedPatch = reifyInstance(deferredRefs, instanceMap, virtualInstances, "ROOT")
applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
local unappliedPatch = reify(instanceMap, virtualInstances, "ROOT")
assert(not PatchSet.hasRemoves(unappliedPatch), "expected no removes")
assert(not PatchSet.hasAdditions(unappliedPatch), "expected no additions")

4
plugin/test Normal file
View File

@@ -0,0 +1,4 @@
#!/bin/sh
rojo build test-place.project.json -o TestPlace.rbxlx
run-in-roblox --script run-tests.server.lua --place TestPlace.rbxlx

View File

@@ -5,7 +5,7 @@
"ReplicatedStorage": {
"Rojo": {
"$path": "../plugin.project.json"
"$path": "default.project.json"
},
"Packages": {

2
plugin/watch-build.sh Normal file
View File

@@ -0,0 +1,2 @@
# Continously build the rojo plugin into the local plugin directory on Windows
rojo build plugin/default.project.json -o $LOCALAPPDATA/Roblox/Plugins/Rojo.rbxm --watch

View File

@@ -6,7 +6,6 @@ expression: contents
<Item class="Model" referent="0">
<Properties>
<string name="Name">init_meta_class_name</string>
<bool name="NeedsPivotMigration">false</bool>
</Properties>
</Item>
</roblox>

View File

@@ -1,6 +1,7 @@
---
source: tests/tests/build.rs
expression: contents
---
<roblox version="4">
<Item class="Folder" referent="0">
@@ -24,7 +25,6 @@ expression: contents
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<bool name="NeedsPivotMigration">false</bool>
<Ref name="PrimaryPart">null</Ref>
<BinaryString name="Tags"></BinaryString>
</Properties>

View File

@@ -1,6 +1,7 @@
---
source: tests/tests/build.rs
expression: contents
---
<roblox version="4">
<Item class="DataModel" referent="0">
@@ -21,7 +22,6 @@ expression: contents
<Item class="Workspace" referent="2">
<Properties>
<string name="Name">Workspace</string>
<bool name="NeedsPivotMigration">false</bool>
</Properties>
<Item class="BoolValue" referent="3">
<Properties>

View File

@@ -1,6 +1,7 @@
---
source: tests/tests/serve.rs
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
gameId: ~
@@ -10,4 +11,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,6 +1,7 @@
---
source: tests/tests/serve.rs
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
gameId: ~
@@ -10,4 +11,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,6 +1,7 @@
---
source: tests/tests/serve.rs
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
gameId: ~
@@ -10,4 +11,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,6 +1,7 @@
---
source: tests/tests/serve.rs
expression: "read_response.intern_and_redact(&mut redactions, root_id)"
---
instances:
id-2:
@@ -21,8 +22,7 @@ instances:
ignoreUnknownInstances: false
Name: test
Parent: id-2
Properties:
NeedsPivotMigration:
Bool: false
Properties: {}
messageCursor: 1
sessionId: id-1

View File

@@ -1,6 +1,7 @@
---
source: tests/tests/serve.rs
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
gameId: ~
@@ -10,4 +11,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,6 +1,7 @@
---
source: tests/tests/serve.rs
expression: "subscribe_response.intern_and_redact(&mut redactions, ())"
---
messageCursor: 1
messages:
@@ -13,9 +14,8 @@ messages:
ignoreUnknownInstances: false
Name: test
Parent: id-2
Properties:
NeedsPivotMigration:
Bool: false
Properties: {}
removed: []
updated: []
sessionId: id-1

View File

@@ -1,64 +0,0 @@
---
source: tests/tests/serve.rs
expression: "read_response.intern_and_redact(&mut redactions, root_id)"
---
instances:
id-2:
Children:
- id-3
ClassName: DataModel
Id: id-2
Metadata:
ignoreUnknownInstances: true
Name: pivot_migration
Parent: "00000000000000000000000000000000"
Properties: {}
id-3:
Children:
- id-4
- id-5
- id-6
ClassName: Workspace
Id: id-3
Metadata:
ignoreUnknownInstances: true
Name: Workspace
Parent: id-2
Properties:
NeedsPivotMigration:
Bool: false
id-4:
Children: []
ClassName: Model
Id: id-4
Metadata:
ignoreUnknownInstances: true
Name: Model
Parent: id-3
Properties:
NeedsPivotMigration:
Bool: false
id-5:
Children: []
ClassName: Tool
Id: id-5
Metadata:
ignoreUnknownInstances: false
Name: Tool
Parent: id-3
Properties:
NeedsPivotMigration:
Bool: false
id-6:
Children: []
ClassName: Actor
Id: id-6
Metadata:
ignoreUnknownInstances: true
Name: Actor
Parent: id-3
Properties:
NeedsPivotMigration:
Bool: false
messageCursor: 1
sessionId: id-1

View File

@@ -1,27 +0,0 @@
---
source: tests/tests/serve.rs
expression: "subscribe_response.intern_and_redact(&mut redactions, ())"
---
messageCursor: 1
messages:
- added:
id-6:
Children: []
ClassName: Actor
Id: id-6
Metadata:
ignoreUnknownInstances: true
Name: Actor
Parent: id-3
Properties:
NeedsPivotMigration:
Bool: false
removed: []
updated:
- changedClassName: ~
changedMetadata:
ignoreUnknownInstances: true
changedName: ~
changedProperties: {}
id: id-3
sessionId: id-1

View File

@@ -1,6 +1,7 @@
---
source: tests/tests/serve.rs
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
gameId: ~
@@ -10,4 +11,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,5 +1,6 @@
---
source: tests/tests/serve.rs
assertion_line: 316
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
@@ -10,4 +11,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,5 +1,6 @@
---
source: tests/tests/serve.rs
assertion_line: 335
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
@@ -10,4 +11,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,5 +1,6 @@
---
source: tests/tests/serve.rs
assertion_line: 351
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
@@ -10,4 +11,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,52 +0,0 @@
---
source: tests/tests/serve.rs
expression: "read_response.intern_and_redact(&mut redactions, root_id)"
---
instances:
id-2:
Children:
- id-3
ClassName: DataModel
Id: id-2
Metadata:
ignoreUnknownInstances: true
Name: pivot_migration
Parent: "00000000000000000000000000000000"
Properties: {}
id-3:
Children:
- id-4
- id-5
ClassName: Workspace
Id: id-3
Metadata:
ignoreUnknownInstances: true
Name: Workspace
Parent: id-2
Properties:
NeedsPivotMigration:
Bool: false
id-4:
Children: []
ClassName: Model
Id: id-4
Metadata:
ignoreUnknownInstances: true
Name: Model
Parent: id-3
Properties:
NeedsPivotMigration:
Bool: false
id-5:
Children: []
ClassName: Tool
Id: id-5
Metadata:
ignoreUnknownInstances: false
Name: Tool
Parent: id-3
Properties:
NeedsPivotMigration:
Bool: false
messageCursor: 0
sessionId: id-1

View File

@@ -1,13 +0,0 @@
---
source: tests/tests/serve.rs
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
gameId: ~
placeId: ~
projectName: pivot_migration
protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -31,8 +31,6 @@ instances:
Attributes:
Rojo_Target_PrimaryPart:
String: project target
NeedsPivotMigration:
Bool: false
PrimaryPart:
Ref: id-9
id-2:
@@ -57,9 +55,7 @@ instances:
ignoreUnknownInstances: true
Name: Workspace
Parent: id-2
Properties:
NeedsPivotMigration:
Bool: false
Properties: {}
id-4:
Children: []
ClassName: ObjectValue
@@ -128,8 +124,6 @@ instances:
Attributes:
Rojo_Target_PrimaryPart:
String: model target 2
NeedsPivotMigration:
Bool: false
PrimaryPart:
Ref: id-7
id-9:
@@ -144,3 +138,4 @@ instances:
Properties: {}
messageCursor: 1
sessionId: id-1

View File

@@ -40,9 +40,7 @@ instances:
ignoreUnknownInstances: true
Name: Workspace
Parent: id-2
Properties:
NeedsPivotMigration:
Bool: false
Properties: {}
id-4:
Children: []
ClassName: ObjectValue
@@ -106,8 +104,6 @@ instances:
Attributes:
Rojo_Target_PrimaryPart:
String: model target
NeedsPivotMigration:
Bool: false
PrimaryPart:
Ref: id-7
id-9:
@@ -122,3 +118,4 @@ instances:
Properties: {}
messageCursor: 0
sessionId: id-1

View File

@@ -10,4 +10,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -40,9 +40,7 @@ instances:
ignoreUnknownInstances: true
Name: Workspace
Parent: id-2
Properties:
NeedsPivotMigration:
Bool: false
Properties: {}
id-4:
Children: []
ClassName: ObjectValue
@@ -106,12 +104,8 @@ instances:
Attributes:
Rojo_Target_PrimaryPart:
String: model target
NeedsPivotMigration:
Bool: false
PrimaryPart:
Ref: id-7
Scale:
Float32: 1
id-9:
Children:
- id-10
@@ -122,5 +116,5 @@ instances:
Name: ProjectTarget
Parent: id-3
Properties: {}
messageCursor: 1
messageCursor: 0
sessionId: id-1

View File

@@ -40,9 +40,7 @@ instances:
ignoreUnknownInstances: true
Name: Workspace
Parent: id-2
Properties:
NeedsPivotMigration:
Bool: false
Properties: {}
id-4:
Children: []
ClassName: ObjectValue
@@ -106,8 +104,6 @@ instances:
Attributes:
Rojo_Target_PrimaryPart:
String: model target
NeedsPivotMigration:
Bool: false
PrimaryPart:
Ref: id-7
id-9:

View File

@@ -10,4 +10,3 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,17 +0,0 @@
---
source: tests/tests/serve.rs
expression: "subscribe_response.intern_and_redact(&mut redactions, ())"
---
messageCursor: 1
messages:
- added: {}
removed: []
updated:
- changedClassName: ~
changedMetadata: ~
changedName: ~
changedProperties:
Scale:
Float32: 1
id: id-8
sessionId: id-1

View File

@@ -10,4 +10,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -18,8 +18,6 @@ messages:
Attributes:
Rojo_Target_PrimaryPart:
String: project target
NeedsPivotMigration:
Bool: false
PrimaryPart:
Ref: id-9
removed: []
@@ -45,3 +43,4 @@ messages:
PrimaryPart: ~
id: id-8
sessionId: id-1

View File

@@ -1,6 +1,7 @@
---
source: tests/tests/serve.rs
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
gameId: ~
@@ -10,4 +11,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,6 +1,7 @@
---
source: tests/tests/serve.rs
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
gameId: ~
@@ -10,4 +11,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,5 +1,6 @@
---
source: tests/tests/serve.rs
assertion_line: 265
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
@@ -10,4 +11,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,5 +1,6 @@
---
source: tests/tests/serve.rs
assertion_line: 281
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
@@ -10,4 +11,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,5 +1,6 @@
---
source: tests/tests/serve.rs
assertion_line: 297
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
@@ -10,4 +11,4 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,5 +1,6 @@
---
source: tests/tests/serve.rs
assertion_line: 383
expression: redactions.redacted_yaml(info)
---
expectedPlaceIds: ~
@@ -10,4 +11,3 @@ protocolVersion: 4
rootInstanceId: id-2
serverVersion: "[server-version]"
sessionId: id-1
unexpectedPlaceIds: ~

View File

@@ -1,3 +0,0 @@
{
"className": "Tool"
}

View File

@@ -1,14 +0,0 @@
{
"name": "pivot_migration",
"tree": {
"$className": "DataModel",
"Workspace": {
"Model": {
"$className": "Model"
},
"Tool": {
"$path": "Tool.model.json"
}
}
}
}

View File

@@ -1,2 +0,0 @@
rojo build plugin/test-place.project.json -o TestPlace.rbxl
run-in-roblox --script plugin/run-tests.server.lua --place TestPlace.rbxl

View File

@@ -1 +0,0 @@
rojo build plugin.project.json --plugin Rojo.rbxm --watch

View File

@@ -136,7 +136,7 @@ impl JobThreadContext {
// created all at once.
let mut current_path = path.as_path();
let affected_ids = loop {
let ids = tree.get_ids_at_path(current_path);
let ids = tree.get_ids_at_path(&current_path);
log::trace!("Path {} affects IDs {:?}", current_path.display(), ids);

View File

@@ -23,7 +23,7 @@ const UNKNOWN_PLUGIN_KIND_ERR: &str = "Could not detect what kind of file to bui
/// Generates a model or place file from the Rojo project.
#[derive(Debug, Parser)]
pub struct BuildCommand {
/// Path to the project to build. Defaults to the current directory.
/// Path to the project to serve. Defaults to the current directory.
#[clap(default_value = "")]
pub project: PathBuf,

View File

@@ -8,7 +8,7 @@ use clap::Parser;
use fs_err::File;
use memofs::Vfs;
use rayon::prelude::*;
use rbx_dom_weak::{types::Ref, Ustr};
use rbx_dom_weak::types::Ref;
use serde::Serialize;
use tokio::runtime::Runtime;
@@ -26,7 +26,7 @@ const PATH_STRIP_FAILED_ERR: &str = "Failed to create relative paths for project
#[serde(rename_all = "camelCase")]
struct SourcemapNode<'a> {
name: &'a str,
class_name: Ustr,
class_name: &'a str,
#[serde(skip_serializing_if = "Vec::is_empty")]
file_paths: Vec<PathBuf>,
@@ -67,7 +67,7 @@ impl SourcemapCommand {
let vfs = Vfs::new_default();
vfs.set_watch_enabled(self.watch);
let session = ServeSession::new(vfs, project_path)?;
let session = ServeSession::new(vfs, &project_path)?;
let mut cursor = session.message_queue().cursor();
let filter = if self.include_non_scripts {
@@ -113,7 +113,7 @@ fn filter_nothing(_instance: &InstanceWithMeta) -> bool {
fn filter_non_scripts(instance: &InstanceWithMeta) -> bool {
matches!(
instance.class_name().as_str(),
instance.class_name(),
"Script" | "LocalScript" | "ModuleScript"
)
}

View File

@@ -22,7 +22,6 @@ trait FmtLua {
}
}
#[allow(dead_code)]
struct DisplayLua<T>(T);
impl<T> fmt::Display for DisplayLua<T>

Some files were not shown because too many files have changed in this diff Show More