1#[cfg(windows)]
2use std::path::{Component, Prefix};
3use std::path::{Path, PathBuf, absolute};
4
5use crate::AbsolutePathBuf;
6
7pub fn home_dir() -> Option<AbsolutePathBuf> {
8 dirs::home_dir().and_then(|home| AbsolutePathBuf::try_from(home).ok())
9}
10
11pub fn data_dir() -> Option<AbsolutePathBuf> {
13 configurable_dir_path("XDG_DATA_HOME", dirs::data_dir)
14}
15
16pub fn cache_dir() -> Option<AbsolutePathBuf> {
18 configurable_dir_path("XDG_CACHE_HOME", dirs::cache_dir)
19}
20
21pub fn nu_config_dir() -> Option<AbsolutePathBuf> {
23 configurable_dir_path("XDG_CONFIG_HOME", dirs::config_dir).map(|mut p| {
24 p.push("nushell");
25 p
26 })
27}
28
29fn configurable_dir_path(
30 name: &'static str,
31 dir: impl FnOnce() -> Option<PathBuf>,
32) -> Option<AbsolutePathBuf> {
33 let path = if let Ok(path) = std::env::var(name)
36 && !path.is_empty()
37 && Path::new(&path).is_absolute()
38 {
39 PathBuf::from(path)
40 } else {
41 dir()?
42 };
43 AbsolutePathBuf::try_from(absolute(&path).unwrap_or(path)).ok()
44}
45
46#[cfg(windows)]
55pub fn is_windows_device_path(path: &Path) -> bool {
56 match path.components().next() {
57 Some(Component::Prefix(prefix)) if matches!(prefix.kind(), Prefix::DeviceNS(_)) => {
58 return true;
59 }
60 _ => {}
61 }
62 let special_paths: [&Path; 28] = [
63 Path::new("CON"),
64 Path::new("PRN"),
65 Path::new("AUX"),
66 Path::new("NUL"),
67 Path::new("COM1"),
68 Path::new("COM2"),
69 Path::new("COM3"),
70 Path::new("COM4"),
71 Path::new("COM5"),
72 Path::new("COM6"),
73 Path::new("COM7"),
74 Path::new("COM8"),
75 Path::new("COM9"),
76 Path::new("COM¹"),
77 Path::new("COM²"),
78 Path::new("COM³"),
79 Path::new("LPT1"),
80 Path::new("LPT2"),
81 Path::new("LPT3"),
82 Path::new("LPT4"),
83 Path::new("LPT5"),
84 Path::new("LPT6"),
85 Path::new("LPT7"),
86 Path::new("LPT8"),
87 Path::new("LPT9"),
88 Path::new("LPT¹"),
89 Path::new("LPT²"),
90 Path::new("LPT³"),
91 ];
92 if special_paths.contains(&path) {
93 return true;
94 }
95 false
96}
97
98#[cfg(not(windows))]
99pub fn is_windows_device_path(_path: &Path) -> bool {
100 false
101}
102
103#[cfg(test)]
104mod test_is_windows_device_path {
105 use crate::is_windows_device_path;
106 use std::path::Path;
107
108 #[cfg_attr(not(windows), ignore = "only for Windows")]
109 #[test]
110 fn device_namespace() {
111 assert!(is_windows_device_path(Path::new(r"\\.\CON")))
112 }
113
114 #[cfg_attr(not(windows), ignore = "only for Windows")]
115 #[test]
116 fn reserved_device_name() {
117 assert!(is_windows_device_path(Path::new(r"NUL")))
118 }
119
120 #[cfg_attr(not(windows), ignore = "only for Windows")]
121 #[test]
122 fn normal_path() {
123 assert!(!is_windows_device_path(Path::new(r"dir\file")))
124 }
125
126 #[cfg_attr(not(windows), ignore = "only for Windows")]
127 #[test]
128 fn absolute_path() {
129 assert!(!is_windows_device_path(Path::new(r"\dir\file")))
130 }
131
132 #[cfg_attr(not(windows), ignore = "only for Windows")]
133 #[test]
134 fn unc_path() {
135 assert!(!is_windows_device_path(Path::new(r"\\server\share")))
136 }
137
138 #[cfg_attr(not(windows), ignore = "only for Windows")]
139 #[test]
140 fn verbatim_path() {
141 assert!(!is_windows_device_path(Path::new(r"\\?\dir\file")))
142 }
143}