diff --git a/Cargo.lock b/Cargo.lock index dad4778..f0f6bd5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2106,6 +2106,7 @@ dependencies = [ "axum", "bytes", "futures", + "rusty-ivyml", "rusty-macros", "serde", "serde_json", @@ -2142,6 +2143,15 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "rusty-ivyml" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "rusty-macros" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index efd17f9..dd8d5b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["rusty", "rusty-macros", "rusty-server", "rusty-docs", "rusty-desktop"] +members = ["rusty", "rusty-macros", "rusty-ivyml", "rusty-server", "rusty-docs", "rusty-desktop"] resolver = "2" [workspace.package] diff --git a/README.md b/README.md index 425e06b..69a4234 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ Rusty-Framework follows the same architecture as Ivy-Framework: |-------|-------------| | `rusty` | Core framework — views, hooks, widgets, server, shared types | | `rusty-macros` | Proc macros for `#[derive(Widget)]`, `#[prop]`, `#[event]` | +| `rusty-ivyml` | Proc macros for `ivyml!` / `ivyml_file!` declarative markup | | `rusty-server` | Standalone server binary | ## Examples diff --git a/rusty-docs/docs/02_concepts/07_markup.md b/rusty-docs/docs/02_concepts/07_markup.md new file mode 100644 index 0000000..7a78ad8 --- /dev/null +++ b/rusty-docs/docs/02_concepts/07_markup.md @@ -0,0 +1,168 @@ +## Markup + +`ivyml!` compiles declarative markup into the same builder chains you would write +by hand. There is no runtime, no interpreter and no wire-format change: the macro +expands to `Layout::vertical().gap(16.0).child(..)`, so a malformed tag is a +`rustc` error with a span rather than a panic in production. + +```rust +use rusty::ivyml; + +impl View for HelloApp { + fn build(&self, _ctx: &mut BuildContext) -> Element { + ivyml! { + + + + + } + } +} +``` + +`ivyml` is exported from the crate root, not from the prelude — a glob-imported +`ivyml!` reads as a locally defined macro. + +### Grammar + +- **One root element per macro.** Wrap siblings in a container. +- **Attributes** are `name=literal` or `name={rust_expr}`. +- **Children** are nested elements or `{expr}` splices. +- Both `` and `` parse; a mismatched closing tag is an error. + +### Elements + +Each tag maps to a constructor, because Rusty's constructors are not uniform and +cannot be derived from the tag name: + +| Element | Constructor | Children attach via | +|---------|-------------|---------------------| +| `` | `Layout::vertical()` | `.child()` | +| `` | `Layout::horizontal()` | `.child()` | +| `` | `Layout::grid(3)` | `.child()` | +| `` | `TextBlock::new("x")` | — (error if given children) | +| `