mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 07:04:22 +00:00
extract area to a crate
This commit is contained in:
parent
821fa7a50a
commit
291d578938
9 changed files with 142 additions and 94 deletions
5
Cargo.lock
generated
5
Cargo.lock
generated
|
@ -683,6 +683,10 @@ dependencies = [
|
||||||
"unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ra_arena"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ra_cli"
|
name = "ra_cli"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -808,6 +812,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ra_arena 0.1.0",
|
||||||
"relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
5
crates/ra_arena/Cargo.toml
Normal file
5
crates/ra_arena/Cargo.toml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
[package]
|
||||||
|
edition = "2018"
|
||||||
|
name = "ra_arena"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
|
97
crates/ra_arena/src/lib.rs
Normal file
97
crates/ra_arena/src/lib.rs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
//! Yet another index-based arena.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fmt,
|
||||||
|
marker::PhantomData,
|
||||||
|
ops::{Index, IndexMut},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct RawId(u32);
|
||||||
|
|
||||||
|
impl From<RawId> for u32 {
|
||||||
|
fn from(raw: RawId) -> u32 {
|
||||||
|
raw.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u32> for RawId {
|
||||||
|
fn from(id: u32) -> RawId {
|
||||||
|
RawId(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for RawId {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
self.0.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for RawId {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
self.0.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Arena<ID: ArenaId, T> {
|
||||||
|
data: Vec<T>,
|
||||||
|
_ty: PhantomData<ID>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! impl_arena_id {
|
||||||
|
($name:ident) => {
|
||||||
|
impl $crate::ArenaId for $name {
|
||||||
|
fn from_raw(raw: $crate::RawId) -> Self {
|
||||||
|
$name(raw)
|
||||||
|
}
|
||||||
|
fn into_raw(self) -> $crate::RawId {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ArenaId {
|
||||||
|
fn from_raw(raw: RawId) -> Self;
|
||||||
|
fn into_raw(self) -> RawId;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<ID: ArenaId, T> Arena<ID, T> {
|
||||||
|
pub fn alloc(&mut self, value: T) -> ID {
|
||||||
|
let id = RawId(self.data.len() as u32);
|
||||||
|
self.data.push(value);
|
||||||
|
ID::from_raw(id)
|
||||||
|
}
|
||||||
|
pub fn iter<'a>(&'a self) -> impl Iterator<Item = (ID, &'a T)> {
|
||||||
|
self.data
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, value)| (ID::from_raw(RawId(idx as u32)), value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.into_raw().0 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.into_raw().0 as usize;
|
||||||
|
&mut self.data[idx]
|
||||||
|
}
|
||||||
|
}
|
|
@ -350,7 +350,7 @@ fn on_notification(
|
||||||
.write()
|
.write()
|
||||||
.add_file_overlay(&path, params.text_document.text)
|
.add_file_overlay(&path, params.text_document.text)
|
||||||
{
|
{
|
||||||
subs.add_sub(FileId(file_id.0));
|
subs.add_sub(FileId(file_id.0.into()));
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -379,7 +379,7 @@ fn on_notification(
|
||||||
.to_file_path()
|
.to_file_path()
|
||||||
.map_err(|()| format_err!("invalid uri: {}", uri))?;
|
.map_err(|()| format_err!("invalid uri: {}", uri))?;
|
||||||
if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) {
|
if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) {
|
||||||
subs.remove_sub(FileId(file_id.0));
|
subs.remove_sub(FileId(file_id.0.into()));
|
||||||
}
|
}
|
||||||
let params = req::PublishDiagnosticsParams {
|
let params = req::PublishDiagnosticsParams {
|
||||||
uri,
|
uri,
|
||||||
|
|
|
@ -337,7 +337,10 @@ pub fn handle_runnables(
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
};
|
};
|
||||||
let file_id = world.analysis().crate_root(crate_id)?;
|
let file_id = world.analysis().crate_root(crate_id)?;
|
||||||
let path = world.vfs.read().file2path(ra_vfs::VfsFile(file_id.0));
|
let path = world
|
||||||
|
.vfs
|
||||||
|
.read()
|
||||||
|
.file2path(ra_vfs::VfsFile(file_id.0.into()));
|
||||||
let res = world.workspaces.iter().find_map(|ws| {
|
let res = world.workspaces.iter().find_map(|ws| {
|
||||||
let tgt = ws.target_by_root(&path)?;
|
let tgt = ws.target_by_root(&path)?;
|
||||||
let res = CargoTargetSpec {
|
let res = CargoTargetSpec {
|
||||||
|
|
|
@ -49,7 +49,7 @@ impl ServerWorldState {
|
||||||
let (mut vfs, roots) = Vfs::new(roots);
|
let (mut vfs, roots) = Vfs::new(roots);
|
||||||
for r in roots {
|
for r in roots {
|
||||||
let is_local = vfs.root2path(r).starts_with(&root);
|
let is_local = vfs.root2path(r).starts_with(&root);
|
||||||
change.add_root(SourceRootId(r.0), is_local);
|
change.add_root(SourceRootId(r.0.into()), is_local);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut crate_graph = CrateGraph::default();
|
let mut crate_graph = CrateGraph::default();
|
||||||
|
@ -60,7 +60,7 @@ impl ServerWorldState {
|
||||||
for tgt in pkg.targets(ws) {
|
for tgt in pkg.targets(ws) {
|
||||||
let root = tgt.root(ws);
|
let root = tgt.root(ws);
|
||||||
if let Some(file_id) = vfs.load(root) {
|
if let Some(file_id) = vfs.load(root) {
|
||||||
let file_id = FileId(file_id.0);
|
let file_id = FileId(file_id.0.into());
|
||||||
let crate_id = crate_graph.add_crate_root(file_id);
|
let crate_id = crate_graph.add_crate_root(file_id);
|
||||||
if tgt.kind(ws) == TargetKind::Lib {
|
if tgt.kind(ws) == TargetKind::Lib {
|
||||||
pkg_to_lib_crate.insert(pkg, crate_id);
|
pkg_to_lib_crate.insert(pkg, crate_id);
|
||||||
|
@ -113,14 +113,19 @@ impl ServerWorldState {
|
||||||
if root_path.starts_with(&self.root) {
|
if root_path.starts_with(&self.root) {
|
||||||
self.roots_to_scan -= 1;
|
self.roots_to_scan -= 1;
|
||||||
for (file, path, text) in files {
|
for (file, path, text) in files {
|
||||||
change.add_file(SourceRootId(root.0), FileId(file.0), path, text);
|
change.add_file(
|
||||||
|
SourceRootId(root.0.into()),
|
||||||
|
FileId(file.0.into()),
|
||||||
|
path,
|
||||||
|
text,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let files = files
|
let files = files
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(vfsfile, path, text)| (FileId(vfsfile.0), path, text))
|
.map(|(vfsfile, path, text)| (FileId(vfsfile.0.into()), path, text))
|
||||||
.collect();
|
.collect();
|
||||||
libs.push((SourceRootId(root.0), files));
|
libs.push((SourceRootId(root.0.into()), files));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VfsChange::AddFile {
|
VfsChange::AddFile {
|
||||||
|
@ -129,13 +134,18 @@ impl ServerWorldState {
|
||||||
path,
|
path,
|
||||||
text,
|
text,
|
||||||
} => {
|
} => {
|
||||||
change.add_file(SourceRootId(root.0), FileId(file.0), path, text);
|
change.add_file(
|
||||||
|
SourceRootId(root.0.into()),
|
||||||
|
FileId(file.0.into()),
|
||||||
|
path,
|
||||||
|
text,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
VfsChange::RemoveFile { root, file, path } => {
|
VfsChange::RemoveFile { root, file, path } => {
|
||||||
change.remove_file(SourceRootId(root.0), FileId(file.0), path)
|
change.remove_file(SourceRootId(root.0.into()), FileId(file.0.into()), path)
|
||||||
}
|
}
|
||||||
VfsChange::ChangeFile { file, text } => {
|
VfsChange::ChangeFile { file, text } => {
|
||||||
change.change_file(FileId(file.0), text);
|
change.change_file(FileId(file.0.into()), text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,18 +183,18 @@ impl ServerWorld {
|
||||||
.read()
|
.read()
|
||||||
.path2file(&path)
|
.path2file(&path)
|
||||||
.ok_or_else(|| format_err!("unknown file: {}", path.display()))?;
|
.ok_or_else(|| format_err!("unknown file: {}", path.display()))?;
|
||||||
Ok(FileId(file.0))
|
Ok(FileId(file.0.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
|
pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
|
||||||
let path = self.vfs.read().file2path(VfsFile(id.0));
|
let path = self.vfs.read().file2path(VfsFile(id.0.into()));
|
||||||
let url = Url::from_file_path(&path)
|
let url = Url::from_file_path(&path)
|
||||||
.map_err(|_| format_err!("can't convert path to url: {}", path.display()))?;
|
.map_err(|_| format_err!("can't convert path to url: {}", path.display()))?;
|
||||||
Ok(url)
|
Ok(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result<Url> {
|
pub fn path_to_uri(&self, root: SourceRootId, path: &RelativePathBuf) -> Result<Url> {
|
||||||
let base = self.vfs.read().root2path(VfsRoot(root.0));
|
let base = self.vfs.read().root2path(VfsRoot(root.0.into()));
|
||||||
let path = path.to_path(base);
|
let path = path.to_path(base);
|
||||||
let url = Url::from_file_path(&path)
|
let url = Url::from_file_path(&path)
|
||||||
.map_err(|_| format_err!("can't convert path to url: {}", path.display()))?;
|
.map_err(|_| format_err!("can't convert path to url: {}", path.display()))?;
|
||||||
|
|
|
@ -12,6 +12,7 @@ crossbeam-channel = "0.3.5"
|
||||||
log = "0.4.6"
|
log = "0.4.6"
|
||||||
|
|
||||||
thread_worker = { path = "../thread_worker" }
|
thread_worker = { path = "../thread_worker" }
|
||||||
|
ra_arena = { path = "../ra_arena" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
use std::{
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
pub fn iter<'a>(&'a self) -> impl Iterator<Item = (ID, &'a T)> {
|
|
||||||
self.data
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(idx, value)| (ID::from_u32(idx as u32), value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,7 +13,6 @@
|
||||||
//! VFS is based on a concept of roots: a set of directories on the file system
|
//! VFS is based on a concept of roots: a set of directories on the file system
|
||||||
//! which are watched for changes. Typically, there will be a root for each
|
//! which are watched for changes. Typically, there will be a root for each
|
||||||
//! Cargo package.
|
//! Cargo package.
|
||||||
mod arena;
|
|
||||||
mod io;
|
mod io;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -32,10 +31,7 @@ use relative_path::RelativePathBuf;
|
||||||
use crossbeam_channel::Receiver;
|
use crossbeam_channel::Receiver;
|
||||||
use walkdir::DirEntry;
|
use walkdir::DirEntry;
|
||||||
use thread_worker::WorkerHandle;
|
use thread_worker::WorkerHandle;
|
||||||
|
use ra_arena::{Arena, RawId, impl_arena_id};
|
||||||
use crate::{
|
|
||||||
arena::{ArenaId, Arena},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use crate::io::TaskResult as VfsTask;
|
pub use crate::io::TaskResult as VfsTask;
|
||||||
|
|
||||||
|
@ -68,29 +64,13 @@ fn has_rs_extension(p: &Path) -> bool {
|
||||||
p.extension() == Some(OsStr::new("rs"))
|
p.extension() == Some(OsStr::new("rs"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct VfsRoot(pub u32);
|
pub struct VfsRoot(pub RawId);
|
||||||
|
impl_arena_id!(VfsRoot);
|
||||||
|
|
||||||
impl ArenaId for VfsRoot {
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
fn from_u32(idx: u32) -> VfsRoot {
|
pub struct VfsFile(pub RawId);
|
||||||
VfsRoot(idx)
|
impl_arena_id!(VfsFile);
|
||||||
}
|
|
||||||
fn to_u32(self) -> u32 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
|
||||||
pub struct VfsFile(pub u32);
|
|
||||||
|
|
||||||
impl ArenaId for VfsFile {
|
|
||||||
fn from_u32(idx: u32) -> VfsFile {
|
|
||||||
VfsFile(idx)
|
|
||||||
}
|
|
||||||
fn to_u32(self) -> u32 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VfsFileData {
|
struct VfsFileData {
|
||||||
root: VfsRoot,
|
root: VfsRoot,
|
||||||
|
|
Loading…
Reference in a new issue