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
//! `PathEntry`: one PATH entry carrying both raw and env-expanded forms.
//!
//! A PATH entry has two distinct semantic forms that detectors and
//! resolvers care about for different reasons:
//!
//! * **raw** — the string as stored at the source. On Windows that
//! means `%LocalAppData%\WindowsApps` for a `REG_EXPAND_SZ` registry
//! value; on Unix that means `~/.local/bin` or `$HOME/bin` if the
//! shell did not expand it before exporting `PATH`. Detectors that
//! reason about *what the user typed* (e.g. `Shortenable`,
//! `RelativePathEntry` for unresolved variables) need the raw form
//! so they don't suggest a shortening the user already wrote.
//!
//! * **expanded** — the result of [`crate::expand::expand_env`] on
//! `raw`. Detectors that reason about *the directory on disk*
//! (`Missing`, `WriteablePathDir`, the resolver) need the expanded
//! form because the filesystem doesn't know what `%LocalAppData%`
//! means.
//!
//! pathlint computes both at the [`crate::path_source`] boundary, so
//! everything downstream picks its side from the type and never has
//! to ask "is this already expanded?" at runtime.
//!
//! # Examples
//!
//! ```
//! use pathlint::path_entry::PathEntry;
//!
//! // Construction from raw runs `expand_env_with` once. The closure
//! // is the only env oracle — pathlint never reads the process
//! // environment from this constructor.
//! let e = PathEntry::from_raw("/usr/bin", |_| -> Option<String> { None });
//! assert_eq!(e.raw, "/usr/bin");
//! assert_eq!(e.expanded, "/usr/bin");
//!
//! // The closure decides what `$VAR` / `%VAR%` / `~` resolve to.
//! let e = PathEntry::from_raw("$VAR/bin", |k| {
//! (k == "VAR").then(|| "/x".to_string())
//! });
//! assert_eq!(e.expanded, "/x/bin");
//!
//! // Unresolved variables stay verbatim.
//! let e = PathEntry::from_raw("$NOPE/bin", |_| None);
//! assert_eq!(e.expanded, "$NOPE/bin");
//! ```
use crateexpand;
/// One PATH entry as it flows from the source down to detectors and
/// resolvers. See the module docs for the semantic split between
/// `raw` and `expanded`.