wip
This commit is contained in:
48
crates/ra_vfs/src/arena.rs
Normal file
48
crates/ra_vfs/src/arena.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
use std::{
|
||||
hash::{Hash, Hasher},
|
||||
marker::PhantomData,
|
||||
ops::{Index, IndexMut},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct Arena<ID: ArenaId, T> {
|
||||
data: Vec<T>,
|
||||
_ty: PhantomData<ID>,
|
||||
}
|
||||
|
||||
pub(crate) trait ArenaId {
|
||||
fn from_u32(id: u32) -> Self;
|
||||
fn to_u32(self) -> u32;
|
||||
}
|
||||
|
||||
impl<ID: ArenaId, T> Arena<ID, T> {
|
||||
pub fn alloc(&mut self, value: T) -> ID {
|
||||
let id = self.data.len() as u32;
|
||||
self.data.push(value);
|
||||
ID::from_u32(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<ID: ArenaId, T> Default for Arena<ID, T> {
|
||||
fn default() -> Arena<ID, T> {
|
||||
Arena {
|
||||
data: Vec::new(),
|
||||
_ty: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<ID: ArenaId, T> Index<ID> for Arena<ID, T> {
|
||||
type Output = T;
|
||||
fn index(&self, idx: ID) -> &T {
|
||||
let idx = idx.to_u32() as usize;
|
||||
&self.data[idx]
|
||||
}
|
||||
}
|
||||
|
||||
impl<ID: ArenaId, T> IndexMut<ID> for Arena<ID, T> {
|
||||
fn index_mut(&mut self, idx: ID) -> &mut T {
|
||||
let idx = idx.to_u32() as usize;
|
||||
&mut self.data[idx]
|
||||
}
|
||||
}
|
||||
72
crates/ra_vfs/src/io.rs
Normal file
72
crates/ra_vfs/src/io.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
thread::JoinHandle,
|
||||
};
|
||||
|
||||
use walkdir::WalkDir;
|
||||
use crossbeam_channel::{Sender, Receiver};
|
||||
|
||||
pub(crate) fn start_io() -> (JoinHandle<(), Sender<()>, Receiver()>) {}
|
||||
|
||||
// use crate::thread_watcher::{ThreadWatcher, Worker};
|
||||
|
||||
// #[derive(Debug)]
|
||||
// pub struct FileEvent {
|
||||
// pub path: PathBuf,
|
||||
// pub kind: FileEventKind,
|
||||
// }
|
||||
|
||||
// #[derive(Debug)]
|
||||
// pub enum FileEventKind {
|
||||
// Add(String),
|
||||
// }
|
||||
|
||||
// pub fn roots_loader() -> (Worker<PathBuf, (PathBuf, Vec<FileEvent>)>, ThreadWatcher) {
|
||||
// Worker::<PathBuf, (PathBuf, Vec<FileEvent>)>::spawn(
|
||||
// "roots loader",
|
||||
// 128,
|
||||
// |input_receiver, output_sender| {
|
||||
// input_receiver
|
||||
// .map(|path| {
|
||||
// log::debug!("loading {} ...", path.as_path().display());
|
||||
// let events = load_root(path.as_path());
|
||||
// log::debug!("... loaded {}", path.as_path().display());
|
||||
// (path, events)
|
||||
// })
|
||||
// .for_each(|it| output_sender.send(it))
|
||||
// },
|
||||
// )
|
||||
// }
|
||||
|
||||
// fn load_root(path: &Path) -> Vec<FileEvent> {
|
||||
// let mut res = Vec::new();
|
||||
// for entry in WalkDir::new(path) {
|
||||
// let entry = match entry {
|
||||
// Ok(entry) => entry,
|
||||
// Err(e) => {
|
||||
// log::warn!("watcher error: {}", e);
|
||||
// continue;
|
||||
// }
|
||||
// };
|
||||
// if !entry.file_type().is_file() {
|
||||
// continue;
|
||||
// }
|
||||
// let path = entry.path();
|
||||
// if path.extension().and_then(|os| os.to_str()) != Some("rs") {
|
||||
// continue;
|
||||
// }
|
||||
// let text = match fs::read_to_string(path) {
|
||||
// Ok(text) => text,
|
||||
// Err(e) => {
|
||||
// log::warn!("watcher error: {}", e);
|
||||
// continue;
|
||||
// }
|
||||
// };
|
||||
// res.push(FileEvent {
|
||||
// path: path.to_owned(),
|
||||
// kind: FileEventKind::Add(text),
|
||||
// })
|
||||
// }
|
||||
// res
|
||||
// }
|
||||
128
crates/ra_vfs/src/lib.rs
Normal file
128
crates/ra_vfs/src/lib.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
//! VFS stands for Virtual File System.
|
||||
//!
|
||||
//! When doing analysis, we don't want to do any IO, we want to keep all source
|
||||
//! code in memory. However, the actual source code is stored on disk, so you
|
||||
//! need to get it into the memory in the first place somehow. VFS is the
|
||||
//! component which does this.
|
||||
//!
|
||||
//! It also is responsible for watching the disk for changes, and for merging
|
||||
//! editor state (modified, unsaved files) with disk state.
|
||||
//!
|
||||
//! VFS is based on a concept of roots: a set of directories on the file system
|
||||
//! whihc are watched for changes. Typically, there will be a root for each
|
||||
//! Cargo package.
|
||||
mod arena;
|
||||
mod io;
|
||||
|
||||
use std::{
|
||||
cmp::Reverse,
|
||||
path::{Path, PathBuf},
|
||||
ffi::OsStr,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use relative_path::RelativePathBuf;
|
||||
use crate::arena::{ArenaId, Arena};
|
||||
|
||||
/// `RootFilter` is a predicate that checks if a file can belong to a root
|
||||
struct RootFilter {
|
||||
root: PathBuf,
|
||||
file_filter: fn(&Path) -> bool,
|
||||
}
|
||||
|
||||
impl RootFilter {
|
||||
fn new(root: PathBuf) -> RootFilter {
|
||||
RootFilter {
|
||||
root,
|
||||
file_filter: rs_extension_filter,
|
||||
}
|
||||
}
|
||||
fn can_contain(&self, path: &Path) -> bool {
|
||||
(self.file_filter)(path) && path.starts_with(&self.root)
|
||||
}
|
||||
}
|
||||
|
||||
fn rs_extension_filter(p: &Path) -> bool {
|
||||
p.extension() == Some(OsStr::new("rs"))
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct VfsRoot(u32);
|
||||
|
||||
impl ArenaId for VfsRoot {
|
||||
fn from_u32(idx: u32) -> VfsRoot {
|
||||
VfsRoot(idx)
|
||||
}
|
||||
fn to_u32(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct VfsFile(u32);
|
||||
|
||||
impl ArenaId for VfsFile {
|
||||
fn from_u32(idx: u32) -> VfsFile {
|
||||
VfsFile(idx)
|
||||
}
|
||||
fn to_u32(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct VfsFileData {
|
||||
root: VfsRoot,
|
||||
path: RelativePathBuf,
|
||||
text: Arc<String>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Vfs {
|
||||
roots: Arena<VfsRoot, RootFilter>,
|
||||
files: Arena<VfsFile, VfsFileData>,
|
||||
// pending_changes: Vec<PendingChange>,
|
||||
}
|
||||
|
||||
impl Vfs {
|
||||
pub fn new(mut roots: Vec<PathBuf>) -> Vfs {
|
||||
let mut res = Vfs::default();
|
||||
|
||||
roots.sort_by_key(|it| Reverse(it.as_os_str().len()));
|
||||
|
||||
for path in roots {
|
||||
res.roots.alloc(RootFilter::new(path));
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
pub fn add_file_overlay(&mut self, path: &Path, content: String) {}
|
||||
|
||||
pub fn change_file_overlay(&mut self, path: &Path, new_content: String) {}
|
||||
|
||||
pub fn remove_file_overlay(&mut self, path: &Path) {}
|
||||
|
||||
pub fn commit_changes(&mut self) -> Vec<VfsChange> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum VfsChange {
|
||||
AddRoot {
|
||||
root: VfsRoot,
|
||||
files: Vec<(VfsFile, RelativePathBuf, Arc<String>)>,
|
||||
},
|
||||
AddFile {
|
||||
file: VfsFile,
|
||||
root: VfsRoot,
|
||||
path: RelativePathBuf,
|
||||
text: Arc<String>,
|
||||
},
|
||||
RemoveFile {
|
||||
file: VfsFile,
|
||||
},
|
||||
ChangeFile {
|
||||
file: VfsFile,
|
||||
text: Arc<String>,
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user