Merge branch 'master' into maybe-sync-signal

This commit is contained in:
ealmloff authored and GitHub committed 2024-01-09 15:31:31 -06:00
commit e1e29d1404
41 files changed
+15956 -389

No files matched your search

+132 -50
View File
@@ -27,93 +27,177 @@ on:
- lib.rs - lib.rs
- Cargo.toml - Cargo.toml
# workflow_dispatch:
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: "0"
jobs: jobs:
check: check:
if: github.event.pull_request.draft == false if: github.event.pull_request.draft == false
name: Check name: Check
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
steps: steps:
- uses: dtolnay/rust-toolchain@stable
- uses: mozilla-actions/sccache-action@v0.0.3
- uses: ilammy/setup-nasm@v1
- run: sudo apt-get update
- run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: sudo apt-get update
- run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
cache-all-crates: "true"
save-if: ${{ github.ref == 'refs/heads/master' }}
- uses: ilammy/setup-nasm@v1
- run: cargo check --all --examples --tests - run: cargo check --all --examples --tests
test: test:
if: github.event.pull_request.draft == false if: github.event.pull_request.draft == false
name: Test Suite name: Test Suite
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
steps: steps:
- uses: dtolnay/rust-toolchain@stable - uses: actions/checkout@v4
- uses: mozilla-actions/sccache-action@v0.0.3
- uses: ilammy/setup-nasm@v1
- run: sudo apt-get update - run: sudo apt-get update
- run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
cache-all-crates: "true"
save-if: ${{ github.ref == 'refs/heads/master' }}
- uses: ilammy/setup-nasm@v1
- uses: davidB/rust-cargo-make@v1 - uses: davidB/rust-cargo-make@v1
- uses: browser-actions/setup-firefox@latest - uses: browser-actions/setup-firefox@latest
- uses: jetli/wasm-pack-action@v0.4.0 - uses: jetli/wasm-pack-action@v0.4.0
- uses: actions/checkout@v4 - run: sudo rm -rf /usr/share/dotnet
- run: sudo rm -rf "$AGENT_TOOLSDIRECTORY"
- run: |
df -h
sudo rm -rf ${GITHUB_WORKSPACE}/.git
df -h
- run: cargo make tests - run: cargo make tests
fmt: fmt:
if: github.event.pull_request.draft == false if: github.event.pull_request.draft == false
name: Rustfmt name: Rustfmt
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
steps: steps:
- uses: dtolnay/rust-toolchain@stable
- uses: mozilla-actions/sccache-action@v0.0.3
- uses: ilammy/setup-nasm@v1
- run: rustup component add rustfmt
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: ilammy/setup-nasm@v1
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- uses: Swatinem/rust-cache@v2
with:
cache-all-crates: "true"
save-if: ${{ github.ref == 'refs/heads/master' }}
- run: cargo fmt --all -- --check - run: cargo fmt --all -- --check
clippy: clippy:
if: github.event.pull_request.draft == false if: github.event.pull_request.draft == false
name: Clippy name: Clippy
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
steps: steps:
- uses: dtolnay/rust-toolchain@stable - uses: actions/checkout@v4
- uses: mozilla-actions/sccache-action@v0.0.3
- uses: ilammy/setup-nasm@v1
- run: sudo apt-get update - run: sudo apt-get update
- run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev - run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev
- run: rustup component add clippy - uses: ilammy/setup-nasm@v1
- uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
with:
cache-all-crates: "true"
save-if: ${{ github.ref == 'refs/heads/master' }}
- run: cargo clippy --workspace --examples --tests -- -D warnings - run: cargo clippy --workspace --examples --tests -- -D warnings
miri:
if: github.event.pull_request.draft == false
name: Miri
runs-on: ubuntu-latest
env:
CARGO_UNSTABLE_SPARSE_REGISTRY: 'true'
RUSTFLAGS: -Dwarnings
RUST_BACKTRACE: 1
MIRIFLAGS: -Zmiri-tag-gc=1
# Change to specific Rust release to pin
rust_stable: stable
rust_nightly: nightly-2023-11-16
rust_clippy: 1.70.0
steps:
- uses: actions/checkout@v4
- uses: ilammy/setup-nasm@v1
- name: Install Rust ${{ env.rust_nightly }}
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.rust_nightly }}
components: miri
- uses: Swatinem/rust-cache@v2
with:
cache-all-crates: "true"
save-if: ${{ github.ref == 'refs/heads/master' }}
- name: miri
# Many of tests in tokio/tests and doctests use #[tokio::test] or
# #[tokio::main] that calls epoll_create1 that Miri does not support.
# run: cargo miri test --features full --lib --no-fail-fast
run: |
cargo miri test --package dioxus-core -- --exact --nocapture
cargo miri test --package dioxus-native-core --test miri_native -- --exact --nocapture
env:
MIRIFLAGS: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-retag-fields
PROPTEST_CASES: 10
playwright:
if: github.event.pull_request.draft == false
name: Playwright Tests
runs-on: ubuntu-latest
steps:
# Do our best to cache the toolchain and node install steps
- uses: actions/checkout@v4
- uses: ilammy/setup-nasm@v1
- uses: actions/setup-node@v4
with:
node-version: 16
- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
targets: x86_64-unknown-linux-gnu,wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
with:
cache-all-crates: "true"
save-if: ${{ github.ref == 'refs/heads/master' }}
- name: Install dependencies
run: npm ci
working-directory: ./playwright-tests
- name: Install Playwright
run: npm install -D @playwright/test
working-directory: ./playwright-tests
- name: Install Playwright Browsers
run: npx playwright install --with-deps
working-directory: ./playwright-tests
- name: Run Playwright tests
run: npx playwright test
working-directory: ./playwright-tests
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
matrix_test: matrix_test:
runs-on: ${{ matrix.platform.os }} runs-on: ${{ matrix.platform.os }}
if: github.event.pull_request.draft == false
env: env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
RUST_CARGO_COMMAND: ${{ matrix.platform.cross == true && 'cross' || 'cargo' }} RUST_CARGO_COMMAND: ${{ matrix.platform.cross == true && 'cross' || 'cargo' }}
strategy: strategy:
matrix: matrix:
@@ -159,20 +243,18 @@ jobs:
with: with:
toolchain: ${{ matrix.platform.toolchain }} toolchain: ${{ matrix.platform.toolchain }}
targets: ${{ matrix.platform.target }} targets: ${{ matrix.platform.target }}
components: rustfmt
- name: Install cross - name: Install cross
if: ${{ matrix.platform.cross == true }} if: ${{ matrix.platform.cross == true }}
uses: taiki-e/install-action@cross uses: taiki-e/install-action@cross
- uses: mozilla-actions/sccache-action@v0.0.3 - uses: Swatinem/rust-cache@v2
with: with:
workspaces: core -> ../target key: "${{ matrix.platform.target }}"
save-if: ${{ matrix.features.key == 'all' }} cache-all-crates: "true"
save-if: ${{ github.ref == 'refs/heads/master' }}
- name: Install rustfmt
run: rustup component add rustfmt
- uses: actions/checkout@v4
- name: test - name: test
run: | run: |
-133
View File
@@ -1,133 +0,0 @@
name: Miri Tests
on:
push:
# Run in PRs and for bors, but not on master.
branches:
- 'auto'
- 'try'
paths:
- packages/**
- examples/**
- src/**
- .github/**
- lib.rs
- Cargo.toml
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
branches:
- 'master'
schedule:
- cron: '6 6 * * *' # At 6:06 UTC every day.
env:
CARGO_UNSTABLE_SPARSE_REGISTRY: 'true'
RUSTFLAGS: -Dwarnings
RUST_BACKTRACE: 1
# Change to specific Rust release to pin
rust_stable: stable
rust_nightly: nightly-2023-11-16
rust_clippy: 1.70.0
# When updating this, also update:
# - README.md
# - tokio/README.md
# - CONTRIBUTING.md
# - tokio/Cargo.toml
# - tokio-util/Cargo.toml
# - tokio-test/Cargo.toml
# - tokio-stream/Cargo.toml
# rust_min: 1.49.0
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ${{ matrix.os }}
env:
RUST_BACKTRACE: 1
HOST_TARGET: ${{ matrix.host_target }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
host_target: x86_64-unknown-linux-gnu
# - os: macos-latest
# host_target: x86_64-apple-darwin
# - os: windows-latest
# host_target: i686-pc-windows-msvc
# - os: windows-latest
# host_target: i686-pc-windows-msvc
# - os: windows-latest
# host_target: i686-pc-windows-msvc
# - os: windows-latest
# host_target: i686-pc-windows-msvc
steps:
- name: Set the tag GC interval to 1 on linux
if: runner.os == 'Linux'
run: echo "MIRIFLAGS=-Zmiri-tag-gc=1" >> $GITHUB_ENV
- uses: actions/checkout@v4
- uses: ilammy/setup-nasm@v1
- name: Install Rust ${{ env.rust_nightly }}
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.rust_nightly }}
components: miri
- uses: Swatinem/rust-cache@v2
- name: miri
# Many of tests in tokio/tests and doctests use #[tokio::test] or
# #[tokio::main] that calls epoll_create1 that Miri does not support.
# run: cargo miri test --features full --lib --no-fail-fast
run: |
cargo miri test --package dioxus-core -- --exact --nocapture
cargo miri test --package dioxus-native-core --test miri_native -- --exact --nocapture
# working-directory: tokio
env:
MIRIFLAGS: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-retag-fields
PROPTEST_CASES: 10
# Cache the global cargo directory, but NOT the local `target` directory which
# we cannot reuse anyway when the nightly changes (and it grows quite large
# over time).
# - name: Add cache for cargo
# id: cache
# uses: actions/cache@v3
# with:
# path: |
# # Taken from <https://doc.rust-lang.org/nightly/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci>.
# ~/.cargo/bin
# ~/.cargo/registry/index
# ~/.cargo/registry/cache
# ~/.cargo/git/db
# # contains package information of crates installed via `cargo install`.
# ~/.cargo/.crates.toml
# ~/.cargo/.crates2.json
# key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
# restore-keys: ${{ runner.os }}-cargo
# - name: Install rustup-toolchain-install-master
# if: ${{ steps.cache.outputs.cache-hit != 'true' }}
# shell: bash
# run: |
# cargo install -f rustup-toolchain-install-master
# - name: Install "master" toolchain
# shell: bash
# run: |
# if [[ ${{ github.event_name }} == 'schedule' ]]; then
# echo "Building against latest rustc git version"
# git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1 > rust-version
# fi
# toolchain --host ${{ matrix.host_target }}
# - name: Show Rust version
# run: |
# rustup show
# rustc -Vv
# cargo -V
# - name: Test
# run: |
# MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-ignore-leaks" cargo +nightly miri test --package dioxus-core --test miri_stress -- --exact --nocapture
# MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-ignore-leaks" cargo +nightly miri test --package dioxus-native-core --test miri_native -- --exact --nocapture
-52
View File
@@ -1,52 +0,0 @@
name: Playwright Tests
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
defaults:
run:
working-directory: ./playwright-tests
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
test:
if: github.event.pull_request.draft == false
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
# Do our best to cache the toolchain and node install steps
- uses: actions/checkout@v4
- uses: ilammy/setup-nasm@v1
- uses: actions/setup-node@v4
with:
node-version: 16
- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
targets: x86_64-unknown-linux-gnu,wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
- name: Install dependencies
run: npm ci
- name: Install Playwright
run: npm install -D @playwright/test
- name: Install Playwright Browsers
run: npx playwright install --with-deps
# Cache the CLI by using cargo run internally
# - name: Install Dioxus CLI
# uses: actions-rs/cargo@v1
# with:
# command: install
# args: --path packages/cli
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
+37
View File
@@ -0,0 +1,37 @@
name: Clear cache
on:
workflow_dispatch:
permissions:
actions: write
jobs:
clear-cache:
runs-on: ubuntu-latest
steps:
- name: Clear cache
uses: actions/github-script@v6
with:
github-token: ${{ secrets.cache_controller }}
script: |
console.log("About to clear")
while (true) {
const caches = await github.rest.actions.getActionsCacheList({
owner: context.repo.owner,
repo: context.repo.repo
})
if (caches.data.actions_caches.length === 0) {
break
}
for (const cache of caches.data.actions_caches) {
console.log(cache)
github.rest.actions.deleteActionsCacheById({
owner: context.repo.owner,
repo: context.repo.repo,
cache_id: cache.id,
})
}
}
console.log("Clear completed")
+3 -1
View File
@@ -2,10 +2,12 @@
/playwright-tests/web/dist /playwright-tests/web/dist
/playwright-tests/fullstack/dist /playwright-tests/fullstack/dist
/dist /dist
Cargo.lock
.DS_Store .DS_Store
/examples/assets/test_video.mp4 /examples/assets/test_video.mp4
# new recommendation to keep the lockfile in for CI and reproducible builds
# Cargo.lock
.vscode/* .vscode/*
!.vscode/settings.json !.vscode/settings.json
!.vscode/tasks.json !.vscode/tasks.json
Generated
+12339
View File
File diff suppressed because it is too large. Load diff
+8 -3
View File
@@ -98,6 +98,12 @@ thiserror = "1.0.40"
prettyplease = { package = "prettier-please", version = "0.2", features = [ prettyplease = { package = "prettier-please", version = "0.2", features = [
"verbatim", "verbatim",
] } ] }
manganis-cli-support = { git = "https://github.com/DioxusLabs/collect-assets", rev = "94ea6f7", features = [
"webp",
"html",
] }
manganis = { git = "https://github.com/DioxusLabs/collect-assets", rev = "94ea6f7" }
# This is a "virtual package" # This is a "virtual package"
# It is not meant to be published, but is used so "cargo run --example XYZ" works properly # It is not meant to be published, but is used so "cargo run --example XYZ" works properly
@@ -136,8 +142,7 @@ reqwest = { version = "0.11.9", features = ["json"] }
env_logger = "0.10.0" env_logger = "0.10.0"
simple_logger = "4.0.0" simple_logger = "4.0.0"
thiserror = { workspace = true } thiserror = { workspace = true }
manganis = { workspace = true }
[dependencies]
tracing-subscriber = "0.3.17" tracing-subscriber = "0.3.17"
http-range = "0.1.5" http-range = "0.1.5"
+1 -1
View File
@@ -10,7 +10,7 @@ fn app(cx: Scope) -> Element {
p { p {
"This should show an image:" "This should show an image:"
} }
img { src: mg!(image("examples/assets/logo.png").format(ImageType::Avif)).to_string() } img { src: manganis::mg!(image("examples/assets/logo.png").format(ImageType::Avif)).to_string() }
} }
}) })
} }
+1 -1
View File
@@ -18,7 +18,7 @@ fn main() {
); );
} }
const _STYLE: &str = mg!(file("./examples/assets/fileexplorer.css")); const _STYLE: &str = manganis::mg!(file("./examples/assets/fileexplorer.css"));
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let files = use_ref(cx, Files::new); let files = use_ref(cx, Files::new);
+3240
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -13,6 +13,7 @@ publish = false
[dependencies] [dependencies]
dioxus = { path = "../../packages/dioxus" } dioxus = { path = "../../packages/dioxus" }
manganis = { workspace = true }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
dioxus-desktop = { path = "../../packages/desktop" } dioxus-desktop = { path = "../../packages/desktop" }
+1 -1
View File
@@ -2,7 +2,7 @@
use dioxus::prelude::*; use dioxus::prelude::*;
const _STYLE: &str = mg!(file("./public/tailwind.css")); const _STYLE: &str = manganis::mg!(file("./public/tailwind.css"));
fn main() { fn main() {
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
+1 -1
View File
@@ -7,7 +7,7 @@ fn main() {
dioxus_desktop::launch(app); dioxus_desktop::launch(app);
} }
const _STYLE: &str = mg!(file("./examples/assets/todomvc.css")); const _STYLE: &str = manganis::mg!(file("./examples/assets/todomvc.css"));
#[derive(PartialEq, Eq, Clone, Copy)] #[derive(PartialEq, Eq, Clone, Copy)]
pub enum FilterState { pub enum FilterState {
+3 -3
View File
@@ -67,7 +67,7 @@ impl Writer<'_> {
} }
// multiline handlers bump everything down // multiline handlers bump everything down
if attr_len > 1000 { if attr_len > 1000 || self.out.indent.split_line_attributes() {
opt_level = ShortOptimization::NoOpt; opt_level = ShortOptimization::NoOpt;
} }
@@ -158,7 +158,7 @@ impl Writer<'_> {
while let Some(field) = field_iter.next() { while let Some(field) = field_iter.next() {
if !sameline { if !sameline {
self.out.indented_tabbed_line()?; self.out.indented_tabbed_line().unwrap();
} }
let name = &field.name; let name = &field.name;
@@ -206,7 +206,7 @@ impl Writer<'_> {
if let Some(exp) = manual_props { if let Some(exp) = manual_props {
if !sameline { if !sameline {
self.out.indented_tabbed_line()?; self.out.indented_tabbed_line().unwrap();
} }
self.write_manual_props(exp)?; self.write_manual_props(exp)?;
} }
+5 -2
View File
@@ -103,7 +103,7 @@ impl Writer<'_> {
} }
// multiline handlers bump everything down // multiline handlers bump everything down
if attr_len > 1000 { if attr_len > 1000 || self.out.indent.split_line_attributes() {
opt_level = ShortOptimization::NoOpt; opt_level = ShortOptimization::NoOpt;
} }
@@ -262,7 +262,6 @@ impl Writer<'_> {
} }
ElementAttrValue::EventTokens(tokens) => { ElementAttrValue::EventTokens(tokens) => {
let out = self.retrieve_formatted_expr(tokens).to_string(); let out = self.retrieve_formatted_expr(tokens).to_string();
let mut lines = out.split('\n').peekable(); let mut lines = out.split('\n').peekable();
let first = lines.next().unwrap(); let first = lines.next().unwrap();
@@ -327,6 +326,10 @@ impl Writer<'_> {
beginning.is_empty() beginning.is_empty()
} }
pub fn is_empty_children(&self, children: &[BodyNode]) -> bool {
children.is_empty()
}
// check if the children are short enough to be on the same line // check if the children are short enough to be on the same line
// We don't have the notion of current line depth - each line tries to be < 80 total // We don't have the notion of current line depth - each line tries to be < 80 total
// returns the total line length if it's short // returns the total line length if it's short
+15 -9
View File
@@ -8,10 +8,11 @@ pub enum IndentType {
pub struct IndentOptions { pub struct IndentOptions {
width: usize, width: usize,
indent_string: String, indent_string: String,
split_line_attributes: bool,
} }
impl IndentOptions { impl IndentOptions {
pub fn new(typ: IndentType, width: usize) -> Self { pub fn new(typ: IndentType, width: usize, split_line_attributes: bool) -> Self {
assert_ne!(width, 0, "Cannot have an indent width of 0"); assert_ne!(width, 0, "Cannot have an indent width of 0");
Self { Self {
width, width,
@@ -19,6 +20,7 @@ impl IndentOptions {
IndentType::Tabs => "\t".into(), IndentType::Tabs => "\t".into(),
IndentType::Spaces => " ".repeat(width), IndentType::Spaces => " ".repeat(width),
}, },
split_line_attributes,
} }
} }
@@ -62,11 +64,15 @@ impl IndentOptions {
} }
indent indent
} }
pub fn split_line_attributes(&self) -> bool {
self.split_line_attributes
}
} }
impl Default for IndentOptions { impl Default for IndentOptions {
fn default() -> Self { fn default() -> Self {
Self::new(IndentType::Spaces, 4) Self::new(IndentType::Spaces, 4, false)
} }
} }
@@ -77,31 +83,31 @@ mod tests {
#[test] #[test]
fn count_indents() { fn count_indents() {
assert_eq!( assert_eq!(
IndentOptions::new(IndentType::Spaces, 4).count_indents("no indentation here!"), IndentOptions::new(IndentType::Spaces, 4, false).count_indents("no indentation here!"),
0 0
); );
assert_eq!( assert_eq!(
IndentOptions::new(IndentType::Spaces, 4).count_indents(" v += 2"), IndentOptions::new(IndentType::Spaces, 4, false).count_indents(" v += 2"),
1 1
); );
assert_eq!( assert_eq!(
IndentOptions::new(IndentType::Spaces, 4).count_indents(" v += 2"), IndentOptions::new(IndentType::Spaces, 4, false).count_indents(" v += 2"),
2 2
); );
assert_eq!( assert_eq!(
IndentOptions::new(IndentType::Spaces, 4).count_indents(" v += 2"), IndentOptions::new(IndentType::Spaces, 4, false).count_indents(" v += 2"),
2 2
); );
assert_eq!( assert_eq!(
IndentOptions::new(IndentType::Spaces, 4).count_indents("\t\tv += 2"), IndentOptions::new(IndentType::Spaces, 4, false).count_indents("\t\tv += 2"),
2 2
); );
assert_eq!( assert_eq!(
IndentOptions::new(IndentType::Spaces, 4).count_indents("\t\t v += 2"), IndentOptions::new(IndentType::Spaces, 4, false).count_indents("\t\t v += 2"),
2 2
); );
assert_eq!( assert_eq!(
IndentOptions::new(IndentType::Spaces, 2).count_indents(" v += 2"), IndentOptions::new(IndentType::Spaces, 2, false).count_indents(" v += 2"),
2 2
); );
} }
+3 -1
View File
@@ -140,7 +140,9 @@ pub fn write_block_out(body: CallBody) -> Option<String> {
} }
fn write_body(buf: &mut Writer, body: &CallBody) { fn write_body(buf: &mut Writer, body: &CallBody) {
if buf.is_short_children(&body.roots).is_some() { let is_short = buf.is_short_children(&body.roots).is_some();
let is_empty = buf.is_empty_children(&body.roots);
if (is_short && !buf.out.indent.split_line_attributes()) || is_empty {
// write all the indents with spaces and commas between // write all the indents with spaces and commas between
for idx in 0..body.roots.len() - 1 { for idx in 0..body.roots.len() - 1 {
let ident = &body.roots[idx]; let ident = &body.roots[idx];
+6 -6
View File
@@ -18,11 +18,11 @@ macro_rules! twoway {
}; };
} }
twoway!("comments-4sp" => comments_4sp (IndentOptions::new(IndentType::Spaces, 4))); twoway!("comments-4sp" => comments_4sp (IndentOptions::new(IndentType::Spaces, 4, false)));
twoway!("comments-tab" => comments_tab (IndentOptions::new(IndentType::Tabs, 4))); twoway!("comments-tab" => comments_tab (IndentOptions::new(IndentType::Tabs, 4, false)));
twoway!("multi-4sp" => multi_4sp (IndentOptions::new(IndentType::Spaces, 4))); twoway!("multi-4sp" => multi_4sp (IndentOptions::new(IndentType::Spaces, 4, false)));
twoway!("multi-tab" => multi_tab (IndentOptions::new(IndentType::Tabs, 4))); twoway!("multi-tab" => multi_tab (IndentOptions::new(IndentType::Tabs, 4, false)));
twoway!("multiexpr-4sp" => multiexpr_4sp (IndentOptions::new(IndentType::Spaces, 4))); twoway!("multiexpr-4sp" => multiexpr_4sp (IndentOptions::new(IndentType::Spaces, 4, false)));
twoway!("multiexpr-tab" => multiexpr_tab (IndentOptions::new(IndentType::Tabs, 4))); twoway!("multiexpr-tab" => multiexpr_tab (IndentOptions::new(IndentType::Tabs, 4, false)));
+1 -1
View File
@@ -76,7 +76,7 @@ toml_edit = "0.19.11"
tauri-bundler = { version = "=1.4.*", features = ["native-tls-vendored"] } tauri-bundler = { version = "=1.4.*", features = ["native-tls-vendored"] }
tauri-utils = "=1.5.*" tauri-utils = "=1.5.*"
manganis-cli-support = { git = "https://github.com/DioxusLabs/collect-assets", features = ["webp", "html"] } manganis-cli-support = { workspace = true, features = ["webp", "html"] }
dioxus-autofmt = { workspace = true } dioxus-autofmt = { workspace = true }
dioxus-check = { workspace = true } dioxus-check = { workspace = true }
+2 -2
View File
@@ -35,13 +35,13 @@ cargo install --path . --debug
## Get started ## Get started
Use `dx create project-name` to initialize a new Dioxus project. Use `dx create` to initialize a new Dioxus project.
It will be cloned from the [dioxus-template](https://github.com/DioxusLabs/dioxus-template) repository. It will be cloned from the [dioxus-template](https://github.com/DioxusLabs/dioxus-template) repository.
Alternatively, you can specify the template path: Alternatively, you can specify the template path:
```shell ```shell
dx create hello --template gh:dioxuslabs/dioxus-template dx create --template gh:dioxuslabs/dioxus-template
``` ```
Run `dx --help` for a list of all the available commands. Run `dx --help` for a list of all the available commands.
+24 -9
View File
@@ -22,23 +22,33 @@ pub struct Autoformat {
/// Input file /// Input file
#[clap(short, long)] #[clap(short, long)]
pub file: Option<String>, pub file: Option<String>,
/// Split attributes in lines or not
#[clap(short, long, default_value = "false")]
pub split_line_attributes: bool,
} }
impl Autoformat { impl Autoformat {
// Todo: autoformat the entire crate // Todo: autoformat the entire crate
pub async fn autoformat(self) -> Result<()> { pub async fn autoformat(self) -> Result<()> {
let Autoformat { check, raw, file } = self; let Autoformat {
check,
raw,
file,
split_line_attributes,
..
} = self;
// Default to formatting the project // Default to formatting the project
if raw.is_none() && file.is_none() { if raw.is_none() && file.is_none() {
if let Err(e) = autoformat_project(check).await { if let Err(e) = autoformat_project(check, split_line_attributes).await {
eprintln!("error formatting project: {}", e); eprintln!("error formatting project: {}", e);
exit(1); exit(1);
} }
} }
if let Some(raw) = raw { if let Some(raw) = raw {
let indent = indentation_for(".")?; let indent = indentation_for(".", self.split_line_attributes)?;
if let Some(inner) = dioxus_autofmt::fmt_block(&raw, 0, indent) { if let Some(inner) = dioxus_autofmt::fmt_block(&raw, 0, indent) {
println!("{}", inner); println!("{}", inner);
} else { } else {
@@ -50,15 +60,15 @@ impl Autoformat {
// Format single file // Format single file
if let Some(file) = file { if let Some(file) = file {
refactor_file(file)?; refactor_file(file, split_line_attributes)?;
} }
Ok(()) Ok(())
} }
} }
fn refactor_file(file: String) -> Result<(), Error> { fn refactor_file(file: String, split_line_attributes: bool) -> Result<(), Error> {
let indent = indentation_for(".")?; let indent = indentation_for(".", split_line_attributes)?;
let file_content = if file == "-" { let file_content = if file == "-" {
let mut contents = String::new(); let mut contents = String::new();
std::io::stdin().read_to_string(&mut contents)?; std::io::stdin().read_to_string(&mut contents)?;
@@ -138,7 +148,7 @@ async fn format_file(
/// Runs using Tokio for multithreading, so it should be really really fast /// Runs using Tokio for multithreading, so it should be really really fast
/// ///
/// Doesn't do mod-descending, so it will still try to format unreachable files. TODO. /// Doesn't do mod-descending, so it will still try to format unreachable files. TODO.
async fn autoformat_project(check: bool) -> Result<()> { async fn autoformat_project(check: bool, split_line_attributes: bool) -> Result<()> {
let crate_config = dioxus_cli_config::CrateConfig::new(None)?; let crate_config = dioxus_cli_config::CrateConfig::new(None)?;
let files_to_format = get_project_files(&crate_config); let files_to_format = get_project_files(&crate_config);
@@ -151,7 +161,7 @@ async fn autoformat_project(check: bool) -> Result<()> {
return Ok(()); return Ok(());
} }
let indent = indentation_for(&files_to_format[0])?; let indent = indentation_for(&files_to_format[0], split_line_attributes)?;
let counts = files_to_format let counts = files_to_format
.into_iter() .into_iter()
@@ -185,7 +195,10 @@ async fn autoformat_project(check: bool) -> Result<()> {
Ok(()) Ok(())
} }
fn indentation_for(file_or_dir: impl AsRef<Path>) -> Result<IndentOptions> { fn indentation_for(
file_or_dir: impl AsRef<Path>,
split_line_attributes: bool,
) -> Result<IndentOptions> {
let out = std::process::Command::new("cargo") let out = std::process::Command::new("cargo")
.args(["fmt", "--", "--print-config", "current"]) .args(["fmt", "--", "--print-config", "current"])
.arg(file_or_dir.as_ref()) .arg(file_or_dir.as_ref())
@@ -225,6 +238,7 @@ fn indentation_for(file_or_dir: impl AsRef<Path>) -> Result<IndentOptions> {
IndentType::Spaces IndentType::Spaces
}, },
tab_spaces, tab_spaces,
split_line_attributes,
)) ))
} }
@@ -273,6 +287,7 @@ async fn test_auto_fmt() {
check: false, check: false,
raw: Some(test_rsx), raw: Some(test_rsx),
file: None, file: None,
split_line_attributes: false,
}; };
fmt.autoformat().await.unwrap(); fmt.autoformat().await.unwrap();
+9 -1
View File
@@ -1,3 +1,4 @@
use crate::ScopeState;
use std::ptr::NonNull; use std::ptr::NonNull;
use crate::{ use crate::{
@@ -174,7 +175,14 @@ impl VirtualDom {
scope.borrowed_props.borrow_mut().clear(); scope.borrowed_props.borrow_mut().clear();
// Now that all the references are gone, we can safely drop our own references in our listeners. // Now that all the references are gone, we can safely drop our own references in our listeners.
let mut listeners = scope.attributes_to_drop_before_render.borrow_mut(); scope.drop_listeners();
}
}
impl ScopeState {
/// Drop all listeners that were allocated in the bump allocator.
pub(crate) fn drop_listeners(&self) {
let mut listeners = self.attributes_to_drop_before_render.borrow_mut();
listeners.drain(..).for_each(|listener| { listeners.drain(..).for_each(|listener| {
let listener = unsafe { &*listener }; let listener = unsafe { &*listener };
if let AttributeValue::Listener(l) = &listener.value { if let AttributeValue::Listener(l) = &listener.value {
+8 -9
View File
@@ -28,15 +28,14 @@ use crate::innerlude::*;
#[allow(non_upper_case_globals, non_snake_case)] #[allow(non_upper_case_globals, non_snake_case)]
pub fn Fragment<'a>(cx: Scope<'a, FragmentProps<'a>>) -> Element { pub fn Fragment<'a>(cx: Scope<'a, FragmentProps<'a>>) -> Element {
let children = cx.props.0.as_ref()?; let children = cx.props.0.as_ref()?;
Some(VNode { Some(cx.vnode(
key: children.key, children.parent.clone(),
parent: children.parent.clone(), children.key,
stable_id: children.stable_id.clone(), children.template.clone(),
template: children.template.clone(), children.root_ids.clone(),
root_ids: children.root_ids.clone(), children.dynamic_nodes,
dynamic_nodes: children.dynamic_nodes, children.dynamic_attrs,
dynamic_attrs: children.dynamic_attrs, ))
})
} }
pub struct FragmentProps<'a>(Element<'a>); pub struct FragmentProps<'a>(Element<'a>);
+10 -10
View File
@@ -24,7 +24,7 @@ use crate::{innerlude::VNode, ScopeState};
/// ///
/// ```rust, ignore /// ```rust, ignore
/// LazyNodes::new(|f| { /// LazyNodes::new(|f| {
/// static TEMPLATE: dioxus::core::Template = dioxus::core::Template { /// static TEMPLATE: dioxus::core::Template = dioxus::core::Template {
/// name: "main.rs:5:5:20", // Source location of the template for hot reloading /// name: "main.rs:5:5:20", // Source location of the template for hot reloading
/// roots: &[ /// roots: &[
/// dioxus::core::TemplateNode::Element { /// dioxus::core::TemplateNode::Element {
@@ -37,19 +37,19 @@ use crate::{innerlude::VNode, ScopeState};
/// node_paths: &[], /// node_paths: &[],
/// attr_paths: &[], /// attr_paths: &[],
/// }; /// };
/// dioxus::core::VNode { /// f.vnode(
/// parent: None, /// None,
/// key: None, /// None,
/// template: std::cell::Cell::new(TEMPLATE), /// std::cell::Cell::new(TEMPLATE),
/// root_ids: dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in( /// dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in(
/// 1usize, /// 1usize,
/// f.bump(), /// f.bump(),
/// ) /// )
/// .into(), /// .into(),
/// dynamic_nodes: f.bump().alloc([]), /// f.bump().alloc([]),
/// dynamic_attrs: f.bump().alloc([]), /// f.bump().alloc([]),
/// }) /// )
/// } /// })
/// ``` /// ```
/// ///
/// Find more information about how to construct [`VNode`] at <https://dioxuslabs.com/learn/0.4/contributing/walkthrough_readme#the-rsx-macro> /// Find more information about how to construct [`VNode`] at <https://dioxuslabs.com/learn/0.4/contributing/walkthrough_readme#the-rsx-macro>
+19 -19
View File
@@ -40,6 +40,7 @@ impl<'a> Default for RenderReturn<'a> {
/// ///
/// The dynamic parts of the template are stored separately from the static parts. This allows faster diffing by skipping /// The dynamic parts of the template are stored separately from the static parts. This allows faster diffing by skipping
/// static parts of the template. /// static parts of the template.
#[non_exhaustive]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct VNode<'a> { pub struct VNode<'a> {
/// The key given to the root of this template. /// The key given to the root of this template.
@@ -70,20 +71,19 @@ pub struct VNode<'a> {
impl<'a> VNode<'a> { impl<'a> VNode<'a> {
/// Create a template with no nodes that will be skipped over during diffing /// Create a template with no nodes that will be skipped over during diffing
pub fn empty(cx: &'a ScopeState) -> Element<'a> { pub fn empty(cx: &'a ScopeState) -> Element<'a> {
Some(VNode { Some(cx.vnode(
key: None, Cell::new(None),
parent: Default::default(), None,
stable_id: Default::default(), Cell::new(Template {
root_ids: RefCell::new(bumpalo::collections::Vec::new_in(cx.bump())),
dynamic_nodes: &[],
dynamic_attrs: &[],
template: Cell::new(Template {
name: "dioxus-empty", name: "dioxus-empty",
roots: &[], roots: &[],
node_paths: &[], node_paths: &[],
attr_paths: &[], attr_paths: &[],
}), }),
}) RefCell::new(bumpalo::collections::Vec::new_in(cx.bump())),
&[],
&[],
))
} }
/// Create a new VNode /// Create a new VNode
@@ -820,16 +820,16 @@ impl<'b> IntoDynNode<'b> for Arguments<'_> {
} }
impl<'a> IntoDynNode<'a> for &'a VNode<'a> { impl<'a> IntoDynNode<'a> for &'a VNode<'a> {
fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode<'a> { fn into_dyn_node(self, cx: &'a ScopeState) -> DynamicNode<'a> {
DynamicNode::Fragment(_cx.bump().alloc([VNode { let vnode = cx.vnode(
parent: self.parent.clone(), self.parent.clone(),
stable_id: self.stable_id.clone(), self.key,
template: self.template.clone(), self.template.clone(),
root_ids: self.root_ids.clone(), self.root_ids.clone(),
key: self.key, self.dynamic_nodes,
dynamic_nodes: self.dynamic_nodes, self.dynamic_attrs,
dynamic_attrs: self.dynamic_attrs, );
}])) DynamicNode::Fragment(cx.bump().alloc([vnode]))
} }
} }
+1
View File
@@ -133,6 +133,7 @@ impl Runtime {
/// } /// }
/// } /// }
/// ///
/// # #[allow(non_snake_case)]
/// fn Component(cx: Scope<ComponentProps>) -> Element { /// fn Component(cx: Scope<ComponentProps>) -> Element {
/// cx.use_hook(|| RuntimeGuard::new(cx.props.runtime.clone())); /// cx.use_hook(|| RuntimeGuard::new(cx.props.runtime.clone()));
/// ///
+37 -10
View File
@@ -2,13 +2,13 @@ use crate::{
any_props::AnyProps, any_props::AnyProps,
any_props::VProps, any_props::VProps,
bump_frame::BumpFrame, bump_frame::BumpFrame,
innerlude::{DynamicNode, EventHandler, VComponent, VNodeId, VText}, innerlude::{DynamicNode, ElementRef, EventHandler, VComponent, VNodeId, VText},
lazynodes::LazyNodes, lazynodes::LazyNodes,
nodes::{IntoAttributeValue, IntoDynNode, RenderReturn}, nodes::{IntoAttributeValue, IntoDynNode, RenderReturn},
runtime::Runtime, runtime::Runtime,
scope_context::ScopeContext, scope_context::ScopeContext,
AnyValue, Attribute, AttributeType, AttributeValue, Element, Event, MountedAttribute, AnyValue, Attribute, AttributeType, AttributeValue, Element, ElementId, Event,
Properties, TaskId, MountedAttribute, Properties, TaskId, Template, VNode,
}; };
use bumpalo::{boxed::Box as BumpBox, Bump}; use bumpalo::{boxed::Box as BumpBox, Bump};
use std::{ use std::{
@@ -102,6 +102,7 @@ pub struct ScopeState {
impl Drop for ScopeState { impl Drop for ScopeState {
fn drop(&mut self) { fn drop(&mut self) {
self.drop_listeners();
self.runtime.remove_context(self.context_id); self.runtime.remove_context(self.context_id);
} }
} }
@@ -345,19 +346,37 @@ impl<'src> ScopeState {
/// // Actually build the tree and allocate it /// // Actually build the tree and allocate it
/// cx.render(lazy_tree) /// cx.render(lazy_tree)
/// } /// }
///``` /// ```
pub fn render(&'src self, rsx: LazyNodes<'src, '_>) -> Element<'src> { pub fn render(&'src self, rsx: LazyNodes<'src, '_>) -> Element<'src> {
let element = rsx.call(self); // Note: We can't do anything in this function related to safety because the user could always circumvent it by creating a VNode manually and return it without calling this function
Some(rsx.call(self))
}
/// Create a [`crate::VNode`] from the component parts
pub fn vnode(
&'src self,
parent: Cell<Option<ElementRef>>,
key: Option<&'src str>,
template: Cell<Template<'static>>,
root_ids: RefCell<bumpalo::collections::Vec<'src, ElementId>>,
dynamic_nodes: &'src [DynamicNode<'src>],
dynamic_attrs: &'src [MountedAttribute<'src>],
) -> VNode<'src> {
let mut listeners = self.attributes_to_drop_before_render.borrow_mut(); let mut listeners = self.attributes_to_drop_before_render.borrow_mut();
for attr in element.dynamic_attrs { for attr in dynamic_attrs {
attr.ty.for_each(|attr| { let attrs = match attr.ty {
AttributeType::Single(ref attr) => std::slice::from_ref(attr),
AttributeType::Many(attrs) => attrs,
};
for attr in attrs {
match attr.value { match attr.value {
// We need to drop listeners before the next render because they may borrow data from the borrowed props which will be dropped // We need to drop listeners before the next render because they may borrow data from the borrowed props which will be dropped
AttributeValue::Listener(_) => { AttributeValue::Listener(_) => {
let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) }; let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) };
listeners.push(unbounded); listeners.push(unbounded);
} }
// We need to drop any values manually to make sure that their drop implementation is called before the next render // We need to drop any values manually to make sure that their drop implementation is called before the next render
AttributeValue::Any(_) => { AttributeValue::Any(_) => {
let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) }; let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) };
@@ -366,7 +385,7 @@ impl<'src> ScopeState {
_ => (), _ => (),
} }
}) }
} }
let mut props = self.borrowed_props.borrow_mut(); let mut props = self.borrowed_props.borrow_mut();
@@ -374,7 +393,7 @@ impl<'src> ScopeState {
.previous_frame() .previous_frame()
.props_to_drop_before_reset .props_to_drop_before_reset
.borrow_mut(); .borrow_mut();
for node in element.dynamic_nodes { for node in dynamic_nodes {
if let DynamicNode::Component(comp) = node { if let DynamicNode::Component(comp) = node {
let unbounded = unsafe { std::mem::transmute(comp as *const VComponent) }; let unbounded = unsafe { std::mem::transmute(comp as *const VComponent) };
if !comp.static_props { if !comp.static_props {
@@ -384,7 +403,15 @@ impl<'src> ScopeState {
} }
} }
Some(element) VNode {
stable_id: Default::default(),
key,
parent,
template,
root_ids,
dynamic_nodes,
dynamic_attrs,
}
} }
/// Create a dynamic text node using [`Arguments`] and the [`ScopeState`]'s internal [`Bump`] allocator /// Create a dynamic text node using [`Arguments`] and the [`ScopeState`]'s internal [`Bump`] allocator
+12 -9
View File
@@ -2,7 +2,7 @@
use dioxus::prelude::Props; use dioxus::prelude::Props;
use dioxus_core::{MountedAttribute, *}; use dioxus_core::{MountedAttribute, *};
use std::{cfg, collections::HashSet}; use std::{cell::Cell, cfg, collections::HashSet};
fn random_ns() -> Option<&'static str> { fn random_ns() -> Option<&'static str> {
let namespace = rand::random::<u8>() % 2; let namespace = rand::random::<u8>() % 2;
@@ -171,15 +171,16 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode {
match rand::random::<u8>() % range { match rand::random::<u8>() % range {
0 => DynamicNode::Placeholder(Default::default()), 0 => DynamicNode::Placeholder(Default::default()),
1 => cx.make_node((0..(rand::random::<u8>() % 5)).map(|_| { 1 => cx.make_node((0..(rand::random::<u8>() % 5)).map(|_| {
VNode::new( cx.vnode(
None, None.into(),
Template { Default::default(),
Cell::new(Template {
name: concat!(file!(), ":", line!(), ":", column!(), ":0"), name: concat!(file!(), ":", line!(), ":", column!(), ":0"),
roots: &[TemplateNode::Dynamic { id: 0 }], roots: &[TemplateNode::Dynamic { id: 0 }],
node_paths: &[&[0]], node_paths: &[&[0]],
attr_paths: &[], attr_paths: &[],
}, }),
bumpalo::collections::Vec::new_in(cx.bump()), bumpalo::collections::Vec::new_in(cx.bump()).into(),
cx.bump().alloc([cx.component( cx.bump().alloc([cx.component(
create_random_element, create_random_element,
DepthProps { depth, root: false }, DepthProps { depth, root: false },
@@ -273,10 +274,12 @@ fn create_random_element(cx: Scope<DepthProps>) -> Element {
) )
.into_boxed_str(), .into_boxed_str(),
)); ));
let node = VNode::new( println!("{template:#?}");
let node = cx.vnode(
None.into(),
None, None,
template, Cell::new(template),
bumpalo::collections::Vec::new_in(cx.bump()), bumpalo::collections::Vec::new_in(cx.bump()).into(),
{ {
let dynamic_nodes: Vec<_> = dynamic_node_types let dynamic_nodes: Vec<_> = dynamic_node_types
.iter() .iter()
+2 -5
View File
@@ -53,10 +53,7 @@ tao = { version = "0.24.0", features = ["rwh_05"] }
[target.'cfg(any(target_os = "windows",target_os = "macos",target_os = "linux",target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))'.dependencies] [target.'cfg(any(target_os = "windows",target_os = "macos",target_os = "linux",target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))'.dependencies]
# This is only for debug mode, and it appears mobile does not support some packages this uses # This is only for debug mode, and it appears mobile does not support some packages this uses
manganis-cli-support = { git = "https://github.com/DioxusLabs/collect-assets", optional = true, features = [ manganis-cli-support = { workspace = true, optional = true, features = ["webp", "html"] }
"webp",
"html",
] }
rfd = "0.12" rfd = "0.12"
global-hotkey = "0.4.1" global-hotkey = "0.4.1"
muda = "0.11.3" muda = "0.11.3"
@@ -76,7 +73,7 @@ fullscreen = ["wry/fullscreen"]
transparent = ["wry/transparent"] transparent = ["wry/transparent"]
devtools = ["wry/devtools"] devtools = ["wry/devtools"]
hot-reload = ["dioxus-hot-reload"] hot-reload = ["dioxus-hot-reload"]
asset-collect = ["manganis-cli-support"] collect-assets = ["manganis-cli-support"]
gnu = [] gnu = []
[package.metadata.docs.rs] [package.metadata.docs.rs]
+2 -2
View File
@@ -63,7 +63,7 @@ impl<P: 'static> App<P> {
pub fn new(cfg: Config, props: P, root: Component<P>) -> (EventLoop<UserWindowEvent>, Self) { pub fn new(cfg: Config, props: P, root: Component<P>) -> (EventLoop<UserWindowEvent>, Self) {
let event_loop = EventLoopBuilder::<UserWindowEvent>::with_user_event().build(); let event_loop = EventLoopBuilder::<UserWindowEvent>::with_user_event().build();
let mut app = Self { let app = Self {
root, root,
window_behavior: cfg.last_window_close_behaviour, window_behavior: cfg.last_window_close_behaviour,
is_visible_before_start: true, is_visible_before_start: true,
@@ -109,7 +109,7 @@ impl<P: 'static> App<P> {
} }
#[cfg(all(feature = "hot-reload", debug_assertions))] #[cfg(all(feature = "hot-reload", debug_assertions))]
pub fn connect_hotreload(&mut self) { pub fn connect_hotreload(&self) {
dioxus_hot_reload::connect({ dioxus_hot_reload::connect({
let proxy = self.shared.proxy.clone(); let proxy = self.shared.proxy.clone();
move |template| { move |template| {
+1
View File
@@ -113,6 +113,7 @@ pub fn launch_with_props_blocking<P: 'static>(root: Component<P>, props: P, cfg:
EventData::Poll => app.poll_vdom(id), EventData::Poll => app.poll_vdom(id),
EventData::NewWindow => app.handle_new_window(), EventData::NewWindow => app.handle_new_window(),
EventData::CloseWindow => app.handle_close_msg(id), EventData::CloseWindow => app.handle_close_msg(id),
#[cfg(feature = "hot-reload")]
EventData::HotReloadEvent(msg) => app.handle_hot_reload_msg(msg), EventData::HotReloadEvent(msg) => app.handle_hot_reload_msg(msg),
EventData::Ipc(msg) => match msg.method() { EventData::Ipc(msg) => match msg.method() {
IpcMethod::FileDialog => app.handle_file_dialog_msg(msg, id), IpcMethod::FileDialog => app.handle_file_dialog_msg(msg, id),
@@ -83,7 +83,7 @@ fn Grid(cx: Scope<GridProps>) -> Element {
let alpha = y as f32*100.0/size as f32 + counts.read()[x*size + y] as f32; let alpha = y as f32*100.0/size as f32 + counts.read()[x*size + y] as f32;
let key = format!("{}-{}", x, y); let key = format!("{}-{}", x, y);
rsx! { rsx! {
Box{ Box {
x: x, x: x,
y: y, y: y,
alpha: 100.0, alpha: 100.0,
-3
View File
@@ -16,7 +16,6 @@ dioxus-html = { workspace = true, optional = true }
dioxus-core-macro = { workspace = true, optional = true } dioxus-core-macro = { workspace = true, optional = true }
dioxus-hooks = { workspace = true, optional = true } dioxus-hooks = { workspace = true, optional = true }
dioxus-rsx = { workspace = true, optional = true } dioxus-rsx = { workspace = true, optional = true }
manganis = { git = "https://github.com/DioxusLabs/collect-assets" }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
dioxus-hot-reload = { workspace = true, optional = true } dioxus-hot-reload = { workspace = true, optional = true }
@@ -37,8 +36,6 @@ criterion = "0.3.5"
thiserror = { workspace = true } thiserror = { workspace = true }
env_logger = "0.10.0" env_logger = "0.10.0"
tokio = { workspace = true, features = ["full"] } tokio = { workspace = true, features = ["full"] }
# dioxus-edit-stream = { workspace = true }
[[bench]] [[bench]]
name = "jsframework" name = "jsframework"
-3
View File
@@ -22,9 +22,6 @@ pub use dioxus_rsx as rsx;
pub use dioxus_core_macro as core_macro; pub use dioxus_core_macro as core_macro;
pub mod prelude { pub mod prelude {
pub use manganis;
pub use manganis::mg;
#[cfg(feature = "hooks")] #[cfg(feature = "hooks")]
pub use crate::hooks::*; pub use crate::hooks::*;
+6 -6
View File
@@ -1654,9 +1654,9 @@
"dev": true "dev": true
}, },
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.15.1", "version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@@ -4973,9 +4973,9 @@
"dev": true "dev": true
}, },
"follow-redirects": { "follow-redirects": {
"version": "1.15.1", "version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"dev": true "dev": true
}, },
"fs-constants": { "fs-constants": {
+3
View File
@@ -15,6 +15,7 @@ pub fn format_rsx(raw: String, use_tabs: bool, indent_size: usize) -> String {
IndentType::Spaces IndentType::Spaces
}, },
indent_size, indent_size,
false,
), ),
); );
block.unwrap() block.unwrap()
@@ -32,6 +33,7 @@ pub fn format_selection(raw: String, use_tabs: bool, indent_size: usize) -> Stri
IndentType::Spaces IndentType::Spaces
}, },
indent_size, indent_size,
false,
), ),
); );
block.unwrap() block.unwrap()
@@ -67,6 +69,7 @@ pub fn format_file(contents: String, use_tabs: bool, indent_size: usize) -> Form
IndentType::Spaces IndentType::Spaces
}, },
indent_size, indent_size,
false,
), ),
); );
let out = dioxus_autofmt::apply_formats(&contents, _edits.clone()); let out = dioxus_autofmt::apply_formats(&contents, _edits.clone());
+1 -1
View File
@@ -69,7 +69,7 @@ web-sys = { version = "0.3.61", features = ["Window", "Document", "Element", "Ht
[target.'cfg(any(target_os = "windows",target_os = "macos",target_os = "linux",target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))'.dependencies] [target.'cfg(any(target_os = "windows",target_os = "macos",target_os = "linux",target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))'.dependencies]
# This is only for debug mode, and it appears mobile does not support some packages this uses # This is only for debug mode, and it appears mobile does not support some packages this uses
manganis-cli-support = { git = "https://github.com/DioxusLabs/collect-assets", features = ["webp", "html"] } manganis-cli-support = { workspace = true, features = ["webp", "html"] }
[features] [features]
default = ["hot-reload"] default = ["hot-reload"]
+2 -2
View File
@@ -1,4 +1,4 @@
use std::{any::Any, collections::HashMap}; use std::any::Any;
pub trait HasFileData: std::any::Any { pub trait HasFileData: std::any::Any {
fn files(&self) -> Option<std::sync::Arc<dyn FileEngine>> { fn files(&self) -> Option<std::sync::Arc<dyn FileEngine>> {
@@ -10,7 +10,7 @@ pub trait HasFileData: std::any::Any {
/// A file engine that serializes files to bytes /// A file engine that serializes files to bytes
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)] #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
pub struct SerializedFileEngine { pub struct SerializedFileEngine {
pub files: HashMap<String, Vec<u8>>, pub files: std::collections::HashMap<String, Vec<u8>>,
} }
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
+14 -23
View File
@@ -1,3 +1,5 @@
use std::cell::Cell;
use dioxus::prelude::Props; use dioxus::prelude::Props;
use dioxus_core::*; use dioxus_core::*;
use dioxus_native_core::prelude::*; use dioxus_native_core::prelude::*;
@@ -178,15 +180,16 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode {
match rand::random::<u8>() % range { match rand::random::<u8>() % range {
0 => DynamicNode::Placeholder(Default::default()), 0 => DynamicNode::Placeholder(Default::default()),
1 => cx.make_node((0..(rand::random::<u8>() % 5)).map(|_| { 1 => cx.make_node((0..(rand::random::<u8>() % 5)).map(|_| {
VNode::new( cx.vnode(
None, None.into(),
Template { Default::default(),
Cell::new(Template {
name: concat!(file!(), ":", line!(), ":", column!(), ":0"), name: concat!(file!(), ":", line!(), ":", column!(), ":0"),
roots: &[TemplateNode::Dynamic { id: 0 }], roots: &[TemplateNode::Dynamic { id: 0 }],
node_paths: &[&[0]], node_paths: &[&[0]],
attr_paths: &[], attr_paths: &[],
}, }),
dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump()), dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump()).into(),
cx.bump().alloc([cx.component( cx.bump().alloc([cx.component(
create_random_element, create_random_element,
DepthProps { depth, root: false }, DepthProps { depth, root: false },
@@ -204,20 +207,6 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode {
} }
} }
fn create_random_dynamic_mounted_attr(cx: &ScopeState) -> MountedAttribute {
match rand::random::<u8>() % 2 {
0 => MountedAttribute::from(
&*cx.bump().alloc(
(0..(rand::random::<u8>() % 3) as usize)
.map(|_| create_random_dynamic_attr(cx))
.collect::<Vec<_>>(),
),
),
1 => MountedAttribute::from(create_random_dynamic_attr(cx)),
_ => unreachable!(),
}
}
fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute { fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute {
let value = match rand::random::<u8>() % 6 { let value = match rand::random::<u8>() % 6 {
0 => AttributeValue::Text(Box::leak( 0 => AttributeValue::Text(Box::leak(
@@ -230,6 +219,7 @@ fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute {
5 => AttributeValue::None, 5 => AttributeValue::None,
_ => unreachable!(), _ => unreachable!(),
}; };
Attribute::new( Attribute::new(
Box::leak(format!("attr{}", rand::random::<usize>()).into_boxed_str()), Box::leak(format!("attr{}", rand::random::<usize>()).into_boxed_str()),
value, value,
@@ -266,10 +256,11 @@ fn create_random_element(cx: Scope<DepthProps>) -> Element {
.into_boxed_str(), .into_boxed_str(),
)); ));
println!("{template:#?}"); println!("{template:#?}");
let node = VNode::new( let node = cx.vnode(
None.into(),
None, None,
template, Cell::new(template),
dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump()), dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump()).into(),
{ {
let dynamic_nodes: Vec<_> = dynamic_node_types let dynamic_nodes: Vec<_> = dynamic_node_types
.iter() .iter()
@@ -287,7 +278,7 @@ fn create_random_element(cx: Scope<DepthProps>) -> Element {
cx.bump() cx.bump()
.alloc( .alloc(
(0..template.attr_paths.len()) (0..template.attr_paths.len())
.map(|_| create_random_dynamic_mounted_attr(cx)) .map(|_| create_random_dynamic_attr(cx).into())
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
) )
.as_slice(), .as_slice(),
+5 -3
View File
@@ -254,10 +254,12 @@ impl<'a> ToTokens for TemplateRenderer<'a> {
node_paths: &[ #(#node_paths),* ], node_paths: &[ #(#node_paths),* ],
attr_paths: &[ #(#attr_paths),* ], attr_paths: &[ #(#attr_paths),* ],
}; };
::dioxus::core::VNode::new(
__cx.vnode(
None.into(),
#key_tokens, #key_tokens,
TEMPLATE, std::cell::Cell::new(TEMPLATE),
dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in(#root_count, __cx.bump()), dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in(#root_count, __cx.bump()).into(),
__cx.bump().alloc([ #( #node_printer ),* ]), __cx.bump().alloc([ #( #node_printer ),* ]),
__cx.bump().alloc([ #( #dyn_attr_printer ),* ]), __cx.bump().alloc([ #( #dyn_attr_printer ),* ]),
) )
-6
View File
@@ -1,6 +0,0 @@
# Known quirks for browsers and their workarounds
- text merging (solved through comment nodes)
- cursor jumping to end on inputs (not yet solved, solved in React already)
- SVG attributes cannot be set (solved using the correct method)
- volatile components