add option to disable notify

This commit is contained in:
Aleksey Kladov 2019-09-06 16:25:24 +03:00
parent 007737a0e7
commit 28df377759
13 changed files with 151 additions and 71 deletions

View file

@ -15,6 +15,8 @@ pub struct ServerConfig {
pub publish_decorations: bool,
pub exclude_globs: Vec<String>,
#[serde(deserialize_with = "nullable_bool_false")]
pub use_client_watching: bool,
pub lru_capacity: Option<usize>,
@ -31,6 +33,7 @@ impl Default for ServerConfig {
ServerConfig {
publish_decorations: false,
exclude_globs: Vec::new(),
use_client_watching: false,
lru_capacity: None,
with_sysroot: true,
feature_flags: FxHashMap::default(),

View file

@ -9,8 +9,9 @@ use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestI
use lsp_types::{ClientCapabilities, NumberOrString};
use ra_ide_api::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId};
use ra_prof::profile;
use ra_vfs::VfsTask;
use ra_vfs::{VfsTask, Watch};
use relative_path::RelativePathBuf;
use rustc_hash::FxHashSet;
use serde::{de::DeserializeOwned, Serialize};
use threadpool::ThreadPool;
@ -55,72 +56,96 @@ pub fn main_loop(
) -> Result<()> {
log::info!("server_config: {:#?}", config);
// FIXME: support dynamic workspace loading.
let workspaces = {
let mut loaded_workspaces = Vec::new();
for ws_root in &ws_roots {
let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot(
ws_root.as_path(),
config.with_sysroot,
);
match workspace {
Ok(workspace) => loaded_workspaces.push(workspace),
Err(e) => {
log::error!("loading workspace failed: {}", e);
let mut loop_state = LoopState::default();
let mut world_state = {
// FIXME: support dynamic workspace loading.
let workspaces = {
let mut loaded_workspaces = Vec::new();
for ws_root in &ws_roots {
let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot(
ws_root.as_path(),
config.with_sysroot,
);
match workspace {
Ok(workspace) => loaded_workspaces.push(workspace),
Err(e) => {
log::error!("loading workspace failed: {}", e);
show_message(
req::MessageType::Error,
format!("rust-analyzer failed to load workspace: {}", e),
&connection.sender,
);
}
}
}
loaded_workspaces
};
let globs = config
.exclude_globs
.iter()
.map(|glob| ra_vfs_glob::Glob::new(glob))
.collect::<std::result::Result<Vec<_>, _>>()?;
if config.use_client_watching {
let registration_options = req::DidChangeWatchedFilesRegistrationOptions {
watchers: workspaces
.iter()
.flat_map(|ws| ws.to_roots())
.filter(|root| root.is_member())
.map(|root| format!("{}/**/*.rs", root.path().display()))
.map(|glob_pattern| req::FileSystemWatcher { glob_pattern, kind: None })
.collect(),
};
let registration = req::Registration {
id: "file-watcher".to_string(),
method: "workspace/didChangeWatchedFiles".to_string(),
register_options: Some(serde_json::to_value(registration_options).unwrap()),
};
let params = req::RegistrationParams { registrations: vec![registration] };
let request =
request_new::<req::RegisterCapability>(loop_state.next_request_id(), params);
connection.sender.send(request.into()).unwrap();
}
let feature_flags = {
let mut ff = FeatureFlags::default();
for (flag, value) in config.feature_flags {
if let Err(_) = ff.set(flag.as_str(), value) {
log::error!("unknown feature flag: {:?}", flag);
show_message(
req::MessageType::Error,
format!("rust-analyzer failed to load workspace: {}", e),
format!("unknown feature flag: {:?}", flag),
&connection.sender,
);
}
}
}
loaded_workspaces
ff
};
log::info!("feature_flags: {:#?}", feature_flags);
WorldState::new(
ws_roots,
workspaces,
config.lru_capacity,
&globs,
Watch(!config.use_client_watching),
Options {
publish_decorations: config.publish_decorations,
supports_location_link: client_caps
.text_document
.and_then(|it| it.definition)
.and_then(|it| it.link_support)
.unwrap_or(false),
},
feature_flags,
)
};
let globs = config
.exclude_globs
.iter()
.map(|glob| ra_vfs_glob::Glob::new(glob))
.collect::<std::result::Result<Vec<_>, _>>()?;
let feature_flags = {
let mut ff = FeatureFlags::default();
for (flag, value) in config.feature_flags {
if let Err(_) = ff.set(flag.as_str(), value) {
log::error!("unknown feature flag: {:?}", flag);
show_message(
req::MessageType::Error,
format!("unknown feature flag: {:?}", flag),
&connection.sender,
);
}
}
ff
};
log::info!("feature_flags: {:#?}", feature_flags);
let mut world_state = WorldState::new(
ws_roots,
workspaces,
config.lru_capacity,
&globs,
Options {
publish_decorations: config.publish_decorations,
supports_location_link: client_caps
.text_document
.and_then(|it| it.definition)
.and_then(|it| it.link_support)
.unwrap_or(false),
},
feature_flags,
);
let pool = ThreadPool::new(THREADPOOL_SIZE);
let (task_sender, task_receiver) = unbounded::<Task>();
let (libdata_sender, libdata_receiver) = unbounded::<LibraryData>();
let mut loop_state = LoopState::default();
log::info!("server initialized, serving requests");
{
@ -227,6 +252,8 @@ impl fmt::Debug for Event {
#[derive(Debug, Default)]
struct LoopState {
next_request_id: u64,
pending_responses: FxHashSet<RequestId>,
pending_requests: PendingRequests,
subscriptions: Subscriptions,
// We try not to index more than MAX_IN_FLIGHT_LIBS libraries at the same
@ -236,6 +263,16 @@ struct LoopState {
workspace_loaded: bool,
}
impl LoopState {
fn next_request_id(&mut self) -> RequestId {
self.next_request_id += 1;
let res: RequestId = self.next_request_id.into();
let inserted = self.pending_responses.insert(res.clone());
assert!(inserted);
res
}
}
fn loop_turn(
pool: &ThreadPool,
task_sender: &Sender<Task>,
@ -290,7 +327,12 @@ fn loop_turn(
)?;
state_changed = true;
}
Message::Response(resp) => log::error!("unexpected response: {:?}", resp),
Message::Response(resp) => {
let removed = loop_state.pending_responses.remove(&resp.id);
if !removed {
log::error!("unexpected response: {:?}", resp)
}
}
},
};
@ -479,6 +521,18 @@ fn on_notification(
}
Err(not) => not,
};
let not = match notification_cast::<req::DidChangeWatchedFiles>(not) {
Ok(params) => {
let mut vfs = state.vfs.write();
for change in params.changes {
let uri = change.uri;
let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
vfs.notify_changed(path)
}
return Ok(());
}
Err(not) => not,
};
log::error!("unhandled notification: {:?}", not);
Ok(())
}
@ -682,3 +736,11 @@ where
{
Notification::new(N::METHOD.to_string(), params)
}
fn request_new<R>(id: RequestId, params: R::Params) -> Request
where
R: lsp_types::request::Request,
R::Params: Serialize,
{
Request::new(id, R::METHOD.to_string(), params)
}

View file

@ -5,10 +5,11 @@ use serde::{Deserialize, Serialize};
pub use lsp_types::{
notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CodeLens,
CodeLensParams, CompletionParams, CompletionResponse, DidChangeConfigurationParams,
DocumentOnTypeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse, Hover,
InitializeResult, MessageType, PublishDiagnosticsParams, ReferenceParams, ShowMessageParams,
SignatureHelp, TextDocumentEdit, TextDocumentPositionParams, TextEdit, WorkspaceEdit,
WorkspaceSymbolParams,
DidChangeWatchedFilesParams, DidChangeWatchedFilesRegistrationOptions,
DocumentOnTypeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse,
FileSystemWatcher, Hover, InitializeResult, MessageType, PublishDiagnosticsParams,
ReferenceParams, Registration, RegistrationParams, ShowMessageParams, SignatureHelp,
TextDocumentEdit, TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams,
};
pub enum AnalyzerStatus {}

View file

@ -12,7 +12,7 @@ use ra_ide_api::{
SourceRootId,
};
use ra_project_model::ProjectWorkspace;
use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask};
use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch};
use ra_vfs_glob::{Glob, RustPackageFilterBuilder};
use relative_path::RelativePathBuf;
@ -60,6 +60,7 @@ impl WorldState {
workspaces: Vec<ProjectWorkspace>,
lru_capacity: Option<usize>,
exclude_globs: &[Glob],
watch: Watch,
options: Options,
feature_flags: FeatureFlags,
) -> WorldState {
@ -85,7 +86,7 @@ impl WorldState {
}
let (task_sender, task_receiver) = unbounded();
let task_sender = Box::new(move |t| task_sender.send(t).unwrap());
let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender);
let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch);
let roots_to_scan = vfs_roots.len();
for r in vfs_roots {
let vfs_root_path = vfs.root2path(r);