nu_protocol/
parser_path.rs1use crate::{
2 FileId,
3 engine::{StateWorkingSet, VirtualPath},
4};
5use std::{
6 ffi::OsStr,
7 path::{Path, PathBuf},
8};
9
10#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
16pub enum ParserPath {
17 RealPath(PathBuf),
18 VirtualFile(PathBuf, usize),
19 VirtualDir(PathBuf, Vec<ParserPath>),
20}
21
22impl ParserPath {
23 pub fn is_dir(&self) -> bool {
24 match self {
25 ParserPath::RealPath(p) => p.is_dir(),
26 ParserPath::VirtualFile(..) => false,
27 ParserPath::VirtualDir(..) => true,
28 }
29 }
30
31 pub fn is_file(&self) -> bool {
32 match self {
33 ParserPath::RealPath(p) => p.is_file(),
34 ParserPath::VirtualFile(..) => true,
35 ParserPath::VirtualDir(..) => false,
36 }
37 }
38
39 pub fn exists(&self) -> bool {
40 match self {
41 ParserPath::RealPath(p) => p.exists(),
42 ParserPath::VirtualFile(..) => true,
43 ParserPath::VirtualDir(..) => true,
44 }
45 }
46
47 pub fn path(&self) -> &Path {
48 match self {
49 ParserPath::RealPath(p) => p,
50 ParserPath::VirtualFile(p, _) => p,
51 ParserPath::VirtualDir(p, _) => p,
52 }
53 }
54
55 pub fn path_buf(self) -> PathBuf {
56 match self {
57 ParserPath::RealPath(p) => p,
58 ParserPath::VirtualFile(p, _) => p,
59 ParserPath::VirtualDir(p, _) => p,
60 }
61 }
62
63 pub fn parent(&self) -> Option<&Path> {
64 match self {
65 ParserPath::RealPath(p) => p.parent(),
66 ParserPath::VirtualFile(p, _) => p.parent(),
67 ParserPath::VirtualDir(p, _) => p.parent(),
68 }
69 }
70
71 pub fn read_dir(&self) -> Option<Vec<ParserPath>> {
72 match self {
73 ParserPath::RealPath(p) => p.read_dir().ok().map(|read_dir| {
74 read_dir
75 .flatten()
76 .map(|dir_entry| ParserPath::RealPath(dir_entry.path()))
77 .collect()
78 }),
79 ParserPath::VirtualFile(..) => None,
80 ParserPath::VirtualDir(_, files) => Some(files.clone()),
81 }
82 }
83
84 pub fn file_stem(&self) -> Option<&OsStr> {
85 self.path().file_stem()
86 }
87
88 pub fn extension(&self) -> Option<&OsStr> {
89 self.path().extension()
90 }
91
92 pub fn join(self, path: impl AsRef<Path>) -> ParserPath {
93 match self {
94 ParserPath::RealPath(p) => ParserPath::RealPath(p.join(path)),
95 ParserPath::VirtualFile(p, file_id) => ParserPath::VirtualFile(p.join(path), file_id),
96 ParserPath::VirtualDir(p, entries) => {
97 let new_p = p.join(path);
98 let mut pp = ParserPath::RealPath(new_p.clone());
99 for entry in entries {
100 if new_p == entry.path() {
101 pp = entry.clone();
102 }
103 }
104 pp
105 }
106 }
107 }
108
109 pub fn open<'a>(
110 &'a self,
111 working_set: &'a StateWorkingSet,
112 ) -> std::io::Result<Box<dyn std::io::Read + 'a>> {
113 match self {
114 ParserPath::RealPath(p) => {
115 std::fs::File::open(p).map(|f| Box::new(f) as Box<dyn std::io::Read>)
116 }
117 ParserPath::VirtualFile(_, file_id) => working_set
118 .get_contents_of_file(FileId::new(*file_id))
119 .map(|bytes| Box::new(bytes) as Box<dyn std::io::Read>)
120 .ok_or(std::io::ErrorKind::NotFound.into()),
121
122 ParserPath::VirtualDir(..) => Err(std::io::ErrorKind::NotFound.into()),
123 }
124 }
125
126 pub fn read<'a>(&'a self, working_set: &'a StateWorkingSet) -> Option<Vec<u8>> {
127 self.open(working_set)
128 .and_then(|mut reader| {
129 let mut vec = vec![];
130 reader.read_to_end(&mut vec)?;
131 Ok(vec)
132 })
133 .ok()
134 }
135
136 pub fn from_virtual_path(
137 working_set: &StateWorkingSet,
138 name: &str,
139 virtual_path: &VirtualPath,
140 ) -> Self {
141 match virtual_path {
142 VirtualPath::File(file_id) => {
143 ParserPath::VirtualFile(PathBuf::from(name), file_id.get())
144 }
145 VirtualPath::Dir(entries) => ParserPath::VirtualDir(
146 PathBuf::from(name),
147 entries
148 .iter()
149 .map(|virtual_path_id| {
150 let (virt_name, virt_path) = working_set.get_virtual_path(*virtual_path_id);
151 ParserPath::from_virtual_path(working_set, virt_name, virt_path)
152 })
153 .collect(),
154 ),
155 }
156 }
157
158 fn normalize_native(path: &str) -> PathBuf {
160 Path::new(&path)
161 .components()
162 .fold(PathBuf::new(), |mut acc, comp| {
163 acc.push(comp);
164 acc
165 })
166 }
167
168 fn normalize_forward(path: impl AsRef<Path>) -> PathBuf {
170 PathBuf::from(
171 path.as_ref()
172 .to_string_lossy()
173 .replace(std::path::MAIN_SEPARATOR, "/"),
174 )
175 }
176
177 pub fn normalize_slashes_forward(self) -> Self {
178 match self {
179 ParserPath::RealPath(p) => ParserPath::RealPath(Self::normalize_forward(p)),
180 ParserPath::VirtualFile(p, file_id) => {
181 ParserPath::VirtualFile(Self::normalize_forward(p), file_id)
182 }
183 ParserPath::VirtualDir(p, entries) => {
184 ParserPath::VirtualDir(Self::normalize_forward(p), entries)
185 }
186 }
187 }
188
189 pub fn normalize_slashes_native(self) -> Self {
190 match self {
191 ParserPath::RealPath(p) => {
192 ParserPath::RealPath(Self::normalize_native(p.to_string_lossy().as_ref()))
193 }
194 ParserPath::VirtualFile(p, file_id) => ParserPath::VirtualFile(
195 Self::normalize_native(p.to_string_lossy().as_ref()),
196 file_id,
197 ),
198 ParserPath::VirtualDir(p, entries) => ParserPath::VirtualDir(
199 Self::normalize_native(p.to_string_lossy().as_ref()),
200 entries,
201 ),
202 }
203 }
204}