aboutsummaryrefslogtreecommitdiff
path: root/crates/vfs/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/vfs/src/lib.rs')
-rw-r--r--crates/vfs/src/lib.rs50
1 files changed, 50 insertions, 0 deletions
diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs
index 2b7b14524..bae2c6118 100644
--- a/crates/vfs/src/lib.rs
+++ b/crates/vfs/src/lib.rs
@@ -53,9 +53,15 @@ pub use crate::{
53}; 53};
54pub use paths::{AbsPath, AbsPathBuf}; 54pub use paths::{AbsPath, AbsPathBuf};
55 55
56/// Handle to a file in [`Vfs`]
57///
58/// Most functions in rust-analyzer use this when they need to refer to a file.
56#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] 59#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
57pub struct FileId(pub u32); 60pub struct FileId(pub u32);
58 61
62/// Storage for all files read by rust-analyzer.
63///
64/// For more informations see the [crate-level](crate) documentation.
59#[derive(Default)] 65#[derive(Default)]
60pub struct Vfs { 66pub struct Vfs {
61 interner: PathInterner, 67 interner: PathInterner,
@@ -63,40 +69,73 @@ pub struct Vfs {
63 changes: Vec<ChangedFile>, 69 changes: Vec<ChangedFile>,
64} 70}
65 71
72/// Changed file in the [`Vfs`].
66pub struct ChangedFile { 73pub struct ChangedFile {
74 /// Id of the changed file
67 pub file_id: FileId, 75 pub file_id: FileId,
76 /// Kind of change
68 pub change_kind: ChangeKind, 77 pub change_kind: ChangeKind,
69} 78}
70 79
71impl ChangedFile { 80impl ChangedFile {
81 /// Returns `true` if the change is not [`Delete`](ChangeKind::Delete).
72 pub fn exists(&self) -> bool { 82 pub fn exists(&self) -> bool {
73 self.change_kind != ChangeKind::Delete 83 self.change_kind != ChangeKind::Delete
74 } 84 }
85
86 /// Returns `true` if the change is [`Create`](ChangeKind::Create) or
87 /// [`Delete`](ChangeKind::Delete).
75 pub fn is_created_or_deleted(&self) -> bool { 88 pub fn is_created_or_deleted(&self) -> bool {
76 matches!(self.change_kind, ChangeKind::Create | ChangeKind::Delete) 89 matches!(self.change_kind, ChangeKind::Create | ChangeKind::Delete)
77 } 90 }
78} 91}
79 92
93/// Kind of [file change](ChangedFile).
80#[derive(Eq, PartialEq, Copy, Clone, Debug)] 94#[derive(Eq, PartialEq, Copy, Clone, Debug)]
81pub enum ChangeKind { 95pub enum ChangeKind {
96 /// The file was (re-)created
82 Create, 97 Create,
98 /// The file was modified
83 Modify, 99 Modify,
100 /// The file was deleted
84 Delete, 101 Delete,
85} 102}
86 103
87impl Vfs { 104impl Vfs {
105 /// Amount of files currently stored.
106 ///
107 /// Note that this includes deleted files.
88 pub fn len(&self) -> usize { 108 pub fn len(&self) -> usize {
89 self.data.len() 109 self.data.len()
90 } 110 }
111
112 /// Id of the given path if it exists in the `Vfs` and is not deleted.
91 pub fn file_id(&self, path: &VfsPath) -> Option<FileId> { 113 pub fn file_id(&self, path: &VfsPath) -> Option<FileId> {
92 self.interner.get(path).filter(|&it| self.get(it).is_some()) 114 self.interner.get(path).filter(|&it| self.get(it).is_some())
93 } 115 }
116
117 /// File path corresponding to the given `file_id`.
118 ///
119 /// # Panics
120 ///
121 /// Panics if the id is not present in the `Vfs`.
94 pub fn file_path(&self, file_id: FileId) -> VfsPath { 122 pub fn file_path(&self, file_id: FileId) -> VfsPath {
95 self.interner.lookup(file_id).clone() 123 self.interner.lookup(file_id).clone()
96 } 124 }
125
126 /// File content corresponding to the given `file_id`.
127 ///
128 /// # Panics
129 ///
130 /// Panics if the id is not present in the `Vfs`, or if the corresponding file is
131 /// deleted.
97 pub fn file_contents(&self, file_id: FileId) -> &[u8] { 132 pub fn file_contents(&self, file_id: FileId) -> &[u8] {
98 self.get(file_id).as_deref().unwrap() 133 self.get(file_id).as_deref().unwrap()
99 } 134 }
135
136 /// Returns an iterator over the stored ids and their corresponding paths.
137 ///
138 /// This will skip deleted files.
100 pub fn iter(&self) -> impl Iterator<Item = (FileId, &VfsPath)> + '_ { 139 pub fn iter(&self) -> impl Iterator<Item = (FileId, &VfsPath)> + '_ {
101 (0..self.data.len()) 140 (0..self.data.len())
102 .map(|it| FileId(it as u32)) 141 .map(|it| FileId(it as u32))
@@ -106,6 +145,13 @@ impl Vfs {
106 (file_id, path) 145 (file_id, path)
107 }) 146 })
108 } 147 }
148
149 /// Update the `path` with the given `contents`. `None` means the file was deleted.
150 ///
151 /// Returns `true` if the file was modified, and saves the [change](ChangedFile).
152 ///
153 /// If the path does not currently exists in the `Vfs`, allocates a new
154 /// [`FileId`] for it.
109 pub fn set_file_contents(&mut self, path: VfsPath, contents: Option<Vec<u8>>) -> bool { 155 pub fn set_file_contents(&mut self, path: VfsPath, contents: Option<Vec<u8>>) -> bool {
110 let file_id = self.alloc_file_id(path); 156 let file_id = self.alloc_file_id(path);
111 let change_kind = match (&self.get(file_id), &contents) { 157 let change_kind = match (&self.get(file_id), &contents) {
@@ -120,9 +166,13 @@ impl Vfs {
120 self.changes.push(ChangedFile { file_id, change_kind }); 166 self.changes.push(ChangedFile { file_id, change_kind });
121 true 167 true
122 } 168 }
169
170 /// Returns `true` if the `Vfs` contains [changes](ChangedFile).
123 pub fn has_changes(&self) -> bool { 171 pub fn has_changes(&self) -> bool {
124 !self.changes.is_empty() 172 !self.changes.is_empty()
125 } 173 }
174
175 /// Drain and returns all the changes in the `Vfs`.
126 pub fn take_changes(&mut self) -> Vec<ChangedFile> { 176 pub fn take_changes(&mut self) -> Vec<ChangedFile> {
127 mem::take(&mut self.changes) 177 mem::take(&mut self.changes)
128 } 178 }