1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
//! # ffcv - Firefox Configuration Viewer Library
//!
//! This library provides functionality for parsing and querying Firefox
//! preference files (prefs.js). It can parse Firefox's custom JavaScript-like
//! preference format, manage Firefox profiles, and filter preferences by glob
//! patterns.
//!
//! ## Features
//!
//! - Parse Firefox prefs.js files with full JavaScript escape sequence support
//! - Extract and merge Firefox's built-in default preferences from omni.ja archives
//! - Auto-discover Firefox installations across platforms (Linux, macOS, Windows)
//! - Detect and manage Firefox profiles across platforms
//! - Query preferences using glob patterns (e.g., `"network.*"`, `"browser.*.enabled"`)
//! - Get human-readable explanations for documented preferences
//! - Support for all four preference types: user, default, locked, and sticky
//! - Track preference sources (built-in, global defaults, user-modified)
//!
//! ## Quick Start
//!
//! ### Parsing Preferences
//!
//! ```rust
//! use ffcv::{parse_prefs_js, PrefType, PrefValue};
//!
//! let content = r#"
//! user_pref("browser.startup.homepage", "https://example.com");
//! pref("javascript.enabled", true);
//! lock_pref("security.default_ssl_enabled", false);
//! "#;
//!
//! let prefs = parse_prefs_js(content)?;
//! let homepage = prefs.iter()
//! .find(|e| e.key == "browser.startup.homepage")
//! .unwrap();
//! assert_eq!(homepage.value, PrefValue::String("https://example.com".to_string()));
//! assert_eq!(homepage.pref_type, PrefType::User);
//! # Ok::<(), ffcv::Error>(())
//! ```
//!
//! For convenient value type checking, import the `PrefValueExt` trait:
//!
//! ```rust
//! use ffcv::{parse_prefs_js, PrefValue, PrefValueExt};
//!
//! let content = r#"user_pref("javascript.enabled", true);"#;
//! let prefs = parse_prefs_js(content)?;
//! let entry = &prefs[0];
//!
//! // Use convenience methods from PrefValueExt
//! if let Some(enabled) = entry.value.as_bool() {
//! println!("JavaScript enabled: {}", enabled);
//! }
//! # Ok::<(), ffcv::Error>(())
//! ```
//!
//! ### Working with Profiles
//!
//! ```rust,no_run
//! use ffcv::{find_profile_path, parse_prefs_js};
//!
//! // Find a specific Firefox profile
//! let profile_path = find_profile_path("default", None)?;
//! let prefs_path = profile_path.join("prefs.js");
//!
//! // Read and parse preferences
//! let content = std::fs::read_to_string(&prefs_path)?;
//! let prefs = parse_prefs_js(&content)?;
//! # Ok::<(), ffcv::Error>(())
//! ```
//!
//! ### Listing All Profiles
//!
//! ```rust,no_run
//! use ffcv::list_profiles;
//!
//! let profiles = list_profiles(None)?;
//! for profile in profiles {
//! println!("Profile: {} ({})", profile.name, profile.path.display());
//! if profile.is_default {
//! println!(" (default profile)");
//! }
//! }
//! # Ok::<(), ffcv::Error>(())
//! ```
//!
//! ### Querying Preferences
//!
//! ```rust
//! use ffcv::{parse_prefs_js, query_preferences};
//!
//! let content = r#"
//! user_pref("network.proxy.http", "proxy.example.com");
//! user_pref("network.proxy.http_port", 8080);
//! user_pref("browser.startup.homepage", "https://example.com");
//! "#;
//!
//! let prefs = parse_prefs_js(content)?;
//! let network_prefs = query_preferences(&prefs, &["network.*"])?;
//!
//! assert_eq!(network_prefs.len(), 2);
//! assert!(network_prefs.iter().any(|e| e.key == "network.proxy.http"));
//! # Ok::<(), ffcv::Error>(())
//! ```
//!
//! ### Firefox Installation Discovery
//!
//! ```rust,no_run
//! use ffcv::find_firefox_installation;
//!
//! // Auto-detect Firefox installation on your system
//! match find_firefox_installation()? {
//! Some(installation) => {
//! println!("Firefox found at: {}", installation.path.display());
//! println!("Version: {}", installation.version);
//! println!("Has omni.ja: {}", installation.has_omni_ja);
//! }
//! None => println!("No Firefox installation found"),
//! }
//! # Ok::<(), ffcv::Error>(())
//! ```
//!
//! ### Merging All Preference Sources
//!
//! ```rust,no_run
//! use ffcv::{merge_all_preferences, find_profile_path, MergeConfig};
//!
//! let profile_path = find_profile_path("default-release", None)?;
//!
//! let config = MergeConfig {
//! include_builtins: true, // Include omni.ja defaults
//! include_globals: true, // Include greprefs.js
//! include_user: true, // Include user prefs.js
//! continue_on_error: true, // Don't fail if some sources are missing
//! };
//!
//! let merged = merge_all_preferences(&profile_path, None, &config)?;
//!
//! println!("Loaded {} preferences from {} sources",
//! merged.entries.len(),
//! merged.loaded_sources.len()
//! );
//!
//! // Display warnings for any missing sources
//! for warning in &merged.warnings {
//! eprintln!("Warning: {}", warning);
//! }
//! # Ok::<(), ffcv::Error>(())
//! ```
//!
//! ### Filtering User-Modified Preferences
//!
//! ```rust,no_run
//! use ffcv::{merge_all_preferences, find_profile_path, MergeConfig, PrefSource};
//!
//! let profile_path = find_profile_path("default-release", None)?;
//! let config = MergeConfig::default();
//! let merged = merge_all_preferences(&profile_path, None, &config)?;
//!
//! // Get only user-modified preferences (exclude built-ins)
//! let user_modified: Vec<_> = merged.entries
//! .iter()
//! .filter(|p| p.source == Some(PrefSource::User))
//! .collect();
//!
//! println!("You've modified {} preferences", user_modified.len());
//! # Ok::<(), ffcv::Error>(())
//! ```
//!
//! ## Preference Types
//!
//! Firefox supports four preference types, indicated by the function name used:
//!
//! - **user_pref()** - [`PrefType::User`]: User-set preferences (most common)
//! - **pref()** - [`PrefType::Default`]: Application defaults
//! - **lock_pref()** - [`PrefType::Locked`]: Locked preferences (cannot be changed by users)
//! - **sticky_pref()** - [`PrefType::Sticky`]: Sticky preferences (persist across updates)
//!
//! ## Error Handling
//!
//! All functions return [`Result<T, Error>`]. The [`Error`] enum provides
//! detailed error context for programmatic handling:
//!
//! ```rust
//! use ffcv::{parse_prefs_js, Error};
//!
//! let invalid_content = "user_pref(invalid syntax";
//! match parse_prefs_js(invalid_content) {
//! Ok(config) => println!("Parsed successfully"),
//! Err(Error::Parser { line, column, message }) => {
//! eprintln!("Parse error at {}:{}: {}", line, column, message);
//! }
//! Err(e) => eprintln!("Other error: {}", e),
//! }
//! ```
//!
//! ## Platform Support
//!
//! This library automatically detects Firefox profiles on:
//! - **Linux**: `~/.mozilla/firefox/`
//! - **macOS**: `~/Library/Application Support/Firefox/`
//! - **Windows**: `%APPDATA%\Mozilla\Firefox\Profiles\`
//!
//! ## See Also
//!
//! - [Firefox preferences documentation](https://support.mozilla.org/en-US/kb/about-config-editor-firefox)
//! - [prefs.js format reference](https://searchfox.org/mozilla-central/source/modules/libpref/parser/src/lib.rs)
// Re-export all public types at crate root
pub use ;
// Re-export error types
pub use ;
// Re-export profile types
pub use ProfileInfo;
// Re-export all public functions at crate root
pub use ;
pub use ;
pub use query_preferences;
// Re-export Firefox locator
pub use ;
// Re-export omni_extractor
pub use ;
// Re-export pref_merger
pub use ;
// All modules are private - use re-exports above for public API