Compare commits

...

483 Commits

Author SHA1 Message Date
Lucien Greathouse
eddbe7d0cf Release 6.0.0-rc.4 2020-12-14 14:15:09 -08:00
Lucien Greathouse
faf86d006a Remove outdated warning from Rojo 0.5.0 alpha 14 2020-12-14 13:16:34 -08:00
Lucien Greathouse
71e4dfeb14 Change logo to be brand color on dark theme 2020-12-14 12:59:53 -08:00
Lucien Greathouse
da8ed6ddf9 Update Changelog 2020-12-14 11:22:43 -08:00
Lucien Greathouse
503e687c55 Fix repository link 2020-12-14 11:20:28 -08:00
Lucien Greathouse
dd667cce0b Add images from plugin rewrite 2020-12-14 11:20:07 -08:00
Lucien Greathouse
f911009752 Remove clibrojo, as it's broken 2020-12-14 11:13:44 -08:00
Reselim
cae4c46669 New UI (#367)
* Add Flipper

* Remove old UI

* Add boilerplate UI

* Change plugin version

* Merge upstream

* Bunch of new UI changes

Too lazy to list them all in individual commits

* Touch ripple for buttons and a few other things

* Make the close button on the PluginGui work

* Set button state to guiEnabled

* Implement Connecting, NotConnected; add Header; don't update plugin button on render

* Replace mapLerpColor with mapLerp

* Update blendAlpha to be 0 without any values

* Add ActionFillTransparency to Theme.Button

* Suffix all Theme entries

* Update Flipper

* Add disconnect button

* Remove cancel button

* Add settings page

* Add scrollbar and dark theme support to settings

* Include settings in startSession

* Set context default value to nil

I always thought this was the name, lol...

* Add Error page

* Fix preloadAssets

* Fix preloadAssets import

* Update checkbox colors a little

* Add setting descriptions

* Fix scrolling frame in settings panel

* Remove .vscode

* Rename Throbber to Spinner

* Update merge

* Move Spinner images to assets

* Change casing of directories

* Remove old directories

* Add comments to getDerivedStateFromProps

* Account for offset in host TextBox size

* Turn width variables into constants

* Attempt to fix the comments

* Add a missing comma in Settings

* Remove a double space

* Remove Dummy object

* Move most of the Studio logic out of render

* Don't truncate port input

* Replace merge with Dictionary.merge

* Replace "Got it!" with "Okay"

* Add projectName to setStatus call

* Add Flipper to build.rs
2020-12-14 11:07:39 -08:00
Lucien Greathouse
a937fc38db Update Changelog 2020-12-14 10:22:45 -08:00
Lucien Greathouse
ff43ffce07 Update to insta 1.3.0 2020-12-14 10:22:40 -08:00
Lucien Greathouse
5bb3dc258a Add projectName to serve output 2020-12-14 10:17:52 -08:00
Lucien Greathouse
98238e4516 Fix longstanding message_queue warning 2020-12-14 10:12:51 -08:00
Lucien Greathouse
23b8308282 Fix lockfile not being updated for 6.0.0-rc.3 2020-11-19 11:50:06 -08:00
Lucien Greathouse
a1f7cdc2b6 Release 6.0.0-rc.3 2020-11-19 11:47:07 -08:00
Lucien Greathouse
dcb30351c5 Fix null referent handling 2020-11-19 11:44:53 -08:00
Lucien Greathouse
1c0dc60071 Update CHANGELOG 2020-11-19 11:31:46 -08:00
Lucien Greathouse
0401c3ac0e Mark HttpEnabled as not scriptable as well 2020-11-19 11:20:30 -08:00
Lucien Greathouse
3b800d1cd7 Patch ReflectionDatabase to turn off SourceAssetId 2020-11-19 11:06:03 -08:00
Lucien Greathouse
35efb464e5 Fix incorrect tag in CHANGELOG 2020-11-19 10:33:09 -08:00
Lucien Greathouse
19a955a327 Release memofs 0.1.3 2020-11-19 10:26:37 -08:00
Lucien Greathouse
836b18e68a Release 6.0.0-rc.2 2020-11-19 10:25:25 -08:00
Lucien Greathouse
046dc0d598 plugin: Fix grammar in comments a bit :) 2020-11-16 11:49:30 -08:00
Lucien Greathouse
039d92ce78 plugin: Support ClassName changes in applyPatch 2020-11-16 11:44:56 -08:00
Lucien Greathouse
2136da15d6 plugin: Ensure InstanceMap deletes existing entries before inserting 2020-11-16 11:44:39 -08:00
Lucien Greathouse
e5041d80ef plugin: Fix warning in applyPatch.lua 2020-11-11 17:11:34 -08:00
Lucien Greathouse
f66860bdfe Break apart plugin reconciler (#332)
* Start splitting apart reconciler, with tests

* Reify children in reify

* Baseline hydrate implementation

* Remove debug print

* Scaffold out diff implementation, just supporting name changes

* invariant -> error in decodeValue

* Flesh out diff and add getProperty

* Clear out top-level reconciler interface, start updating code that touches it

* Address review feedback

* Add (experimental) Selene configuration

* Add emptiness checks to PatchSet, remove unimplement invert method

* Improve descendant destruction behavior in InstanceMap

* Track instanceId on all reify errors

* Base implementation of applyPatch, returning partial patches on failure

* Change reify to accept InstanceMap and insert instances into it

* Start testing applyPatch for removals

* Add test for applyPatch adding instances successfully and not

* Add , which is just error with formatting

* Correctly use new diff and applyPatch APIs

* Improve applyPatch logging and fix field name typo

* Better debug output when reify fails

* Print out unapplied patch in debug mode

* Don't write properties if their values are not different.

This was exposed trying to sync the Rojo plugin, which
has a gigantic ModuleScript in it with the reflection
database. This workaround was present in some form in
many versions of Rojo, and I guess we still need it.

This time, I actually documented why it's here so that
I don't forget for the umpteenth time...

* Add placeholder test that needs to happen still

* Introduce easier plugin testing, write applyPatch properties test

* Delete legacy get/setCanonicalProperty files

* Fix trying to remove numbers instead of instances

* Change applyPatch to return partial patches instead of binary success

* Work towards being able to decode and apply refs

* Add helpers for PatchSet assertions

* Apply refs in reify, test all cases

* Improve diagnostics when patches fail to apply

* Stop logging when destroying untracked instances, it's ok

* Remove read before setting property in applyPatch

* Fix diff thinking all properties are changed
2020-11-11 16:30:23 -08:00
Lucien Greathouse
50f0a2bd2e Update CLI dependencies 2020-10-29 10:36:20 -07:00
Lucien Greathouse
7cd9bd383e Update to latest reflection database 2020-10-29 10:35:55 -07:00
Lucien Greathouse
45a20a1633 Remove outdated notices 2020-09-09 17:39:24 -07:00
Lucien Greathouse
ec5b3f80ef Fix theme component error regression 2020-07-03 12:21:49 -07:00
Lucien Greathouse
3b257ea87a Update repo references after Roblox move 2020-06-23 11:55:46 -07:00
Lucien Greathouse
6b82cead9c Move from rojo-rbx org to Roblox org 2020-06-22 14:14:42 -07:00
cliffchapmanrbx
79ae4c52cd Enable CLA bot (#333) 2020-06-22 14:11:53 -07:00
Lucien Greathouse
a4616cda7d Fix test place's CharacterAutoLoads value 2020-06-20 22:16:35 -07:00
Lucien Greathouse
95648361be Recreate test place, just running in Studio 2020-06-20 21:51:26 -07:00
Lucien Greathouse
0c41e9c10b Depend on latest Rojo release from Rojo 2020-06-20 21:50:25 -07:00
Lucien Greathouse
61c7ef3cb0 plugin: lazily access settings() to help with testing 2020-06-20 21:50:14 -07:00
Lucien Greathouse
65898125d0 Update changelog 2020-06-17 23:14:24 -07:00
Lucien Greathouse
da05078ff3 Load project file from VFS instead of through fs.
Fixes #320.

Previously, the root project file was loaded via methods on Project
(which do not know about the VFS) instead of through the VFS like
all other disk access.

This meant that Rojo was unable to build its own plugin because
there is no project file on the real disk, only in the VFS.
2020-06-17 23:13:29 -07:00
Lucien Greathouse
badb5c3636 Stop redundantly adding ignore paths when starting ServeSession 2020-06-17 22:54:35 -07:00
Lucien Greathouse
9453588ab1 Load built-in plugin from absolute path to make errors more apparent 2020-06-17 22:54:13 -07:00
Lucien Greathouse
4cbb3874a4 Use anyhow error reporting instead of custom 2020-06-17 14:56:09 -07:00
Lucien Greathouse
940aff7ef4 Enable globIgnorePaths by default 2020-06-17 14:42:46 -07:00
Lucien Greathouse
a3edb93273 Update Changelog 2020-06-17 14:38:39 -07:00
Lucien Greathouse
782b054b1a Pass build watch argument into Vfs 2020-06-17 14:11:48 -07:00
Lucien Greathouse
fc27b2911e Allow turning off file watching in memofs.
Also preemptively bumping version to 0.1.3 so I don't forget on next release
2020-06-17 14:06:44 -07:00
Lucien Greathouse
486b067567 Flatten snapshot middleware to be much simpler (#324)
* First take at flattening middleware for simpler code and better perf

* Undo debug prints

* Fix using wrong path in snapshot_from_vfs

* Disable some broken tests

* Re-enable (mistakenly?) disabled CSV test

* Fix some tests

* Update project file tests

* Fix benchmark
2020-06-17 13:47:09 -07:00
Lucien Greathouse
bdd1afea57 Run CI on master and PRs to master only 2020-05-20 15:30:44 -07:00
Lucien Greathouse
5ccd02939b Replace rojo-test with regular tests folder again (#323)
* Replace rojo-test with regular tests folder again

* Bump MSRV to 1.43.1
2020-05-20 15:30:05 -07:00
Lucien Greathouse
ca5b8ab309 Restore improperly tested dependency on rojo from rojo-test 2020-05-20 11:56:34 -07:00
Lucien Greathouse
9481fdd38d Add missing Cargo.lock change 2020-05-02 21:47:36 -07:00
Lucien Greathouse
56bf6d282b Stop building Rojo in rojo-test, since it doesn't work as intended 2020-05-02 21:39:13 -07:00
Lucien Greathouse
5364c9c1bc Fix Lua string escaping.
Closes #314.
2020-04-16 12:00:02 -07:00
Lucien Greathouse
a4d4beeb97 Update default place template 2020-03-30 11:34:41 -07:00
Lucien Greathouse
30a01381be Fix malformed CSV files causing crashes; fixes #310 2020-03-30 11:12:20 -07:00
Lucien Greathouse
def99a9e4d Update release job to fix 6.0.0 release 2020-03-29 17:09:52 -07:00
Lucien Greathouse
1214fc8b0d Release 6.0.0-rc.1
This change also includes some minor packaging changes in order to make Cargo happy.
2020-03-29 16:58:37 -07:00
Lucien Greathouse
5a5b1268d3 Update changelog 2020-03-29 16:03:58 -07:00
jeparlefrancais
6a1fffd1ce Infer class name (#210)
* infer service names

* Update project code and add support for StarterPlayer

* Store parent_class in InstigatingSource

* Update snapshots

Co-authored-by: Lucien Greathouse <me@lpghatguy.com>
2020-03-29 16:03:15 -07:00
Lucien Greathouse
571ef3060a Update Changelog 2020-03-29 13:46:27 -07:00
jeparlefrancais
3cf82e112f Install plugin from CLI (#304)
* add install command

* cargo fmt

* filter spec files

* Update src/cli/plugin.rs

Co-Authored-By: Lucien Greathouse <me@lpghatguy.com>

* Update src/cli/plugin.rs

Co-Authored-By: Lucien Greathouse <me@lpghatguy.com>

* fix comments

* encode plugin with rbx_binary

* update build script

* refactor pathbuf error into io error

* fix rojo typo

* remove snafu

* Update `snapshot_from_fs_path`

* Print `rerun-if-changed` even for directories, in order to run the
  build.rs script when files are added.

* Switch `filter_map` loop to a regular for loop. I like the FP-style
  iterator stuff in Rust, but I think Result handling is easier in a
  normal loop. Also, I don't believe the result of read_dir implements
  `ExactSizedIterator`, so some of the wins of map+collect aren't there.

* Replace Result::unwrap with ? in build.rs

* Simplify error handling code in runtime

* Checkout with submodules

Co-authored-by: Lucien Greathouse <me@lpghatguy.com>
2020-03-29 13:41:54 -07:00
Lucien Greathouse
9b459c20d6 Fix GHA only running on pushes to master 2020-03-29 13:17:06 -07:00
Lucien Greathouse
5c85cd27c3 Fix default place project.
Closes #311.
2020-03-29 12:21:55 -07:00
Lucien Greathouse
4bf73c7a8a Implement support for turning .json files into Lua modules (#308)
* Stub implementation

* Flesh out feature and add tests. Other snapshots currently failing.

* Blacklist .meta.json in JSON handler

* Write to correct property (Source) instead of Value

* Update changelog
2020-03-28 00:36:01 -07:00
Lucien Greathouse
62e51b7535 Upgrade to latest rbx-dom 2020-03-27 23:58:31 -07:00
Lucien Greathouse
729a7f0053 Turn panics into errors in ServeSession 2020-03-26 12:16:55 -07:00
Lucien Greathouse
03c297190d Make ServeSession::new fallible 2020-03-26 12:07:44 -07:00
Lucien Greathouse
9c790eddd7 Tidy up ServeSession now that trait bounds are gone 2020-03-26 12:06:16 -07:00
Lucien Greathouse
8ebe7e332b Update Changelog 2020-03-25 17:02:32 -07:00
Lucien Greathouse
f43777e37e Require a Rojo project again (#307) 2020-03-25 17:01:28 -07:00
Lucien Greathouse
691a8fcdeb Upgrade lockfile using latest rustc 2020-03-25 16:15:21 -07:00
Lucien Greathouse
69c0e8d70e Fix warnings 2020-03-21 17:49:56 -07:00
Lucien Greathouse
330c92c9a8 Refactor ChangeProcessor loop to get rid of panics 2020-03-21 17:47:25 -07:00
Lucien Greathouse
cf0ff60d31 plugin: Add simple signal implementation for future work 2020-03-18 23:31:22 -07:00
Lucien Greathouse
9e9cf5dd1f plugin: Add support for pausing updates tracked by InstanceMap 2020-03-18 23:27:30 -07:00
Lucien Greathouse
5768d8e4a4 plugin: Miscellaneous cleanup 2020-03-18 23:15:03 -07:00
Lucien Greathouse
3b433e53be Memofs v0.1.1 2020-03-18 18:35:44 -07:00
Lucien Greathouse
28ddf40344 memofs: Update fs-err and use it more 2020-03-18 18:06:58 -07:00
Lucien Greathouse
c1286db9c1 Update Changelog 2020-03-18 16:26:41 -07:00
Lucien Greathouse
f13940262e Update CHANGELOG 2020-03-18 12:03:50 -07:00
Lucien Greathouse
9f0a6101b8 Add configurable color options 2020-03-18 12:03:07 -07:00
Lucien Greathouse
0b0fe01a7c Tidy up root repository files 2020-03-18 11:40:12 -07:00
Lucien Greathouse
85e098d5c8 Update README 2020-03-18 11:36:50 -07:00
Lucien Greathouse
e8d1faf4e2 Update changelog 2020-03-18 10:43:42 -07:00
Lucien Greathouse
2a46df1110 Expose two-way sync.
- Convert plugin DevSettings flag to settings panel feature
- Remove server feature, always enable write API
2020-03-18 10:39:40 -07:00
Lucien Greathouse
1601e6d26e Update changelog 2020-03-17 23:20:40 -07:00
Lucien Greathouse
0e4f6dea2b plugin: Add setting for opening scripts externally 2020-03-17 23:20:05 -07:00
Lucien Greathouse
a2356773dc Add checkbox and fill out settings panel 2020-03-17 23:14:32 -07:00
Lucien Greathouse
4a4da4737d Fix plugin settings persistent 2020-03-17 23:03:59 -07:00
Lucien Greathouse
2cefd1bf2e plugin: Add PluginSettings context item, render it in settings screen 2020-03-17 23:03:01 -07:00
Lucien Greathouse
c5ce15fe34 plugin: Add dummy settings panel 2020-03-17 22:38:53 -07:00
Lucien Greathouse
76dea568c9 Update changelog 2020-03-17 22:30:00 -07:00
Lucien Greathouse
8e81140eff Increase verbosity of logging 2020-03-17 22:29:23 -07:00
Lucien Greathouse
d58e1f0792 Add logging when running rojo build 2020-03-17 22:28:38 -07:00
Lucien Greathouse
830c242751 plugin: Stop using codename in dev mode 2020-03-17 22:25:04 -07:00
Lucien Greathouse
91d45afd0f Add plugin feature 'UnstableOpenScriptsExternally' 2020-03-17 18:13:52 -07:00
Lucien Greathouse
102c77b23e Implement /api/open/{id} to open a script by ID in your default editor 2020-03-17 17:50:54 -07:00
Lucien Greathouse
aa4039a2e7 bye snafu 2020-03-16 23:37:00 -07:00
Lucien Greathouse
c065ded440 Tidy up SnapshotError a lot 2020-03-16 21:35:46 -07:00
Lucien Greathouse
f69096dadb Use thiserror and anyhow for command-level error types 2020-03-16 21:13:38 -07:00
Lucien Greathouse
363f95ba14 memofs: Use fs_err instead of std::fs when possible 2020-03-16 20:35:58 -07:00
Lucien Greathouse
dcc15e8911 Refactor upload to use ServeSession and drop common_setup 2020-03-16 20:20:12 -07:00
Lucien Greathouse
bd13047b58 Release 0.6.0-alpha.3 2020-03-13 23:50:54 -07:00
Lucien Greathouse
1a83789c01 Update Changelog 2020-03-13 20:50:03 -07:00
Lucien Greathouse
1cbe272e19 Fix malformed meta files causing panics.
Fixes #280.
2020-03-13 20:38:06 -07:00
Lucien Greathouse
6de74b41b3 Update snapshot error type and handle serde_json errors in JSON models 2020-03-13 20:31:31 -07:00
Lucien Greathouse
b0fc9ee507 Rename 'src/common' in default place template to 'src/shared' 2020-03-13 20:25:50 -07:00
Lucien Greathouse
a95ffe1d31 Add snapshot error handling to ChangeProcessor 2020-03-13 20:24:14 -07:00
Lucien Greathouse
4119a510f5 Fix broken error source tracking 2020-03-13 20:12:42 -07:00
Lucien Greathouse
cfa7f03815 Add help link to default model project 2020-03-13 20:11:08 -07:00
Lucien Greathouse
9b4c89820d Fix extra Git output in rojo init and update place template 2020-03-13 20:10:31 -07:00
Lucien Greathouse
fe874720aa Upgrade rojo init to create README.md and create Git repo 2020-03-13 20:00:48 -07:00
Lucien Greathouse
f7c0f33eb5 Add brand new rojo init command 2020-03-13 19:33:43 -07:00
Lucien Greathouse
c1bf9d9dfc Update duplicate env_logger dep 2020-03-12 19:39:27 -07:00
Lucien Greathouse
255bf439d3 Add 'rojo doc' command 2020-03-12 16:02:19 -07:00
Lucien Greathouse
2a31937b81 Use CARGO_PKG_REPOSITORY instead of hard-coded URL 2020-03-12 15:48:30 -07:00
Lucien Greathouse
eb8964e1d1 Improve panic messaging and process behavior.
- Replaced main() to use custom panic hook
- Updated log formatting
- Switched to panic=abort, since we don't need to unwind now.
- Process will now abort if any thread panics.
2020-03-12 15:42:56 -07:00
Lucien Greathouse
fe0ca280a1 Update disabled CSV middleware test 2020-03-10 23:52:55 -07:00
Lucien Greathouse
e8e3b7b985 plugin: Fix dark theme when resized to be wide 2020-03-10 20:34:12 -07:00
Lucien Greathouse
c437507442 Update changelogs 2020-03-10 18:15:06 -07:00
Lucien Greathouse
ca151b434e Update memofs dependency 2020-03-10 18:13:34 -07:00
Lucien Greathouse
10ba74c21e memofs: Add description 2020-03-10 18:11:39 -07:00
Lucien Greathouse
6191b6371d Update using cargo-readme 2020-03-10 18:09:04 -07:00
Lucien Greathouse
5be4175ac3 Rename vfs -> memofs across the codebase 2020-03-10 18:05:31 -07:00
Lucien Greathouse
f61f3671a6 Choose 'memofs' as the vfs name 2020-03-10 17:57:57 -07:00
Lucien Greathouse
477e0ada32 VFS in external crate (#297)
* vroom

* Port dir middleware

* Filter rules

* Directory metadata

* Project support

* Enable Lua support

* StringValue support

* CSV

* rbxm, rbxmx, and rbxlx

* JSON models

* Clean up some warnings

* Strip out PathMap

* Unwatch paths when they're reported as removed

* Fix 'rojo upload' behavior

* Upgrade to Insta 0.13.1

* Update dependencies

* Release 0.6.0-alpha.2

* Fix bad merge

* Replace MemoryBackend with InMemoryFs

* Sledgehammer tests into passing for now

* Txt middleware

* Update easy snapshot tests

* Lua tests

* Project middleware tests

* Try to fix test failures by sorting

* Port first set of serve session tests

* Add InMemoryFs::raise_event

* Finish porting serve session tests

* Remove UI code for introspecting VFS for now

* VFS docs
2020-03-10 17:38:49 -07:00
Lucien Greathouse
a884f693ae Update changelog 2020-03-08 18:34:11 -07:00
Lucien Greathouse
3107b1b21b Dynamic theming. Closes #241.
Upgrades to Roact master and introduces dynamic theme switching.

We branch on the theme name in order to try to use Rojo's brand
colors instead of Studio's. I kind of winged it with these colors
and we might want to choose slightly nicer dark theme colors
in the future.

I also took the opportunity to reorganize the color naming scheme
since it didn't really work for dark theme.
2020-03-08 18:32:42 -07:00
Lucien Greathouse
04529de7b3 Update Changelog 2020-03-08 17:48:50 -07:00
Lucien Greathouse
199a39208c Implement 'rojo build --watch' (#284)
* Refactor build command to reproduce model more easily

* Spawn ServeSession for building
2020-03-08 17:48:14 -07:00
Lucien Greathouse
0187da5f24 Release 0.6.0-alpha.2 2020-03-06 13:56:21 -08:00
Lucien Greathouse
2e1c37ffff Update dependencies 2020-03-06 13:54:04 -08:00
Lucien Greathouse
4b0189dd55 Upgrade to Insta 0.13.1 2020-03-06 13:52:23 -08:00
Lucien Greathouse
d4a39674de Fix 'rojo upload' behavior 2020-03-06 13:23:49 -08:00
Lucien Greathouse
07c6fd3711 Update docs repo link 2020-03-04 15:00:10 -08:00
Lucien Greathouse
cf5b72aa9a Docs have moved to https://github.com/rojo-rbx/rojo.space 2020-02-27 22:57:06 -08:00
Lucien Greathouse
cdfbebd637 Update changelog for 0.5.4 release 2020-02-27 10:29:41 -08:00
Lucien Greathouse
e86e3316a9 Update changelog to include 0.5.x versions 2020-02-26 17:56:33 -08:00
Lucien Greathouse
bb2dcbaea0 vfs: Flesh out MemoryBackend 2020-02-21 23:52:11 -08:00
Lucien Greathouse
fefc7a69cd vfs: Expand documentation 2020-02-21 23:34:56 -08:00
Lucien Greathouse
1b24cd36e0 vfs: Snapshots, roughly 2020-02-19 23:58:09 -08:00
Lucien Greathouse
6322c1f46d vfs: Add stub MemoryBackend 2020-02-19 23:35:45 -08:00
Lucien Greathouse
00a29bb6be Unwatch paths when they're reported as removed 2020-02-19 23:34:57 -08:00
Lucien Greathouse
3a029caf2b Bump MSRV to 1.40.0 2020-02-19 23:22:51 -08:00
Lucien Greathouse
57263905e7 Add IoResultExt, fix mutability and Send-ness 2020-02-19 10:11:43 -08:00
Lucien Greathouse
4f46012c11 Complete an unfinished 2020-02-19 09:49:18 -08:00
Lucien Greathouse
7ea9a1e3e8 Expose metadata, remove_file, and remove_dir_all 2020-02-19 09:43:39 -08:00
Lucien Greathouse
c7510e12c4 Removal API 2020-02-19 09:39:49 -08:00
Lucien Greathouse
89b5d9294c Event receiving/committing infrastructure 2020-02-19 09:36:38 -08:00
Lucien Greathouse
339e1060b7 Clean up Vfs methods that defer to VfsLock 2020-02-19 09:17:21 -08:00
Lucien Greathouse
52e1dbd846 Flesh out crate 2020-02-18 23:16:56 -08:00
Lucien Greathouse
b4963f4ff7 Watching 2020-02-18 22:42:31 -08:00
Lucien Greathouse
838e8f6bde VFS crate 2020-02-18 22:30:12 -08:00
Lucien Greathouse
8f21514855 two-way-sync: Add super special case script syncing 2020-02-18 18:19:08 -08:00
Lucien Greathouse
44041f33e3 Start trying to sync parenting-to-nil (deleting) 2020-02-14 18:29:43 -08:00
Lucien Greathouse
5d9bc4473c two-way-sync: Track Parent property for value objects 2020-02-14 18:25:54 -08:00
Lucien Greathouse
a3e0d42e86 two-way-sync: Handle deleting non-project node files.
This is the tiniest step towards this feature and not even
very useful, but an important proof of concept.
2020-02-14 18:24:03 -08:00
Lucien Greathouse
4a9c1d0d1b two-way sync: allow changedProperties to be null to avoid array/object issues 2020-02-14 18:15:18 -08:00
Lucien Greathouse
ff47f79c62 Fix serverVersion in snapshots failing tests 2020-02-14 17:57:01 -08:00
Lucien Greathouse
f46a391873 Build releases on tag push instead of release creation 2020-01-22 10:20:37 -08:00
Lucien Greathouse
99b8ada42b Release v0.6.0-alpha.1 2020-01-22 10:09:07 -08:00
Lucien Greathouse
f2227aa7cb Use static OpenSSL for macOS binaries, too 2020-01-22 09:58:30 -08:00
Lucien Greathouse
a9f6c20113 Support Linux release binaries 2020-01-22 09:55:21 -08:00
Lucien Greathouse
e261e7a2c7 Implement glob ignores (#272)
* Add Glob wrapper type with better serialization

* Introduce PathIgnoreRule struct

* Implement equality for Glob type

* Add PathIgnoreRule to InstanceContext

* Implement glob ignores in directory middleware

* Fix up filters

* Use Iterator::all instead of loop

* Add project-level configuration for glob ignores

* Add test project for glob ignores

* Wire up project file and snapshots to make glob ignores work

* Better codepaths for adding ignore rules with empty iterators

* Add test for globs inherited from parent projects

* Add test details, support glob ignores in nested projects

* Add feature flag for globs

* Switch to use ExactSizeIterator instead of size_hint

* Remove glob visitor
2020-01-08 17:58:37 -08:00
Lucien Greathouse
ae811aafd0 Make ChangeProcessor abort gracefully on RecvError 2020-01-05 23:46:12 -08:00
Lucien Greathouse
cc593b465d Delete unused plugin place project 2020-01-04 21:31:36 -08:00
Lucien Greathouse
f81e8339e3 Add 'homepage' and 'documentation' links to Cargo.toml 2019-12-20 16:52:56 -08:00
Lucien Greathouse
cdc5513726 Rename dev-live-assets feature to dev_live_assets 2019-12-20 14:26:08 -08:00
Lucien Greathouse
a398338c02 Two way sync V0 (#282)
* Unfinished two-way sync API

* In-memory two-way sync complete

* Move PatchSet application into ChangeProcessor thread, where it can be synchronous

* Stop InstanceMap's signals when a ServeSession terminates

* Apply patch in ChangeProcessor

* Feature flag

* Fix error in ChangeProcessor due to wrong drop order
2019-12-20 14:24:28 -08:00
Lucien Greathouse
26e2e81188 Refactor ChangeProcessor to be easier to follow 2019-12-19 17:41:35 -08:00
Lucien Greathouse
46d7bba87d Add .rbxl.lock and .rbxlx.lock files to gitignore 2019-12-19 14:46:34 -08:00
Lucien Greathouse
57d5610a58 plugin: Improve HTTP error messages by using response body 2019-12-19 14:41:57 -08:00
Lucien Greathouse
1968e1fdb7 Fix bad formatting string in plugin HTTP module 2019-12-19 14:40:29 -08:00
Lucien Greathouse
f2584cf807 Fix live sync.
The refactor to use StructOpt instead of plain Clap had some absolute
vs relative path issues that slipped through. This commit adds getters
to each StructOpt struct that exposes an explicitly absolute version
of each path value.
2019-12-18 17:52:16 -08:00
Lucien Greathouse
dd592d1d6d Break pathing everywhere (fix coming soon), fix verbosity argument 2019-12-18 17:44:47 -08:00
Lucien Greathouse
cfff08cdfd Add plugin half of script-only, existing-instance-only, two way sync 2019-12-18 17:39:04 -08:00
Lucien Greathouse
e83437c193 Add debug formatter for instances 2019-12-18 17:38:31 -08:00
Lucien Greathouse
1d900a6a3c Update benchmarks to use new CLI API 2019-12-18 15:56:24 -08:00
Lucien Greathouse
859c7bea8a Update most dependencies 2019-12-18 15:52:47 -08:00
Lucien Greathouse
1b9e90e786 Port from Failure to Snafu (#281)
* Failure -> Snafu for build command

* Port skeletal remains of init to snafu

* failure -> snafu for serve

* failure -> snafu for upload, remove impl_from macro

* failure -> custom error in vfs

* Bye bye, failure

* Fix Rust 1.36 build regression
2019-12-18 15:44:46 -08:00
Lucien Greathouse
41396367ac Tell Cargo to use Rojo's README.md 2019-12-17 13:59:59 -08:00
Lucien Greathouse
16c9a23d55 Shuffle around Rojo's public API 2019-12-17 13:58:46 -08:00
Lucien Greathouse
ce338a2a72 Remove impl_from macro from public API 2019-12-17 13:40:52 -08:00
Lucien Greathouse
1f7f2b22e7 Rewrite Project, remove SourceProject (#274)
* Rewrite project file to have relative paths and drop SourceProject

* Redo project error types

* Tidy up and document Project type

* Strip out init command
2019-12-12 14:45:15 -08:00
Lucien Greathouse
47c7f63d75 Switch everything to StructOpt (#277)
* Add types for Rojo's subcommands

* Flesh out CLI types

* Port everything to structopt instead of clap
2019-12-12 14:30:47 -08:00
Lucien Greathouse
8b1e85fbb4 Upgrade dependencies 2019-12-11 18:05:44 -08:00
Lucien Greathouse
ff4e9fb027 Stop overriding default-members in CI 2019-12-10 17:13:37 -08:00
Lucien Greathouse
d15ef40988 Upgrade dependencies correctly this time 2019-12-10 17:02:08 -08:00
Lucien Greathouse
eadfb18f74 Update rbx_xml and rbx_reflection 2019-12-10 13:39:55 -08:00
Lucien Greathouse
4b89bb087a Attach context to instances produced by middleware (#273) 2019-12-04 11:38:28 -08:00
Lucien Greathouse
f0a602b48b Revert "Remove some PartialEq derives"
This reverts commit fe10da9a6c.
2019-12-03 16:47:19 -08:00
Lucien Greathouse
fe10da9a6c Remove some PartialEq derives 2019-12-03 16:34:46 -08:00
Lucien Greathouse
948303aac8 Remove InstanceSnapshotContext in favor of InstanceContext (#271)
* Drop plugin context on the floor

* Remove redirect from old context to new context

* Pass InstanceContext via & instead of &mut reference

* Re-use context value in ChangeProcessor from metadata
2019-12-03 16:11:51 -08:00
Lucien Greathouse
12df80da56 Introduce InstanceContext (#270)
* Add instance context with dummy field

* Remove stub field
2019-12-03 15:30:20 -08:00
Lucien Greathouse
a48c238ed7 Add InstanceMetadata builder (#269)
* Add InstanceMetadata builder, with context field for globbing

* Revert snapshot changes

* Port snapshot functions to InstanceMetadata builder-ish pattern

* Remove IgnoreGlob struct

* Elide lifetime
2019-12-03 14:49:40 -08:00
Lucien Greathouse
da6c7b4d7a Fix Insta snapshot files having their line endings truncated when edited 2019-11-25 18:10:39 -08:00
Lucien Greathouse
15cbbacc2f Refcount entries in snapshot context, moving towards sharing 2019-11-25 15:11:58 -08:00
Lucien Greathouse
c3f6a17bae Add builder-ish methods to InstanceSnapshot to make middleware code more readable 2019-11-19 14:02:57 -08:00
Lucien Greathouse
0fbeb70865 Remove erroneous comment in SnapshotJsonModel 2019-11-19 13:53:48 -08:00
Lucien Greathouse
02f98a4053 Remove lifetime from SnapshotInstanceResult 2019-11-19 13:06:31 -08:00
Lucien Greathouse
d2e2a13479 Start stripping out lifetimes in InstanceSnapshot 2019-11-19 13:05:18 -08:00
Lucien Greathouse
f32cb592e2 Remove ownership stuff from InstanceSnapshot 2019-11-19 13:02:35 -08:00
Lucien Greathouse
72342f3118 Trim vestigial middleware method 2019-11-19 12:55:55 -08:00
Lucien Greathouse
246fd5f6c4 Add init scripts as relevant paths to all directories.
This doesn't feel ideal. Though it's true that all directories are influenced by
any init scripts they have, the directory middleware shouldn't need to know
about Lua.

I don't really want to go back into working on the middleware chain since it
mostly feels like busywork when there are other things to build on in Rojo.

also all of this feels really complicated
2019-11-18 18:28:36 -08:00
Lucien Greathouse
715022def5 Make init files copy metadata from folder.
Fixes #267.
2019-11-18 18:16:37 -08:00
Lucien Greathouse
78b2bafde1 Add test for #267. 2019-11-18 18:11:33 -08:00
Lucien Greathouse
2d7ebac8e6 Enable test for removing files 2019-11-18 18:08:18 -08:00
Lucien Greathouse
bcffd2eb99 Add support for removing files, handled in ChangeProcessor 2019-11-18 18:08:12 -08:00
Lucien Greathouse
459bf62fab Add missing contents for disabled remove_file test 2019-11-18 16:52:19 -08:00
Lucien Greathouse
bdaa671823 Plugin: Pipe InstanceMap around, improve debug output, fix session ID bug 2019-11-18 16:30:57 -08:00
Lucien Greathouse
463bf9b116 Make errors scrollable when too long 2019-11-18 15:57:22 -08:00
Lucien Greathouse
0c7a94c062 Update more code to new formatting machinery 2019-11-18 15:18:06 -08:00
Lucien Greathouse
af866f0665 Fix request timeout in long polling causing error to bubble to console 2019-11-15 15:54:58 -08:00
Lucien Greathouse
2493c70241 Fix log special case for empty tables 2019-11-15 15:43:42 -08:00
Lucien Greathouse
3c3359999c Fix hydration patch incorrectly comparing properties 2019-11-15 15:42:11 -08:00
Lucien Greathouse
2467004dc2 Update HTTP logs 2019-11-15 15:40:03 -08:00
Lucien Greathouse
3a9f438390 Integrate fmt into log 2019-11-15 15:39:15 -08:00
Lucien Greathouse
3126de2c37 Build out real formatting machinery 2019-11-15 15:00:54 -08:00
Lucien Greathouse
b7d026b98e Partial implementation of better formatting machinery 2019-11-14 18:43:51 -08:00
Lucien Greathouse
3f8b178f88 Add support for computing property and name changes in hydration patch computation 2019-11-14 18:18:38 -08:00
Lucien Greathouse
6184f4ce4f Improve debug output for initialization of ServeSession 2019-11-14 18:18:24 -08:00
Lucien Greathouse
fa736697a9 Introduce early Lua formatting library inspired by Rust 2019-11-14 18:18:07 -08:00
Lucien Greathouse
2c88c700ca Work around plugins loading too early by searching for DevSettings via ChildAdded 2019-11-14 18:16:48 -08:00
Lucien Greathouse
0b2e9ce1ad Improve InstanceMap tracking of ValueBase instances 2019-11-14 18:16:17 -08:00
Lucien Greathouse
ccafdf250e Add counterpart to setCanonicalProperty for reading 2019-11-14 18:15:53 -08:00
Lucien Greathouse
57b28faa74 Update ApiSubcribeMessage signature 2019-11-14 18:15:33 -08:00
Lucien Greathouse
d0d7c58af1 Start tracking property changes in plugin 2019-11-13 18:34:48 -08:00
Lucien Greathouse
339fc979f5 Add disabled test for removing file that currently hangs 2019-11-11 18:03:31 -08:00
Lucien Greathouse
47614c3102 Update names in subscribe portion of sync protocol 2019-11-11 17:52:09 -08:00
Lucien Greathouse
94e1501329 Stop having clibrojo as a default project, update docs 2019-11-07 18:24:16 -08:00
Lucien Greathouse
dfb015acc2 Add Rojo C API experiment 2019-11-07 18:20:55 -08:00
Lucien Greathouse
f1daafbf9e Fix ordering not being preserved in Vfs 2019-11-03 00:00:50 -07:00
Lucien Greathouse
432e10c205 Scrap old project load tests 2019-11-02 23:47:03 -07:00
Lucien Greathouse
62b626a931 Remove Project::load_from_str in favor of from_slice 2019-11-02 23:43:24 -07:00
Lucien Greathouse
9a2893c6bc Remove warnings for upgrading from 0.4.x 2019-11-02 23:41:32 -07:00
Lucien Greathouse
3a538f98ed Tightened project discovery behavior 2019-11-02 23:36:28 -07:00
Lucien Greathouse
7c71708de7 Drop support for roblox-project.json 2019-11-02 23:16:01 -07:00
Lucien Greathouse
b64d97e808 Force PathMap to have deterministic ordering by using BTreeSet instead of HashSet 2019-10-21 16:25:34 -07:00
Lucien Greathouse
428a19789d Enable 'move folder of stuff' test 2019-10-21 16:00:43 -07:00
Lucien Greathouse
7cc4055d94 Upgrade to Insta master to get bugfix.
Map sorting in Insta was previously not recursive.
As of this PR, it is!
https://github.com/mitsuhiko/insta/pull/80

Since it hasn't made it into a release yet, but is
important for Rojo to have snapshot determinism,
we're moving temporarily to depend on Insta via Git.
2019-10-21 15:29:33 -07:00
Lucien Greathouse
114c93fa46 Fix non-portable path serialization in ProjectNode.
This was failing snapshot tests on the Linux CI machines,
since I committed snapshots with backslashes.

I think the old path serializer was still the wrong approach,
this one is sort of a middleground but I'm still not super
happy with it.
2019-10-18 19:40:47 -07:00
Lucien Greathouse
07801a0283 Add support for updating instances defined in project nodes 2019-10-18 18:06:40 -07:00
Lucien Greathouse
30c8ea583b Remove special path serialization for ProjectNode 2019-10-18 18:06:25 -07:00
Lucien Greathouse
d54a5f647e Improve tree explorer UI 2019-10-18 16:49:03 -07:00
Lucien Greathouse
457ed05174 Fix missed references to IMFS in CSS instead of VFS 2019-10-18 15:37:38 -07:00
Lucien Greathouse
44c94da2d8 Fix clippy warnings 2019-10-17 18:22:53 -07:00
Lucien Greathouse
ec614e1912 Remove last unused warning. Closes #245. 2019-10-17 17:48:30 -07:00
Lucien Greathouse
559b509a03 Upgrade to latest rbx-dom 2019-10-17 17:37:49 -07:00
Lucien Greathouse
e2e9209655 rojo-test: Add disabled test for moving big folder of stuff 2019-10-17 16:03:21 -07:00
Lucien Greathouse
e55b72f73f rojo-test: Move settings closer to where settings are applied 2019-10-17 16:01:03 -07:00
Lucien Greathouse
85e30cc968 Write tests and ensure adding instances works 2019-10-17 13:46:59 -07:00
Lucien Greathouse
51dcfbab75 Fix rustfmt on benches 2019-10-16 19:32:10 -07:00
Lucien Greathouse
7c0aa45057 Add support for adding new instances, very pedantically 2019-10-16 18:28:38 -07:00
Lucien Greathouse
a5fdc2a9cc Add logging, fix flipped condition on child add 2019-10-16 18:28:11 -07:00
Lucien Greathouse
64fd2f9cf8 Add disabled test for adding a folder, currently failing 2019-10-16 17:54:10 -07:00
Lucien Greathouse
a77495c562 Add names to serve test snapshots 2019-10-16 17:41:21 -07:00
Lucien Greathouse
3880708e1d Improve serve snapshot test ergonomics 2019-10-16 17:36:13 -07:00
Lucien Greathouse
cc68d57f11 Remove insta dependency for rojo-insta-ext 2019-10-16 17:03:21 -07:00
Lucien Greathouse
56f5a61362 Add test for folder of scripts being mutated 2019-10-16 16:55:55 -07:00
Lucien Greathouse
40540c3637 Improve serve test, add single txt file test 2019-10-16 16:21:33 -07:00
Lucien Greathouse
82678235ab VFS Improvements (#259)
This PR refactors all of the methods on `Vfs` from accepting `&mut self` to
accepting `&self` and keeping data wrapped in a mutex. This builds on previous
changes to make reference count file contents and cleans up the last places
where we're returning borrowed data out of the VFS interface.

Once this change lands, there are two possible directions we can go that I see:
* Conservative: Refactor all remaining `&mut Vfs` handles to `&Vfs`
* Interesting: Embrace ref counting by changing `Vfs` methods to accept `self:
  Arc<Self>`, which makes the `VfsEntry` API no longer need an explicit `Vfs`
  argument for its operations.

* Change VfsFetcher to be immutable with internal locking
* Refactor Vfs::would_be_resident
* Refactor Vfs::read_if_not_exists
* Refactor Vfs::raise_file_removed
* Refactor Vfs::raise_file_changed
* Add Vfs::get_internal as bits of Vfs::get
* Switch Vfs to use internal locking
* Migrate all Vfs methods from &mut self to &self
* Make VfsEntry access Vfs immutably
* Remove outer VFS locking (#260)
* Refactor all snapshot middleware to accept &Vfs instead of &mut Vfs
* Remove outer VFS Mutex across the board
2019-10-16 15:45:23 -07:00
Lucien Greathouse
5123d21290 Rename Vfs::inner to Vfs::data, use Self more 2019-10-14 16:46:15 -07:00
Lucien Greathouse
b0dcf515f0 Refactor plugins, port message dropping bugfix from 0.5.1 2019-10-14 14:05:25 -07:00
Lucien Greathouse
9aafccc946 Update CHANGELOG 2019-10-14 13:46:02 -07:00
Lucien Greathouse
ccf98d7283 Move and tidy up small place benchmark 2019-10-14 11:38:16 -07:00
Lucien Greathouse
1b35c98be5 Add build tests for init.meta.json 2019-10-12 23:54:39 -07:00
Lucien Greathouse
db23c3d35a Mark init.meta.json as relevant path for directories 2019-10-12 23:46:49 -07:00
Lucien Greathouse
1c6c1298d5 Add init.meta.json support, untested 2019-10-12 23:45:38 -07:00
Lucien Greathouse
b9ebed14a5 Add documentation for AdjacentMetadata 2019-10-12 23:31:33 -07:00
Lucien Greathouse
7077f0f1f3 Load user plugins on startup instead of lazily at snapshot time 2019-10-12 23:27:12 -07:00
Lucien Greathouse
d1887c6cd3 Merge branch 'vfs-arc' 2019-10-12 15:29:54 -07:00
Lucien Greathouse
9278c81611 Merge branch 'master' into vfs-arc 2019-10-12 15:28:33 -07:00
Lucien Greathouse
dec9ec32df Add small place benchmark 2019-10-12 15:24:57 -07:00
Lucien Greathouse
1967f738a8 Make all file contents be Arc<Vec<u8>> instead of &[u8] 2019-10-12 14:17:52 -07:00
Lucien Greathouse
1031600c63 Batch rename: imfs -> vfs 2019-10-12 13:58:00 -07:00
Lucien Greathouse
24c697bea7 Port commands to use common setup code
Initialization logic needed for serve, build, and upload is now
much more clear than it was when these functions were written.

This commit refactors all of them to use a new common_setup
module for all of their initialization that's the same.
2019-10-11 18:35:10 -07:00
Lucien Greathouse
83665018d4 Compute snapshot context from project in build 2019-10-11 18:25:12 -07:00
Lucien Greathouse
b093626a21 User plugin foundations for 0.6.0 (#257)
Starts work on #55.

This is similar to the previous work in #125. It's gated behind a new Cargo
feature, `user-plugins`. This time, the config gate is much smaller. The
`plugins` member of projects is still accessible when plugins aren't enabled,
but is always empty. Additionally, user plugins are only enabled if there's a
Lua state present in the snapshot context when the `SnapshotUserPlugins`
snapshot middleware runs. This not ever the case currently.

This code has very little possibility of rotting while we focus on other work,
since it'll be guaranteed to still compile and can be tested in isolation
without the feature being turned on.
2019-10-11 15:45:02 -07:00
Lucien Greathouse
f3dc78b7cd Make InstanceSnapshotContext mutable through whole middleware pipeline 2019-10-10 14:07:10 -07:00
Lucien Greathouse
f0cd4333c3 Thread InstanceSnapshotContext through all SnapshotMiddleware 2019-10-10 11:44:33 -07:00
Lucien Greathouse
6d38a785ed Make SnapshotMiddleware::from_instance have a default impl 2019-10-10 10:44:46 -07:00
Lucien Greathouse
e46f9fd94f Simplify snapshot code using match_file_name utility 2019-10-09 18:27:52 -07:00
Lucien Greathouse
6b620ddcef Add utility for working with file names, port JSON model to use it 2019-10-09 18:22:58 -07:00
Lucien Greathouse
e5684ad947 Add error for malformed project files 2019-10-09 18:15:07 -07:00
Lucien Greathouse
dfabc07044 More consistent handling of non-Unicode file names (should be rare) 2019-10-09 17:15:34 -07:00
Lucien Greathouse
dca88e8272 Port Project snapshot to use with_not_found 2019-10-09 15:30:03 -07:00
Lucien Greathouse
9f947ae2c5 Improve bad Unicode error handling in txt, CSV, and directory handling 2019-10-09 12:55:24 -07:00
Lucien Greathouse
28156bcaf2 Switch SnapshotMiddleware over to SnapshotError 2019-10-09 12:42:08 -07:00
Lucien Greathouse
a14aacbcf9 Improve SnapshotError in preparation for moving middleware to it 2019-10-09 12:39:36 -07:00
boyned//Kampfkarren
321e026e43 Fix failing snapshot (#256) 2019-10-09 12:29:33 -07:00
Lucien Greathouse
30351f7b9d Add support for .meta.json files associated with .txt files 2019-10-08 17:44:23 -07:00
Lucien Greathouse
2393a1a114 Add support for .meta.json files affecting .csv LocalizationTables 2019-10-08 16:48:49 -07:00
Lucien Greathouse
479476561e Fix errors in 'Sync Details' page 2019-10-08 16:16:06 -07:00
Lucien Greathouse
a02f485040 Add end-to-end build test for Script.Disabled via .meta.json 2019-10-08 16:05:15 -07:00
Lucien Greathouse
2957e8ad73 Make Lua snapshot middleware test sort maps 2019-10-08 16:03:15 -07:00
Lucien Greathouse
f83abe15cb Add test for ensuring that scripts can be disabled with .meta.json files 2019-10-08 15:46:51 -07:00
Lucien Greathouse
709cba45ce Remove className from adjacent meta files, which is not supported in 0.5.x 2019-10-08 15:44:47 -07:00
Lucien Greathouse
8a9a72fd50 Refactor .meta.json into AdjacentMetadata type more strongly 2019-10-08 15:42:44 -07:00
Lucien Greathouse
13cb0a27a0 Make .meta.json changes cause scripts to be updated 2019-10-08 15:30:16 -07:00
Lucien Greathouse
fa817e3cdd Add baseline support for adjacent meta files for scripts 2019-10-08 14:14:44 -07:00
Lucien Greathouse
3bd8549f41 Add ServeSession test for project with folder 2019-10-08 13:57:40 -07:00
Lucien Greathouse
4e47655b17 Refactor MessageQueue API to return a oneshot receiver 2019-10-08 13:49:41 -07:00
Lucien Greathouse
18533d5944 Improve ServeSession test using async and Tokio 2019-10-08 13:26:21 -07:00
Lucien Greathouse
c5839c94ca Add test-only MessageQueue::subscribe_any.
This makes writing tests that do async things easier.
2019-10-08 13:25:34 -07:00
Lucien Greathouse
ffc146ff9b Add ServeSession test for changing text file 2019-10-07 18:23:39 -07:00
Lucien Greathouse
7b82e3d641 Add TestFetcher for mocking more filesystem operations than NoopFetcher 2019-10-07 18:22:29 -07:00
Lucien Greathouse
ab6cedb659 Move some serve code into serve_session.rs, start writing serve session tests 2019-10-07 16:24:36 -07:00
Lucien Greathouse
e60be94be0 Move patch apply test utility into tree_view module 2019-10-07 16:21:25 -07:00
Lucien Greathouse
f830b024d5 Add ImfsSnapshot::empty_dir() for debugging the Imfs 2019-10-07 16:20:04 -07:00
Lucien Greathouse
98519da7d9 Reintroduce instigating paths for snapshot middleware 2019-10-04 18:36:04 -07:00
Lucien Greathouse
cb3211cf46 Mark project node as instigating source for instances from project 2019-10-04 18:10:45 -07:00
Lucien Greathouse
c051153a1f Mark project file as instigating source for top-level instances 2019-10-04 18:05:27 -07:00
Lucien Greathouse
956d7e0918 Fix warning in JSON model snapshot test 2019-10-04 17:52:05 -07:00
Lucien Greathouse
530a7aa834 Rename 'contributing paths' to 'relevant paths' 2019-10-04 17:36:26 -07:00
Lucien Greathouse
052ca52cc3 Move instigating source out of contributing paths (#253)
* Refactor contributing_paths into contributing_sources, deleting project node sources

* Instead of changing contributing_paths, add instigating_source

* Remove InstanceMetadata::project_node

* Stop pushing project path to front of contributing_paths since it doesn't matter now

* Remove accidental UI change for path display
2019-10-04 17:34:05 -07:00
Lucien Greathouse
2025b8a494 Fix patch I missed project_node change 2019-10-04 15:49:12 -07:00
Lucien Greathouse
238233ca81 Stop serializing project_node if it's None 2019-10-04 15:12:34 -07:00
Lucien Greathouse
938c8259c3 Include project node in debug UI 2019-10-04 14:29:02 -07:00
Lucien Greathouse
35df5f25c7 Show metadata in web interface, take one 2019-10-04 14:14:45 -07:00
Lucien Greathouse
cd84fb9fc1 Bring forward 0.5.1 release notes 2019-10-04 13:19:14 -07:00
Lucien Greathouse
8bcf12e317 Update dependencies 2019-10-04 13:18:42 -07:00
Lucien Greathouse
10ed353e0a Add TODO for JSON model metadata 2019-10-03 18:30:10 -07:00
Lucien Greathouse
72d88200e4 Snapshot tests for JSON models 2019-10-03 18:28:58 -07:00
Lucien Greathouse
6ef832b3a9 Improve documentation for SnapshotProject 2019-10-03 18:25:06 -07:00
Lucien Greathouse
17d91563d5 Port project file tests to use insta 2019-10-03 18:22:20 -07:00
Lucien Greathouse
fb65693627 Propagate metadata in project files correctly 2019-10-03 18:12:52 -07:00
Lucien Greathouse
079fc738ad plugin: Properly handle removals in patches 2019-10-03 18:12:36 -07:00
Lucien Greathouse
ae0f3b0b02 Assign contributing paths in simple cases for snapshots 2019-10-03 17:34:33 -07:00
Lucien Greathouse
b2c515f2e6 plugin: Prevent HTTP timeout cascading after session stop 2019-10-03 17:28:34 -07:00
Lucien Greathouse
6f1469a551 plugin: Implement patch application, which makes live sync work 2019-10-03 17:13:29 -07:00
Lucien Greathouse
1d441b86d2 plugin: Fix type bindings for instance Parent 2019-10-03 17:13:17 -07:00
Lucien Greathouse
b72e6e54e6 plugin: Add debugging function for InstanceMap state 2019-10-03 17:12:43 -07:00
Lucien Greathouse
1ee679395d Add 'invariant' function for debugging 2019-10-03 17:12:08 -07:00
Lucien Greathouse
cf62ee5ccb plugin: Add Id and ParentId to ApiInstance type definitions 2019-10-03 15:54:49 -07:00
Lucien Greathouse
995685adfe Expose instance ID and parent ID in web API 2019-10-03 15:54:11 -07:00
Lucien Greathouse
f0eb955628 Expose parent from RojoTree instances 2019-10-03 15:53:50 -07:00
Lucien Greathouse
923f661428 Start rewriting plugin on top of new sync protocol 2019-10-02 18:41:52 -07:00
Lucien Greathouse
b562d11994 plugin: Remove Logging alias and update imports 2019-10-02 11:10:34 -07:00
Lucien Greathouse
3554112f31 plugin: Add test that loads all modules 2019-10-02 11:07:22 -07:00
Lucien Greathouse
7cada2608f plugin: Refactor HTTP and ApiContext foundations 2019-10-02 11:04:40 -07:00
Lucien Greathouse
21d4acebc3 Move .luacheckrc for better editor detection 2019-10-02 10:42:10 -07:00
Lucien Greathouse
73bbaaf0af Add script for installing release plugin 2019-10-01 18:42:25 -07:00
Lucien Greathouse
40105515d2 plugin: Unify test running code 2019-10-01 18:41:33 -07:00
Lucien Greathouse
79f09deecb Add strong type checking to plugin API client 2019-10-01 18:37:35 -07:00
Lucien Greathouse
c4a7f8675f Fix log level in plugin dev mode 2019-10-01 18:37:25 -07:00
Lucien Greathouse
f9a5fee364 Reorganize and clean up plugin 2019-10-01 18:23:29 -07:00
Lucien Greathouse
bdd9c58cae Update all CI scripts and mark as executable 2019-10-01 18:07:32 -07:00
Lucien Greathouse
09368e87cf Further update contributing guide on tools 2019-10-01 17:54:53 -07:00
Lucien Greathouse
46858c45b8 Add note about tools for contributing 2019-10-01 17:52:36 -07:00
Lucien Greathouse
fe1a96f850 Improve plugin test running, reducing project duplication 2019-10-01 17:44:24 -07:00
Lucien Greathouse
581449d992 Port more code over to use strict 2019-10-01 17:13:43 -07:00
Lucien Greathouse
15e848d4bf Add new scripts and machinery to make working on plugin easier 2019-10-01 17:13:28 -07:00
Lucien Greathouse
0dbbf44ab2 plugin: Add API interface for strongly typing responses 2019-10-01 16:55:45 -07:00
Lucien Greathouse
c62a5d15ad Add script to build plugin as changes occur 2019-10-01 16:55:15 -07:00
Lucien Greathouse
53bd02a890 Add script to quickly install plugin into LocalAppData 2019-10-01 16:52:20 -07:00
Lucien Greathouse
099aa26ef8 Rough pass on transforming applied patches into API responses 2019-10-01 14:45:24 -07:00
Lucien Greathouse
2598ea3577 Add contributing paths to SnapshotLua, switch to Insta tests 2019-10-01 14:09:05 -07:00
Lucien Greathouse
7be5b36494 Fix unreachable pattern warning 2019-10-01 14:07:50 -07:00
Lucien Greathouse
3dff4d1061 Generate and apply patches, routing them through message queue 2019-10-01 13:59:10 -07:00
Lucien Greathouse
5b7037550d Start ChangeProcessor pumping work 2019-10-01 13:48:16 -07:00
Lucien Greathouse
b94f21402c Expose RojoTree::get_metadata publicly 2019-10-01 13:47:25 -07:00
Lucien Greathouse
9f5875d4bb imfs: move debugging messages outside of converter thread 2019-10-01 13:47:14 -07:00
Lucien Greathouse
694b6101ca New Imfs event type 2019-10-01 11:29:09 -07:00
Lucien Greathouse
1737da9c1f Move ImfsEvent into its own module 2019-10-01 10:44:35 -07:00
Lucien Greathouse
bcf4fea598 Add RojoTree::get_ids_at_path 2019-10-01 10:37:06 -07:00
Lucien Greathouse
90e41f3ce9 Fix bounds on MultiMap::get 2019-10-01 10:36:20 -07:00
Lucien Greathouse
5f5fb51eae Make up terminology for 'instigating path' in instance metadata 2019-10-01 10:32:05 -07:00
Lucien Greathouse
95f06d56d8 Port SnapshotDir tests to use insta snapshots 2019-09-30 18:33:46 -07:00
Lucien Greathouse
1c6788ea45 Migrate from source_path to contributing_paths 2019-09-30 18:12:19 -07:00
Lucien Greathouse
457a8a5cf8 Fix warning in serve_test 2019-09-30 17:37:16 -07:00
Lucien Greathouse
282caf10a5 Expand patch_apply tests 2019-09-30 17:36:37 -07:00
Lucien Greathouse
b2fc6c165b Improve patch application test 2019-09-30 17:22:54 -07:00
Lucien Greathouse
0a1fa9588f Test for AppliedPatchSet result 2019-09-30 17:13:56 -07:00
Lucien Greathouse
5f5bfadf2b Add compute_patch tests for adding/removing children 2019-09-30 17:04:45 -07:00
Lucien Greathouse
b512e707a5 First round of snapshot tests for patch_compute 2019-09-30 17:00:12 -07:00
Lucien Greathouse
3678ddfa36 Break redaction stuff out into separate crate 2019-09-30 16:27:31 -07:00
Lucien Greathouse
ab8aa89f2a Add real networked message type 2019-09-29 20:16:54 -07:00
Lucien Greathouse
fd22482f06 Goodbye Travis 2019-09-27 15:09:35 -07:00
Lucien Greathouse
e741f7b557 Actually generate AppliedPatchSet objects (#250)
* Start actually computing AppliedPatchSet values

* Improve patch_apply documentation and flesh out applied patch code

* Add file link notes

* Stub out where tests for snapshot subsystem will go

* Create baseline tests

* Fix build failure by silencing Clippy
2019-09-27 15:07:11 -07:00
Lucien Greathouse
a70b7ee150 Add GitHub Actions badge 2019-09-27 15:03:57 -07:00
Lucien Greathouse
87227c96ed Document snapshot pipeline 2019-09-26 14:28:04 -07:00
Lucien Greathouse
91d12aeb4f Break out expandable section into a component thing 2019-09-25 17:29:47 -07:00
Lucien Greathouse
b3f132201b Better expandables for the instance debugger 2019-09-25 14:47:07 -07:00
Lucien Greathouse
24b9f552eb Improve imfs debugging page 2019-09-25 11:05:56 -07:00
Lucien Greathouse
b4a8dec68c Track watched paths in ImfsFetcher, exposed via ImfsDebug interface 2019-09-25 10:45:14 -07:00
Lucien Greathouse
c140823bea Move Imfs snapshotting into ImfsDebug 2019-09-24 18:14:48 -07:00
Lucien Greathouse
f166cc93cd Remove unused MessageQueue method 2019-09-24 18:08:32 -07:00
Lucien Greathouse
125c9767f1 Fix warnings around ChangeProcessor 2019-09-24 18:07:33 -07:00
Lucien Greathouse
7b7c978db6 Fix warning and make 'rojo serve' output to stdout 2019-09-24 18:06:31 -07:00
Lucien Greathouse
26fc097672 Add visualizer for IMFS state 2019-09-24 18:04:25 -07:00
Lucien Greathouse
0f2e2406e8 imfs: Correctly mark children_enumerated when calling get_children 2019-09-24 17:58:46 -07:00
Lucien Greathouse
061a096600 Add PathMap::orphans for traversing the map's roots 2019-09-24 17:55:39 -07:00
Lucien Greathouse
07fe963bed Don't include CSS in live asset mode 2019-09-24 17:53:39 -07:00
Lucien Greathouse
7a1eda98ca Implement instance tree visualization 2019-09-24 16:46:19 -07:00
Lucien Greathouse
e8a5e44319 Add abstraction for files to make iteration on UI easier 2019-09-24 14:00:48 -07:00
Lucien Greathouse
486319407a Refactor web UI to be more readable 2019-09-24 11:29:13 -07:00
Lucien Greathouse
4f3d917c9b Add support for snapshotting rbxlx files 2019-09-23 18:13:38 -07:00
Lucien Greathouse
e2761965d5 Add support for serving non-project files directly 2019-09-23 18:00:54 -07:00
Lucien Greathouse
171ab196c8 Update changelog 2019-09-23 17:54:49 -07:00
Lucien Greathouse
5630cea9a0 Improve command line and web interface 2019-09-23 17:54:04 -07:00
Lucien Greathouse
5a4189a770 Move ChangeReceiver main block into its own function 2019-09-23 16:13:19 -07:00
Lucien Greathouse
2440d9fc48 Create ChangeProcessor for routing events from imfs to tree to message queue 2019-09-23 16:09:58 -07:00
Lucien Greathouse
bd33aebc3d Turn messages into stub SubscribeMessage struct 2019-09-23 10:53:11 -07:00
boyned//Kampfkarren
a46d467b75 Fix broken link to sync details (#248) 2019-09-22 17:37:00 -07:00
Lucien Greathouse
8c6981da0d Fix guide to point to release versions instead of alphas 2019-09-20 11:08:01 -07:00
Lucien Greathouse
500a9f647f Fix snapshot test with new version number 2019-09-19 15:26:31 -07:00
Lucien Greathouse
71968fca0d Fold imfs::new back into imfs 2019-09-19 15:25:07 -07:00
Lucien Greathouse
fc6f84897f Update docs link to rojo.space 2019-09-19 14:02:02 -07:00
Lucien Greathouse
b31ad4b1f8 Update version to 0.6.0-dev 2019-09-19 13:58:53 -07:00
Lucien Greathouse
aababf37a8 Catch more HTTP API errors 2019-09-19 13:50:42 -07:00
Lucien Greathouse
44a42a177a Change API errors to be JSON 2019-09-19 13:20:58 -07:00
Lucien Greathouse
e773a92e53 Connect message queue to frontend API 2019-09-19 13:12:21 -07:00
Lucien Greathouse
196d27b959 Allow IMFS testing features to be unused 2019-09-19 11:13:27 -07:00
Lucien Greathouse
ec8861e983 Apply patch sets by value in preparation for AppliedPatchSet 2019-09-19 11:10:25 -07:00
Lucien Greathouse
9b601eb9fe Tidy up patch structs, add AppliedPatchSet 2019-09-19 10:56:10 -07:00
Lucien Greathouse
c80d9cbf01 Add default-members to make 'cargo t' work better 2019-09-19 10:46:09 -07:00
Lucien Greathouse
717c15256f Update GH workflows, bump minimum Rust to 1.36.0 2019-09-17 18:31:02 -07:00
Lucien Greathouse
13dafc2091 Bump minimum Rust in GitHub actions to 1.36.0 2019-09-17 17:31:00 -07:00
Lucien Greathouse
cfc3bcfa41 Switch to single quotes for GitHub action workflow 2019-09-17 16:51:40 -07:00
Lucien Greathouse
2e052e97c5 Experimental GitHub Action 2019-09-17 16:48:51 -07:00
Lucien Greathouse
5d48d05287 Update Changelog 2019-09-13 17:31:53 -07:00
Lucien Greathouse
e34ba844c5 Improve diagnostics for failed instance creation 2019-09-13 17:16:16 -07:00
Lucien Greathouse
1d84d3e440 Wrap RojoTree in Mutex 2019-09-13 12:57:37 -07:00
Lucien Greathouse
7a7e9087e6 Expose imfs from ServeSession 2019-09-13 12:57:22 -07:00
Lucien Greathouse
8481caa67c Add Imfs to ServeSession, threading through generic ImfsFetcher 2019-09-13 12:52:15 -07:00
Lucien Greathouse
651e63a0fb Tidy up docs links in readme 2019-09-11 11:37:58 -07:00
Lucien Greathouse
88e462c4e5 Add help page to direct people to Discord, GitHub, and Twitter 2019-09-11 11:34:52 -07:00
Lucien Greathouse
8ef797d1a4 Start writing real serve tests 2019-09-10 18:04:05 -07:00
Lucien Greathouse
877fd1af35 Make /api/subscribe hang forever instead of returning no messages 2019-09-10 16:42:14 -07:00
Lucien Greathouse
fc01eecdcb Use real Rojo metadata for live sync 2019-09-10 15:59:36 -07:00
Lucien Greathouse
e6ba6203bb Expose tree in API, with hacks to make initial sync-in work sort of 2019-09-10 15:39:50 -07:00
Lucien Greathouse
6a786f18e6 Update plugin protocl version, fix error in error 2019-09-10 15:37:21 -07:00
Lucien Greathouse
57d46287d7 Glue message queue onto ServeSession, simplify some HTTP 2019-09-09 18:32:44 -07:00
Lucien Greathouse
bb6ab74c19 Clean up warnings, add RojoTree into ServeSession 2019-09-09 15:17:03 -07:00
Lucien Greathouse
3e759b3e8e Finish off bulk of metadata tracking in snapshot system 2019-09-09 15:04:57 -07:00
Lucien Greathouse
47ee8d54a8 Clean up some of the instance wrapper APIs 2019-09-09 13:59:36 -07:00
Lucien Greathouse
824b984a64 First pass converting snapshot code over to RojoTree from RbxTree 2019-09-09 13:50:39 -07:00
Lucien Greathouse
618185a52d Start using multimap correctly for path tracking in RojoTree 2019-09-09 11:50:58 -07:00
Lucien Greathouse
8dbc6ab7d3 Start MapSet work 2019-09-06 17:05:01 -07:00
Lucien Greathouse
5eb6754b7c Implement metadata, replacing source field and laying foundations 2019-09-06 14:21:47 -07:00
Lucien Greathouse
a914a92cea Add SnapshotSource property 2019-09-05 11:27:16 -07:00
Lucien Greathouse
439a1a758e Upgrade all snapshots to insta 0.11.0 format 2019-09-03 18:15:53 -07:00
Lucien Greathouse
9383240627 Move rojo-test snapshots into partitioned folders 2019-09-03 18:11:28 -07:00
Lucien Greathouse
ea765eb929 Add serve snapshot test for empty project 2019-09-03 17:56:23 -07:00
Lucien Greathouse
d5c816f24d Document and expose public members for Rojo API 2019-09-03 14:20:12 -07:00
Lucien Greathouse
cf5f20bbb5 Upgrade depdendencies, removing need for opt-level in debug 2019-09-03 14:09:35 -07:00
Lucien Greathouse
27839dfd21 Shuffle web_interface into web::interface 2019-09-03 14:00:31 -07:00
Lucien Greathouse
27517e1aee Rename web::interface to web::ui 2019-09-03 13:58:44 -07:00
Lucien Greathouse
a31bfbefa7 Start extracting web interface from implementation 2019-09-03 13:57:28 -07:00
Lucien Greathouse
f1729163cf Add foundations for 'rojo serve' tests 2019-09-03 13:48:27 -07:00
Lucien Greathouse
6747d97d60 Factor out test utilities in preparation for serve tests 2019-09-03 10:25:48 -07:00
Lucien Greathouse
2fb2342fd4 Fix Lua snapshot code to work with children.
It's also way easier to read now
2019-08-29 17:13:36 -07:00
Lucien Greathouse
0f530b7e80 Add deep-nesting test for folders in folders 2019-08-29 16:38:41 -07:00
Lucien Greathouse
78e3cf4ffb Fix rojo-test tests not running on CI 2019-08-29 16:38:04 -07:00
Lucien Greathouse
4e512b7023 Revert to using Reqwest, reimplement upload command 2019-08-29 16:31:42 -07:00
Lucien Greathouse
ee3fed97e0 Fix parsing of auth cookie data 2019-08-29 16:31:32 -07:00
Jaguar
b45d4f6401 Correct capitalization/typos (#240)
* Fix typo

* Correct capitalization

* Correct capitalization
2019-08-28 21:29:48 -07:00
Lucien Greathouse
d4c28de2c4 Update changelog 2019-08-28 14:34:14 -07:00
Lucien Greathouse
b7d613ace6 Correct bug report repository link 2019-08-28 13:55:12 -07:00
Lucien Greathouse
68dbb31272 Add verbosity level argument 2019-08-28 13:34:20 -07:00
Lucien Greathouse
8fe1fa48b8 Let Rojo pull auth cookie from registry on Windows 2019-08-28 13:21:30 -07:00
Lucien Greathouse
e5575b782c Hide project module, moving towards Rojo API 2019-08-28 12:20:20 -07:00
Lucien Greathouse
ea112dd93d Mark security cookie as optional 2019-08-28 12:09:12 -07:00
Lucien Greathouse
056fc5e087 Remove old 'scratch project' test script, clean up .gitignore 2019-08-27 18:23:05 -07:00
Lucien Greathouse
cacb02b7c8 Fix incorrect license in Cargo.toml 2019-08-27 18:12:15 -07:00
Lucien Greathouse
c0b6ec8ccb Clean up more old plugin gunk 2019-08-27 18:10:15 -07:00
Lucien Greathouse
f4c8f0a3d8 Mark bin/run-plugin-tests.sh as executable 2019-08-27 18:05:17 -07:00
Lucien Greathouse
81407ffe3c Goodbye Lemur and other cruft, hello run-in-roblox-based testing 2019-08-27 18:04:58 -07:00
Lucien Greathouse
6f7dbe99fe Move Rojo server into root of the repository 2019-08-27 16:56:52 -07:00
Lucien Greathouse
ec9afba029 Remove unfinished plugin scaffolding 2019-08-27 16:44:40 -07:00
Lucien Greathouse
6164c5d78d Update dependencies 2019-08-27 16:30:35 -07:00
Lucien Greathouse
94dbcd5c06 Remove unused dependencies, reqwest and rlua (for now) 2019-08-27 16:30:10 -07:00
Lucien Greathouse
4d0dee7ee8 Fix or_fun clippy lint 2019-08-27 16:23:58 -07:00
Lucien Greathouse
49e10698b1 Mark bin/run-tests.sh as executable 2019-08-27 16:06:30 -07:00
Lucien Greathouse
8e1536b59b Restructure Travis config to fail fast 2019-08-27 15:42:55 -07:00
Lucien Greathouse
aed160994a Fix rustfmt error 2019-08-27 15:42:20 -07:00
Lucien Greathouse
b2b3173420 Fix editorconfig to stop fighting rustfmt 2019-08-27 15:42:07 -07:00
Lucien Greathouse
f465af964a Make Travis test rustfmt and clippy 2019-08-27 15:27:25 -07:00
Lucien Greathouse
5a7d6a673a Fix bug caught by clippy 2019-08-27 15:26:51 -07:00
Lucien Greathouse
7fb9aa2115 rustfmt the codebase 2019-08-27 15:10:34 -07:00
Lucien Greathouse
fea303ac8b Major Subsystem Rewrite (Reconciler Mk5) (#217) 2019-08-27 15:00:37 -07:00
Lucien Greathouse
8e8291a0bd Add more stern warning about docs from master branch 2019-08-27 14:52:40 -07:00
Lucien Greathouse
4dc175fcd2 Update docs home for 0.5.x 2019-08-27 14:38:51 -07:00
478 changed files with 80776 additions and 11430 deletions

View File

@@ -3,16 +3,24 @@ root = true
[*] [*]
end_of_line = lf end_of_line = lf
charset = utf-8 charset = utf-8
insert_final_newline = false
trim_trailing_whitespace = true trim_trailing_whitespace = true
insert_final_newline = false
[*.{json,js,css}] [*.{json,js,css}]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
[*.{md,rs}] [*.md]
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
[*.{rs,toml}]
indent_style = space
indent_size = 4
insert_final_newline = true
[*.snap]
insert_final_newline = true
[*.lua] [*.lua]
indent_style = tab indent_style = tab

39
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: CI
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
rust_version: [stable, "1.43.1"]
steps:
- uses: actions/checkout@v1
with:
submodules: true
- name: Setup Rust toolchain
run: rustup default ${{ matrix.rust_version }}
- name: Build
run: cargo build --locked --verbose
- name: Run tests
run: cargo test --locked --verbose
- name: Rustfmt and Clippy
run: |
cargo fmt -- --check
cargo clippy
if: matrix.rust_version == 'stable'

66
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
name: Release
on:
push:
tags: ["*"]
jobs:
windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
with:
submodules: true
- name: Build release binary
run: cargo build --verbose --locked --release
- name: Upload artifacts
uses: actions/upload-artifact@v1
with:
name: rojo-win64
path: target/release/rojo.exe
macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v1
with:
submodules: true
- name: Install Rust
run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
- name: Build release binary
run: |
source $HOME/.cargo/env
cargo build --verbose --locked --release
env:
OPENSSL_STATIC: 1
- name: Upload artifacts
uses: actions/upload-artifact@v1
with:
name: rojo-macos
path: target/release/rojo
linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
with:
submodules: true
- name: Build
run: cargo build --locked --verbose --release
env:
OPENSSL_STATIC: 1
- name: Upload artifacts
uses: actions/upload-artifact@v1
with:
name: rojo-linux
path: target/release/rojo

23
.gitignore vendored
View File

@@ -1,9 +1,24 @@
# Rust output directory
/target /target
/scratch-project
/server/failed-snapshots/ # Headers for clibrojo
**/*.rs.bk /include
# Roblox model and place files in the root, used for debugging
/*.rbxm /*.rbxm
/*.rbxmx /*.rbxmx
/*.rbxl /*.rbxl
/*.rbxlx /*.rbxlx
**/*.snap.new
# Test places for the Roblox Studio Plugin
/plugin/*.rbxlx
# Roblox Studio holds 'lock' files on places
*.rbxl.lock
*.rbxlx.lock
# Snapshot files from the 'insta' Rust crate
**/*.snap.new
# Selene generates a roblox.toml file that should not be checked in.
/roblox.toml

9
.gitmodules vendored
View File

@@ -4,15 +4,12 @@
[submodule "plugin/modules/testez"] [submodule "plugin/modules/testez"]
path = plugin/modules/testez path = plugin/modules/testez
url = https://github.com/Roblox/testez.git url = https://github.com/Roblox/testez.git
[submodule "plugin/modules/lemur"]
path = plugin/modules/lemur
url = https://github.com/LPGhatguy/lemur.git
[submodule "plugin/modules/promise"] [submodule "plugin/modules/promise"]
path = plugin/modules/promise path = plugin/modules/promise
url = https://github.com/LPGhatguy/roblox-lua-promise.git url = https://github.com/LPGhatguy/roblox-lua-promise.git
[submodule "plugin/modules/t"] [submodule "plugin/modules/t"]
path = plugin/modules/t path = plugin/modules/t
url = https://github.com/osyrisrblx/t.git url = https://github.com/osyrisrblx/t.git
[submodule "plugin/modules/rbx-dom"] [submodule "plugin/modules/flipper"]
path = plugin/modules/rbx-dom path = plugin/modules/flipper
url = http://github.com/rojo-rbx/rbx-dom url = https://github.com/Reselim/Flipper

View File

@@ -20,6 +20,7 @@ stds.roblox = {
"CFrame", "CFrame",
"Enum", "Enum",
"Instance", "Instance",
"DockWidgetPluginGuiInfo",
} }
} }
@@ -32,7 +33,7 @@ stds.plugin = {
stds.testez = { stds.testez = {
read_globals = { read_globals = {
"describe", "describe",
"it", "itFOCUS", "itSKIP", "it", "itFOCUS", "itSKIP", "itFIXME",
"FOCUS", "SKIP", "HACK_NO_XPCALL", "FOCUS", "SKIP", "HACK_NO_XPCALL",
"expect", "expect",
} }

View File

@@ -1,44 +0,0 @@
matrix:
include:
# Lua tests are currently disabled because of holes in Lemur that are pretty
# tedious to fix. It should be fixed by either adding missing features to
# Lemur or by migrating to a CI system based on real Roblox instead.
# - language: python
# env:
# - LUA="lua=5.1"
# before_install:
# - pip install hererocks
# - hererocks lua_install -r^ --$LUA
# - export PATH=$PATH:$PWD/lua_install/bin
# install:
# - luarocks install luafilesystem
# - luarocks install busted
# - luarocks install luacov
# - luarocks install luacov-coveralls
# - luarocks install luacheck
# script:
# - cd plugin
# - luacheck src
# - lua -lluacov spec.lua
# after_success:
# - cd plugin
# - luacov-coveralls -e $TRAVIS_BUILD_DIR/lua_install
- language: rust
rust: 1.34.0
cache: cargo
script:
- cargo test --verbose
- language: rust
rust: stable
cache: cargo
script:
- cargo test --verbose

View File

@@ -2,6 +2,97 @@
## Unreleased Changes ## Unreleased Changes
## [6.0.0 Release Candidate 4](https://github.com/rojo-rbx/rojo/releases/tag/v6.0.0-rc.4) (December 14, 2020)
* Added brand new Rojo UI ([#367](https://github.com/rojo-rbx/rojo/pull/367))
* Added `projectName` to `/api/rojo` output.
## [6.0.0 Release Candidate 3](https://github.com/rojo-rbx/rojo/releases/tag/v6.0.0-rc.3) (November 19, 2020)
* Fixed the Rojo plugin attempting to write the non-scriptable properties `Instance.SourceAssetId` and `HttpServer.HttpEnabled`.
* Fixed the Rojo plugin's handling of null referents.
## [6.0.0 Release Candidate 2](https://github.com/rojo-rbx/rojo/releases/tag/v6.0.0-rc.2) (November 19, 2020)
* Fixed crash when malformed CSV files are put into a project. ([#310](https://github.com/rojo-rbx/rojo/issues/310))
* Fixed incorrect string escaping when producing Lua code from JSON files. ([#314](https://github.com/rojo-rbx/rojo/issues/314))
* Fixed performance issues introduced in Rojo 6.0.0-rc.1. ([#317](https://github.com/rojo-rbx/rojo/issues/317))
* Fixed `rojo plugin install` subcommand failing for everyone except Rojo developers. ([#320](https://github.com/rojo-rbx/rojo/issues/320))
* Updated default place template to take advantage of [#210](https://github.com/rojo-rbx/rojo/pull/210).
* Enabled glob ignore patterns by default and removed the `unstable_glob_ignore` feature.
* `globIgnorePaths` can be set on a project to a list of globs to ignore.
* The Rojo plugin now completes as much as it can from a patch without disconnecting. Warnings are shown in the console.
* Fixed 6.0.0-rc.1 regression causing instances that changed ClassName to instead... not change ClassName.
## [6.0.0 Release Candidate 1](https://github.com/rojo-rbx/rojo/releases/tag/v6.0.0-rc.1) (March 29, 2020)
This release jumped from 0.6.0 to 6.0.0. Rojo has been in use in production for many users for quite a long times, and so 6.0 is a more accurate reflection of Rojo's version than a pre-1.0 version.
* Added basic settings panel to plugin, with two settings:
* "Open Scripts Externally": When enabled, opening a script in Studio will instead open it in your default text editor.
* "Two-Way Sync": When enabled, Rojo will attempt to save changes to your place back to the filesystem. **Very early feature, very broken, beware!**
* Added `--color` option to force-enable or force-disable color in Rojo's output.
* Added support for turning `.json` files into `ModuleScript` instances ([#308](https://github.com/rojo-rbx/rojo/pull/308))
* Added `rojo plugin install` and `rojo plugin uninstall` to allow Rojo to manage its Roblox Studio plugin. ([#304](https://github.com/rojo-rbx/rojo/pull/304))
* Class names no longer need to be specified for Roblox services in Rojo projects. ([#210](https://github.com/rojo-rbx/rojo/pull/210))
* The server half of **experimental** two-way sync is now enabled by default.
* Increased default logging verbosity in commands like `rojo build`.
* Rojo now requires a project file again, just like 0.5.4.
## [0.6.0 Alpha 3](https://github.com/rojo-rbx/rojo/releases/tag/v0.6.0-alpha.3) (March 13, 2020)
* Added `--watch` argument to `rojo build`. ([#284](https://github.com/rojo-rbx/rojo/pull/284))
* Added dark theme support to plugin. ([#241](https://github.com/rojo-rbx/rojo/issues/241))
* Added a revamped `rojo init` command, which will now create more complete projects.
* Added the `rojo doc` command, which opens Rojo's documentation in your browser.
* Fixed many crashes from malformed projects and filesystem edge cases in `rojo serve`.
* Simplified filesystem access code dramatically.
* Improved error reporting and logging across the board.
* Log messages have a less noisy prefix.
* Any thread panicking now causes Rojo to abort instead of existing as a zombie.
* Errors now have a list of causes, helping make many errors more clear.
## [0.6.0 Alpha 2](https://github.com/rojo-rbx/rojo/releases/tag/v0.6.0-alpha.2) (March 6, 2020)
* Fixed `rojo upload` command always uploading models.
* Removed `--kind` parameter to `rojo upload`; Rojo now automatically uploads the correct kind of asset based on your project file.
## [0.5.4](https://github.com/rojo-rbx/rojo/releases/tag/v0.5.4) (February 26, 2020)
This is a general maintenance release for the Rojo 0.5.x release series.
* Updated reflection database and other dependencies.
* First stable release with binaries for macOS and Linux.
## [0.6.0 Alpha 1](https://github.com/rojo-rbx/rojo/releases/tag/v0.6.0-alpha.1) (January 22, 2020)
### General
* Added support for nested project files. ([#95](https://github.com/rojo-rbx/rojo/issues/95))
* Added project file hot-reloading. ([#10](https://github.com/rojo-rbx/rojo/issues/10)])
* Fixed Rojo dropping Ref properties ([#142](https://github.com/rojo-rbx/rojo/issues/142))
* This means that properties like `PrimaryPart` now work!
* Improved live sync protocol to reduce round-trips and improve syncing consistency.
* Improved support for binary model files and places.
### Command Line
* Added `--verbose`/`-v` flag, which can be specified multiple times to increase verbosity.
* Added support for automatically finding Roblox Studio's auth cookie for `rojo upload` on Windows.
* Added support for building, serving and uploading sources that aren't Rojo projects.
* Improved feedback from `rojo serve`.
* Removed support for legacy `roblox-project.json` projects, deprecated in an early Rojo 0.5.0 alpha.
* Rojo no longer traverses directories upwards looking for project files.
* Though undocumented, Rojo 0.5.x will search for a project file contained in any ancestor folders. This feature was removed to better support other 0.6.x features.
### Roblox Studio Plugin
* Added "connecting" state to improve experience when live syncing.
* Added "error" state to show errors in a place that isn't the output panel.
* Improved diagnostics for when the Rojo plugin cannot create an instance.
## [0.5.3](https://github.com/rojo-rbx/rojo/releases/tag/v0.5.3) (October 15, 2019)
* Fixed an issue where Rojo would throw an error when encountering recently-added instance classes.
## [0.5.2](https://github.com/rojo-rbx/rojo/releases/tag/v0.5.2) (October 14, 2019)
* Fixed an issue where `LocalizationTable` instances would have their column order randomized. ([#173](https://github.com/rojo-rbx/rojo/issues/173))
## [0.5.1](https://github.com/rojo-rbx/rojo/releases/tag/v0.5.1) (October 4, 2019)
* Fixed an issue where Rojo would drop changes if they happened too quickly ([#252](https://github.com/rojo-rbx/rojo/issues/252))
* Improved diagnostics for when the Rojo plugin cannot create an instance.
* Updated dependencies
* This brings Rojo's reflection database from client release 395 to client release 404.
## [0.5.0](https://github.com/rojo-rbx/rojo/releases/tag/v0.5.0) (August 27, 2019) ## [0.5.0](https://github.com/rojo-rbx/rojo/releases/tag/v0.5.0) (August 27, 2019)
* Changed `.model.json` naming, which may require projects to migrate ambiguous cases: * Changed `.model.json` naming, which may require projects to migrate ambiguous cases:
* The file name now takes precedence over the `Name` field in the model, like Rojo 0.4.x. * The file name now takes precedence over the `Name` field in the model, like Rojo 0.4.x.
@@ -50,7 +141,7 @@
## [0.5.0 Alpha 9](https://github.com/rojo-rbx/rojo/releases/tag/v0.5.0-alpha.9) (April 4, 2019) ## [0.5.0 Alpha 9](https://github.com/rojo-rbx/rojo/releases/tag/v0.5.0-alpha.9) (April 4, 2019)
* Changed `rojo build` to use buffered I/O, which can make it up to 2x faster in some cases. * Changed `rojo build` to use buffered I/O, which can make it up to 2x faster in some cases.
* Building [*Road Not Taken*](https://github.com/rojo-rbx/roads) to an `rbxlx` file dropped from 150ms to 70ms on my machine * Building [*Road Not Taken*](https://github.com/LPGhatguy/roads) to an `rbxlx` file dropped from 150ms to 70ms on my machine
* Fixed `LocalizationTable` instances being made from `csv` files incorrectly interpreting empty rows and columns. ([#149](https://github.com/rojo-rbx/rojo/pull/149)) * Fixed `LocalizationTable` instances being made from `csv` files incorrectly interpreting empty rows and columns. ([#149](https://github.com/rojo-rbx/rojo/pull/149))
* Fixed CSV files with entries that parse as numbers causing Rojo to panic. ([#152](https://github.com/rojo-rbx/rojo/pull/152)) * Fixed CSV files with entries that parse as numbers causing Rojo to panic. ([#152](https://github.com/rojo-rbx/rojo/pull/152))
* Improved error messages when malformed CSV files are found in a Rojo project. * Improved error messages when malformed CSV files are found in a Rojo project.
@@ -247,4 +338,4 @@
* More robust syncing with a new reconciler * More robust syncing with a new reconciler
## [0.1.0](https://github.com/rojo-rbx/rojo/releases/tag/v0.1.0) (November 29, 2017) ## [0.1.0](https://github.com/rojo-rbx/rojo/releases/tag/v0.1.0) (November 29, 2017)
* Initial release, functionally very similar to [rbxfs](https://github.com/rojo-rbx/rbxfs) * Initial release, functionally very similar to [rbxfs](https://github.com/LPGhatguy/rbxfs)

View File

@@ -1,5 +1,5 @@
# Contributing to the Rojo Project # Contributing to the Rojo Project
Rojo is a big project and can always use more help! This guide covers all repositories underneath the [rojo-rbx organization on GitHub](https://github.com/rojo-rbx). Rojo is a big project and can always use more help!
Some of the repositories covered are: Some of the repositories covered are:
@@ -11,6 +11,12 @@ Some of the repositories covered are:
## Code ## Code
Code contributions are welcome for features and bugs that have been reported in the project's bug tracker. We want to make sure that no one wastes their time, so be sure to talk with maintainers about what changes would be accepted before doing any work! Code contributions are welcome for features and bugs that have been reported in the project's bug tracker. We want to make sure that no one wastes their time, so be sure to talk with maintainers about what changes would be accepted before doing any work!
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)
## Documentation ## Documentation
Documentation impacts way more people than the individual lines of code we write. Documentation impacts way more people than the individual lines of code we write.
@@ -26,15 +32,13 @@ Please file issues and we'll try to help figure out what the best way forward is
## Pushing a Rojo Release ## Pushing a Rojo Release
The Rojo release process is pretty manual right now. If you need to do it, here's how: The Rojo release process is pretty manual right now. If you need to do it, here's how:
1. Bump server version in [`server/Cargo.toml`](server/Cargo.toml) 1. Bump server version in [`Cargo.toml`](Cargo.toml)
2. Bump plugin version in [`plugin/src/Config.lua`](plugin/src/Config.lua) 2. Bump plugin version in [`plugin/src/Config.lua`](plugin/src/Config.lua)
3. Run `cargo test` to update `Cargo.lock` and double-check tests 3. Run `cargo test` to update `Cargo.lock` and double-check tests
4. Update [`CHANGELOG.md`](CHANGELOG.md) 4. Update [`CHANGELOG.md`](CHANGELOG.md)
5. Commit! 5. Commit!
* `git add . && git commit -m "Release vX.Y.Z"` * `git add . && git commit -m "Release vX.Y.Z"`
6. Tag the commit with the version from `Cargo.toml` prepended with a v, like `v0.4.13` 6. Tag the commit with the version from `Cargo.toml` prepended with a v, like `v0.4.13`
7. Build Windows release build of CLI
* `cargo build --release`
7. Publish the CLI 7. Publish the CLI
* `cargo publish` * `cargo publish`
8. Build and upload the plugin 8. Build and upload the plugin
@@ -45,4 +49,5 @@ The Rojo release process is pretty manual right now. If you need to do it, here'
10. Copy GitHub release content from previous release 10. Copy GitHub release content from previous release
* Update the leading text with a summary about the release * Update the leading text with a summary about the release
* Paste the changelog notes (as-is!) from [`CHANGELOG.md`](CHANGELOG.md) * Paste the changelog notes (as-is!) from [`CHANGELOG.md`](CHANGELOG.md)
* Write a small summary of each major feature * Write a small summary of each major feature
* Attach release artifacts from GitHub Actions for each platform

2780
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,105 @@
[workspace] [package]
members = [ name = "rojo"
"server", version = "6.0.0-rc.4"
"rojo-test", authors = ["Lucien Greathouse <me@lpghatguy.com>"]
description = "Enables professional-grade development tools for Roblox developers"
license = "MPL-2.0"
homepage = "https://rojo.space"
documentation = "https://rojo.space/docs"
repository = "https://github.com/rojo-rbx/rojo"
readme = "README.md"
edition = "2018"
exclude = [
"/test-projects/**",
] ]
[profile.dev] [profile.dev]
opt-level = 1 panic = "abort"
[profile.release]
panic = "abort"
[features]
default = []
# Enable this feature to live-reload assets from the web UI.
dev_live_assets = []
[workspace]
members = [
"rojo-insta-ext",
"memofs",
]
[lib]
name = "librojo"
path = "src/lib.rs"
[[bin]]
name = "rojo"
path = "src/bin.rs"
[[bench]]
name = "build"
harness = false
[dependencies]
memofs = { version = "0.1.2", path = "memofs" }
anyhow = "1.0.27"
backtrace = "0.3"
bincode = "1.2.1"
crossbeam-channel = "0.4.0"
csv = "1.1.1"
env_logger = "0.7.1"
fs-err = "2.2.0"
futures = "0.1.29"
globset = "0.4.4"
humantime = "1.3.0"
hyper = "0.12.35"
jod-thread = "0.1.0"
lazy_static = "1.4.0"
log = "0.4.8"
maplit = "1.0.1"
notify = "4.0.14"
opener = "0.4.1"
rbx_binary = "0.5.0"
rbx_dom_weak = "1.10.1"
rbx_reflection = "3.3.408"
rbx_xml = "0.11.3"
regex = "1.3.1"
reqwest = "0.9.20"
ritz = "0.1.0"
rlua = "0.17.0"
roblox_install = "0.2.2"
serde = { version = "1.0", features = ["derive", "rc"] }
serde_json = "1.0"
structopt = "0.3.5"
termcolor = "1.0.5"
thiserror = "1.0.11"
tokio = "0.1.22"
uuid = { version = "0.8.1", features = ["v4", "serde"] }
[target.'cfg(windows)'.dependencies]
winreg = "0.6.2"
[build-dependencies]
memofs = { version = "0.1.3", path = "memofs" }
anyhow = "1.0.27"
bincode = "1.2.1"
fs-err = "2.3.0"
maplit = "1.0.1"
[dev-dependencies]
rojo-insta-ext = { path = "rojo-insta-ext" }
criterion = "0.3"
insta = { version = "1.3.0", features = ["redactions"] }
lazy_static = "1.2"
paste = "0.1"
pretty_assertions = "0.6.1"
serde_yaml = "0.8.9"
tempfile = "3.0"
walkdir = "2.1"

View File

@@ -7,17 +7,14 @@
<div>&nbsp;</div> <div>&nbsp;</div>
<div align="center"> <div align="center">
<a href="https://travis-ci.org/rojo-rbx/rojo"> <a href="https://github.com/rojo-rbx/rojo/actions">
<img src="https://api.travis-ci.org/rojo-rbx/rojo.svg?branch=master" alt="Travis-CI Build Status" /> <img src="https://github.com/rojo-rbx/rojo/workflows/CI/badge.svg" alt="Actions status" />
</a> </a>
<a href="https://crates.io/crates/rojo"> <a href="https://crates.io/crates/rojo">
<img src="https://img.shields.io/crates/v/rojo.svg?label=version" alt="Latest server version" /> <img src="https://img.shields.io/crates/v/rojo.svg?label=latest%20release" alt="Latest server version" />
</a> </a>
<a href="https://rojo.space/docs/0.4.x"> <a href="https://rojo.space/docs">
<img src="https://img.shields.io/badge/docs-0.4.x-brightgreen.svg" alt="Rojo 0.4.x Documentation" /> <img src="https://img.shields.io/badge/docs-website-brightgreen.svg" alt="Rojo Documentation" />
</a>
<a href="https://rojo.space/docs/0.5.x">
<img src="https://img.shields.io/badge/docs-0.5.x-brightgreen.svg" alt="Rojo 0.5.x Documentation" />
</a> </a>
</div> </div>
@@ -37,22 +34,21 @@ Rojo enables:
* Streaming `rbxmx` and `rbxm` models into your game in real time * Streaming `rbxmx` and `rbxm` models into your game in real time
* Packaging and deploying your project to Roblox.com from the command line * Packaging and deploying your project to Roblox.com from the command line
Soon, Rojo will be able to: In the future, Rojo will be able to:
* Automatically convert your existing game to work with Rojo
* Sync instances from Roblox Studio to the filesystem * Sync instances from Roblox Studio to the filesystem
* Automatically manage your assets on Roblox.com, like images and sounds * Automatically convert your existing game to work with Rojo
* Import custom instances like MoonScript code * Import custom instances like MoonScript code
## [Documentation](https://rojo.space/docs/latest) ## [Documentation](https://rojo.space/docs)
If you find any mistakes, feel free to make changes in the [docs](https://github.com/rojo-rbx/rojo/tree/master/docs) folder of this repository and submit a pull request! Documentation is hosted in the [rojo.space repository](https://github.com/rojo-rbx/rojo.space).
## Contributing ## Contributing
Check out our [contribution guide](CONTRIBUTING.md) for detailed instructions for helping work on Rojo! Check out our [contribution guide](CONTRIBUTING.md) for detailed instructions for helping work on Rojo!
Pull requests are welcome! Pull requests are welcome!
Rojo supports Rust 1.34.0 and newer. The minimum supported version of Rust is based on the latest versions of the dependencies that Rojo has. Rojo supports Rust 1.43.1 and newer. The minimum supported version of Rust is based on the latest versions of the dependencies that Rojo has.
## License ## License
Rojo is available under the terms of the Mozilla Public License, Version 2.0. See [LICENSE.txt](LICENSE.txt) for details. Rojo is available under the terms of the Mozilla Public License, Version 2.0. See [LICENSE.txt](LICENSE.txt) for details.

View File

@@ -0,0 +1,11 @@
# {project_name}
Generated by [Rojo](https://github.com/rojo-rbx/rojo) {rojo_version}.
## Getting Started
To build this library or plugin, use:
```bash
rojo build -o "{project_name}.rbxmx"
```
For more help, check out [the Rojo documentation](https://rojo.space/docs).

View File

@@ -0,0 +1,6 @@
{
"name": "{project_name}",
"tree": {
"$path": "src"
}
}

View File

@@ -0,0 +1,3 @@
# Roblox Studio lock files
/*.rbxlx.lock
/*.rbxl.lock

View File

@@ -0,0 +1,5 @@
return {
hello = function()
print("Hello world, from {project_name}!")
end,
}

View File

@@ -0,0 +1,17 @@
# {project_name}
Generated by [Rojo](https://github.com/rojo-rbx/rojo) {rojo_version}.
## Getting Started
To build the place from scratch, use:
```bash
rojo build -o "{project_name}.rbxlx"
```
Next, open `{project_name}.rbxlx` in Roblox Studio and start the Rojo server:
```bash
rojo serve
```
For more help, check out [the Rojo documentation](https://rojo.space/docs).

View File

@@ -1,41 +1,29 @@
{ {
"name": "[placeholder]", "name": "{project_name}",
"tree": { "tree": {
"$className": "DataModel", "$className": "DataModel",
"HttpService": {
"$className": "HttpService",
"$properties": {
"HttpEnabled": true
}
},
"Lighting": {
"$className": "Lighting",
"$properties": {
"Ambient": [
0,
0,
0
],
"Brightness": 2,
"GlobalShadows": true,
"Outlines": false,
"Technology": "Voxel"
}
},
"ReplicatedStorage": { "ReplicatedStorage": {
"$className": "ReplicatedStorage", "Common": {
"Source": { "$path": "src/shared"
"$path": "src"
} }
}, },
"SoundService": {
"$className": "SoundService", "ServerScriptService": {
"$properties": { "Server": {
"RespectFilteringEnabled": true "$path": "src/server"
} }
}, },
"StarterPlayer": {
"StarterPlayerScripts": {
"Client": {
"$path": "src/client"
}
}
},
"Workspace": { "Workspace": {
"$className": "Workspace",
"$properties": { "$properties": {
"FilteringEnabled": true "FilteringEnabled": true
}, },
@@ -61,6 +49,24 @@
] ]
} }
} }
},
"Lighting": {
"$properties": {
"Ambient": [
0,
0,
0
],
"Brightness": 2,
"GlobalShadows": true,
"Outlines": false,
"Technology": "Voxel"
}
},
"SoundService": {
"$properties": {
"RespectFilteringEnabled": true
}
} }
} }
} }

View File

@@ -0,0 +1,6 @@
# Project place file
/{project_name}.rbxlx
# Roblox Studio lock files
/*.rbxlx.lock
/*.rbxl.lock

BIN
assets/icon-32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 B

BIN
assets/images/back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

5
assets/images/back.svg Normal file
View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<path d="M20,11L20,13L8,13L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11L20,11Z" style="fill:white;fill-rule:nonzero;"/>
</svg>

After

Width:  |  Height:  |  Size: 584 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<g transform="matrix(1,0,0,1,-54,-1)">
<g id="Artboard3" transform="matrix(1.77778,0,0,1.45455,-42,-0.454545)">
<rect x="54" y="1" width="9" height="11" style="fill:none;"/>
<g transform="matrix(3.375,0,0,4.125,-3654,-2753.12)">
<path d="M1099,670L1101,668" style="fill:none;stroke:white;stroke-width:0.5px;"/>
<g transform="matrix(-1,0,0,1,2200,0)">
<path d="M1099,670L1101,668" style="fill:none;stroke:white;stroke-width:0.5px;"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<g transform="matrix(1,0,0,1,-32,0)">
<g id="Artboard2" transform="matrix(0.8,0,0,0.941176,6.4,0)">
<rect x="32" y="0" width="20" height="17" style="fill:none;"/>
<g transform="matrix(5,0,0,4.25,-5470.5,-2371.5)">
<path d="M1101,560L1102,561L1104,559" style="fill:none;stroke:white;stroke-width:0.75px;"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 870 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
assets/images/circle-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

BIN
assets/images/circle-32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

BIN
assets/images/circle-64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

BIN
assets/images/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

15
assets/images/close.svg Normal file
View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<g id="Artboard1" transform="matrix(0.0666667,0,0,0.097561,-31,-18.6341)">
<rect x="465" y="191" width="360" height="246" style="fill:none;"/>
<g transform="matrix(134.328,0,0,102.5,-74228.5,-15214.7)">
<g transform="matrix(1.11667,0,0,1,-57.3333,0)">
<path d="M551,152L550,151" style="fill:none;stroke:white;stroke-width:0.3px;"/>
</g>
<g transform="matrix(1.11667,0,0,1,-57.3333,0)">
<path d="M550,152L551,151" style="fill:none;stroke:white;stroke-width:0.3px;"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 60 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g id="Artboard1" transform="matrix(0.952381,0,0,0.710526,-228.571,-156.316)">
<rect x="240" y="220" width="63" height="38" style="fill:none;"/>
<g transform="matrix(0.0789166,0,0,0.105779,211.848,170.749)">
<g transform="matrix(340.635,0,0,340.635,376,753)">
<path d="M0.302,-0.836L0.306,-0.836L0.302,-0.829L0.302,-0.814C0.333,-0.82 0.349,-0.828 0.349,-0.836L0.371,-0.833C0.408,-0.835 0.441,-0.836 0.472,-0.836L0.476,-0.836C0.524,-0.836 0.58,-0.81 0.646,-0.757C0.66,-0.734 0.668,-0.714 0.672,-0.695L0.672,-0.659C0.664,-0.609 0.65,-0.571 0.632,-0.546C0.621,-0.537 0.597,-0.507 0.56,-0.456L0.556,-0.456L0.556,-0.463L0.566,-0.478L0.56,-0.478C0.474,-0.405 0.378,-0.349 0.27,-0.311C0.243,-0.304 0.216,-0.3 0.19,-0.3C0.224,-0.26 0.287,-0.207 0.378,-0.141C0.387,-0.136 0.445,-0.099 0.552,-0.028C0.641,0.027 0.747,0.087 0.871,0.153L0.871,0.157L0.856,0.157C0.832,0.148 0.82,0.141 0.82,0.138L0.813,0.142L0.806,0.142C0.803,0.142 0.802,0.141 0.802,0.138C0.793,0.14 0.786,0.149 0.78,0.164C0.795,0.168 0.802,0.173 0.802,0.178C0.796,0.183 0.792,0.186 0.788,0.186L0.77,0.182L0.77,0.186C0.77,0.19 0.773,0.193 0.78,0.193L0.78,0.204L0.777,0.204C0.772,0.204 0.717,0.172 0.614,0.109C0.541,0.072 0.451,0.015 0.346,-0.061C0.311,-0.077 0.247,-0.124 0.153,-0.202L0.143,-0.202C0.129,-0.181 0.111,-0.129 0.088,-0.046C0.083,-0.027 0.059,0.001 0.016,0.037L0.008,0.037L0.001,0.026L0.001,0.022C0.001,0.017 0.005,0.006 0.012,-0.01L0.012,-0.014L0.008,-0.014C0.008,-0.007 -0.007,0.004 -0.035,0.019L-0.039,0.019L-0.039,0.012C0.046,-0.24 0.105,-0.404 0.139,-0.481C0.197,-0.614 0.226,-0.69 0.226,-0.709C0.213,-0.709 0.184,-0.693 0.139,-0.659L0.132,-0.659L0.135,-0.666L0.135,-0.673C0.122,-0.673 0.092,-0.652 0.045,-0.608L0.041,-0.608L0.041,-0.612L0.088,-0.666L0.096,-0.677L0.096,-0.681L0.088,-0.681L0.045,-0.645C0.04,-0.645 0.038,-0.647 0.038,-0.651C0.083,-0.701 0.138,-0.744 0.204,-0.778C0.265,-0.794 0.295,-0.812 0.295,-0.833L0.302,-0.836ZM0.632,-0.735L0.632,-0.731C0.632,-0.727 0.635,-0.724 0.639,-0.724L0.639,-0.728C0.639,-0.732 0.637,-0.735 0.632,-0.735ZM0.208,-0.387L0.211,-0.387C0.255,-0.396 0.277,-0.403 0.277,-0.409C0.274,-0.414 0.273,-0.417 0.273,-0.42C0.365,-0.451 0.427,-0.482 0.458,-0.514C0.461,-0.514 0.48,-0.534 0.516,-0.576L0.52,-0.576L0.52,-0.572C0.515,-0.564 0.512,-0.558 0.512,-0.554L0.516,-0.554C0.547,-0.578 0.563,-0.604 0.563,-0.633L0.563,-0.655C0.556,-0.655 0.552,-0.658 0.552,-0.663C0.564,-0.665 0.57,-0.671 0.57,-0.681C0.57,-0.693 0.546,-0.705 0.498,-0.717C0.459,-0.727 0.417,-0.731 0.371,-0.731C0.348,-0.731 0.325,-0.689 0.302,-0.604C0.292,-0.594 0.261,-0.522 0.208,-0.387ZM0.251,-0.695L0.251,-0.691C0.255,-0.691 0.258,-0.695 0.262,-0.702L0.262,-0.706C0.259,-0.706 0.255,-0.702 0.251,-0.695ZM0.255,-0.626L0.259,-0.626C0.266,-0.629 0.27,-0.636 0.27,-0.648C0.266,-0.648 0.261,-0.641 0.255,-0.626ZM0.596,-0.612L0.596,-0.604C0.599,-0.604 0.603,-0.608 0.606,-0.615L0.606,-0.619L0.603,-0.619C0.598,-0.618 0.596,-0.616 0.596,-0.612ZM0.204,-0.369L0.204,-0.365L0.211,-0.365C0.216,-0.368 0.22,-0.369 0.222,-0.369L0.222,-0.365C0.281,-0.376 0.316,-0.388 0.328,-0.401L0.324,-0.401C0.271,-0.389 0.231,-0.378 0.204,-0.369ZM0.19,-0.333L0.193,-0.333L0.259,-0.347L0.255,-0.354C0.212,-0.349 0.19,-0.341 0.19,-0.333ZM0.334,-0.108L0.334,-0.101C0.372,-0.072 0.395,-0.057 0.403,-0.057C0.394,-0.064 0.389,-0.07 0.389,-0.075L0.334,-0.108ZM0.44,-0.028C0.442,-0.019 0.449,-0.014 0.461,-0.014L0.465,-0.014L0.465,-0.018C0.459,-0.018 0.452,-0.021 0.443,-0.028L0.44,-0.028ZM0.675,0.102C0.694,0.119 0.723,0.136 0.762,0.153L0.766,0.146C0.736,0.128 0.708,0.113 0.683,0.102L0.675,0.102ZM0.875,0.16L0.886,0.16C0.89,0.161 0.893,0.163 0.893,0.167C0.888,0.167 0.886,0.171 0.886,0.178L0.878,0.178L0.882,0.171L0.882,0.167L0.875,0.167L0.875,0.16Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(340.635,0,0,340.635,588.398,753)">
<path d="M0.631,-0.705C0.646,-0.705 0.661,-0.696 0.673,-0.678L0.646,-0.678C0.62,-0.678 0.587,-0.67 0.546,-0.653L0.546,-0.65L0.549,-0.65C0.607,-0.654 0.649,-0.656 0.677,-0.656L0.683,-0.656L0.683,-0.65L0.67,-0.65C0.668,-0.65 0.667,-0.651 0.667,-0.653L0.503,-0.629C0.503,-0.627 0.493,-0.624 0.473,-0.62L0.473,-0.614L0.519,-0.623L0.521,-0.623L0.521,-0.617C0.386,-0.581 0.318,-0.555 0.318,-0.538C0.252,-0.483 0.204,-0.431 0.175,-0.383C0.131,-0.304 0.108,-0.243 0.108,-0.201C0.108,-0.157 0.131,-0.125 0.175,-0.104C0.183,-0.102 0.19,-0.101 0.196,-0.101C0.286,-0.136 0.353,-0.196 0.397,-0.28C0.409,-0.318 0.419,-0.363 0.427,-0.417L0.434,-0.417L0.427,-0.359C0.433,-0.359 0.439,-0.374 0.443,-0.404C0.441,-0.412 0.439,-0.42 0.439,-0.429L0.439,-0.438L0.446,-0.438C0.448,-0.407 0.449,-0.386 0.449,-0.374C0.449,-0.358 0.444,-0.331 0.434,-0.292C0.445,-0.302 0.458,-0.335 0.473,-0.392C0.48,-0.447 0.486,-0.474 0.491,-0.474C0.491,-0.472 0.492,-0.471 0.494,-0.471C0.492,-0.469 0.49,-0.457 0.488,-0.435L0.488,-0.432L0.491,-0.432C0.499,-0.454 0.504,-0.48 0.506,-0.508C0.502,-0.516 0.5,-0.522 0.5,-0.526L0.506,-0.529C0.512,-0.529 0.518,-0.513 0.525,-0.48C0.525,-0.4 0.491,-0.297 0.424,-0.17C0.372,-0.093 0.305,-0.042 0.224,-0.019C0.188,-0.006 0.154,-0 0.121,-0C0.04,-0.022 -0.001,-0.083 -0.001,-0.183C-0.001,-0.296 0.045,-0.398 0.136,-0.489C0.165,-0.522 0.227,-0.568 0.321,-0.629C0.425,-0.68 0.529,-0.705 0.631,-0.705ZM0.482,-0.656L0.482,-0.653C0.499,-0.653 0.508,-0.652 0.509,-0.65C0.526,-0.659 0.536,-0.663 0.54,-0.663L0.54,-0.668L0.482,-0.656ZM0.099,-0.417C0.144,-0.458 0.179,-0.494 0.206,-0.523C0.23,-0.538 0.242,-0.55 0.242,-0.559C0.201,-0.535 0.156,-0.493 0.108,-0.432C0.102,-0.427 0.099,-0.422 0.099,-0.417ZM0.105,-0.261C0.108,-0.261 0.118,-0.284 0.136,-0.328C0.158,-0.378 0.203,-0.439 0.272,-0.511L0.272,-0.514C0.204,-0.463 0.167,-0.422 0.16,-0.392C0.142,-0.371 0.124,-0.328 0.105,-0.261ZM0.069,-0.334L0.069,-0.332L0.072,-0.332C0.116,-0.393 0.139,-0.429 0.139,-0.438C0.11,-0.413 0.086,-0.378 0.069,-0.334ZM0.467,-0.31L0.467,-0.307L0.47,-0.307C0.492,-0.371 0.503,-0.413 0.503,-0.432C0.49,-0.409 0.478,-0.369 0.467,-0.31ZM0.087,-0.404L0.087,-0.401C0.091,-0.401 0.093,-0.403 0.093,-0.407L0.093,-0.41C0.089,-0.41 0.087,-0.408 0.087,-0.404ZM0.063,-0.368C0.032,-0.297 0.017,-0.245 0.017,-0.213C0.021,-0.148 0.028,-0.107 0.039,-0.088L0.042,-0.088L0.042,-0.094C0.035,-0.107 0.032,-0.129 0.032,-0.158C0.032,-0.191 0.035,-0.227 0.042,-0.268L0.039,-0.273C0.045,-0.3 0.054,-0.331 0.066,-0.365L0.066,-0.368L0.063,-0.368ZM0.096,-0.24L0.096,-0.237C0.1,-0.237 0.103,-0.239 0.103,-0.243L0.103,-0.246C0.098,-0.245 0.096,-0.243 0.096,-0.24ZM0.397,-0.222L0.397,-0.219L0.4,-0.219C0.408,-0.232 0.412,-0.241 0.412,-0.243C0.407,-0.242 0.402,-0.235 0.397,-0.222ZM0.066,-0.24C0.06,-0.222 0.055,-0.202 0.051,-0.179C0.055,-0.138 0.061,-0.108 0.069,-0.088L0.072,-0.088L0.072,-0.094C0.066,-0.121 0.063,-0.139 0.063,-0.146L0.066,-0.152C0.064,-0.155 0.063,-0.16 0.063,-0.164C0.063,-0.169 0.064,-0.173 0.066,-0.176C0.064,-0.18 0.063,-0.183 0.063,-0.186C0.067,-0.218 0.069,-0.235 0.069,-0.237L0.069,-0.24L0.066,-0.24ZM0.294,-0.125L0.294,-0.122C0.3,-0.122 0.322,-0.143 0.357,-0.186L0.357,-0.188L0.354,-0.188C0.314,-0.151 0.294,-0.129 0.294,-0.125ZM0.379,-0.149C0.379,-0.146 0.36,-0.126 0.321,-0.088L0.324,-0.088C0.351,-0.112 0.37,-0.132 0.382,-0.146L0.385,-0.146L0.385,-0.149L0.379,-0.149ZM0.09,-0.104L0.09,-0.101C0.094,-0.08 0.104,-0.07 0.121,-0.07L0.13,-0.07L0.13,-0.073L0.09,-0.104ZM0.151,-0.055L0.188,-0.055L0.203,-0.058L0.203,-0.061L0.157,-0.061C0.153,-0.06 0.151,-0.058 0.151,-0.055ZM0.096,-0.058L0.096,-0.055C0.104,-0.045 0.113,-0.04 0.124,-0.04L0.13,-0.04L0.13,-0.042C0.127,-0.042 0.116,-0.048 0.096,-0.058Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(340.635,0,0,340.635,758.882,753)">
<path d="M0.208,-0.7L0.223,-0.7C0.227,-0.7 0.229,-0.697 0.229,-0.691C0.294,-0.687 0.328,-0.684 0.331,-0.682C0.333,-0.682 0.333,-0.683 0.333,-0.685C0.364,-0.683 0.387,-0.682 0.401,-0.682L0.462,-0.682C0.466,-0.682 0.468,-0.684 0.468,-0.688L0.45,-0.688L0.45,-0.694L0.49,-0.694L0.49,-0.688L0.475,-0.688L0.475,-0.682L0.557,-0.682C0.564,-0.682 0.573,-0.681 0.584,-0.679C0.603,-0.681 0.612,-0.685 0.612,-0.691L0.658,-0.691C0.678,-0.691 0.688,-0.692 0.689,-0.694C0.706,-0.692 0.72,-0.691 0.731,-0.691L0.903,-0.691L0.921,-0.688L0.928,-0.691C1.035,-0.686 1.096,-0.681 1.111,-0.676L1.13,-0.682L1.13,-0.676L1.068,-0.667L1.068,-0.664C1.075,-0.664 1.078,-0.661 1.078,-0.657C1.078,-0.654 1.075,-0.651 1.068,-0.648C1.064,-0.65 1.061,-0.651 1.059,-0.651C1.059,-0.647 1.055,-0.645 1.047,-0.645L1.047,-0.642C1.048,-0.638 1.05,-0.636 1.053,-0.636L1.059,-0.636C1.072,-0.636 1.087,-0.635 1.105,-0.633C1.113,-0.635 1.12,-0.636 1.126,-0.636C1.139,-0.625 1.145,-0.619 1.145,-0.618C1.138,-0.613 1.132,-0.611 1.126,-0.611L1.099,-0.611C1.088,-0.611 1.079,-0.608 1.071,-0.602L1.029,-0.602C1.024,-0.602 1.02,-0.603 1.017,-0.605L1.01,-0.602C0.993,-0.604 0.98,-0.605 0.971,-0.605C0.962,-0.605 0.958,-0.604 0.958,-0.602L0.928,-0.605L0.695,-0.605C0.69,-0.605 0.686,-0.604 0.683,-0.602C0.679,-0.604 0.675,-0.605 0.67,-0.605L0.563,-0.605C0.555,-0.605 0.547,-0.604 0.539,-0.602C0.531,-0.604 0.523,-0.605 0.514,-0.605L0.453,-0.605C0.429,-0.578 0.401,-0.525 0.37,-0.446C0.37,-0.439 0.334,-0.358 0.263,-0.201L0.177,-0.021C0.185,-0.001 0.189,0.011 0.189,0.013C0.186,0.013 0.177,0.001 0.162,-0.023L0.156,-0.023L0.153,-0.008C0.159,-0.001 0.162,0.006 0.162,0.013L0.162,0.017L0.15,0.007L0.128,0.007C0.128,-0.005 0.108,-0.045 0.067,-0.112C0.012,-0.235 -0.028,-0.332 -0.052,-0.403L-0.052,-0.412C-0.048,-0.412 -0.046,-0.409 -0.046,-0.403L-0.043,-0.403C-0.039,-0.403 -0.037,-0.405 -0.037,-0.409L-0.046,-0.443L-0.046,-0.446L-0.04,-0.446L0.034,-0.293L0.037,-0.293L0.037,-0.296C0.008,-0.37 -0.006,-0.41 -0.006,-0.416L-0.006,-0.421C0.009,-0.398 0.037,-0.343 0.076,-0.256C0.118,-0.177 0.142,-0.135 0.147,-0.13C0.212,-0.285 0.285,-0.442 0.364,-0.602C0.36,-0.602 0.358,-0.604 0.358,-0.608L0.352,-0.605L0.333,-0.605C0.332,-0.605 0.331,-0.606 0.331,-0.608C0.327,-0.606 0.324,-0.605 0.321,-0.605L0.315,-0.608C0.313,-0.608 0.312,-0.607 0.312,-0.605L0.291,-0.608L0.263,-0.608C0.263,-0.615 0.261,-0.618 0.257,-0.618L0.254,-0.618C0.247,-0.618 0.215,-0.621 0.159,-0.626L0.159,-0.63L0.162,-0.636L0.156,-0.636L0.156,-0.639C0.156,-0.641 0.163,-0.646 0.177,-0.654L0.184,-0.654L0.189,-0.651C0.189,-0.653 0.191,-0.659 0.193,-0.669C0.188,-0.671 0.178,-0.674 0.162,-0.676L0.162,-0.682L0.184,-0.682C0.191,-0.682 0.199,-0.688 0.208,-0.7ZM0.291,-0.697L0.352,-0.697C0.356,-0.697 0.358,-0.694 0.358,-0.691L0.291,-0.691L0.291,-0.697ZM0.41,-0.694L0.419,-0.694L0.419,-0.688L0.41,-0.688L0.41,-0.694ZM0.505,-0.694L0.533,-0.694L0.533,-0.688L0.505,-0.688L0.505,-0.694ZM0.603,-0.694L0.603,-0.691C0.603,-0.687 0.601,-0.685 0.597,-0.685L0.563,-0.685L0.563,-0.691L0.588,-0.691L0.603,-0.694ZM0.202,-0.667L0.202,-0.664L0.239,-0.664L0.239,-0.667L0.202,-0.667ZM0.269,-0.339L0.266,-0.327L0.266,-0.324L0.269,-0.324L0.272,-0.336L0.272,-0.339L0.269,-0.339ZM0.257,-0.308C0.237,-0.266 0.211,-0.205 0.177,-0.125C0.195,-0.147 0.223,-0.207 0.26,-0.305L0.26,-0.308L0.257,-0.308Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(340.635,0,0,340.635,891.444,753)">
<path d="M0.631,-0.705C0.646,-0.705 0.661,-0.696 0.673,-0.678L0.646,-0.678C0.62,-0.678 0.587,-0.67 0.546,-0.653L0.546,-0.65L0.549,-0.65C0.607,-0.654 0.649,-0.656 0.677,-0.656L0.683,-0.656L0.683,-0.65L0.67,-0.65C0.668,-0.65 0.667,-0.651 0.667,-0.653L0.503,-0.629C0.503,-0.627 0.493,-0.624 0.473,-0.62L0.473,-0.614L0.519,-0.623L0.521,-0.623L0.521,-0.617C0.386,-0.581 0.318,-0.555 0.318,-0.538C0.252,-0.483 0.204,-0.431 0.175,-0.383C0.131,-0.304 0.108,-0.243 0.108,-0.201C0.108,-0.157 0.131,-0.125 0.175,-0.104C0.183,-0.102 0.19,-0.101 0.196,-0.101C0.286,-0.136 0.353,-0.196 0.397,-0.28C0.409,-0.318 0.419,-0.363 0.427,-0.417L0.434,-0.417L0.427,-0.359C0.433,-0.359 0.439,-0.374 0.443,-0.404C0.441,-0.412 0.439,-0.42 0.439,-0.429L0.439,-0.438L0.446,-0.438C0.448,-0.407 0.449,-0.386 0.449,-0.374C0.449,-0.358 0.444,-0.331 0.434,-0.292C0.445,-0.302 0.458,-0.335 0.473,-0.392C0.48,-0.447 0.486,-0.474 0.491,-0.474C0.491,-0.472 0.492,-0.471 0.494,-0.471C0.492,-0.469 0.49,-0.457 0.488,-0.435L0.488,-0.432L0.491,-0.432C0.499,-0.454 0.504,-0.48 0.506,-0.508C0.502,-0.516 0.5,-0.522 0.5,-0.526L0.506,-0.529C0.512,-0.529 0.518,-0.513 0.525,-0.48C0.525,-0.4 0.491,-0.297 0.424,-0.17C0.372,-0.093 0.305,-0.042 0.224,-0.019C0.188,-0.006 0.154,-0 0.121,-0C0.04,-0.022 -0.001,-0.083 -0.001,-0.183C-0.001,-0.296 0.045,-0.398 0.136,-0.489C0.165,-0.522 0.227,-0.568 0.321,-0.629C0.425,-0.68 0.529,-0.705 0.631,-0.705ZM0.482,-0.656L0.482,-0.653C0.499,-0.653 0.508,-0.652 0.509,-0.65C0.526,-0.659 0.536,-0.663 0.54,-0.663L0.54,-0.668L0.482,-0.656ZM0.099,-0.417C0.144,-0.458 0.179,-0.494 0.206,-0.523C0.23,-0.538 0.242,-0.55 0.242,-0.559C0.201,-0.535 0.156,-0.493 0.108,-0.432C0.102,-0.427 0.099,-0.422 0.099,-0.417ZM0.105,-0.261C0.108,-0.261 0.118,-0.284 0.136,-0.328C0.158,-0.378 0.203,-0.439 0.272,-0.511L0.272,-0.514C0.204,-0.463 0.167,-0.422 0.16,-0.392C0.142,-0.371 0.124,-0.328 0.105,-0.261ZM0.069,-0.334L0.069,-0.332L0.072,-0.332C0.116,-0.393 0.139,-0.429 0.139,-0.438C0.11,-0.413 0.086,-0.378 0.069,-0.334ZM0.467,-0.31L0.467,-0.307L0.47,-0.307C0.492,-0.371 0.503,-0.413 0.503,-0.432C0.49,-0.409 0.478,-0.369 0.467,-0.31ZM0.087,-0.404L0.087,-0.401C0.091,-0.401 0.093,-0.403 0.093,-0.407L0.093,-0.41C0.089,-0.41 0.087,-0.408 0.087,-0.404ZM0.063,-0.368C0.032,-0.297 0.017,-0.245 0.017,-0.213C0.021,-0.148 0.028,-0.107 0.039,-0.088L0.042,-0.088L0.042,-0.094C0.035,-0.107 0.032,-0.129 0.032,-0.158C0.032,-0.191 0.035,-0.227 0.042,-0.268L0.039,-0.273C0.045,-0.3 0.054,-0.331 0.066,-0.365L0.066,-0.368L0.063,-0.368ZM0.096,-0.24L0.096,-0.237C0.1,-0.237 0.103,-0.239 0.103,-0.243L0.103,-0.246C0.098,-0.245 0.096,-0.243 0.096,-0.24ZM0.397,-0.222L0.397,-0.219L0.4,-0.219C0.408,-0.232 0.412,-0.241 0.412,-0.243C0.407,-0.242 0.402,-0.235 0.397,-0.222ZM0.066,-0.24C0.06,-0.222 0.055,-0.202 0.051,-0.179C0.055,-0.138 0.061,-0.108 0.069,-0.088L0.072,-0.088L0.072,-0.094C0.066,-0.121 0.063,-0.139 0.063,-0.146L0.066,-0.152C0.064,-0.155 0.063,-0.16 0.063,-0.164C0.063,-0.169 0.064,-0.173 0.066,-0.176C0.064,-0.18 0.063,-0.183 0.063,-0.186C0.067,-0.218 0.069,-0.235 0.069,-0.237L0.069,-0.24L0.066,-0.24ZM0.294,-0.125L0.294,-0.122C0.3,-0.122 0.322,-0.143 0.357,-0.186L0.357,-0.188L0.354,-0.188C0.314,-0.151 0.294,-0.129 0.294,-0.125ZM0.379,-0.149C0.379,-0.146 0.36,-0.126 0.321,-0.088L0.324,-0.088C0.351,-0.112 0.37,-0.132 0.382,-0.146L0.385,-0.146L0.385,-0.149L0.379,-0.149ZM0.09,-0.104L0.09,-0.101C0.094,-0.08 0.104,-0.07 0.121,-0.07L0.13,-0.07L0.13,-0.073L0.09,-0.104ZM0.151,-0.055L0.188,-0.055L0.203,-0.058L0.203,-0.061L0.157,-0.061C0.153,-0.06 0.151,-0.058 0.151,-0.055ZM0.096,-0.058L0.096,-0.055C0.104,-0.045 0.113,-0.04 0.124,-0.04L0.13,-0.04L0.13,-0.042C0.127,-0.042 0.116,-0.048 0.096,-0.058Z" style="fill:white;fill-rule:nonzero;"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 9 7" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,0,-10)">
<g id="Bottom" transform="matrix(0.243243,0,0,0.179487,-59.1081,-30.2051)">
<rect x="243" y="224" width="37" height="39" style="fill:none;"/>
<clipPath id="_clip1">
<rect x="243" y="224" width="37" height="39"/>
</clipPath>
<g clip-path="url(#_clip1)">
<g transform="matrix(-4.11111,6.82303e-16,-3.59619e-16,-3.97959,280,259.816)">
<path d="M7,5.5C7,3.568 5.88,2 4.5,2C3.12,2 2,3.568 2,5.5L2,9L7,9L7,5.5Z" style="fill:white;"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 B

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 9 1" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,0,-8)">
<g id="Middle" transform="matrix(1,0,0,0.111111,0,7.11111)">
<rect x="0" y="8" width="9" height="9" style="fill:none;"/>
<g transform="matrix(1,0,0,9,0,-64)">
<rect x="2" y="8" width="5" height="1" style="fill:white;"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 796 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 9 7" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g id="Top" transform="matrix(0.243243,0,0,0.179487,-59.1081,-40.2051)">
<rect x="243" y="224" width="37" height="39" style="fill:none;"/>
<g transform="matrix(4.11111,0,0,3.97959,243,227.184)">
<path d="M7,5.5C7,3.568 5.88,2 4.5,2C3.12,2 2,3.568 2,5.5L2,9L7,9L7,5.5Z" style="fill:white;"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 793 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g id="Artboard1" transform="matrix(0.5,0,0,0.5,0,0)">
<rect x="0" y="0" width="48" height="48" style="fill:none;"/>
<path d="M24,0C37.246,0 48,10.754 48,24C48,37.246 37.246,48 24,48C10.754,48 0,37.246 0,24C0,10.754 10.754,0 24,0ZM24,8.4C32.61,8.4 39.6,15.39 39.6,24C39.6,32.61 32.61,39.6 24,39.6C15.39,39.6 8.4,32.61 8.4,24C8.4,15.39 15.39,8.4 24,8.4Z" style="fill:white;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 855 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g id="Artboard1" transform="matrix(0.5,0,0,0.5,0,0)">
<rect x="0" y="0" width="48" height="48" style="fill:none;"/>
<path d="M48,24C48,10.745 37.255,0 24,0L24,8.4C32.616,8.4 39.6,15.384 39.6,24L48,24Z" style="fill:white;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 704 B

181
assets/index.css Normal file
View File

@@ -0,0 +1,181 @@
* {
margin: 0;
padding: 0;
border: none;
text-decoration: inherit;
color: inherit;
font: inherit;
box-sizing: inherit;
line-height: inherit;
}
html {
box-sizing: border-box;
font-family: sans-serif;
font-size: 18px;
text-decoration: none;
line-height: 1.4;
}
img {
max-width:100%;
max-height:100%;
height: auto;
}
.path-list > li {
margin-left: 1.2em;
font-family: monospace;
}
.root {
display: flex;
flex-direction: column;
margin: 0.5rem auto;
width: 100%;
max-width: 50rem;
background-color: #efefef;
border: 1px solid #666;
border-radius: 4px;
}
.header {
flex: 0 0;
display: flex;
flex-wrap: wrap;
align-items: center;
border-bottom: 1px solid #666;
}
.main {
padding: 1rem;
}
.main-logo {
flex: 0 0 10rem;
margin: 1rem;
}
.stats {
flex: 0 0 20rem;
margin: 1rem;
}
.stat {
display: block;
}
.stat-name {
display: inline;
font-weight: bold;
}
.main-section:not(:last-of-type) {
margin-bottom: 1rem;
}
.section-title {
font-size: 1.8rem;
}
.button-list {
flex: 0 0;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
margin: -1rem;
}
.button {
display: inline-block;
border: 1px solid #666;
padding: 0.3em 1em;
margin: 1rem;
}
.instance {
margin-bottom: 0.5rem;
}
.instance-title {
font-size: 1.2rem;
padding: 0.5rem;
}
.expandable-section {
margin: 0.25rem 0.5rem;
}
.expandable-items {
padding: 0.5rem 1rem;
}
.expandable-input {
display: none;
}
.expandable-label > label {
cursor: pointer;
display: flex;
align-items: center;
align-content: center;
}
.expandable-input ~ .expandable-label .expandable-visualizer {
font-family: monospace;
display: inline-flex;
align-items: center;
align-content: center;
text-align: center;
width: 1rem;
height: 1rem;
font-size: 2rem;
margin: 0 0.5rem;
transition: transform 100ms ease-in-out;
transform-origin: 60% 60%;
}
.expandable-visualizer::before {
content: "";
font-weight: bold;
}
.expandable-input:checked ~ .expandable-label {
border-bottom: 1px solid #bbb;
}
.expandable-input:checked ~ .expandable-label .expandable-visualizer {
transform: rotate(90deg);
}
.expandable-input:not(:checked) ~ .expandable-items {
display: none;
}
.vfs-entry {
}
.vfs-entry-name {
position: relative;
font-family: monospace;
}
.vfs-entry-children .vfs-entry-name::before {
content: "";
width: 0.6em;
height: 1px;
background-color: #999;
position: absolute;
top: 50%;
left: -0.8em;
}
.vfs-entry-note {
font-style: italic;
}
.vfs-entry-children {
padding-left: 0.8em;
margin-left: 0.2em;
border-left: 1px solid #999;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,41 +0,0 @@
<TextureAtlas imagePath="sheet.png">
<SubTexture name="grey_arrowDownGrey.png" x="78" y="498" width="15" height="10"/>
<SubTexture name="grey_arrowDownWhite.png" x="123" y="496" width="15" height="10"/>
<SubTexture name="grey_arrowUpGrey.png" x="108" y="498" width="15" height="10"/>
<SubTexture name="grey_arrowUpWhite.png" x="93" y="498" width="15" height="10"/>
<SubTexture name="grey_box.png" x="147" y="433" width="38" height="36"/>
<SubTexture name="grey_boxCheckmark.png" x="147" y="469" width="38" height="36"/>
<SubTexture name="grey_boxCross.png" x="185" y="433" width="38" height="36"/>
<SubTexture name="grey_boxTick.png" x="190" y="198" width="36" height="36"/>
<SubTexture name="grey_button00.png" x="0" y="143" width="190" height="45"/>
<SubTexture name="grey_button01.png" x="0" y="188" width="190" height="49"/>
<SubTexture name="grey_button02.png" x="0" y="98" width="190" height="45"/>
<SubTexture name="grey_button03.png" x="0" y="331" width="190" height="49"/>
<SubTexture name="grey_button04.png" x="0" y="286" width="190" height="45"/>
<SubTexture name="grey_button05.png" x="0" y="0" width="195" height="49"/>
<SubTexture name="grey_button06.png" x="0" y="49" width="191" height="49"/>
<SubTexture name="grey_button07.png" x="195" y="0" width="49" height="49"/>
<SubTexture name="grey_button08.png" x="240" y="49" width="49" height="49"/>
<SubTexture name="grey_button09.png" x="98" y="433" width="49" height="45"/>
<SubTexture name="grey_button10.png" x="191" y="49" width="49" height="49"/>
<SubTexture name="grey_button11.png" x="0" y="433" width="49" height="45"/>
<SubTexture name="grey_button12.png" x="244" y="0" width="49" height="49"/>
<SubTexture name="grey_button13.png" x="49" y="433" width="49" height="45"/>
<SubTexture name="grey_button14.png" x="0" y="384" width="190" height="49"/>
<SubTexture name="grey_button15.png" x="0" y="237" width="190" height="49"/>
<SubTexture name="grey_checkmarkGrey.png" x="99" y="478" width="21" height="20"/>
<SubTexture name="grey_checkmarkWhite.png" x="78" y="478" width="21" height="20"/>
<SubTexture name="grey_circle.png" x="185" y="469" width="36" height="36"/>
<SubTexture name="grey_crossGrey.png" x="120" y="478" width="18" height="18"/>
<SubTexture name="grey_crossWhite.png" x="190" y="318" width="18" height="18"/>
<SubTexture name="grey_panel.png" x="190" y="98" width="100" height="100"/>
<SubTexture name="grey_sliderDown.png" x="190" y="234" width="28" height="42"/>
<SubTexture name="grey_sliderEnd.png" x="138" y="478" width="8" height="10"/>
<SubTexture name="grey_sliderHorizontal.png" x="0" y="380" width="190" height="4"/>
<SubTexture name="grey_sliderLeft.png" x="0" y="478" width="39" height="31"/>
<SubTexture name="grey_sliderRight.png" x="39" y="478" width="39" height="31"/>
<SubTexture name="grey_sliderUp.png" x="190" y="276" width="28" height="42"/>
<SubTexture name="grey_sliderVertical.png" x="208" y="318" width="4" height="100"/>
<SubTexture name="grey_tickGrey.png" x="190" y="336" width="17" height="17"/>
<SubTexture name="grey_tickWhite.png" x="190" y="353" width="17" height="17"/>
</TextureAtlas>

BIN
assets/test-folder.rbxm Normal file

Binary file not shown.

43
benches/build.rs Normal file
View File

@@ -0,0 +1,43 @@
use std::path::Path;
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use tempfile::{tempdir, TempDir};
use librojo::cli::{build, BuildCommand};
pub fn benchmark_small_place(c: &mut Criterion) {
bench_build_place(c, "Small Place", "test-projects/benchmark_small_place")
}
criterion_group!(benches, benchmark_small_place);
criterion_main!(benches);
fn bench_build_place(c: &mut Criterion, name: &str, path: &str) {
let mut group = c.benchmark_group(name);
// 'rojo build' generally takes a fair bit of time to execute.
group.sample_size(10);
group.bench_function("build", |b| {
b.iter_batched(
|| place_setup(path),
|(_dir, options)| build(options).unwrap(),
BatchSize::SmallInput,
)
});
group.finish();
}
fn place_setup<P: AsRef<Path>>(input_path: P) -> (TempDir, BuildCommand) {
let dir = tempdir().unwrap();
let input = input_path.as_ref().to_path_buf();
let output = dir.path().join("output.rbxlx");
let options = BuildCommand {
project: input,
watch: false,
output,
};
(dir, options)
}

5
bin/dev-plugin.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/sh
set -e
watchexec -c -w plugin "sh -c './bin/install-dev-plugin.sh'"

13
bin/install-dev-plugin.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/sh
set -e
DIR="$( mktemp -d )"
PLUGIN_FILE="$DIR/Rojo.rbxm"
TESTEZ_FILE="$DIR/TestEZ.rbxm"
rojo build plugin -o "$PLUGIN_FILE"
rojo build plugin/testez.project.json -o "$TESTEZ_FILE"
remodel bin/mark-plugin-as-dev.lua "$PLUGIN_FILE" "$TESTEZ_FILE" 2>/dev/null
cp "$PLUGIN_FILE" "$LOCALAPPDATA/Roblox/Plugins/Rojo.rbxm"

5
bin/install-release-plugin.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/sh
set -e
rojo build plugin -o "$LOCALAPPDATA/Roblox/Plugins/Rojo.rbxm"

View File

@@ -0,0 +1,12 @@
local pluginPath, testezPath = ...
local plugin = remodel.readModelFile(pluginPath)[1]
local testez = remodel.readModelFile(testezPath)[1]
local marker = Instance.new("Folder")
marker.Name = "ROJO_DEV_BUILD"
marker.Parent = plugin
testez.Parent = plugin
remodel.writeModelFile(plugin, pluginPath)

View File

@@ -0,0 +1,8 @@
local pluginPath, placePath = ...
local plugin = remodel.readModelFile(pluginPath)[1]
local place = remodel.readPlaceFile(placePath)
plugin.Parent = place:GetService("ReplicatedStorage")
remodel.writePlaceFile(place, placePath)

6
bin/run-all-tests.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh
set -e
./bin/run-cli-tests.sh
./bin/run-plugin-tests.sh

9
bin/run-cli-tests.sh Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/sh
set -e
cargo test --all --locked
cargo fmt -- --check
touch src/lib.rs # Nudge Rust source to make Clippy actually check things
cargo clippy

16
bin/run-plugin-tests.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
set -e
DIR="$( mktemp -d )"
PLUGIN_FILE="$DIR/Rojo.rbxmx"
PLACE_FILE="$DIR/RojoTestPlace.rbxlx"
rojo build plugin -o "$PLUGIN_FILE"
rojo build plugin/place.project.json -o "$PLACE_FILE"
remodel bin/put-plugin-in-test-place.lua "$PLUGIN_FILE" "$PLACE_FILE"
run-in-roblox -s plugin/testBootstrap.server.lua "$PLACE_FILE"
luacheck plugin/src plugin/log plugin/http

View File

@@ -1,21 +0,0 @@
#!/bin/sh
# Copies a project from 'test-projects' into a folder that can be messed with
# without accidentally checking the results into version control.
set -e
if [ ! -d "test-projects/$1" ]
then
echo "Pick a project that exists!"
exit 1
fi
if [ -d "scratch-project/$1" ]
then
rm -rf "scratch-project/$1"
fi
mkdir -p scratch-project
cp -r "test-projects/$1" scratch-project
cargo run -- serve "scratch-project/$1"

77
build.rs Normal file
View File

@@ -0,0 +1,77 @@
use std::{
env, io,
path::{Path, PathBuf},
};
use fs_err as fs;
use fs_err::File;
use maplit::hashmap;
use memofs::VfsSnapshot;
fn snapshot_from_fs_path(path: &Path) -> io::Result<VfsSnapshot> {
println!("cargo:rerun-if-changed={}", path.display());
if path.is_dir() {
let mut children = Vec::new();
for entry in fs::read_dir(path)? {
let entry = entry?;
let file_name = entry.file_name().to_str().unwrap().to_owned();
// We can skip any TestEZ test files since they aren't necessary for
// the plugin to run.
if file_name.ends_with(".spec.lua") {
continue;
}
let child_snapshot = snapshot_from_fs_path(&entry.path())?;
children.push((file_name, child_snapshot));
}
Ok(VfsSnapshot::dir(children))
} else {
let content = fs::read_to_string(path)?;
Ok(VfsSnapshot::file(content))
}
}
fn main() -> Result<(), anyhow::Error> {
let out_dir = env::var_os("OUT_DIR").unwrap();
let root_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap();
let plugin_root = PathBuf::from(root_dir).join("plugin");
let plugin_modules = plugin_root.join("modules");
let snapshot = VfsSnapshot::dir(hashmap! {
"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"))?,
"modules" => VfsSnapshot::dir(hashmap! {
"roact" => VfsSnapshot::dir(hashmap! {
"src" => snapshot_from_fs_path(&plugin_modules.join("roact").join("src"))?
}),
"promise" => VfsSnapshot::dir(hashmap! {
"lib" => snapshot_from_fs_path(&plugin_modules.join("promise").join("lib"))?
}),
"t" => VfsSnapshot::dir(hashmap! {
"lib" => snapshot_from_fs_path(&plugin_modules.join("t").join("lib"))?
}),
"flipper" => VfsSnapshot::dir(hashmap! {
"src" => snapshot_from_fs_path(&plugin_modules.join("flipper").join("src"))?
}),
}),
});
let out_path = Path::new(&out_dir).join("plugin.bincode");
let out_file = File::create(&out_path)?;
bincode::serialize_into(out_file, &snapshot)?;
Ok(())
}

View File

@@ -1,13 +0,0 @@
.md-typeset__table {
width: 100%;
}
.feature-image img {
border: 1px solid rgba(0, 0, 0, 0.2);
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.2);
}
.codehilite {
border: 1px solid rgba(0, 0, 0, 0.2);
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.2);
}

View File

@@ -1,11 +0,0 @@
**This page is under construction!**
## Summary
* Tools to port existing games are in progress!
* [rbxlx-to-rojo](https://github.com/rojo-rbx/rbxlx-to-rojo)
* `rojo export` ([issue #208](https://github.com/rojo-rbx/rojo/issues/208))
* Can port as much or as little of your game as you like
* Rojo can manage just a slice of your game!
* Some Roblox idioms aren't very well supported
* Redundant copies of scripts don't work well with files
* Having only a couple places with scripts simplifies your project dramatically!

View File

@@ -1,46 +0,0 @@
This is this installation guide for Rojo **0.5.x**.
[TOC]
## Overview
Rojo has two components:
* The command line interface (CLI)
* The Roblox Studio plugin
!!! info
It's important that your installed version of the plugin and CLI are compatible.
The plugin will show errors in the Roblox Studio output window if there is a version mismatch.
## Visual Studio Code Extension
If you use Visual Studio Code, you can install [the Rojo VS Code extension](https://marketplace.visualstudio.com/items?itemName=evaera.vscode-rojo), which will install both halves of Rojo for you. It even has a nifty UI to sync files and start/stop the Rojo server!
## Installing the CLI
### Installing from GitHub
If you're on Windows, there are pre-built binaries available from Rojo's [GitHub Releases page](https://github.com/LPGhatguy/rojo/releases).
The Rojo CLI must be run from the command line, like Terminal.app on MacOS or `cmd.exe` on Windows. It's recommended that you put the Rojo CLI executable on your `PATH` to make this easier.
### Installing from Cargo
If you have Rust installed, the easiest way to get Rojo is with Cargo!
To install the latest 0.5.0 alpha, use:
```sh
cargo install rojo --version 0.5.0-alpha.13
```
## Installing the Plugin
### Installing from GitHub
The Rojo Roblox Studio plugin is available from Rojo's [GitHub Releases page](https://github.com/LPGhatguy/rojo/releases).
Download the attached `rbxm` file and put it into your Roblox Studio plugins folder. You can find that folder by pressing **Plugins Folder** from your Plugins toolbar in Roblox Studio:
!['Plugins Folder' button in Roblox Studio](../images/plugins-folder-in-studio.png)
{: align="center" }
### Installing from Roblox.com
Visit [Rojo's Roblox.com Plugin page](https://www.roblox.com/library/1997686364/Rojo-0-5-0-alpha-3) in Roblox Studio and press **Install**.

View File

@@ -1,63 +0,0 @@
Rojo underwent a large refactor during most of 2018 to enable a bunch of new features and lay groundwork for lots more in 2019. As such, Rojo **0.5.x** projects are not compatible with Rojo **0.4.x** projects.
[TOC]
## Supporting Both 0.4.x and 0.5.x
Rojo 0.5.x uses a different name for its project format. While 0.4.x used `rojo.json`, 0.5.x uses `default.project.json`, which allows them to coexist.
If you aren't sure about upgrading or want to upgrade gradually, it's possible to keep both files in the same project without causing problems.
## Upgrading Your Project File
Project files in 0.5.x are more explicit and flexible than they were in 0.4.x. Project files can now describe models and plugins in addition to places.
This new project file format also guards against two of the biggest pitfalls when writing a config file:
* Using a service as a partition target directly, which often wiped away extra instances
* Defining two partitions that overlapped, which made Rojo act unpredictably
The biggest change is that the `partitions` field has been replaced with a new field, `tree`, that describes the entire hierarchy of your project from the top-down.
A project for 0.4.x that syncs from the `src` directory into `ReplicatedStorage.Source` would look like this:
```json
{
"name": "Rojo 0.4.x Example",
"partitions": {
"path": "src",
"target": "ReplicatedStorage.Source"
}
}
```
In 0.5.x, the project format is more explicit:
```json
{
"name": "Rojo 0.5.x Example",
"tree": {
"$className": "DataModel",
"ReplicatedStorage": {
"$className": "ReplicatedStorage",
"Source": {
"$path": "src"
}
}
}
}
```
For each object in the tree, we define *metadata* and *children*.
Metadata begins with a dollar sign (`$`), like `$className`. This is so that children and metadata can coexist without creating too many nested layers.
All other values are considered children, where the key is the instance's name, and the value is an object, repeating the process.
## Migrating Unknown Files
If you used Rojo to sync in files as `StringValue` objects, you'll need to make sure those files end with the `txt` extension to preserve this in Rojo 0.5.x.
Unknown files are now ignored in Rojo instead of being converted to `StringValue` objects.
## Migrating `init.model.json` files
In Rojo 0.4.x, it's possible to create a file named `init.model.json` that lets you describe a model that becomes the container for all of the other files in the folder, just like `init.lua`.
In Rojo 0.5.x, this feature has been replaced with `init.meta.json` files. See [Sync Details](../reference/sync-details) for more information about these new files.

View File

@@ -1,90 +0,0 @@
[TOC]
## Creating the Rojo Project
To use Rojo to build a game, you'll need to create a new project file, which tells Rojo how to turn your files into a Roblox place.
First, create a new folder to contain the files for your game and open up a new terminal inside of it, like cmd.exe or Bash.
It's convenient to make the folder from the command line:
```sh
mkdir my-new-project
cd my-new-project
```
Inside the folder, initialize a new Rojo project:
```sh
rojo init
```
Rojo will make a small project file in your directory, named `default.project.json`. It matches the "Baseplate" template from Roblox Studio, except that it'll take any files you put in a folder called `src` and put it into `ReplicatedStorage.Source`.
Speaking of files, make sure to create a directory named `src` in this folder, or Rojo will be upset about missing files!
```sh
mkdir src
```
Let's also add a Lua file, `hello.lua` to the `src` folder, so that we can make this project our own.
```sh
echo 'return "Hello, Rojo!"' > src/hello.lua
```
## Building Your Place
Now that we have a project, one thing we can do is build a Roblox place file for our project. This is a great way to get started with a project quickly with no fuss.
All we have to do is call `rojo build`:
```sh
rojo build -o MyNewProject.rbxlx
```
If you open `MyNewProject.rbxlx` in Roblox Studio now, you should see a `Folder` named "Source" containing a `ModuleScript` under `ReplicatedStorage`.
!!! info
To generate a binary place file instead, use `rbxl`. Note that support for binary model/place files (`rbxm` and `rbxl`) is very limited in Rojo presently.
## Live-Syncing into Studio
Building a place file is great for starting to work on a game, but for active iteration, you'll want something faster.
In Roblox Studio, make sure the Rojo plugin is installed. If you need it, check out [the installation guide](../installation) to learn how to install it.
To expose your project to the plugin, you'll need to start a new **live sync session** from the command line:
```sh
rojo serve
```
You should see output like this in your terminal:
```sh
$ rojo serve
Rojo server listening on port 34872
```
Switch into Roblox Studio and press the **Connect** button on the Rojo plugin toolbar. A dialog should appear:
![Rojo plugin connection dialog](../images/connection-dialog.png)
{: class="feature-image" align="center" }
If the port number doesn't match the output from the command line, change it, and then press **Connect**.
If all went well, you should now be able to change files in the `src` directory and watch them sync into Roblox Studio in real time!
## Uploading Your Place
Aimed at teams that want serious levels of automation, Rojo can upload places to Roblox.com automatically.
You'll need an existing game on Roblox.com as well as the `.ROBLOSECURITY` cookie of an account that has write access to that game.
!!! warning
It's recommended that you set up a Roblox account dedicated to deploying your game instead of your personal account in case your security cookie is compromised.
Generating and publishing your game is as simple as:
```sh
rojo upload --asset_id [PLACE ID] --cookie "[SECURITY COOKIE]"
```
An example project is available on GitHub that deploys to Roblox.com from GitHub and Travis-CI automatically: [https://github.com/LPGhatguy/roads](https://github.com/LPGhatguy/roads)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -1,17 +0,0 @@
digraph "Sync Files" {
graph [
ranksep = "0.7",
nodesep = "0.5",
];
node [
fontname = "monospace",
shape = "record",
];
my_model [label = "MyModel"]
init_server [label = "init.server.lua"]
foo [label = "foo.lua"]
my_model -> init_server
my_model -> foo
}

View File

@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: Sync Files Pages: 1 -->
<svg width="258pt" height="132pt"
viewBox="0.00 0.00 258.00 132.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 128)">
<title>Sync Files</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-128 254,-128 254,4 -4,4"/>
<!-- my_model -->
<g id="node1" class="node"><title>my_model</title>
<polygon fill="none" stroke="black" points="104,-87.5 104,-123.5 178,-123.5 178,-87.5 104,-87.5"/>
<text text-anchor="middle" x="141" y="-101.8" font-family="monospace" font-size="14.00">MyModel</text>
</g>
<!-- init_server -->
<g id="node2" class="node"><title>init_server</title>
<polygon fill="none" stroke="black" points="0,-0.5 0,-36.5 140,-36.5 140,-0.5 0,-0.5"/>
<text text-anchor="middle" x="70" y="-14.8" font-family="monospace" font-size="14.00">init.server.lua</text>
</g>
<!-- my_model&#45;&gt;init_server -->
<g id="edge1" class="edge"><title>my_model&#45;&gt;init_server</title>
<path fill="none" stroke="black" d="M126.632,-87.299C116.335,-74.9713 102.308,-58.1787 90.7907,-44.3902"/>
<polygon fill="black" stroke="black" points="93.4435,-42.1065 84.3465,-36.6754 88.0711,-46.594 93.4435,-42.1065"/>
</g>
<!-- foo -->
<g id="node3" class="node"><title>foo</title>
<polygon fill="none" stroke="black" points="176,-0.5 176,-36.5 250,-36.5 250,-0.5 176,-0.5"/>
<text text-anchor="middle" x="213" y="-14.8" font-family="monospace" font-size="14.00">foo.lua</text>
</g>
<!-- my_model&#45;&gt;foo -->
<g id="edge2" class="edge"><title>my_model&#45;&gt;foo</title>
<path fill="none" stroke="black" d="M155.57,-87.299C166.013,-74.9713 180.237,-58.1787 191.917,-44.3902"/>
<polygon fill="black" stroke="black" points="194.659,-46.5681 198.451,-36.6754 189.317,-42.0437 194.659,-46.5681"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1,15 +0,0 @@
digraph "Sync Files" {
graph [
ranksep = "0.7",
nodesep = "0.5",
];
node [
fontname = "monospace",
shape = "record",
];
my_model [label = "MyModel (Script)"]
foo [label = "foo (ModuleScript)"]
my_model -> foo
}

View File

@@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: Sync Files Pages: 1 -->
<svg width="173pt" height="132pt"
viewBox="0.00 0.00 173.00 132.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 128)">
<title>Sync Files</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-128 169,-128 169,4 -4,4"/>
<!-- my_model -->
<g id="node1" class="node"><title>my_model</title>
<polygon fill="none" stroke="black" points="8,-87.5 8,-123.5 157,-123.5 157,-87.5 8,-87.5"/>
<text text-anchor="middle" x="82.5" y="-101.8" font-family="monospace" font-size="14.00">MyModel (Script)</text>
</g>
<!-- foo -->
<g id="node2" class="node"><title>foo</title>
<polygon fill="none" stroke="black" points="0,-0.5 0,-36.5 165,-36.5 165,-0.5 0,-0.5"/>
<text text-anchor="middle" x="82.5" y="-14.8" font-family="monospace" font-size="14.00">foo (ModuleScript)</text>
</g>
<!-- my_model&#45;&gt;foo -->
<g id="edge1" class="edge"><title>my_model&#45;&gt;foo</title>
<path fill="none" stroke="black" d="M82.5,-87.299C82.5,-75.6626 82.5,-60.0479 82.5,-46.7368"/>
<polygon fill="black" stroke="black" points="86.0001,-46.6754 82.5,-36.6754 79.0001,-46.6755 86.0001,-46.6754"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,17 +0,0 @@
digraph "Sync Files" {
graph [
ranksep = "0.7",
nodesep = "0.5",
];
node [
fontname = "monospace",
shape = "record",
];
model [label = "My Cool Model (Folder)"]
root_part [label = "RootPart (Part)"]
send_money [label = "SendMoney (RemoteEvent)"]
model -> root_part
model -> send_money
}

View File

@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: Sync Files Pages: 1 -->
<svg width="390pt" height="132pt"
viewBox="0.00 0.00 390.00 132.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 128)">
<title>Sync Files</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-128 386,-128 386,4 -4,4"/>
<!-- model -->
<g id="node1" class="node"><title>model</title>
<polygon fill="none" stroke="black" points="75,-87.5 75,-123.5 273,-123.5 273,-87.5 75,-87.5"/>
<text text-anchor="middle" x="174" y="-101.8" font-family="monospace" font-size="14.00">My Cool Model (Folder)</text>
</g>
<!-- root_part -->
<g id="node2" class="node"><title>root_part</title>
<polygon fill="none" stroke="black" points="0,-0.5 0,-36.5 140,-36.5 140,-0.5 0,-0.5"/>
<text text-anchor="middle" x="70" y="-14.8" font-family="monospace" font-size="14.00">RootPart (Part)</text>
</g>
<!-- model&#45;&gt;root_part -->
<g id="edge1" class="edge"><title>model&#45;&gt;root_part</title>
<path fill="none" stroke="black" d="M152.954,-87.299C137.448,-74.6257 116.168,-57.2335 99.0438,-43.2377"/>
<polygon fill="black" stroke="black" points="100.972,-40.2938 91.0147,-36.6754 96.5426,-45.7138 100.972,-40.2938"/>
</g>
<!-- send_money -->
<g id="node3" class="node"><title>send_money</title>
<polygon fill="none" stroke="black" points="176,-0.5 176,-36.5 382,-36.5 382,-0.5 176,-0.5"/>
<text text-anchor="middle" x="279" y="-14.8" font-family="monospace" font-size="14.00">SendMoney (RemoteEvent)</text>
</g>
<!-- model&#45;&gt;send_money -->
<g id="edge2" class="edge"><title>model&#45;&gt;send_money</title>
<path fill="none" stroke="black" d="M195.248,-87.299C210.904,-74.6257 232.388,-57.2335 249.677,-43.2377"/>
<polygon fill="black" stroke="black" points="252.213,-45.6878 257.783,-36.6754 247.809,-40.2471 252.213,-45.6878"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -1,11 +0,0 @@
This is the documentation home for Rojo 0.5.x.
Available versions of these docs:
* [Latest version (currently 0.5.x)](https://rojo.space/docs/latest)
* [0.5.x](https://rojo.space/docs/0.5.x)
* [0.4.x](https://rojo.space/docs/0.4.x)
**Rojo** is a flexible multi-tool designed for creating robust Roblox projects.
This documentation is a continual work in progress. If you find any issues, please file an issue on [Rojo's issue tracker](https://github.com/rojo-rbx/rojo/issues)!

View File

@@ -1,45 +0,0 @@
This document aims to give a general overview of how Rojo works. It's intended for people who want to contribute to the project as well as anyone who's just curious how the tool works!
[TOC]
## CLI
### RbxTree
Rojo uses a library named [`rbx_tree`](https://github.com/LPGhatguy/rbx-tree) as its implementation of the Roblox DOM. It serves as a common format for serialization to all the formats Rojo supports!
Rojo uses two related libraries to deserialize instances from Roblox's file formats, `rbx_xml` and `rbx_binary`.
### In-Memory Filesystem (IMFS)
Relevant source files:
* [`server/src/imfs.rs`](https://github.com/LPGhatguy/rojo/blob/master/server/src/imfs.rs)
* [`server/src/fs_watcher.rs`](https://github.com/LPGhatguy/rojo/blob/master/server/src/fs_watcher.rs)
Rojo keeps an in-memory copy of all files that it needs reasons about. This enables taking fast, stateless, tear-tree snapshots of files to turn them into instances.
Keeping an in-memory copy of file contents will also enable Rojo to debounce changes that are caused by Rojo itself. This'll happen when two-way sync finally happens.
### Snapshot Reconciler
Relevant source files:
* [`server/src/snapshot_reconciler.rs`](https://github.com/LPGhatguy/rojo/blob/master/server/src/snapshot_reconciler.rs)
* [`server/src/rbx_snapshot.rs`](https://github.com/LPGhatguy/rojo/blob/master/server/src/rbx_snapshot.rs)
* [`server/src/rbx_session.rs`](https://github.com/LPGhatguy/rojo/blob/master/server/src/rbx_session.rs)
To simplify incremental updates of instances, Rojo generates lightweight snapshots describing how files map to instances. This means that Rojo can treat file change events similarly to damage painting as opposed to trying to surgically update the correct instances.
This approach reduces the number of desynchronization bugs, reduces the complexity of important pieces of the codebase, and makes writing plugins a lot easier.
### HTTP API
Relevant source files:
* [`server/src/web.rs`](https://github.com/LPGhatguy/rojo/blob/master/server/src/web.rs)
The Rojo live-sync server and Roblox Studio plugin communicate via HTTP.
Requests sent from the plugin to the server are regular HTTP requests.
Messages sent from the server to the plugin are delivered via HTTP long-polling. This is an approach that uses long-lived HTTP requests that restart on timeout. It's largely been replaced by WebSockets, but Roblox doesn't have support for them.
## Roblox Studio Plugin
TODO

View File

@@ -1,37 +0,0 @@
Rojo is designed to be adopted incrementally. How much of your project Rojo manages is up to you!
There are two primary categories of ways to use Rojo: *Fully Managed*, where everything is managed by Rojo, and *Partially Managed*, where Rojo only manages a slice of your project.
## Fully Managed
In a fully managed game project, Rojo controls every instance. A fully managed Rojo project can be built from scratch using `rojo build`.
Fully managed projects are most practical for libraries, plugins, and simple games.
Rojo's goal is to make it practical and easy for _every_ project to be fully managed, but we're not quite there yet!
### Pros
* Fully reproducible builds from scratch
* Everything checked into version control
### Cons
* Without two-way sync, models have to be saved manually
* This can be done with the 'Save to File...' menu in Roblox Studio
* This will be solved by Two-Way Sync ([issue #164](https://github.com/LPGhatguy/rojo/issues/164))
* Rojo can't manage everything yet
* Refs are currently broken ([issue #142](https://github.com/LPGhatguy/rojo/issues/142))
## Partially Managed
In a partially managed project, Rojo only handles a slice of the game. This could be as small as a couple scripts, or as large as everything except `Workspace`!
The rest of the place's content can be versioned using Team Create or checked into source control.
Partially managed projects are most practical for complicated games, or games that are migrating to use Rojo.
### Pros
* Easier to adopt gradually
* Integrates with Team Create
### Cons
* Not everything is in version control, which makes merges tougher
* Rojo can't live-sync instances like Terrain, MeshPart, or CSG operations yet
* Will be fixed with plugin escalation ([issue #169](https://github.com/LPGhatguy/rojo/issues/169))

View File

@@ -1,151 +0,0 @@
[TOC]
## Project File
Rojo projects are JSON files that have the `.project.json` extension. They have the following fields:
* `name`: A string indicating the name of the project. This name is used when building the project into a model or place file.
* **Required**
* `tree`: An [Instance Description](#instance-description) describing the root instance of the project.
* **Required**
* `servePort`: The port that `rojo serve` should listen on. Passing `--port` will override this setting.
* **Optional**
* Default is `34872`
* `servePlaceIds`: A list of place IDs that this project may be live-synced to. This feature can help prevent overwriting the wrong game with source from Rojo.
* **Optional**
* Default is `null`
## Instance Description
Instance Descriptions correspond one-to-one with the actual Roblox Instances in the project.
* `$className`: The ClassName of the Instance being described.
* **Optional if `$path` is specified.**
* `$path`: The path on the filesystem to pull files from into the project.
* **Optional if `$className` is specified.**
* Paths are relative to the folder containing the project file.
* `$properties`: Properties to apply to the instance. Values should be [Instance Property Values](#instance-property-value).
* **Optional**
* `$ignoreUnknownInstances`: Whether instances that Rojo doesn't know about should be deleted.
* **Optional**
* Default is `false` if `$path` is specified, otherwise `true`.
All other fields in an Instance Description are turned into instances whose name is the key. These values should also be Instance Descriptions!
Instance Descriptions are fairly verbose and strict. In the future, it'll be possible for Rojo to [infer class names for known services like `Workspace`](https://github.com/LPGhatguy/rojo/issues/179).
## Instance Property Value
There are two kinds of property values on instances, **implicit** and **explicit**.
In the vast majority of cases, you should be able to use **implicit** property values. To use them, just use a value that's the same shape as the type that the property has:
```json
"MyPart": {
"$className": "Part",
"$properties": {
"Size": [3, 5, 3],
"Color": [0.5, 0, 0.5],
"Anchored": true,
"Material": "Granite"
}
}
```
`Vector3` and `Color3` properties can just be arrays of numbers, as can types like `Vector2`, `CFrame`, and more!
Enums can be set to a string containing the enum variant. Rojo will raise an error if the string isn't a valid variant for the enum.
There are some cases where this syntax for assigning properties _doesn't_ work. In these cases, Rojo requires you to use the **explicit** property syntax.
Some reasons why you might need to use an **explicit** property:
* Using exotic property types like `BinaryString`
* Using properties added to Roblox recently that Rojo doesn't know about yet
The shape of explicit property values is defined by the [rbx-dom](https://github.com/LPGhatguy/rbx-dom) library, so it uses slightly different conventions than the rest of Rojo.
Each value should be an object with the following required fields:
* `Type`: The type of property to represent.
* [Supported types can be found here](https://github.com/LPGhatguy/rbx-tree#property-type-coverage).
* `Value`: The value of the property.
* The shape of this field depends on which property type is being used. `Vector3` and `Color3` values are both represented as a list of numbers, while `BinaryString` expects a base64-encoded string, for example.
Here's the same object, but with explicit properties:
```json
"MyPart": {
"$className": "Part",
"$properties": {
"Size": {
"Type": "Vector3",
"Value": [3, 5, 3]
},
"Color": {
"Type": "Color3",
"Value": [0.5, 0, 0.5]
},
"Anchored": {
"Type": "Bool",
"Value": true
},
"Material": {
"Type": "Enum",
"Value": 832
}
}
}
```
## Example Projects
This project bundles up everything in the `src` directory. It'd be suitable for making a plugin or model:
```json
{
"name": "AwesomeLibrary",
"tree": {
"$path": "src"
}
}
```
This project describes the layout you might use if you were making the next hit simulator game, *Sisyphus Simulator*:
```json
{
"name": "Sisyphus Simulator",
"tree": {
"$className": "DataModel",
"HttpService": {
"$className": "HttpService",
"$properties": {
"HttpEnabled": true
}
},
"ReplicatedStorage": {
"$className": "ReplicatedStorage",
"$path": "src/ReplicatedStorage"
},
"StarterPlayer": {
"$className": "StarterPlayer",
"StarterPlayerScripts": {
"$className": "StarterPlayerScripts",
"$path": "src/StarterPlayerScripts"
}
},
"Workspace": {
"$className": "Workspace",
"$properties": {
"Gravity": 67.3
},
"Terrain": {
"$path": "Terrain.rbxm"
}
}
}
}
```

View File

@@ -1,149 +0,0 @@
This page aims to describe how Rojo turns files on the filesystem into Roblox objects.
[TOC]
## Overview
| File Name | Instance Type |
| -------------- | ------------------------- |
| any directory | `Folder` |
| `*.server.lua` | `Script` |
| `*.client.lua` | `LocalScript` |
| `*.lua` | `ModuleScript` |
| `*.csv` | `LocalizationTable` |
| `*.txt` | `StringValue` |
| `*.model.json` | Any |
| `*.rbxm` | Any |
| `*.rbxmx` | Any |
| `*.meta.json` | Modifies another instance |
## Limitations
Not all property types can be synced by Rojo in real-time due to limitations of the Roblox Studio plugin API. In these cases, you can usually generate a place file and open it when you start working on a project.
Some common cases you might hit are:
* Binary data (Terrain, CSG, CollectionService tags)
* `MeshPart.MeshId`
* `HttpService.HttpEnabled`
For a list of all property types that Rojo can reason about, both when live-syncing and when building place files, look at [rbx-dom's type coverage chart](https://github.com/rojo-rbx/rbx-dom#property-type-coverage).
This limitation may be solved by [issue #205](https://github.com/rojo-rbx/rojo/issues/205) in the future.
## Folders
Any directory on the filesystem will turn into a `Folder` instance unless it contains an 'init' script, described below.
## Scripts
The default script type in Rojo projects is `ModuleScript`, since most scripts in well-structued Roblox projects will be modules.
If a directory contains a file named `init.server.lua`, `init.client.lua`, or `init.lua`, that folder will be transformed into a `*Script` instance with the contents of the 'init' file. This can be used to create scripts inside of scripts.
For example, these files:
![Tree of files on disk](../images/sync-example-files.svg)
{: align="center" }
Will turn into these instances in Roblox:
![Tree of instances in Roblox](../images/sync-example-instances.svg)
{: align="center" }
## Localization Tables
Any CSV files are transformed into `LocalizationTable` instances. Rojo expects these files to follow the same format that Roblox does when importing and exporting localization information.
## Plain Text Files
Plain text files (`.txt`) files are transformed into `StringValue` instances. This is useful for bringing in text data that can be read by scripts at runtime.
## JSON Models
Files ending in `.model.json` can be used to describe simple models. They're designed to be hand-written and are useful for instances like `RemoteEvent`.
A JSON model describing a folder containing a `Part` and a `RemoteEvent` could be described as:
```json
{
"Name": "My Cool Model",
"ClassName": "Folder",
"Children": [
{
"Name": "RootPart",
"ClassName": "Part",
"Properties": {
"Size": {
"Type": "Vector3",
"Value": [4, 4, 4]
}
}
},
{
"Name": "SendMoney",
"ClassName": "RemoteEvent"
}
]
}
```
It would turn into instances in this shape:
![Tree of instances in Roblox](../images/sync-example-json-model.svg)
{: align="center" }
!!! warning
Starting in Rojo 0.5.0 (stable), the `Name` field is no longer required. The name of the top-level instance in a JSON model is now based on its file name, and the `Name` field is now ignored.
Rojo will emit a warning if the `Name` field is specified and does not match the file's name.
## Binary and XML Models
Rojo supports both binary (`.rbxm`) and XML (`.rbxmx`) models generated by Roblox Studio or another tool.
Support for the `rbxmx` is very good, while support for `rbxm` is still very early, buggy, and lacking features.
For a rundown of supported types, check out [rbx-dom's type coverage chart](https://github.com/rojo-rbx/rbx-dom#property-type-coverage).
## Meta Files
New in Rojo 0.5.0-alpha.12 are meta files, named `.meta.json`.
Meta files allow attaching extra Rojo data to models defined in other formats, like Roblox's `rbxm` and `rbxmx` model formats, or even Lua scripts.
This can be used to set Rojo-specific settings like `ignoreUnknownInstances`, or can be used to set properties like `Disabled` on a script.
Meta files can contain:
* `className`: Changes the `className` of a containing `Folder` into something else.
* Usable only in `init.meta.json` files
* `properties`: A map of properties to set on the instance, just like projects
* Usable on anything except `.rbxmx`, `.rbxm`, and `.model.json` files, which already have properties
* `ignoreUnknownInstances`: Works just like `$ignoreUnknownInstances` in project files
### Meta Files to set Rojo metadata
Sometimes it's useful to apply properties like `ignoreUnknownInstances` on instances that are defined on the filesystem instead of within the project itself.
### Meta Files for Disabled Scripts
Meta files can be used to set properties on `Script` instances, like `Disabled`.
If your project had `foo.server.lua` and you wanted to make sure it would be disabled, you could create a `foo.meta.json` next to it with:
```json
{
"properties": {
"Disabled": true
}
}
```
### Meta Files for Tools
If you wanted to represent a tool containing a script and a model for its handle, create a directory with an `init.meta.json` file in it:
```json
{
"className": "Tool",
"properties": {
"Grip": [
0, 0, 0,
1, 0, 0,
0, 1, 0,
0, 0, 1,
]
}
}
```
Instead of a `Folder` instance, you'll end up with a `Tool` instance with the `Grip` property set!

View File

@@ -1,3 +0,0 @@
mkdocs
mkdocs-material
pymdown-extensions

View File

@@ -1,23 +0,0 @@
There are a number of existing plugins for Roblox that move code from the filesystem into Roblox.
Besides Rojo, you might consider:
* [rbxmk by Anaminus](https://github.com/anaminus/rbxmk)
* [Rofresh by Osyris](https://github.com/osyrisrblx/rofresh)
* [RbxRefresh by Osyris](https://github.com/osyrisrblx/RbxRefresh)
* [Studio Bridge by Vocksel](https://github.com/vocksel/studio-bridge)
* [Elixir by Vocksel](https://github.com/vocksel/elixir)
* [RbxSync by evaera](https://github.com/evaera/RbxSync)
* [CodeSync by MemoryPenguin](https://github.com/MemoryPenguin/CodeSync)
* [rbx-exteditor by MemoryPenguin](https://github.com/MemoryPenguin/rbx-exteditor)
So why did I build Rojo?
Each of these tools solves what is essentially the same problem from a few different angles. The goal of Rojo is to take all of the lessons and ideas learned from these projects and build a tool that can solve this problem for good.
Additionally:
* I think that this tool needs to be built in a compiled language without a runtime, for easy distribution and good performance.
* I think that the conventions promoted by other sync plugins (`.module.lua` for modules, as well a single sync point) are sub-optimal.
* I think that I have a good enough understanding of the problem to build something robust.
* I think that Rojo should be able to do more than just sync code.

View File

@@ -1,44 +0,0 @@
Adding a tool like Rojo to your Roblox workflow can be daunting, but it comes with some key advantages.
[TOC]
## Rojo at RDC 2019
Nathan Riemer (Kampfkarren) gave a talk at RDC 2019 talking about some of the benefits of using a tool like Rojo.
<iframe style="margin: 0 auto; max-width: 100%" width="560" height="315" src="https://www.youtube-nocookie.com/embed/czlvzEyhaBc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
## External Text Editors
Rojo opens the door to use the absolute best text editors in the world and their rich plugin ecosystems.
Some very popular editors include [Visual Studio Code](https://code.visualstudio.com) and [Sublime Text](https://www.sublimetext.com).
These advanced text editors have features like multi-cursor editing, goto symbol, multi-file regex find and replace, bookmarks and much more.
Many Rojo VS Code users also use extensions like:
* [vscode-rbxlua](https://marketplace.visualstudio.com/items?itemName=AmaranthineCodices.vscode-rbxlua)
* [Roblox Lua Autocompletes](https://marketplace.visualstudio.com/items?itemName=Kampfkarren.roblox-lua-autofills)
* [TabNine](https://tabnine.com)
## Version Control
By building your game (or just the scripts) as individual files on the filesystem, it becomes easy to start using professional-grade version control tools like [Git](https://git-scm.com) and [GitHub](https://github.com).
Hundreds of thousands of companies and individual developers use Git to version their software projects. With Rojo, Roblox developers can take advantage of the best collaboration tool around.
Using a repository hosting service like GitHub or GitLab brings powerful features to Roblox developers like code reviews and issue tracking that professional engineers can't live without.
## TypeScript
TypeScript enables static type safety, which helps prevent typos and adds unparalleled autocompletion. It also brings features like arrow functions, object destructuring, functional programming methods, and more!
With Rojo, you can use [roblox-ts](https://roblox-ts.github.io) to compile TypeScript to Lua and take advantage of a huge ecosystem of TypeScript tooling.
It's also possible to use other languages that compile to Lua like [MoonScript](https://moonscript.org) and [Haxe](https://haxe.org).
## Other Tools
There are decades of excellent tools available that operate on files. With Rojo, it's possible to take advantage of any of them!
Popular tools include:
* [luacheck](https://github.com/mpeterv/luacheck), a static analysis tool to help you write better Lua
* [ripgrep](https://github.com/BurntSushi/ripgrep), an extremely fast code search tool
* [Tokei](https://github.com/XAMPPRocky/tokei), a tool for statistics like lines of code

3
foreman.toml Normal file
View File

@@ -0,0 +1,3 @@
[tools]
rojo = { source = "rojo-rbx/rojo", version = "6.0.0-rc.3" }
run-in-roblox = { source = "rojo-rbx/run-in-roblox", version = "0.3.0" }

15
memofs/CHANGELOG.md Normal file
View File

@@ -0,0 +1,15 @@
# memofs Changelog
## Unreleased Changes
## 0.1.3 (2020-11-19)
* Added `set_watch_enabled` to `Vfs` and `VfsLock` to allow turning off file watching.
## 0.1.2 (2020-03-29)
* `VfsSnapshot` now implements Serde's `Serialize` and `Deserialize` traits.
## 0.1.1 (2020-03-18)
* Improved error messages using the [fs-err](https://crates.io/crates/fs-err) crate.
## 0.1.0 (2020-03-10)
* Initial release

17
memofs/Cargo.toml Normal file
View File

@@ -0,0 +1,17 @@
[package]
name = "memofs"
description = "Virtual filesystem with configurable backends."
version = "0.1.3"
authors = ["Lucien Greathouse <me@lpghatguy.com>"]
edition = "2018"
readme = "README.md"
license = "MIT"
homepage = "https://github.com/rojo-rbx/rojo/tree/master/memofs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
crossbeam-channel = "0.4.0"
fs-err = "2.3.0"
notify = "4.0.15"
serde = { version = "1.0", features = ["derive"] }

7
memofs/LICENSE.txt Normal file
View File

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

22
memofs/README.md Normal file
View File

@@ -0,0 +1,22 @@
# memofs
[![Crates.io](https://img.shields.io/crates/v/memofs.svg)](https://crates.io/crates/memofs)
Implementation of a virtual filesystem with a configurable backend and file
watching.
memofs is currently an unstable minimum viable library. Its primary consumer is
[Rojo](https://github.com/rojo-rbx/rojo), a build system for Roblox.
### Current Features
* API similar to `std::fs`
* Configurable backends
* `StdBackend`, which uses `std::fs` and the `notify` crate
* `NoopBackend`, which always throws errors
* `InMemoryFs`, a simple in-memory filesystem useful for testing
### Future Features
* Hash-based hierarchical memoization keys (hence the name)
* Configurable caching (write-through, write-around, write-back)
## License
memofs is available under the terms of the MIT license. See [LICENSE.txt](LICENSE.txt) or <https://opensource.org/licenses/MIT> for more details.

7
memofs/README.tpl Normal file
View File

@@ -0,0 +1,7 @@
# {{crate}}
[![Crates.io](https://img.shields.io/crates/v/memofs.svg)](https://crates.io/crates/memofs)
{{readme}}
## License
memofs is available under the terms of the MIT license. See [LICENSE.txt](LICENSE.txt) or <https://opensource.org/licenses/MIT> for more details.

249
memofs/src/in_memory_fs.rs Normal file
View File

@@ -0,0 +1,249 @@
use std::collections::{BTreeSet, HashMap, VecDeque};
use std::io;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use crossbeam_channel::{Receiver, Sender};
use crate::{DirEntry, Metadata, ReadDir, VfsBackend, VfsEvent, VfsSnapshot};
/// In-memory filesystem that can be used as a VFS backend.
///
/// Internally reference counted to enable giving a copy to
/// [`Vfs`](struct.Vfs.html) and keeping the original to mutate the filesystem's
/// state with.
#[derive(Debug, Clone)]
pub struct InMemoryFs {
inner: Arc<Mutex<InMemoryFsInner>>,
}
impl InMemoryFs {
/// Create a new empty `InMemoryFs`.
pub fn new() -> Self {
Self {
inner: Arc::new(Mutex::new(InMemoryFsInner::new())),
}
}
/// Load a [`VfsSnapshot`](enum.VfsSnapshot.html) into a subtree of the
/// in-memory filesystem.
///
/// This function will return an error if the operations required to apply
/// the snapshot result in errors, like trying to create a file inside a
/// file.
pub fn load_snapshot<P: Into<PathBuf>>(
&mut self,
path: P,
snapshot: VfsSnapshot,
) -> io::Result<()> {
let mut inner = self.inner.lock().unwrap();
inner.load_snapshot(path.into(), snapshot)
}
/// Raises a filesystem change event.
///
/// If this `InMemoryFs` is being used as the backend of a
/// [`Vfs`](struct.Vfs.html), then any listeners be notified of this event.
pub fn raise_event(&mut self, event: VfsEvent) {
let inner = self.inner.lock().unwrap();
inner.event_sender.send(event).unwrap();
}
}
#[derive(Debug)]
struct InMemoryFsInner {
entries: HashMap<PathBuf, Entry>,
orphans: BTreeSet<PathBuf>,
event_receiver: Receiver<VfsEvent>,
event_sender: Sender<VfsEvent>,
}
impl InMemoryFsInner {
fn new() -> Self {
let (event_sender, event_receiver) = crossbeam_channel::unbounded();
Self {
entries: HashMap::new(),
orphans: BTreeSet::new(),
event_receiver,
event_sender,
}
}
fn load_snapshot(&mut self, path: PathBuf, snapshot: VfsSnapshot) -> io::Result<()> {
if let Some(parent_path) = path.parent() {
if let Some(parent_entry) = self.entries.get_mut(parent_path) {
if let Entry::Dir { children } = parent_entry {
children.insert(path.clone());
} else {
return must_be_dir(parent_path);
}
} else {
self.orphans.insert(path.clone());
}
} else {
self.orphans.insert(path.clone());
}
match snapshot {
VfsSnapshot::File { contents } => {
self.entries.insert(path, Entry::File { contents });
}
VfsSnapshot::Dir { children } => {
self.entries.insert(
path.clone(),
Entry::Dir {
children: BTreeSet::new(),
},
);
for (child_name, child) in children {
let full_path = path.join(child_name);
self.load_snapshot(full_path, child)?;
}
}
}
Ok(())
}
fn remove(&mut self, root_path: PathBuf) {
self.orphans.remove(&root_path);
let mut to_remove = VecDeque::new();
to_remove.push_back(root_path);
while let Some(path) = to_remove.pop_front() {
if let Some(Entry::Dir { children }) = self.entries.remove(&path) {
to_remove.extend(children);
}
}
}
}
#[derive(Debug)]
enum Entry {
File { contents: Vec<u8> },
Dir { children: BTreeSet<PathBuf> },
}
impl VfsBackend for InMemoryFs {
fn read(&mut self, path: &Path) -> io::Result<Vec<u8>> {
let inner = self.inner.lock().unwrap();
match inner.entries.get(path) {
Some(Entry::File { contents }) => Ok(contents.clone()),
Some(Entry::Dir { .. }) => must_be_file(path),
None => not_found(path),
}
}
fn write(&mut self, path: &Path, data: &[u8]) -> io::Result<()> {
let mut inner = self.inner.lock().unwrap();
inner.load_snapshot(
path.to_path_buf(),
VfsSnapshot::File {
contents: data.to_owned(),
},
)
}
fn read_dir(&mut self, path: &Path) -> io::Result<ReadDir> {
let inner = self.inner.lock().unwrap();
match inner.entries.get(path) {
Some(Entry::Dir { children }) => {
let iter = children
.clone()
.into_iter()
.map(|path| Ok(DirEntry { path }));
Ok(ReadDir {
inner: Box::new(iter),
})
}
Some(Entry::File { .. }) => must_be_dir(path),
None => not_found(path),
}
}
fn remove_file(&mut self, path: &Path) -> io::Result<()> {
let mut inner = self.inner.lock().unwrap();
match inner.entries.get(path) {
Some(Entry::File { .. }) => {
inner.remove(path.to_owned());
Ok(())
}
Some(Entry::Dir { .. }) => must_be_file(path),
None => not_found(path),
}
}
fn remove_dir_all(&mut self, path: &Path) -> io::Result<()> {
let mut inner = self.inner.lock().unwrap();
match inner.entries.get(path) {
Some(Entry::Dir { .. }) => {
inner.remove(path.to_owned());
Ok(())
}
Some(Entry::File { .. }) => must_be_dir(path),
None => not_found(path),
}
}
fn metadata(&mut self, path: &Path) -> io::Result<Metadata> {
let inner = self.inner.lock().unwrap();
match inner.entries.get(path) {
Some(Entry::File { .. }) => Ok(Metadata { is_file: true }),
Some(Entry::Dir { .. }) => Ok(Metadata { is_file: false }),
None => not_found(path),
}
}
fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
let inner = self.inner.lock().unwrap();
inner.event_receiver.clone()
}
fn watch(&mut self, _path: &Path) -> io::Result<()> {
Ok(())
}
fn unwatch(&mut self, _path: &Path) -> io::Result<()> {
Ok(())
}
}
fn must_be_file<T>(path: &Path) -> io::Result<T> {
Err(io::Error::new(
io::ErrorKind::Other,
format!(
"path {} was a directory, but must be a file",
path.display()
),
))
}
fn must_be_dir<T>(path: &Path) -> io::Result<T> {
Err(io::Error::new(
io::ErrorKind::Other,
format!(
"path {} was a file, but must be a directory",
path.display()
),
))
}
fn not_found<T>(path: &Path) -> io::Result<T> {
Err(io::Error::new(
io::ErrorKind::NotFound,
format!("path {} not found", path.display()),
))
}

433
memofs/src/lib.rs Normal file
View File

@@ -0,0 +1,433 @@
/*!
Implementation of a virtual filesystem with a configurable backend and file
watching.
memofs is currently an unstable minimum viable library. Its primary consumer is
[Rojo](https://github.com/rojo-rbx/rojo), a build system for Roblox.
## Current Features
* API similar to `std::fs`
* Configurable backends
* `StdBackend`, which uses `std::fs` and the `notify` crate
* `NoopBackend`, which always throws errors
* `InMemoryFs`, a simple in-memory filesystem useful for testing
## Future Features
* Hash-based hierarchical memoization keys (hence the name)
* Configurable caching (write-through, write-around, write-back)
*/
mod in_memory_fs;
mod noop_backend;
mod snapshot;
mod std_backend;
use std::io;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex, MutexGuard};
pub use in_memory_fs::InMemoryFs;
pub use noop_backend::NoopBackend;
pub use snapshot::VfsSnapshot;
pub use std_backend::StdBackend;
mod sealed {
use super::*;
/// Sealing trait for VfsBackend.
pub trait Sealed {}
impl Sealed for NoopBackend {}
impl Sealed for StdBackend {}
impl Sealed for InMemoryFs {}
}
/// Trait that transforms `io::Result<T>` into `io::Result<Option<T>>`.
///
/// `Ok(None)` takes the place of IO errors whose `io::ErrorKind` is `NotFound`.
pub trait IoResultExt<T> {
fn with_not_found(self) -> io::Result<Option<T>>;
}
impl<T> IoResultExt<T> for io::Result<T> {
fn with_not_found(self) -> io::Result<Option<T>> {
match self {
Ok(v) => Ok(Some(v)),
Err(err) => {
if err.kind() == io::ErrorKind::NotFound {
Ok(None)
} else {
Err(err)
}
}
}
}
}
/// Backend that can be used to create a `Vfs`.
///
/// This trait is sealed and cannot not be implemented outside this crate.
pub trait VfsBackend: sealed::Sealed + Send + 'static {
fn read(&mut self, path: &Path) -> io::Result<Vec<u8>>;
fn write(&mut self, path: &Path, data: &[u8]) -> io::Result<()>;
fn read_dir(&mut self, path: &Path) -> io::Result<ReadDir>;
fn metadata(&mut self, path: &Path) -> io::Result<Metadata>;
fn remove_file(&mut self, path: &Path) -> io::Result<()>;
fn remove_dir_all(&mut self, path: &Path) -> io::Result<()>;
fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent>;
fn watch(&mut self, path: &Path) -> io::Result<()>;
fn unwatch(&mut self, path: &Path) -> io::Result<()>;
}
/// Vfs equivalent to [`std::fs::DirEntry`][std::fs::DirEntry].
///
/// [std::fs::DirEntry]: https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html
pub struct DirEntry {
pub(crate) path: PathBuf,
}
impl DirEntry {
pub fn path(&self) -> &Path {
&self.path
}
}
/// Vfs equivalent to [`std::fs::ReadDir`][std::fs::ReadDir].
///
/// [std::fs::ReadDir]: https://doc.rust-lang.org/stable/std/fs/struct.ReadDir.html
pub struct ReadDir {
pub(crate) inner: Box<dyn Iterator<Item = io::Result<DirEntry>>>,
}
impl Iterator for ReadDir {
type Item = io::Result<DirEntry>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
/// Vfs equivalent to [`std::fs::Metadata`][std::fs::Metadata].
///
/// [std::fs::Metadata]: https://doc.rust-lang.org/stable/std/fs/struct.Metadata.html
#[derive(Debug)]
pub struct Metadata {
pub(crate) is_file: bool,
}
impl Metadata {
pub fn is_file(&self) -> bool {
self.is_file
}
pub fn is_dir(&self) -> bool {
!self.is_file
}
}
/// Represents an event that a filesystem can raise that might need to be
/// handled.
#[derive(Debug)]
#[non_exhaustive]
pub enum VfsEvent {
Create(PathBuf),
Write(PathBuf),
Remove(PathBuf),
}
/// Contains implementation details of the Vfs, wrapped by `Vfs` and `VfsLock`,
/// the public interfaces to this type.
struct VfsInner {
backend: Box<dyn VfsBackend>,
watch_enabled: bool,
}
impl VfsInner {
fn read<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Arc<Vec<u8>>> {
let path = path.as_ref();
let contents = self.backend.read(path)?;
if self.watch_enabled {
self.backend.watch(path)?;
}
Ok(Arc::new(contents))
}
fn write<P: AsRef<Path>, C: AsRef<[u8]>>(&mut self, path: P, contents: C) -> io::Result<()> {
let path = path.as_ref();
let contents = contents.as_ref();
self.backend.write(path, contents)
}
fn read_dir<P: AsRef<Path>>(&mut self, path: P) -> io::Result<ReadDir> {
let path = path.as_ref();
let dir = self.backend.read_dir(path)?;
if self.watch_enabled {
self.backend.watch(path)?;
}
Ok(dir)
}
fn remove_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
let path = path.as_ref();
let _ = self.backend.unwatch(path);
self.backend.remove_file(path)
}
fn remove_dir_all<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
let path = path.as_ref();
let _ = self.backend.unwatch(path);
self.backend.remove_dir_all(path)
}
fn metadata<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Metadata> {
let path = path.as_ref();
self.backend.metadata(path)
}
fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
self.backend.event_receiver()
}
fn commit_event(&mut self, event: &VfsEvent) -> io::Result<()> {
match event {
VfsEvent::Remove(path) => {
let _ = self.backend.unwatch(&path);
}
_ => {}
}
Ok(())
}
}
/// A virtual filesystem with a configurable backend.
///
/// All operations on the Vfs take a lock on an internal backend. For performing
/// large batches of operations, it might be more performant to call `lock()`
/// and use [`VfsLock`](struct.VfsLock.html) instead.
pub struct Vfs {
inner: Mutex<VfsInner>,
}
impl Vfs {
/// Creates a new `Vfs` with the default backend, `StdBackend`.
pub fn new_default() -> Self {
Self::new(StdBackend::new())
}
/// Creates a new `Vfs` with the given backend.
pub fn new<B: VfsBackend>(backend: B) -> Self {
let lock = VfsInner {
backend: Box::new(backend),
watch_enabled: true,
};
Self {
inner: Mutex::new(lock),
}
}
/// Manually lock the Vfs, useful for large batches of operations.
pub fn lock(&self) -> VfsLock<'_> {
VfsLock {
inner: self.inner.lock().unwrap(),
}
}
/// Turns automatic file watching on or off. Enabled by default.
///
/// Turning off file watching may be useful for single-use cases, especially
/// on platforms like macOS where registering file watches has significant
/// performance cost.
pub fn set_watch_enabled(&self, enabled: bool) {
let mut inner = self.inner.lock().unwrap();
inner.watch_enabled = enabled;
}
/// Read a file from the VFS, or the underlying backend if it isn't
/// resident.
///
/// Roughly equivalent to [`std::fs::read`][std::fs::read].
///
/// [std::fs::read]: https://doc.rust-lang.org/stable/std/fs/fn.read.html
#[inline]
pub fn read<P: AsRef<Path>>(&self, path: P) -> io::Result<Arc<Vec<u8>>> {
let path = path.as_ref();
self.inner.lock().unwrap().read(path)
}
/// Write a file to the VFS and the underlying backend.
///
/// Roughly equivalent to [`std::fs::write`][std::fs::write].
///
/// [std::fs::write]: https://doc.rust-lang.org/stable/std/fs/fn.write.html
#[inline]
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(&self, path: P, contents: C) -> io::Result<()> {
let path = path.as_ref();
let contents = contents.as_ref();
self.inner.lock().unwrap().write(path, contents)
}
/// Read all of the children of a directory.
///
/// Roughly equivalent to [`std::fs::read_dir`][std::fs::read_dir].
///
/// [std::fs::read_dir]: https://doc.rust-lang.org/stable/std/fs/fn.read_dir.html
#[inline]
pub fn read_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<ReadDir> {
let path = path.as_ref();
self.inner.lock().unwrap().read_dir(path)
}
/// Remove a file.
///
/// Roughly equivalent to [`std::fs::remove_file`][std::fs::remove_file].
///
/// [std::fs::remove_file]: https://doc.rust-lang.org/stable/std/fs/fn.remove_file.html
#[inline]
pub fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
let path = path.as_ref();
self.inner.lock().unwrap().remove_file(path)
}
/// Remove a directory and all of its descendants.
///
/// Roughly equivalent to [`std::fs::remove_dir_all`][std::fs::remove_dir_all].
///
/// [std::fs::remove_dir_all]: https://doc.rust-lang.org/stable/std/fs/fn.remove_dir_all.html
#[inline]
pub fn remove_dir_all<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
let path = path.as_ref();
self.inner.lock().unwrap().remove_dir_all(path)
}
/// Query metadata about the given path.
///
/// Roughly equivalent to [`std::fs::metadata`][std::fs::metadata].
///
/// [std::fs::metadata]: https://doc.rust-lang.org/stable/std/fs/fn.metadata.html
#[inline]
pub fn metadata<P: AsRef<Path>>(&self, path: P) -> io::Result<Metadata> {
let path = path.as_ref();
self.inner.lock().unwrap().metadata(path)
}
/// Retrieve a handle to the event receiver for this `Vfs`.
#[inline]
pub fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
self.inner.lock().unwrap().event_receiver()
}
/// Commit an event to this `Vfs`.
#[inline]
pub fn commit_event(&self, event: &VfsEvent) -> io::Result<()> {
self.inner.lock().unwrap().commit_event(event)
}
}
/// A locked handle to a [`Vfs`](struct.Vfs.html), created by `Vfs::lock`.
///
/// Implements roughly the same API as [`Vfs`](struct.Vfs.html).
pub struct VfsLock<'a> {
inner: MutexGuard<'a, VfsInner>,
}
impl VfsLock<'_> {
/// Turns automatic file watching on or off. Enabled by default.
///
/// Turning off file watching may be useful for single-use cases, especially
/// on platforms like macOS where registering file watches has significant
/// performance cost.
pub fn set_watch_enabled(&mut self, enabled: bool) {
self.inner.watch_enabled = enabled;
}
/// Read a file from the VFS, or the underlying backend if it isn't
/// resident.
///
/// Roughly equivalent to [`std::fs::read`][std::fs::read].
///
/// [std::fs::read]: https://doc.rust-lang.org/stable/std/fs/fn.read.html
#[inline]
pub fn read<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Arc<Vec<u8>>> {
let path = path.as_ref();
self.inner.read(path)
}
/// Write a file to the VFS and the underlying backend.
///
/// Roughly equivalent to [`std::fs::write`][std::fs::write].
///
/// [std::fs::write]: https://doc.rust-lang.org/stable/std/fs/fn.write.html
#[inline]
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(
&mut self,
path: P,
contents: C,
) -> io::Result<()> {
let path = path.as_ref();
let contents = contents.as_ref();
self.inner.write(path, contents)
}
/// Read all of the children of a directory.
///
/// Roughly equivalent to [`std::fs::read_dir`][std::fs::read_dir].
///
/// [std::fs::read_dir]: https://doc.rust-lang.org/stable/std/fs/fn.read_dir.html
#[inline]
pub fn read_dir<P: AsRef<Path>>(&mut self, path: P) -> io::Result<ReadDir> {
let path = path.as_ref();
self.inner.read_dir(path)
}
/// Remove a file.
///
/// Roughly equivalent to [`std::fs::remove_file`][std::fs::remove_file].
///
/// [std::fs::remove_file]: https://doc.rust-lang.org/stable/std/fs/fn.remove_file.html
#[inline]
pub fn remove_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
let path = path.as_ref();
self.inner.remove_file(path)
}
/// Remove a directory and all of its descendants.
///
/// Roughly equivalent to [`std::fs::remove_dir_all`][std::fs::remove_dir_all].
///
/// [std::fs::remove_dir_all]: https://doc.rust-lang.org/stable/std/fs/fn.remove_dir_all.html
#[inline]
pub fn remove_dir_all<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
let path = path.as_ref();
self.inner.remove_dir_all(path)
}
/// Query metadata about the given path.
///
/// Roughly equivalent to [`std::fs::metadata`][std::fs::metadata].
///
/// [std::fs::metadata]: https://doc.rust-lang.org/stable/std/fs/fn.metadata.html
#[inline]
pub fn metadata<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Metadata> {
let path = path.as_ref();
self.inner.metadata(path)
}
/// Retrieve a handle to the event receiver for this `Vfs`.
#[inline]
pub fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
self.inner.event_receiver()
}
/// Commit an event to this `Vfs`.
#[inline]
pub fn commit_event(&mut self, event: &VfsEvent) -> io::Result<()> {
self.inner.commit_event(event)
}
}

View File

@@ -0,0 +1,76 @@
use std::io;
use std::path::Path;
use crate::{Metadata, ReadDir, VfsBackend, VfsEvent};
/// `VfsBackend` that returns an error on every operation.
#[non_exhaustive]
pub struct NoopBackend;
impl NoopBackend {
pub fn new() -> Self {
Self
}
}
impl VfsBackend for NoopBackend {
fn read(&mut self, _path: &Path) -> io::Result<Vec<u8>> {
Err(io::Error::new(
io::ErrorKind::Other,
"NoopBackend doesn't do anything",
))
}
fn write(&mut self, _path: &Path, _data: &[u8]) -> io::Result<()> {
Err(io::Error::new(
io::ErrorKind::Other,
"NoopBackend doesn't do anything",
))
}
fn read_dir(&mut self, _path: &Path) -> io::Result<ReadDir> {
Err(io::Error::new(
io::ErrorKind::Other,
"NoopBackend doesn't do anything",
))
}
fn remove_file(&mut self, _path: &Path) -> io::Result<()> {
Err(io::Error::new(
io::ErrorKind::Other,
"NoopBackend doesn't do anything",
))
}
fn remove_dir_all(&mut self, _path: &Path) -> io::Result<()> {
Err(io::Error::new(
io::ErrorKind::Other,
"NoopBackend doesn't do anything",
))
}
fn metadata(&mut self, _path: &Path) -> io::Result<Metadata> {
Err(io::Error::new(
io::ErrorKind::Other,
"NoopBackend doesn't do anything",
))
}
fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
crossbeam_channel::never()
}
fn watch(&mut self, _path: &Path) -> io::Result<()> {
Err(io::Error::new(
io::ErrorKind::Other,
"NoopBackend doesn't do anything",
))
}
fn unwatch(&mut self, _path: &Path) -> io::Result<()> {
Err(io::Error::new(
io::ErrorKind::Other,
"NoopBackend doesn't do anything",
))
}
}

45
memofs/src/snapshot.rs Normal file
View File

@@ -0,0 +1,45 @@
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
/// A slice of a tree of files. Can be loaded into an
/// [`InMemoryFs`](struct.InMemoryFs.html).
#[derive(Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum VfsSnapshot {
File {
contents: Vec<u8>,
},
Dir {
children: BTreeMap<String, VfsSnapshot>,
},
}
impl VfsSnapshot {
pub fn file<C: Into<Vec<u8>>>(contents: C) -> Self {
Self::File {
contents: contents.into(),
}
}
pub fn dir<K: Into<String>, I: IntoIterator<Item = (K, VfsSnapshot)>>(children: I) -> Self {
Self::Dir {
children: children
.into_iter()
.map(|(key, value)| (key.into(), value))
.collect(),
}
}
pub fn empty_file() -> Self {
Self::File {
contents: Vec::new(),
}
}
pub fn empty_dir() -> Self {
Self::Dir {
children: BTreeMap::new(),
}
}
}

110
memofs/src/std_backend.rs Normal file
View File

@@ -0,0 +1,110 @@
use std::io;
use std::path::Path;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use crossbeam_channel::Receiver;
use notify::{watcher, DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
use crate::{DirEntry, Metadata, ReadDir, VfsBackend, VfsEvent};
/// `VfsBackend` that uses `std::fs` and the `notify` crate.
pub struct StdBackend {
watcher: RecommendedWatcher,
watcher_receiver: Receiver<VfsEvent>,
}
impl StdBackend {
pub fn new() -> StdBackend {
let (notify_tx, notify_rx) = mpsc::channel();
let watcher = watcher(notify_tx, Duration::from_millis(50)).unwrap();
let (tx, rx) = crossbeam_channel::unbounded();
thread::spawn(move || {
for event in notify_rx {
match event {
DebouncedEvent::Create(path) => {
tx.send(VfsEvent::Create(path))?;
}
DebouncedEvent::Write(path) => {
tx.send(VfsEvent::Write(path))?;
}
DebouncedEvent::Remove(path) => {
tx.send(VfsEvent::Remove(path))?;
}
DebouncedEvent::Rename(from, to) => {
tx.send(VfsEvent::Remove(from))?;
tx.send(VfsEvent::Create(to))?;
}
_ => {}
}
}
Result::<(), crossbeam_channel::SendError<VfsEvent>>::Ok(())
});
Self {
watcher,
watcher_receiver: rx,
}
}
}
impl VfsBackend for StdBackend {
fn read(&mut self, path: &Path) -> io::Result<Vec<u8>> {
fs_err::read(path)
}
fn write(&mut self, path: &Path, data: &[u8]) -> io::Result<()> {
fs_err::write(path, data)
}
fn read_dir(&mut self, path: &Path) -> io::Result<ReadDir> {
let entries: Result<Vec<_>, _> = fs_err::read_dir(path)?.collect();
let mut entries = entries?;
entries.sort_by_cached_key(|entry| entry.file_name());
let inner = entries
.into_iter()
.map(|entry| Ok(DirEntry { path: entry.path() }));
Ok(ReadDir {
inner: Box::new(inner),
})
}
fn remove_file(&mut self, path: &Path) -> io::Result<()> {
fs_err::remove_file(path)
}
fn remove_dir_all(&mut self, path: &Path) -> io::Result<()> {
fs_err::remove_dir_all(path)
}
fn metadata(&mut self, path: &Path) -> io::Result<Metadata> {
let inner = fs_err::metadata(path)?;
Ok(Metadata {
is_file: inner.is_file(),
})
}
fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
self.watcher_receiver.clone()
}
fn watch(&mut self, path: &Path) -> io::Result<()> {
self.watcher
.watch(path, RecursiveMode::NonRecursive)
.map_err(|inner| io::Error::new(io::ErrorKind::Other, inner))
}
fn unwatch(&mut self, path: &Path) -> io::Result<()> {
self.watcher
.unwatch(path)
.map_err(|inner| io::Error::new(io::ErrorKind::Other, inner))
}
}

View File

@@ -1,36 +0,0 @@
site_name: Rojo Documentation
repo_name: rojo-rbx/rojo
repo_url: https://github.com/rojo-rbx/rojo
theme:
name: material
palette:
primary: 'Red'
accent: 'Red'
nav:
- Home: index.md
- Why Rojo?: why-rojo.md
- Guide:
- Installation: guide/installation.md
- Creating a Game with Rojo: guide/new-game.md
- Porting an Existing Game to Rojo: guide/existing-game.md
- Migrating from 0.4.x to 0.5.x: guide/migrating-to-epiphany.md
- Reference:
- Fully vs Partially Managed Rojo: reference/full-vs-partial.md
- Project Format: reference/project-format.md
- Sync Details: reference/sync-details.md
- Rojo Alternatives: rojo-alternatives.md
- Rojo Internals:
- Internals Overview: internals/overview.md
extra_css:
- extra.css
markdown_extensions:
- attr_list
- admonition
- codehilite:
guess_lang: false
- toc:
permalink: true

10
perf-test.sh Normal file
View File

@@ -0,0 +1,10 @@
#!/bin/sh
set -e
cargo build --release
echo "Known good:"
time rojo build ../uiblox/test-place.project.json -o UIBlox.rbxlx
echo "Current:"
time ./target/release/rojo build ../uiblox/test-place.project.json -o UIBlox.rbxlx

1
plugin/.gitignore vendored
View File

@@ -1 +0,0 @@
/luacov.*

View File

@@ -1,8 +0,0 @@
return {
include = {
"^src",
},
exclude = {
"%.spec$",
},
}

View File

@@ -5,6 +5,18 @@
"Plugin": { "Plugin": {
"$path": "src" "$path": "src"
}, },
"Log": {
"$path": "log"
},
"Http": {
"$path": "http"
},
"Fmt": {
"$path": "fmt"
},
"RbxDom": {
"$path": "rbx_dom_lua"
},
"Roact": { "Roact": {
"$path": "modules/roact/src" "$path": "modules/roact/src"
}, },
@@ -14,8 +26,8 @@
"t": { "t": {
"$path": "modules/t/lib" "$path": "modules/t/lib"
}, },
"RbxDom": { "Flipper": {
"$path": "modules/rbx-dom/rbx_dom_lua/src" "$path": "modules/flipper/src"
} }
} }
} }

245
plugin/fmt/init.lua Normal file
View File

@@ -0,0 +1,245 @@
--[[
This library describes a formatting mechanism akin to Rust's std::fmt.
It has a couple building blocks:
* A new syntax for formatting strings, taken verbatim from Rust. It'd also
be possible to use printf-style formatting specifiers to integrate with
the existing string.format utility.
* An equivalent to Rust's `Display` trait. We're mapping the semantics of
tostring and the __tostring metamethod onto this trait. A lot of types
should already have __tostring implementations, too!
* An equivalent to Rust's `Debug` trait. This library Lua-ifies that idea by
inventing a new metamethod, `__fmtDebug`. We pass along the "extended
form" attribute which is the equivalent of the "alternate mode" in Rust's
Debug trait since it's the author's opinion that treating it as a
verbosity flag is semantically accurate.
]]
--[[
The default implementation of __fmtDebug for tables when the extended option
is not set.
]]
local function defaultTableDebug(buffer, input)
buffer:writeRaw("{")
for key, value in pairs(input) do
buffer:write("[{:?}] = {:?}", key, value)
if next(input, key) ~= nil then
buffer:writeRaw(", ")
end
end
buffer:writeRaw("}")
end
--[[
The default implementation of __fmtDebug for tables with the extended option
set.
]]
local function defaultTableDebugExtended(buffer, input)
-- Special case for empty tables.
if next(input) == nil then
buffer:writeRaw("{}")
return
end
buffer:writeLineRaw("{")
buffer:indent()
for key, value in pairs(input) do
buffer:writeLine("[{:?}] = {:#?},", key, value)
end
buffer:unindent()
buffer:writeRaw("}")
end
--[[
The default debug representation for all types.
]]
local function debugImpl(buffer, value, extendedForm)
local valueType = typeof(value)
if valueType == "string" then
local formatted = string.format("%q", value)
buffer:writeRaw(formatted)
elseif valueType == "table" then
local valueMeta = getmetatable(value)
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.
valueMeta.__fmtDebug(value, buffer, extendedForm)
else
if extendedForm then
defaultTableDebugExtended(buffer, value)
else
defaultTableDebug(buffer, value)
end
end
elseif valueType == "Instance" then
buffer:writeRaw(value:GetFullName())
else
buffer:writeRaw(tostring(value))
end
end
--[[
Defines and implements the library's template syntax.
]]
local function writeFmt(buffer, template, ...)
local currentArg = 0
local i = 1
local len = #template
while i <= len do
local openBrace = template:find("{", i)
if openBrace == nil then
-- There are no remaining open braces in this string, so we can
-- write the rest of the string to the buffer.
buffer:writeRaw(template:sub(i))
break
else
-- We found an open brace! This could be:
-- - A literal '{', written as '{{'
-- - The beginning of an interpolation, like '{}'
-- - An error, if there's no matching '}'
local charAfterBrace = template:sub(openBrace + 1, openBrace + 1)
if charAfterBrace == "{" then
-- This is a literal brace, so we'll write everything up to this
-- point (including the first brace), and then skip over the
-- second brace.
buffer:writeRaw(template:sub(i, openBrace))
i = openBrace + 2
else
-- This SHOULD be an interpolation. We'll find our matching
-- brace and treat the contents as the formatting specifier.
-- If there were any unwritten characters before this
-- interpolation, write them to the buffer.
if openBrace - i > 0 then
buffer:writeRaw(template:sub(i, openBrace - 1))
end
local closeBrace = template:find("}", openBrace + 1)
assert(closeBrace ~= nil, "Unclosed formatting specifier. Use '{{' to write an open brace.")
local formatSpecifier = template:sub(openBrace + 1, closeBrace - 1)
currentArg = currentArg + 1
local arg = select(currentArg, ...)
if formatSpecifier == "" then
-- This should use the equivalent of Rust's 'Display', ie
-- tostring and the __tostring metamethod.
buffer:writeRaw(tostring(arg))
elseif formatSpecifier == ":?" then
-- This should use the equivalent of Rust's 'Debug',
-- invented for this library as __fmtDebug.
debugImpl(buffer, arg, false)
elseif formatSpecifier == ":#?" then
-- This should use the equivlant of Rust's 'Debug' with the
-- 'alternate' (ie expanded) flag set.
debugImpl(buffer, arg, true)
else
error("unsupported format specifier " .. formatSpecifier, 2)
end
i = closeBrace + 1
end
end
end
end
local function debugOutputBuffer()
local buffer = {}
local startOfLine = true
local indentLevel = 0
local indentation = ""
function buffer:writeLine(template, ...)
writeFmt(self, template, ...)
self:nextLine()
end
function buffer:writeLineRaw(value)
self:writeRaw(value)
self:nextLine()
end
function buffer:write(template, ...)
return writeFmt(self, template, ...)
end
function buffer:writeRaw(value)
if #value > 0 then
if startOfLine and #indentation > 0 then
startOfLine = false
table.insert(self, indentation)
end
table.insert(self, value)
startOfLine = false
end
end
function buffer:nextLine()
table.insert(self, "\n")
startOfLine = true
end
function buffer:indent()
indentLevel = indentLevel + 1
indentation = string.rep(" ", indentLevel)
end
function buffer:unindent()
indentLevel = math.max(0, indentLevel - 1)
indentation = string.rep(" ", indentLevel)
end
function buffer:finish()
return table.concat(self, "")
end
return buffer
end
local function fmt(template, ...)
local buffer = debugOutputBuffer()
writeFmt(buffer, template, ...)
return buffer:finish()
end
--[[
Wrap the given object in a type that implements the given function as its
Debug implementation, and forwards __tostring to the type's underlying
tostring implementation.
]]
local function debugify(object, fmtFunc)
return setmetatable({}, {
__fmtDebug = function(_, ...)
return fmtFunc(object, ...)
end,
__tostring = function()
return tostring(object)
end,
})
end
return {
debugOutputBuffer = debugOutputBuffer,
fmt = fmt,
debugify = debugify,
}

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