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}