Some checks failed
Update All Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Triage Project Sync (#84) / Sync triage project (push) Has been cancelled
release_nightly / notify_on_failure (push) Has been cancelled
release_nightly / check_style (push) Has been cancelled
release_nightly / run_tests_windows (push) Has been cancelled
release_nightly / clippy_windows (push) Has been cancelled
release_nightly / bundle_linux_aarch64 (push) Has been cancelled
release_nightly / bundle_linux_x86_64 (push) Has been cancelled
release_nightly / bundle_mac_aarch64 (push) Has been cancelled
release_nightly / bundle_mac_x86_64 (push) Has been cancelled
release_nightly / bundle_windows_aarch64 (push) Has been cancelled
release_nightly / bundle_windows_x86_64 (push) Has been cancelled
release_nightly / build_nix_linux_x86_64 (push) Has been cancelled
release_nightly / build_nix_mac_aarch64 (push) Has been cancelled
release_nightly / update_nightly_tag (push) Has been cancelled
Hotfix Review Monitor / check-hotfix-reviews (push) Has been cancelled
Stale PR Review Reminder / check-stale-prs (push) Has been cancelled
Update Weekly Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Bump collab-staging Tag / update-collab-staging-tag (push) Has been cancelled
compliance_check / scheduled_compliance_check (push) Has been cancelled
Single-commit orphan branch: full zed-industries/zed @ 8c74db0 source tree with a 3-file patch applied (no upstream history). Patch (crates/gpui_linux/src/linux/wayland/): - serial.rs: add SerialKind::KeyboardEnter - client.rs: store wl_keyboard.enter serial; add latest_serial_of() - window.rs: activate() uses keyboard-enter serial (Mutter focus gate) Mutter honors window activation only when the token carries the keyboard- focus serial from wl_keyboard.enter; GPUI used a stale mouse-press serial. See docs/tray-window-focus-wayland.md in logiguard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
133 lines
5.2 KiB
Rust
133 lines
5.2 KiB
Rust
pub use derive_refineable::Refineable;
|
|
|
|
/// A trait for types that can be refined with partial updates.
|
|
///
|
|
/// The `Refineable` trait enables hierarchical configuration patterns where a base configuration
|
|
/// can be selectively overridden by refinements. This is particularly useful for styling and
|
|
/// settings, and theme hierarchies.
|
|
///
|
|
/// # Derive Macro
|
|
///
|
|
/// The `#[derive(Refineable)]` macro automatically generates a companion refinement type and
|
|
/// implements this trait. For a struct `Style`, it creates `StyleRefinement` where each field is
|
|
/// wrapped appropriately:
|
|
///
|
|
/// - **Refineable fields** (marked with `#[refineable]`): Become the corresponding refinement type
|
|
/// (e.g., `Bar` becomes `BarRefinement`, or `BarRefinement` remains `BarRefinement`)
|
|
/// - **Optional fields** (`Option<T>`): Remain as `Option<T>`
|
|
/// - **Regular fields**: Become `Option<T>`
|
|
///
|
|
/// ## Attributes
|
|
///
|
|
/// The derive macro supports these attributes on the struct:
|
|
/// - `#[refineable(Debug)]`: Implements `Debug` for the refinement type
|
|
/// - `#[refineable(Serialize)]`: Derives `Serialize` which skips serializing `None`
|
|
/// - `#[refineable(OtherTrait)]`: Derives additional traits on the refinement type
|
|
///
|
|
/// Fields can be marked with:
|
|
/// - `#[refineable]`: Field is itself refineable (uses nested refinement type)
|
|
pub trait Refineable: Clone {
|
|
type Refinement: Refineable<Refinement = Self::Refinement> + IsEmpty + Default;
|
|
|
|
/// Applies the given refinement to this instance, modifying it in place.
|
|
///
|
|
/// Only non-empty values in the refinement are applied.
|
|
///
|
|
/// * For refineable fields, this recursively calls `refine`.
|
|
/// * For other fields, the value is replaced if present in the refinement.
|
|
fn refine(&mut self, refinement: &Self::Refinement);
|
|
|
|
/// Returns a new instance with the refinement applied, equivalent to cloning `self` and calling
|
|
/// `refine` on it.
|
|
fn refined(self, refinement: Self::Refinement) -> Self;
|
|
|
|
/// Creates an instance from a cascade by merging all refinements atop the default value.
|
|
fn from_cascade(cascade: &Cascade<Self>) -> Self
|
|
where
|
|
Self: Default + Sized,
|
|
{
|
|
Self::default().refined(cascade.merged())
|
|
}
|
|
|
|
/// Returns `true` if this instance would contain all values from the refinement.
|
|
///
|
|
/// For refineable fields, this recursively checks `is_superset_of`. For other fields, this
|
|
/// checks if the refinement's `Some` values match this instance's values.
|
|
fn is_superset_of(&self, refinement: &Self::Refinement) -> bool;
|
|
|
|
/// Returns a refinement that represents the difference between this instance and the given
|
|
/// refinement.
|
|
///
|
|
/// For refineable fields, this recursively calls `subtract`. For other fields, the field is
|
|
/// `None` if the field's value is equal to the refinement.
|
|
fn subtract(&self, refinement: &Self::Refinement) -> Self::Refinement;
|
|
}
|
|
|
|
pub trait IsEmpty {
|
|
/// Returns `true` if applying this refinement would have no effect.
|
|
fn is_empty(&self) -> bool;
|
|
}
|
|
|
|
/// A cascade of refinements that can be merged in priority order.
|
|
///
|
|
/// A cascade maintains a sequence of optional refinements where later entries
|
|
/// take precedence over earlier ones. The first slot (index 0) is always the
|
|
/// base refinement and is guaranteed to be present.
|
|
///
|
|
/// This is useful for implementing configuration hierarchies like CSS cascading,
|
|
/// where styles from different sources (user agent, user, author) are combined
|
|
/// with specific precedence rules.
|
|
pub struct Cascade<S: Refineable>(Vec<Option<S::Refinement>>);
|
|
|
|
impl<S: Refineable + Default> Default for Cascade<S> {
|
|
fn default() -> Self {
|
|
Self(vec![Some(Default::default())])
|
|
}
|
|
}
|
|
|
|
/// A handle to a specific slot in a cascade.
|
|
///
|
|
/// Slots are used to identify specific positions in the cascade where
|
|
/// refinements can be set or updated.
|
|
#[derive(Copy, Clone)]
|
|
pub struct CascadeSlot(usize);
|
|
|
|
impl<S: Refineable + Default> Cascade<S> {
|
|
/// Reserves a new slot in the cascade and returns a handle to it.
|
|
///
|
|
/// The new slot is initially empty (`None`) and can be populated later
|
|
/// using `set()`.
|
|
pub fn reserve(&mut self) -> CascadeSlot {
|
|
self.0.push(None);
|
|
CascadeSlot(self.0.len() - 1)
|
|
}
|
|
|
|
/// Returns a mutable reference to the base refinement (slot 0).
|
|
///
|
|
/// The base refinement is always present and serves as the foundation
|
|
/// for the cascade.
|
|
pub fn base(&mut self) -> &mut S::Refinement {
|
|
self.0[0].as_mut().unwrap()
|
|
}
|
|
|
|
/// Sets the refinement for a specific slot in the cascade.
|
|
///
|
|
/// Setting a slot to `None` effectively removes it from consideration
|
|
/// during merging.
|
|
pub fn set(&mut self, slot: CascadeSlot, refinement: Option<S::Refinement>) {
|
|
self.0[slot.0] = refinement
|
|
}
|
|
|
|
/// Merges all refinements in the cascade into a single refinement.
|
|
///
|
|
/// Refinements are applied in order, with later slots taking precedence.
|
|
/// Empty slots (`None`) are skipped during merging.
|
|
pub fn merged(&self) -> S::Refinement {
|
|
let mut merged = self.0[0].clone().unwrap();
|
|
for refinement in self.0.iter().skip(1).flatten() {
|
|
merged.refine(refinement);
|
|
}
|
|
merged
|
|
}
|
|
}
|