powerpack_env/
lib.rs

1//! Useful environment variables in Alfred workflows.
2//!
3//! See <https://www.alfredapp.com/help/workflows/script-environment-variables/>
4//!
5//! # Usage
6//!
7//! This crate is re-exported from the `powerpack` crate, so you can access it
8//! using `powerpack::env`.
9//!
10//! ```no_run
11//! # mod powerpack { pub extern crate powerpack_env as env; } // mock re-export
12//! use powerpack::env;
13//!
14//! let cache_dir = env::workflow_cache();
15//! ```
16
17use std::env;
18use std::ffi::{OsStr, OsString};
19use std::path::PathBuf;
20
21/// Fetches the environment variable `key` from the current process.
22///
23/// This function is similar to [`std::env::var(key).ok()`][std::env::var] but
24/// it also maps an empty string to `None`.
25///
26/// # None
27///
28/// Returns `None` in the following cases:
29/// - if the environment variable is not present.
30/// - if the environment variable is not valid Unicode.
31/// - if the environment variable is set to an empty string.
32#[inline]
33pub fn var<K: AsRef<OsStr>>(key: K) -> Option<String> {
34    env::var(key).ok().filter(|s| !s.is_empty())
35}
36
37/// Fetches the environment variable `key` from the current process.
38///
39/// This function is similar to [`std::env::var_os(key).ok()`][std::env::var]
40/// but it also maps an empty string to `None`.
41///
42/// # None
43///
44/// Returns `None` in the following cases:
45/// - if the environment variable is not present.
46/// - if the environment variable is set to an empty string.
47///
48/// Note that the method will not check if the environment variable is valid
49/// Unicode. If you want to return `None` on invalid UTF-8, use the [`var`]
50/// function instead.
51#[inline]
52pub fn var_os<K: AsRef<OsStr>>(key: K) -> Option<OsString> {
53    env::var_os(key).filter(|s| !s.is_empty())
54}
55
56/// Whether or not the user currently has the Alfred debug panel open.
57#[inline]
58pub fn is_debug() -> bool {
59    var("alfred_debug").as_deref() == Some("1")
60}
61
62/// The location of the `Alfred.alfredpreferences` directory.
63///
64/// If a user has synced their settings, this will allow you to find out where
65/// their settings are.
66///
67/// # Examples
68///
69/// ```no_run
70/// # use powerpack_env as env;
71/// let prefs = env::preferences().unwrap();
72/// println!("Alfred Preferences:\n{prefs:?}");
73/// // Alfred Preferences:
74/// // /Users/John/Library/Application Support/Alfred/Alfred.alfredpreferences
75///
76pub fn preferences() -> Option<PathBuf> {
77    var_os("alfred_preferences").map(PathBuf::from)
78}
79
80/// The Alfred version that is currently running.
81///
82/// This may be useful if your workflow depends on particular Alfred features.
83///
84/// # Examples
85///
86/// ```no_run
87/// # use powerpack_env as env;
88/// let version = env::version().unwrap();
89/// println!("Alfred Version: {version}");
90/// // Alfred Version: 5.5.1
91#[inline]
92pub fn version() -> Option<String> {
93    var("alfred_version")
94}
95
96/// The Alfred build version that is currently running.
97///
98/// This may be useful if your workflow depends on particular Alfred features.
99///
100/// # Examples
101///
102/// ```no_run
103/// # use powerpack_env as env;
104/// let build = env::version_build().unwrap();
105/// println!("Alfred Build: {build}");
106/// // Alfred Build: 2273
107/// ```
108#[inline]
109pub fn version_build() -> Option<u32> {
110    var("alfred_version_build").and_then(|s| s.parse().ok())
111}
112
113/// The bundle ID of the currently running workflow.
114///
115/// # Examples
116///
117/// ```no_run
118/// # use powerpack_env as env;
119/// let bundle_id = env::workflow_bundle_id().unwrap();
120/// println!("Workflow Bundle ID: {bundle_id}");
121/// // Workflow Bundle ID: com.example.workflow
122#[inline]
123pub fn workflow_bundle_id() -> Option<String> {
124    var("alfred_workflow_bundleid")
125}
126
127/// The name of the currently running workflow.
128///
129/// # Examples
130///
131/// ```no_run
132/// # use powerpack_env as env;
133/// let name = env::workflow_name().unwrap();
134/// println!("Workflow Name: {name}");
135/// // Workflow Name: Example Workflow
136#[inline]
137pub fn workflow_name() -> Option<String> {
138    var("alfred_workflow_name")
139}
140
141/// The unique ID of the currently running workflow.
142///
143/// # Examples
144///
145/// ```no_run
146/// # use powerpack_env as env;
147/// let uid = env::workflow_uid().unwrap();
148/// println!("Workflow UID: {uid}");
149/// // Workflow UID: user.workflow.B0AC54EC-601C-479A-9428-01F9FD732959
150/// ```
151#[inline]
152pub fn workflow_uid() -> Option<String> {
153    var("alfred_workflow_uid")
154}
155
156/// The version of the currently running workflow.
157///
158/// # Examples
159///
160/// ```no_run
161/// # use powerpack_env as env;
162/// let version = env::workflow_version().unwrap();
163/// println!("Workflow Version: {version}");
164/// // Workflow Version: 1.2.3
165#[inline]
166pub fn workflow_version() -> Option<String> {
167    var("alfred_workflow_version")
168}
169
170/// The recommended directory for volatile workflow data.
171///
172/// This will only be populated if your workflow has a bundle id set.
173///
174/// # Examples
175///
176/// ```no_run
177/// # use powerpack_env as env;
178/// let cache = env::workflow_cache().unwrap();
179/// println!("Workflow Cache:\n{cache:?}");
180/// // Workflow Cache:
181/// // /Users/John/Library/Caches/com.runningwithcrayons.Alfred/Workflow Data/com.example.workflow
182#[inline]
183pub fn workflow_cache() -> Option<PathBuf> {
184    var_os("alfred_workflow_cache").map(PathBuf::from)
185}
186
187/// The workflow cache directory or sensible default value.
188///
189/// # Panics
190///
191/// Panics if the user's home directory cannot be determined.
192///
193/// # Examples
194///
195/// ```no_run
196/// # use powerpack_env as env;
197/// let cache = env::workflow_cache_or_default();
198/// println!("Workflow Cache:\n{cache:?}");
199/// // Workflow Cache:
200/// // /Users/John/Library/Caches/com.runningwithcrayons.Alfred/Workflow Data/com.example.workflow
201#[inline]
202pub fn workflow_cache_or_default() -> PathBuf {
203    try_workflow_cache_or_default().expect("no home directory found")
204}
205
206/// The workflow cache directory or sensible default value.
207///
208/// # None
209///
210/// Returns `None` if the user's home directory cannot be determined.
211#[inline]
212pub fn try_workflow_cache_or_default() -> Option<PathBuf> {
213    workflow_cache().or_else(|| {
214        let mut d = workflow_cache_home()?;
215        let bundle_id = workflow_bundle_id();
216        d.push(bundle_id.as_deref().unwrap_or("powerpack"));
217        Some(d)
218    })
219}
220fn workflow_cache_home() -> Option<PathBuf> {
221    let mut d = home::home_dir()?;
222    d.extend([
223        "Library",
224        "Caches",
225        "com.runningwithcrayons.Alfred",
226        "Workflow Data",
227    ]);
228    Some(d)
229}
230
231/// The recommended directory for non-volatile workflow data.
232///
233/// This will only be populated if your workflow has a bundle id set.
234///
235/// # Examples
236///
237/// ```no_run
238/// # use powerpack_env as env;
239/// let data = env::workflow_data().unwrap();
240/// println!("Workflow Data:\n{data:?}");
241/// // Workflow Data:
242/// // /Users/John/Library/Application Support/Alfred/Workflow Data/com.example.workflow
243#[inline]
244pub fn workflow_data() -> Option<PathBuf> {
245    var_os("alfred_workflow_data").map(PathBuf::from)
246}
247
248/// The workflow data directory or sensible default value.
249///
250/// # Panics
251///
252/// Panics if the user's home directory cannot be determined.
253///
254/// # Examples
255///
256/// ```no_run
257/// # use powerpack_env as env;
258/// let data = env::workflow_data_or_default();
259/// println!("Workflow Data:\n{data:?}");
260/// // Workflow Data:
261/// // /Users/John/Library/Application Support/Alfred/Workflow Data/com.example.workflow
262#[inline]
263pub fn workflow_data_or_default() -> PathBuf {
264    try_workflow_data_or_default().expect("no home directory found")
265}
266/// The workflow data directory or sensible default value.
267///
268/// # None
269///
270/// Returns `None` if the user's home directory cannot be determined.
271#[inline]
272pub fn try_workflow_data_or_default() -> Option<PathBuf> {
273    workflow_data().or_else(|| {
274        let mut d = workflow_data_home()?;
275        let bundle_id = workflow_bundle_id();
276        d.push(bundle_id.as_deref().unwrap_or("powerpack"));
277        Some(d)
278    })
279}
280fn workflow_data_home() -> Option<PathBuf> {
281    let mut d = home::home_dir()?;
282    d.extend(["Library", "Application Support", "Alfred", "Workflow Data"]);
283    Some(d)
284}