first pass of merging in warp (doesn't build)

This commit is contained in:
Ryan Ward
2026-07-01 16:08:58 -05:00
parent 2f64909469
commit 4770ac06b5
3662 changed files with 414574 additions and 89772 deletions
@@ -3,7 +3,8 @@
use std::path::{Path, PathBuf};
use super::{in_memory::InMemoryPreferences, Error};
use super::in_memory::InMemoryPreferences;
use super::Error;
/// An implementation of the [`UserPreferences`] trait using a file for
/// persistence.
@@ -1,4 +1,5 @@
use std::{cell::RefCell, collections::HashMap};
use std::cell::RefCell;
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
@@ -1,5 +1,7 @@
use gloo_storage::errors::StorageError;
use gloo_storage::{LocalStorage, Storage};
use super::UserPreferences;
use gloo_storage::{errors::StorageError, LocalStorage, Storage};
/// An implementation of the [`UserPreferences`] trait using the local storage
/// property of the Web Storage API for persistence.
@@ -1,10 +1,11 @@
use std::io;
use windows_registry::{Key, CURRENT_USER};
use windows_result::HRESULT;
/// Store user preferences in the Windows Registry.
/// Modeled after https://github.com/neovide/neovide/blob/main/src/windows_utils.rs .
use super::UserPreferences;
use windows_registry::{Key, CURRENT_USER};
use windows_result::HRESULT;
pub struct RegistryBackedPreferences {
app_key_path: String,
@@ -1,7 +1,7 @@
use super::*;
use toml_edit::Item;
use super::*;
#[test]
fn test_json_to_toml_round_trip_bool() {
let item = TomlBackedUserPreferences::json_value_to_toml_item("true", None);
@@ -220,7 +220,6 @@ fn test_write_and_read_with_hierarchy() {
#[test]
fn test_write_and_read_struct_value() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("test_settings.toml");
@@ -257,7 +256,6 @@ fn test_write_and_read_struct_value() {
#[test]
fn test_new_with_invalid_toml_returns_error_and_recovers_on_reload() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("broken_settings.toml");
@@ -298,7 +296,6 @@ fn test_new_with_invalid_toml_returns_error_and_recovers_on_reload() {
#[test]
fn test_writes_inhibited_when_file_initially_broken() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("broken_settings.toml");
@@ -338,7 +335,6 @@ fn test_writes_inhibited_when_file_initially_broken() {
#[test]
fn test_string_value_for_numeric_setting_reads_as_json_string() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("test_settings.toml");
@@ -370,7 +366,6 @@ fn test_string_value_for_numeric_setting_reads_as_json_string() {
#[test]
fn test_remove_with_hierarchy() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("test_settings.toml");
@@ -397,7 +392,6 @@ fn test_remove_with_hierarchy() {
#[test]
fn test_per_key_write_inhibition_preserves_value_in_file() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("settings.toml");
@@ -441,7 +435,6 @@ fn test_per_key_write_inhibition_preserves_value_in_file() {
#[test]
fn test_per_key_write_inhibition_blocks_remove() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("settings.toml");
@@ -464,7 +457,6 @@ fn test_per_key_write_inhibition_blocks_remove() {
#[test]
fn test_reload_clears_per_key_inhibitions() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("settings.toml");
@@ -491,7 +483,6 @@ fn test_reload_clears_per_key_inhibitions() {
#[test]
fn test_clear_all_write_inhibitions() {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("settings.toml");
@@ -592,7 +583,6 @@ fn write_and_read_file(
value_json: &str,
max_table_depth: Option<u32>,
) -> String {
use super::super::UserPreferences;
let dir = tempfile::tempdir().unwrap();
let file_path = dir.path().join("settings.toml");
@@ -1,14 +1,14 @@
//! Implementation of the [`UserPreferences`] trait using macOS user defaults.
#![allow(deprecated)]
use cocoa::base::{id, nil};
use objc::{class, msg_send, rc::StrongPtr, sel, sel_impl};
use objc2::rc::Retained;
use objc2::runtime::AnyObject;
use objc2::AnyThread;
use objc2_foundation::{NSString, NSUserDefaults};
/// A user preferences store backed by macOS user defaults (`NSUserDefaults`).
pub struct UserDefaultsPreferencesStorage {
/// A strong reference to the `NSUserDefaults` backing store.
user_defaults: StrongPtr,
user_defaults: Retained<NSUserDefaults>,
}
impl UserDefaultsPreferencesStorage {
@@ -28,73 +28,53 @@ impl UserDefaultsPreferencesStorage {
///
/// If [`None`] is provided as the suite name, the standard user defaults
/// will be used (namespaced based on the current application).
fn user_defaults(suite_name: Option<String>) -> StrongPtr {
unsafe {
// Calling `[[NSUserDefaults alloc] initWithSuiteName]`` where the suite name is the
// application's bundle ID (the default `data_domain` if `data_profile` is unset)
// _should_ be equivalent to `[NSUserDefaults standardUserDefaults]`. However, in case
// the two ever deviate, we explicitly use `standardUserDefaults` below. The Apple docs
// also imply that `standardUserDefaults` is cached.
if let Some(suite_name) = &suite_name {
let defaults: id = msg_send![class!(NSUserDefaults), alloc];
let suite_name = util::make_nsstring(suite_name);
fn user_defaults(suite_name: Option<String>) -> Retained<NSUserDefaults> {
// Calling `[[NSUserDefaults alloc] initWithSuiteName]`` where the suite name is the
// application's bundle ID (the default `data_domain` if `data_profile` is unset)
// _should_ be equivalent to `[NSUserDefaults standardUserDefaults]`. However, in case
// the two ever deviate, we explicitly use `standardUserDefaults` below. The Apple docs
// also imply that `standardUserDefaults` is cached.
if let Some(suite_name) = &suite_name {
let suite_name = NSString::from_str(suite_name);
StrongPtr::new(msg_send![defaults, initWithSuiteName: *suite_name])
} else {
StrongPtr::retain(msg_send![class!(NSUserDefaults), standardUserDefaults])
}
// `initWithSuiteName:` only returns nil when the suite name is a reserved domain
// (NSGlobalDomain/NSArgumentDomain/NSRegistrationDomain) or the app's own bundle
// identifier; our `{app_id}-{profile}` suite name is never either of those, so this
// is unreachable in practice.
NSUserDefaults::initWithSuiteName(NSUserDefaults::alloc(), Some(&suite_name)).expect(
"initWithSuiteName: only returns nil for a reserved domain or the app's own bundle id",
)
} else {
NSUserDefaults::standardUserDefaults()
}
}
}
impl super::UserPreferences for UserDefaultsPreferencesStorage {
fn write_value(&self, key: &str, value: String) -> Result<(), super::Error> {
unsafe {
let key = util::make_nsstring(key);
let value = util::make_nsstring(&value);
let key = NSString::from_str(key);
let value = NSString::from_str(&value);
let value: &AnyObject = &value;
let _: () = msg_send![*self.user_defaults, setObject: *value forKey: *key];
Ok(())
// `setObject:forKey:` stores an arbitrary object; the value and key are
// both `NSString`s, which are valid property-list types.
unsafe {
self.user_defaults.setObject_forKey(Some(value), &key);
}
Ok(())
}
fn read_value(&self, key: &str) -> Result<Option<String>, super::Error> {
unsafe {
let key = util::make_nsstring(key);
let value: id = msg_send![*self.user_defaults, stringForKey: *key];
if value != nil {
Ok(Some(
galaxyui::platform::mac::utils::nsstring_as_str(value)?.to_owned(),
))
} else {
Ok(None)
}
let key = NSString::from_str(key);
match self.user_defaults.stringForKey(&key) {
Some(value) => Ok(Some(value.to_string())),
None => Ok(None),
}
}
fn remove_value(&self, key: &str) -> Result<(), super::Error> {
unsafe {
let key = util::make_nsstring(key);
let _: () = msg_send![*self.user_defaults, removeObjectForKey: *key];
Ok(())
}
}
}
mod util {
use cocoa::{base::nil, foundation::NSString};
use objc::rc::StrongPtr;
/// Creates a new `NSString` from the given `&str`, wrapped in a
/// [`StrongPtr`] so it is released when the `StrongPtr` is dropped.
///
/// **Important:** when passing the result to `msg_send!`, always
/// dereference it (e.g. `msg_send![obj, foo: *nsstring]`). Passing the
/// `StrongPtr` itself by value causes it to be moved into the
/// `unsafe extern fn` call that `msg_send!` transmutes to, and Rust will
/// not run the `StrongPtr`'s `Drop` glue after that call, leaking the
/// underlying `NSString`.
pub fn make_nsstring(value: &str) -> StrongPtr {
unsafe { StrongPtr::new(NSString::alloc(nil).init_str(value)) }
let key = NSString::from_str(key);
self.user_defaults.removeObjectForKey(&key);
Ok(())
}
}