Full Code of StaffEngineer/velo for AI

main 8489b7e99471 cached
92 files
479.8 KB
105.4k tokens
272 symbols
1 requests
Download .txt
Showing preview only (509K chars total). Download the full file or copy to clipboard to get everything.
Repository: StaffEngineer/velo
Branch: main
Commit: 8489b7e99471
Files: 92
Total size: 479.8 KB

Directory structure:
gitextract_nb0mso7g/

├── .cargo/
│   └── config.toml
├── .github/
│   └── workflows/
│       ├── deploy-wasm.yml
│       ├── pr.yml
│       └── release.yml
├── .gitignore
├── 128x128.icns
├── Cargo.toml
├── Cross.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── Readme.md
├── assets/
│   └── shaders/
│       ├── grid.wgsl
│       └── shadows.wgsl
├── code_of_conduct.md
├── contributing.md
├── crates/
│   └── bevy_markdown/
│       ├── Cargo.toml
│       ├── LICENSE-APACHE
│       ├── LICENSE-MIT
│       ├── Readme.md
│       └── src/
│           ├── lib.rs
│           └── snapshots/
│               ├── bevy_markdown__tests__test_render_break.snap
│               ├── bevy_markdown__tests__test_render_break_after_link.snap
│               ├── bevy_markdown__tests__test_render_code.snap
│               ├── bevy_markdown__tests__test_render_nested_ordered_list.snap
│               ├── bevy_markdown__tests__test_render_nested_unordered_list.snap
│               ├── bevy_markdown__tests__test_render_ordered_list.snap
│               ├── bevy_markdown__tests__test_render_text_style.snap
│               ├── bevy_markdown__tests__test_render_text_style_complicated.snap
│               ├── bevy_markdown__tests__test_render_text_style_header.snap
│               └── bevy_markdown__tests__test_render_unordered_list.snap
├── docs/
│   └── architecture.md
├── justfile
├── security.md
└── src/
    ├── canvas/
    │   ├── arrow/
    │   │   ├── components.rs
    │   │   ├── events.rs
    │   │   ├── mod.rs
    │   │   ├── systems.rs
    │   │   └── utils.rs
    │   ├── grid/
    │   │   ├── mod.rs
    │   │   └── systems.rs
    │   ├── mod.rs
    │   └── shadows/
    │       ├── mod.rs
    │       └── systems.rs
    ├── components.rs
    ├── lib.rs
    ├── macros.rs
    ├── main.rs
    ├── resources.rs
    ├── systems.rs
    ├── themes.rs
    ├── ui_plugin/
    │   ├── mod.rs
    │   ├── systems/
    │   │   ├── active_editor_changed.rs
    │   │   ├── button_handlers.rs
    │   │   ├── canvas_click.rs
    │   │   ├── clickable_links.rs
    │   │   ├── create_new_node.rs
    │   │   ├── doc_list.rs
    │   │   ├── drawing.rs
    │   │   ├── effects.rs
    │   │   ├── entity_to_edit_changed.rs
    │   │   ├── init_layout/
    │   │   │   ├── add_arrow.rs
    │   │   │   ├── add_color.rs
    │   │   │   ├── add_effect.rs
    │   │   │   ├── add_front_back.rs
    │   │   │   ├── add_list.rs
    │   │   │   ├── add_menu_button.rs
    │   │   │   ├── add_pencil.rs
    │   │   │   ├── add_search_box.rs
    │   │   │   ├── add_text.rs
    │   │   │   ├── add_text_pos.rs
    │   │   │   ├── add_two_points_draw.rs
    │   │   │   ├── add_visibility.rs
    │   │   │   ├── init_layout.rs
    │   │   │   └── node_manipulation.rs
    │   │   ├── interactive_sprites.rs
    │   │   ├── keyboard.rs
    │   │   ├── load.rs
    │   │   ├── modal.rs
    │   │   ├── resize_node.rs
    │   │   ├── resize_window.rs
    │   │   ├── save.rs
    │   │   ├── search.rs
    │   │   ├── set_focused_entity.rs
    │   │   ├── tabs.rs
    │   │   └── update_rectangle_position.rs
    │   └── ui_helpers/
    │       ├── add_list_item.rs
    │       ├── add_tab.rs
    │       ├── components.rs
    │       ├── spawn_modal.rs
    │       ├── spawn_node.rs
    │       └── ui_helpers.rs
    └── utils.rs

================================================
FILE CONTENTS
================================================

================================================
FILE: .cargo/config.toml
================================================
[target.wasm32-unknown-unknown]
runner = "wasm-server-runner"

================================================
FILE: .github/workflows/deploy-wasm.yml
================================================
name: Build and Deploy WebAssembly to Web Branch
on:
  push:
    branches: [main]

jobs:
  build_and_deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Install Rust and wasm toolchain
        uses: actions-rs/toolchain@v1
        with:
          profile: minimal
          toolchain: stable
          target: wasm32-unknown-unknown
      
      - name: Cache
        uses: Swatinem/rust-cache@v2

      - name: Install wasm-bindgen
        run: |
          mkdir wasm-bindgen
          curl -sSL "https://github.com/rustwasm/wasm-bindgen/releases/download/0.2.86/wasm-bindgen-0.2.86-x86_64-unknown-linux-musl.tar.gz" | tar xvz -C ./wasm-bindgen wasm-bindgen-0.2.86-x86_64-unknown-linux-musl --strip=1
          echo `pwd`/wasm-bindgen >> $GITHUB_PATH
          
      - name: Install wasm-opt
        run: |
          mkdir binaryen
          curl -sSL https://github.com/WebAssembly/binaryen/releases/download/version_111/binaryen-version_111-x86_64-linux.tar.gz  | tar xvz -C ./binaryen binaryen-version_111 --strip=1
          echo `pwd`/binaryen/bin >> $GITHUB_PATH

      - name : Build Wasm
        run: RUSTFLAGS=--cfg=web_sys_unstable_apis cargo build --release --target wasm32-unknown-unknown
        
      - name: Generate JavaScript bindings
        run: wasm-bindgen --target web  --no-typescript --out-dir out target/wasm32-unknown-unknown/release/velo.wasm
        
      - name: Optimize Wasm
        run : wasm-opt -Os out/velo_bg.wasm -o out/velo_bg.wasm

      - name: Copy WebAssembly files to web branch
        run: |
          git config --global user.email ""
          git config --global user.name "GitHub Actions"
          git fetch --all
          git checkout -b web origin/web -f
          cp -r out/* .
          rm -rf binaryen wasm-bindgen target out
          git add .
          git commit -m "Build and Deploy WebAssembly to Web Branch" || true
          git push origin web


================================================
FILE: .github/workflows/pr.yml
================================================
---
on:
  pull_request: null
name: pr checks

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  check-default:
    name: Check default
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Install stable toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: stable
          target: wasm32-unknown-unknown
      - name: Update
        run: sudo apt-get update
      - name: Deps
        run: sudo apt-get install g++ pkg-config libx11-dev libasound2-dev libudev-dev
      - name: Cache
        uses: Swatinem/rust-cache@v2
      - name: Check
        run: cargo check --all-targets
  check-wasm:
    name: Check wasm
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Install stable toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: stable
          target: wasm32-unknown-unknown
      - name: Cache
        uses: Swatinem/rust-cache@v2
      - name: Check
        run: RUSTFLAGS=--cfg=web_sys_unstable_apis cargo check --target wasm32-unknown-unknown --all-targets
  lints:
    name: Lints
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Install stable toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: stable
          components: rustfmt, clippy
      - name: Update
        run: sudo apt-get update
      - name: Deps
        run: sudo apt-get install g++ pkg-config libx11-dev libasound2-dev libudev-dev
      - name: Cache
        uses: Swatinem/rust-cache@v2
      - name: Fmt
        run: cargo fmt --all -- --check
      - name: Clippy
        run: cargo clippy -- -A clippy::type_complexity -A clippy::too_many_arguments -D
          warnings
  test-velo:
    name: Test velo
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Install stable toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: stable

      - name: Cache
        uses: Swatinem/rust-cache@v2

      - name: Test velo
        run: cargo test
  test-markdown:
    name: Test markdown
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Install stable toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: stable

      - name: Cache
        uses: Swatinem/rust-cache@v2
 
      - name: Test bevy-markdown
        run: cargo test -p bevy_markdown --lib
  coverage:
    runs-on: ubuntu-latest
    env:
      CARGO_TERM_COLOR: always
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Install stable toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: stable

      - name: Cache
        uses: Swatinem/rust-cache@v2

      - name: Install cargo-llvm-cov
        uses: taiki-e/install-action@cargo-llvm-cov
    
      - name: Generate code coverage
        run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info
        
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3
        with:
          token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
          files: lcov.info
          fail_ci_if_error: true

================================================
FILE: .github/workflows/release.yml
================================================
name: release
on:
  workflow_dispatch:
    inputs:
      version:
        description: "Version"
        required: true
        default: "TEST-0.0.0"
        type: string
  push:
    tags:
    - "[0-9]+.[0-9]+.[0-9]+"
jobs:
  create-release:
    name: create-release
    runs-on: ubuntu-latest
    env:
      # Set to force version number, e.g., when no tag exists.
      VELO_VERSION: ${{ inputs.version }}

    outputs:
      upload_url: ${{ steps.release.outputs.upload_url }}
      velo_version: ${{ env.VELO_VERSION }}
    steps:
      - name: Get the release version from the tag
        shell: bash
        if: env.VELO_VERSION == ''
        run: |
          # Apparently, this is the right way to get a tag name. Really?
          #
          # See: https://github.community/t5/GitHub-Actions/How-to-get-just-the-tag-name/m-p/32167/highlight/true#M1027
          echo "VELO_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
          echo "version is: ${{ env.VELO_VERSION }}"
      - name: Create GitHub release
        id: release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ env.VELO_VERSION }}
          release_name: ${{ env.VELO_VERSION }}
          draft: true

  build-release:
    name: build-release
    needs: ['create-release']
    runs-on: ${{ matrix.os }}
    continue-on-error: true
    env:
      # For some builds, we use cross to test on 32-bit and big-endian
      # systems.
      CARGO: cargo
      # When CARGO is set to CROSS, this is set to `--target matrix.target`.
      TARGET_FLAGS: ""
      # When CARGO is set to CROSS, TARGET_DIR includes matrix.target.
      TARGET_DIR: ./target
      # Emit backtraces on panics.
      RUST_BACKTRACE: 1
    strategy:
      matrix:
        include:
        - build: linux
          os: ubuntu-20.04
          rust: stable
          target: x86_64-unknown-linux-gnu
        - build: linux-arm
          os: ubuntu-20.04
          rust: stable
          target: arm-unknown-linux-gnueabihf
        - build: macos
          os: macos-latest
          rust: stable
          target: x86_64-apple-darwin
        - build: win-msvc
          os: windows-2019
          rust: stable
          target: x86_64-pc-windows-msvc
        - build: win-gnu
          os: windows-2019
          rust: stable-x86_64-gnu
          target: x86_64-pc-windows-gnu
        - build: win32-msvc
          os: windows-2019
          rust: stable
          target: i686-pc-windows-msvc

    steps:
    - name: Checkout repository
      uses: actions/checkout@v2
      with:
        fetch-depth: 1

    - name: Remove .cargo
      uses: JesseTG/rm@v1.0.0
      with:
        path: .cargo

    - name: Cache cargo folder
      uses: actions/cache@v3
      with:
        key: ${{ matrix.build }}
        path: |
          ~/.cargo
          ~/.rustup

    - name: Install Rust
      uses: actions-rs/toolchain@v1
      with:
        toolchain: ${{ matrix.rust }}
        profile: minimal
        override: true
        target: ${{ matrix.target }}

    - name: Use Cross
      shell: bash
      run: |
        cargo install cross --vers 0.2.1
        echo "CARGO=cross" >> $GITHUB_ENV
        echo "TARGET_FLAGS=--target ${{ matrix.target }}" >> $GITHUB_ENV
        echo "TARGET_DIR=./target/${{ matrix.target }}" >> $GITHUB_ENV

    - name: Show command used for Cargo
      run: |
        echo "cargo command is: ${{ env.CARGO }}"
        echo "target flag is: ${{ env.TARGET_FLAGS }}"
        echo "target dir is: ${{ env.TARGET_DIR }}"

    - name: Build release binary
      env:
        BEVY_ASSET_PATH: /project/assets
      run: ${{ env.CARGO }} build --verbose --release ${{ env.TARGET_FLAGS }}

    - name: Strip release binary (linux and macos)
      if: matrix.build == 'linux' || matrix.build == 'macos'
      run: strip "target/${{ matrix.target }}/release/velo"

    - name: Strip release binary (arm)
      if: matrix.build == 'linux-arm'
      run: |
        docker run --rm -v \
          "$PWD/target:/target:Z" \
          rustembedded/cross:arm-unknown-linux-gnueabihf \
          arm-linux-gnueabihf-strip \
          /target/arm-unknown-linux-gnueabihf/release/velo

    - name: Build archive
      shell: bash
      run: |
        staging="velo-${{ needs.create-release.outputs.velo_version }}-${{ matrix.target }}"

        mkdir -p "$staging"

        cp {Readme.md,LICENSE-APACHE,LICENSE-MIT} "$staging/"

        if [ "${{ matrix.os }}" = "windows-2019" ]; then
          cp "target/${{ matrix.target }}/release/velo.exe" "$staging/"
          7z a "$staging.zip" "$staging"
          echo "ASSET=$staging.zip" >> $GITHUB_ENV
        else
          cp "target/${{ matrix.target }}/release/velo" "$staging/"
          tar czf "$staging.tar.gz" "$staging"
          echo "ASSET=$staging.tar.gz" >> $GITHUB_ENV
        fi

    - name: Upload release archive
      uses: actions/upload-release-asset@v1.0.2
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        upload_url: ${{ needs.create-release.outputs.upload_url }}
        asset_path: ${{ env.ASSET }}
        asset_name: ${{ env.ASSET }}
        asset_content_type: application/octet-stream


================================================
FILE: .gitignore
================================================
/target
.idea
.vscode
velo.json
ichart.json
data
out

================================================
FILE: Cargo.toml
================================================
[package]
name = "velo"
license = "MIT OR Apache-2.0"
description = "App for brainstorming & sharing ideas 🦀 Learning Project"
repository = "https://github.com/StaffEngineer/velo.git"
readme = "Readme.md"
version = "0.9.3"
edition = "2021"

exclude = ["assets/fonts/*", "velo.gif", "velo.png"]

# Enable max optimizations for dependencies, but not for our code:
[profile.dev.package."*"]
opt-level = 3

[profile.release]
opt-level = 'z'

[workspace]
members = [
    "crates/bevy_markdown",
]

[dependencies]
bevy = { version = "0.11", default-features = false, features = [
  "bevy_asset",
  "bevy_core_pipeline",
  "bevy_render",
  "bevy_scene",
  "bevy_sprite",
  "bevy_text",
  "bevy_ui",
  "bevy_winit",
  "png",
  "x11",
] }
base64 = "0.21.0"
serde_json = "1.0.94"
uuid = { version = "1.3.0", default-features = false, features = ["v4", "js"] }
serde = { version = "1.0", features = ["derive"] }
linkify = "0.9.0"
ehttp = "0.1.0"
async-channel = "1.8"
image = { version = "0.24.5", default-features = false, features = ["ico"] }
bevy_markdown = { path = "crates/bevy_markdown" }
bevy_cosmic_edit = { version = "0.9.2" }
bevy_embedded_assets = { version = "0.8" }
cosmic-text = { version = "0.9" }
bevy_prototype_lyon = { version = "0.9" }
bevy_pancam = { version = "0.9" }
bevy_pkv = { version = "0.8.0", default-features = true }
rand = "0.8.5"
getrandom = { version = "0.2.10", features = ["js"] }

[target.'cfg(target_arch = "wasm32")'.dependencies]
console_error_panic_hook = "0.1.7"
web-sys = { version = "0.3.61", default-features = false, features = ["Window", "Location"] }
wasm-bindgen = "0.2.86"
js-sys = "0.3.61"
url = "2.3.1"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
bevy_hanabi = { version = "0.7" }
arboard = "3.2.0"
open = "4.0.1"
toml = "0.7.3"
tantivy = "0.19.2"
directories = "5.0"
env_logger = "0.10.0"

[dev-dependencies]
tempfile = "3.5.0"

[package.metadata.bundle]
name = "velo"
identifier = "com.rust.velo"
icon = ["128x128.icns"]

# [patch.crates-io]
# bevy = { path = "../bevy" }
# bevy_ecs = { path = "../bevy/crates/bevy_ecs" }

# [patch."https://github.com/bevyengine/bevy"]
# bevy = { path = "../bevy" }


================================================
FILE: Cross.toml
================================================
[build.env]
passthrough = [
    "BEVY_ASSET_PATH",
]


================================================
FILE: LICENSE-APACHE
================================================
                                 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

================================================
FILE: LICENSE-MIT
================================================
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.

================================================
FILE: Readme.md
================================================
# Velo 🚵‍♀️🚵
![Rust](https://img.shields.io/badge/Rust-lang-000000.svg?style=flat&logo=rust)[![codecov](https://codecov.io/gh/StaffEngineer/velo/branch/main/graph/badge.svg?token=QGEKLM6ZDF)](https://codecov.io/gh/StaffEngineer/velo)

![velo](./velo.gif)
![alt text](velo.png "Velo")

## Demo

This app is primarily designed for native desktop platforms, and its
WebAssembly (wasm) target has a limited feature set. wasm target is best
suited for quick document sharing, currently, only WebGPU backend enabled for the demo:

  [<https://dimchikkk.github.io/velo?document=https://gist.githubusercontent.com/StaffEngineer/bf7d94759abbd7aa722330e5fe4f0bd5/raw/e817be0ba700e94be472d435638d762b9deadf33/velo.json>](https://staffengineer.github.io/velo?document=https://gist.githubusercontent.com/StaffEngineer/bf7d94759abbd7aa722330e5fe4f0bd5/raw/e817be0ba700e94be472d435638d762b9deadf33/velo.json)

## What\'s implemented:
-   support rectangle/circle/paperlike notes
-   add/remove note
-   note resizing
-   note repositioning
-   wrapped text inside notes
-   paste screenshot from clipboard [native target only 🖥️] 
-   connect notes with arrows
-   make app snapshot in memory and load from it (MacOs: Command + s\[l\])
-   save app state to database and load from it
-   change background color of notes
-   move note to front/back
-   positioning text inside note
-   multiple documents/tabs support
-   load app state from url
-   ability to create sharable url of the document using \"Share
    Document\" button (**.velo.toml** should be created in user's home
    directory containing GitHub access token with \"gist\" scope) [native target only 🖥️]:

   ```toml
   github_access_token = "<github_access_token>"
   ```

- initial markdown support
  - italic/bold text style
  - links
  - syntax highlighting
  - headings (proper headings support was temporarily removed)
  - inline code
  - ordered/unordered lists
- particles effect [native target only 🖥️]
- filter documents by text in notes (fuzzy search) [native target only 🖥️]
- highlight notes containing searched text [native target only 🖥️]
- ligature/emoji rendering support [emoji native target only 🖥️]
- dark/light theme support (app restart is required for now)
- infinite canvas with zooming (right click to move camera, mouse wheel to zoom)
- undo/redo for text editing [native target only 🖥️]
- drawing mode (click on pencil icon to enable it)
- draw line, arrow, rhombus or rectangle by choosing 2 points
- hide/show children notes for selected note
- navigation to random note

## Installation

[Archives of precompiled binaries for *velo* are available for Windows, macOS
and Linux.](https://github.com/StaffEngineer/velo/releases/latest)

### Compiling from Source

If you want to compile from source you can use 
```sh
cargo install --path .
```

**ATTENTION**
If you have set your cargo target directory in `.cargo/config.toml` you must provide the fullpath to the assets directory like this
```sh
BEVY_ASSET_PATH=$(realpath assets) cargo install --path .
```

## Run

Native:

```sh
cargo r --release
```

Wasm:

```sh
cargo install wasm-server-runner
RUSTFLAGS=--cfg=web_sys_unstable_apis cargo r --release --target wasm32-unknown-unknown
```

To create app bundle with icon (tested only on MacOS):

```sh
cargo install cargo-bundle
cargo bundle
```

## Pre-commit actions

```sh
cargo fmt
cargo clippy -- -A clippy::type_complexity -A clippy::too_many_arguments
```

## Basic usage

- click on rectangle icon to create rectangle note
- double-click to select note
- start typing to add text to selected note
- resize note by dragging its corners
- click on canvas to deselect note
- move note by dragging it (only unselected note can be dragged to allow mouse text selection for selected note)
- click on little arrow connector icon to connect notes, arrow connector icons are placed on each side of note
- for native target there is search box that allows to filter documents by text in notes (fuzzy search)
- for wasm target there is url query parameter `?document=<url>` to load document from url
- click save icon to save document to database on native platform or to localStorage on wasm target
- click on drawing pencil to enable drawing mode

## Troubleshooting

If the application fails to start, you can try resolving the issue by removing velo data folder. This problem may occur due to changes in the data schema between different versions of the application.

- MacOS: `/Users/<username>/Library/Application Support/velo`
- Windows: `C:\Users\<username>\AppData\Roaming\velo`
- Linux: `/home/<username>/.config/velo`
- wasm: `localStorage.clear()`

## License
All code in this repository dual-licensed under either:

MIT License or http://opensource.org/licenses/MIT
Apache License, Version 2.0 or http://www.apache.org/licenses/LICENSE-2.0
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

## Contributing
Contributions are always welcome! Please adhere to this project\'s code
of conduct.

❤️


================================================
FILE: assets/shaders/grid.wgsl
================================================
#import bevy_sprite::mesh2d_vertex_output MeshVertexOutput

struct CustomGridMaterial {
    line_color: vec4<f32>,
    grid_size: vec2<f32>,
    cell_size: vec2<f32>,
    major: f32,
};

@group(1) @binding(0)
var<uniform> material: CustomGridMaterial;

fn grid(point: vec2<f32>, cell_size: vec2<f32>, thickness: f32) -> f32 {
  let x = (abs(fract(point.x / cell_size.x)) - thickness) * cell_size.x;
  let y = (abs(fract(point.y / cell_size.y)) - thickness) * cell_size.y;
  return min(x, y);
}

fn origin(point: vec2<f32>, thickness: f32) -> f32 {
  return min(abs(point.x), abs(point.y)) - thickness;
}

@fragment
fn fragment(
    mesh: MeshVertexOutput,
) -> @location(0) vec4<f32> {
    let line_color: vec4<f32> = material.line_color;
    let grid_size: vec2<f32> = material.grid_size;
    let cell_size: vec2<f32> = material.cell_size;
    let major: f32 = material.major;

    let point = (mesh.uv - vec2(0.5)) * grid_size;

    let t = grid(point, cell_size, 0.05);
    let u = grid(point, cell_size * major, 0.2 / major);
    let g = min(t, u);
    let alpha =  1.0 - smoothstep(0.0, fwidth(g), g);
    return vec4(line_color.rgb, alpha * line_color.a);
}


================================================
FILE: assets/shaders/shadows.wgsl
================================================
//! https://www.w3.org/TR/WGSL/#builtin-functions

// #import bevy_sprite::mesh2d_vertex_output MeshVertexOutput

// taken from https://github.com/bevyengine/bevy/blob/264195ed772e1fc964c34b6f1e64a476805e1766/crates/bevy_sprite/src/mesh2d/mesh2d_vertex_output.wgsl
struct MeshVertexOutput {
    // this is `clip position` when the struct is used as a vertex stage output 
    // and `frag coord` when used as a fragment stage input
    @builtin(position) position: vec4<f32>,
    @location(0) world_position: vec4<f32>,
    @location(1) world_normal: vec3<f32>,
    @location(2) uv: vec2<f32>,
    // #ifdef VERTEX_TANGENTS
    // @location(3) world_tangent: vec4<f32>,
    // #endif
    // #ifdef VERTEX_COLORS
    // @location(4) color: vec4<f32>,
    // #endif
}

struct CustomShadowMaterial {
    color: vec4<f32>,
    flat_size: vec2<f32>,
    edge_size: vec2<f32>,
};

@group(1) @binding(0)
var<uniform> material: CustomShadowMaterial;

@fragment
fn fragment(
    mesh: MeshVertexOutput,
) -> @location(0) vec4<f32> {
    let color = material.color;
    let flat_size = material.flat_size;
    let edge_size = material.edge_size;
    let full_size = flat_size + edge_size;

    // the size matters because we want the shadow blurred edge to be in physical pixels
    // but uv is relative to the mesh size
    // we ensure, outside, in Bevy-land, that
    // the mesh size is the "shadow-casting object"'s size plus the blurred edge
    // let's imagine that we want 100px of blurred edge, for an 800px object, so that's 1000px
    // if mesh size = 1000px, then that's 10%
    // or more generally, the blurred edge size in 0..1 scale is the blurred edge size in pixels / total mesh size in pixels
    // here, edge_x/edge_y is the blurred edge size in the 0..1 scale

    let edge = edge_size / full_size;
    let ax = smoothstep(0.0, 1.0, symmetric_top(mesh.uv.x) / edge.x / 2.0);
    let ay = smoothstep(0.0, 1.0, symmetric_top(mesh.uv.y) / edge.y / 2.0);

    // `min(ax, ay)` gives sharp corners
    // `ax * ay` gives rounded corners
    // blending the two seems to give the nicest-looking results
    var a = mix(ax * ay, min(ax, ay), 0.3);

    return vec4<f32>(color.rgb, a * color.a);
}

// `v` is a value in the range between 0..0.5..1, and we want it to be a value between 1..0..1
// e.g. 0.2 becomes 0.6, 0.5 becomes 0, 0.6 becomes 0.2
fn symmetric_bottom(v: f32) -> f32 {
    return 2.0 * abs(v - 0.5);
}

// `v` is a value in the range between 0..0.5..1, and we want it to be a value between 0..1..0
// e.g. 0.2 becomes 0.4, 0.5 becomes 1, 0.6 becomes 0.8
fn symmetric_top(v: f32) -> f32 {
    return invert(symmetric_bottom(v));
}

// converts a value `v` from 0..1 to 1..0
// e.g. 0.3 becomes 0.7
fn invert(v: f32) -> f32 {
    return 1.0 - v;
}

================================================
FILE: code_of_conduct.md
================================================
# Contributor Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
  and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
  overall community

Examples of unacceptable behavior include:

* The use of sexualized language or imagery, and sexual attention or
  advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
  address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement.
All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the
reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series
of actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior,  harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within
the community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.

Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

================================================
FILE: contributing.md
================================================
# Contributing to the Velo

We welcome contributions from the community to help improve this project. Whether you're interested in fixing bugs, adding new features, or improving documentation, there are many ways to get involved.

## How to Contribute
Here are some steps to get started with contributing to this project:

* Fork the repository and clone it to your local machine
* Create a new branch for your changes
* Make your changes and test them thoroughly
* Commit your changes with a descriptive commit message
* Push your changes to your fork and submit a pull request

We appreciate contributions of any size, from small bug fixes to major new features. If you're unsure about a change you'd like to make, feel free to open an issue first to discuss it with the maintainers.


================================================
FILE: crates/bevy_markdown/Cargo.toml
================================================
[package]
name = "bevy_markdown"
version = "0.2.0"
license = "MIT OR Apache-2.0"
description = "Bevy markdown renderer"
repository = "https://github.com/StaffEngineer/velo/tree/main/crates/bevy_markdown"
edition = "2021"
keywords = ["bevy"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
markdown = "1.0.0-alpha.9"
syntect = { version = "5.0.0", default-features = false, features = ["default-fancy"] }
cosmic-text = { version = "0.9" }

[dev-dependencies]
insta = "1.29.0"

================================================
FILE: crates/bevy_markdown/LICENSE-APACHE
================================================
                                 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

================================================
FILE: crates/bevy_markdown/LICENSE-MIT
================================================
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.

MIT License

Copyright (c) 2017 Tristan Hume, Keith Hall, Google Inc and other contributors

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.

================================================
FILE: crates/bevy_markdown/Readme.md
================================================
# bevy_markdown

Built for `bevy_cosmic_edit` plugin.

Features:

- [x] bold text style
- [x] italic text style
- [x] links
- [ ] inline images
- [ ] headings (proper headings support was temporarily removed)
- [x] inline code
- [x] code block with syntax highlighting
- [x] ordered/unordered lists
- [ ] quotes
- [ ] tables
- [ ] strikethrough text
- [ ] checkboxes

⚠️ *Warning: This plugin is currently in early development, and its API is subject to change.*

================================================
FILE: crates/bevy_markdown/src/lib.rs
================================================
use std::vec;

use cosmic_text::{AttrsOwned, Color, Weight};
use syntect::easy::HighlightLines;
use syntect::highlighting::{FontStyle, ThemeSet};
use syntect::parsing::SyntaxSet;
use syntect::util::LinesWithEndings;

pub struct BevyMarkdownTheme {
    pub code_theme: String,
    pub code_default_lang: String,
    pub link: cosmic_text::Color,
    pub inline_code: cosmic_text::Color,
}

#[derive(Clone, Debug, Default)]
pub struct TextSpanMetadata {
    pub link: Option<String>,
}

#[inline]
pub fn default<T: Default>() -> T {
    std::default::Default::default()
}

#[derive(Default)]
pub struct TextSpan {
    pub text: String,
    pub font_size: Option<f32>,
    pub weigth: Option<Weight>,
    pub style: Option<cosmic_text::Style>,
    pub color: Option<cosmic_text::Color>,
    pub metadata: Option<TextSpanMetadata>,
}

pub struct BevyMarkdown {
    pub markdown_theme: BevyMarkdownTheme,
    pub text: String,
    pub attrs: AttrsOwned,
}

#[repr(u8)]
#[derive(Clone)]
enum InlineStyleType {
    Strong = 0x01,
    Emphasis = 0x02,
    StrongEmphasis = 0x03,
    // StrikeThrough = 0x04,
    // StrikeBold = 0x05,
    // StrikeItalic = 0x06,
    // StrikeBoldItalic = 0x07,
    None = 0x00,
}

pub fn get_header_font_size(val: u8) -> f32 {
    match val {
        1 => 30.0,
        2 => 27.0,
        3 => 24.0,
        4 => 21.0,
        5 => 18.0,
        6 => 15.0,
        _ => 15.0,
    }
}

impl InlineStyleType {
    #[inline]
    pub fn from_u8(style_code: u8) -> Self {
        match style_code {
            0x01 => InlineStyleType::Strong,
            0x02 => InlineStyleType::Emphasis,
            0x03 => InlineStyleType::StrongEmphasis,
            // 0x04 => InlineStyleType::StrikeThrough,
            // 0x05 => InlineStyleType::StrikeBold,
            // 0x06 => InlineStyleType::StrikeItalic,
            // 0x07 => InlineStyleType::StrikeBoldItalic,
            _ => InlineStyleType::None,
        }
    }
}

#[derive(Debug)]
pub enum BevyMarkdownError {
    Transform { info: String },
    Parsing { info: String },
}

pub fn get_bullet_for_indentation_level(level: u8) -> &'static str {
    let level = level % 3;
    if level == 0 {
        " • "
    } else if level == 1 {
        " ◦ "
    } else {
        " ▪ "
    }
}

pub fn handle_block_styling(
    node: &markdown::mdast::Node,
    bevy_markdown: &BevyMarkdown,
    text_spans: &mut Vec<TextSpan>,
    errors: &mut Vec<BevyMarkdownError>,
) -> Result<(), Vec<BevyMarkdownError>> {
    match node {
        markdown::mdast::Node::Heading(header) => {
            text_spans.push(TextSpan {
                text: "\n".to_string(),
                ..default()
            });
            header.children.iter().for_each(|child| {
                let _ = handle_inline_styling(
                    child,
                    bevy_markdown,
                    text_spans,
                    errors,
                    InlineStyleType::Strong as u8,
                    None,
                    Some(get_header_font_size(header.depth)),
                    &None,
                );
            });
            text_spans.push(TextSpan {
                text: "\n".to_string(),
                ..default()
            });
        }
        markdown::mdast::Node::Paragraph(paragraph) => {
            paragraph.children.iter().for_each(|child| match child {
                markdown::mdast::Node::Break(_) => {
                    text_spans.push(TextSpan {
                        text: "\n".to_string(),
                        ..default()
                    });
                }
                markdown::mdast::Node::Text(text) => {
                    text_spans.push(TextSpan {
                        text: text.value.to_string(),
                        ..default()
                    });
                }
                markdown::mdast::Node::Strong(_)
                | markdown::mdast::Node::Emphasis(_)
                | markdown::mdast::Node::InlineCode(_)
                | markdown::mdast::Node::Delete(_)
                | markdown::mdast::Node::Link(_) => {
                    let _ = handle_inline_styling(
                        child,
                        bevy_markdown,
                        text_spans,
                        errors,
                        InlineStyleType::None as u8,
                        None,
                        None,
                        &None,
                    );
                }
                node => errors.push(BevyMarkdownError::Transform {
                    info: format!("{:?} node is not implemented for paragraph", node),
                }),
            });
        }
        _ => errors.push(BevyMarkdownError::Transform {
            info: "nesting is not implemented".to_string(),
        }),
    }
    Ok(())
}

pub fn handle_inline_styling(
    node: &markdown::mdast::Node,
    bevy_markdown: &BevyMarkdown,
    text_spans: &mut Vec<TextSpan>,
    errors: &mut Vec<BevyMarkdownError>,
    applied_style: u8,
    force_color: Option<Color>,
    force_size: Option<f32>,
    force_data: &Option<String>,
) -> Result<(), Vec<BevyMarkdownError>> {
    match node {
        markdown::mdast::Node::InlineCode(code) => {
            let mut text_span = TextSpan {
                text: code.value.clone(),
                color: Some(bevy_markdown.markdown_theme.inline_code),
                font_size: force_size,
                ..default()
            };
            if let Some(link) = force_data {
                text_span.metadata = Some(TextSpanMetadata {
                    link: Some(link.clone()),
                })
            }
            text_spans.push(text_span);
        }
        markdown::mdast::Node::Emphasis(emphasis) => emphasis.children.iter().for_each(|child| {
            let _ = handle_inline_styling(
                child,
                bevy_markdown,
                text_spans,
                errors,
                applied_style | InlineStyleType::Emphasis as u8,
                force_color,
                force_size,
                force_data,
            );
        }),
        markdown::mdast::Node::Strong(strong) => strong.children.iter().for_each(|child| {
            let _ = handle_inline_styling(
                child,
                bevy_markdown,
                text_spans,
                errors,
                applied_style | InlineStyleType::Strong as u8,
                force_color,
                force_size,
                force_data,
            );
        }),
        markdown::mdast::Node::Text(text) => {
            let mut text_span = TextSpan {
                text: text.value.clone(),
                font_size: force_size,
                ..default()
            };
            if let Some(color) = force_color {
                text_span.color = Some(color)
            }
            if let Some(link) = force_data {
                text_span.metadata = Some(TextSpanMetadata {
                    link: Some(link.clone()),
                })
            }
            match InlineStyleType::from_u8(applied_style) {
                InlineStyleType::Strong => {
                    text_span.weigth = Some(Weight::BOLD);
                }
                InlineStyleType::Emphasis => {
                    text_span.style = Some(cosmic_text::Style::Italic);
                }
                InlineStyleType::StrongEmphasis => {
                    text_span.weigth = Some(Weight::BOLD);
                    text_span.style = Some(cosmic_text::Style::Italic);
                }
                _ => {}
            }
            text_spans.push(text_span);
        }
        markdown::mdast::Node::Link(link) => link.children.iter().for_each(|child| {
            let _ = handle_inline_styling(
                child,
                bevy_markdown,
                text_spans,
                errors,
                applied_style,
                Some(bevy_markdown.markdown_theme.link),
                force_size,
                &Some(link.url.clone()),
            );
        }),
        _ => {
            errors.push(BevyMarkdownError::Transform {
                info: "nesting is not implemented".to_string(),
            });
        }
    }
    Ok(())
}

fn handle_list_recursive(
    list: &markdown::mdast::List,
    bevy_markdown: &BevyMarkdown,
    text_spans: &mut Vec<TextSpan>,
    errors: &mut Vec<BevyMarkdownError>,
    indentation_level: u8,
) -> Result<(), Vec<BevyMarkdownError>> {
    text_spans.push(TextSpan {
        text: "\n".to_string(),
        ..default()
    });

    let mut list_index = list.start;
    list.children
        .clone()
        .into_iter()
        .for_each(|node| match node {
            markdown::mdast::Node::ListItem(item) => {
                for _ in 0..indentation_level {
                    text_spans.push(TextSpan {
                        text: "    ".to_string(),
                        ..default()
                    });
                }

                let indent_char = if list.ordered {
                    let index = list_index.unwrap();
                    list_index = Some(index + 1);
                    format!(" {}. ", index)
                } else {
                    get_bullet_for_indentation_level(indentation_level).to_string()
                };

                text_spans.push(TextSpan {
                    text: indent_char,
                    ..default()
                });

                item.children.into_iter().for_each(|child| match child {
                    markdown::mdast::Node::Paragraph(paragraph) => {
                        paragraph.children.iter().for_each(|child| {
                            let _ = handle_inline_styling(
                                child,
                                bevy_markdown,
                                text_spans,
                                errors,
                                InlineStyleType::None as u8,
                                None,
                                None,
                                &None,
                            );
                        })
                    }
                    markdown::mdast::Node::List(inner_list) => {
                        let _ = handle_list_recursive(
                            &inner_list,
                            bevy_markdown,
                            text_spans,
                            errors,
                            indentation_level + 1,
                        );
                    }
                    node => errors.push(BevyMarkdownError::Transform {
                        info: format!("{:?} node is not implemented for list item", node),
                    }),
                });

                text_spans.push(TextSpan {
                    text: "\n".to_string(),
                    ..default()
                });
            }
            _ => {
                errors.push(BevyMarkdownError::Transform {
                    info: "invalid list children".to_string(),
                });
            }
        });
    Ok(())
}

#[derive(Debug)]
pub struct BevyMarkdownLines {
    pub lines: Vec<Vec<(String, cosmic_text::AttrsOwned)>>,
    pub span_metadata: Vec<TextSpanMetadata>,
}

pub fn generate_markdown_lines(
    bevy_markdown: BevyMarkdown,
) -> Result<BevyMarkdownLines, Vec<BevyMarkdownError>> {
    let node = markdown::to_mdast(bevy_markdown.text.as_str(), &markdown::ParseOptions::gfm());
    let ps = SyntaxSet::load_defaults_newlines();
    let ts = ThemeSet::load_defaults();

    match node {
        Ok(node) => {
            let mut text_spans = Vec::new();
            let mut errors = Vec::new();
            match node {
                markdown::mdast::Node::Root(root) => {
                    root.children.iter().for_each(|child| match child {
                        markdown::mdast::Node::Code(code) => {
                            let default_lang =
                                bevy_markdown.markdown_theme.code_default_lang.clone();
                            let lang = code.lang.as_ref().unwrap_or(&default_lang);
                            let syntax = [
                                ps.find_syntax_by_name(lang.as_str()),
                                ps.find_syntax_by_extension(lang.as_str()),
                            ]
                            .iter()
                            .find(|&o| o.is_some())
                            .unwrap()
                            .unwrap();
                            let mut h = HighlightLines::new(
                                syntax,
                                &ts.themes[&bevy_markdown.markdown_theme.code_theme.clone()],
                            );
                            text_spans.push(TextSpan {
                                text: "\n\n".to_string(),
                                ..default()
                            });
                            for line in LinesWithEndings::from(code.value.as_str()) {
                                let ranges: Vec<(syntect::highlighting::Style, &str)> =
                                    h.highlight_line(line, &ps).unwrap();

                                for &(style, text) in ranges.iter() {
                                    let mut text_span = TextSpan {
                                        text: text.to_string(),
                                        ..default()
                                    };
                                    match style.font_style {
                                        FontStyle::BOLD => text_span.weigth = Some(Weight::BOLD),
                                        FontStyle::ITALIC => {
                                            text_span.style = Some(cosmic_text::Style::Italic)
                                        }
                                        FontStyle::UNDERLINE => {
                                            text_span.weigth = Some(Weight::BOLD);
                                            text_span.style = Some(cosmic_text::Style::Italic);
                                        }
                                        _ => text_span.weigth = Some(Weight::SEMIBOLD),
                                    };
                                    let color = style.foreground;
                                    text_span.color =
                                        Some(cosmic_text::Color::rgb(color.r, color.g, color.b));
                                    text_spans.push(text_span);
                                }
                            }
                            text_spans.push(TextSpan {
                                text: "\n".to_string(),
                                ..default()
                            });
                        }
                        markdown::mdast::Node::Heading(_) | markdown::mdast::Node::Paragraph(_) => {
                            let _ = handle_block_styling(
                                child,
                                &bevy_markdown,
                                &mut text_spans,
                                &mut errors,
                            );
                        }
                        markdown::mdast::Node::List(list) => {
                            let _ = handle_list_recursive(
                                list,
                                &bevy_markdown,
                                &mut text_spans,
                                &mut errors,
                                0,
                            );
                        }
                        node => errors.push(BevyMarkdownError::Transform {
                            info: format!("{:?} node is not implemented for root", node),
                        }),
                    });
                }
                node => errors.push(BevyMarkdownError::Transform {
                    info: format!("unexpected node: {:?}", node),
                }),
            }
            if !errors.is_empty() {
                Err(errors)
            } else {
                let mut spans_meta = vec![];
                let mut lines: Vec<Vec<(String, AttrsOwned)>> = vec![vec![]];

                for (i, span) in text_spans.iter().enumerate() {
                    let mut attrs = bevy_markdown.attrs.as_attrs();
                    // if cosmic-text implements attrs.size add it here
                    if let Some(color) = span.color {
                        attrs = attrs.color(color)
                    }
                    if let Some(style) = span.style {
                        attrs = attrs.style(style)
                    }
                    if let Some(weight) = span.weigth {
                        attrs = attrs.weight(weight)
                    }
                    attrs = attrs.metadata(i);
                    if let Some(metadata) = span.metadata.clone() {
                        spans_meta.push(metadata);
                    } else {
                        spans_meta.push(TextSpanMetadata { link: None });
                    };

                    let mut temp = String::new();

                    for ch in span.text.chars() {
                        if ch == '\n' {
                            if !temp.is_empty() {
                                lines
                                    .last_mut()
                                    .unwrap()
                                    .push((temp.clone(), AttrsOwned::new(attrs)));
                                temp.clear();
                            }
                            lines.push(Vec::new());
                        } else {
                            temp.push(ch);
                        }
                    }

                    if !temp.is_empty() {
                        lines
                            .last_mut()
                            .unwrap()
                            .push((temp, AttrsOwned::new(attrs)));
                    }
                }
                Ok(BevyMarkdownLines {
                    lines,
                    span_metadata: spans_meta,
                })
            }
        }
        Err(e) => Err(vec![BevyMarkdownError::Parsing {
            info: e.to_string(),
        }]),
    }
}

#[cfg(test)]
mod tests {
    use cosmic_text::Attrs;

    use crate::*;

    fn test_bevymarkdown(input: String, test_name: String) {
        let markdown_theme = BevyMarkdownTheme {
            code_theme: "Solarized (light)".to_string(),
            code_default_lang: "rs".to_string(),
            link: Color::rgb(10, 10, 10),
            inline_code: Color::rgb(100, 100, 100),
        };

        insta::assert_debug_snapshot!(
            test_name.clone(),
            generate_markdown_lines(BevyMarkdown {
                markdown_theme,
                text: input.clone(),
                attrs: AttrsOwned::new(Attrs::new()),
            })
        );
    }

    #[test]
    pub fn test_render_text_complicated() {
        let input = "**bold1** normal text
**Italic* and then italic again*
[Inner links **can be styled*too***](https://google.com)
    ";
        test_bevymarkdown(
            input.to_string(),
            "test_render_text_style_complicated".to_string(),
        );
    }

    #[test]
    pub fn test_render_text_with_header() {
        let input = "# Header 1
## Header 2
### Header 3
#### Some header 4 *as well* italicised
##### another header [*redirecting to google*](https://google.com)
";
        test_bevymarkdown(
            input.to_string(),
            "test_render_text_style_header".to_string(),
        );
    }

    #[test]
    pub fn test_render_text_style() {
        let input = "**bold1**  
__bold2__
*italic1*
_italic2_
Hello world
[link](https://example.com)
    ";
        test_bevymarkdown(input.to_string(), "test_render_text_style".to_string());
    }

    #[test]
    pub fn test_render_code() {
        let input = "My rust code:

```rs
fn main() {
    println!(\"Hello world\");
}
```
    "
        .to_string();
        test_bevymarkdown(input.to_string(), "test_render_code".to_string());
    }

    #[test]
    pub fn test_render_break() {
        let input = "Hello world  
hello world
    "
        .to_string();
        test_bevymarkdown(input.to_string(), "test_render_break".to_string());
    }

    #[test]
    pub fn test_render_break_after_link() {
        let input = "(link)[https://example.com]   

hello world
    "
        .to_string();
        test_bevymarkdown(
            input.to_string(),
            "test_render_break_after_link".to_string(),
        );
    }

    #[test]
    pub fn test_render_unordered_list() {
        let input = "
- Import a HTML file and watch it magically convert to Markdown
- Drag and drop images (requires your Dropbox account be linked)
- Import and save files from GitHub, Dropbox, Google Drive and One Drive
- Drag and drop markdown and HTML files into Dillinger
- Export documents as Markdown, HTML and PDF
"
        .to_string();
        test_bevymarkdown(input, "test_render_unordered_list".to_string())
    }

    #[test]
    pub fn test_render_ordered_list() {
        let input = "
1. Import a HTML file and watch it magically convert to Markdown
2. Drag and drop images (requires your Dropbox account be linked)
3. Import and save files from GitHub, Dropbox, Google Drive and One Drive
"
        .to_string();
        test_bevymarkdown(input, "test_render_ordered_list".to_string())
    }

    #[test]
    pub fn test_render_nested_unordered_list() {
        let input = "
- Import a HTML file and watch it magically convert to Markdown
    - Drag and drop images (requires your Dropbox account be linked)
- Import and save files from GitHub, Dropbox, Google Drive and One Drive
    - Drag and drop markdown and HTML files into Dillinger
- Export documents as Markdown, HTML and PDF
"
        .to_string();
        test_bevymarkdown(input, "test_render_nested_unordered_list".to_string())
    }

    #[test]
    pub fn test_render_nested_ordered_list() {
        let input = "
1. Import a HTML file and watch it magically convert to Markdown
2. Drag and drop images (requires your Dropbox account be linked)
    1. Import and save files from GitHub, Dropbox, Google Drive and One Drive
    2. Drag and drop images (requires your Dropbox account be linked)
3. Drag and drop images (requires your Dropbox account be linked)
"
        .to_string();
        test_bevymarkdown(input, "test_render_nested_ordered_list".to_string())
    }
}


================================================
FILE: crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_break.snap
================================================
---
source: crates/bevy_markdown/src/lib.rs
expression: "generate_markdown_lines(BevyMarkdown {\n        markdown_theme,\n        text: input.clone(),\n        attrs: AttrsOwned::new(Attrs::new()),\n    })"
---
Ok(
    BevyMarkdownLines {
        lines: [
            [
                (
                    "Hello world",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 0,
                    },
                ),
            ],
            [
                (
                    "hello world",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 2,
                    },
                ),
            ],
        ],
        span_metadata: [
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
        ],
    },
)


================================================
FILE: crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_break_after_link.snap
================================================
---
source: crates/bevy_markdown/src/lib.rs
expression: "generate_markdown_lines(BevyMarkdown {\n        markdown_theme,\n        text: input.clone(),\n        attrs: AttrsOwned::new(Attrs::new()),\n    })"
---
Ok(
    BevyMarkdownLines {
        lines: [
            [
                (
                    "(link)[",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 0,
                    },
                ),
                (
                    "https://example.com",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4278848010,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 1,
                    },
                ),
                (
                    "]",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 2,
                    },
                ),
                (
                    "hello world",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 3,
                    },
                ),
            ],
        ],
        span_metadata: [
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: Some(
                    "https://example.com",
                ),
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
        ],
    },
)


================================================
FILE: crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_code.snap
================================================
---
source: crates/bevy_markdown/src/lib.rs
expression: "generate_markdown_lines(BevyMarkdown {\n        markdown_theme,\n        text: input.clone(),\n        attrs: AttrsOwned::new(Attrs::new()),\n    })"
---
Ok(
    BevyMarkdownLines {
        lines: [
            [
                (
                    "My rust code:",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 0,
                    },
                ),
            ],
            [],
            [
                (
                    "fn",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4280716242,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 2,
                    },
                ),
                (
                    " ",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4284840835,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 3,
                    },
                ),
                (
                    "main",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4290087168,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 4,
                    },
                ),
                (
                    "(",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4284840835,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 5,
                    },
                ),
                (
                    ")",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4284840835,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 6,
                    },
                ),
                (
                    " ",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4284840835,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 7,
                    },
                ),
                (
                    "{",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4284840835,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 8,
                    },
                ),
            ],
            [
                (
                    "    ",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4284840835,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 10,
                    },
                ),
                (
                    "println!",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4286945536,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 11,
                    },
                ),
                (
                    "(",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4284840835,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 12,
                    },
                ),
                (
                    "\"",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4286813334,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 13,
                    },
                ),
                (
                    "Hello world",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4280983960,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 14,
                    },
                ),
                (
                    "\"",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4286813334,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 15,
                    },
                ),
                (
                    ")",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4284840835,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 16,
                    },
                ),
                (
                    ";",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4284840835,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 17,
                    },
                ),
            ],
            [
                (
                    "}",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4284840835,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            600,
                        ),
                        metadata: 19,
                    },
                ),
            ],
            [],
        ],
        span_metadata: [
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
        ],
    },
)


================================================
FILE: crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_nested_ordered_list.snap
================================================
---
source: crates/bevy_markdown/src/lib.rs
expression: "generate_markdown_lines(BevyMarkdown {\n        markdown_theme,\n        text: input.clone(),\n        attrs: AttrsOwned::new(Attrs::new()),\n    })"
---
Ok(
    BevyMarkdownLines {
        lines: [
            [],
            [
                (
                    " 1. ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 1,
                    },
                ),
                (
                    "Import a HTML file and watch it magically convert to Markdown",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 2,
                    },
                ),
            ],
            [
                (
                    " 2. ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 4,
                    },
                ),
                (
                    "Drag and drop images (requires your Dropbox account be linked)",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 5,
                    },
                ),
            ],
            [
                (
                    "    ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 7,
                    },
                ),
                (
                    " 1. ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 8,
                    },
                ),
                (
                    "Import and save files from GitHub, Dropbox, Google Drive and One Drive",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 9,
                    },
                ),
            ],
            [
                (
                    "    ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 11,
                    },
                ),
                (
                    " 2. ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 12,
                    },
                ),
                (
                    "Drag and drop images (requires your Dropbox account be linked)",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 13,
                    },
                ),
            ],
            [],
            [
                (
                    " 3. ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 16,
                    },
                ),
                (
                    "Drag and drop images (requires your Dropbox account be linked)",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 17,
                    },
                ),
            ],
            [],
        ],
        span_metadata: [
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
        ],
    },
)


================================================
FILE: crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_nested_unordered_list.snap
================================================
---
source: crates/bevy_markdown/src/lib.rs
expression: "generate_markdown_lines(BevyMarkdown {\n        markdown_theme,\n        text: input.clone(),\n        attrs: AttrsOwned::new(Attrs::new()),\n    })"
---
Ok(
    BevyMarkdownLines {
        lines: [
            [],
            [
                (
                    " • ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 1,
                    },
                ),
                (
                    "Import a HTML file and watch it magically convert to Markdown",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 2,
                    },
                ),
            ],
            [
                (
                    "    ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 4,
                    },
                ),
                (
                    " ◦ ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 5,
                    },
                ),
                (
                    "Drag and drop images (requires your Dropbox account be linked)",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 6,
                    },
                ),
            ],
            [],
            [
                (
                    " • ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 9,
                    },
                ),
                (
                    "Import and save files from GitHub, Dropbox, Google Drive and One Drive",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 10,
                    },
                ),
            ],
            [
                (
                    "    ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 12,
                    },
                ),
                (
                    " ◦ ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 13,
                    },
                ),
                (
                    "Drag and drop markdown and HTML files into Dillinger",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 14,
                    },
                ),
            ],
            [],
            [
                (
                    " • ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 17,
                    },
                ),
                (
                    "Export documents as Markdown, HTML and PDF",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 18,
                    },
                ),
            ],
            [],
        ],
        span_metadata: [
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
        ],
    },
)


================================================
FILE: crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_ordered_list.snap
================================================
---
source: crates/bevy_markdown/src/lib.rs
expression: "generate_markdown_lines(BevyMarkdown {\n        markdown_theme,\n        text: input.clone(),\n        attrs: AttrsOwned::new(Attrs::new()),\n    })"
---
Ok(
    BevyMarkdownLines {
        lines: [
            [],
            [
                (
                    " 1. ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 1,
                    },
                ),
                (
                    "Import a HTML file and watch it magically convert to Markdown",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 2,
                    },
                ),
            ],
            [
                (
                    " 2. ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 4,
                    },
                ),
                (
                    "Drag and drop images (requires your Dropbox account be linked)",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 5,
                    },
                ),
            ],
            [
                (
                    " 3. ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 7,
                    },
                ),
                (
                    "Import and save files from GitHub, Dropbox, Google Drive and One Drive",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 8,
                    },
                ),
            ],
            [],
        ],
        span_metadata: [
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
        ],
    },
)


================================================
FILE: crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_text_style.snap
================================================
---
source: crates/bevy_markdown/src/lib.rs
expression: "generate_markdown_lines(BevyMarkdown {\n        markdown_theme,\n        text: input.clone(),\n        attrs: AttrsOwned::new(Attrs::new()),\n    })"
---
Ok(
    BevyMarkdownLines {
        lines: [
            [
                (
                    "bold1",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            700,
                        ),
                        metadata: 0,
                    },
                ),
            ],
            [
                (
                    "bold2",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            700,
                        ),
                        metadata: 2,
                    },
                ),
            ],
            [
                (
                    "italic1",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Italic,
                        weight: Weight(
                            400,
                        ),
                        metadata: 4,
                    },
                ),
            ],
            [
                (
                    "italic2",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Italic,
                        weight: Weight(
                            400,
                        ),
                        metadata: 6,
                    },
                ),
            ],
            [
                (
                    "Hello world",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 7,
                    },
                ),
            ],
            [
                (
                    "link",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4278848010,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 8,
                    },
                ),
            ],
        ],
        span_metadata: [
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: Some(
                    "https://example.com",
                ),
            },
        ],
    },
)


================================================
FILE: crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_text_style_complicated.snap
================================================
---
source: crates/bevy_markdown/src/lib.rs
expression: "generate_markdown_lines(BevyMarkdown {\n        markdown_theme,\n        text: input.clone(),\n        attrs: AttrsOwned::new(Attrs::new()),\n    })"
---
Ok(
    BevyMarkdownLines {
        lines: [
            [
                (
                    "bold1",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            700,
                        ),
                        metadata: 0,
                    },
                ),
                (
                    " normal text",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 1,
                    },
                ),
            ],
            [
                (
                    "Italic",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Italic,
                        weight: Weight(
                            400,
                        ),
                        metadata: 2,
                    },
                ),
                (
                    " and then italic again",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Italic,
                        weight: Weight(
                            400,
                        ),
                        metadata: 3,
                    },
                ),
            ],
            [
                (
                    "Inner links ",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4278848010,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 5,
                    },
                ),
                (
                    "can be styled",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4278848010,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            700,
                        ),
                        metadata: 6,
                    },
                ),
                (
                    "too",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4278848010,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Italic,
                        weight: Weight(
                            700,
                        ),
                        metadata: 7,
                    },
                ),
            ],
        ],
        span_metadata: [
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: Some(
                    "https://google.com",
                ),
            },
            TextSpanMetadata {
                link: Some(
                    "https://google.com",
                ),
            },
            TextSpanMetadata {
                link: Some(
                    "https://google.com",
                ),
            },
        ],
    },
)


================================================
FILE: crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_text_style_header.snap
================================================
---
source: crates/bevy_markdown/src/lib.rs
expression: "generate_markdown_lines(BevyMarkdown {\n        markdown_theme,\n        text: input.clone(),\n        attrs: AttrsOwned::new(Attrs::new()),\n    })"
---
Ok(
    BevyMarkdownLines {
        lines: [
            [],
            [
                (
                    "Header 1",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            700,
                        ),
                        metadata: 1,
                    },
                ),
            ],
            [],
            [
                (
                    "Header 2",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            700,
                        ),
                        metadata: 4,
                    },
                ),
            ],
            [],
            [
                (
                    "Header 3",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            700,
                        ),
                        metadata: 7,
                    },
                ),
            ],
            [],
            [
                (
                    "Some header 4 ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            700,
                        ),
                        metadata: 10,
                    },
                ),
                (
                    "as well",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Italic,
                        weight: Weight(
                            700,
                        ),
                        metadata: 11,
                    },
                ),
                (
                    " italicised",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            700,
                        ),
                        metadata: 12,
                    },
                ),
            ],
            [],
            [
                (
                    "another header ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            700,
                        ),
                        metadata: 15,
                    },
                ),
                (
                    "redirecting to google",
                    AttrsOwned {
                        color_opt: Some(
                            Color(
                                4278848010,
                            ),
                        ),
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Italic,
                        weight: Weight(
                            700,
                        ),
                        metadata: 16,
                    },
                ),
            ],
            [],
        ],
        span_metadata: [
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: Some(
                    "https://google.com",
                ),
            },
            TextSpanMetadata {
                link: None,
            },
        ],
    },
)


================================================
FILE: crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_unordered_list.snap
================================================
---
source: crates/bevy_markdown/src/lib.rs
expression: "generate_markdown_lines(BevyMarkdown {\n        markdown_theme,\n        text: input.clone(),\n        attrs: AttrsOwned::new(Attrs::new()),\n    })"
---
Ok(
    BevyMarkdownLines {
        lines: [
            [],
            [
                (
                    " • ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 1,
                    },
                ),
                (
                    "Import a HTML file and watch it magically convert to Markdown",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 2,
                    },
                ),
            ],
            [
                (
                    " • ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 4,
                    },
                ),
                (
                    "Drag and drop images (requires your Dropbox account be linked)",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 5,
                    },
                ),
            ],
            [
                (
                    " • ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 7,
                    },
                ),
                (
                    "Import and save files from GitHub, Dropbox, Google Drive and One Drive",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 8,
                    },
                ),
            ],
            [
                (
                    " • ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 10,
                    },
                ),
                (
                    "Drag and drop markdown and HTML files into Dillinger",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 11,
                    },
                ),
            ],
            [
                (
                    " • ",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 13,
                    },
                ),
                (
                    "Export documents as Markdown, HTML and PDF",
                    AttrsOwned {
                        color_opt: None,
                        family_owned: SansSerif,
                        stretch: Normal,
                        style: Normal,
                        weight: Weight(
                            400,
                        ),
                        metadata: 14,
                    },
                ),
            ],
            [],
        ],
        span_metadata: [
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
            TextSpanMetadata {
                link: None,
            },
        ],
    },
)


================================================
FILE: docs/architecture.md
================================================
**ATTENTION**

_This doc may be outdated_

# PreStartup

_Runs once at the start of the app_

## Systems

- [VeloPlugin/setup_velo_theme](#setup_velo_theme)

# Startup

_Runs once at the start of the app_

## Systems

- (NATIVE-ONLY): [UiPlugin/read_native_config](#read_native_config)
- (NATIVE-ONLY): [UiPlugin/init_search_index](#init_search_index)
- (WASM-ONLY): [UiPlugin/load_from_url](#load_from_url)
- [UiPlugin/init_layout](#init_layout)
- [VeloPlugin/setup_camera](#setup_camera)
- [VeloPlugin/setup_background](#setup_background)

## Ordering

- (NATIVE-ONLY): [UiPlugin/read_native_config](#read_native_config) --> [UiPlugin/init_layout](#init_layout)
- (NATIVE-ONLY): [UiPlugin/init_search_index](#init_search_index) --> [UiPlugin/init_layout](#init_layout)
- (WASM-ONLY): [UiPlugin/load_from_url](#load_from_url) --> [UiPlugin/init_layout](#init_layout)

# PreUpdate

## Systems

- [ArrowPlugin/create_arrow_start](#create_arrow_start)
- [ArrowPlugin/create_arrow_end](#create_arrow_end)
- [ArrowPlugin/redraw_arrows](#redraw_arrows)

# Update

## Systems

- [PreStartup](#prestartup)
  - [Systems](#systems)
- [Startup](#startup)
  - [Systems](#systems-1)
  - [Ordering](#ordering)
- [PreUpdate](#preupdate)
  - [Systems](#systems-2)
- [Update](#update)
  - [Systems](#systems-3)
  - [Ordering](#ordering-1)
- [PostUpdate](#postupdate)
  - [Systems](#systems-4)
- [All systems](#all-systems)
  - [`active_editor_changed`](#active_editor_changed)
  - [`add_tab_handler`](#add_tab_handler)
  - [`button_generic_handler`](#button_generic_handler)
  - [`cancel_modal`](#cancel_modal)
  - [`canvas_click`](#canvas_click)
  - [`change_arrow_type`](#change_arrow_type)
  - [`change_color_pallete`](#change_color_pallete)
  - [`change_text_pos`](#change_text_pos)
  - [`change_theme`](#change_theme)
  - [`clickable_links`](#clickable_links)
  - [`confirm_modal`](#confirm_modal)
  - [`cosmic_edit_bevy_events`](#cosmic_edit_bevy_events)
  - [`cosmic_edit_redraw_buffer`](#cosmic_edit_redraw_buffer)
  - [`cosmic_edit_redraw_buffer_ui`](#cosmic_edit_redraw_buffer_ui)
  - [`cosmic_edit_set_redraw`](#cosmic_edit_set_redraw)
  - [`create_arrow_end`](#create_arrow_end)
  - [`create_arrow_start`](#create_arrow_start)
  - [`create_new_node`](#create_new_node)
  - [`delete_doc_handler`](#delete_doc_handler)
  - [`delete_tab_handler`](#delete_tab_handler)
  - [`doc_list_del_button_update`](#doc_list_del_button_update)
  - [`doc_list_ui_changed`](#doc_list_ui_changed)
  - [`entity_to_edit_changed`](#entity_to_edit_changed)
  - [`export_to_file`](#export_to_file)
  - [`import_from_file`](#import_from_file)
  - [`import_from_url`](#import_from_url)
  - [`init_layout`](#init_layout)
  - [`init_search_index`](#init_search_index)
  - [`interactive_sprite`](#interactive_sprite)
  - [`keyboard_input_system`](#keyboard_input_system)
  - [`list_item_click`](#list_item_click)
  - [`load_doc`](#load_doc)
  - [`load_doc_handler`](#load_doc_handler)
  - [`load_from_url`](#load_from_url)
  - [`load_tab`](#load_tab)
  - [`mouse_scroll_list`](#mouse_scroll_list)
  - [`new_doc_handler`](#new_doc_handler)
  - [`on_scale_factor_change`](#on_scale_factor_change)
  - [`particles_effect`](#particles_effect)
  - [`read_native_config`](#read_native_config)
  - [`rec_button_handlers`](#rec_button_handlers)
  - [`redraw_arrows`](#redraw_arrows)
  - [`remove_load_doc_request`](#remove_load_doc_request)
  - [`remove_load_tab_request`](#remove_load_tab_request)
  - [`remove_save_doc_request`](#remove_save_doc_request)
  - [`remove_save_tab_request`](#remove_save_tab_request)
  - [`rename_doc_handler`](#rename_doc_handler)
  - [`rename_tab_handler`](#rename_tab_handler)
  - [`resize_entity_end`](#resize_entity_end)
  - [`resize_entity_run`](#resize_entity_run)
  - [`resize_entity_start`](#resize_entity_start)
  - [`resize_notificator`](#resize_notificator)
  - [`save_doc`](#save_doc)
  - [`save_doc_handler`](#save_doc_handler)
  - [`save_tab`](#save_tab)
  - [`save_to_store`](#save_to_store)
  - [`search_box_click`](#search_box_click)
  - [`search_box_text_changed`](#search_box_text_changed)
  - [`select_tab_handler`](#select_tab_handler)
  - [`set_focused_entity`](#set_focused_entity)
  - [`set_window_property`](#set_window_property)
  - [`setup_background`](#setup_background)
  - [`setup_camera`](#setup_camera)
  - [`setup_velo_theme`](#setup_velo_theme)
  - [`shared_doc_handler`](#shared_doc_handler)
  - [`should_load_doc`](#should_load_doc)
  - [`should_load_tab`](#should_load_tab)
  - [`should_save_doc`](#should_save_doc)
  - [`should_save_tab`](#should_save_tab)
  - [`update_rectangle_position`](#update_rectangle_position)

## Ordering

- [CosmicEditPlugin/cosmic_edit_redraw_buffer_ui](#cosmic_edit_redraw_buffer_ui) --> [CosmicEditPlugin/cosmic_edit_set_redraw](#cosmic_edit_set_redraw)
- [CosmicEditPlugin/cosmic_edit_redraw_buffer_ui](#cosmic_edit_redraw_buffer_ui) --> [CosmicEditPlugin/on_scale_factor_change](#on_scale_factor_change)
- [CosmicEditPlugin/cosmic_edit_redraw_buffer](#cosmic_edit_redraw_buffer) --> [CosmicEditPlugin/on_scale_factor_change](#on_scale_factor_change)
- [UiPlugin/save_doc](#save_doc) --> [UiPlugin/remove_save_doc_request](#remove_save_doc_request)
- [UiPlugin/save_doc](#save_doc) --> [UiPlugin/remove_save_tab_request](#remove_save_tab_request)
- [UiPlugin/save_doc](#save_doc) --> [UiPlugin/remove_load_doc_request](#remove_load_doc_request)
- [UiPlugin/save_doc](#save_doc) --> [UiPlugin/remove_load_tab_request](#remove_load_tab_request)
- [UiPlugin/keyboard_input_system](#keyboard_input_system) --> [CosmicEditPlugin/cosmic_edit_bevy_events](#cosmic_edit_bevy_events)
- [UiPlugin/doc_list_del_button_update](#doc_list_del_button_update) --> [UiPlugin/doc_list_ui_changed](#doc_list_ui_changed)
- [UiPlugin/save_tab](#save_tab) --> [UiPlugin/save_to_store](#save_to_store)
- [UiPlugin/interactive_sprite](#interactive_sprite) --> [UiPlugin/canvas_click](#canvas_click)
- [UiPlugin/set_focused_entity](#set_focused_entity) --> [UiPlugin/clickable_links](#clickable_links)
- [UiPlugin/entity_to_edit_changed](#entity_to_edit_changed) --> [UiPlugin/save_doc](#save_doc)
- [UiPlugin/entity_to_edit_changed](#entity_to_edit_changed) --> [UiPlugin/save_doc](#save_doc)
- [UiPlugin/entity_to_edit_changed](#entity_to_edit_changed) --> [UiPlugin/load_tab](#load_tab)
- [UiPlugin/entity_to_edit_changed](#entity_to_edit_changed) --> [UiPlugin/load_doc](#load_doc)
- [UiPlugin/entity_to_edit_changed](#entity_to_edit_changed) --> [UiPlugin/rec_button_handlers](#rec_button_handlers)
- [UiPlugin/entity_to_edit_changed](#entity_to_edit_changed) --> [UiPlugin/create_new_node](#create_new_node)

# PostUpdate

## Systems

- [UiPlugin/resize_notificator](#resize_notificator)

# All systems

## <span id="active_editor_changed">`active_editor_changed`</span>

```rs
pub fn active_editor_changed(
    active_editor: ResMut<ActiveEditor>,
    mut previous_editor: Local<Option<Entity>>,
    mut cosmic_edit_query: Query<&mut CosmicEdit, With<CosmicEdit>>,
    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
) {}
```

## <span id="add_tab_handler">`add_tab_handler`</span>

```rs
pub fn add_tab_handler(
    mut commands: Commands,
    mut interaction_query: Query<&Interaction, (Changed<Interaction>, With<AddTab>)>,
    mut app_state: ResMut<AppState>,
) {}
```

## <span id="button_generic_handler">`button_generic_handler`</span>

```rs
pub fn button_generic_handler(
    _commands: Commands,
    mut generic_button_query: Query<
        (&Interaction, &mut BackgroundColor, Entity),
        (Changed<Interaction>, With<GenericButton>),
    >,
    mut windows: Query<&mut Window, With<PrimaryWindow>>,
    mut tooltips_query: Query<(&mut Style, &Parent), With<Tooltip>>,
) {}
```

## <span id="cancel_modal">`cancel_modal`</span>

```rs
pub fn cancel_modal(
    mut commands: Commands,
    mut interaction_query: Query<
        (&Interaction, &ModalCancel),
        (Changed<Interaction>, With<ModalCancel>),
    >,
    mut state: ResMut<UiState>,
    query: Query<(Entity, &ModalTop), With<ModalTop>>,
) {}
```

## <span id="canvas_click">`canvas_click`</span>

```rs
pub fn canvas_click(
    interaction_query: Query<&Interaction, (Changed<Interaction>, With<MainPanel>)>,
    mut ui_state: ResMut<UiState>,
    mut windows: Query<&mut Window, With<PrimaryWindow>>,
    mut node_interaction_events: EventReader<NodeInteraction>,
    raw_text: Query<With<RawText>>,
) {}
```

## <span id="change_arrow_type">`change_arrow_type`</span>

```rs
pub fn change_arrow_type(
    mut interaction_query: Query<
        (&Interaction, &ArrowMode),
        (Changed<Interaction>, With<ArrowMode>),
    >,
    mut state: ResMut<UiState>,
) {}
```

## <span id="change_color_pallete">`change_color_pallete`</span>

```rs
pub fn change_color_pallete(
    mut interaction_query: Query<
        (&Interaction, &ChangeColor),
        (Changed<Interaction>, With<ChangeColor>),
    >,
    mut velo_border: Query<(&mut Fill, &VeloBorder), With<VeloBorder>>,
    ui_state: Res<UiState>,
) {}
```

## <span id="change_text_pos">`change_text_pos`</span>

```rs
pub fn change_text_pos(
    mut interaction_query: Query<
        (&Interaction, &TextPosMode),
        (Changed<Interaction>, With<TextPosMode>),
    >,
    state: Res<UiState>,
    mut raw_text_node_query: Query<(&RawText, &mut CosmicEdit), With<RawText>>,
) {}
```

## <span id="change_theme">`change_theme`</span>

```rs
pub fn change_theme(
    mut pkv: ResMut<PkvStore>,
    mut change_theme_button: Query<&Interaction, (Changed<Interaction>, With<ChangeTheme>)>,
    mut change_theme_label: Query<&mut Text, (With<ChangeTheme>, Without<Tooltip>)>,
    mut tooltip_label: Query<&mut Text, (With<Tooltip>, Without<ChangeTheme>)>,
) {}
```

## <span id="clickable_links">`clickable_links`</span>

```rs
pub fn clickable_links(
    mut windows: Query<&mut Window, With<PrimaryWindow>>,
    mut markdown_text_query: Query<
        (&GlobalTransform, &mut CosmicEdit, &BevyMarkdownView),
        With<BevyMarkdownView>,
    >,
    mut node_interaction_events: EventReader<NodeInteraction>,
    ui_state: Res<UiState>,
) {}
```

## <span id="confirm_modal">`confirm_modal`</span>

```rs
pub fn confirm_modal(
    mut commands: Commands,
    mut interaction_query: Query<
        (&Interaction, &ModalConfirm),
        (Changed<Interaction>, With<ModalConfirm>),
    >,
    mut app_state: ResMut<AppState>,
    mut ui_state: ResMut<UiState>,
    query_top: Query<(Entity, &ModalTop), With<ModalTop>>,
    mut tab_query_container: Query<(Entity, &TabContainer), With<TabContainer>>,
    mut pkv: ResMut<PkvStore>,
    input: Res<Input<KeyCode>>,
    mut query_path: Query<(&CosmicEdit, &EditableText), With<EditableText>>,
    comm_channels: Res<CommChannels>,
) {}
```

## <span id="cosmic_edit_bevy_events">`cosmic_edit_bevy_events`</span>

```rs
pub fn cosmic_edit_bevy_events(
    windows: Query<&Window, With<PrimaryWindow>>,
    active_editor: Res<ActiveEditor>,
    keys: Res<Input<KeyCode>>,
    mut char_evr: EventReader<ReceivedCharacter>,
    buttons: Res<Input<MouseButton>>,
    mut cosmic_edit_query: Query<(&mut CosmicEdit, &GlobalTransform, Entity), With<CosmicEdit>>,
    mut is_deleting: Local<bool>,
    mut font_system_assets: ResMut<Assets<CosmicFont>>,
    mut scroll_evr: EventReader<MouseWheel>,
) {}
```

## <span id="cosmic_edit_redraw_buffer">`cosmic_edit_redraw_buffer`</span>

```rs
fn cosmic_edit_redraw_buffer(
    windows: Query<&Window, With<PrimaryWindow>>,
    mut images: ResMut<Assets<Image>>,
    mut swash_cache_state: ResMut<SwashCacheState>,
    mut cosmic_edit_query: Query<
        (&mut CosmicEdit, &mut Handle<Image>, &mut Visibility),
        With<CosmicEdit>,
    >,
    mut font_system_assets: ResMut<Assets<CosmicFont>>,
) {}
```

## <span id="cosmic_edit_redraw_buffer_ui">`cosmic_edit_redraw_buffer_ui`</span>

```rs
fn cosmic_edit_redraw_buffer_ui(
    windows: Query<&Window, With<PrimaryWindow>>,
    mut images: ResMut<Assets<Image>>,
    mut swash_cache_state: ResMut<SwashCacheState>,
    mut cosmic_edit_query: Query<
        (&mut CosmicEdit, &mut UiImage, &Node, &mut Visibility),
        With<CosmicEdit>,
    >,
    mut font_system_assets: ResMut<Assets<CosmicFont>>,
) {}
```

## <span id="cosmic_edit_set_redraw">`cosmic_edit_set_redraw`</span>

```rs
fn cosmic_edit_set_redraw(mut cosmic_edit_query: Query<&mut CosmicEdit, Added<CosmicEdit>>) {}
```

## <span id="create_arrow_end">`create_arrow_end`</span>

```rs
pub fn create_arrow_end(
    mut commands: Commands,
    mut events: EventReader<CreateArrow>,
    arrow_markers: Query<(&ArrowConnect, &GlobalTransform), With<ArrowConnect>>,
    theme: Res<Theme>,
) {}
```

## <span id="create_arrow_start">`create_arrow_start`</span>

```rs
pub fn create_arrow_start(
    mut node_interaction_events: EventReader<NodeInteraction>,
    arrow_connect_query: Query<&ArrowConnect, With<ArrowConnect>>,
    mut state: ResMut<UiState>,
    mut create_arrow: EventWriter<CreateArrow>,
    mut windows: Query<&mut Window, With<PrimaryWindow>>,
) {}
```

## <span id="create_new_node">`create_new_node`</span>

```rs
pub fn create_new_node(
    mut commands: Commands,
    mut events: EventReader<AddRect>,
    mut ui_state: ResMut<UiState>,
    app_state: Res<AppState>,
    mut windows: Query<&mut Window, With<PrimaryWindow>>,
    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
    font_system_state: ResMut<FontSystemState>,
    theme: Res<Theme>,
    mut z_index_local: Local<f32>,
    mut shaders: ResMut<Assets<Shader>>,
) {}
```

## <span id="delete_doc_handler">`delete_doc_handler`</span>

```rs
pub fn delete_doc_handler(
    mut commands: Commands,
    mut delete_doc_query: Query<&Interaction, (Changed<Interaction>, With<DeleteDoc>)>,
    mut ui_state: ResMut<UiState>,
    mut app_state: ResMut<AppState>,
    main_panel_query: Query<Entity, With<MainPanel>>,
    windows: Query<&Window, With<PrimaryWindow>>,
    pkv: Res<PkvStore>,
    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
    font_system_state: ResMut<FontSystemState>,
    theme: Res<Theme>,
) {}
```

## <span id="delete_tab_handler">`delete_tab_handler`</span>

```rs
pub fn delete_tab_handler(
    mut commands: Commands,
    mut interaction_query: Query<&Interaction, (Changed<Interaction>, With<DeleteTab>)>,
    mut app_state: ResMut<AppState>,
    mut ui_state: ResMut<UiState>,
    main_panel_query: Query<Entity, With<MainPanel>>,
    windows: Query<&Window, With<PrimaryWindow>>,
    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
    font_system_state: ResMut<FontSystemState>,
    theme: Res<Theme>,
) {}
```

## <span id="doc_list_del_button_update">`doc_list_del_button_update`</span>

```rs
pub fn doc_list_del_button_update(
    app_state: Res<AppState>,
    mut delete_doc: Query<(&mut Visibility, &DeleteDoc), With<DeleteDoc>>,
    mut event_reader: EventReader<UpdateDeleteDocBtn>,
) {}
```

## <span id="doc_list_ui_changed">`doc_list_ui_changed`</span>

```rs
pub fn doc_list_ui_changed(
    mut commands: Commands,
    app_state: Res<AppState>,
    mut last_doc_list: Local<HashSet<ReflectableUuid>>,
    mut doc_list_query: Query<Entity, With<DocList>>,
    asset_server: Res<AssetServer>,
    pkv: Res<PkvStore>,
    mut query_container: Query<Entity, With<DocListItemContainer>>,
    mut event_writer: EventWriter<UpdateDeleteDocBtn>,
    theme: Res<Theme>,
    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
    font_system_state: ResMut<FontSystemState>,
    windows: Query<&mut Window, With<PrimaryWindow>>,
) {}
```

## <span id="entity_to_edit_changed">`entity_to_edit_changed`</span>

```rs
pub fn entity_to_edit_changed(
    ui_state: Res<UiState>,
    app_state: Res<AppState>,
    theme: Res<Theme>,
    mut last_entity_to_edit: Local<Option<ReflectableUuid>>,
    mut velo_border: Query<(&mut Stroke, &VeloBorder), With<VeloBorder>>,
    mut raw_text_node_query: Query<(Entity, &mut RawText, &mut CosmicEdit), With<RawText>>,
    mut commands: Commands,
    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
) {}
```

## <span id="export_to_file">`export_to_file`</span>

```rs
pub fn export_to_file(
    mut commands: Commands,
    mut query: Query<&Interaction, (Changed<Interaction>, With<ExportToFile>)>,
    mut ui_state: ResMut<UiState>,
    main_panel_query: Query<Entity, With<MainPanel>>,
    windows: Query<&Window, With<PrimaryWindow>>,
    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
    font_system_state: ResMut<FontSystemState>,
    theme: Res<Theme>,
) {}
```

## <span id="import_from_file">`import_from_file`</span>

```rs
pub fn import_from_file(
    mut commands: Commands,
    mut query: Query<&Interaction, (Changed<Interaction>, With<ImportFromFile>)>,
    mut ui_state: ResMut<UiState>,
    main_panel_query: Query<Entity, With<MainPanel>>,
    windows: Query<&Window, With<PrimaryWindow>>,
    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
    font_system_state: ResMut<FontSystemState>,
    theme: Res<Theme>,
) {}
```

## <span id="import_from_url">`import_from_url`</span>

```rs
pub fn import_from_url(
    mut commands: Commands,
    mut query: Query<&Interaction, (Changed<Interaction>, With<ImportFromUrl>)>,
    mut ui_state: ResMut<UiState>,
    main_panel_query: Query<Entity, With<MainPanel>>,
    windows: Query<&Window, With<PrimaryWindow>>,
    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
    font_system_state: ResMut<FontSystemState>,
    theme: Res<Theme>,
) {}
```

## <span id="init_layout">`init_layout`</span>

```rs
pub fn init_layout(
    mut commands: Commands,
    mut app_state: ResMut<AppState>,
    asset_server: Res<AssetServer>,
    mut pkv: ResMut<PkvStore>,
    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
    windows: Query<&Window, With<PrimaryWindow>>,
    mut fonts: ResMut<Assets<Font>>,
    theme: Res<Theme>,
) {}
```

## <span id="init_search_index">`init_search_index`</span>

```rs
pub fn init_search_index(mut app_state: ResMut<AppState>) {}
```

## <span id="interactive_sprite">`interactive_sprite`</span>

```rs
pub fn interactive_sprite(
    cursor_moved_events: EventReader<CursorMoved>,
    windows: Query<&Window, With<PrimaryWindow>>,
    buttons: Res<Input<MouseButton>>,
    res_images: Res<Assets<Image>>,
    mut sprite_query: Query<
        (&Sprite, &Handle<Image>, &GlobalTransform, Entity),
        With<InteractiveNode>,
    >,
    camera_q: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
    mut node_interaction_events: EventWriter<NodeInteraction>,
    mut double_click: Local<(Duration, Option<Entity>)>,
    mut holding_state: Local<HoldingState>,
) {}
```

## <span id="keyboard_input_system">`keyboard_input_system`</span>

```rs
pub fn keyboard_input_system(
    mut commands: Commands,
    mut images: ResMut<Assets<Image>>,
    mut app_state: ResMut<AppState>,
    mut ui_state: ResMut<UiState>,
    mut events: EventWriter<AddRect>,
    input: Res<Input<KeyCode>>,
    windows: Query<&Window, With<PrimaryWindow>>,
    mut editable_text_query: Query<(&EditableText, &mut CosmicEdit), With<EditableText>>,
    theme: Res<Theme>,
) {}
```

## <span id="list_item_click">`list_item_click`</span>

```rs
pub fn list_item_click(
    mut interaction_query: Query<
        (&Interaction, &DocListItemButton),
        (Changed<Interaction>, With<DocListItemButton>),
    >,
    mut state: ResMut<AppState>,
    mut commands: Commands,
) {}
```

## <span id="load_doc">`load_doc`</span>

```rs
pub fn load_doc(
    request: Res<LoadDocRequest>,
    mut app_state: ResMut<AppState>,
    mut commands: Commands,
    mut bottom_panel: Query<Entity, With<BottomPanel>>,
    mut pkv: ResMut<PkvStore>,
    asset_server: Res<AssetServer>,
    mut tabs_query: Query<Entity, With<TabContainer>>,
    mut delete_doc: Query<(&mut Visibility, &DeleteDoc), With<DeleteDoc>>,
    theme: Res<Theme>,
    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
    font_system_state: ResMut<FontSystemState>,
    windows: Query<&Window, With<PrimaryWindow>>,
) {}
```

## <span id="load_doc_handler">`load_doc_handler`</span>

```rs
pub fn load_doc_handler(
    mut commands: Commands,
    mut app_state: ResMut<AppState>,
    comm_channels: Res<CommChannels>,
    pkv: Res<PkvStore>,
) {}
```

## <span id="load_from_url">`load_from_url`</span>

```rs
fn load_from_url(mut commands: Commands) {}
```

## <span id="load_tab">`load_tab`</span>

```rs
pub fn load_tab(
    old_nodes: Query<Entity, With<VeloNode>>,
    mut old_arrows: Query<Entity, With<ArrowMeta>>,
    request: Res<LoadTabRequest>,
    mut app_state: ResMut<AppState>,
    mut ui_state: ResMut<UiState>,
    mut commands: Commands,
    mut res_images: ResMut<Assets<Image>>,
    mut create_arrow: EventWriter<CreateArrow>,
    mut delete_tab: Query<(&mut Visibility, &DeleteTab), (With<DeleteTab>, Without<ArrowMeta>)>,
    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
    font_system_state: ResMut<FontSystemState>,
    mut windows: Query<&mut Window, With<PrimaryWindow>>,
    mut shaders: ResMut<Assets<Shader>>,
    theme: Res<Theme>,
) {}
```

## <span id="mouse_scroll_list">`mouse_scroll_list`</span>

```rs
pub fn mouse_scroll_list(
    mut mouse_wheel_events: EventReader<MouseWheel>,
    mut query_list: Query<(&mut ScrollingList, &mut Style, &Parent, &Node)>,
    query_node: Query<&Node>,
) {}
```

## <span id="new_doc_handler">`new_doc_handler`</span>

```rs
pub fn new_doc_handler(
    mut commands: Commands,
    mut new_doc_query: Query<&Interaction, (Changed<Interaction>, With<NewDoc>)>,
    mut app_state: ResMut<AppState>,
) {}
```

## <span id="on_scale_factor_change">`on_scale_factor_change`</span>

```rs
fn on_scale_factor_change(
    mut scale_factor_changed: EventReader<WindowScaleFactorChanged>,
    mut cosmic_edit_query: Query<&mut CosmicEdit, With<CosmicEdit>>,
    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
) {}
```

## <span id="particles_effect">`particles_effect`</span>

```rs
pub fn particles_effect(
    mut query: Query<&Interaction, (Changed<Interaction>, With<ParticlesEffect>)>,
    mut commands: Commands,
    mut effects: ResMut<Assets<bevy_hanabi::EffectAsset>>,
    mut effects_camera: Query<&mut Camera, With<EffectsCamera>>,
    mut effects_query: Query<(&Name, Entity)>,
    mut shadow_query: Query<&mut Transform, With<VeloShadow>>,
) {}
```

## <span id="read_native_config">`read_native_config`</span>

```rs
fn read_native_config(mut app_state: ResMut<AppState>) {}
```

## <span id="rec_button_handlers">`rec_button_handlers`</span>

```rs
pub fn rec_button_handlers(
    mut commands: Commands,
    mut events: EventWriter<AddRect>,
    mut interaction_query: Query<
        (&Interaction, &ButtonAction),
        (Changed<Interaction>, With<ButtonAction>),
    >,
    mut raw_text_query: Query<(&mut CosmicEdit, &RawText, &Parent), With<RawText>>,
    border_query: Query<&Parent, With<VeloBorder>>,
    mut velo_node_query: Query<(Entity, &VeloNode, &mut Transform), With<VeloNode>>,
    mut arrows: Query<(Entity, &ArrowMeta, &mut Visibility), (With<ArrowMeta>, Without<Tooltip>)>,
    mut state: ResMut<UiState>,
    mut app_state: ResMut<AppState>,
    theme: Res<Theme>,
) {}
```

## <span id="redraw_arrows">`redraw_arrows`</span>

```rs
pub fn redraw_arrows(
    mut redraw_arrow: EventReader<RedrawArrow>,
    mut arrow_query: Query<(&mut Path, &mut ArrowMeta), With<ArrowMeta>>,
    arrow_markers: Query<(&ArrowConnect, &GlobalTransform), With<ArrowConnect>>,
) {}
```

## <span id="remove_load_doc_request">`remove_load_doc_request`</span>

```rs
pub fn remove_load_doc_request(world: &mut World) {}
```

## <span id="remove_load_tab_request">`remove_load_tab_request`</span>

```rs
pub fn remove_load_tab_request(world: &mut World) {}
```

## <span id="remove_save_doc_request">`remove_save_doc_request`</span>

```rs
pub fn remove_save_doc_request(world: &mut World) {}
```

## <span id="remove_save_tab_request">`remove_save_tab_request`</span>

```rs
pub fn remove_save_tab_request(world: &mut World) {}
```

## <span id="rename_doc_handler">`rename_doc_handler`</span>

```rs
pub fn rename_doc_handler(
    mut commands: Commands,
    mut rename_doc_query: Query<
        (&Interaction, &DocListItemButton, Entity, &mut CosmicEdit),
        (Changed<Interaction>, With<DocListItemButton>),
    >,
    mut ui_state: ResMut<UiState>,
    mut double_click: Local<(Duration, Option<ReflectableUuid>)>,
    theme: Res<Theme>,
) {}
```

## <span id="rename_tab_handler">`rename_tab_handler`</span>

```rs
pub fn rename_tab_handler(
    mut commands: Commands,
    mut interaction_query: Query<
        (&Interaction, &TabButton, Entity, &mut CosmicEdit),
        (Changed<Interaction>, With<TabButton>),
    >,
    mut ui_state: ResMut<UiState>,
    mut app_state: ResMut<AppState>,
    mut double_click: Local<(Duration, Option<ReflectableUuid>)>,
    theme: Res<Theme>,
) {}
```

## <span id="resize_entity_end">`resize_entity_end`</span>

```rs
pub fn resize_entity_end(
    mut commands: Commands,
    mut shaders: ResMut<Assets<Shader>>,
    theme: ResMut<Theme>,
    mut ui_state: ResMut<UiState>,
    mut node_interaction_events: EventReader<NodeInteraction>,
    raw_text_query: Query<(&Parent, &RawText, &CosmicEdit), With<RawText>>,
    border_query: Query<(&Parent, &VeloBorder), With<VeloBorder>>,
    velo_node_query: Query<Entity, With<VeloNode>>,
) {}
```

## <span id="resize_entity_run">`resize_entity_run`</span>

```rs
pub fn resize_entity_run(
    mut commands: Commands,
    ui_state: ResMut<UiState>,
    mut cursor_moved_events: EventReader<CursorMoved>,
    mut events: EventWriter<RedrawArrow>,
    mut resize_marker_query: Query<
        (&ResizeMarker, &Parent, &mut Transform),
        (With<ResizeMarker>, Without<VeloNode>, Without<ArrowConnect>),
    >,
    mut arrow_connector_query: Query<
        (&ArrowConnect, &mut Transform),
        (With<ArrowConnect>, Without<VeloNode>, Without<ResizeMarker>),
    >,
    mut raw_text_query: Query<(&Parent, &RawText, &mut CosmicEdit, &mut Sprite), With<RawText>>,
    mut border_query: Query<(&Parent, &VeloBorder, &mut Path), With<VeloBorder>>,
    mut velo_node_query: Query<
        (&mut Transform, &Children),
        (With<VeloNode>, Without<ResizeMarker>, Without<ArrowConnect>),
    >,
    shadow_query: Query<Entity, With<VeloShadow>>,
    camera_q: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
) {}
```

## <span id="resize_entity_start">`resize_entity_start`</span>

```rs
pub fn resize_entity_start(
    mut ui_state: ResMut<UiState>,
    mut node_interaction_events: EventReader<NodeInteraction>,
    mut windows: Query<&mut Window, With<PrimaryWindow>>,
    resize_marker_query: Query<(&ResizeMarker, &Parent, &mut Transform), With<ResizeMarker>>,
    velo_node_query: Query<&VeloNode, With<VeloNode>>,
) {}
```

## <span id="resize_notificator">`resize_notificator`</span>

```rs
pub fn resize_notificator(
    mut commands: Commands,
    resize_event: Res<Events<WindowResized>>,
    app_state: Res<AppState>,
    mut tabs: Query<&mut CosmicEdit, (With<TabButton>, Without<DocListItemButton>)>,
    mut docs: Query<&mut CosmicEdit, (With<DocListItemButton>, Without<TabButton>)>,
) {}
```

## <span id="save_doc">`save_doc`</span>

```rs
pub fn save_doc(
    request: Res<SaveDocRequest>,
    mut app_state: ResMut<AppState>,
    mut pkv: ResMut<PkvStore>,
    mut commands: Commands,
    mut events: EventWriter<SaveStore>,
) {}
```

## <span id="save_doc_handler">`save_doc_handler`</span>

```rs
pub fn save_doc_handler(
    mut commands: Commands,
    mut save_doc_query: Query<&Interaction, (Changed<Interaction>, With<SaveDoc>)>,
    state: Res<AppState>,
) {}
```

## <span id="save_tab">`save_tab`</span>

```rs
pub fn save_tab(
    images: Res<Assets<Image>>,
    arrows: Query<&ArrowMeta, With<ArrowMeta>>,
    request: Res<SaveTabRequest>,
    mut app_state: ResMut<AppState>,
    raw_text_query: Query<(&RawText, &CosmicEdit, &Parent), With<RawText>>,
    border_query: Query<(&Parent, &VeloBorder, &Fill), With<VeloBorder>>,
    velo_node_query: Query<&Transform, With<VeloNode>>,
) {}
```

## <span id="save_to_store">`save_to_store`</span>

```rs
pub fn save_to_store(
    mut pkv: ResMut<PkvStore>,
    mut app_state: ResMut<AppState>,
    mut events: EventReader<SaveStore>,
) {}
```

## <span id="search_box_click">`search_box_click`</span>

```rs
pub fn search_box_click(
    mut commands: Commands,
    mut interaction_query: Query<
        (&Interaction, &SearchButton),
        (Changed<Interaction>, With<SearchButton>),
    >,
    mut search_query: Query<(&SearchText, Entity), With<SearchText>>,
    mut state: ResMut<UiState>,
    mut windows: Query<&mut Window, With<PrimaryWindow>>,
) {}
```

## <span id="search_box_text_changed">`search_box_text_changed`</span>

```rs
pub fn search_box_text_changed(
    text_query: Query<&CosmicEdit, With<SearchText>>,
    mut velo_border: Query<(&mut Stroke, &VeloBorder), With<VeloBorder>>,
    mut previous_search_text: Local<String>,
    mut app_state: ResMut<AppState>,
    pkv: Res<PkvStore>,
    theme: Res<Theme>,
) {}
```

## <span id="select_tab_handler">`select_tab_handler`</span>

```rs
pub fn select_tab_handler(
    mut commands: Commands,
    mut interaction_query: Query<
        (&Interaction, &TabButton),
        (Changed<Interaction>, With<TabButton>),
    >,
    mut state: ResMut<AppState>,
) {}
```

## <span id="set_focused_entity">`set_focused_entity`</span>

```rs
pub fn set_focused_entity(
    mut windows: Query<&mut Window, With<PrimaryWindow>>,
    mut node_interaction_events: EventReader<NodeInteraction>,
    mut ui_state: ResMut<UiState>,
    velo: Query<&RawText, With<RawText>>,
) {}
```

## <span id="set_window_property">`set_window_property`</span>

```rs
pub fn set_window_property(mut app_state: ResMut<AppState>, mut pkv: ResMut<PkvStore>) {}
```

## <span id="setup_background">`setup_background`</span>

```rs
pub fn setup_background(mut commands: Commands, asset_server: Res<AssetServer>, theme: Res<Theme>) {}
```

## <span id="setup_camera">`setup_camera`</span>

```rs
pub fn setup_camera(mut commands: Commands) {}
```

## <span id="setup_velo_theme">`setup_velo_theme`</span>

```rs
pub fn setup_velo_theme(mut commands: Commands, pkv: Res<PkvStore>) {}
```

## <span id="shared_doc_handler">`shared_doc_handler`</span>

```rs
pub fn shared_doc_handler(
    mut app_state: ResMut<AppState>,
    mut query: Query<&Interaction, (Changed<Interaction>, With<ShareDoc>)>,
    mut pkv: ResMut<PkvStore>,
) {}
```

## <span id="should_load_doc">`should_load_doc`</span>

```rs
pub fn should_load_doc(request: Option<Res<LoadDocRequest>>) -> bool {}
```

## <span id="should_load_tab">`should_load_tab`</span>

```rs
pub fn should_load_tab(request: Option<Res<LoadTabRequest>>) -> bool {}
```

## <span id="should_save_doc">`should_save_doc`</span>

```rs
pub fn should_save_doc(request: Option<Res<SaveDocRequest>>) -> bool {}
```

## <span id="should_save_tab">`should_save_tab`</span>

```rs
pub fn should_save_tab(request: Option<Res<SaveTabRequest>>) -> bool {}
```

## <span id="update_rectangle_position">`update_rectangle_position`</span>

```rs
pub fn update_rectangle_position(
    mut cursor_moved_events: EventReader<CursorMoved>,
    raw_text_query: Query<(&RawText, &Parent), With<RawText>>,
    border_query: Query<&Parent, With<VeloBorder>>,
    mut velo_node_query: Query<&mut Transform, With<VeloNode>>,
    mut events: EventWriter<RedrawArrow>,
    camera_q: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
    ui_state: Res<UiState>,
) {}
```


================================================
FILE: justfile
================================================
# Run native
native:
    cargo run --release

# Run wasm
wasm:
    cargo install wasm-server-runner
    RUSTFLAGS=--cfg=web_sys_unstable_apis cargo run --release --target wasm32-unknown-unknown

# Create app bundle with icon (tested only on MacOS)
bundle:
    cargo build --release
    cargo install cargo-bundle
    cargo bundle

# Lints to be used before commit
lint:
    cargo fmt
    cargo clippy -- -A clippy::type_complexity -A clippy::too_many_arguments


================================================
FILE: security.md
================================================
# Security Policy

## Introduction
This security policy outlines the expectations and procedures for reporting and resolving vulnerabilities in our GitHub repository. The security of our code is of utmost importance to us, and we appreciate the help of the community in identifying and reporting potential security vulnerabilities.

## Reporting a Vulnerability
If you believe you have discovered a vulnerability in our repository, please report it to us immediately by opening a new issue on our GitHub repository. When reporting a vulnerability, please include as much detail as possible, including a clear description of the issue, steps to reproduce the vulnerability, and any relevant code snippets or screenshots.

## Vulnerability Assessment
We will review the reported vulnerability and assess the potential impact to our codebase and systems. If the vulnerability is confirmed, we will determine the severity of the issue and prioritize it accordingly.

## Fixing the Vulnerability
Once we have determined the severity of the vulnerability, we will work to address it as quickly as possible. We may contact you for additional information or assistance in reproducing the vulnerability, and we will keep you updated on our progress in fixing the issue.

## Disclosure
Once the vulnerability has been fixed, we will publicly disclose the vulnerability and our response to it.

## Vulnerability Declined
In some cases, we may determine that a reported vulnerability is not a security issue or does not pose a significant risk to our systems. If we decline to address a reported vulnerability, we will explain our decision and provide our rationale for not taking action.

## Conclusion
We appreciate your assistance in helping to ensure the security of our codebase and systems. By working together, we can maintain a safe and secure environment for our users and customers.

================================================
FILE: src/canvas/arrow/components.rs
================================================
use crate::utils::ReflectableUuid;
use bevy::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(
    Component, Copy, Clone, Debug, Eq, PartialEq, Hash, Reflect, Default, Serialize, Deserialize,
)]
#[reflect(Component)]
pub struct ArrowMeta {
    pub visible: bool,
    pub arrow_type: ArrowType,
    pub start: ArrowConnect,
    pub end: ArrowConnect,
}
#[derive(
    Component, Copy, Clone, Debug, Eq, PartialEq, Hash, Reflect, Default, Serialize, Deserialize,
)]
#[reflect(Component)]
pub struct ArrowConnect {
    pub id: ReflectableUuid,
    pub pos: ArrowConnectPos,
}

#[derive(Component)]
pub struct ArrowMode {
    pub arrow_type: ArrowType,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Reflect, Default, Serialize, Deserialize)]
pub enum ArrowConnectPos {
    #[default]
    Top,
    Bottom,
    Left,
    Right,
}

#[derive(Serialize, Deserialize, Default, Copy, Clone, Reflect, Debug, Eq, PartialEq, Hash)]
pub enum ArrowType {
    Line,
    Arrow,
    DoubleArrow,
    ParallelLine,
    #[default]
    ParallelArrow,
    ParallelDoubleArrow,
}


================================================
FILE: src/canvas/arrow/events.rs
================================================
use bevy::prelude::Event;

use super::components::{ArrowConnect, ArrowType};
use crate::utils::ReflectableUuid;

#[derive(Event)]
pub struct RedrawArrow {
    pub id: ReflectableUuid,
}
#[derive(Event, Eq, PartialEq, Hash, Debug, Clone, Copy)]
pub struct CreateArrow {
    pub visible: bool,
    pub arrow_type: ArrowType,
    pub start: ArrowConnect,
    pub end: ArrowConnect,
}


================================================
FILE: src/canvas/arrow/mod.rs
================================================
pub mod components;
pub mod events;
mod systems;
mod utils;
use bevy::{
    app::{App, Plugin},
    prelude::PreUpdate,
};
use bevy_prototype_lyon::prelude::ShapePlugin;
use systems::*;

pub struct ArrowPlugin;

impl Plugin for ArrowPlugin {
    fn build(&self, app: &mut App) {
        app.add_plugins(ShapePlugin).add_systems(
            PreUpdate, // due to CreateArrow event
            (create_arrow_start, create_arrow_end, redraw_arrows),
        );
    }
}


================================================
FILE: src/canvas/arrow/systems.rs
================================================
use bevy::{prelude::*, window::PrimaryWindow};

use super::components::{ArrowConnect, ArrowMeta};
use super::events::{CreateArrow, RedrawArrow};
use super::utils::{build_arrow, create_arrow};
use crate::themes::Theme;
use crate::ui_plugin::ui_helpers::VeloNode;
use crate::ui_plugin::{NodeInteraction, UiState};
use bevy_prototype_lyon::prelude::Path;

pub fn create_arrow_start(
    mut node_interaction_events: EventReader<NodeInteraction>,
    arrow_connect_query: Query<&ArrowConnect, With<ArrowConnect>>,
    mut state: ResMut<UiState>,
    mut create_arrow: EventWriter<CreateArrow>,
    mut windows: Query<&mut Window, With<PrimaryWindow>>,
) {
    let mut primary_window = windows.single_mut();
    for event in node_interaction_events.iter() {
        if let Ok(arrow_connect) = arrow_connect_query.get(event.entity) {
            match event.node_interaction_type {
                crate::ui_plugin::NodeInteractionType::Hover => {
                    primary_window.cursor.icon = CursorIcon::Crosshair;
                }
                crate::ui_plugin::NodeInteractionType::LeftClick => {
                    match state.arrow_to_draw_start {
                        Some(start_arrow) => {
                            if start_arrow.id == arrow_connect.id {
                                continue;
                            }
                            state.arrow_to_draw_start = None;
                            create_arrow.send(CreateArrow {
                                visible: true,
                                start: start_arrow,
                                end: *arrow_connect,
                                arrow_type: state.arrow_type,
                            });
                        }
                        None => {
                            state.arrow_to_draw_start = Some(*arrow_connect);
                        }
                    }
                }
                crate::ui_plugin::NodeInteractionType::LeftDoubleClick => {}
                crate::ui_plugin::NodeInteractionType::LeftMouseHoldAndDrag => {}
                crate::ui_plugin::NodeInteractionType::RightClick => {}
                crate::ui_plugin::NodeInteractionType::LeftMouseRelease => {}
            }
        }
    }
}

pub fn create_arrow_end(
    mut commands: Commands,
    mut events: EventReader<CreateArrow>,
    arrow_markers: Query<(&ArrowConnect, &GlobalTransform), With<ArrowConnect>>,
    velo_nodes: Query<(&Transform, &VeloNode), With<VeloNode>>,
    theme: Res<Theme>,
) {
    for event in events.iter() {
        let mut start = None;
        let mut end = None;
        for (arrow_connect, global_transform) in &mut arrow_markers.iter() {
            if *arrow_connect == event.start {
                start = Some(global_transform.affine().translation.truncate());
            }
            if *arrow_connect == event.end {
                end = Some(global_transform.affine().translation.truncate());
            }
            if let (Some(start), Some(end)) = (start, end) {
                let mut max_z = 0.1;
                for (transform, velo_node) in velo_nodes.iter() {
                    if velo_node.id == event.start.id {
                        max_z = f32::max(max_z, transform.translation.z);
                    }
                    if velo_node.id == event.end.id {
                        max_z = f32::max(max_z, transform.translation.z);
                    }
                }

                create_arrow(
                    &mut commands,
                    &theme,
                    start,
                    end,
                    max_z,
                    ArrowMeta {
                        visible: event.visible,
                        start: event.start,
                        end: event.end,
                        arrow_type: event.arrow_type,
                    },
                );
                break;
            }
        }
    }
}
pub fn redraw_arrows(
    mut redraw_arrow: EventReader<RedrawArrow>,
    mut arrow_query: Query<(&mut Path, &mut ArrowMeta), With<ArrowMeta>>,
    arrow_markers: Query<(&ArrowConnect, &GlobalTransform), With<ArrowConnect>>,
) {
    for event in redraw_arrow.iter() {
        for (mut path, mut arrow) in arrow_query.iter_mut() {
            if arrow.start.id == event.id || arrow.end.id == event.id {
                let (arrow_hold_vec, arrow_move_vec): (Vec<_>, Vec<_>) = arrow_markers
                    .iter()
                    .filter(|(x, _)| x.id == arrow.end.id || x.id == arrow.start.id)
                    .map(|(ac, gt)| (ac, gt.affine().translation.truncate()))
                    .partition(|(x, _)| x.id == arrow.end.id);
                let arrow_pos = arrow_hold_vec
                    .iter()
                    .flat_map(move |x| std::iter::repeat(*x).zip(arrow_move_vec.clone()))
                    .min_by_key(|(arrow_hold, arrow_move)| {
                        arrow_hold.1.distance(arrow_move.1) as u32
                    });
                if let Some((start_pos, end_pos)) = arrow_pos {
                    let ((start_pos, start), (end_pos, end)) = if start_pos.0.id == arrow.start.id {
                        (start_pos, end_pos)
                    } else {
                        (end_pos, start_pos)
                    };
                    arrow.start = *start_pos;
                    arrow.end = *end_pos;
                    *path = build_arrow(start, end, *arrow);
                }
            }
        }
    }
}


================================================
FILE: src/canvas/arrow/utils.rs
================================================
use std::f32::consts::PI;

use bevy::prelude::*;
use bevy_prototype_lyon::{
    prelude::{GeometryBuilder, Path, ShapeBundle, Stroke},
    shapes,
};

use crate::themes::Theme;

use super::components::{ArrowConnectPos, ArrowMeta, ArrowType};

pub fn create_arrow(
    commands: &mut Commands,
    theme: &Res<Theme>,
    start: Vec2,
    end: Vec2,
    z: f32,
    arrow_meta: ArrowMeta,
) {
    let arrow_path = build_arrow(start, end, arrow_meta);
    let visibility = if arrow_meta.visible {
        Visibility::Visible
    } else {
        Visibility::Hidden
    };
    commands.spawn((
        ShapeBundle {
            visibility,
            transform: Transform::from_xyz(0.0, 0.0, z),
            path: arrow_path,
            ..default()
        },
        arrow_meta,
        Stroke::new(theme.arrow, 1.5),
    ));
}
fn parallel_arrow_mid(start: Vec2, end: Vec2, arrow_meta: ArrowMeta) -> (Vec2, Vec2) {
    let mid = (start + end) / 2.0;
    use ArrowConnectPos::*;
    match (arrow_meta.start.pos, arrow_meta.end.pos) {
        (Top, Bottom) | (Bottom, Top) => (Vec2::new(start.x, mid.y), Vec2::new(end.x, mid.y)),
        (Left, Right) | (Right, Left) => (Vec2::new(mid.x, start.y), Vec2::new(mid.x, end.y)),
        (Bottom, Left) | (Top, Right) | (Top, Left) | (Bottom, Right) => {
            (Vec2::new(start.x, end.y), Vec2::new(start.x, end.y))
        }
        (Left, Bottom) | (Right, Top) | (Left, Top) | (Right, Bottom) => {
            (Vec2::new(end.x, start.y), Vec2::new(end.x, start.y))
        }
        (_, _) => (mid, mid),
    }
}
fn arrow_head(point: Vec2, pos: ArrowConnectPos) -> shapes::Polygon {
    let headlen: f32 = 10.0;
    use ArrowConnectPos::*;
    let angle = match pos {
        Top => PI / 2.,
        Bottom => -PI / 2.,
        Right => 0.,
        Left => PI,
    };
    let points = vec![
        point + Vec2::from_angle(angle - PI / 6.) * headlen,
        point,
        point + Vec2::from_angle(angle + PI / 6.) * headlen,
    ];
    shapes::Polygon {
        points,
        closed: false,
    }
}
pub fn build_arrow(start: Vec2, end: Vec2, arrow_meta: ArrowMeta) -> Path {
    match arrow_meta.arrow_type {
        ArrowType::Line => {
            let main = shapes::Line(start, end);
            GeometryBuilder::build_as(&main)
        }
        ArrowType::Arrow => {
            let dt = end.x - start.x;
            let dy = end.y - start.y;
            let angle = dy.atan2(dt);
            let headlen = 10.0;
            GeometryBuilder::new()
                .add(&shapes::Line(start, end))
                .add(&shapes::Line(
                    end,
                    end - headlen * Vec2::from_angle(angle + PI / 6.),
                ))
                .add(&shapes::Line(
                    end,
                    end - headlen * Vec2::from_angle(angle - PI / 6.),
                ))
                .build()
        }
        ArrowType::DoubleArrow => {
            let headlen = 10.0;
            let dt = end.x - start.x;
            let dy = end.y - start.y;
            let angle = dy.atan2(dt);
            GeometryBuilder::new()
                .add(&shapes::Line(
                    start,
                    start + headlen * Vec2::from_angle(angle + PI / 6.),
                ))
                .add(&shapes::Line(
                    start,
                    start + headlen * Vec2::from_angle(angle - PI / 6.),
                ))
                .add(&shapes::Line(start, end))
                .add(&shapes::Line(
                    end,
                    end - headlen * Vec2::from_angle(angle + PI / 6.),
                ))
                .add(&shapes::Line(
                    end,
                    end - headlen * Vec2::from_angle(angle - PI / 6.),
                ))
                .build()
        }
        ArrowType::ParallelLine => {
            let mid_point = parallel_arrow_mid(start, end, arrow_meta);
            GeometryBuilder::new()
                .add(&shapes::Line(start, mid_point.0))
                .add(&shapes::Line(mid_point.0, mid_point.1))
                .add(&shapes::Line(mid_point.1, end))
                .build()
        }
        ArrowType::ParallelArrow => {
            let head_pos = arrow_meta.end.pos;
            let mid_point = parallel_arrow_mid(start, end, arrow_meta);
            GeometryBuilder::new()
                .add(&shapes::Line(start, mid_point.0))
                .add(&shapes::Line(mid_point.0, mid_point.1))
                .add(&shapes::Line(mid_point.1, end))
                .add(&arrow_head(end, head_pos))
                .build()
        }
        ArrowType::ParallelDoubleArrow => {
            let head_pos = arrow_meta.end.pos;
            let tail_pos = arrow_meta.start.pos;
            let mid_point = parallel_arrow_mid(start, end, arrow_meta);
            GeometryBuilder::new()
                .add(&arrow_head(start, tail_pos))
                .add(&shapes::Line(start, mid_point.0))
                .add(&shapes::Line(mid_point.0, mid_point.1))
                .add(&shapes::Line(mid_point.1, end))
                .add(&arrow_head(end, head_pos))
                .build()
        }
    }
}


================================================
FILE: src/canvas/grid/mod.rs
================================================
use bevy::{
    prelude::*,
    reflect::{TypePath, TypeUuid},
    render::render_resource::{AsBindGroup, ShaderRef},
    sprite::{Material2d, Material2dPlugin},
    transform::TransformSystem,
};

pub mod systems;
use systems::*;

pub struct GridPlugin;

#[derive(Resource, Default)]
pub struct CanvasInserted(pub bool);

impl Plugin for GridPlugin {
    fn build(&self, app: &mut App) {
        app.add_plugins(Material2dPlugin::<CustomGridMaterial>::default())
            .add_systems(Startup, grid)
            .add_systems(
                PostUpdate,
                (update_grid, grid_follows_camera)
                    .chain()
                    .after(TransformSystem::TransformPropagate),
            );
    }
}

#[derive(AsBindGroup, TypeUuid, TypePath, Debug, Clone)]
#[uuid = "CC3772B3-5282-4F1F-92B5-4F2D864B4441"]
pub struct CustomGridMaterial {
    #[uniform(0)]
    line_color: Color,
    #[uniform(0)]
    grid_size: Vec2,
    #[uniform(0)]
    cell_size: Vec2,
    #[uniform(0)]
    major: f32,
}

impl Material2d for CustomGridMaterial {
    fn fragment_shader() -> ShaderRef {
        "shaders/grid.wgsl".into()
    }
}


================================================
FILE: src/canvas/grid/systems.rs
================================================
use crate::{components::MainCamera, themes::Theme};

use super::CustomGridMaterial;
use bevy::{
    prelude::*,
    sprite::{MaterialMesh2dBundle, Mesh2dHandle},
};

const CELL_SIZE: f32 = 12.0;

#[derive(Component)]
pub struct Grid;

pub fn grid(
    mut commands: Commands,
    mut materials: ResMut<Assets<CustomGridMaterial>>,
    mut meshes: ResMut<Assets<Mesh>>,
    theme: Res<Theme>,
) {
    let max_size = 1_000_000.;
    let size = Vec2::new(max_size, max_size);
    let mesh = Mesh::from(shape::Quad { size, flip: false });

    commands
        .spawn(MaterialMesh2dBundle {
            mesh: meshes.add(mesh).into(),
            transform: Transform {
                translation: Vec3::new(0.0, 0.0, 0.0),
                ..Default::default()
            },
            material: materials.add(CustomGridMaterial {
                line_color: theme.canvas_bg_line_color,
                grid_size: size,
                cell_size: Vec2::splat(CELL_SIZE),
                major: 8.0,
            }),
            ..Default::default()
        })
        .insert(Grid);
}

pub fn update_grid(
    camera: Query<
        (&Camera, &GlobalTransform, &OrthographicProjection),
        (Changed<OrthographicProjection>, With<MainCamera>),
    >,
    grid: Query<(&Handle<CustomGridMaterial>, &Mesh2dHandle)>,
    mut materials: ResMut<Assets<CustomGridMaterial>>,
    mut meshes: ResMut<Assets<Mesh>>,
) {
    for (camera, camera_transform, projection) in camera.iter() {
        for (grid_handle, mesh_handle) in grid.iter() {
            let current_zoom = projection.scale;
            let ndc = Vec3::ONE;
            let world_coords = camera.ndc_to_world(camera_transform, ndc).unwrap();
            let corner_offset = world_coords - camera_transform.translation();
            let rect = corner_offset.truncate() * 2.0;
            let side = rect.max_element();
            let size = Vec2::splat(side) * 2.0;
            if let Some(mesh) = meshes.get_mut(&mesh_handle.0) {
                *mesh = shape::Quad::new(size).into();
            }
            if let Some(material) = materials.get_mut(grid_handle) {
                let exponent = current_zoom.log(material.major);
                let exponent = exponent.ceil();
                let grid_scale = material.major.powf(exponent);
                material.cell_size = Vec2::splat(CELL_SIZE) * grid_scale;
                material.grid_size = size;
            }
        }
    }
}

pub fn grid_follows_camera(
    camera: Query<
        &GlobalTransform,
        (
            With<Camera>,
            With<MainCamera>,
            Or<(Changed<OrthographicProjection>, Changed<GlobalTransform>)>,
        ),
    >,
    mut grid: Query<(&mut Transform, &Handle<CustomGridMaterial>)>,
    materials: Res<Assets<CustomGridMaterial>>,
) {
    for (mut transform, material_handle) in grid.iter_mut() {
        if let Some(material) = materials.get(material_handle) {
            for camera in camera.iter() {
                let major_grid_translation = material.cell_size * material.major;
                let camera_major_grid_translation =
                    (camera.translation().truncate() / major_grid_translation).trunc();
                let truncated_camera_major_grid_translation =
                    camera_major_grid_translation * major_grid_translation;
                transform.translation.x = truncated_camera_major_grid_translation.x;
                transform.translation.y = truncated_camera_major_grid_translation.y;
            }
        }
    }
}


================================================
FILE: src/canvas/mod.rs
================================================
pub mod arrow;
pub mod grid;
pub mod shadows;

use arrow::*;
use bevy::app::{App, Plugin};
use grid::*;
use shadows::*;

pub struct CanvasPlugin;

impl Plugin for CanvasPlugin {
    fn build(&self, app: &mut App) {
        app.add_plugins((ArrowPlugin, ShadowsPlugin, GridPlugin));
    }
}


================================================
FILE: src/canvas/shadows/mod.rs
================================================
use bevy::{
    prelude::*,
    reflect::{TypePath, TypeUuid},
    render::render_resource::{AsBindGroup, ShaderRef},
    sprite::{Material2d, Material2dPlugin},
};

use self::systems::synchronise_shadow_sizes;

pub mod systems;
pub struct ShadowsPlugin;

impl Plugin for ShadowsPlugin {
    fn build(&self, app: &mut App) {
        app.add_plugins(Material2dPlugin::<CustomShadowMaterial>::default())
            .add_systems(PostUpdate, synchronise_shadow_sizes);
    }
}

#[derive(AsBindGroup, TypeUuid, TypePath, Debug, Clone)]
#[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
pub struct CustomShadowMaterial {
    #[uniform(0)]
    color: Color,
    #[uniform(0)]
    flat_size: Vec2,
    #[uniform(0)]
    edge_size: Vec2,
}

impl Material2d for CustomShadowMaterial {
    fn fragment_shader() -> ShaderRef {
        "shaders/shadows.wgsl".into()
    }
}


================================================
FILE: src/canvas/shadows/systems.rs
================================================
use bevy::{
    prelude::{shape::Quad, *},
    sprite::{MaterialMesh2dBundle, Mesh2dHandle},
};

use crate::themes::Theme;

use super::CustomShadowMaterial;

#[derive(Component)]
pub struct Shadow;

// Spawn an entity using `CustomMaterial`.
pub fn spawn_shadow(
    commands: &mut Commands,
    materials: &mut ResMut<Assets<CustomShadowMaterial>>,
    meshes: &mut ResMut<Assets<Mesh>>,
    theme: &Res<Theme>,
    flat_size: Vec2,
) -> Entity {
    let edge_size = 0.09 * flat_size;
    let full_size = flat_size + edge_size;
    let mesh: Mesh = Quad::new(full_size).into();
    let mesh = Mesh2dHandle(meshes.add(mesh));

    let material = materials.add(CustomShadowMaterial {
        color: theme.shadow,
        flat_size,
        edge_size,
    });
    let entity = commands
        .spawn(MaterialMesh2dBundle {
            mesh,
            material,
            transform: Transform {
                translation: Vec3::new(-3., -3., 0.0009),
                ..Default::default()
            },
            ..default()
        })
        .id();
    commands
        .spawn(SpriteBundle {
            sprite: Sprite {
                color: Color::WHITE,
                custom_size: Some(flat_size),
                ..default()
            },
            ..default()
        })
        .insert(Shadow)
        .add_child(entity)
        .id()
}

pub fn synchronise_shadow_sizes(
    objects: Query<&Sprite, (Changed<Sprite>, With<Shadow>)>,
    shadows: Query<(&Parent, &Handle<CustomShadowMaterial>, &Mesh2dHandle)>,
    mut materials: ResMut<Assets<CustomShadowMaterial>>,
    mut meshes: ResMut<Assets<Mesh>>,
) {
    for (parent, mat, mesh) in shadows.iter() {
        let Ok(sprite) = objects.get(parent.get()) else {
            continue;
        };
        let Some(material) = materials.get_mut(mat) else {
            continue;
        };
        let Some(mesh) = meshes.get_mut(&mesh.0) else {
            continue;
        };

        let flat_size = sprite.custom_size.unwrap();
        let edge_size = material.edge_size;
        let full_size = flat_size + edge_size;
        *mesh = Quad::new(full_size).into();
        material.flat_size = flat_size;
    }
}


================================================
FILE: src/components.rs
================================================
use crate::utils::ReflectableUuid;
use bevy::prelude::*;
use serde::{Deserialize, Serialize};
use std::collections::VecDeque;
#[derive(Component)]
pub struct MainCamera;

#[derive(Component)]
pub struct EffectsCamera;

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Tab {
    pub is_active: bool,
    pub id: ReflectableUuid,
    pub name: String,
    pub checkpoints: VecDeque<String>,
    pub z_index: f32,
}

#[derive(Default, Serialize, Deserialize, Clone, Debug)]
pub struct Doc {
    pub tabs: Vec<Tab>,
    pub id: ReflectableUuid,
    pub name: String,
    pub tags: Vec<String>,
}


================================================
FILE: src/lib.rs
================================================
mod canvas;
mod components;
mod resources;
mod systems;
mod themes;
mod ui_plugin;
mod utils;

use bevy::{prelude::*, window::PresentMode};
use bevy_cosmic_edit::CosmicEditPlugin;
use bevy_embedded_assets::EmbeddedAssetPlugin;
#[cfg(not(target_arch = "wasm32"))]
use bevy_hanabi::HanabiPlugin;
use bevy_pancam::PanCamPlugin;
use bevy_pkv::PkvStore;
use canvas::CanvasPlugin;
use resources::FontSystemState;
use systems::*;
use ui_plugin::*;

pub static ORG_NAME: &str = "";
pub static APP_NAME: &str = "velo";

pub struct VeloPlugin;
impl Plugin for VeloPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(PreStartup, setup_velo_theme)
            .add_systems(Startup, setup_camera)
            .add_plugins(
                DefaultPlugins
                    .set(WindowPlugin {
                        primary_window: Some(Window {
                            title: "Velo".into(),
                            present_mode: PresentMode::AutoVsync,
                            // Tells wasm to resize the window according to the available canvas
                            fit_canvas_to_parent: true,
                            // Tells wasm not to override default event handling, like F5, Ctrl+R etc.
                            prevent_default_event_handling: false,
                            ..default()
                        }),
                        ..default()
                    })
                    .build()
                    .add_before::<bevy::asset::AssetPlugin, _>(EmbeddedAssetPlugin),
            )
            .add_plugins(CosmicEditPlugin)
            .add_plugins(CanvasPlugin)
            .add_plugins(UiPlugin)
            .add_plugins(PanCamPlugin)
            .insert_resource(PkvStore::new(ORG_NAME, APP_NAME))
            .init_resource::<FontSystemState>();

        #[cfg(not(target_arch = "wasm32"))]
        app.add_plugins(HanabiPlugin);
    }
}


================================================
FILE: src/macros.rs
================================================
macro_rules! pair_struct {
    ($obj:ident . $field:ident) => {{
        let field_val = $obj.$field;
        (stringify!($field).to_string(), field_val)
    }};
}


================================================
FILE: src/main.rs
================================================
use bevy::prelude::*;
use velo::VeloPlugin;

fn main() {
    #[cfg(target_arch = "wasm32")]
    console_error_panic_hook::set_once();
    #[cfg(not(target_arch = "wasm32"))]
    std::env::set_var("RUST_LOG", "warn,velo=info,tantivy=warn");
    App::new().add_plugins(VeloPlugin).run();
}


================================================
FILE: src/resources.rs
================================================
use crate::components::Doc;
#[cfg(not(target_arch = "wasm32"))]
use crate::ui_plugin::SearchIndexState;
use crate::utils::ReflectableUuid;
use bevy::prelude::*;
use bevy_cosmic_edit::CosmicFont;
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;

#[derive(Resource, Default)]
pub struct AppState {
    pub current_document: Option<ReflectableUuid>,
    pub docs: HashMap<ReflectableUuid, Doc>,
    pub github_token: Option<String>,
    #[cfg(not(target_arch = "wasm32"))]
    pub search_index: Option<SearchIndexState>,
    pub doc_list_ui: HashSet<ReflectableUuid>,
}

#[derive(Resource, Debug)]
pub struct SaveDocRequest {
    pub doc_id: ReflectableUuid,
    pub path: Option<PathBuf>, // Save current document to file
}

#[derive(Resource, Debug)]
pub struct SaveTabRequest {
    pub doc_id: ReflectableUuid,
    pub tab_id: ReflectableUuid,
}

#[derive(Resource, Debug)]
pub struct LoadDocRequest {
    pub doc_id: ReflectableUuid,
}

#[derive(Resource, Debug)]
pub struct LoadTabRequest {
    pub doc_id: ReflectableUuid,
    pub tab_id: ReflectableUuid,
    pub drop_last_checkpoint: bool, // Useful for undo functionality
}

#[derive(Resource, Default)]
pub struct FontSystemState(pub Option<Handle<CosmicFont>>);


================================================
FILE: src/systems.rs
================================================
use crate::{
    components::{EffectsCamera, MainCamera},
    themes::{get_theme_by_name, Theme},
    utils::get_theme_key,
};
use bevy::{
    core_pipeline::clear_color::ClearColorConfig,
    prelude::*,
    render::{camera::ScalingMode, view::RenderLayers},
};
use bevy_pancam::PanCam;
use bevy_pkv::PkvStore;

pub fn setup_velo_theme(mut commands: Commands, pkv: Res<PkvStore>) {
    let theme_key = get_theme_key(&pkv);
    let theme = get_theme_by_name(&theme_key);
    commands.insert_resource(theme);
}

pub fn setup_camera(mut commands: Commands, theme: Res<Theme>) {
    let mut main_camera = Camera2dBundle::default();
    if let Some(bg_color) = theme.canvas_bg_color {
        main_camera.camera_2d.clear_color = ClearColorConfig::Custom(bg_color);
    } else {
        main_camera.camera_2d.clear_color = ClearColorConfig::Custom(Color::WHITE.with_a(0.1));
    }

    let max_size = theme.max_camera_space;
    commands.spawn((main_camera, MainCamera)).insert(PanCam {
        grab_buttons: vec![MouseButton::Right],
        enabled: true,
        zoom_to_cursor: false,
        min_scale: 1.,
        max_scale: None,
        min_x: Some(-max_size / 2.),
        max_x: Some(max_size / 2.),
        min_y: Some(-max_size / 2.),
        max_y: Some(max_size / 2.),
    });
    let mut effects_camera = Camera2dBundle {
        camera: Camera {
            order: 2,
            is_active: false,
            ..default()
        },
        camera_2d: Camera2d {
            clear_color: ClearColorConfig::None,
        },
        ..default()
    };
    effects_camera.projection.scale = 1.0;
    effects_camera.projection.scaling_mode = ScalingMode::FixedVertical(1.);
    commands.spawn((
        effects_camera,
        EffectsCamera,
        RenderLayers::from_layers(&[2]),
    ));
}


================================================
FILE: src/themes.rs
================================================
use bevy::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Resource, Debug, Serialize, Deserialize)]
pub struct Theme {
    pub add_tab_bg: Color,
    pub arrow_btn_bg: Color,
    pub arrow_connector_size: f32,
    pub arrow_connector: Color,
    pub arrow: Color,
    pub bottom_panel_bg: Color,
    pub btn_border: Color,
    pub canvas_bg_color: Option<Color>,
    pub canvas_bg_line_color: Color,
    pub celebrate_btn_bg: Color,
    pub celebrate_btn: Color,
    pub drawing_pencil_btn_bg: Color,
    pub drawing_pencil_btn: Color,
    pub drawing_two_points_btn_bg: Color,
    pub drawing_two_points_btn: Color,
    pub add_text_btn_bg: Color,
    pub add_text_btn: Color,
    pub drawing_selected: Color,
    pub clipboard_image_bg: Color,
    pub code_default_lang: String,
    pub code_theme: String,
    pub color_change_1: Color,
    pub color_change_2: Color,
    pub color_change_3: Color,
    pub color_change_4: Color,
    pub color_change_5: Color,
    pub del_button: Color,
    pub doc_list_bg: Color,
    pub font_name: String,
    pub font_size: f32,
    pub font: Color,
    pub front_back_btn_bg: Color,
    pub inline_code: Color,
    pub left_panel_bg: Color,
    pub line_height: f32,
    pub link: Color,
    pub max_camera_space: f32,
    pub menu_bg: Color,
    pub menu_btn_bg: Color,
    pub menu_btn: Color,
    pub modal_bg: Color,
    pub modal_text_input_bg: Color,
    pub new_tab_btn_bg: Color,
    pub node_bg: Color,
    pub node_border: Color,
    pub node_found_color: Color,
    pub node_height: f32,
    pub node_manipulation_bg: Color,
    pub node_manipulation: Color,
    pub node_shadow: Color,
    pub node_width: f32,
    pub ok_cancel_bg: Color,
    pub paper_node_bg: Color,
    pub resize_marker_size: f32,
    pub search_box_bg: Color,
    pub search_box_border: Color,
    pub selected_node_border: Color,
    pub shadow: Color,
    pub tab_bg: Color,
    pub text_pos_btn_bg: Color,
    pub visibility_btn_bg: Color,
    pub tooltip_bg: Color,
    pub color_none: Color,
}

pub fn velo_light() -> Theme {
    Theme {
        add_tab_bg: Color::rgb(1., 193.0 / 255.0, 7.0 / 255.0),
        arrow_btn_bg: Color::rgb(207.0 / 255.0, 216.0 / 255.0, 220.0 / 255.0),
        arrow_connector_size: 5.0,
        arrow_connector: Color::NONE,
        arrow: Color::rgb(63.0 / 255.0, 81.0 / 255.0, 181.0 / 255.0),
        bottom_panel_bg: Color::rgb(189.0 / 255.0, 189.0 / 255.0, 189.0 / 255.0),
        btn_border: Color::rgb(0.5, 0.5, 0.5),
        canvas_bg_color: None,
        canvas_bg_line_color: Color::rgba(97. / 255., 164. / 255., 1., 0.2),
        celebrate_btn_bg: Color::rgb(0.9, 0.9, 0.9),
        celebrate_btn: Color::RED,
        drawing_pencil_btn_bg: Color::rgb(0.9, 0.9, 0.9),
        drawing_pencil_btn: Color::RED,
        drawing_two_points_btn_bg: Color::rgb(0.9, 0.9, 0.9),
        drawing_two_points_btn: Color::GRAY.with_a(0.9),
        add_text_btn_bg: Color::rgb(0.9, 0.9, 0.9),
        add_text_bt
Download .txt
gitextract_nb0mso7g/

├── .cargo/
│   └── config.toml
├── .github/
│   └── workflows/
│       ├── deploy-wasm.yml
│       ├── pr.yml
│       └── release.yml
├── .gitignore
├── 128x128.icns
├── Cargo.toml
├── Cross.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── Readme.md
├── assets/
│   └── shaders/
│       ├── grid.wgsl
│       └── shadows.wgsl
├── code_of_conduct.md
├── contributing.md
├── crates/
│   └── bevy_markdown/
│       ├── Cargo.toml
│       ├── LICENSE-APACHE
│       ├── LICENSE-MIT
│       ├── Readme.md
│       └── src/
│           ├── lib.rs
│           └── snapshots/
│               ├── bevy_markdown__tests__test_render_break.snap
│               ├── bevy_markdown__tests__test_render_break_after_link.snap
│               ├── bevy_markdown__tests__test_render_code.snap
│               ├── bevy_markdown__tests__test_render_nested_ordered_list.snap
│               ├── bevy_markdown__tests__test_render_nested_unordered_list.snap
│               ├── bevy_markdown__tests__test_render_ordered_list.snap
│               ├── bevy_markdown__tests__test_render_text_style.snap
│               ├── bevy_markdown__tests__test_render_text_style_complicated.snap
│               ├── bevy_markdown__tests__test_render_text_style_header.snap
│               └── bevy_markdown__tests__test_render_unordered_list.snap
├── docs/
│   └── architecture.md
├── justfile
├── security.md
└── src/
    ├── canvas/
    │   ├── arrow/
    │   │   ├── components.rs
    │   │   ├── events.rs
    │   │   ├── mod.rs
    │   │   ├── systems.rs
    │   │   └── utils.rs
    │   ├── grid/
    │   │   ├── mod.rs
    │   │   └── systems.rs
    │   ├── mod.rs
    │   └── shadows/
    │       ├── mod.rs
    │       └── systems.rs
    ├── components.rs
    ├── lib.rs
    ├── macros.rs
    ├── main.rs
    ├── resources.rs
    ├── systems.rs
    ├── themes.rs
    ├── ui_plugin/
    │   ├── mod.rs
    │   ├── systems/
    │   │   ├── active_editor_changed.rs
    │   │   ├── button_handlers.rs
    │   │   ├── canvas_click.rs
    │   │   ├── clickable_links.rs
    │   │   ├── create_new_node.rs
    │   │   ├── doc_list.rs
    │   │   ├── drawing.rs
    │   │   ├── effects.rs
    │   │   ├── entity_to_edit_changed.rs
    │   │   ├── init_layout/
    │   │   │   ├── add_arrow.rs
    │   │   │   ├── add_color.rs
    │   │   │   ├── add_effect.rs
    │   │   │   ├── add_front_back.rs
    │   │   │   ├── add_list.rs
    │   │   │   ├── add_menu_button.rs
    │   │   │   ├── add_pencil.rs
    │   │   │   ├── add_search_box.rs
    │   │   │   ├── add_text.rs
    │   │   │   ├── add_text_pos.rs
    │   │   │   ├── add_two_points_draw.rs
    │   │   │   ├── add_visibility.rs
    │   │   │   ├── init_layout.rs
    │   │   │   └── node_manipulation.rs
    │   │   ├── interactive_sprites.rs
    │   │   ├── keyboard.rs
    │   │   ├── load.rs
    │   │   ├── modal.rs
    │   │   ├── resize_node.rs
    │   │   ├── resize_window.rs
    │   │   ├── save.rs
    │   │   ├── search.rs
    │   │   ├── set_focused_entity.rs
    │   │   ├── tabs.rs
    │   │   └── update_rectangle_position.rs
    │   └── ui_helpers/
    │       ├── add_list_item.rs
    │       ├── add_tab.rs
    │       ├── components.rs
    │       ├── spawn_modal.rs
    │       ├── spawn_node.rs
    │       └── ui_helpers.rs
    └── utils.rs
Download .txt
SYMBOL INDEX (272 symbols across 59 files)

FILE: crates/bevy_markdown/src/lib.rs
  type BevyMarkdownTheme (line 9) | pub struct BevyMarkdownTheme {
  type TextSpanMetadata (line 17) | pub struct TextSpanMetadata {
  function default (line 22) | pub fn default<T: Default>() -> T {
  type TextSpan (line 27) | pub struct TextSpan {
  type BevyMarkdown (line 36) | pub struct BevyMarkdown {
  type InlineStyleType (line 44) | enum InlineStyleType {
    method from_u8 (line 69) | pub fn from_u8(style_code: u8) -> Self {
  function get_header_font_size (line 55) | pub fn get_header_font_size(val: u8) -> f32 {
  type BevyMarkdownError (line 84) | pub enum BevyMarkdownError {
  function get_bullet_for_indentation_level (line 89) | pub fn get_bullet_for_indentation_level(level: u8) -> &'static str {
  function handle_block_styling (line 100) | pub fn handle_block_styling(
  function handle_inline_styling (line 171) | pub fn handle_inline_styling(
  function handle_list_recursive (line 270) | fn handle_list_recursive(
  type BevyMarkdownLines (line 352) | pub struct BevyMarkdownLines {
  function generate_markdown_lines (line 357) | pub fn generate_markdown_lines(
  function test_bevymarkdown (line 515) | fn test_bevymarkdown(input: String, test_name: String) {
  function test_render_text_complicated (line 534) | pub fn test_render_text_complicated() {
  function test_render_text_with_header (line 546) | pub fn test_render_text_with_header() {
  function test_render_text_style (line 560) | pub fn test_render_text_style() {
  function test_render_code (line 572) | pub fn test_render_code() {
  function test_render_break (line 586) | pub fn test_render_break() {
  function test_render_break_after_link (line 595) | pub fn test_render_break_after_link() {
  function test_render_unordered_list (line 608) | pub fn test_render_unordered_list() {
  function test_render_ordered_list (line 621) | pub fn test_render_ordered_list() {
  function test_render_nested_unordered_list (line 632) | pub fn test_render_nested_unordered_list() {
  function test_render_nested_ordered_list (line 645) | pub fn test_render_nested_ordered_list() {

FILE: src/canvas/arrow/components.rs
  type ArrowMeta (line 8) | pub struct ArrowMeta {
  type ArrowConnect (line 18) | pub struct ArrowConnect {
  type ArrowMode (line 24) | pub struct ArrowMode {
  type ArrowConnectPos (line 28) | pub enum ArrowConnectPos {
  type ArrowType (line 37) | pub enum ArrowType {

FILE: src/canvas/arrow/events.rs
  type RedrawArrow (line 7) | pub struct RedrawArrow {
  type CreateArrow (line 11) | pub struct CreateArrow {

FILE: src/canvas/arrow/mod.rs
  type ArrowPlugin (line 12) | pub struct ArrowPlugin;
  method build (line 15) | fn build(&self, app: &mut App) {

FILE: src/canvas/arrow/systems.rs
  function create_arrow_start (line 11) | pub fn create_arrow_start(
  function create_arrow_end (line 53) | pub fn create_arrow_end(
  function redraw_arrows (line 99) | pub fn redraw_arrows(

FILE: src/canvas/arrow/utils.rs
  function create_arrow (line 13) | pub fn create_arrow(
  function parallel_arrow_mid (line 38) | fn parallel_arrow_mid(start: Vec2, end: Vec2, arrow_meta: ArrowMeta) -> ...
  function arrow_head (line 53) | fn arrow_head(point: Vec2, pos: ArrowConnectPos) -> shapes::Polygon {
  function build_arrow (line 72) | pub fn build_arrow(start: Vec2, end: Vec2, arrow_meta: ArrowMeta) -> Path {

FILE: src/canvas/grid/mod.rs
  type GridPlugin (line 12) | pub struct GridPlugin;
  type CanvasInserted (line 15) | pub struct CanvasInserted(pub bool);
  method build (line 18) | fn build(&self, app: &mut App) {
  type CustomGridMaterial (line 32) | pub struct CustomGridMaterial {
  method fragment_shader (line 44) | fn fragment_shader() -> ShaderRef {

FILE: src/canvas/grid/systems.rs
  constant CELL_SIZE (line 9) | const CELL_SIZE: f32 = 12.0;
  type Grid (line 12) | pub struct Grid;
  function grid (line 14) | pub fn grid(
  function update_grid (line 42) | pub fn update_grid(
  function grid_follows_camera (line 74) | pub fn grid_follows_camera(

FILE: src/canvas/mod.rs
  type CanvasPlugin (line 10) | pub struct CanvasPlugin;
  method build (line 13) | fn build(&self, app: &mut App) {

FILE: src/canvas/shadows/mod.rs
  type ShadowsPlugin (line 11) | pub struct ShadowsPlugin;
  method build (line 14) | fn build(&self, app: &mut App) {
  type CustomShadowMaterial (line 22) | pub struct CustomShadowMaterial {
  method fragment_shader (line 32) | fn fragment_shader() -> ShaderRef {

FILE: src/canvas/shadows/systems.rs
  type Shadow (line 11) | pub struct Shadow;
  function spawn_shadow (line 14) | pub fn spawn_shadow(
  function synchronise_shadow_sizes (line 56) | pub fn synchronise_shadow_sizes(

FILE: src/components.rs
  type MainCamera (line 6) | pub struct MainCamera;
  type EffectsCamera (line 9) | pub struct EffectsCamera;
  type Tab (line 12) | pub struct Tab {
  type Doc (line 21) | pub struct Doc {

FILE: src/lib.rs
  type VeloPlugin (line 24) | pub struct VeloPlugin;
  method build (line 26) | fn build(&self, app: &mut App) {

FILE: src/main.rs
  function main (line 4) | fn main() {

FILE: src/resources.rs
  type AppState (line 11) | pub struct AppState {
  type SaveDocRequest (line 21) | pub struct SaveDocRequest {
  type SaveTabRequest (line 27) | pub struct SaveTabRequest {
  type LoadDocRequest (line 33) | pub struct LoadDocRequest {
  type LoadTabRequest (line 38) | pub struct LoadTabRequest {
  type FontSystemState (line 45) | pub struct FontSystemState(pub Option<Handle<CosmicFont>>);

FILE: src/systems.rs
  function setup_velo_theme (line 14) | pub fn setup_velo_theme(mut commands: Commands, pkv: Res<PkvStore>) {
  function setup_camera (line 20) | pub fn setup_camera(mut commands: Commands, theme: Res<Theme>) {

FILE: src/themes.rs
  type Theme (line 5) | pub struct Theme {
  function velo_light (line 71) | pub fn velo_light() -> Theme {
  function velo_dark (line 139) | pub fn velo_dark() -> Theme {
  function get_theme_by_name (line 207) | pub fn get_theme_by_name(theme_name: &str) -> Theme {

FILE: src/ui_plugin/mod.rs
  type UiPlugin (line 87) | pub struct UiPlugin;
  type AddRect (line 90) | pub struct AddRect<T> {
  type SaveStore (line 96) | pub struct SaveStore {
  type NodeInteractionType (line 102) | pub enum NodeInteractionType {
  type NodeInteraction (line 112) | pub struct NodeInteraction {
  type UpdateDeleteDocBtn (line 118) | pub struct UpdateDeleteDocBtn;
  type CommChannels (line 121) | pub struct CommChannels {
  type NodeType (line 127) | pub enum NodeType {
  type TextPos (line 135) | pub enum TextPos {
  type JsonNodeText (line 142) | pub struct JsonNodeText {
  type JsonNode (line 148) | pub struct JsonNode<T> {
  type DrawingJsonNode (line 162) | pub struct DrawingJsonNode<T> {
  constant MAX_CHECKPOINTS (line 172) | pub const MAX_CHECKPOINTS: i32 = 7;
  constant MAX_SAVED_DOCS_IN_MEMORY (line 173) | pub const MAX_SAVED_DOCS_IN_MEMORY: i32 = 7;
  type UiState (line 176) | pub struct UiState {
  method build (line 195) | fn build(&self, app: &mut App) {
  function load_from_url (line 335) | fn load_from_url(mut commands: Commands) {
  function read_native_config (line 362) | fn read_native_config(mut app_state: ResMut<AppState>) {

FILE: src/ui_plugin/systems/active_editor_changed.rs
  function active_editor_changed (line 5) | pub fn active_editor_changed(

FILE: src/ui_plugin/systems/button_handlers.rs
  function rec_button_handlers (line 37) | pub fn rec_button_handlers(
  function change_color_pallete (line 344) | pub fn change_color_pallete(
  function change_text_pos (line 374) | pub fn change_text_pos(
  function change_arrow_type (line 400) | pub fn change_arrow_type(
  function new_doc_handler (line 418) | pub fn new_doc_handler(
  function rename_doc_handler (line 469) | pub fn rename_doc_handler(
  function delete_doc_handler (line 519) | pub fn delete_doc_handler(
  function save_doc_handler (line 574) | pub fn save_doc_handler(
  function export_to_file (line 593) | pub fn export_to_file(
  function set_window_property (line 629) | pub fn set_window_property(mut app_state: ResMut<AppState>, mut pkv: Res...
  type GistFile (line 642) | struct GistFile {
  type GistCreateRequest (line 647) | struct GistCreateRequest {
  function shared_doc_handler (line 653) | pub fn shared_doc_handler(
  function import_from_file (line 718) | pub fn import_from_file(
  function import_from_url (line 753) | pub fn import_from_url(
  function button_generic_handler (line 788) | pub fn button_generic_handler(
  function enable_drawing_mode (line 820) | pub fn enable_drawing_mode(
  function enable_two_points_draw_mode (line 845) | pub fn enable_two_points_draw_mode(
  function change_theme (line 880) | pub fn change_theme(

FILE: src/ui_plugin/systems/canvas_click.rs
  function canvas_click (line 8) | pub fn canvas_click(

FILE: src/ui_plugin/systems/clickable_links.rs
  function clickable_links (line 9) | pub fn clickable_links(
  function open_url_in_new_tab (line 77) | pub fn open_url_in_new_tab(url: &str) -> Result<(), wasm_bindgen::prelud...

FILE: src/ui_plugin/systems/create_new_node.rs
  function create_new_node (line 13) | pub fn create_new_node(

FILE: src/ui_plugin/systems/doc_list.rs
  function list_item_click (line 24) | pub fn list_item_click(
  function mouse_scroll_list (line 52) | pub fn mouse_scroll_list(
  function doc_list_del_button_update (line 76) | pub fn doc_list_del_button_update(
  function doc_list_ui_changed (line 92) | pub fn doc_list_ui_changed(
  function get_doc_name (line 142) | pub fn get_doc_name(

FILE: src/ui_plugin/systems/drawing.rs
  function entity_to_draw_selected_changed (line 22) | pub fn entity_to_draw_selected_changed(
  function set_focus_drawing (line 49) | pub fn set_focus_drawing(
  function drawing_two_points (line 77) | pub fn drawing_two_points(
  function drawing (line 270) | pub fn drawing(
  function update_drawing_position (line 377) | pub fn update_drawing_position(

FILE: src/ui_plugin/systems/effects.rs
  function update_particles_effect (line 9) | pub fn update_particles_effect(
  function create_particles_effect (line 43) | pub fn create_particles_effect(

FILE: src/ui_plugin/systems/entity_to_edit_changed.rs
  function entity_to_edit_changed (line 20) | pub fn entity_to_edit_changed(

FILE: src/ui_plugin/systems/init_layout/add_arrow.rs
  function add_arrow (line 10) | pub fn add_arrow(

FILE: src/ui_plugin/systems/init_layout/add_color.rs
  function add_color (line 7) | pub fn add_color(commands: &mut Commands, theme: &Res<Theme>, color: (St...

FILE: src/ui_plugin/systems/init_layout/add_effect.rs
  function add_effect (line 5) | pub fn add_effect(

FILE: src/ui_plugin/systems/init_layout/add_front_back.rs
  function add_front_back (line 10) | pub fn add_front_back(

FILE: src/ui_plugin/systems/init_layout/add_list.rs
  function add_list (line 21) | pub fn add_list(

FILE: src/ui_plugin/systems/init_layout/add_menu_button.rs
  function add_menu_button (line 9) | pub fn add_menu_button(

FILE: src/ui_plugin/systems/init_layout/add_pencil.rs
  function add_pencil (line 5) | pub fn add_pencil(

FILE: src/ui_plugin/systems/init_layout/add_search_box.rs
  function add_search_box (line 18) | pub fn add_search_box(

FILE: src/ui_plugin/systems/init_layout/add_text.rs
  function add_text (line 5) | pub fn add_text(

FILE: src/ui_plugin/systems/init_layout/add_text_pos.rs
  function add_text_pos (line 10) | pub fn add_text_pos(

FILE: src/ui_plugin/systems/init_layout/add_two_points_draw.rs
  function add_two_points_draw (line 8) | pub fn add_two_points_draw(

FILE: src/ui_plugin/systems/init_layout/add_visibility.rs
  function add_visibility (line 8) | pub fn add_visibility(

FILE: src/ui_plugin/systems/init_layout/init_layout.rs
  function init_layout (line 78) | pub fn init_layout(

FILE: src/ui_plugin/systems/init_layout/node_manipulation.rs
  function node_manipulation (line 8) | pub fn node_manipulation(
  function add_button_action (line 78) | fn add_button_action(

FILE: src/ui_plugin/systems/interactive_sprites.rs
  type HoldingState (line 13) | pub struct HoldingState {
  function interactive_node (line 19) | pub fn interactive_node(

FILE: src/ui_plugin/systems/keyboard.rs
  function keyboard_input_system (line 34) | pub fn keyboard_input_system(
  function insert_from_clipboard (line 244) | pub fn insert_from_clipboard(

FILE: src/ui_plugin/systems/load.rs
  function should_load_doc (line 31) | pub fn should_load_doc(request: Option<Res<LoadDocRequest>>) -> bool {
  function should_load_tab (line 35) | pub fn should_load_tab(request: Option<Res<LoadTabRequest>>) -> bool {
  function remove_load_tab_request (line 39) | pub fn remove_load_tab_request(world: &mut World) {
  function remove_load_doc_request (line 43) | pub fn remove_load_doc_request(world: &mut World) {
  function load_doc (line 47) | pub fn load_doc(
  function load_tab (line 102) | pub fn load_tab(

FILE: src/ui_plugin/systems/modal.rs
  function cancel_modal (line 19) | pub fn cancel_modal(
  function delete_doc (line 40) | fn delete_doc(
  function delete_tab (line 68) | fn delete_tab(
  function load_doc_handler (line 124) | pub fn load_doc_handler(
  function confirm_modal (line 153) | pub fn confirm_modal(
  function remove_from_storage (line 298) | fn remove_from_storage(

FILE: src/ui_plugin/systems/resize_node.rs
  function resize_entity_start (line 15) | pub fn resize_entity_start(
  function resize_entity_end (line 54) | pub fn resize_entity_end(
  function resize_entity_run (line 67) | pub fn resize_entity_run(

FILE: src/ui_plugin/systems/resize_window.rs
  function resize_notificator (line 12) | pub fn resize_notificator(

FILE: src/ui_plugin/systems/save.rs
  function should_save_doc (line 21) | pub fn should_save_doc(request: Option<Res<SaveDocRequest>>) -> bool {
  function should_save_tab (line 25) | pub fn should_save_tab(request: Option<Res<SaveTabRequest>>) -> bool {
  function remove_save_doc_request (line 29) | pub fn remove_save_doc_request(world: &mut World) {
  function remove_save_tab_request (line 33) | pub fn remove_save_tab_request(world: &mut World) {
  function save_doc (line 37) | pub fn save_doc(
  function save_to_store (line 63) | pub fn save_to_store(
  function save_tab (line 128) | pub fn save_tab(
  function test_save_doc1 (line 247) | fn test_save_doc1() {
  function test_save_doc2 (line 305) | fn test_save_doc2() {
  function test_save_doc3 (line 367) | fn test_save_doc3() {

FILE: src/ui_plugin/systems/search.rs
  type SearchIndexState (line 36) | pub struct SearchIndexState {
  type NodeSearchLocation (line 43) | pub struct NodeSearchLocation {
  function search_box_click (line 49) | pub fn search_box_click(
  function search_box_text_changed (line 85) | pub fn search_box_text_changed(
  function init_search_index (line 131) | pub fn init_search_index(mut app_state: ResMut<AppState>) {
  function initialize_search_index (line 145) | pub fn initialize_search_index(dir: PathBuf) -> tantivy::Index {
  function update_search_index (line 158) | pub fn update_search_index(
  constant MAX_SEARCH_RESULTS (line 195) | const MAX_SEARCH_RESULTS: usize = 1000;
  function clear_tabs_index (line 197) | pub fn clear_tabs_index(index: &Index, tab_ids: &HashSet<Uuid>) -> tanti...
  function clear_doc_index (line 213) | pub fn clear_doc_index(index: &Index, doc_id: &Uuid) -> tantivy::Result<...
  function fuzzy_search (line 227) | pub fn fuzzy_search(index: &Index, query: &str) -> tantivy::Result<Vec<N...
  function highlight_search_match_nodes (line 272) | fn highlight_search_match_nodes(
  function test_fuzzy_search (line 304) | fn test_fuzzy_search() {
  function test_clear_tab (line 345) | fn test_clear_tab() {
  function test_clear_doc (line 392) | fn test_clear_doc() {

FILE: src/ui_plugin/systems/set_focused_entity.rs
  function set_focused_entity (line 5) | pub fn set_focused_entity(

FILE: src/ui_plugin/systems/tabs.rs
  function select_tab_handler (line 17) | pub fn select_tab_handler(
  function add_tab_handler (line 68) | pub fn add_tab_handler(
  function rename_tab_handler (line 106) | pub fn rename_tab_handler(
  function delete_tab_handler (line 158) | pub fn delete_tab_handler(

FILE: src/ui_plugin/systems/update_rectangle_position.rs
  function update_rectangle_position (line 10) | pub fn update_rectangle_position(

FILE: src/ui_plugin/ui_helpers/add_list_item.rs
  function add_list_item (line 21) | pub fn add_list_item(

FILE: src/ui_plugin/ui_helpers/add_tab.rs
  function add_tab (line 15) | pub fn add_tab(

FILE: src/ui_plugin/ui_helpers/components.rs
  type GenericButton (line 8) | pub struct GenericButton;
  type Root (line 11) | pub struct Root;
  type Menu (line 14) | pub struct Menu;
  type AddTab (line 17) | pub struct AddTab;
  type DeleteTab (line 20) | pub struct DeleteTab {
  type Tooltip (line 25) | pub struct Tooltip;
  type NewDoc (line 28) | pub struct NewDoc;
  type ParticlesEffect (line 31) | pub struct ParticlesEffect;
  type DrawPencil (line 34) | pub struct DrawPencil;
  type TwoPointsDrawType (line 37) | pub enum TwoPointsDrawType {
  type TwoPointsDraw (line 45) | pub struct TwoPointsDraw {
  type DocList (line 50) | pub struct DocList;
  type SaveDoc (line 53) | pub struct SaveDoc;
  type ExportToFile (line 56) | pub struct ExportToFile;
  type SetWindowProperty (line 59) | pub struct SetWindowProperty;
  type ImportFromFile (line 62) | pub struct ImportFromFile;
  type ImportFromUrl (line 65) | pub struct ImportFromUrl;
  type ShareDoc (line 68) | pub struct ShareDoc;
  type ChangeTheme (line 71) | pub struct ChangeTheme;
  type DeleteDoc (line 74) | pub struct DeleteDoc {
  type TabButton (line 79) | pub struct TabButton {
  type TabContainer (line 83) | pub struct TabContainer {
  type SearchButton (line 88) | pub struct SearchButton {
  type SearchText (line 93) | pub struct SearchText {
  type ScrollingList (line 98) | pub struct ScrollingList {
  type DocListItemContainer (line 103) | pub struct DocListItemContainer {
  type DocListItemButton (line 108) | pub struct DocListItemButton {
  type ChangeColor (line 113) | pub struct ChangeColor {
  type TextPosMode (line 118) | pub struct TextPosMode {
  type MainPanel (line 123) | pub struct MainPanel;
  type BottomPanel (line 126) | pub struct BottomPanel;
  type LeftPanel (line 129) | pub struct LeftPanel;
  type LeftPanelControls (line 132) | pub struct LeftPanelControls;
  type LeftPanelExplorer (line 135) | pub struct LeftPanelExplorer;
  type VeloShape (line 138) | pub struct VeloShape {
  type VeloNode (line 145) | pub struct VeloNode {
  type ButtonTypes (line 150) | pub enum ButtonTypes {
  type ButtonAction (line 163) | pub struct ButtonAction {
  type EditableText (line 169) | pub struct EditableText {
  type RawText (line 174) | pub struct RawText {
  type BevyMarkdownView (line 180) | pub struct BevyMarkdownView {
  type ResizeMarker (line 186) | pub enum ResizeMarker {
  type ModalTop (line 195) | pub struct ModalTop {
  type ModalAction (line 201) | pub enum ModalAction {
    method fmt (line 210) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  type ModalConfirm (line 222) | pub struct ModalConfirm {
  type ModalCancel (line 228) | pub struct ModalCancel {
  type InteractiveNode (line 233) | pub struct InteractiveNode;
  type Drawing (line 236) | pub struct Drawing<T> {

FILE: src/ui_plugin/ui_helpers/spawn_modal.rs
  function spawn_modal (line 19) | pub fn spawn_modal(

FILE: src/ui_plugin/ui_helpers/spawn_node.rs
  type NodeMeta (line 22) | pub struct NodeMeta {
  function spawn_sprite_node (line 35) | pub fn spawn_sprite_node(
  function spawn_resize_marker (line 268) | fn spawn_resize_marker(
  function spawn_arrow_marker (line 305) | fn spawn_arrow_marker(

FILE: src/ui_plugin/ui_helpers/ui_helpers.rs
  function add_rectangle_txt (line 20) | pub fn add_rectangle_txt(theme: &Res<Theme>, text: String) -> TextBundle {
  type TooltipPosition (line 31) | pub enum TooltipPosition {
  function get_tooltip (line 36) | pub fn get_tooltip(

FILE: src/utils.rs
  type ReflectableUuid (line 19) | pub struct ReflectableUuid(pub Uuid);
    method generate (line 27) | pub fn generate() -> Self {
  type UserPreferences (line 22) | pub struct UserPreferences {
  function get_timestamp (line 34) | pub fn get_timestamp() -> f64 {
  function get_timestamp (line 39) | pub fn get_timestamp() -> f64 {
  function load_doc_to_memory (line 46) | pub fn load_doc_to_memory(
  type Config (line 70) | pub struct Config {
  function read_config_file (line 75) | pub fn read_config_file() -> Option<Config> {
  method from (line 90) | fn from(pos: TextPos) -> Self {
  method from (line 99) | fn from(pos: CosmicTextPos) -> Self {
  function bevy_color_to_cosmic (line 107) | pub fn bevy_color_to_cosmic(color: bevy::prelude::Color) -> cosmic_text:...
  function get_theme_key (line 116) | pub fn get_theme_key(pkv: &PkvStore) -> String {
Condensed preview — 92 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (513K chars).
[
  {
    "path": ".cargo/config.toml",
    "chars": 61,
    "preview": "[target.wasm32-unknown-unknown]\nrunner = \"wasm-server-runner\""
  },
  {
    "path": ".github/workflows/deploy-wasm.yml",
    "chars": 1984,
    "preview": "name: Build and Deploy WebAssembly to Web Branch\non:\n  push:\n    branches: [main]\n\njobs:\n  build_and_deploy:\n    runs-on"
  },
  {
    "path": ".github/workflows/pr.yml",
    "chars": 3479,
    "preview": "---\non:\n  pull_request: null\nname: pr checks\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 5240,
    "preview": "name: release\non:\n  workflow_dispatch:\n    inputs:\n      version:\n        description: \"Version\"\n        required: true\n"
  },
  {
    "path": ".gitignore",
    "chars": 52,
    "preview": "/target\n.idea\n.vscode\nvelo.json\nichart.json\ndata\nout"
  },
  {
    "path": "Cargo.toml",
    "chars": 2156,
    "preview": "[package]\nname = \"velo\"\nlicense = \"MIT OR Apache-2.0\"\ndescription = \"App for brainstorming & sharing ideas 🦀 Learning Pr"
  },
  {
    "path": "Cross.toml",
    "chars": 53,
    "preview": "[build.env]\npassthrough = [\n    \"BEVY_ASSET_PATH\",\n]\n"
  },
  {
    "path": "LICENSE-APACHE",
    "chars": 10172,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "LICENSE-MIT",
    "chars": 1022,
    "preview": "Permission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentati"
  },
  {
    "path": "Readme.md",
    "chars": 5170,
    "preview": "# Velo 🚵‍♀️🚵\n![Rust](https://img.shields.io/badge/Rust-lang-000000.svg?style=flat&logo=rust)[![codecov](https://codecov."
  },
  {
    "path": "assets/shaders/grid.wgsl",
    "chars": 1164,
    "preview": "#import bevy_sprite::mesh2d_vertex_output MeshVertexOutput\n\nstruct CustomGridMaterial {\n    line_color: vec4<f32>,\n    g"
  },
  {
    "path": "assets/shaders/shadows.wgsl",
    "chars": 2770,
    "preview": "//! https://www.w3.org/TR/WGSL/#builtin-functions\n\n// #import bevy_sprite::mesh2d_vertex_output MeshVertexOutput\n\n// tak"
  },
  {
    "path": "code_of_conduct.md",
    "chars": 5188,
    "preview": "# Contributor Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in o"
  },
  {
    "path": "contributing.md",
    "chars": 786,
    "preview": "# Contributing to the Velo\n\nWe welcome contributions from the community to help improve this project. Whether you're int"
  },
  {
    "path": "crates/bevy_markdown/Cargo.toml",
    "chars": 540,
    "preview": "[package]\nname = \"bevy_markdown\"\nversion = \"0.2.0\"\nlicense = \"MIT OR Apache-2.0\"\ndescription = \"Bevy markdown renderer\"\n"
  },
  {
    "path": "crates/bevy_markdown/LICENSE-APACHE",
    "chars": 10172,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "crates/bevy_markdown/LICENSE-MIT",
    "chars": 2152,
    "preview": "MIT License\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associate"
  },
  {
    "path": "crates/bevy_markdown/Readme.md",
    "chars": 462,
    "preview": "# bevy_markdown\n\nBuilt for `bevy_cosmic_edit` plugin.\n\nFeatures:\n\n- [x] bold text style\n- [x] italic text style\n- [x] li"
  },
  {
    "path": "crates/bevy_markdown/src/lib.rs",
    "chars": 22490,
    "preview": "use std::vec;\n\nuse cosmic_text::{AttrsOwned, Color, Weight};\nuse syntect::easy::HighlightLines;\nuse syntect::highlightin"
  },
  {
    "path": "crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_break.snap",
    "chars": 1462,
    "preview": "---\nsource: crates/bevy_markdown/src/lib.rs\nexpression: \"generate_markdown_lines(BevyMarkdown {\\n        markdown_theme,"
  },
  {
    "path": "crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_break_after_link.snap",
    "chars": 2570,
    "preview": "---\nsource: crates/bevy_markdown/src/lib.rs\nexpression: \"generate_markdown_lines(BevyMarkdown {\\n        markdown_theme,"
  },
  {
    "path": "crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_code.snap",
    "chars": 11478,
    "preview": "---\nsource: crates/bevy_markdown/src/lib.rs\nexpression: \"generate_markdown_lines(BevyMarkdown {\\n        markdown_theme,"
  },
  {
    "path": "crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_nested_ordered_list.snap",
    "chars": 7349,
    "preview": "---\nsource: crates/bevy_markdown/src/lib.rs\nexpression: \"generate_markdown_lines(BevyMarkdown {\\n        markdown_theme,"
  },
  {
    "path": "crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_nested_unordered_list.snap",
    "chars": 7405,
    "preview": "---\nsource: crates/bevy_markdown/src/lib.rs\nexpression: \"generate_markdown_lines(BevyMarkdown {\\n        markdown_theme,"
  },
  {
    "path": "crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_ordered_list.snap",
    "chars": 3920,
    "preview": "---\nsource: crates/bevy_markdown/src/lib.rs\nexpression: \"generate_markdown_lines(BevyMarkdown {\\n        markdown_theme,"
  },
  {
    "path": "crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_text_style.snap",
    "chars": 3934,
    "preview": "---\nsource: crates/bevy_markdown/src/lib.rs\nexpression: \"generate_markdown_lines(BevyMarkdown {\\n        markdown_theme,"
  },
  {
    "path": "crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_text_style_complicated.snap",
    "chars": 4626,
    "preview": "---\nsource: crates/bevy_markdown/src/lib.rs\nexpression: \"generate_markdown_lines(BevyMarkdown {\\n        markdown_theme,"
  },
  {
    "path": "crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_text_style_header.snap",
    "chars": 5572,
    "preview": "---\nsource: crates/bevy_markdown/src/lib.rs\nexpression: \"generate_markdown_lines(BevyMarkdown {\\n        markdown_theme,"
  },
  {
    "path": "crates/bevy_markdown/src/snapshots/bevy_markdown__tests__test_render_unordered_list.snap",
    "chars": 6219,
    "preview": "---\nsource: crates/bevy_markdown/src/lib.rs\nexpression: \"generate_markdown_lines(BevyMarkdown {\\n        markdown_theme,"
  },
  {
    "path": "docs/architecture.md",
    "chars": 31500,
    "preview": "**ATTENTION**\n\n_This doc may be outdated_\n\n# PreStartup\n\n_Runs once at the start of the app_\n\n## Systems\n\n- [VeloPlugin/"
  },
  {
    "path": "justfile",
    "chars": 461,
    "preview": "# Run native\nnative:\n    cargo run --release\n\n# Run wasm\nwasm:\n    cargo install wasm-server-runner\n    RUSTFLAGS=--cfg="
  },
  {
    "path": "security.md",
    "chars": 1880,
    "preview": "# Security Policy\n\n## Introduction\nThis security policy outlines the expectations and procedures for reporting and resol"
  },
  {
    "path": "src/canvas/arrow/components.rs",
    "chars": 1071,
    "preview": "use crate::utils::ReflectableUuid;\nuse bevy::prelude::*;\nuse serde::{Deserialize, Serialize};\n#[derive(\n    Component, C"
  },
  {
    "path": "src/canvas/arrow/events.rs",
    "chars": 381,
    "preview": "use bevy::prelude::Event;\n\nuse super::components::{ArrowConnect, ArrowType};\nuse crate::utils::ReflectableUuid;\n\n#[deriv"
  },
  {
    "path": "src/canvas/arrow/mod.rs",
    "chars": 466,
    "preview": "pub mod components;\npub mod events;\nmod systems;\nmod utils;\nuse bevy::{\n    app::{App, Plugin},\n    prelude::PreUpdate,\n"
  },
  {
    "path": "src/canvas/arrow/systems.rs",
    "chars": 5508,
    "preview": "use bevy::{prelude::*, window::PrimaryWindow};\n\nuse super::components::{ArrowConnect, ArrowMeta};\nuse super::events::{Cr"
  },
  {
    "path": "src/canvas/arrow/utils.rs",
    "chars": 5168,
    "preview": "use std::f32::consts::PI;\n\nuse bevy::prelude::*;\nuse bevy_prototype_lyon::{\n    prelude::{GeometryBuilder, Path, ShapeBu"
  },
  {
    "path": "src/canvas/grid/mod.rs",
    "chars": 1145,
    "preview": "use bevy::{\n    prelude::*,\n    reflect::{TypePath, TypeUuid},\n    render::render_resource::{AsBindGroup, ShaderRef},\n  "
  },
  {
    "path": "src/canvas/grid/systems.rs",
    "chars": 3540,
    "preview": "use crate::{components::MainCamera, themes::Theme};\n\nuse super::CustomGridMaterial;\nuse bevy::{\n    prelude::*,\n    spri"
  },
  {
    "path": "src/canvas/mod.rs",
    "chars": 290,
    "preview": "pub mod arrow;\npub mod grid;\npub mod shadows;\n\nuse arrow::*;\nuse bevy::app::{App, Plugin};\nuse grid::*;\nuse shadows::*;\n"
  },
  {
    "path": "src/canvas/shadows/mod.rs",
    "chars": 861,
    "preview": "use bevy::{\n    prelude::*,\n    reflect::{TypePath, TypeUuid},\n    render::render_resource::{AsBindGroup, ShaderRef},\n  "
  },
  {
    "path": "src/canvas/shadows/systems.rs",
    "chars": 2187,
    "preview": "use bevy::{\n    prelude::{shape::Quad, *},\n    sprite::{MaterialMesh2dBundle, Mesh2dHandle},\n};\n\nuse crate::themes::Them"
  },
  {
    "path": "src/components.rs",
    "chars": 602,
    "preview": "use crate::utils::ReflectableUuid;\nuse bevy::prelude::*;\nuse serde::{Deserialize, Serialize};\nuse std::collections::VecD"
  },
  {
    "path": "src/lib.rs",
    "chars": 1908,
    "preview": "mod canvas;\nmod components;\nmod resources;\nmod systems;\nmod themes;\nmod ui_plugin;\nmod utils;\n\nuse bevy::{prelude::*, wi"
  },
  {
    "path": "src/macros.rs",
    "chars": 164,
    "preview": "macro_rules! pair_struct {\n    ($obj:ident . $field:ident) => {{\n        let field_val = $obj.$field;\n        (stringify"
  },
  {
    "path": "src/main.rs",
    "chars": 288,
    "preview": "use bevy::prelude::*;\nuse velo::VeloPlugin;\n\nfn main() {\n    #[cfg(target_arch = \"wasm32\")]\n    console_error_panic_hook"
  },
  {
    "path": "src/resources.rs",
    "chars": 1237,
    "preview": "use crate::components::Doc;\n#[cfg(not(target_arch = \"wasm32\"))]\nuse crate::ui_plugin::SearchIndexState;\nuse crate::utils"
  },
  {
    "path": "src/systems.rs",
    "chars": 1800,
    "preview": "use crate::{\n    components::{EffectsCamera, MainCamera},\n    themes::{get_theme_by_name, Theme},\n    utils::get_theme_k"
  },
  {
    "path": "src/themes.rs",
    "chars": 8619,
    "preview": "use bevy::prelude::*;\nuse serde::{Deserialize, Serialize};\n\n#[derive(Resource, Debug, Serialize, Deserialize)]\npub struc"
  },
  {
    "path": "src/ui_plugin/mod.rs",
    "chars": 10515,
    "preview": "use async_channel::{Receiver, Sender};\nuse bevy::prelude::*;\n\nuse serde::{Deserialize, Serialize};\n\nuse crate::resources"
  },
  {
    "path": "src/ui_plugin/systems/active_editor_changed.rs",
    "chars": 1053,
    "preview": "use bevy::prelude::*;\nuse bevy_cosmic_edit::{ActiveEditor, CosmicEdit, CosmicFont};\nuse cosmic_text::{Action, Edit};\n\npu"
  },
  {
    "path": "src/ui_plugin/systems/button_handlers.rs",
    "chars": 39620,
    "preview": "#![allow(clippy::duplicate_mod)]\nuse std::collections::HashMap;\nuse std::{collections::VecDeque, time::Duration};\n\nuse b"
  },
  {
    "path": "src/ui_plugin/systems/canvas_click.rs",
    "chars": 946,
    "preview": "use bevy::{prelude::*, window::PrimaryWindow};\n\nuse super::{\n    ui_helpers::{MainPanel, RawText},\n    NodeInteraction, "
  },
  {
    "path": "src/ui_plugin/systems/clickable_links.rs",
    "chars": 3895,
    "preview": "use bevy::{prelude::*, window::PrimaryWindow};\nuse bevy_cosmic_edit::{get_node_cursor_pos, get_x_offset, get_y_offset, C"
  },
  {
    "path": "src/ui_plugin/systems/create_new_node.rs",
    "chars": 2169,
    "preview": "use bevy::{prelude::*, window::PrimaryWindow};\nuse bevy_cosmic_edit::CosmicFont;\n\nuse crate::{\n    canvas::shadows::Cust"
  },
  {
    "path": "src/ui_plugin/systems/doc_list.rs",
    "chars": 5390,
    "preview": "use bevy::{\n    input::mouse::{MouseScrollUnit, MouseWheel},\n    prelude::*,\n    window::PrimaryWindow,\n};\nuse bevy_cosm"
  },
  {
    "path": "src/ui_plugin/systems/drawing.rs",
    "chars": 16223,
    "preview": "use std::{f32::consts::PI, time::Duration};\n\nuse bevy::{prelude::*, window::PrimaryWindow};\nuse bevy_prototype_lyon::pre"
  },
  {
    "path": "src/ui_plugin/systems/effects.rs",
    "chars": 6179,
    "preview": "#![allow(clippy::duplicate_mod)]\nuse bevy::prelude::*;\nuse bevy::render::view::RenderLayers;\n\nuse super::ui_helpers::Par"
  },
  {
    "path": "src/ui_plugin/systems/entity_to_edit_changed.rs",
    "chars": 10261,
    "preview": "use std::collections::VecDeque;\n\nuse bevy::prelude::*;\nuse bevy_cosmic_edit::{\n    cosmic_edit_set_text, get_cosmic_text"
  },
  {
    "path": "src/ui_plugin/systems/init_layout/add_arrow.rs",
    "chars": 2811,
    "preview": "use bevy::prelude::*;\n\nuse crate::{\n    themes::Theme,\n    ui_plugin::ui_helpers::{GenericButton, TooltipPosition},\n};\n\n"
  },
  {
    "path": "src/ui_plugin/systems/init_layout/add_color.rs",
    "chars": 1627,
    "preview": "use bevy::prelude::*;\n\nuse crate::{themes::Theme, ui_plugin::ui_helpers::GenericButton};\n\nuse super::ui_helpers::ChangeC"
  },
  {
    "path": "src/ui_plugin/systems/init_layout/add_effect.rs",
    "chars": 2198,
    "preview": "use bevy::{prelude::*, text::BreakLineOn};\n\nuse crate::{themes::Theme, ui_plugin::ui_helpers::GenericButton};\n\npub fn ad"
  },
  {
    "path": "src/ui_plugin/systems/init_layout/add_front_back.rs",
    "chars": 2189,
    "preview": "use bevy::prelude::*;\n\nuse crate::{\n    themes::Theme,\n    ui_plugin::ui_helpers::{GenericButton, TooltipPosition},\n};\n\n"
  },
  {
    "path": "src/ui_plugin/systems/init_layout/add_list.rs",
    "chars": 2602,
    "preview": "use std::collections::{HashMap, VecDeque};\n\nuse bevy::{\n    a11y::{\n        accesskit::{NodeBuilder, Role},\n        Acce"
  },
  {
    "path": "src/ui_plugin/systems/init_layout/add_menu_button.rs",
    "chars": 6647,
    "preview": "use bevy::{prelude::*, text::BreakLineOn};\n\nuse crate::{\n    themes::Theme,\n    ui_plugin::ui_helpers::{get_tooltip, Gen"
  },
  {
    "path": "src/ui_plugin/systems/init_layout/add_pencil.rs",
    "chars": 2208,
    "preview": "use bevy::{prelude::*, text::BreakLineOn};\n\nuse crate::{themes::Theme, ui_plugin::ui_helpers::GenericButton};\n\npub fn ad"
  },
  {
    "path": "src/ui_plugin/systems/init_layout/add_search_box.rs",
    "chars": 2499,
    "preview": "use bevy::prelude::*;\nuse bevy_cosmic_edit::{\n    spawn_cosmic_edit, CosmicEditMeta, CosmicFont, CosmicMetrics, CosmicNo"
  },
  {
    "path": "src/ui_plugin/systems/init_layout/add_text.rs",
    "chars": 2194,
    "preview": "use bevy::{prelude::*, text::BreakLineOn};\n\nuse crate::{themes::Theme, ui_plugin::ui_helpers::GenericButton};\n\npub fn ad"
  },
  {
    "path": "src/ui_plugin/systems/init_layout/add_text_pos.rs",
    "chars": 3013,
    "preview": "use bevy::{prelude::*, text::BreakLineOn};\n\nuse crate::{\n    themes::Theme,\n    ui_plugin::ui_helpers::{get_tooltip, Gen"
  },
  {
    "path": "src/ui_plugin/systems/init_layout/add_two_points_draw.rs",
    "chars": 2608,
    "preview": "use bevy::{prelude::*, text::BreakLineOn};\n\nuse crate::{\n    themes::Theme,\n    ui_plugin::ui_helpers::{GenericButton, T"
  },
  {
    "path": "src/ui_plugin/systems/init_layout/add_visibility.rs",
    "chars": 3197,
    "preview": "use bevy::{prelude::*, text::BreakLineOn};\n\nuse crate::{\n    themes::Theme,\n    ui_plugin::ui_helpers::{get_tooltip, But"
  },
  {
    "path": "src/ui_plugin/systems/init_layout/init_layout.rs",
    "chars": 22152,
    "preview": "#![allow(clippy::duplicate_mod)]\nuse bevy::prelude::*;\n\nuse bevy::window::PrimaryWindow;\nuse bevy_cosmic_edit::{create_c"
  },
  {
    "path": "src/ui_plugin/systems/init_layout/node_manipulation.rs",
    "chars": 4521,
    "preview": "use bevy::{prelude::*, text::BreakLineOn};\n\nuse crate::{\n    themes::Theme,\n    ui_plugin::ui_helpers::{get_tooltip, But"
  },
  {
    "path": "src/ui_plugin/systems/interactive_sprites.rs",
    "chars": 7034,
    "preview": "use bevy::{prelude::*, window::PrimaryWindow};\n\nuse crate::{components::MainCamera, utils::get_timestamp};\n\nuse std::tim"
  },
  {
    "path": "src/ui_plugin/systems/keyboard.rs",
    "chars": 11438,
    "preview": "#![allow(clippy::duplicate_mod)]\nuse bevy::{\n    prelude::*,\n    render::render_resource::{Extent3d, TextureDimension, T"
  },
  {
    "path": "src/ui_plugin/systems/load.rs",
    "chars": 10489,
    "preview": "use base64::{engine::general_purpose, Engine};\nuse bevy::{\n    prelude::*,\n    render::render_resource::{Extent3d, Textu"
  },
  {
    "path": "src/ui_plugin/systems/modal.rs",
    "chars": 13235,
    "preview": "use std::collections::HashMap;\nuse std::fs::canonicalize;\nuse std::path::PathBuf;\n\nuse bevy::prelude::*;\nuse bevy::tasks"
  },
  {
    "path": "src/ui_plugin/systems/resize_node.rs",
    "chars": 9643,
    "preview": "use super::{\n    ui_helpers::{ResizeMarker, VeloShape},\n    NodeInteraction, NodeType, RawText, RedrawArrow, VeloNode,\n}"
  },
  {
    "path": "src/ui_plugin/systems/resize_window.rs",
    "chars": 1390,
    "preview": "use bevy::{prelude::*, window::WindowResized};\nuse bevy_cosmic_edit::CosmicEdit;\nuse cosmic_text::Edit;\n\nuse crate::reso"
  },
  {
    "path": "src/ui_plugin/systems/save.rs",
    "chars": 16712,
    "preview": "use base64::{engine::general_purpose, Engine};\nuse bevy::prelude::*;\n\nuse bevy_cosmic_edit::CosmicEdit;\nuse bevy_pkv::Pk"
  },
  {
    "path": "src/ui_plugin/systems/search.rs",
    "chars": 14887,
    "preview": "use bevy::prelude::*;\nuse bevy::window::PrimaryWindow;\n\nuse bevy_cosmic_edit::get_cosmic_text;\nuse bevy_cosmic_edit::Act"
  },
  {
    "path": "src/ui_plugin/systems/set_focused_entity.rs",
    "chars": 1960,
    "preview": "use bevy::{prelude::*, window::PrimaryWindow};\n\nuse super::{ui_helpers::RawText, NodeInteraction, UiState};\n\npub fn set_"
  },
  {
    "path": "src/ui_plugin/systems/tabs.rs",
    "chars": 7467,
    "preview": "use std::{collections::VecDeque, time::Duration};\n\nuse bevy::prelude::*;\n\nuse bevy::window::PrimaryWindow;\nuse bevy_cosm"
  },
  {
    "path": "src/ui_plugin/systems/update_rectangle_position.rs",
    "chars": 2164,
    "preview": "use bevy::prelude::*;\n\nuse crate::{canvas::arrow::events::RedrawArrow, components::MainCamera};\n\nuse super::{\n    ui_hel"
  },
  {
    "path": "src/ui_plugin/ui_helpers/add_list_item.rs",
    "chars": 4036,
    "preview": "use bevy::{\n    a11y::{\n        accesskit::{NodeBuilder, Role},\n        AccessibilityNode,\n    },\n    prelude::*,\n};\nuse"
  },
  {
    "path": "src/ui_plugin/ui_helpers/add_tab.rs",
    "chars": 4142,
    "preview": "use bevy::prelude::*;\nuse bevy_cosmic_edit::{\n    spawn_cosmic_edit, CosmicEditMeta, CosmicFont, CosmicMetrics, CosmicNo"
  },
  {
    "path": "src/ui_plugin/ui_helpers/components.rs",
    "chars": 4420,
    "preview": "use crate::{ui_plugin::NodeType, utils::ReflectableUuid};\nuse bevy::prelude::*;\nuse bevy_markdown::TextSpanMetadata;\n\nus"
  },
  {
    "path": "src/ui_plugin/ui_helpers/spawn_modal.rs",
    "chars": 9944,
    "preview": "use bevy_cosmic_edit::{\n    spawn_cosmic_edit, ActiveEditor, CosmicEditMeta, CosmicFont, CosmicMetrics, CosmicNode,\n    "
  },
  {
    "path": "src/ui_plugin/ui_helpers/spawn_node.rs",
    "chars": 11193,
    "preview": "use bevy_cosmic_edit::{\n    spawn_cosmic_edit, ActiveEditor, CosmicEditMeta, CosmicEditSprite, CosmicFont, CosmicMetrics"
  },
  {
    "path": "src/ui_plugin/ui_helpers/ui_helpers.rs",
    "chars": 2147,
    "preview": "use bevy::{prelude::*, text::BreakLineOn};\n\nuse crate::themes::Theme;\n#[path = \"components.rs\"]\nmod components;\npub use "
  },
  {
    "path": "src/utils.rs",
    "chars": 3599,
    "preview": "use bevy::prelude::*;\n\nuse bevy_cosmic_edit::CosmicTextPos;\nuse serde::{Deserialize, Serialize};\n\nuse crate::resources::"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the StaffEngineer/velo GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 92 files (479.8 KB), approximately 105.4k tokens, and a symbol index with 272 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!