From 315ec8b3dd381832269f6513a3f33f169801f94a Mon Sep 17 00:00:00 2001 From: zyansheep Date: Mon, 25 Jul 2022 15:57:55 -0400 Subject: [PATCH 1/2] update everything --- block-lang/.github/workflows/mdbook.yml | 35 +++ block-lang/.gitignore | 2 + block-lang/.vscode/settings.json | 7 +- block-lang/Cargo.lock | 40 ++-- block-lang/Cargo.toml | 13 +- block-lang/README.md | 15 +- .../{Application.png => AppState=Formed.png} | Bin block-lang/assets/AppState=None.png | Bin 0 -> 1354 bytes block-lang/assets/AppState=Placed.png | Bin 0 -> 2022 bytes block-lang/assets/AppState=Slotted.png | Bin 0 -> 1666 bytes block-lang/assets/LamState=Connected.png | Bin 0 -> 2894 bytes .../{LambdaEmpty.png => LamState=Formed.png} | Bin ...daDot.png => LamState=FormedConnected.png} | Bin block-lang/assets/LamState=None.png | Bin 0 -> 1358 bytes block-lang/assets/LamState=Placed.png | Bin 0 -> 2782 bytes block-lang/assets/Lambda.png | Bin 1307 -> 0 bytes ...riableBound.png => VarState=Connected.png} | Bin .../{Variable.png => VarState=None.png} | Bin .../{VariableDot.png => VarState=Placed.png} | Bin block-lang/book.toml | 9 + block-lang/pages/SUMMARY.md | 5 + block-lang/pages/build_instruction.md | 10 + block-lang/pages/how_to_use.md | 23 ++ block-lang/pages/introduction.md | 14 ++ block-lang/src/block.rs | 60 +++-- block-lang/src/block_to_expr.rs | 11 +- block-lang/src/cli.rs | 2 +- block-lang/src/expr/bind.rs | 211 +++++----------- block-lang/src/main.rs | 171 +++++++++---- block-lang/src/parse.rs | 2 +- block-lang/src/placing.rs | 18 +- block-lang/src/ui.rs | 6 +- block-lang/tmp-lang | 1 - .../.github/workflows/ci.yml | 67 ------ .../vendor/bevy-mouse-tracking/.gitignore | 2 - .../vendor/bevy-mouse-tracking/Cargo.toml | 21 -- .../vendor/bevy-mouse-tracking/README.md | 180 -------------- .../assets/FiraMono-Medium.ttf | Bin 173516 -> 0 bytes .../bevy-mouse-tracking/assets/cursor.png | Bin 400 -> 0 bytes .../bevy-mouse-tracking/assets/origin.png | Bin 191 -> 0 bytes .../bevy-mouse-tracking/examples/screen.rs | 67 ------ .../bevy-mouse-tracking/examples/world.rs | 87 ------- .../vendor/bevy-mouse-tracking/src/lib.rs | 213 ----------------- .../bevy-mouse-tracking/src/mouse_motion.rs | 18 -- .../bevy-mouse-tracking/src/mouse_pos.rs | 225 ------------------ block-lang/vendor/bevy_pancam/.gitignore | 2 - block-lang/vendor/bevy_pancam/Cargo.toml | 18 -- block-lang/vendor/bevy_pancam/LICENSE | 6 - block-lang/vendor/bevy_pancam/LICENSE-APACHE | 176 -------------- block-lang/vendor/bevy_pancam/LICENSE-MIT | 19 -- .../vendor/bevy_pancam/examples/simple.rs | 38 --- .../vendor/bevy_pancam/examples/toggle.rs | 47 ---- block-lang/vendor/bevy_pancam/readme.md | 54 ----- block-lang/vendor/bevy_pancam/src/lib.rs | 101 -------- 54 files changed, 376 insertions(+), 1620 deletions(-) create mode 100644 block-lang/.github/workflows/mdbook.yml rename block-lang/assets/{Application.png => AppState=Formed.png} (100%) create mode 100644 block-lang/assets/AppState=None.png create mode 100644 block-lang/assets/AppState=Placed.png create mode 100644 block-lang/assets/AppState=Slotted.png create mode 100644 block-lang/assets/LamState=Connected.png rename block-lang/assets/{LambdaEmpty.png => LamState=Formed.png} (100%) rename block-lang/assets/{LambdaDot.png => LamState=FormedConnected.png} (100%) create mode 100644 block-lang/assets/LamState=None.png create mode 100644 block-lang/assets/LamState=Placed.png delete mode 100644 block-lang/assets/Lambda.png rename block-lang/assets/{VariableBound.png => VarState=Connected.png} (100%) rename block-lang/assets/{Variable.png => VarState=None.png} (100%) rename block-lang/assets/{VariableDot.png => VarState=Placed.png} (100%) create mode 100644 block-lang/book.toml create mode 100644 block-lang/pages/SUMMARY.md create mode 100644 block-lang/pages/build_instruction.md create mode 100644 block-lang/pages/how_to_use.md create mode 100644 block-lang/pages/introduction.md delete mode 160000 block-lang/tmp-lang delete mode 100644 block-lang/vendor/bevy-mouse-tracking/.github/workflows/ci.yml delete mode 100644 block-lang/vendor/bevy-mouse-tracking/.gitignore delete mode 100644 block-lang/vendor/bevy-mouse-tracking/Cargo.toml delete mode 100644 block-lang/vendor/bevy-mouse-tracking/README.md delete mode 100755 block-lang/vendor/bevy-mouse-tracking/assets/FiraMono-Medium.ttf delete mode 100644 block-lang/vendor/bevy-mouse-tracking/assets/cursor.png delete mode 100644 block-lang/vendor/bevy-mouse-tracking/assets/origin.png delete mode 100644 block-lang/vendor/bevy-mouse-tracking/examples/screen.rs delete mode 100644 block-lang/vendor/bevy-mouse-tracking/examples/world.rs delete mode 100644 block-lang/vendor/bevy-mouse-tracking/src/lib.rs delete mode 100644 block-lang/vendor/bevy-mouse-tracking/src/mouse_motion.rs delete mode 100644 block-lang/vendor/bevy-mouse-tracking/src/mouse_pos.rs delete mode 100644 block-lang/vendor/bevy_pancam/.gitignore delete mode 100644 block-lang/vendor/bevy_pancam/Cargo.toml delete mode 100644 block-lang/vendor/bevy_pancam/LICENSE delete mode 100644 block-lang/vendor/bevy_pancam/LICENSE-APACHE delete mode 100644 block-lang/vendor/bevy_pancam/LICENSE-MIT delete mode 100644 block-lang/vendor/bevy_pancam/examples/simple.rs delete mode 100644 block-lang/vendor/bevy_pancam/examples/toggle.rs delete mode 100644 block-lang/vendor/bevy_pancam/readme.md delete mode 100644 block-lang/vendor/bevy_pancam/src/lib.rs diff --git a/block-lang/.github/workflows/mdbook.yml b/block-lang/.github/workflows/mdbook.yml new file mode 100644 index 0000000..f6d5fcb --- /dev/null +++ b/block-lang/.github/workflows/mdbook.yml @@ -0,0 +1,35 @@ +name: Deploy +on: + push: + branches: + - main + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Install mdbook + run: | + mkdir mdbook + curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.14/mdbook-v0.4.14-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook + echo `pwd`/mdbook >> $GITHUB_PATH + - name: Deploy GitHub Pages + run: | + # This assumes your book is in the root of your repository. + # Just add a `cd` here if you need to change to another directory. + mdbook build + git worktree add gh-pages + git config user.name "Deploy from CI" + git config user.email "" + cd gh-pages + # Delete the ref to avoid keeping history. + git update-ref -d refs/heads/gh-pages + rm -rf * + mv ../docs/ . + sed '/^\/docs\/$/d' .gitignore -i + git add . + git commit -m "Deploy $GITHUB_SHA to gh-pages" + git push --force --set-upstream origin gh-pages diff --git a/block-lang/.gitignore b/block-lang/.gitignore index 3dd439d..0d77843 100644 --- a/block-lang/.gitignore +++ b/block-lang/.gitignore @@ -13,3 +13,5 @@ # Added by cargo /target + +/docs/ diff --git a/block-lang/.vscode/settings.json b/block-lang/.vscode/settings.json index 431a2ff..9469be5 100644 --- a/block-lang/.vscode/settings.json +++ b/block-lang/.vscode/settings.json @@ -1,4 +1,7 @@ { - "nixEnvSelector.nixFile": "${workspaceRoot}/shell.nix", - "rust-analyzer.server.extraEnv": {"RUSTUP_TOOLCHAIN": "nightly"} + "rust-analyzer.server.extraEnv": { + "RUSTUP_TOOLCHAIN": "nightly" + }, + "nixEnvSelector.suggestion": false, + "nixEnvSelector.nixFile": "${workspaceRoot}/shell.nix" } \ No newline at end of file diff --git a/block-lang/Cargo.lock b/block-lang/Cargo.lock index 671b1bd..ff49b49 100644 --- a/block-lang/Cargo.lock +++ b/block-lang/Cargo.lock @@ -534,6 +534,7 @@ dependencies = [ [[package]] name = "bevy_mouse_tracking_plugin" version = "0.2.1" +source = "git+https://github.com/zyansheep/bevy-mouse-tracking#7b358c66feffc38b44d0d1b2d479057914888b04" dependencies = [ "bevy", ] @@ -541,6 +542,7 @@ dependencies = [ [[package]] name = "bevy_pancam" version = "0.3.0" +source = "git+https://github.com/zyansheep/bevy_pancam#e3e3f3e0824f21a6a38c6f59df74c635fcab3867" dependencies = [ "bevy", ] @@ -915,6 +917,25 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-lang" +version = "0.1.0" +dependencies = [ + "anyhow", + "ariadne", + "bevy", + "bevy_mouse_tracking_plugin", + "bevy_pancam", + "bevy_prototype_lyon", + "bytecheck", + "chumsky", + "hashdb", + "iyes_loopless", + "rkyv", + "rustyline", + "thiserror", +] + [[package]] name = "bs58" version = "0.4.0" @@ -3573,25 +3594,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" -[[package]] -name = "tmp-lang" -version = "0.1.0" -dependencies = [ - "anyhow", - "ariadne", - "bevy", - "bevy_mouse_tracking_plugin", - "bevy_pancam", - "bevy_prototype_lyon", - "bytecheck", - "chumsky", - "hashdb", - "iyes_loopless", - "rkyv", - "rustyline", - "thiserror", -] - [[package]] name = "toml" version = "0.5.9" diff --git a/block-lang/Cargo.toml b/block-lang/Cargo.toml index 41ca0d8..036ea6e 100644 --- a/block-lang/Cargo.toml +++ b/block-lang/Cargo.toml @@ -1,8 +1,8 @@ [package] -name = "tmp-lang" +name = "block-lang" version = "0.1.0" edition = "2021" -default-run = "tmp-lang" +default-run = "block-lang" [[bin]] name = "cli" @@ -29,16 +29,12 @@ anyhow = "1.0.58" bytecheck = "0.6.8" rkyv = { version = "0.7.39", features = ["validation"] } thiserror = "1.0.31" -bevy_pancam = { version = "*" } -bevy_mouse_tracking_plugin = { version = "*" } +bevy_pancam = { git = "https://github.com/zyansheep/bevy_pancam" } +bevy_mouse_tracking_plugin = { git = "https://github.com/zyansheep/bevy-mouse-tracking" } iyes_loopless = "0.6.1" rustyline = "10.0.0" bevy_prototype_lyon = "0.5.0" -[patch.crates-io] -bevy_mouse_tracking_plugin = { path = "vendor/bevy-mouse-tracking" } -bevy_pancam = { path = "vendor/bevy_pancam" } - # Stuff for Zyansheep, I use NixOS btw :) [package.metadata.nix] build = true @@ -51,6 +47,7 @@ nativeBuildInputs = [ "pkgconfig", "cmake", "mold", + "rust-analyzer", ] buildInputs = [ # Window and Input diff --git a/block-lang/README.md b/block-lang/README.md index 9916926..dec2d1b 100644 --- a/block-lang/README.md +++ b/block-lang/README.md @@ -1,6 +1,5 @@ -# tmp-lang - -Some unwritten language... +# Block Lang +*Functional Blocks* ## General idea @@ -10,12 +9,8 @@ Lambda calculus, but a visual drag-n-drop application, a bit like MIT Scratch Putting blocks together counts as assembly -The beautiful part, is animating the reductions - +The beautiful part, is animating the reductions (Not finished yet) -## How to run: +Gui: `cargo run --release` -```bash -cargo run --release -``` -(may need some graphics libraries, should be fine on windows) +Cli: `cargo run --package cli --release` \ No newline at end of file diff --git a/block-lang/assets/Application.png b/block-lang/assets/AppState=Formed.png similarity index 100% rename from block-lang/assets/Application.png rename to block-lang/assets/AppState=Formed.png diff --git a/block-lang/assets/AppState=None.png b/block-lang/assets/AppState=None.png new file mode 100644 index 0000000000000000000000000000000000000000..0c38c70b8e14e2a618da267f26d88012053a0680 GIT binary patch literal 1354 zcmeAS@N?(olHy`uVBq!ia0y~yVAKJ!&vUQ=N&j1K-U2Dk0*}aI1_o|n5N2eUHAey{ z$XFcY?!>U}oXkrghb7(7*O7r?V?XzwL{=d8zNd?0NCo5D+rD|Br4q+KKA&SI_;`u; z3hf5j6A}S0xiqvFEY+G8C^>P_+UueLVF}JIb2P12Xn)XKXdGWu-S<6)IkQ2?iOF{V zlh2ZO=1l)Tx9;mqzb3Y{=+ExGiWYz5}hnXZM@4LBY zbA75&j$Tt~{o|KeyRZB;yC0+5P-yw@^^^PlvqO4C|}pP`gPl_rQNIsMV}*TuWh>; zuhlT|_4DoPqV97sDTdu*;!uom;5o>Y#33f&yrDs&iS>wpjzU`kqah1-$Eeh3XpomS zdbX{!(rfr=o%eg$e6a&3Os~ps{pMv<*%RrJo(Ixan9<07w7KH ze!aYZ&!^0D8xAaCowIzQqyF)%54Z9;_uu_pv-tJvX9b&AGuTZydU*e``!Z4`$9`_U zd%t2=)alJ%w`J#_31266pxU4%t77k~`8RVm8P{|CXe-T6FMs{<>$+)r=2zo$R`0wL yzEiqobB}WPQ8oUdC_F%oTtE|kHOQ`&t;ucLK6Vg^%Z*n literal 0 HcmV?d00001 diff --git a/block-lang/assets/AppState=Placed.png b/block-lang/assets/AppState=Placed.png new file mode 100644 index 0000000000000000000000000000000000000000..3ed187e1b6b7bf54818f1d16f043e905bbf7a84d GIT binary patch literal 2022 zcmds&|2NZn9LGQNJtj0?%aFe4WXM&yNUkE>o0eGfZHCS$L|G+-UCtrjh4QU6aXPeV zmVAkPJ(6lO%9m+k7h%R)yIZ4;c0b+Dxt;qj^uzo8ct2m~{eHe*=ly=4*E{?4DGyEc z?dkvkXnJ|NodEy{0vr#ksenC_y~+o%<&tLr9so38-x>s{ylV&sA^0;M#{eqRco`H* zk*?mZ0Pwg_V=b?cs)i5lvXcV~T8dbV+rj!z8Cv*^6KD!cklh*F1_x8BLuB)9t! z6|BUz<%r1jl6Mu;6^X^e7Ga5;gqf~XQ8H#P1|kaLqVM2e)CGiS(qk=@O4{j*!s1Rr^)r?J+PfqMBD6_gpZ*-iVkP9BamdGFAD zVJ_BU`jEd(VORH|xe4q03exj6J_8?#GM4Gn(X0gM#EgObQ^`K^MaTgF=aZKv7+h&> zGwrbgSHM#qw3FG}0L8Jq(LV)(Ao&L4+yaA`gxhnr_dtD+xK?nuQ4&!e62?yya_=PGB^h_>Fsjxc1{|jvX6NHdcNHr47Dd0{ zMdOUd$$()z3V#J9rJ5BzpZf(U)<&3V_9?vm`CzD7t}4KGk8G^PBECF-yZ)gDHzY4p z7XMBw_g!L=3eZ@NslCevk}e##WWDe$bg>8)Ki{(xzc?HRFTid}vf2j7lEwCUp$MHY zBedg|hT2+CgP-a4I0@;=B>d(XV+Ua_A$E&Ces1#N@isWcMzIVL$c|qnis~AgxRu~^ z>+Utyoz2LJPHm2KQ8Fndk_OUcA4x}3YmF#cRJmpKj&%27=D{UjG!=Vq20IBID>K13 zb#0DhSOzkCE{l2~)7pq6$>P*tkiMZ`NA0l$4alK@;%~#{YDhz|Zn&{8Ie15;=_Rtr-?{aj-&ZyOnqm)Y>>zCk{ zkS)e`F_GO{^f4E(7^Buv&=1XQR;JU4soIE$AsW$D=RXX9Y8xWre{hVLWL9s{hl3^~ zO1TAwt#;5K2)^FqZesbkKk0`R%Shne_IfqPHn6i?6 zuH72qgmeKDpa`I?J=eZ6rUn(H?zHmT7Cn>FjoY(Mo4frPIkQd~KTruObAQHnTp9R8 zbk#<5gs(Hr)bug7HzKvcqcQ3pjZ1fDK{?A{t`?aBaY^VKSbu`li^k3V*HX;*L`>B| zBweeUm62u~kF;R2D4WXqBahw?98PO-3W<&fyV5rDj|+$C2J^35=vIwwjVVdXIfPjM zFk1`WY_cqRWtiv!7szGd^vB>EOzLvRzz~aW&Nt*IrVy0rVt0C_h`OZEu~1y(AaWBm z(L$Wz$@8o>jLL*1MH8FW$IH2=n><)>7J_d`HCf4sE(@PcSDl+}y?^8iT|GC^hvOi2 zOkS)s(l5#kg-ubp>0`;p)d7p z{~nC*`|u$Ej|iF8gO2))s9dif-k-jOKdhO|@86C=U6{2(0U_`~*&sDpd8 z#=tU6MhBFjTAYB)le@y#m_l#ZXNfqY)`p*!)Tv&U+54%!su?erDw+xm_!g^hS&FDX z91lSKu3j4Ku4`i)iJwB_d9a3Nf-8B)miP5K~%J6=|(SNIacIPVMCNzj`Ia3{?@b^uQ?{>`O8Xk^5E-z zXHh!2iq#rdtI73yxBJ}9tGWEti2P(teSGk%*8Rg`a}<*ge%Juu<$lVIdMq^kA06hM A{{R30 literal 0 HcmV?d00001 diff --git a/block-lang/assets/AppState=Slotted.png b/block-lang/assets/AppState=Slotted.png new file mode 100644 index 0000000000000000000000000000000000000000..583ed95715b3f1138166e2c07c74c95494d675a6 GIT binary patch literal 1666 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 GlK%%Z@$3Eo literal 0 HcmV?d00001 diff --git a/block-lang/assets/LambdaEmpty.png b/block-lang/assets/LamState=Formed.png similarity index 100% rename from block-lang/assets/LambdaEmpty.png rename to block-lang/assets/LamState=Formed.png diff --git a/block-lang/assets/LambdaDot.png b/block-lang/assets/LamState=FormedConnected.png similarity index 100% rename from block-lang/assets/LambdaDot.png rename to block-lang/assets/LamState=FormedConnected.png diff --git a/block-lang/assets/LamState=None.png b/block-lang/assets/LamState=None.png new file mode 100644 index 0000000000000000000000000000000000000000..b697154828164de7df49322242e3a416b9f11cb8 GIT binary patch literal 1358 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 AiU0rr literal 0 HcmV?d00001 diff --git a/block-lang/assets/Lambda.png b/block-lang/assets/Lambda.png deleted file mode 100644 index 0d983c596904587d9237b65879ce79dab7514a0f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1307 zcmeAS@N?(olHy`uVBq!ia0y~yVAKJ!&vUQ=N&j1K-U2Dk0*}aI1_o|n5N2eUHAey{ z$XFcY?!>U}oXkrghb7(7*O7r?V?XzwL{=bogQtsQNCo5D+unI1;Sy~R|BKA+*~^m7 zx~1S*B6}kHjYmp`Ol1OL0@X(p`V6c;@CiLT_-c(pT+{Ku<^HQ~H|Q9ga5}Wkze;Xp z$o6$|`>dAhtzEa^e0*-G?sHS=x^?&7_qA_3p1PW0-?^JRbXIM3)%`ttTSZ09)b3l; z{qmel*USrheco$9L;mwERo1Jn?q7fV(aD$3>%QDf_&WFS^2e{H3u!(0)$=fFZ-#n* zzn*nv=7wK$@7LFwuVUI!xAyJ!{c<+{pL{sZ{%h{x@W&VLGVKU_yJBzchVqXm3JRas zq^O1+5czWV-{Tugxb1p29E*6{clkg#tAXlX`+W8OZ`WtfPWbxs^xIuu@5-0{+r@NX z%ABk9+v_sA_ip~I`S8Qvze3sxv$kbL)%ku_h0iM)3R*iQ&Ptw?rLvjT9&&y z?ex!pz3;>hTv>Z-Z{i%0dwLBkv%g;cwe0sEhGqHHvO4#xqHIPe@~O5zX` zaNf`$(ZqU0Ku4i1fzgnKyJJ*pG&IOd8$G2P&T%FDI(O}$m2Sh!Xr8ODeHndX*Y9ta z`c(*IthR5DIw$tjPRt;6uix$4?Z=&?-^>kt&(3NP>Ri7!GPf*j^IxM=Ov^H4Vy_le zZn<}d<@H^S*RG5{=U%x++gQft*H#p6nQIf(zsZNUQPUEX|L(ot(trNj-22BSzpZ1u zv*O>by|r7aKb}yZ|7_3i#))DDllkoWuHIUDU#PF2e|~6w_3YWP4A+k-, Box) -} +/// Associated `Entity` with a variable +pub type BindEntityTree = BindTree<'static, Entity>; -#[derive(Component, Default)] -pub enum Expr { - Function { bind: Binding, expr: Option }, - Application { func: Option, args: Option }, - #[default] - Variable, -} */ +#[derive(Clone, Copy, Debug)] +pub enum PartialForm { + Func, Args +} #[derive(Component, Clone, Debug)] pub enum WrappedExpr { - Variable { bound: Option }, + Variable { formed: (&'static Expr<'static>, &'static BindEntityTree) }, Lambda { - bind_entity: Option, expr_entity: Option, - formed: Option>, + is_bound: bool, + formed: Option<(&'static Expr<'static>, &'static BindEntityTree)>, }, Application { func_entity: Option, args_entity: Option, - formed: Option>, + partial_formed: Option<(&'static Expr<'static>, &'static BindEntityTree, PartialForm)>, + formed: Option<(&'static Expr<'static>, &'static BindEntityTree)>, } } impl WrappedExpr { - pub const APPLICATION: WrappedExpr = WrappedExpr::Application { func_entity: None, args_entity: None, formed: None }; - pub const LAMBDA: WrappedExpr = WrappedExpr::Lambda { bind_entity: None, expr_entity: None, formed: None }; - pub const VARIABLE: WrappedExpr = WrappedExpr::Variable { bound: None }; + pub const APPLICATION: WrappedExpr = WrappedExpr::Application { func_entity: None, args_entity: None, partial_formed: None, formed: None }; + pub const LAMBDA: WrappedExpr = WrappedExpr::Lambda { is_bound: false, expr_entity: None, formed: None }; + pub const VARIABLE: WrappedExpr = WrappedExpr::Variable { formed: (Expr::VAR, BindTree::NONE) }; + pub fn unform(&mut self) { + match self { + Self::Application { formed, partial_formed, .. } => { + *formed = None; *partial_formed = None; + } + Self::Lambda { formed, .. } => *formed = None, + _ => {}, + } + } } impl Default for WrappedExpr { fn default() -> Self { Self::VARIABLE } } @@ -80,12 +84,16 @@ impl ObjectData { } pub fn gen_texture(expr: &WrappedExpr, asset_server: &AssetServer) -> Handle { match expr { - WrappedExpr::Variable { .. } => asset_server.load("VariableDot.png"), - WrappedExpr::Variable { bound: Some(_) } => asset_server.load("VariableBound.png"), - WrappedExpr::Lambda { expr_entity: None, formed: None, .. } => asset_server.load("Lambda.png"), - WrappedExpr::Lambda { expr_entity: Some(_), formed: None, .. } => asset_server.load("LambdaEmpty.png"), - WrappedExpr::Lambda { formed: Some(_), .. } => asset_server.load("LambdaDot.png"), - WrappedExpr::Application { .. } => asset_server.load("Application.png"), + WrappedExpr::Variable { formed: (_, BindEntityTree::End(_)) } => asset_server.load("VarState=Connected.png"), + WrappedExpr::Variable { .. } => asset_server.load("VarState=Placed.png"), + WrappedExpr::Lambda { formed: Some(_), is_bound: true, .. } => asset_server.load("LamState=FormedConnected.png"), + WrappedExpr::Lambda { formed: Some(_), .. } => asset_server.load("LamState=Formed.png"), + WrappedExpr::Lambda { expr_entity: Some(_), is_bound: true, .. } => asset_server.load("LamState=Connected.png"), + WrappedExpr::Lambda { expr_entity: Some(_), .. } => asset_server.load("LamState=Placed.png"), + WrappedExpr::Lambda { expr_entity: None, .. } => asset_server.load("LamState=None.png"), + WrappedExpr::Application { formed: Some(_), .. } => asset_server.load("AppState=Formed.png"), + WrappedExpr::Application { func_entity: Some(_), args_entity: Some(_), .. } => asset_server.load("AppState=Slotted.png"), + WrappedExpr::Application { .. } => asset_server.load("AppState=Placed.png"), } } pub fn gen_transform(&self, z_loc: f32) -> Transform { diff --git a/block-lang/src/block_to_expr.rs b/block-lang/src/block_to_expr.rs index 5d2762d..3f3063c 100644 --- a/block-lang/src/block_to_expr.rs +++ b/block-lang/src/block_to_expr.rs @@ -1,11 +1,10 @@ use crate::{expr::Expr, block::WrappedExpr}; - -pub fn block_to_expr(wrapped: &WrappedExpr) -> Result<&Expr<'static>, String> { +pub fn block_to_expr(wrapped: &WrappedExpr) -> Result<&Expr<'static>, Box> { match wrapped { - WrappedExpr::Variable { bound } => Ok(&Expr::Variable), - WrappedExpr::Lambda { bind_entity, expr_entity, formed: Some(expr) } => Ok(expr), - WrappedExpr::Application { func_entity, args_entity, formed: Some(expr) } => Ok(expr), - _ => Err("malformed expression".into()), + WrappedExpr::Variable { formed: (expr, _) } + | WrappedExpr::Lambda { formed: Some((expr, _)), .. } + | WrappedExpr::Application { formed: Some((expr, _)), .. } => Ok(expr), + _ => Err(format!("unformed expression for {wrapped:?}"))?, } } diff --git a/block-lang/src/cli.rs b/block-lang/src/cli.rs index 7bf0dba..cce5139 100644 --- a/block-lang/src/cli.rs +++ b/block-lang/src/cli.rs @@ -20,7 +20,7 @@ fn cli_editor() { use parse::Command; use rustyline::Editor; - println!("tmp-lang cli editor!"); + println!("block-lang cli editor!"); let mut editor = Editor::<()>::new().unwrap(); if editor.load_history(".editor_history").is_err() {} diff --git a/block-lang/src/expr/bind.rs b/block-lang/src/expr/bind.rs index e437f70..8d6a59f 100644 --- a/block-lang/src/expr/bind.rs +++ b/block-lang/src/expr/bind.rs @@ -17,12 +17,8 @@ pub enum Binding<'a> { None, End, Branch( - #[with(HashType)] - #[omit_bounds] - &'a Binding<'a>, - #[with(HashType)] - #[omit_bounds] - &'a Binding<'a>, + #[with(HashType)] #[omit_bounds] &'a Binding<'a>, + #[with(HashType)] #[omit_bounds] &'a Binding<'a>, ), } impl<'a> Binding<'a> { @@ -72,7 +68,7 @@ pub enum BindTreeError { InvalidSplit, } -// Associates a type with +// Associates a value with various parts of an `Expr` #[derive(Clone, Hash, PartialEq, Debug)] pub enum BindTree<'a, T: TypeStorable> { None, @@ -89,58 +85,39 @@ impl<'a, 'e, T: TypeStorable + 'e> BindTree<'a, T> { }) } fn branch_new(left: &'a Self, right: &'a Self) -> Self { - if let (BindTree::None, BindTree::None) = (left, right) { - BindTree::None - } else { - BindTree::Branch(left, right) - } + if let (BindTree::None, BindTree::None) = (left, right) { BindTree::None } + else { BindTree::Branch(left, right) } } - pub fn branch(left: &'a Self, right: &'a Self, binds: &'a impl TypeStore<'a>) -> &'a Self { - binds.add(Self::branch_new(left, right)) + pub fn branch(left: &'a Self, right: &'a Self, trees: &'a impl TypeStore<'a>) -> &'a Self { + trees.add(Self::branch_new(left, right)) } - pub fn left(&'a self, binds: &'a impl TypeStore<'a>) -> &'a Self { - Self::branch(self, BindTree::NONE, binds) + pub fn left(&'a self, trees: &'a impl TypeStore<'a>) -> &'a Self { + Self::branch(self, BindTree::NONE, trees) } - pub fn right(&'a self, binds: &'a impl TypeStore<'a>) -> &'a Self { - Self::branch(BindTree::NONE, self, binds) + pub fn right(&'a self, trees: &'a impl TypeStore<'a>) -> &'a Self { + Self::branch(BindTree::NONE, self, trees) } - pub fn end(val: T, binds: &'a impl TypeStore<'a>) -> &'a Self { - binds.add(BindTree::End(val)) - } -} - -impl<'a, T: fmt::Display + TypeStorable> fmt::Display for BindTree<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - BindTree::Branch(BindTree::None, right) => write!(f, ">{}", right)?, - BindTree::Branch(left, BindTree::None) => write!(f, "<{}", left)?, - BindTree::Branch(left, right) => write!(f, "({},{})", left, right)?, - BindTree::End(val) => write!(f, "{}", val)?, - BindTree::None => write!(f, "N")?, - } - Ok(()) + pub fn end(val: T, trees: &'a impl TypeStore<'a>) -> &'a Self { + trees.add(BindTree::End(val)) } -} - -/// BindTree that can represent multiple lambda abstractions at once -pub type BindSubTree<'a> = BindTree<'a, usize>; -impl<'a, 'e> BindSubTree<'a> { /// Add PointerTree to ReplaceTree at certain abstraction level - pub fn push_binding(self: &mut &'a Self, binds: &'a impl TypeStore<'a>, level: usize, pointer: &'e Binding<'e>) -> Result<(), BindTreeError> { - *self = match (*self, pointer) { - // If ReplaceTree is None, fill in pointer + pub fn push_binding(self: &mut &'a Self, trees: &'a impl TypeStore<'a>, end: T, binds: &'e Binding<'e>) -> Result<(), BindTreeError> + where T: Clone, + { + *self = match (*self, binds) { + // If ReplaceTree is None, fill in binds (tree, Binding::None) => tree, - (BindTree::None, Binding::End) => Self::end(level, binds), + (BindTree::None, Binding::End) => Self::end(end, trees), (BindTree::None, Binding::Branch(l, r)) => { let (mut left, mut right) = (Self::NONE, Self::NONE); - left.push_binding(binds, level, l)?; - right.push_binding(binds, level, r)?; - Self::branch(left, right, binds) + left.push_binding(trees, end.clone(), l)?; + right.push_binding(trees, end, r)?; + Self::branch(left, right, trees) } (BindTree::Branch(mut left, mut right), Binding::Branch(l, r)) => { - left.push_binding(binds, level, l)?; - right.push_binding(binds, level, r)?; - Self::branch(left, right, binds) + left.push_binding(trees, end.clone(), l)?; + right.push_binding(trees, end, r)?; + Self::branch(left, right, trees) } (BindTree::End(_), _) => return Err(BindTreeError::AlreadyBound), (_, Binding::End) => return Err(BindTreeError::InvalidBindLocation), @@ -148,15 +125,17 @@ impl<'a, 'e> BindSubTree<'a> { Ok(()) } /// Constructs PointerTree from ReplaceTree at certain abstraction level - pub fn pop_binding(self: &mut &'a Self, binds: &'a impl TypeStore<'a>, level: usize, ptrs: &'e impl TypeStore<'e>) -> Result<&'e Binding<'e>, BindTreeError> { + pub fn pop_binding(self: &mut &'a Self, trees: &'a impl TypeStore<'a>, end: &T, binds: &'e impl TypeStore<'e>) -> Result<&'e Binding<'e>, BindTreeError> + where T: PartialEq, + { Ok(match self { BindTree::Branch(mut l, mut r) => { - let left = l.pop_binding(binds, level, ptrs)?; - let right = r.pop_binding(binds, level, ptrs)?; - *self = Self::branch(l, r, binds); - Binding::branch_reduce(left, right, ptrs) + let left = l.pop_binding(trees, end, binds)?; + let right = r.pop_binding(trees, end, binds)?; + *self = Self::branch(l, r, trees); + Binding::branch_reduce(left, right, binds) } - BindTree::End(count) if level == *count => { + BindTree::End(count) if *end == *count => { *self = Self::NONE; Binding::END } @@ -165,33 +144,22 @@ impl<'a, 'e> BindSubTree<'a> { } } -/// BindTree that can associate an Expr with bound variables -pub type BindTypeTree<'a, 'e> = BindTree<'a, &'e Expr<'e>>; -impl<'a, 'e> BindTypeTree<'a, 'e> { - // Push Binding and type Expr onto BindTypeTree - pub fn push_binding(self: &mut &'a Self, bind: &'e Binding<'e>, bind_type: &'e Expr<'e>, binds: &'a impl TypeStore<'a>) -> Result<(), BindTreeError> { - *self = match (*self, bind) { - // If ReplaceTree is None, fill in pointer - (tree, Binding::None) => tree, - (BindTree::None, Binding::End) => Self::end(bind_type, binds), - (BindTree::None, Binding::Branch(l, r)) => { - let (mut left, mut right) = (Self::NONE, Self::NONE); - left.push_binding(l, bind_type, binds)?; - right.push_binding(r, bind_type, binds)?; - Self::branch(left, right, binds) - } - (BindTree::Branch(mut left, mut right), Binding::Branch(l, r)) => { - left.push_binding(l, bind_type, binds)?; - right.push_binding(r, bind_type, binds)?; - Self::branch(left, right, binds) - } - (BindTree::End(_), _) => return Err(BindTreeError::AlreadyBound), - (_, Binding::End) => return Err(BindTreeError::InvalidBindLocation), - }; +impl<'a, T: fmt::Display + TypeStorable> fmt::Display for BindTree<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + BindTree::Branch(BindTree::None, right) => write!(f, ">{}", right)?, + BindTree::Branch(left, BindTree::None) => write!(f, "<{}", left)?, + BindTree::Branch(left, right) => write!(f, "({},{})", left, right)?, + BindTree::End(val) => write!(f, "{}", val)?, + BindTree::None => write!(f, "N")?, + } Ok(()) } } +/// BindTree that can represent multiple lambda abstractions at once +pub type BindSubTree<'a> = BindTree<'a, usize>; + // Index = 0 means no lambda history (tree should BindTree::None) // Index > 0 means there is history #[derive(PartialEq, Debug, Clone)] @@ -200,8 +168,9 @@ pub struct BindIndex<'a> { pub tree: &'a BindSubTree<'a>, } -impl<'a, 'e> BindIndex<'a> { +impl<'a> BindIndex<'a> { pub const DEFAULT: BindIndex<'a> = BindIndex::new(0, BindTree::NONE); + /// Create new BindIndex pub const fn new(index: usize, tree: &'a BindSubTree<'a>) -> Self { Self { index, tree } } @@ -211,43 +180,41 @@ impl<'a, 'e> BindIndex<'a> { Ok((BindIndex::new(self.index, left), BindIndex::new(self.index, right))) } // Join two BindIndexs of same index - pub fn join(left: BindIndex<'a>, right: BindIndex<'a>, binds: &'a impl TypeStore<'a>) -> BindIndex<'a> { + pub fn join(left: BindIndex<'a>, right: BindIndex<'a>, trees: &'a impl TypeStore<'a>) -> BindIndex<'a> { debug_assert_eq!(left.index, right.index); - BindIndex::new(left.index, BindTree::branch(left.tree, right.tree, binds)) + BindIndex::new(left.index, BindTree::branch(left.tree, right.tree, trees)) } /// Push Binding onto BindIndex - pub fn push_binding(&mut self, pointer: &'e Binding<'e>, binds: &'a impl TypeStore<'a>) -> Result<(), BindTreeError> { + pub fn push_binding<'e>(&mut self, binds: &'e Binding<'e>, trees: &'a impl TypeStore<'a>) -> Result<(), BindTreeError> { let BindIndex { index, tree } = self; *index += 1; - tree.push_binding(binds, *index, pointer)?; + tree.push_binding(trees, *index, binds)?; Ok(()) } /// Pop Binding from BindIndex - pub fn pop_binding(&mut self, binds: &'a impl TypeStore<'a>, ptrs: &'e impl TypeStore<'e>) -> Result<&'e Binding<'e>, LambdaError> { - let BindIndex { index, tree } = self; + pub fn pop_binding<'e>(&mut self, trees: &'a impl TypeStore<'a>, binds: &'e impl TypeStore<'e>) -> Result<&'e Binding<'e>, LambdaError> { + let BindIndex::<'a> { index, tree } = self; if *index == 0 { return Err(LambdaError::BindingLevelMismatch); } - let ret = tree.pop_binding(binds, *index, ptrs)?; + let ret = tree.pop_binding(trees, index, binds)?; *index -= 1; Ok(ret) } /// Build BindIndex from nested Lambda expressions - pub fn push_lambda(&mut self, expr: &'a Expr<'a>, binds: &'a impl TypeStore<'a>) -> Result<&'a Expr<'a>, BindTreeError> { - Ok(if let Expr::Lambda { bind: pointer_tree, expr } = expr { - let pushed_expr = self.push_lambda(expr, binds)?; - self.push_binding(pointer_tree, binds)?; + pub fn push_lambda<'e>(&mut self, expr: &'e Expr<'e>, trees: &'a impl TypeStore<'a>) -> Result<&'e Expr<'e>, BindTreeError> { + Ok(if let Expr::Lambda { bind: binds_tree, expr } = expr { + let pushed_expr = self.push_lambda(expr, trees)?; + self.push_binding(binds_tree, trees)?; pushed_expr - } else { - &expr - }) + } else { &expr }) } /// Creates nested Lambda expressions from BindIndex #[allow(dead_code)] - pub fn pop_lambda(&mut self, expr: &'e Expr<'e>, binds: &'a impl TypeStore<'a>, exprs: &'e impl TypeStore<'e>) -> Result<&'e Expr<'e>, LambdaError> { - let pointer_tree = self.pop_binding(binds, exprs)?; - let popped_expr = if self.index == 0 { &expr } else { self.pop_lambda(expr, binds, exprs)? }; - Ok(Expr::lambda(pointer_tree, popped_expr, exprs)) + pub fn pop_lambda<'e>(&mut self, expr: &'e Expr<'e>, trees: &'a impl TypeStore<'a>, exprs: &'e impl TypeStore<'e>) -> Result<&'e Expr<'e>, LambdaError> { + let binds_tree = self.pop_binding(trees, exprs)?; + let popped_expr = if self.index == 0 { &expr } else { self.pop_lambda(expr, trees, exprs)? }; + Ok(Expr::lambda(binds_tree, popped_expr, exprs)) } } @@ -256,55 +223,3 @@ impl<'a> fmt::Display for BindIndex<'a> { write!(f, "{}/{}", self.tree, self.index) } } - -#[test] -fn test_replace_tree() { - use crate::name::NamespaceMut; - use hashdb::LinkArena; - - use Binding as B; - let binds = &LinkArena::new(); - let exprs = &LinkArena::new(); - let mut r = BindIndex::DEFAULT; - println!("start: [{}]", r); - - let lambda = crate::parse::parse("[x y z w] x (y z) w", &mut NamespaceMut::new(), exprs).unwrap(); - println!("lambda: {}", lambda); - let expr = r.push_lambda(&lambda, binds).unwrap(); - println!("after push: {} : {}", expr, r); - let lambda_2 = r.pop_lambda(expr, binds, exprs).unwrap(); - println!("after pop: {}", lambda_2); - assert_eq!(lambda, lambda_2); - - // Test Split & Join - let r = BindIndex::DEFAULT; - test_split(binds, r).unwrap(); - - let _pts = &LinkArena::new(); - let mut r = BindIndex::DEFAULT; - r.push_binding(&B::END, binds).unwrap(); - test_split(binds, r).unwrap_err(); - - // let r = &mut ReduceArena(, 0); - // test_split(r, db).unwrap(); // This will error - let mut r = BindIndex::DEFAULT; - r.push_binding(&B::left(B::END, exprs), binds).unwrap(); - test_split(binds, r).unwrap(); - - let mut r = BindIndex::DEFAULT; - r.push_binding(&B::branch(B::right(B::END, exprs), B::END, exprs), binds).unwrap(); - test_split(binds, r).unwrap(); -} -#[allow(dead_code)] -fn test_split<'a>(binds: &'a impl TypeStore<'a>, r: BindIndex<'a>) -> Result<(), BindTreeError> { - print!("split [{}] ", r); - let (left, right) = r.split().map_err(|e| { - println!("split err: {}", e); - e - })?; - print!(" - ([{}] [{}])", left, right); - let r_after = BindIndex::join(left, right, binds); - println!(" = [{}]", r); - assert_eq!(r, r_after); - Ok(()) -} diff --git a/block-lang/src/main.rs b/block-lang/src/main.rs index a165bfc..358f4c4 100644 --- a/block-lang/src/main.rs +++ b/block-lang/src/main.rs @@ -3,10 +3,10 @@ use bevy::prelude::*; use bevy_mouse_tracking_plugin::{MainCamera, MousePosPlugin, MousePosWorld}; use bevy_pancam::{PanCam, PanCamPlugin}; use bevy_prototype_lyon::prelude::*; -use block::{ObjectData, Orientation, WrappedExpr}; +use block::{BindEntityTree, ObjectData, Orientation, PartialForm, WrappedExpr}; use block_to_expr::block_to_expr; -use expr::{Binding, Expr}; -use hashdb::LinkArena; +use expr::{Binding, Expr, BindTree}; +use hashdb::{LinkArena, TypeStore}; use mouseover::{BottomHover, HoverState, TopHover}; use placing::place_expr; @@ -43,14 +43,15 @@ fn main() { .add_system_set(SystemSet::on_update(AppState::PlacingObject).with_system(placing::placing_system)) - .add_system_set(SystemSet::on_update(AppState::WiringObject).with_system(wiring_system).with_system(connecting_system)) + .add_system_set(SystemSet::on_update(AppState::WiringObject).with_system(wiring_system)) + .add_system_set(SystemSet::on_exit(AppState::WiringObject).with_system(connecting_system)) .add_system(block::data_update).add_system(block::expr_update).add_system(block::hover_update) .add_system(mouseover::mouseover_system) .add_system(state_change_detect) .add_system(ui::button_system) .add_system(bevy::window::exit_on_window_close_system) - .add_system(exprs_forming_system) + .add_system(exprs_forming_system).add_system(reform_system) .init_resource::() .run(); } @@ -153,13 +154,6 @@ fn block_input( } } - -// Component that travels from Variable to Lambda and once it gets there, it changes the state. -#[derive(Component)] -struct WireFinder { - bind: Binding<'static>, -} - #[derive(Debug, Clone, Copy)] enum PortType { Lambda, @@ -184,34 +178,57 @@ struct ActiveWire; #[derive(Component, Debug, Clone)] struct FormConnection(Entity, PortType); +#[derive(Component, Debug, Clone)] +struct TriggerReform; + fn connecting_system( mut commands: Commands, - mut objects: Query<(Entity, &mut ObjectData, &mut WrappedExpr, &FormConnection)> + mut objects: Query<(Entity, &mut ObjectData, &mut WrappedExpr, &FormConnection), Added> ) { for (entity, data, mut expr, conn) in objects.iter_mut() { match (&mut *expr, conn.1) { - (WrappedExpr::Variable { bound }, PortType::Variable) => *bound = Some(conn.0), - (WrappedExpr::Lambda { bind_entity, .. }, PortType::Lambda) => *bind_entity = Some(conn.0), + (WrappedExpr::Variable { formed: (_, bind_tree) }, PortType::Variable) => { + *bind_tree = BindTree::end(conn.0, &LeakStore); + commands.entity(entity).insert(TriggerReform); + debug!("Set bind {entity:?} : {:?} to {:?}", *expr, conn.0); + }, + (WrappedExpr::Lambda { is_bound, .. }, PortType::Lambda) => { + *is_bound = true; + commands.entity(entity).insert(TriggerReform); + debug!("Set bind {entity:?} : {:?} to {:?}", *expr, conn.0); + }, _ => { error!("Invalid connection") } } commands.entity(entity).remove::(); } } +fn reform_system(mut commands: Commands, mut objects: Query<(Entity, &ObjectData, &mut WrappedExpr), Added>) { + for (entity, data, mut expr) in objects.iter_mut() { + debug!("Unformed: {:?}", entity); + expr.unform(); // Remove formed fields + commands.entity(entity).remove::().remove::(); + if let WrappedExpr::Variable { .. } = *expr { commands.entity(entity).insert(Formed); } + if let Some(parent) = data.parent { + commands.entity(parent).insert(TriggerReform).remove::(); + } + } +} // System for wiring things up fn wiring_system( mut commands: Commands, mut app_state: ResMut>, - mut state: ResMut, - mut top_hover: Query<(Entity, &ObjectData, &WrappedExpr, &HoverState), With>, + // mut state: ResMut, + mut top_hover: Query<(Entity, &ObjectData, &WrappedExpr), With>, mut mouse: ResMut>, mut keyboard: ResMut>, mut wire: Query<(Entity, &mut Wire, Option<&mut Path>), With>, mouse_pos: Res, ) { - if let Ok((entity, mut wire, mut path)) = wire.get_single_mut() { + // Start wiring if there is an active wire + if let Ok((wire_entity, mut wire, mut path)) = wire.get_single_mut() { wire.end = Vec2::new(mouse_pos.x, mouse_pos.y); - if let Ok((entity, data, expr, state)) = top_hover.get_single_mut() { + if let Ok((entity, data, expr)) = top_hover.get_single_mut() { if mouse.clear_just_pressed(MouseButton::Left) { match (expr, wire.port) { (WrappedExpr::Variable { .. }, PortType::Lambda) | @@ -220,20 +237,22 @@ fn wiring_system( commands.entity(entity).insert(FormConnection(wire.from, wire.port.swap())); wire.end = data.location; app_state.pop().unwrap(); + commands.entity(wire_entity).remove::(); + debug!("Wired {:?} to {:?}:({expr:?})", wire.from, entity) } _ => {}, } } } if keyboard.clear_just_pressed(KeyCode::Escape) { - commands.entity(entity).despawn(); + commands.entity(wire_entity).despawn(); app_state.pop().unwrap(); } // Build line let mut path_builder = PathBuilder::new(); - path_builder.move_to(wire.start); - path_builder.line_to(wire.end); + path_builder.move_to(Vec2::ZERO); + path_builder.line_to(wire.end - wire.start); let line = path_builder.build(); if let Some(path) = &mut path { **path = line; @@ -241,43 +260,95 @@ fn wiring_system( commands.spawn().insert_bundle(GeometryBuilder::build_as( &line, DrawMode::Stroke(StrokeMode::new(Color::BLACK, 10.0)), - Transform::from_xyz(0.0, 0.0, 1000.0), + Transform::from_translation(wire.start.extend(1000.0)), )); } } } +// *I like to leak it leak it, I like to leak it leak it, I like to leak it leak it, I like to, LEAK IT* +struct LeakStore; +impl TypeStore<'static> for LeakStore { + fn add(&self, val: T) -> &'static T { + Box::leak(Box::new(val)) + } +} +#[derive(Component)] +struct Formed; + fn exprs_forming_system( - mut paramset: ParamSet<(Query<(&ObjectData, &mut WrappedExpr, Entity)>, Query<(&ObjectData, &mut WrappedExpr, Entity)>)> + mut commands: Commands, + formed: Query<(Entity, &ObjectData, &mut WrappedExpr), (With, With)>, + mut unformed: Query<(Entity, &mut WrappedExpr), Without>, ) { - let mut exprs: Vec<(Expr, Entity)> = Vec::new(); - for (data, w_expr, entity) in paramset.p0().iter() { - match w_expr { - WrappedExpr::Variable { bound: Some(_) } => { - exprs.push((Expr::Variable, entity)); - } - WrappedExpr::Application {formed: Some(expr), ..} - | WrappedExpr::Lambda {formed: Some(expr), ..} => { - exprs.push((expr.clone(), entity)); - } - _ => {} - } - } - for (data, mut w_expr, entity) in paramset.p1().iter_mut() { - let mut expr_option: Option<&Expr> = None; - for (e_expr, e_entity) in exprs.iter_mut() { - if entity == *e_entity { - expr_option = Some(e_expr); - } - } - if let Some(expr) = expr_option { - match &mut (*w_expr) { - WrappedExpr::Application { formed, .. } - | WrappedExpr::Lambda { formed, .. } => { - *formed = Some(expr.clone()); + for (f_entity, data, f_wexpr) in formed.iter() { + if let WrappedExpr::Variable { formed: (f_expr, mut f_bind_tree) } + | WrappedExpr::Lambda { formed: Some((f_expr, mut f_bind_tree)), .. } + | WrappedExpr::Application { formed: Some((f_expr, mut f_bind_tree)), .. } = *f_wexpr { + if let Some(Ok((entity, mut wexpr))) = data.parent.map(|parent|unformed.get_mut(parent)) { + match &mut *wexpr { + WrappedExpr::Lambda { + expr_entity: Some(expr_entity), + formed, .. + } if *expr_entity == f_entity => { + let bind = f_bind_tree.pop_binding(&LeakStore, &entity, &LeakStore).unwrap(); + debug!("Using bind: {:?}", bind); + *formed = Some((LeakStore.add(Expr::Lambda { bind, expr: f_expr }), f_bind_tree)); + commands.entity(entity).insert(Formed); + info!("Entity {:?} formed expression: {:?}", entity, *formed); + } + WrappedExpr::Application { + func_entity: Some(func_entity), + args_entity: Some(args_entity), + partial_formed: Some((partial_expr, partial_tree, partial_form)), + formed, + } if formed.is_none() => match partial_form { + PartialForm::Func if *args_entity == f_entity => { + *formed = Some(( + Expr::app(*partial_expr, f_expr, &LeakStore), + BindEntityTree::branch(*partial_tree, f_bind_tree, &LeakStore) + )); + commands.entity(entity).insert(Formed); + info!("Entity {:?} formed expression: {:?}", entity, *formed); + } + PartialForm::Args if *func_entity == f_entity => { + *formed = Some(( + Expr::app(f_expr, *partial_expr, &LeakStore), + BindEntityTree::branch(f_bind_tree, *partial_tree, &LeakStore) + )); + commands.entity(entity).insert(Formed); + info!("Entity {:?} formed expression: {:?}", entity, *formed); + } + _ => { warn!("Entity {:?} Couldn't form partial form with expression {:?}", entity, *wexpr); } + } + WrappedExpr::Application { + func_entity: Some(func_entity), + args_entity: _, + partial_formed, + formed: None, + } if partial_formed.is_none() && *func_entity == f_entity => { + *partial_formed = Some((f_expr, f_bind_tree, PartialForm::Func)); + info!("Entity {:?} formed partial expression for: {:?}", entity, PartialForm::Func); + } + WrappedExpr::Application { + func_entity: _, + args_entity: Some(args_entity), + partial_formed, + formed: None, + } if partial_formed.is_none() && *args_entity == f_entity => { + *partial_formed = Some((f_expr, f_bind_tree, PartialForm::Args)); + info!("Entity {:?} formed partial expression for: {:?}", entity, PartialForm::Args); + } + WrappedExpr::Variable { .. } => { + commands.entity(entity).insert(Formed); + warn!("Variable not set to Formed for some reason"); + } + _ => { warn!("Entity {:?} couldn't form expression: {:?}", entity, *wexpr); } } - _ => {} } + } else { + warn!("Entity {f_entity:?} did not have formed field but had Formed component"); + commands.entity(f_entity).remove::(); } } } \ No newline at end of file diff --git a/block-lang/src/parse.rs b/block-lang/src/parse.rs index eea6c86..6ecc52e 100644 --- a/block-lang/src/parse.rs +++ b/block-lang/src/parse.rs @@ -80,7 +80,7 @@ fn parser<'e: 'b, 'b, B: TypeStore<'b>, E: TypeStore<'e>>(namespace: &'b Namespa }); 0..symbols.len() }).then(expr.clone()).foldr(|_, (lam_expr, mut bind_tree)| { - let binding = bind_tree.pop_binding(binds, bind_map.pop_bind(), exprs).expect("failed to pop lambda"); + let binding = bind_tree.pop_binding(binds, &bind_map.pop_bind(), exprs).expect("failed to pop lambda"); (Expr::lambda(binding, lam_expr, exprs), bind_tree) }).labelled("lambda"); diff --git a/block-lang/src/placing.rs b/block-lang/src/placing.rs index a70067e..decaad7 100644 --- a/block-lang/src/placing.rs +++ b/block-lang/src/placing.rs @@ -5,7 +5,7 @@ use std::f32::consts::FRAC_1_SQRT_2; use bevy::prelude::*; use bevy_mouse_tracking_plugin::{MainCamera, MousePosWorld}; -use crate::{AppState, GameState, block::{WrappedExpr, Object, ObjectData, Orientation}, mouseover::{HoverState, Side, TopHover}}; +use crate::{AppState, Formed, GameState, block::{WrappedExpr, Object, ObjectData, Orientation}, mouseover::{HoverState, Side, TopHover}}; #[derive(Component, Default, Clone)] pub struct Placing; @@ -16,7 +16,7 @@ pub fn place_expr( state: &mut GameState, expr: WrappedExpr, ) { - info!("Placing: {:?}", expr); + debug!("Placing: {:?}", expr); match app_state.current() { AppState::Default => { state.just_pressed = true; // Prevent a single mouse click @@ -59,6 +59,7 @@ pub fn placing_system( *expr = new_expr; } + let mut follow_mouse = true; if let Ok((h_entity, mut h_data, mut h_expr, HoverState::Yes { side, .. })) = top_hover.get_single_mut() { // Make sure we can place block if let Some((side, expr_slot)) = match (&mut *h_expr, side) { @@ -75,6 +76,7 @@ pub fn placing_system( } (_, _) => None, } { + follow_mouse = false; let size = (h_data.size * FRAC_1_SQRT_2) * 0.90; data.orientation = h_data.orientation.swap(); data.size = size; @@ -91,7 +93,10 @@ pub fn placing_system( // Place block inside another block if mouse.clear_just_pressed(MouseButton::Left) { - state.just_pressed = true; + // Variables are formed expressions + if let WrappedExpr::Variable { .. } = *expr { commands.entity(entity).insert(Formed); } + debug!("Placed inside {:?} on {:?} side: {:?}, {:?}", h_entity, side, entity, expr); + *expr_slot = Some(entity); data.parent = Some(h_entity); // commands.entity(h_entity).add_child(entity); // DONT DO THIS, YOUR LIFE WILL BE PAINNNN @@ -100,13 +105,18 @@ pub fn placing_system( return; } } - } else { + } + if follow_mouse { data.size = camera_proj.iter().next().unwrap().scale * 300.0; // Scale block-to-place with size data.location = Vec2::new(mouse_pos.x, mouse_pos.y); // Move block-to-place to mouse cursor data.orientation = state.placing_orientation; // Set orientation based on game state // Place block on blank canvas (if there are no objects in scene) if mouse.clear_just_pressed(MouseButton::Left) && top_hover.is_empty() { + // Variables are formed expressions + if let WrappedExpr::Variable { .. } = *expr { commands.entity(entity).insert(Formed); } + debug!("Placed on canvas {:?}, {:?}", entity, expr); + state.just_pressed = true; commands.entity(entity).remove::().insert(HoverState::No); app_state.pop().unwrap(); diff --git a/block-lang/src/ui.rs b/block-lang/src/ui.rs index 60fdc24..6334b0d 100644 --- a/block-lang/src/ui.rs +++ b/block-lang/src/ui.rs @@ -64,7 +64,7 @@ pub fn ui_setup(mut commands: Commands, asset_server: Res) { build_button( parent, - asset_server.load("VariableDot.png"), + asset_server.load("VarState=None.png"), |commands, app_state, state| { place_expr(commands, app_state, state, WrappedExpr::VARIABLE); info!("Added variable"); @@ -72,7 +72,7 @@ pub fn ui_setup(mut commands: Commands, asset_server: Res) { ); build_button( parent, - asset_server.load("Lambda.png"), + asset_server.load("LamState=None.png"), |commands, app_state, state| { place_expr( commands, @@ -85,7 +85,7 @@ pub fn ui_setup(mut commands: Commands, asset_server: Res) { ); build_button( parent, - asset_server.load("Application.png"), + asset_server.load("AppState=None.png"), |commands, app_state, state| { place_expr( commands, diff --git a/block-lang/tmp-lang b/block-lang/tmp-lang deleted file mode 160000 index 7ed3533..0000000 --- a/block-lang/tmp-lang +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7ed35338791af0486dc22623ab65459238ec2ece diff --git a/block-lang/vendor/bevy-mouse-tracking/.github/workflows/ci.yml b/block-lang/vendor/bevy-mouse-tracking/.github/workflows/ci.yml deleted file mode 100644 index 25d61e0..0000000 --- a/block-lang/vendor/bevy-mouse-tracking/.github/workflows/ci.yml +++ /dev/null @@ -1,67 +0,0 @@ -on: [pull_request] - -name: CI - -jobs: - - test: - name: Test Suite - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - - fmt: - name: Rustfmt - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - run: rustup component add rustfmt - - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check - - clippy: - name: Clippy - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - run: rustup component add clippy - - uses: actions-rs/cargo@v1 - with: - command: clippy - args: -- -D warnings - - readme: - name: README - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - run: cargo install cargo-rdme - - uses: actions-rs/cargo@v1 - with: - command: rdme - args: --check diff --git a/block-lang/vendor/bevy-mouse-tracking/.gitignore b/block-lang/vendor/bevy-mouse-tracking/.gitignore deleted file mode 100644 index 96ef6c0..0000000 --- a/block-lang/vendor/bevy-mouse-tracking/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock diff --git a/block-lang/vendor/bevy-mouse-tracking/Cargo.toml b/block-lang/vendor/bevy-mouse-tracking/Cargo.toml deleted file mode 100644 index f74ac26..0000000 --- a/block-lang/vendor/bevy-mouse-tracking/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "bevy_mouse_tracking_plugin" -description = "A plugin for effortless mouse tracking in the bevy game engine." -version = "0.2.1" -authors = ["JoJoJet "] -edition = "2021" -license = "MIT" -repository = "https://github.com/JoJoJet/bevy-mouse-tracking" -keywords = ["gamedev", "bevy", "mouse", "input"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies.bevy] -version = "0.7.*" -default-features = false -features = [ "render" ] - -[dev-dependencies.bevy] -version = "0.7.*" -default-features = false -features = [ "render", "png", "bevy_winit" ] diff --git a/block-lang/vendor/bevy-mouse-tracking/README.md b/block-lang/vendor/bevy-mouse-tracking/README.md deleted file mode 100644 index 4b0795c..0000000 --- a/block-lang/vendor/bevy-mouse-tracking/README.md +++ /dev/null @@ -1,180 +0,0 @@ -# bevy_mouse_tracking_plugin - - - -[![CI](https://github.com/JoJoJet/bevy-mouse-tracking/actions/workflows/ci.yml/badge.svg)](https://github.com/JoJoJet/bevy-mouse-tracking/workflows/ci.yml) -[![bevy_mouse_tracking on crates.io](https://img.shields.io/crates/v/bevy_mouse_tracking_plugin.svg)](https://crates.io/crates/bevy_mouse_tracking_plugin) -[![bevy_mouse_tracking docs](https://img.shields.io/badge/docs-docs.rs-orange.svg)](https://docs.rs/bevy_mouse_tracking_plugin) - -Tracking the mouse in `bevy` is kind of annoying. -You gotta use [`Events`], and [`EventReader`]s, and even then, they only -get called when the mouse actually *moves*. - -[`Events`]: bevy::ecs::event::Events -[`EventReader`]: bevy::ecs::event::EventReader - -This crate aims to make this as easy as possible, by providing a -static [resource](bevy::ecs::system::Res) that tracks the mouse position every frame. - -This crate also supports more complex use cases such as multiple cameras, which are discussed further down. - -## Basics - -First, add the plugin to your app: - -```rust -use bevy::prelude::*; -use bevy_mouse_tracking_plugin::MousePosPlugin; - -App::new() - .add_plugins(DefaultPlugins) - .add_plugin(MousePosPlugin::SingleCamera); -``` - -Now, you can access the resource in your [`System`]s: - -[`System`]: bevy::ecs::system::System - -```rust -use bevy_mouse_tracking_plugin::MousePos; -fn dbg_mouse(mouse: Res) { - eprintln!("{}", *mouse); -} -``` -...and don't forget to add the system to your app: -```rust - .add_plugin(MousePosPlugin::SingleCamera) - .add_system(dbg_mouse); - -``` - -This will print the screen-space location of the mouse on every frame. - -However, we can do better than just screen-space: we support automatic -transformation to world-space coordinates via the [`MousePosWorld`] resource. - -```rust -use bevy_mouse_tracking_plugin::MousePosWorld; -fn dbg_world(mouse: Res) { - eprintln!("{}", *mouse); -} -``` - -This will print the world-space location of the mouse on every frame. -Note that this is only supported for two-dimensional, orthographic camera, -but pull requests for 3D support are welcome! - -## Multiple cameras - -You may notice that if you try to use this plugin in an app that has multiple cameras, it crashes! - -```rust - -App::new() - .add_plugins(DefaultPlugins) - .add_plugin(MousePosPlugin::SingleCamera) - .add_startup_system(setup) - .run(); - -fn setup(mut commands: Commands) { - commands.spawn_bundle(OrthographicCameraBundle::new_2d()); - commands.spawn_bundle(UiCameraBundle::default()); -} -``` - -This panics with the following output: - -```text -thread 'main' panicked at 'cannot identify main camera -- consider adding the MainCamera component to one of the cameras', src\mouse_pos.rs:163:13 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -``` - -This is because the plugin doesn't know which of the two cameras to use when figuring out -the values of the `MousePos` and `MousePosWorld` resources. Let's take the panic message's advice. - -```rust - commands.spawn_bundle(OrthographicCameraBundle::new_2d()) - .insert(MainCamera); // added this line - commands.spawn_bundle(UiCameraBundle::default()); -``` - -### Queries - -If you want to get mouse tracking information relative to each camera individually, -simply [query](bevy::ecs::system::Query) for a `MousePos` or `MousePosWorld` as a -_component_ instead of as a resource. - -```rust - -App::new() - // plugins omitted... - .add_system(dbg_for_each); - -fn dbg_for_each(mouse_pos: Query<&MousePosWorld>) { - for pos in mouse_pos.iter() { - // This prints the mouse position twice per frame: - // once relative to the UI camera, and once relative to the physical camera. - eprintln!("{}", *pos); - } -} -``` - -If you want the mouse position for a specific camera, you can add query filters as always. -Note that as of `bevy 0.6`, the only way to tell the difference between a UI camera and -an orthographic camera is by checking for the [`Frustum`] component. - -[`Frustum`]: bevy::render::primitives::Frustum - -```rust - - -use bevy::render::primitives::Frustum; -fn dbg_ui_pos(mouse_pos: Query<&MousePosWorld, Without>) { - // query for the UI camera, which doesn't have a Frustum component. - let pos = mouse_pos.single(); - eprintln!("{}", *pos); -} -``` - -### No main camera - -Let's say you have multiple cameras in your app, and you want to treat them all equally, -without declaring any one of them as the main camera. -Change the plugin to this: - -```rust -App::new() - .add_plugins(DefaultPlugins) - .add_plugin(MousePosPlugin::MultiCamera) // SingleCamera -> MultiCamera - .add_startup_system(setup) - // ... - -``` - -Now, you can add as many cameras as you want, without having to worry about marking any -of them as the main camera. -Note that `MousePos` and `MousePosWorld` will no longer be accessible as global resources --- you can only access them by `Query`ing camera entities. - -## Mouse motion - -This crate supports a resource that tracks mouse motion, via [`MouseMotionPlugin`]. -The motion can be accessed from any system in a [`MouseMotion`] resource. - -[`Res`]: bevy::ecs::system::Res - -## Crate name - -As a final aside: the name of this crate is intentionally verbose. -This is because I didn't want to steal a crate name, especially since -it is very likely that this crate will eventually be made redundant by -future updates to `bevy`. -I recommend renaming the crate in your `Cargo.toml`: -```toml -[dependencies] -mouse_tracking = { package = "bevy_mouse_tracking_plugin", version = "..." } -``` - - - -License: MIT diff --git a/block-lang/vendor/bevy-mouse-tracking/assets/FiraMono-Medium.ttf b/block-lang/vendor/bevy-mouse-tracking/assets/FiraMono-Medium.ttf deleted file mode 100755 index 1e95ced4c44be8648f1555ab8c135a6799f8c5a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 173516 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

>(@<@>0tc& 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 z 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

*N&HECA^t4B6n_zy#b3o&;&0-L_`CR8{6kz7 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 H_|N|V7~3XI diff --git a/block-lang/vendor/bevy-mouse-tracking/assets/cursor.png b/block-lang/vendor/bevy-mouse-tracking/assets/cursor.png deleted file mode 100644 index 7c3721f5d27b43e650c5242362f00aa817656673..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 400 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCik#1AIbU z|NsC0@83Tl2?5A#m>7ZvY65Z`ZscqSvII(k{DSA-&#zyL#57f|gwzrh@ES^OfP-?05DTCjT`8`kTSi L)z4*}Q$iB}vXHbA diff --git a/block-lang/vendor/bevy-mouse-tracking/assets/origin.png b/block-lang/vendor/bevy-mouse-tracking/assets/origin.png deleted file mode 100644 index ca83cce331220c54d69202fa8603d8cd02544ca4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|emUKs7M+SzC{oH>NS%G|s0G|-o z|4889zkfg;PzFfmqzAnKve-+4{DR-x=dZtio?&9`&AC7!drud~5Rc=@9?q;!pJp)e zEar0C#KdE;DnUb2qn$}3{)T|udx3^^3VWtBFnt$d;u4v0LA2-CQG+mpD8IfOR)$SU W=Gh^YSC0dYV(@hJb6Mw<&;$TiE=Jn` diff --git a/block-lang/vendor/bevy-mouse-tracking/examples/screen.rs b/block-lang/vendor/bevy-mouse-tracking/examples/screen.rs deleted file mode 100644 index 55ed526..0000000 --- a/block-lang/vendor/bevy-mouse-tracking/examples/screen.rs +++ /dev/null @@ -1,67 +0,0 @@ -use bevy::prelude::*; - -use bevy_mouse_tracking_plugin::{MousePos, MousePosPlugin}; - -#[derive(Component)] -struct Cursor; - -#[derive(Component)] -struct Hud; - -fn main() { - App::new() - .add_plugins(DefaultPlugins) - .insert_resource(ClearColor(Color::BLACK)) - .insert_resource(WindowDescriptor::default()) - .add_plugin(MousePosPlugin::SingleCamera) - .add_startup_system(setup) - .add_system(bevy::input::system::exit_on_esc_system) - .add_system(run) - .run(); -} - -fn setup(mut commands: Commands, asset_server: Res, window: Res) { - // Spawn a Camera - commands.spawn_bundle(OrthographicCameraBundle::new_2d()); - - // Reference for the origin - commands.spawn_bundle(SpriteBundle { - texture: asset_server.load("origin.png"), - ..Default::default() - }); - - // Hud - let font = asset_server.load("FiraMono-Medium.ttf"); - let style = TextStyle { - font, - font_size: 24.0, - color: Color::ORANGE, - }; - let alignment = TextAlignment { - vertical: VerticalAlign::Top, - horizontal: HorizontalAlign::Left, - }; - let (win_width, win_height) = (window.width, window.height); - let (hud_x, hud_y) = (win_width / 2. * -1., win_height / 2.); - let translation = Vec3::new(hud_x, hud_y, 0.); - let transform = Transform::from_translation(translation); - let value = "Mouse: (-, -)".to_string(); - - commands - .spawn_bundle(Text2dBundle { - text: Text::with_section(value, style.clone(), alignment), - transform, - ..Default::default() - }) - .insert(Hud); -} - -fn run(mouse_pos: Res, mut hud_text: Query<&mut Text, With>) { - let hud_value = format!("Mouse: ({}, {})", mouse_pos.x, mouse_pos.y,); - - if let Some(mut hud_text) = hud_text.iter_mut().next() { - hud_text.sections.first_mut().unwrap().value = hud_value.clone(); - } else { - println!("No Hud Found"); - } -} diff --git a/block-lang/vendor/bevy-mouse-tracking/examples/world.rs b/block-lang/vendor/bevy-mouse-tracking/examples/world.rs deleted file mode 100644 index f26a1bc..0000000 --- a/block-lang/vendor/bevy-mouse-tracking/examples/world.rs +++ /dev/null @@ -1,87 +0,0 @@ -use bevy::prelude::*; - -use bevy_mouse_tracking_plugin::{MousePos, MousePosPlugin, MousePosWorld}; - -#[derive(Component)] -struct Cursor; - -#[derive(Component)] -struct Hud; - -fn main() { - App::new() - .add_plugins(DefaultPlugins) - .insert_resource(ClearColor(Color::BLACK)) - .insert_resource(WindowDescriptor::default()) - .add_plugin(MousePosPlugin::SingleCamera) - .add_startup_system(setup) - .add_system(bevy::input::system::exit_on_esc_system) - .add_system(run) - .run(); -} - -fn setup(mut commands: Commands, asset_server: Res, window: Res) { - // Spawn a Camera - let mut camera_bundle = OrthographicCameraBundle::new_2d(); - camera_bundle.orthographic_projection.scale = 0.5; // works fine with non-unit scaling. - commands.spawn_bundle(camera_bundle); - - // Reference for the origin - commands.spawn_bundle(SpriteBundle { - texture: asset_server.load("origin.png"), - ..Default::default() - }); - - // Reference for the mouse position - commands - .spawn_bundle(SpriteBundle { - texture: asset_server.load("cursor.png"), - ..Default::default() - }) - .insert(Cursor); - - // Hud - let font = asset_server.load("FiraMono-Medium.ttf"); - let style = TextStyle { - font, - font_size: 24.0, - color: Color::ORANGE, - }; - let alignment = TextAlignment { - vertical: VerticalAlign::Top, - horizontal: HorizontalAlign::Left, - }; - let (win_width, win_height) = (window.width, window.height); - let (hud_x, hud_y) = (win_width / 2. * -1., win_height / 2.); - let translation = Vec3::new(hud_x, hud_y, 0.); - let transform = Transform::from_translation(translation); - let value = "Screen: (-, -)\nWorld: (-, -)".to_string(); - - commands - .spawn_bundle(Text2dBundle { - text: Text::with_section(value, style.clone(), alignment), - transform, - ..Default::default() - }) - .insert(Hud); -} - -fn run( - mouse_screen_pos: Res, - mouse_world_pos: Res, - mut hud_text: Query<&mut Text, With>, - mut cursor: Query<&mut Transform, With>, -) { - let hud_value = format!( - "Screen: ({}, {})\nWorld: ({}, {})", - mouse_screen_pos.x, mouse_screen_pos.y, mouse_world_pos.x, mouse_world_pos.y, - ); - - if let Some(mut hud_text) = hud_text.iter_mut().next() { - hud_text.sections.first_mut().unwrap().value = hud_value.clone(); - } - - if let Some(mut cursor_transform) = cursor.iter_mut().next() { - cursor_transform.translation = Vec3::new(mouse_world_pos.x, mouse_world_pos.y, 0.); - } -} diff --git a/block-lang/vendor/bevy-mouse-tracking/src/lib.rs b/block-lang/vendor/bevy-mouse-tracking/src/lib.rs deleted file mode 100644 index d2a9d84..0000000 --- a/block-lang/vendor/bevy-mouse-tracking/src/lib.rs +++ /dev/null @@ -1,213 +0,0 @@ -//! [![CI](https://github.com/JoJoJet/bevy-mouse-tracking/actions/workflows/ci.yml/badge.svg)](https://github.com/JoJoJet/bevy-mouse-tracking/workflows/ci.yml) -//! [![bevy_mouse_tracking on crates.io](https://img.shields.io/crates/v/bevy_mouse_tracking_plugin.svg)](https://crates.io/crates/bevy_mouse_tracking_plugin) -//! [![bevy_mouse_tracking docs](https://img.shields.io/badge/docs-docs.rs-orange.svg)](https://docs.rs/bevy_mouse_tracking_plugin) -//! -//! Tracking the mouse in `bevy` is kind of annoying. -//! You gotta use [`Events`], and [`EventReader`]s, and even then, they only -//! get called when the mouse actually *moves*. -//! -//! [`Events`]: bevy::ecs::event::Events -//! [`EventReader`]: bevy::ecs::event::EventReader -//! -//! This crate aims to make this as easy as possible, by providing a -//! static [resource](bevy::ecs::system::Res) that tracks the mouse position every frame. -//! -//! This crate also supports more complex use cases such as multiple cameras, which are discussed further down. -//! -//! # Basics -//! -//! First, add the plugin to your app: -//! -//! ``` -//! use bevy::prelude::*; -//! use bevy_mouse_tracking_plugin::MousePosPlugin; -//! -//! App::new() -//! .add_plugins(DefaultPlugins) -//! .add_plugin(MousePosPlugin::SingleCamera); -//! ``` -//! -//! Now, you can access the resource in your [`System`]s: -//! -//! [`System`]: bevy::ecs::system::System -//! -//! ``` -//! # use bevy::prelude::*; -//! use bevy_mouse_tracking_plugin::MousePos; -//! fn dbg_mouse(mouse: Res) { -//! eprintln!("{}", *mouse); -//! } -//! ``` -//! ...and don't forget to add the system to your app: -//! ``` -//! # use bevy::prelude::*; -//! # use bevy_mouse_tracking_plugin::MousePosPlugin; -//! # App::new() -//! # .add_plugins(DefaultPlugins) -//! .add_plugin(MousePosPlugin::SingleCamera) -//! .add_system(dbg_mouse); -//! -//! # fn dbg_mouse() { } -//! ``` -//! -//! This will print the screen-space location of the mouse on every frame. -//! -//! However, we can do better than just screen-space: we support automatic -//! transformation to world-space coordinates via the [`MousePosWorld`] resource. -//! -//! ``` -//! # use bevy::prelude::*; -//! use bevy_mouse_tracking_plugin::MousePosWorld; -//! fn dbg_world(mouse: Res) { -//! eprintln!("{}", *mouse); -//! } -//! ``` -//! -//! This will print the world-space location of the mouse on every frame. -//! Note that this is only supported for two-dimensional, orthographic camera, -//! but pull requests for 3D support are welcome! -//! -//! # Multiple cameras -//! -//! You may notice that if you try to use this plugin in an app that has multiple cameras, it crashes! -//! -//! ```should_panic -//! # use bevy::prelude::*; -//! # use bevy_mouse_tracking_plugin::MousePosPlugin; -//! -//! App::new() -//! .add_plugins(DefaultPlugins) -//! .add_plugin(MousePosPlugin::SingleCamera) -//! .add_startup_system(setup) -//! .run(); -//! -//! fn setup(mut commands: Commands) { -//! commands.spawn_bundle(OrthographicCameraBundle::new_2d()); -//! commands.spawn_bundle(UiCameraBundle::default()); -//! } -//! ``` -//! -//! This panics with the following output: -//! -//! ```text -//! thread 'main' panicked at 'cannot identify main camera -- consider adding the MainCamera component to one of the cameras', src\mouse_pos.rs:163:13 -//! note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -//! ``` -//! -//! This is because the plugin doesn't know which of the two cameras to use when figuring out -//! the values of the `MousePos` and `MousePosWorld` resources. Let's take the panic message's advice. -//! -//! ``` -//! # use bevy::prelude::*; -//! # use bevy_mouse_tracking_plugin::{MousePosPlugin, MainCamera}; -//! # App::new() -//! # .add_plugins(DefaultPlugins) -//! # .add_plugin(MousePosPlugin::SingleCamera) -//! # .add_startup_system(setup) -//! # .update(); -//! # fn setup(mut commands: Commands) { -//! commands.spawn_bundle(OrthographicCameraBundle::new_2d()) -//! .insert(MainCamera); // added this line -//! commands.spawn_bundle(UiCameraBundle::default()); -//! # } -//! ``` -//! -//! ## Queries -//! -//! If you want to get mouse tracking information relative to each camera individually, -//! simply [query](bevy::ecs::system::Query) for a `MousePos` or `MousePosWorld` as a -//! _component_ instead of as a resource. -//! -//! ``` -//! # use bevy::prelude::*; -//! # use bevy_mouse_tracking_plugin::{MousePosPlugin, MainCamera, MousePosWorld}; -//! -//! App::new() -//! // plugins omitted... -//! # .add_plugins(DefaultPlugins) -//! # .add_plugin(MousePosPlugin::SingleCamera) -//! .add_system(dbg_for_each); -//! -//! fn dbg_for_each(mouse_pos: Query<&MousePosWorld>) { -//! for pos in mouse_pos.iter() { -//! // This prints the mouse position twice per frame: -//! // once relative to the UI camera, and once relative to the physical camera. -//! eprintln!("{}", *pos); -//! } -//! } -//! ``` -//! -//! If you want the mouse position for a specific camera, you can add query filters as always. -//! Note that as of `bevy 0.6`, the only way to tell the difference between a UI camera and -//! an orthographic camera is by checking for the [`Frustum`] component. -//! -//! [`Frustum`]: bevy::render::primitives::Frustum -//! -//! ``` -//! # use bevy::prelude::*; -//! # use bevy_mouse_tracking_plugin::{MousePosPlugin, MainCamera, MousePosWorld}; -//! -//! # App::new() -//! # .add_plugins(DefaultPlugins) -//! # .add_plugin(MousePosPlugin::SingleCamera) -//! # .add_system(dbg_ui_pos); -//! -//! use bevy::render::primitives::Frustum; -//! fn dbg_ui_pos(mouse_pos: Query<&MousePosWorld, Without>) { -//! // query for the UI camera, which doesn't have a Frustum component. -//! let pos = mouse_pos.single(); -//! eprintln!("{}", *pos); -//! } -//! ``` -//! -//! ## No main camera -//! -//! Let's say you have multiple cameras in your app, and you want to treat them all equally, -//! without declaring any one of them as the main camera. -//! Change the plugin to this: -//! -//! ``` -//! # use bevy::prelude::*; -//! # use bevy_mouse_tracking_plugin::{MousePosPlugin}; -//! App::new() -//! .add_plugins(DefaultPlugins) -//! .add_plugin(MousePosPlugin::MultiCamera) // SingleCamera -> MultiCamera -//! .add_startup_system(setup) -//! // ... -//! # .update(); -//! -//! # fn setup(mut commands: Commands) { -//! # commands.spawn_bundle(OrthographicCameraBundle::new_2d()); -//! # commands.spawn_bundle(UiCameraBundle::default()); -//! # } -//! ``` -//! -//! Now, you can add as many cameras as you want, without having to worry about marking any -//! of them as the main camera. -//! Note that `MousePos` and `MousePosWorld` will no longer be accessible as global resources -//! -- you can only access them by `Query`ing camera entities. -//! -//! # Mouse motion -//! -//! This crate supports a resource that tracks mouse motion, via [`MouseMotionPlugin`]. -//! The motion can be accessed from any system in a [`MouseMotion`] resource. -//! -//! [`Res`]: bevy::ecs::system::Res -//! -//! # Crate name -//! -//! As a final aside: the name of this crate is intentionally verbose. -//! This is because I didn't want to steal a crate name, especially since -//! it is very likely that this crate will eventually be made redundant by -//! future updates to `bevy`. -//! I recommend renaming the crate in your `Cargo.toml`: -//! ```toml -//! [dependencies] -//! mouse_tracking = { package = "bevy_mouse_tracking_plugin", version = "..." } -//! ``` - -mod mouse_pos; -pub use mouse_pos::{MainCamera, MousePos, MousePosPlugin, MousePosWorld}; - -mod mouse_motion; -pub use mouse_motion::{MouseMotion, MouseMotionPlugin}; diff --git a/block-lang/vendor/bevy-mouse-tracking/src/mouse_motion.rs b/block-lang/vendor/bevy-mouse-tracking/src/mouse_motion.rs deleted file mode 100644 index d3688c2..0000000 --- a/block-lang/vendor/bevy-mouse-tracking/src/mouse_motion.rs +++ /dev/null @@ -1,18 +0,0 @@ -use bevy::prelude::*; - -/// Plugin that tracks mouse motion. -pub struct MouseMotionPlugin; - -pub use bevy::input::mouse::MouseMotion; - -impl bevy::app::Plugin for MouseMotionPlugin { - fn build(&self, app: &mut bevy::app::App) { - app.insert_resource(MouseMotion { delta: Vec2::ZERO }); - app.add_system_to_stage(CoreStage::First, update_mouse_motion); - } -} - -fn update_mouse_motion(mut events: EventReader, mut res: ResMut) { - let delta = events.iter().fold(Vec2::ZERO, |acc, e| acc + e.delta); - *res = MouseMotion { delta }; -} diff --git a/block-lang/vendor/bevy-mouse-tracking/src/mouse_pos.rs b/block-lang/vendor/bevy-mouse-tracking/src/mouse_pos.rs deleted file mode 100644 index 1dd18fe..0000000 --- a/block-lang/vendor/bevy-mouse-tracking/src/mouse_pos.rs +++ /dev/null @@ -1,225 +0,0 @@ -use std::{fmt::Display, ops::Deref}; - -use bevy::prelude::*; - -/// Plugin that tracks the mouse location. -pub enum MousePosPlugin { - /// Configuration for apps that have a single main camera. - /// Provides global Resources for [`MousePos`] and [`MousePosWorld`]. - SingleCamera, - /// Configuration for apps that have multiple cameras which must be handled separately. - MultiCamera, -} - -impl Plugin for MousePosPlugin { - fn build(&self, app: &mut App) { - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, SystemLabel)] - enum MouseSystem { - ScreenPos, - WorldPos, - FindMain, - } - - // System to add mouse tracking components. - // Runs once at the end of each frame. This means that no cameras will have - // mouse tracking components until after the first frame. - // This might cause some issues, but it's probably for the best since, - // during the first frame, nothing has been rendered yet. - app.add_system_to_stage(CoreStage::PostUpdate, add_pos_components); - - app.add_system_to_stage(CoreStage::First, update_pos.label(MouseSystem::ScreenPos)); - app.add_system_to_stage( - CoreStage::First, - update_pos_ortho - .label(MouseSystem::WorldPos) - .after(MouseSystem::ScreenPos), - ); - - match self { - Self::SingleCamera => { - app.insert_resource(MousePos(Default::default())); - app.insert_resource(MousePosWorld(Default::default())); - app.init_resource::(); - - // system to update the current main camera - app.add_system_set_to_stage( - CoreStage::First, - SystemSet::new() - .label(MouseSystem::FindMain) - .with_run_criteria(main_camera_changed) - .with_system(find_main_camera), - ); - // - app.add_system_to_stage( - CoreStage::First, - update_resources - .after(MouseSystem::WorldPos) - .after(MouseSystem::FindMain), - ); - } - Self::MultiCamera => {} - } - } -} - -/// The location of the mouse in screenspace. -/// This will be updated every frame during [`CoreStage::First`]. Any systems that rely -/// on this should come after `CoreStage::First`. -#[derive(Debug, Clone, Copy, PartialEq, Component)] -pub struct MousePos(Vec2); - -impl Deref for MousePos { - type Target = Vec2; - fn deref(&self) -> &Vec2 { - &self.0 - } -} - -impl Display for MousePos { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.0.fmt(f) - } -} - -fn add_pos_components( - cameras1: Query<(Entity, &Camera), Without>, - cameras2: Query, Without)>, - windows: Res, - mut commands: Commands, -) { - for (e, camera) in cameras1.iter() { - if let RenderTarget::Window(window_id) = camera.target { - // get the initial position of the cursor. - let position = windows - .get(window_id) - .and_then(|w| w.cursor_position()) - .unwrap_or_default(); - commands.entity(e).insert(MousePos(position)); - } - } - for cam in cameras2.iter() { - commands - .entity(cam) - .insert(MousePosWorld(Default::default())); - } -} - -fn update_pos( - mut movement: EventReader, - mut cameras: Query<(&Camera, &mut MousePos)>, -) { - for &CursorMoved { id, position } in movement.iter() { - // find all cameras corresponding to the window on which the cursor moved. - for (_, mut pos) in cameras - .iter_mut() - .filter(|(c, ..)| c.target == RenderTarget::Window(id)) - { - pos.0 = position; - } - } -} - -/// The location of the mouse in worldspace. -/// This will be updated every frame during [`CoreStage::First`]. Any systems that rely -/// on this should come after `CoreStage::First`. -#[derive(Debug, Clone, Copy, PartialEq, Component)] -pub struct MousePosWorld(Vec3); - -impl Display for MousePosWorld { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - self.0.fmt(f) - } -} - -impl Deref for MousePosWorld { - type Target = Vec3; - fn deref(&self) -> &Vec3 { - &self.0 - } -} - -fn update_pos_ortho( - mut tracking: Query<(Entity, &mut MousePosWorld, &MousePos), Changed>, - cameras: Query<(&GlobalTransform, &OrthographicProjection)>, -) { - for (camera, mut world, screen) in tracking.iter_mut() { - let (camera, proj) = cameras - .get(camera) - .expect("only orthographic cameras are supported"); - let offset = Vec2::new(proj.left, proj.bottom); - - // Must multiply by projection scale before applying camera global transform - // Otherwise you get weird offset mouse positions when both scaling and panning the camera. - world.0 = camera.mul_vec3(((screen.0 + offset) * proj.scale).extend(0.0)); - } -} - -/// Marker component for the primary camera in the world. -/// If only one camera exists, this is optional. -#[derive(Debug, Clone, Copy, Component)] -pub struct MainCamera; - -/// Resource that caches the main camera, so it doesn't need to be looked up every frame. -/// This is an implementation detail and thus should not be part of the public api. -#[derive(Debug, Default)] -struct MainCameraStore(Option); - -// only run when the candidates for the main camera change. -use bevy::ecs::schedule::ShouldRun; -use bevy::render::camera::RenderTarget; - -fn main_camera_changed( - cam: Query>, - main: Query>, -) -> ShouldRun { - if !cam.is_empty() || !main.is_empty() { - ShouldRun::Yes - } else { - ShouldRun::No - } -} - -fn find_main_camera( - mut main_store: ResMut, - cameras: Query<(Entity, Option<&MainCamera>), With>, -) { - use bevy::ecs::system::QuerySingleError; - main_store.0 = match cameras.get_single() { - Ok((e, ..)) => Some(e), - Err(QuerySingleError::NoEntities(_)) => { - // no main camera exists - None - } - Err(QuerySingleError::MultipleEntities(_)) => { - // try to disambiguate - let mut mains = cameras.iter().filter_map(|(e, main)| main.and(Some(e))); - let main = mains.next().unwrap_or_else(|| { - panic!("cannot identify main camera -- consider adding the MainCamera component to one of the cameras") - }); - if mains.next().is_some() { - panic!("only one camera may be marked with the MainCamera component"); - } - Some(main) - } - } -} - -fn update_resources( - mut screen_res: ResMut, - mut world_res: ResMut, - main: Res, - screen: Query<&MousePos, Changed>, - world: Query<&MousePosWorld, Changed>, -) { - let main = match main.0 { - Some(m) => m, - None => return, // no main camera, try again next frame - }; - // update the global resources if the components for the main camera changed. - if let Ok(screen) = screen.get(main) { - screen_res.0 = screen.0; - } - if let Ok(world) = world.get(main) { - world_res.0 = world.0; - } -} diff --git a/block-lang/vendor/bevy_pancam/.gitignore b/block-lang/vendor/bevy_pancam/.gitignore deleted file mode 100644 index 96ef6c0..0000000 --- a/block-lang/vendor/bevy_pancam/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock diff --git a/block-lang/vendor/bevy_pancam/Cargo.toml b/block-lang/vendor/bevy_pancam/Cargo.toml deleted file mode 100644 index 8c6c946..0000000 --- a/block-lang/vendor/bevy_pancam/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "bevy_pancam" -version = "0.3.0" -edition = "2021" -license = "MIT OR Apache-2.0" -readme = "readme.md" -authors = ["Johan Helsing "] -description = "A camera that allows panning by dragging with the mouse" -keywords = ["gamedev", "bevy"] -categories = ["game-development"] -repository = "https://github.com/johanhelsing/bevy_pancam" - -[dependencies] -bevy = { version = "0.7", features = ["render"], default-features = false } - -[dev-dependencies] -bevy = { version = "0.7", features = ["render"] } -rand = "0.8" diff --git a/block-lang/vendor/bevy_pancam/LICENSE b/block-lang/vendor/bevy_pancam/LICENSE deleted file mode 100644 index 45dd01d..0000000 --- a/block-lang/vendor/bevy_pancam/LICENSE +++ /dev/null @@ -1,6 +0,0 @@ -bevy_pancam is dual-licensed under either - -* MIT License (./LICENSE-MIT or http://opensource.org/licenses/MIT) -* Apache License, Version 2.0 (./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) - -at your option. diff --git a/block-lang/vendor/bevy_pancam/LICENSE-APACHE b/block-lang/vendor/bevy_pancam/LICENSE-APACHE deleted file mode 100644 index d9a10c0..0000000 --- a/block-lang/vendor/bevy_pancam/LICENSE-APACHE +++ /dev/null @@ -1,176 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS diff --git a/block-lang/vendor/bevy_pancam/LICENSE-MIT b/block-lang/vendor/bevy_pancam/LICENSE-MIT deleted file mode 100644 index 9cf1062..0000000 --- a/block-lang/vendor/bevy_pancam/LICENSE-MIT +++ /dev/null @@ -1,19 +0,0 @@ -MIT License - -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. diff --git a/block-lang/vendor/bevy_pancam/examples/simple.rs b/block-lang/vendor/bevy_pancam/examples/simple.rs deleted file mode 100644 index fa58861..0000000 --- a/block-lang/vendor/bevy_pancam/examples/simple.rs +++ /dev/null @@ -1,38 +0,0 @@ -use bevy::prelude::*; -use bevy_pancam::{PanCam, PanCamPlugin}; -use rand::prelude::random; - -fn main() { - App::new() - .add_plugins(DefaultPlugins) - .add_plugin(PanCamPlugin::default()) - .add_startup_system(setup) - .run(); -} - -fn setup(mut commands: Commands) { - commands - .spawn_bundle(OrthographicCameraBundle::new_2d()) - .insert(PanCam::default()); - - let n = 20; - let spacing = 50.; - let offset = spacing * n as f32 / 2.; - let custom_size = Some(Vec2::new(spacing, spacing)); - for x in 0..n { - for y in 0..n { - let x = x as f32 * spacing - offset; - let y = y as f32 * spacing - offset; - let color = Color::hsl(240., random::() * 0.3, random::() * 0.3); - commands.spawn_bundle(SpriteBundle { - sprite: Sprite { - color, - custom_size, - ..default() - }, - transform: Transform::from_xyz(x, y, 0.), - ..default() - }); - } - } -} \ No newline at end of file diff --git a/block-lang/vendor/bevy_pancam/examples/toggle.rs b/block-lang/vendor/bevy_pancam/examples/toggle.rs deleted file mode 100644 index f57a1ef..0000000 --- a/block-lang/vendor/bevy_pancam/examples/toggle.rs +++ /dev/null @@ -1,47 +0,0 @@ -use bevy::prelude::*; -use bevy_pancam::{PanCam, PanCamPlugin}; -use rand::prelude::random; - -fn main() { - App::new() - .add_plugins(DefaultPlugins) - .add_plugin(PanCamPlugin::default()) - .add_startup_system(setup) - .add_system(toggle_key) - .run(); -} - -fn setup(mut commands: Commands) { - commands - .spawn_bundle(OrthographicCameraBundle::new_2d()) - .insert(PanCam::default()); - - let n = 20; - let spacing = 50.; - let offset = spacing * n as f32 / 2.; - let custom_size = Some(Vec2::new(spacing, spacing)); - for x in 0..n { - for y in 0..n { - let x = x as f32 * spacing - offset; - let y = y as f32 * spacing - offset; - let color = Color::hsl(240., random::() * 0.3, random::() * 0.3); - commands.spawn_bundle(SpriteBundle { - sprite: Sprite { - color, - custom_size, - ..default() - }, - transform: Transform::from_xyz(x, y, 0.), - ..default() - }); - } - } -} - -fn toggle_key(mut query: Query<&mut PanCam>, keys: Res>) { - if keys.just_pressed(KeyCode::Space) { - for mut pancam in query.iter_mut() { - pancam.enabled = !pancam.enabled; - } - } -} diff --git a/block-lang/vendor/bevy_pancam/readme.md b/block-lang/vendor/bevy_pancam/readme.md deleted file mode 100644 index c92e593..0000000 --- a/block-lang/vendor/bevy_pancam/readme.md +++ /dev/null @@ -1,54 +0,0 @@ -# bevy_pancam - -[![crates.io](https://img.shields.io/crates/v/bevy_pancam.svg)](https://crates.io/crates/bevy_pancam) -![MIT/Apache 2.0](https://img.shields.io/badge/license-MIT%2FApache-blue.svg) -[![crates.io](https://img.shields.io/crates/d/bevy_pancam.svg)](https://crates.io/crates/bevy_pancam) -[![docs.rs](https://img.shields.io/docsrs/bevy_pancam)](https://docs.rs/bevy_pancam) - -A 2d-camera plugin for bevy that works with orthographic cameras. - -The motivation is that this could be used for something like a map editor for a 2D game. - -## Controls - -Behaves similarly to common online map applications: - -- Click and drag to move the camera -- Scroll to zoom - -## Usage - -Add the plugin to your app - -```rust -App::build() - .add_plugins(DefaultPlugins) - .add_plugin(PanCamPlugin::default()); -``` - -```rust -commands.spawn_bundle(OrthographicCameraBundle::new_2d()) - .insert(PanCam::default()); -``` - -See the [`simple`](./examples/simple.rs) example. - -## Bevy Version Support - -The `main` branch targets the latest bevy release. - -I intend to support the `main` branch of Bevy in the `bevy-main` branch. - -|bevy|bevy_pancam| -|---|---| -|0.7|0.3, main| -|0.6|0.2| -|0.5|0.1| - -## License - -MIT or Apache-2.0 - -## Contributions - -PRs welcome! \ No newline at end of file diff --git a/block-lang/vendor/bevy_pancam/src/lib.rs b/block-lang/vendor/bevy_pancam/src/lib.rs deleted file mode 100644 index f00969e..0000000 --- a/block-lang/vendor/bevy_pancam/src/lib.rs +++ /dev/null @@ -1,101 +0,0 @@ -use bevy::{ - input::mouse::{MouseScrollUnit, MouseWheel}, - prelude::*, - render::camera::OrthographicProjection, -}; - -#[derive(Default)] -pub struct PanCamPlugin; - -impl Plugin for PanCamPlugin { - fn build(&self, app: &mut App) { - app.add_system(camera_movement).add_system(camera_zoom); - } -} - -// Zoom doesn't work on bevy 0.5 due to: https://github.com/bevyengine/bevy/pull/2015 -fn camera_zoom( - mut query: Query<(&PanCam, &mut OrthographicProjection, &mut Transform)>, - mut scroll_events: EventReader, - windows: Res, -) { - let pixels_per_line = 100.; // Maybe make configurable? - let scroll = scroll_events - .iter() - .map(|ev| match ev.unit { - MouseScrollUnit::Pixel => ev.y, - MouseScrollUnit::Line => ev.y * pixels_per_line, - }) - .sum::(); - - if scroll == 0. { - return; - } - - let window = windows.get_primary().unwrap(); - let window_size = Vec2::new(window.width(), window.height()); - let mouse_normalized_screen_pos = (window.cursor_position().unwrap() / window_size) * 2. - Vec2::ONE; - - for (cam, mut proj, mut pos) in query.iter_mut() { - if cam.enabled { - let old_scale = proj.scale; - proj.scale = (proj.scale * (1. + -scroll * 0.001)).max(0.00001); - - if cam.track_mouse { - let proj_size = Vec2::new(proj.right, proj.top); - let mouse_world_pos = pos.translation.truncate() + mouse_normalized_screen_pos * proj_size * old_scale; - pos.translation = (mouse_world_pos - mouse_normalized_screen_pos * proj_size * proj.scale).extend(pos.translation.z); - } - } - } -} - -fn camera_movement( - windows: Res, - mouse_buttons: Res>, - mut query: Query<(&PanCam, &mut Transform, &OrthographicProjection)>, - mut last_pos: Local>, -) { - let window = windows.get_primary().unwrap(); - - // Use position instead of MouseMotion, otherwise we don't get acceleration movement - let current_pos = match window.cursor_position() { - Some(current_pos) => current_pos, - None => return, - }; - let delta = current_pos - last_pos.unwrap_or(current_pos); - - for (cam, mut transform, projection) in query.iter_mut() { - if cam.enabled - && cam - .grab_buttons - .iter() - .any(|btn| mouse_buttons.pressed(*btn)) - { - let scaling = Vec2::new( - window.width() / (projection.right - projection.left), - window.height() / (projection.top - projection.bottom), - ) * projection.scale; - - transform.translation -= (delta * scaling).extend(0.); - } - } - *last_pos = Some(current_pos); -} - -#[derive(Component)] -pub struct PanCam { - pub grab_buttons: Vec, - pub enabled: bool, - pub track_mouse: bool, -} - -impl Default for PanCam { - fn default() -> Self { - Self { - grab_buttons: vec![MouseButton::Left, MouseButton::Right, MouseButton::Middle], - enabled: true, - track_mouse: false, - } - } -} From e4258cc29075b63671f7dd54487bd6ebfa7563d4 Mon Sep 17 00:00:00 2001 From: zyansheep Date: Mon, 25 Jul 2022 15:59:06 -0400 Subject: [PATCH 2/2] update everything --- block-lang/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block-lang/README.md b/block-lang/README.md index dec2d1b..04189ed 100644 --- a/block-lang/README.md +++ b/block-lang/README.md @@ -1,6 +1,8 @@ # Block Lang *Functional Blocks* +See the website: https://zyansheep.github.io/tmp-lang/ + ## General idea Lambda calculus, but a visual drag-n-drop application, a bit like MIT Scratch @@ -13,4 +15,4 @@ The beautiful part, is animating the reductions (Not finished yet) Gui: `cargo run --release` -Cli: `cargo run --package cli --release` \ No newline at end of file +Cli: `cargo run --package cli --release`