mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 13:48:50 +00:00
Index deps
This commit is contained in:
parent
b04c14d4ad
commit
47cbaeba6f
7 changed files with 128 additions and 84 deletions
|
@ -57,9 +57,9 @@ impl AnalysisHostImpl {
|
||||||
}
|
}
|
||||||
self.data_mut().crate_graph = graph;
|
self.data_mut().crate_graph = graph;
|
||||||
}
|
}
|
||||||
pub fn set_libraries(&mut self, libs: impl Iterator<Item=impl Iterator<Item=(FileId, String)>>) {
|
pub fn add_library(&mut self, files: impl Iterator<Item=(FileId, String)>) {
|
||||||
let libs = libs.map(ReadonlySourceRoot::new).collect::<Vec<_>>();
|
let libs = ReadonlySourceRoot::new(files);
|
||||||
self.data_mut().libs = Arc::new(libs);
|
self.data_mut().libs.push(Arc::new(libs));
|
||||||
}
|
}
|
||||||
fn data_mut(&mut self) -> &mut WorldData {
|
fn data_mut(&mut self) -> &mut WorldData {
|
||||||
Arc::make_mut(&mut self.data)
|
Arc::make_mut(&mut self.data)
|
||||||
|
@ -93,7 +93,7 @@ impl AnalysisImpl {
|
||||||
if self.data.root.contains(file_id) {
|
if self.data.root.contains(file_id) {
|
||||||
return &self.data.root;
|
return &self.data.root;
|
||||||
}
|
}
|
||||||
self.data.libs.iter().find(|it| it.contains(file_id)).unwrap()
|
&**self.data.libs.iter().find(|it| it.contains(file_id)).unwrap()
|
||||||
}
|
}
|
||||||
pub fn file_syntax(&self, file_id: FileId) -> &File {
|
pub fn file_syntax(&self, file_id: FileId) -> &File {
|
||||||
self.root(file_id).syntax(file_id)
|
self.root(file_id).syntax(file_id)
|
||||||
|
@ -308,7 +308,7 @@ impl AnalysisImpl {
|
||||||
struct WorldData {
|
struct WorldData {
|
||||||
crate_graph: CrateGraph,
|
crate_graph: CrateGraph,
|
||||||
root: WritableSourceRoot,
|
root: WritableSourceRoot,
|
||||||
libs: Arc<Vec<ReadonlySourceRoot>>,
|
libs: Vec<Arc<ReadonlySourceRoot>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SourceChange {
|
impl SourceChange {
|
||||||
|
|
|
@ -68,8 +68,8 @@ impl AnalysisHost {
|
||||||
pub fn set_crate_graph(&mut self, graph: CrateGraph) {
|
pub fn set_crate_graph(&mut self, graph: CrateGraph) {
|
||||||
self.imp.set_crate_graph(graph)
|
self.imp.set_crate_graph(graph)
|
||||||
}
|
}
|
||||||
pub fn set_libraries(&mut self, libs: impl Iterator<Item=impl Iterator<Item=(FileId, String)>>) {
|
pub fn add_library(&mut self, files: impl Iterator<Item=(FileId, String)>) {
|
||||||
self.imp.set_libraries(libs)
|
self.imp.add_library(files)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,14 +141,18 @@ pub fn handle_workspace_symbol(
|
||||||
token: JobToken,
|
token: JobToken,
|
||||||
) -> Result<Option<Vec<SymbolInformation>>> {
|
) -> Result<Option<Vec<SymbolInformation>>> {
|
||||||
let all_symbols = params.query.contains("#");
|
let all_symbols = params.query.contains("#");
|
||||||
|
let libs = params.query.contains("*");
|
||||||
let query = {
|
let query = {
|
||||||
let query: String = params.query.chars()
|
let query: String = params.query.chars()
|
||||||
.filter(|&c| c != '#')
|
.filter(|&c| c != '#' && c != '*')
|
||||||
.collect();
|
.collect();
|
||||||
let mut q = Query::new(query);
|
let mut q = Query::new(query);
|
||||||
if !all_symbols {
|
if !all_symbols {
|
||||||
q.only_types();
|
q.only_types();
|
||||||
}
|
}
|
||||||
|
if libs {
|
||||||
|
q.libs();
|
||||||
|
}
|
||||||
q.limit(128);
|
q.limit(128);
|
||||||
q
|
q
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,9 +38,8 @@ pub fn main_loop(
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let pool = ThreadPool::new(4);
|
let pool = ThreadPool::new(4);
|
||||||
let (task_sender, task_receiver) = bounded::<Task>(16);
|
let (task_sender, task_receiver) = bounded::<Task>(16);
|
||||||
let (fs_events_receiver, watcher) = vfs::watch(vec![root.clone()]);
|
let (fs_sender, fs_receiver, fs_watcher) = vfs::roots_loader();
|
||||||
let (ws_root_sender, ws_receiver, ws_watcher) = workspace_loader();
|
let (ws_sender, ws_receiver, ws_watcher) = workspace_loader();
|
||||||
ws_root_sender.send(root);
|
|
||||||
|
|
||||||
info!("server initialized, serving requests");
|
info!("server initialized, serving requests");
|
||||||
let mut state = ServerWorldState::new();
|
let mut state = ServerWorldState::new();
|
||||||
|
@ -48,13 +47,15 @@ pub fn main_loop(
|
||||||
let mut pending_requests = HashMap::new();
|
let mut pending_requests = HashMap::new();
|
||||||
let mut subs = Subscriptions::new();
|
let mut subs = Subscriptions::new();
|
||||||
let main_res = main_loop_inner(
|
let main_res = main_loop_inner(
|
||||||
|
root,
|
||||||
&pool,
|
&pool,
|
||||||
msg_receriver,
|
|
||||||
msg_sender,
|
msg_sender,
|
||||||
task_receiver.clone(),
|
msg_receriver,
|
||||||
task_sender,
|
task_sender,
|
||||||
fs_events_receiver,
|
task_receiver.clone(),
|
||||||
ws_root_sender,
|
fs_sender,
|
||||||
|
fs_receiver,
|
||||||
|
ws_sender,
|
||||||
ws_receiver,
|
ws_receiver,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut pending_requests,
|
&mut pending_requests,
|
||||||
|
@ -68,38 +69,40 @@ pub fn main_loop(
|
||||||
pool.join();
|
pool.join();
|
||||||
info!("...threadpool has finished");
|
info!("...threadpool has finished");
|
||||||
|
|
||||||
let vfs_res = watcher.stop();
|
let fs_res = fs_watcher.stop();
|
||||||
let ws_res = ws_watcher.stop();
|
let ws_res = ws_watcher.stop();
|
||||||
|
|
||||||
main_res?;
|
main_res?;
|
||||||
vfs_res?;
|
fs_res?;
|
||||||
ws_res?;
|
ws_res?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main_loop_inner(
|
fn main_loop_inner(
|
||||||
|
ws_root: PathBuf,
|
||||||
pool: &ThreadPool,
|
pool: &ThreadPool,
|
||||||
msg_receiver: &mut Receiver<RawMessage>,
|
|
||||||
msg_sender: &mut Sender<RawMessage>,
|
msg_sender: &mut Sender<RawMessage>,
|
||||||
task_receiver: Receiver<Task>,
|
msg_receiver: &mut Receiver<RawMessage>,
|
||||||
task_sender: Sender<Task>,
|
task_sender: Sender<Task>,
|
||||||
fs_receiver: Receiver<Vec<FileEvent>>,
|
task_receiver: Receiver<Task>,
|
||||||
_ws_roots_sender: Sender<PathBuf>,
|
fs_sender: Sender<PathBuf>,
|
||||||
|
fs_receiver: Receiver<(PathBuf, Vec<FileEvent>)>,
|
||||||
|
ws_sender: Sender<PathBuf>,
|
||||||
ws_receiver: Receiver<Result<CargoWorkspace>>,
|
ws_receiver: Receiver<Result<CargoWorkspace>>,
|
||||||
state: &mut ServerWorldState,
|
state: &mut ServerWorldState,
|
||||||
pending_requests: &mut HashMap<u64, JobHandle>,
|
pending_requests: &mut HashMap<u64, JobHandle>,
|
||||||
subs: &mut Subscriptions,
|
subs: &mut Subscriptions,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut fs_receiver = Some(fs_receiver);
|
ws_sender.send(ws_root.clone());
|
||||||
|
fs_sender.send(ws_root.clone());
|
||||||
loop {
|
loop {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Event {
|
enum Event {
|
||||||
Msg(RawMessage),
|
Msg(RawMessage),
|
||||||
Task(Task),
|
Task(Task),
|
||||||
Fs(Vec<FileEvent>),
|
Fs(PathBuf, Vec<FileEvent>),
|
||||||
Ws(Result<CargoWorkspace>),
|
Ws(Result<CargoWorkspace>),
|
||||||
FsWatcherDead,
|
|
||||||
}
|
}
|
||||||
trace!("selecting");
|
trace!("selecting");
|
||||||
let event = select! {
|
let event = select! {
|
||||||
|
@ -109,8 +112,8 @@ fn main_loop_inner(
|
||||||
},
|
},
|
||||||
recv(task_receiver, task) => Event::Task(task.unwrap()),
|
recv(task_receiver, task) => Event::Task(task.unwrap()),
|
||||||
recv(fs_receiver, events) => match events {
|
recv(fs_receiver, events) => match events {
|
||||||
Some(events) => Event::Fs(events),
|
None => bail!("roots watcher died"),
|
||||||
None => Event::FsWatcherDead,
|
Some((pb, events)) => Event::Fs(pb, events),
|
||||||
}
|
}
|
||||||
recv(ws_receiver, ws) => match ws {
|
recv(ws_receiver, ws) => match ws {
|
||||||
None => bail!("workspace watcher died"),
|
None => bail!("workspace watcher died"),
|
||||||
|
@ -120,19 +123,30 @@ fn main_loop_inner(
|
||||||
trace!("selected {:?}", event);
|
trace!("selected {:?}", event);
|
||||||
let mut state_changed = false;
|
let mut state_changed = false;
|
||||||
match event {
|
match event {
|
||||||
Event::FsWatcherDead => fs_receiver = None,
|
|
||||||
Event::Task(task) => on_task(task, msg_sender, pending_requests),
|
Event::Task(task) => on_task(task, msg_sender, pending_requests),
|
||||||
Event::Fs(events) => {
|
Event::Fs(root, events) => {
|
||||||
trace!("fs change, {} events", events.len());
|
info!("fs change, {}, {} events", root.display(), events.len());
|
||||||
|
if root == ws_root {
|
||||||
state.apply_fs_changes(events);
|
state.apply_fs_changes(events);
|
||||||
|
} else {
|
||||||
|
state.add_library(events);
|
||||||
|
}
|
||||||
state_changed = true;
|
state_changed = true;
|
||||||
}
|
}
|
||||||
Event::Ws(ws) => {
|
Event::Ws(ws) => {
|
||||||
match ws {
|
match ws {
|
||||||
Ok(ws) => {
|
Ok(ws) => {
|
||||||
let not = RawNotification::new::<req::DidReloadWorkspace>(&vec![ws.clone()]);
|
let workspaces = vec![ws];
|
||||||
|
let not = RawNotification::new::<req::DidReloadWorkspace>(&workspaces);
|
||||||
msg_sender.send(RawMessage::Notification(not));
|
msg_sender.send(RawMessage::Notification(not));
|
||||||
state.set_workspaces(vec![ws]);
|
for ws in workspaces.iter() {
|
||||||
|
for pkg in ws.packages().filter(|pkg| !pkg.is_member(ws)) {
|
||||||
|
debug!("sending root, {}", pkg.root(ws).to_path_buf().display());
|
||||||
|
// deadlocky :-(
|
||||||
|
fs_sender.send(pkg.root(ws).to_path_buf());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.set_workspaces(workspaces);
|
||||||
state_changed = true;
|
state_changed = true;
|
||||||
}
|
}
|
||||||
Err(e) => warn!("loading workspace failed: {}", e),
|
Err(e) => warn!("loading workspace failed: {}", e),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::{HashMap, HashSet},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
use cargo_metadata::{metadata_run, CargoOpt};
|
use cargo_metadata::{metadata_run, CargoOpt};
|
||||||
|
@ -13,7 +13,6 @@ use {
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
pub struct CargoWorkspace {
|
pub struct CargoWorkspace {
|
||||||
ws_members: Vec<Package>,
|
|
||||||
packages: Vec<PackageData>,
|
packages: Vec<PackageData>,
|
||||||
targets: Vec<TargetData>,
|
targets: Vec<TargetData>,
|
||||||
}
|
}
|
||||||
|
@ -27,7 +26,8 @@ pub struct Target(usize);
|
||||||
struct PackageData {
|
struct PackageData {
|
||||||
name: SmolStr,
|
name: SmolStr,
|
||||||
manifest: PathBuf,
|
manifest: PathBuf,
|
||||||
targets: Vec<Target>
|
targets: Vec<Target>,
|
||||||
|
is_member: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
|
@ -50,9 +50,15 @@ impl Package {
|
||||||
pub fn manifest(self, ws: &CargoWorkspace) -> &Path {
|
pub fn manifest(self, ws: &CargoWorkspace) -> &Path {
|
||||||
ws.pkg(self).manifest.as_path()
|
ws.pkg(self).manifest.as_path()
|
||||||
}
|
}
|
||||||
|
pub fn root(self, ws: &CargoWorkspace) -> &Path {
|
||||||
|
ws.pkg(self).manifest.parent().unwrap()
|
||||||
|
}
|
||||||
pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item=Target> + 'a {
|
pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item=Target> + 'a {
|
||||||
ws.pkg(self).targets.iter().cloned()
|
ws.pkg(self).targets.iter().cloned()
|
||||||
}
|
}
|
||||||
|
pub fn is_member(self, ws: &CargoWorkspace) -> bool {
|
||||||
|
ws.pkg(self).is_member
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Target {
|
impl Target {
|
||||||
|
@ -81,13 +87,21 @@ impl CargoWorkspace {
|
||||||
let mut pkg_by_id = HashMap::new();
|
let mut pkg_by_id = HashMap::new();
|
||||||
let mut packages = Vec::new();
|
let mut packages = Vec::new();
|
||||||
let mut targets = Vec::new();
|
let mut targets = Vec::new();
|
||||||
|
|
||||||
|
let ws_members: HashSet<String> = meta.workspace_members
|
||||||
|
.into_iter()
|
||||||
|
.map(|it| it.raw)
|
||||||
|
.collect();
|
||||||
|
|
||||||
for meta_pkg in meta.packages {
|
for meta_pkg in meta.packages {
|
||||||
let pkg = Package(packages.len());
|
let pkg = Package(packages.len());
|
||||||
|
let is_member = ws_members.contains(&meta_pkg.id);
|
||||||
pkg_by_id.insert(meta_pkg.id.clone(), pkg);
|
pkg_by_id.insert(meta_pkg.id.clone(), pkg);
|
||||||
let mut pkg_data = PackageData {
|
let mut pkg_data = PackageData {
|
||||||
name: meta_pkg.name.into(),
|
name: meta_pkg.name.into(),
|
||||||
manifest: PathBuf::from(meta_pkg.manifest_path),
|
manifest: PathBuf::from(meta_pkg.manifest_path),
|
||||||
targets: Vec::new(),
|
targets: Vec::new(),
|
||||||
|
is_member,
|
||||||
};
|
};
|
||||||
for meta_tgt in meta_pkg.targets {
|
for meta_tgt in meta_pkg.targets {
|
||||||
let tgt = Target(targets.len());
|
let tgt = Target(targets.len());
|
||||||
|
@ -101,19 +115,12 @@ impl CargoWorkspace {
|
||||||
}
|
}
|
||||||
packages.push(pkg_data)
|
packages.push(pkg_data)
|
||||||
}
|
}
|
||||||
let ws_members = meta.workspace_members
|
|
||||||
.iter()
|
|
||||||
.map(|it| pkg_by_id[&it.raw])
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(CargoWorkspace { packages, targets, ws_members })
|
Ok(CargoWorkspace { packages, targets })
|
||||||
}
|
}
|
||||||
pub fn packages<'a>(&'a self) -> impl Iterator<Item=Package> + 'a {
|
pub fn packages<'a>(&'a self) -> impl Iterator<Item=Package> + 'a {
|
||||||
(0..self.packages.len()).map(Package)
|
(0..self.packages.len()).map(Package)
|
||||||
}
|
}
|
||||||
pub fn ws_members<'a>(&'a self) -> impl Iterator<Item=Package> + 'a {
|
|
||||||
self.ws_members.iter().cloned()
|
|
||||||
}
|
|
||||||
pub fn target_by_root(&self, root: &Path) -> Option<Target> {
|
pub fn target_by_root(&self, root: &Path) -> Option<Target> {
|
||||||
self.packages()
|
self.packages()
|
||||||
.filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root))
|
.filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root))
|
||||||
|
|
|
@ -47,7 +47,6 @@ impl ServerWorldState {
|
||||||
.map(|event| {
|
.map(|event| {
|
||||||
let text = match event.kind {
|
let text = match event.kind {
|
||||||
FileEventKind::Add(text) => Some(text),
|
FileEventKind::Add(text) => Some(text),
|
||||||
FileEventKind::Remove => None,
|
|
||||||
};
|
};
|
||||||
(event.path, text)
|
(event.path, text)
|
||||||
})
|
})
|
||||||
|
@ -65,6 +64,18 @@ impl ServerWorldState {
|
||||||
|
|
||||||
self.analysis_host.change_files(changes);
|
self.analysis_host.change_files(changes);
|
||||||
}
|
}
|
||||||
|
pub fn add_library(&mut self, events: Vec<FileEvent>) {
|
||||||
|
let pm = &mut self.path_map;
|
||||||
|
let files = events.into_iter()
|
||||||
|
.map(|event| {
|
||||||
|
let text = match event.kind {
|
||||||
|
FileEventKind::Add(text) => text,
|
||||||
|
};
|
||||||
|
(event.path, text)
|
||||||
|
})
|
||||||
|
.map(|(path, text)| (pm.get_or_insert(path), text));
|
||||||
|
self.analysis_host.add_library(files);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId {
|
pub fn add_mem_file(&mut self, path: PathBuf, text: String) -> FileId {
|
||||||
let file_id = self.path_map.get_or_insert(path);
|
let file_id = self.path_map.get_or_insert(path);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
path::PathBuf,
|
path::{PathBuf, Path},
|
||||||
fs,
|
fs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,20 +20,29 @@ pub struct FileEvent {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FileEventKind {
|
pub enum FileEventKind {
|
||||||
Add(String),
|
Add(String),
|
||||||
#[allow(unused)]
|
|
||||||
Remove,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn watch(roots: Vec<PathBuf>) -> (Receiver<Vec<FileEvent>>, ThreadWatcher) {
|
pub fn roots_loader() -> (Sender<PathBuf>, Receiver<(PathBuf, Vec<FileEvent>)>, ThreadWatcher) {
|
||||||
let (sender, receiver) = bounded(16);
|
let (path_sender, path_receiver) = bounded::<PathBuf>(2048);
|
||||||
let watcher = ThreadWatcher::spawn("vfs", move || run(roots, sender));
|
let (event_sender, event_receiver) = bounded::<(PathBuf, Vec<FileEvent>)>(1);
|
||||||
(receiver, watcher)
|
let thread = ThreadWatcher::spawn("roots loader", move || {
|
||||||
|
path_receiver
|
||||||
|
.into_iter()
|
||||||
|
.map(|path| {
|
||||||
|
debug!("loading {} ...", path.as_path().display());
|
||||||
|
let events = load_root(path.as_path());
|
||||||
|
debug!("... loaded {}", path.as_path().display());
|
||||||
|
(path, events)
|
||||||
|
})
|
||||||
|
.for_each(|it| event_sender.send(it))
|
||||||
|
});
|
||||||
|
|
||||||
|
(path_sender, event_receiver, thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(roots: Vec<PathBuf>, sender: Sender<Vec<FileEvent>>) {
|
fn load_root(path: &Path) -> Vec<FileEvent> {
|
||||||
for root in roots {
|
let mut res = Vec::new();
|
||||||
let mut events = Vec::new();
|
for entry in WalkDir::new(path) {
|
||||||
for entry in WalkDir::new(root.as_path()) {
|
|
||||||
let entry = match entry {
|
let entry = match entry {
|
||||||
Ok(entry) => entry,
|
Ok(entry) => entry,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -55,11 +64,10 @@ fn run(roots: Vec<PathBuf>, sender: Sender<Vec<FileEvent>>) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
events.push(FileEvent {
|
res.push(FileEvent {
|
||||||
path: path.to_owned(),
|
path: path.to_owned(),
|
||||||
kind: FileEventKind::Add(text),
|
kind: FileEventKind::Add(text),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sender.send(events)
|
res
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue