GPUI-CE Documentation

repository·main·Indexed 20 days ago

https://github.com/gpui-ce/gpui-ce

A community-driven, GPU-accelerated UI framework for Rust, forked from Zed's GPUI. It provides a hybrid immediate and retained mode API for building high-performance desktop applications on macOS and Linux. The framework features three programming registers: Entities for state management, Views for high-level declarative UI with a Tailwind-style API, and Elements for low-level imperative UI. It includes integrated services for actions, platform tasks, and an async executor.

Tokens
63.1K
Snippets
224
Records
304
Agent score
72%

What's inside GPUI-CE

  1. Use `App` and `Context<T>` for state access

    main

    GPUI provides different levels of context depending on the scope of your operation:

    • App: The root context. It owns all entities' data and provides access to the application's global state. Use it to read or update data referenced by any Entity<T>.
    • Context<T>: A specialized context provided when interacting with a specific Entity<T>. It includes methods specific to that entity, such as notifying observers and emitting events.

    Key Relationship: Context<T> dereferences into App. This means any function that accepts an &App can also accept a &Context<T>.

  2. How GPUI state, views, and elements work together

    main

    GPUI provides three primary layers for building applications:

    • State Management (Entities): Use Entitys to store application state that needs to be shared across different parts of the app. Entities are owned by GPUI and accessed via owned smart pointers (similar to Rc). See app::context for details.
    • High-level Declarative UI (Views): A View is an Entity that implements the Render trait. GPUI calls the render method on the root view every frame. Views build a tree of elements using a Tailwind-style API. The div element is a versatile tool for rendering.
    • Low-level Imperative UI (Elements): Elements are the fundamental building blocks. They provide an imperative API for maximum control, useful for high-performance needs like custom layouts for code editors or efficient large lists. See the element module for details.
  3. Work with `Window` and `Entity<T>`

    main

    GPUI separates the handles to state from the state itself using Window and Entity<T>:

    • Entity<T>: A handle to a structure that requires state. The actual data is owned by the App. You access and modify this data via context references. If T implements Render, the entity is considered a view. Entities support observation: you can register a closure to be called when notify is called on the entity's Context.
    • Window: Provides access to an application window's state. A window has a root view (an Entity implementing Render).

    Note: Window is not a context. To read or update a window's root view, you must pass a &mut App (or a context that dereferences to it) to the relevant functions. You can obtain a Window from a WindowHandle by calling WindowHandle::update.

  4. Understand GPUI's three programming registers

    main

    GPUI provides three distinct ways (registers) to build your application depending on the level of abstraction required:

    1. State Management with Entity

    Use Entity when you need to store application state that must be shared and communicated between different parts of your application. Entities are owned by GPUI and accessed via owned smart pointers (similar to Rc). See the app::context module for details.

    2. High-level Declarative UI with Views

    A View is an Entity that implements the Render trait. GPUI calls the render method on the root view of a window every frame. Views build a tree of elements, which are styled using a Tailwind-style API. The div element is a versatile tool for general rendering.

    3. Low-level Imperative UI with Elements

    Elements are the fundamental building blocks of the UI. They provide a wrapper around an imperative API, offering maximum flexibility. Use Elements for performance-critical tasks like efficient large-list rendering or implementing custom layouts (e.g., for a code editor). See the element module for details.

  5. Use GPUI services: Actions, Platform, and Executor

    main

    GPUI provides several specialized services to handle common application tasks:

    • Actions: Define user-defined structs to map keystrokes to logical UI operations (e.g., mapping cmd-q to a quit action). See the action module.
    • Platform Services: Access methods on app::App to perform system-level tasks like quitting the application or opening a URL.
    • Async Executor: An executor integrated with the platform's event loop for handling asynchronous tasks. See the executor module.
    • Testing: Use the [gpui::test] macro for application testing. Tests can use TestAppContext to simulate platform inputs. See app::test_context and test modules.
  6. Understand GPUI Contexts and the `cx` parameter

    main

    GPUI uses context parameters (conventionally named cx) to provide access to application state, services, and entities. Contexts act as references passed to functions to enable interaction with the global state, windows, and system services.

    There are two primary types of contexts:

    1. Synchronous Contexts: Passed as references (e.g., &mut App or &mut Context<T>). These are used for immediate state access and updates.
    2. Asynchronous Contexts: Created by calling .to_async() on a synchronous context. These have a 'static lifetime, allowing them to be held across .await points. Because an async context might outlive the window or app it originated from, interactions using an async context are fallible.
  7. Use GPUI-CE as a drop-in replacement via Cargo patch

    main

    Since GPUI-CE is a drop-in replacement for the mainline GPUI, you can use Cargo's [patch] mechanism to force existing libraries (like gpui-component) to use GPUI-CE instead of the original version.

    Use [patch.crates-io] if the dependency is coming from crates.io, or [patch."URL"] if it is coming from a specific git remote.

    # If they're using the crates release
    [patch.crates-io]
    gpui = { git = "https://github.com/gpui-ce/gpui-ce", package = "gpui-ce" }
    
    # If they're using the git remote
    [patch."https://github.com/zed-industries/zed.git"]
    gpui = { git = "https://github.com/gpui-ce/gpui-ce" }
  8. Guidelines for fixing build issues after upstream sync

    main

    When gpui-ce undergoes a 3-way merge with upstream Zed GPUI changes, build errors, warnings, or test failures may occur. Follow these rules to resolve them:

    Core Principles

    • Scope: Fix only what the merge/sync caused (e.g., renamed items, changed function signatures, or fallout in gpui-ce patches).
    • Warnings: Fix the root cause of every compile warning (unused imports, deprecated APIs, etc.). Do not use #[allow(...)] or _ prefixes to silence warnings unless it is the correct idiomatic fix.
    • Tests: Fix the underlying cause of failures. Do not delete tests, add #[ignore], or weaken assertions. If upstream behavior changed, update the test to match upstream's intent.
    • Style: Use minimal, idiomatic changes consistent with upstream's new API and gpui-ce code style. Preserve existing features like blur, kinetic scrolling, and the wgpu device-loss API.

    Dependency and Workspace Management

    • Vendored Crates: Utility crates (e.g., collections, util, scheduler) are vendored in-tree with gpui_ prefixes (e.g., gpui_collections, gpui_scheduler). Use these APIs; only hand-add to a vendored crate if the merge genuinely missed a required API.
    • Root Cargo.toml: If upstream adds new [workspace.dependencies], you must add them to the root Cargo.toml using gpui-ce sourcing conventions:
      • Vendored crates: Use path dependencies: { path = "crates/gpui_*", package = "gpui_*" }.
      • Font-kit: Use zed-font-kit.
      • Others: Use crates.io versions. Note: There are no longer any zed-industries/zed git dependencies.

    Packaging Newly Vendored Crates

    If a new tracked crate is added via merge, it must be adapted to the gpui-ce fork format:

    1. Naming: Set name to the gpui_* name, but keep [lib] name as the upstream name to avoid breaking use sites.
    2. Metadata: Match sibling crates for version, edition, publish, description, and repository.
    3. License: Set license = "Apache-2.0". Do not silently vendor non-Apache code; flag it for review.
    4. License File: Copy a sibling's LICENSE-APACHE file into the new crate directory (upstream symlinks may dangle).
    5. Workspace: Add the crate to the root Cargo.toml members.
  9. Install GPUI-CE via Cargo dependencies

    main

    You can add GPUI-CE to your project using either the crates release or the git version.

    Using the crates release: Use the gpui-ce package and the gpui_platform git dependency.

    Using the git version: Use the gpui package pointing directly to the gpui-ce repository.

    After adding the dependencies, use gpui::{import} as normal in your code.

    # Using the crates release
    [dependencies]
    gpui = { package = "gpui-ce", version = "0.3" }
    gpui_platform = { git = "https://github.com/gpui-ce/gpui-ce" }
    
    # For test support
    [dev-dependencies]
    gpui = { package = "gpui-ce", version = "0.3", features = ["test-support"] }
    # Using the git version
    gpui = { package = "gpui", git = "https://github.com/gpui-ce/gpui-ce" }
  10. Create a basic GPUI application

    main

    Every GPUI application begins with an Application. The lifecycle follows this pattern:

    1. Initialize the application using Application::new().
    2. Start the application loop by calling Application::run() and passing a callback.
    3. Inside the run callback, use App::open_window() to create a window.
    4. Register a root view within that window to begin rendering.

    For a complete implementation, refer to the gpui.rs example in the repository.

    // Conceptual workflow
    Application::new().run(|app| {
        app.open_window(WindowSettings::default(), |window: &mut Window| {
            window.set_root_view(|_| MyRootView::new());
        });
    });
  11. Set up macOS dependencies for GPUI

    main

    GPUI uses Metal for rendering on macOS. To ensure a working environment, follow these steps:

    1. Install Xcode: Download from the macOS App Store or the Apple Developer website. Launch Xcode after installation to ensure macOS components are installed.
    2. Install Xcode Command Line Tools:
      xcode-select --install
    3. Configure Xcode path: Ensure the command line tools point to your Xcode installation:
      sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
    xcode-select --install
    sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
  12. Install GPUI in your Rust project

    main

    GPUI is a hybrid immediate and retained mode, GPU-accelerated UI framework for Rust. It is currently in active development (pre-1.0) and requires the latest version of stable Rust. It is supported on macOS and Linux.

    To add GPUI to your project, include it in your Cargo.toml:

    gpui = { version = "*" }