diff --git a/.github/workflows/examples-build.yml b/.github/workflows/examples-build.yml index 3b7958e..30dd2d9 100644 --- a/.github/workflows/examples-build.yml +++ b/.github/workflows/examples-build.yml @@ -47,3 +47,13 @@ jobs: with: name: ${{ matrix.example }}-${{ matrix.target }} path: target/wasm32-unknown-unknown/debug/examples/*.wasm + + sandbox: #new sandbox job + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + + - name: Build efx-sandbox + run: cargo build -p efx-sandbox diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..212feca --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,106 @@ +# Contributing to EFx + +Thank you for your interest in contributing! +Any help — from filing a bug report to implementing new tags — makes EFx better. + +--- + +## Principles + +* **Safety & compatibility.** Avoid breaking public APIs unless agreed upon in advance. +* **Code style.** Follow `cargo fmt` and ensure `clippy` passes without warnings. +* **Tests.** Any logic change should come with tests (`cargo test`, doctests, compile-fail tests). +* **Docs.** Public APIs, new tags, and attributes must be documented. +* **Performance.** Avoid regressions; add profiling notes if relevant. + +--- + +## Filing Issues + +Before opening a new issue: + +1. **Search existing issues** to avoid duplicates. +2. Prepare a **minimal reproducible example** (short `efx! { ... }` snippet, log, or screenshot). + +**Template for issues:** + +* **Type:** bug / feature / docs / question +* **Expected behavior:** … +* **Actual behavior:** … +* **Reproduction:** code or steps +* **Versions:** `rustc --version`, EFx crate versions +* **Platform:** OS/architecture +* **Additional info:** backtrace, perf data, etc. + +--- + +## Submitting Pull Requests + +1. **Fork** and create a branch: + + * `feat/` — new functionality + * `fix/` — bugfix + * `docs/` — docs only + * `chore/` — maintenance +2. Make your changes and ensure **all tests pass**. +3. Update **docs** and **CHANGELOG.md** if behavior is user-visible. +4. Run local checks (see below). +5. Open a PR with: + + * **Title:** short and clear + * **Description:** what/why, how tested, API impact + * Link to relevant **issue or RFC** + +Small follow-up commits for review fixes are welcome. + +--- + +## Pre-PR Checklist + +```bash +# formatting +cargo fmt --all -- --check + +# linting +cargo clippy --all-targets --all-features -D warnings + +# tests (unit, doctests, compile-fail) +cargo test --workspace + +# docs build +cargo doc --workspace --no-deps +``` + +You can also check examples manually: + +```bash +cargo run -p efx-sandbox +cargo run -p efx --example eframe_demo +``` + +--- + +## Commit Messages + +Use [Conventional Commits](https://www.conventionalcommits.org/): + +``` +feat(button): add rounding attribute +fix(core): correct parsing of numeric attribute +docs: update intro example +``` + +--- + +## Versioning + +We follow **SemVer**. +Breaking changes require discussion in an issue/RFC. +All user-facing changes should be added to `CHANGELOG.md` under **Unreleased**. + +--- + +## License + +By submitting a contribution, you agree that your work is licensed under the same terms as EFx +([MIT OR Apache-2.0](efx/LICENSE)). \ No newline at end of file diff --git a/Makefile b/Makefile index 6a96e19..f3826bf 100644 --- a/Makefile +++ b/Makefile @@ -42,5 +42,8 @@ dump: ## Make dump of project ! -path "./target/*" \ -exec sh -c 'echo ">>> START {}"; cat "{}"; echo ">>> END {}"; echo ""' \; > efx_code.dump.txt +sandbox: ## Run sandbox on local machine + @cargo run -p efx-sandbox + help: ## Outputs this help screen @grep -E '(^[a-zA-Z0-9\./_-]+:.*?##.*$$)|(^##)' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}{printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}' | sed -e 's/\[32m##/[33m/' diff --git a/README.md b/README.md index 7be2b0c..b1750ec 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ ![EFX — Rust templating for egui/eframe](efx/docs/efx_cover.png) # EFx -[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com) -[![Crates.io](https://img.shields.io/crates/v/efx.svg)](https://crates.io/crates/efx) +[![Crates.io](https://img.shields.io/crates/v/efx.svg?color=green)](https://crates.io/crates/efx) ![Crates.io Version](https://img.shields.io/crates/v/efx-core?label=efx-core) -[![MSRV](https://img.shields.io/badge/rustc-1.85%2B-blue.svg)](#) +![Crates.io Version](https://img.shields.io/crates/v/efx-attrnames?label=efx-attrnames&color=red) +[![MSRV](https://img.shields.io/badge/rustc-1.75%2B-blue.svg?logo=rust)](#) [![Docs.rs](https://docs.rs/efx/badge.svg)](https://docs.rs/efx) [![License](https://img.shields.io/crates/l/efx)](https://github.com/ZhukMax/efx/blob/main/LICENSE) ![Crates.io Total Downloads](https://img.shields.io/crates/d/efx) @@ -12,7 +12,7 @@ **EFx** — Rust 🦀 XML Template Engine for [egui](https://github.com/emilk/egui)-based frameworks: [eframe](https://github.com/emilk/egui/tree/master/crates/eframe), [bevy_egui](https://github.com/vladbat00/bevy_egui), [egui-winit](https://crates.io/crates/egui-winit), [egui-miniquad](https://github.com/not-fl3/egui-miniquad). `efx!` is a proc-macro for writing tiny XML-like UI snippets in `eframe/egui`. It converts short tags into `egui` calls. -**Simplicity and Convenience — XML, 🚀 Speed ​​and 🔐 Security — Rust** +**Simplicity and Convenience — XML, 🚀 Speed and 🔐 Security — Rust** **Easy as HTML, Fast as C** @@ -25,7 +25,7 @@ You can embed arbitrary Rust expressions inside braces (`{...}`). Requires `egui` (the project currently uses `egui 0.32`). Add to `Cargo.toml`: ```toml [dependencies] -efx = "0.5" +efx = "0.6" egui = "0.32" # or egui-based framework ``` @@ -39,9 +39,9 @@ use efx::efx; // the macro ### Documentation You can see on web page https://docs.rs/efx/latest/efx/ or in files: -- [Introduction](efx/docs/intro.md) -- [Tags](efx/docs/tags.md) -- [Guide](efx/docs/guide.md) +- [Introduction](efx/docs/intro.md) ([🇫🇷 fr](efx/docs/fr/intro.md)) +- [Tags](efx/docs/tags.md) ([🇫🇷 fr](efx/docs/fr/tags.md)) +- [Guide](efx/docs/guide.md) ([🇫🇷 fr](efx/docs/fr/guide.md)) --- @@ -92,8 +92,6 @@ At compile time the macro parses your snippet; at runtime it shows readable diag **TL;DR.** EFx is a minimalist XML DSL on top of `egui` that compiles to plain `ui.*` calls. The next three releases focus on expressiveness and first-class examples across popular `egui` runtimes: -* **0.5 — Attributes & core tags:** type-checked attributes, `Heading`, `Hyperlink`, `Image`, `TextField`, `Grid`, plus `Window/CentralPanel/SidePanel`. Diagnostics & examples. -* **0.6 — Components & events:** reusable components/slots, event sugar (`onClick`, etc.), classes/presets, Bevy examples. * **0.7 — Themes & layouts:** lightweight style sheets, extended containers (`Tabs/Table` behind `extras`), perf & polish. This plan is incremental and **non-breaking**; new features are opt-in. Priorities may change based on community feedback. @@ -127,7 +125,7 @@ EFx renders into any runtime that provides `&mut egui::Ui`. We officially build ```toml # Cargo.toml [dependencies] -efx = "0.5" +efx = "0.6" eframe = "0.32" ``` @@ -145,7 +143,7 @@ egui::CentralPanel::default().show(ctx, |ui| { ```toml # Cargo.toml [dependencies] -efx = "0.5" +efx = "0.6" bevy = "0.16" bevy_egui = "0.36" # re-exports `egui` ``` @@ -166,7 +164,7 @@ bevy_egui::egui::Window::new("EFx").show(egui_ctx.ctx_mut(), |ui| { ```toml # Cargo.toml [dependencies] -efx = "0.5" +efx = "0.6" egui = "0.32" egui-winit = "0.32" egui-wgpu = "0.32" @@ -180,11 +178,63 @@ Use the example in `examples/winit_wgpu_min.rs` as a starting point. ### Contributing -* Start with the roadmap RFC: [EFX-0001](efx/docs/rfcs/EFX-0001-roadmap-0.5-0.7.md). -* You can write me with your ideas on [mail@zhukmax.com](mailto:mail@zhukmax.com). -* Open issues are grouped by milestones **0.5 / 0.6 / 0.7**. -* PRs that change behavior should reference the relevant RFC section. -* Looking for help with: Bevy example(s), raw `winit+wgpu` example, attribute codegen & compile-fail tests, `TextField` docs. +[![PRs Welcome](https://img.shields.io/badge/PullRequest-welcome-brightgreen.svg?style=flat-square)]() + +**Thanks for considering a contribution!** Please follow this lightweight workflow: + +#### 1) Pick or propose an issue + +* **Claim an issue:** comment “I’d like to take this” (optionally add a brief plan/ETA). + The maintainer will assign it to you. +* **Propose a new issue:** open a ticket with a minimal reproducible example (for bugs) or a short rationale (for features). + Start with the roadmap RFC: [EFX-0001](efx/docs/rfcs/EFX-0001-roadmap-0.5-0.7.md). + +> Tip: issues labeled `good first issue` are designed for first-time contributors. + +#### 2) Fork & branch + +* Fork the repository and create a **feature branch from `main`**: + + ```bash + git checkout main + git pull + git checkout -b feat/short-topic + ``` +* Keep your branch focused on **one issue**. + +#### 3) Implement with tests & docs + +* Make the change and add tests/docs where it makes sense. +* Local checks (examples build-only; no GUI run is required): + + ```bash + cargo fmt --all + cargo clippy --all-targets -- -D warnings + cargo build --workspace --locked + cargo build -p efx --example eframe_demo --locked + rustup target add wasm32-unknown-unknown + cargo build -p efx --example eframe_demo --target wasm32-unknown-unknown --locked + ``` + +#### 4) Open a Pull Request + +* Target the **next release branch** (e.g., `v0.6`, `v0.7`). + If the issue has a **milestone**, use the branch named after that milestone. +* Link the issue (e.g., “Closes #123”) and fill the checklist below. + +**PR checklist** + +* [ ] References the related issue / RFC section when behavior changes. +* [ ] CI is green (workspace build, examples, wasm32 build-only). +* [ ] Tests/docs updated where applicable. +* [ ] No unrelated changes. + +#### 5) Reviews & merge + +* Address review comments; small, focused PRs get merged faster. +* If you go silent for **7 days**, the issue may be unassigned to keep momentum (you can re-claim it anytime). + +**Questions?** Reach out at [mail@zhukmax.com](mailto:mail@zhukmax.com). --- diff --git a/efx-core/src/doc_prelude.rs b/efx-core/src/doc_prelude.rs index 520dff9..e890cb4 100644 --- a/efx-core/src/doc_prelude.rs +++ b/efx-core/src/doc_prelude.rs @@ -44,6 +44,8 @@ impl Ui { #[inline] pub fn label(&mut self, _text: T) {} #[inline] + pub fn heading(&mut self, _text: T) {} + #[inline] pub fn button(&mut self, _text: T) -> Resp { Resp } diff --git a/efx-sandbox/Cargo.toml b/efx-sandbox/Cargo.toml index c457f60..a373b0e 100644 --- a/efx-sandbox/Cargo.toml +++ b/efx-sandbox/Cargo.toml @@ -7,4 +7,5 @@ publish = false [dependencies] eframe = "0.32" +egui = "0.32" efx = { path = "../efx" } diff --git a/efx-sandbox/src/main.rs b/efx-sandbox/src/main.rs index deed9f3..35edd59 100644 --- a/efx-sandbox/src/main.rs +++ b/efx-sandbox/src/main.rs @@ -1,5 +1,5 @@ use eframe::{egui, NativeOptions}; -use efx::efx; +use efx::efx_ctx; fn main() -> eframe::Result<()> { let native = NativeOptions::default(); @@ -10,50 +10,59 @@ fn main() -> eframe::Result<()> { ) } -#[derive(Default)] struct App { counter: i32, input: String, + show_settings: bool, +} + +impl Default for App { + fn default() -> Self { + Self { + counter: 0, + input: String::new(), + show_settings: true, + } + } } impl eframe::App for App { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - egui::CentralPanel::default().show(ctx, |ui| { - // Header - let _ = efx!( - ui, - r#" - - + efx_ctx!( + ctx, + r##" + + + + - - "# - ); - - // Increment/decrement buttons - catch Response - ui.horizontal(|ui| { - let inc = efx!(ui, r#""#); - if inc.clicked() { - self.counter += 1; - } - - let dec = efx!(ui, r#""#); - if dec.clicked() { - self.counter -= 1; - } - }); - - // Dynamic text via {expr} - let _ = efx!(ui, r#""#); - - // Input field (binding directly to the state field) - let _ = efx!(ui, r#""#); + + + + + + + + + + + + + + + + + + + + + + - // Scrolling + different tags - let _ = efx!( - ui, - r##" + Main title + Section + Small note @@ -68,8 +77,47 @@ impl eframe::App for App { - "## - ); - }); + + + + + + + + + + + + + + + + + + + + + + + + + + "## + ); } } diff --git a/efx-syntax/LICENSE b/efx-syntax/LICENSE new file mode 100644 index 0000000..192f2c3 --- /dev/null +++ b/efx-syntax/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Max Zhuk + +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/efx-syntax/README.md b/efx-syntax/README.md new file mode 100644 index 0000000..9244b01 --- /dev/null +++ b/efx-syntax/README.md @@ -0,0 +1,34 @@ + +# EFx Syntax (TextMate / VS Code / JetBrains) + +Syntax highlighting for EFx templates: + +- Files: `*.efx` +- Basic constructions: tags ``, `