first pass of merging in warp (doesn't build)
This commit is contained in:
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user