ltk/
dirs.rs

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
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

//! The user's folders: XDG's on Linux, the profile's on Windows. An app keeps its files in a folder of its own under one of these, named after itself.
//!
//! | Function | Linux | Windows |
//! | --- | --- | --- |
//! | [`home`] | `HOME` | `USERPROFILE` |
//! | [`data_home`] | `XDG_DATA_HOME`, else `~/.local/share` | `APPDATA`, roaming with the user |
//! | [`config_home`] | `XDG_CONFIG_HOME`, else `~/.config` | `APPDATA` |
//! | [`cache_home`] | `XDG_CACHE_HOME`, else `~/.cache` | `LOCALAPPDATA`, kept on this machine |
//! | [`state_home`] | `XDG_STATE_HOME`, else `~/.local/state` | `LOCALAPPDATA` |
//!
//! An `XDG_*` variable that is set wins on Windows too. Each is `None` when neither the variable nor what it falls back to is set.

use std::path::PathBuf;

fn var( name: &str ) -> Option<PathBuf>
{
	std::env::var_os( name ).filter( |v| !v.is_empty() ).map( PathBuf::from )
}

/// `xdg`, else `windows` on Windows and `~/<unix>` elsewhere.
fn base( xdg: &str, windows: &str, unix: &str ) -> Option<PathBuf>
{
	let fallback = if cfg!( windows ) { var( windows ) } else { home().map( |home| home.join( unix ) ) };
	var( xdg ).or( fallback )
}

/// The user's home folder: `HOME`, or on Windows, where it is seldom set, `USERPROFILE`.
pub fn home() -> Option<PathBuf>
{
	if cfg!( windows ) { var( "HOME" ).or_else( || var( "USERPROFILE" ) ) } else { var( "HOME" ) }
}

/// Where the user's own data goes, such as bookmarks or history.
pub fn data_home() -> Option<PathBuf>
{
	base( "XDG_DATA_HOME", "APPDATA", ".local/share" )
}

/// Where the user's settings go.
pub fn config_home() -> Option<PathBuf>
{
	base( "XDG_CONFIG_HOME", "APPDATA", ".config" )
}

/// Where what can be rebuilt goes, such as downloaded pages or thumbnails.
pub fn cache_home() -> Option<PathBuf>
{
	base( "XDG_CACHE_HOME", "LOCALAPPDATA", ".cache" )
}

/// Where state that should outlive a run but not follow the user goes, such as logs or a window's last place.
pub fn state_home() -> Option<PathBuf>
{
	base( "XDG_STATE_HOME", "LOCALAPPDATA", ".local/state" )
}