defaults-rs 0.3.4

Near drop-in replacement for the macOS defaults CLI with API bindings for Rust
docs.rs failed to build defaults-rs-0.3.4
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

defaults-rs

Near drop-in replacement for the macOS defaults CLI with API bindings for Rust

Table of Contents

Key Features

  • Use it as a direct replacement for defaults without hassle.
  • Read, write, delete, rename, import/export, and inspect preferences using the built-in async Rust API.
  • Supports user and global domains, or any plist file path.
  • Supports all plist value types (int, float, bool, string, arrays, dictionaries).
  • Pretty-prints plist data close to the original defaults format.
  • Handles both binary and XML plist files transparently.
  • Extensible.

Installation

Using brew:

$ brew install hitblast/tap/drs

Using cargo:

$ cargo install defaults-rs

Using mise:

# NOTE: This will compile the binary for your system.
$ mise use -g cargo:defaults-rs

Manual Build & Install

$ cargo install --git https://github.com/hitblast/defaults-rs

CLI Usage

The CLI command is drs. It closely mimics the original defaults tool.

Examples

Read a key (domain or path)

$ drs read com.apple.dock tilesize
$ drs read ~/Library/Preferences/com.apple.dock.plist tilesize
$ drs read ./custom.plist mykey
$ drs read com.apple.dock.plist tilesize   # if file exists, treated as path; else as domain

Write a key

$ drs write com.apple.dock tilesize -i 48
$ drs write com.apple.dock tilesize --int 48
$ drs write ~/Library/Preferences/com.apple.dock.plist tilesize --int 48
$ drs write ./custom.plist mykey --string "hello"

Delete a key

$ drs delete com.apple.dock tilesize
$ drs delete ~/Library/Preferences/com.apple.dock.plist tilesize
$ drs delete ./custom.plist mykey

Read the whole domain

$ drs read com.apple.dock
$ drs read ~/Library/Preferences/com.apple.dock.plist
$ drs read ./custom.plist

List all entries in all domains containing word

$ drs find <word>

View all domains

$ drs domains

Use the global domain

$ drs read -g com.apple.keyboard.fnState
$ drs write -g InitialKeyRepeat --int 25

Read the type of a key

$ drs read-type com.apple.dock tilesize

Rename a key

$ drs rename com.apple.dock oldKey newKey
$ drs rename ~/Library/Preferences/com.apple.dock.plist oldKey newKey
$ drs rename ./custom.plist oldKey newKey

Import/export a domain

$ drs import com.apple.dock ./mysettings.plist
$ drs export com.apple.dock ./backup.plist

Rust API

To access the developer-side API for defaults-rs, run the following command and add it to your Cargo project:

$ cargo add defaults-rs

Please refer to the API reference for more information about all the available functions.

Example

use defaults_rs::{Domain, PrefValue, Preferences};

#[tokio::main]
async fn main() {
    // Read a value
    let value = Preferences::read(Domain::User("com.apple.dock".into()), Some("tilesize"))
        .await
        .unwrap();

    // Write a value
    Preferences::write(
        Domain::User("com.apple.dock".into()),
        "tilesize",
        PrefValue::Integer(48),
    )
    .await
    .unwrap();

    // Delete a key
    Preferences::delete(Domain::User("com.apple.dock".into()), Some("tilesize"))
        .await
        .unwrap();
}

The API also provides unified batch functions which can significantly reduce the amount of I/O per read/write/delete if you want to do multiple queries.

use defaults_rs::{Domain, PrefValue, Preferences};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Batch write (only updates designated keys)
    let write_batch = vec![
        (Domain::User("com.apple.dock".into()), "tilesize".into(), PrefValue::Integer(48)),
        (Domain::User("com.apple.dock".into()), "autohide".into(), PrefValue::Boolean(true)),
        (Domain::User("com.apple.keyboard".into()), "InitialKeyRepeat".into(), PrefValue::Integer(25)),
    ];
    Preferences::write_batch(write_batch).await?;

    // Batch read:
    let read_batch = vec![
        (Domain::User("com.apple.dock".into()), Some("tilesize".into())),
        (Domain::User("com.apple.keyboard".into()), None), // Read entire domain
    ];
    let results = Preferences::read_batch(read_batch).await?;
    for (domain, key, result) in results {
        match key {
            None => println!("Domain: {:?}, Full plist: {:?}", domain, result),
            Some(k) => println!("Domain: {:?}, Key: {:?}, Value: {:?}", domain, k, result),
        }
    }

    // Batch delete:
    let delete_batch = vec![
        (Domain::User("com.apple.dock".into()), Some("tilesize".into())),
        (Domain::User("com.apple.dock".into()), Some("autohide".into())),
        (Domain::User("com.apple.keyboard".into()), None), // Delete entire domain file
    ];
    Preferences::delete_batch(delete_batch).await?;

    Ok(())
}

Contributing

New pull requests and issues are always welcome. Please read the contribution guidelines for more information about certain parts of the codebase and/or how to form a structured pull request.

License

This project has been licensed under the MIT License.