aboutsummaryrefslogtreecommitdiff
path: root/crates/vfs/src/vfs_path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/vfs/src/vfs_path.rs')
-rw-r--r--crates/vfs/src/vfs_path.rs55
1 files changed, 53 insertions, 2 deletions
diff --git a/crates/vfs/src/vfs_path.rs b/crates/vfs/src/vfs_path.rs
index 74b6333e2..2b3d7fd84 100644
--- a/crates/vfs/src/vfs_path.rs
+++ b/crates/vfs/src/vfs_path.rs
@@ -102,7 +102,14 @@ impl VfsPath {
102 } 102 }
103 } 103 }
104 104
105 // Don't make this `pub` 105 /// **Don't make this `pub`**
106 ///
107 /// Encode the path in the given buffer.
108 ///
109 /// The encoding will be `0` if [`AbsPathBuf`], `1` if [`VirtualPath`], followed
110 /// by `self`'s representation.
111 ///
112 /// Note that this encoding is dependent on the operating system.
106 pub(crate) fn encode(&self, buf: &mut Vec<u8>) { 113 pub(crate) fn encode(&self, buf: &mut Vec<u8>) {
107 let tag = match &self.0 { 114 let tag = match &self.0 {
108 VfsPathRepr::PathBuf(_) => 0, 115 VfsPathRepr::PathBuf(_) => 0,
@@ -259,6 +266,7 @@ mod windows_paths {
259 } 266 }
260} 267}
261 268
269/// Internal, private representation of [`VfsPath`].
262#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] 270#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
263enum VfsPathRepr { 271enum VfsPathRepr {
264 PathBuf(AbsPathBuf), 272 PathBuf(AbsPathBuf),
@@ -295,13 +303,34 @@ impl fmt::Debug for VfsPathRepr {
295 } 303 }
296} 304}
297 305
306/// `/`-separated virtual path.
307///
308/// This is used to describe files that do not reside on the file system.
298#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] 309#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
299struct VirtualPath(String); 310struct VirtualPath(String);
300 311
301impl VirtualPath { 312impl VirtualPath {
313 /// Returns `true` if `other` is a prefix of `self` (as strings).
302 fn starts_with(&self, other: &VirtualPath) -> bool { 314 fn starts_with(&self, other: &VirtualPath) -> bool {
303 self.0.starts_with(&other.0) 315 self.0.starts_with(&other.0)
304 } 316 }
317
318 /// Remove the last component of `self`.
319 ///
320 /// This will find the last `'/'` in `self`, and remove everything after it,
321 /// including the `'/'`.
322 ///
323 /// If `self` contains no `'/'`, returns `false`; else returns `true`.
324 ///
325 /// # Example
326 ///
327 /// ```rust,ignore
328 /// let mut path = VirtualPath("/foo/bar".to_string());
329 /// path.pop();
330 /// assert_eq!(path.0, "/foo");
331 /// path.pop();
332 /// assert_eq!(path.0, "");
333 /// ```
305 fn pop(&mut self) -> bool { 334 fn pop(&mut self) -> bool {
306 let pos = match self.0.rfind('/') { 335 let pos = match self.0.rfind('/') {
307 Some(pos) => pos, 336 Some(pos) => pos,
@@ -310,6 +339,17 @@ impl VirtualPath {
310 self.0 = self.0[..pos].to_string(); 339 self.0 = self.0[..pos].to_string();
311 true 340 true
312 } 341 }
342
343 /// Append the given *relative* path `path` to `self`.
344 ///
345 /// This will resolve any leading `"../"` in `path` before appending it.
346 ///
347 /// Returns [`None`] if `path` has more leading `"../"` than the number of
348 /// components in `self`.
349 ///
350 /// # Notes
351 ///
352 /// In practice, appending here means `self/path` as strings.
313 fn join(&self, mut path: &str) -> Option<VirtualPath> { 353 fn join(&self, mut path: &str) -> Option<VirtualPath> {
314 let mut res = self.clone(); 354 let mut res = self.clone();
315 while path.starts_with("../") { 355 while path.starts_with("../") {
@@ -322,7 +362,18 @@ impl VirtualPath {
322 Some(res) 362 Some(res)
323 } 363 }
324 364
325 pub(crate) fn name_and_extension(&self) -> Option<(&str, Option<&str>)> { 365 /// Returns `self`'s base name and file extension.
366 ///
367 /// # Returns
368 /// - `None` if `self` ends with `"//"`.
369 /// - `Some((name, None))` if `self`'s base contains no `.`, or only one `.` at
370 /// the start.
371 /// - `Some((name, Some(extension))` else.
372 ///
373 /// # Note
374 /// The extension will not contains `.`. This means `"/foo/bar.baz.rs"` will
375 /// return `Some(("bar.baz", Some("rs"))`.
376 fn name_and_extension(&self) -> Option<(&str, Option<&str>)> {
326 let file_path = if self.0.ends_with('/') { &self.0[..&self.0.len() - 1] } else { &self.0 }; 377 let file_path = if self.0.ends_with('/') { &self.0[..&self.0.len() - 1] } else { &self.0 };
327 let file_name = match file_path.rfind('/') { 378 let file_name = match file_path.rfind('/') {
328 Some(position) => &file_path[position + 1..], 379 Some(position) => &file_path[position + 1..],