Adds support for multiple editor workspaces on initialization

This is a quick, partial fix for #1104
This commit is contained in:
Roberto Vidal 2019-04-11 08:08:19 +02:00
parent 23b876bc3b
commit 3507bcb97a
5 changed files with 40 additions and 31 deletions

View File

@ -40,12 +40,23 @@ fn main_inner() -> Result<()> {
run_server(ra_lsp_server::server_capabilities(), receiver, sender, |params, r, s| { run_server(ra_lsp_server::server_capabilities(), receiver, sender, |params, r, s| {
let root = params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd); let root = params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd);
let workspace_roots = params
.workspace_folders
.map(|workspaces| {
workspaces
.into_iter()
.filter_map(|it| it.uri.to_file_path().ok())
.collect::<Vec<_>>()
})
.filter(|workspaces| !workspaces.is_empty())
.unwrap_or_else(|| vec![root]);
let opts = params let opts = params
.initialization_options .initialization_options
.and_then(|v| InitializationOptions::deserialize(v).ok()) .and_then(|v| InitializationOptions::deserialize(v).ok())
.unwrap_or(InitializationOptions::default()); .unwrap_or(InitializationOptions::default());
ra_lsp_server::main_loop(root, opts, r, s) ra_lsp_server::main_loop(workspace_roots, opts, r, s)
})?; })?;
log::info!("shutting down IO..."); log::info!("shutting down IO...");
threads.join()?; threads.join()?;

View File

@ -48,7 +48,7 @@ enum Task {
const THREADPOOL_SIZE: usize = 8; const THREADPOOL_SIZE: usize = 8;
pub fn main_loop( pub fn main_loop(
ws_root: PathBuf, ws_roots: Vec<PathBuf>,
options: InitializationOptions, options: InitializationOptions,
msg_receiver: &Receiver<RawMessage>, msg_receiver: &Receiver<RawMessage>,
msg_sender: &Sender<RawMessage>, msg_sender: &Sender<RawMessage>,
@ -59,9 +59,11 @@ pub fn main_loop(
// FIXME: support dynamic workspace loading. // FIXME: support dynamic workspace loading.
let workspaces = { let workspaces = {
let ws_worker = workspace_loader(); let ws_worker = workspace_loader();
let mut loaded_workspaces = Vec::new();
for ws_root in &ws_roots {
ws_worker.sender().send(ws_root.clone()).unwrap(); ws_worker.sender().send(ws_root.clone()).unwrap();
match ws_worker.receiver().recv().unwrap() { match ws_worker.receiver().recv().unwrap() {
Ok(ws) => vec![ws], Ok(ws) => loaded_workspaces.push(ws),
Err(e) => { Err(e) => {
log::error!("loading workspace failed: {}", e); log::error!("loading workspace failed: {}", e);
@ -70,12 +72,13 @@ pub fn main_loop(
format!("rust-analyzer failed to load workspace: {}", e), format!("rust-analyzer failed to load workspace: {}", e),
msg_sender, msg_sender,
); );
Vec::new()
} }
} }
}
loaded_workspaces
}; };
let mut state = ServerWorldState::new(ws_root.clone(), workspaces); let mut state = ServerWorldState::new(ws_roots, workspaces);
log::info!("server initialized, serving requests"); log::info!("server initialized, serving requests");

View File

@ -24,7 +24,7 @@ use crate::{
#[derive(Debug)] #[derive(Debug)]
pub struct ServerWorldState { pub struct ServerWorldState {
pub roots_to_scan: usize, pub roots_to_scan: usize,
pub root: PathBuf, pub roots: Vec<PathBuf>,
pub workspaces: Arc<Vec<ProjectWorkspace>>, pub workspaces: Arc<Vec<ProjectWorkspace>>,
pub analysis_host: AnalysisHost, pub analysis_host: AnalysisHost,
pub vfs: Arc<RwLock<Vfs>>, pub vfs: Arc<RwLock<Vfs>>,
@ -37,19 +37,20 @@ pub struct ServerWorld {
} }
impl ServerWorldState { impl ServerWorldState {
pub fn new(root: PathBuf, workspaces: Vec<ProjectWorkspace>) -> ServerWorldState { pub fn new(folder_roots: Vec<PathBuf>, workspaces: Vec<ProjectWorkspace>) -> ServerWorldState {
let mut change = AnalysisChange::new(); let mut change = AnalysisChange::new();
let mut roots = Vec::new(); let mut roots = Vec::new();
roots.push(IncludeRustFiles::member(root.clone())); roots.extend(folder_roots.iter().cloned().map(IncludeRustFiles::member));
for ws in workspaces.iter() { for ws in workspaces.iter() {
roots.extend(IncludeRustFiles::from_roots(ws.to_roots())); roots.extend(IncludeRustFiles::from_roots(ws.to_roots()));
} }
let (mut vfs, roots) = Vfs::new(roots); let (mut vfs, vfs_roots) = Vfs::new(roots);
let roots_to_scan = roots.len(); let roots_to_scan = vfs_roots.len();
for r in roots { for r in vfs_roots {
let is_local = vfs.root2path(r).starts_with(&root); let vfs_root_path = vfs.root2path(r);
let is_local = folder_roots.iter().any(|it| vfs_root_path.starts_with(it));
change.add_root(SourceRootId(r.0.into()), is_local); change.add_root(SourceRootId(r.0.into()), is_local);
} }
@ -68,7 +69,7 @@ impl ServerWorldState {
analysis_host.apply_change(change); analysis_host.apply_change(change);
ServerWorldState { ServerWorldState {
roots_to_scan, roots_to_scan,
root, roots: folder_roots,
workspaces: Arc::new(workspaces), workspaces: Arc::new(workspaces),
analysis_host, analysis_host,
vfs: Arc::new(RwLock::new(vfs)), vfs: Arc::new(RwLock::new(vfs)),
@ -90,7 +91,8 @@ impl ServerWorldState {
match c { match c {
VfsChange::AddRoot { root, files } => { VfsChange::AddRoot { root, files } => {
let root_path = self.vfs.read().root2path(root); let root_path = self.vfs.read().root2path(root);
if root_path.starts_with(&self.root) { let is_local = self.roots.iter().any(|r| root_path.starts_with(r));
if is_local {
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( change.add_file(

View File

@ -63,7 +63,7 @@ impl Server {
128, 128,
move |mut msg_receiver, mut msg_sender| { move |mut msg_receiver, mut msg_sender| {
main_loop( main_loop(
path, vec![path],
InitializationOptions::default(), InitializationOptions::default(),
&mut msg_receiver, &mut msg_receiver,
&mut msg_sender, &mut msg_sender,

View File

@ -17,13 +17,6 @@ export class Server {
let folder: string = '.'; let folder: string = '.';
if (workspace.workspaceFolders !== undefined) { if (workspace.workspaceFolders !== undefined) {
folder = workspace.workspaceFolders[0].uri.fsPath.toString(); folder = workspace.workspaceFolders[0].uri.fsPath.toString();
if (workspace.workspaceFolders.length > 1) {
// Tell the user that we do not support multi-root workspaces yet
window.showWarningMessage(
'Multi-root workspaces are not currently supported'
);
}
} }
const run: lc.Executable = { const run: lc.Executable = {