From 8c4aab0c803e3962ffc2c42538df1d29dd3a8ef0 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 19 Mar 2020 01:39:12 +0200 Subject: Client side draft --- crates/rust-analyzer/src/main_loop.rs | 8 +++++++- crates/rust-analyzer/src/req.rs | 2 +- editors/code/src/main.ts | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index c899ff677..f81f43930 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -641,9 +641,15 @@ fn on_notification( }; let not = match notification_cast::(not) { Ok(_params) => { + dbg!(_params); + // let request = request_new::( + // loop_state.next_request_id(), + // ConfigurationParams::default(), + // ); + // let zz = connection.sender.send(request.into()).unwrap(); return Ok(()); } - Err(not) => not, + Err(not) => dbg!(not), }; let not = match notification_cast::(not) { Ok(params) => { diff --git a/crates/rust-analyzer/src/req.rs b/crates/rust-analyzer/src/req.rs index 8557294f6..994f0ed61 100644 --- a/crates/rust-analyzer/src/req.rs +++ b/crates/rust-analyzer/src/req.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; pub use lsp_types::{ notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CodeLens, - CodeLensParams, CompletionParams, CompletionResponse, DiagnosticTag, + CodeLensParams, CompletionParams, CompletionResponse, ConfigurationParams, DiagnosticTag, DidChangeConfigurationParams, DidChangeWatchedFilesParams, DidChangeWatchedFilesRegistrationOptions, DocumentOnTypeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse, FileSystemWatcher, Hover, InitializeResult, MessageType, diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 980ed925b..63d145db0 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -91,6 +91,12 @@ export async function activate(context: vscode.ExtensionContext) { activateHighlighting(ctx); } activateInlayHints(ctx); + + vscode.workspace.onDidChangeConfiguration( + _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }), + null, + ctx?.subscriptions, + ); } export async function deactivate() { -- cgit v1.2.3 From 019f269a0a4f42854c84e749fd5bb24177eafff9 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 19 Mar 2020 23:56:32 +0200 Subject: Process configuration response draft --- crates/rust-analyzer/src/main_loop.rs | 41 ++++++++++++++++++----------------- editors/code/src/config.ts | 6 ++--- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index f81f43930..c990a3951 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -40,6 +40,7 @@ use crate::{ world::{Options, WorldSnapshot, WorldState}, Result, ServerConfig, }; +use req::ConfigurationParams; #[derive(Debug)] pub struct LspError { @@ -336,10 +337,10 @@ struct LoopState { in_flight_libraries: usize, pending_libraries: Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc)>)>, workspace_loaded: bool, - roots_progress_reported: Option, roots_scanned: usize, roots_total: usize, + configuration_request_id: Option, } impl LoopState { @@ -397,15 +398,14 @@ fn loop_turn( req, )?, Message::Notification(not) => { - on_notification( - &connection.sender, - world_state, - &mut loop_state.pending_requests, - &mut loop_state.subscriptions, - not, - )?; + on_notification(&connection.sender, world_state, loop_state, not)?; } Message::Response(resp) => { + if Some(&resp.id) == loop_state.configuration_request_id.as_ref() { + loop_state.configuration_request_id.take(); + eprintln!("!!!!!!!!!!!!!!1"); + dbg!(&resp); + } let removed = loop_state.pending_responses.remove(&resp.id); if !removed { log::error!("unexpected response: {:?}", resp) @@ -569,8 +569,7 @@ fn on_request( fn on_notification( msg_sender: &Sender, state: &mut WorldState, - pending_requests: &mut PendingRequests, - subs: &mut Subscriptions, + loop_state: &mut LoopState, not: Notification, ) -> Result<()> { let not = match notification_cast::(not) { @@ -579,7 +578,7 @@ fn on_notification( NumberOrString::Number(id) => id.into(), NumberOrString::String(id) => id.into(), }; - if pending_requests.cancel(&id) { + if loop_state.pending_requests.cancel(&id) { let response = Response::new_err( id, ErrorCode::RequestCanceled as i32, @@ -598,7 +597,7 @@ fn on_notification( if let Some(file_id) = state.vfs.write().add_file_overlay(&path, params.text_document.text) { - subs.add_sub(FileId(file_id.0)); + loop_state.subscriptions.add_sub(FileId(file_id.0)); } return Ok(()); } @@ -629,7 +628,7 @@ fn on_notification( let uri = params.text_document.uri; let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?; if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) { - subs.remove_sub(FileId(file_id.0)); + loop_state.subscriptions.remove_sub(FileId(file_id.0)); } let params = req::PublishDiagnosticsParams { uri, diagnostics: Vec::new(), version: None }; @@ -641,15 +640,17 @@ fn on_notification( }; let not = match notification_cast::(not) { Ok(_params) => { - dbg!(_params); - // let request = request_new::( - // loop_state.next_request_id(), - // ConfigurationParams::default(), - // ); - // let zz = connection.sender.send(request.into()).unwrap(); + let request_id = loop_state.next_request_id(); + let request = request_new::( + request_id.clone(), + ConfigurationParams::default(), + ); + msg_sender.send(request.into()).unwrap(); + loop_state.configuration_request_id.replace(request_id); + return Ok(()); } - Err(not) => dbg!(not), + Err(not) => not, }; let not = match notification_cast::(not) { Ok(params) => { diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index e77462c1b..501997fef 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -12,9 +12,9 @@ export class Config { private readonly requiresReloadOpts = [ "serverPath", "cargoFeatures", - "cargo-watch", - "highlighting.semanticTokens", - "inlayHints", + "excludeGlobs", + "useClientWatching", + "highlighting", "updates.channel", ] .map(opt => `${this.rootSection}.${opt}`); -- cgit v1.2.3 From a9dd4427333d410bebf8e0923d5907b2a31efb50 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Fri, 20 Mar 2020 00:42:18 +0200 Subject: Send the config from the client --- editors/code/src/client.ts | 49 ++++++++++++++++++++++++---------------------- editors/code/src/ctx.ts | 3 ++- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 98f2f232f..0d0832c44 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -5,6 +5,31 @@ import { Config } from './config'; import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed'; +export function configToOptions(config: Config): object { + return { + publishDecorations: !config.highlightingSemanticTokens, + lruCapacity: config.lruCapacity, + + inlayHintsType: config.inlayHints.typeHints, + inlayHintsParameter: config.inlayHints.parameterHints, + inlayHintsChaining: config.inlayHints.chainingHints, + inlayHintsMaxLength: config.inlayHints.maxLength, + + cargoWatchEnable: config.cargoWatchOptions.enable, + cargoWatchArgs: config.cargoWatchOptions.arguments, + cargoWatchCommand: config.cargoWatchOptions.command, + cargoWatchAllTargets: config.cargoWatchOptions.allTargets, + + excludeGlobs: config.excludeGlobs, + useClientWatching: config.useClientWatching, + featureFlags: config.featureFlags, + withSysroot: config.withSysroot, + cargoFeatures: config.cargoFeatures, + rustfmtArgs: config.rustfmtArgs, + vscodeLldb: vscode.extensions.getExtension("vadimcn.vscode-lldb") != null, + }; +} + export async function createClient(config: Config, serverPath: string): Promise { // '.' Is the fallback if no folder is open // TODO?: Workspace folders support Uri's (eg: file://test.txt). @@ -22,32 +47,10 @@ export async function createClient(config: Config, serverPath: string): Promise< const traceOutputChannel = vscode.window.createOutputChannel( 'Rust Analyzer Language Server Trace', ); - const cargoWatchOpts = config.cargoWatchOptions; const clientOptions: lc.LanguageClientOptions = { documentSelector: [{ scheme: 'file', language: 'rust' }], - initializationOptions: { - publishDecorations: !config.highlightingSemanticTokens, - lruCapacity: config.lruCapacity, - - inlayHintsType: config.inlayHints.typeHints, - inlayHintsParameter: config.inlayHints.parameterHints, - inlayHintsChaining: config.inlayHints.chainingHints, - inlayHintsMaxLength: config.inlayHints.maxLength, - - cargoWatchEnable: cargoWatchOpts.enable, - cargoWatchArgs: cargoWatchOpts.arguments, - cargoWatchCommand: cargoWatchOpts.command, - cargoWatchAllTargets: cargoWatchOpts.allTargets, - - excludeGlobs: config.excludeGlobs, - useClientWatching: config.useClientWatching, - featureFlags: config.featureFlags, - withSysroot: config.withSysroot, - cargoFeatures: config.cargoFeatures, - rustfmtArgs: config.rustfmtArgs, - vscodeLldb: vscode.extensions.getExtension("vadimcn.vscode-lldb") != null, - }, + initializationOptions: configToOptions(config), traceOutputChannel, middleware: { // Workaround for https://github.com/microsoft/vscode-languageserver-node/issues/576 diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index 84c170ea8..934638c6d 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -2,7 +2,7 @@ import * as vscode from 'vscode'; import * as lc from 'vscode-languageclient'; import { Config } from './config'; -import { createClient } from './client'; +import { createClient, configToOptions } from './client'; import { isRustEditor, RustEditor } from './util'; export class Ctx { @@ -20,6 +20,7 @@ export class Ctx { const res = new Ctx(config, extCtx, client, serverPath); res.pushCleanup(client.start()); await client.onReady(); + client.onRequest('workspace/configuration', _ => [configToOptions(config)]); return res; } -- cgit v1.2.3 From 2feaef91bd640dd842ee8e1f6244b877124eb8eb Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Fri, 20 Mar 2020 00:49:26 +0200 Subject: Read new config on the server side --- crates/rust-analyzer/src/main_loop.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index c990a3951..a48368e30 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -243,7 +243,7 @@ pub fn main_loop( break; }; } - loop_turn( + if let Some(new_server_config) = loop_turn( &pool, &task_sender, &libdata_sender, @@ -251,7 +251,9 @@ pub fn main_loop( &mut world_state, &mut loop_state, event, - )?; + )? { + dbg!(new_server_config); + } } } world_state.analysis_host.request_cancellation(); @@ -361,7 +363,7 @@ fn loop_turn( world_state: &mut WorldState, loop_state: &mut LoopState, event: Event, -) -> Result<()> { +) -> Result> { let loop_start = Instant::now(); // NOTE: don't count blocking select! call as a loop-turn time @@ -372,6 +374,8 @@ fn loop_turn( log::info!("queued count = {}", queue_count); } + let mut new_server_config = None; + match event { Event::Task(task) => { on_task(task, &connection.sender, &mut loop_state.pending_requests, world_state); @@ -401,15 +405,20 @@ fn loop_turn( on_notification(&connection.sender, world_state, loop_state, not)?; } Message::Response(resp) => { - if Some(&resp.id) == loop_state.configuration_request_id.as_ref() { - loop_state.configuration_request_id.take(); - eprintln!("!!!!!!!!!!!!!!1"); - dbg!(&resp); - } let removed = loop_state.pending_responses.remove(&resp.id); if !removed { log::error!("unexpected response: {:?}", resp) } + if Some(&resp.id) == loop_state.configuration_request_id.as_ref() { + loop_state.configuration_request_id.take(); + let new_config = + serde_json::from_value::>(resp.result.unwrap()) + .unwrap() + .first() + .unwrap() + .to_owned(); + new_server_config = Some(new_config); + } } }, }; @@ -479,7 +488,7 @@ fn loop_turn( } } - Ok(()) + Ok(new_server_config) } fn on_task( -- cgit v1.2.3 From 332799d914bdd35740c25c27f5bac7e4b3cba6c7 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Fri, 20 Mar 2020 22:09:23 +0200 Subject: Reload only the properties that do not affect vfs --- crates/ra_ide/src/lib.rs | 5 ++ crates/ra_ide_db/src/lib.rs | 12 ++-- crates/rust-analyzer/src/main_loop.rs | 121 ++++++++++++++++++---------------- crates/rust-analyzer/src/world.rs | 11 ++++ 4 files changed, 89 insertions(+), 60 deletions(-) diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index e43414985..937c9caa5 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -138,6 +138,11 @@ impl AnalysisHost { pub fn new(lru_capacity: Option) -> AnalysisHost { AnalysisHost { db: RootDatabase::new(lru_capacity) } } + + pub fn update_lru_capacity(&mut self, lru_capacity: Option) { + self.db.update_lru_capacity(lru_capacity); + } + /// Returns a snapshot of the current state, which you can query for /// semantic information. pub fn analysis(&self) -> Analysis { diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index 4faeefa8d..e6f2d36e9 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs @@ -115,12 +115,16 @@ impl RootDatabase { db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); db.set_local_roots_with_durability(Default::default(), Durability::HIGH); db.set_library_roots_with_durability(Default::default(), Durability::HIGH); - let lru_capacity = lru_capacity.unwrap_or(ra_db::DEFAULT_LRU_CAP); - db.query_mut(ra_db::ParseQuery).set_lru_capacity(lru_capacity); - db.query_mut(hir::db::ParseMacroQuery).set_lru_capacity(lru_capacity); - db.query_mut(hir::db::MacroExpandQuery).set_lru_capacity(lru_capacity); + db.update_lru_capacity(lru_capacity); db } + + pub fn update_lru_capacity(&mut self, lru_capacity: Option) { + let lru_capacity = lru_capacity.unwrap_or(ra_db::DEFAULT_LRU_CAP); + self.query_mut(ra_db::ParseQuery).set_lru_capacity(lru_capacity); + self.query_mut(hir::db::ParseMacroQuery).set_lru_capacity(lru_capacity); + self.query_mut(hir::db::MacroExpandQuery).set_lru_capacity(lru_capacity); + } } impl salsa::ParallelDatabase for RootDatabase { diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index a48368e30..85bde90bb 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -17,8 +17,9 @@ use std::{ use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; use lsp_types::{ - ClientCapabilities, NumberOrString, WorkDoneProgress, WorkDoneProgressBegin, - WorkDoneProgressCreateParams, WorkDoneProgressEnd, WorkDoneProgressReport, + ClientCapabilities, NumberOrString, TextDocumentClientCapabilities, WorkDoneProgress, + WorkDoneProgressBegin, WorkDoneProgressCreateParams, WorkDoneProgressEnd, + WorkDoneProgressReport, }; use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckTask}; use ra_ide::{Canceled, FileId, InlayHintsOptions, LibraryData, SourceRootId}; @@ -64,6 +65,53 @@ impl fmt::Display for LspError { impl Error for LspError {} +fn get_feature_flags(config: &ServerConfig, connection: &Connection) -> FeatureFlags { + let mut ff = FeatureFlags::default(); + for (flag, &value) in &config.feature_flags { + if ff.set(flag.as_str(), value).is_err() { + log::error!("unknown feature flag: {:?}", flag); + show_message( + req::MessageType::Error, + format!("unknown feature flag: {:?}", flag), + &connection.sender, + ); + } + } + log::info!("feature_flags: {:#?}", ff); + ff +} + +fn get_options( + config: &ServerConfig, + text_document_caps: Option<&TextDocumentClientCapabilities>, +) -> Options { + Options { + publish_decorations: config.publish_decorations, + supports_location_link: text_document_caps + .and_then(|it| it.definition) + .and_then(|it| it.link_support) + .unwrap_or(false), + line_folding_only: text_document_caps + .and_then(|it| it.folding_range.as_ref()) + .and_then(|it| it.line_folding_only) + .unwrap_or(false), + inlay_hints: InlayHintsOptions { + type_hints: config.inlay_hints_type, + parameter_hints: config.inlay_hints_parameter, + chaining_hints: config.inlay_hints_chaining, + max_length: config.inlay_hints_max_length, + }, + cargo_watch: CheckOptions { + enable: config.cargo_watch_enable, + args: config.cargo_watch_args.clone(), + command: config.cargo_watch_command.clone(), + all_targets: config.cargo_watch_all_targets, + }, + rustfmt_args: config.rustfmt_args.clone(), + vscode_lldb: config.vscode_lldb, + } +} + pub fn main_loop( ws_roots: Vec, client_caps: ClientCapabilities, @@ -91,23 +139,10 @@ pub fn main_loop( SetThreadPriority(thread, thread_priority_above_normal); } + let text_document_caps = client_caps.text_document.as_ref(); let mut loop_state = LoopState::default(); let mut world_state = { - let feature_flags = { - let mut ff = FeatureFlags::default(); - for (flag, value) in config.feature_flags { - if ff.set(flag.as_str(), value).is_err() { - 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 feature_flags = get_feature_flags(&config, &connection); // FIXME: support dynamic workspace loading. let workspaces = { @@ -169,42 +204,13 @@ pub fn main_loop( connection.sender.send(request.into()).unwrap(); } - let options = { - let text_document_caps = client_caps.text_document.as_ref(); - Options { - publish_decorations: config.publish_decorations, - supports_location_link: text_document_caps - .and_then(|it| it.definition) - .and_then(|it| it.link_support) - .unwrap_or(false), - line_folding_only: text_document_caps - .and_then(|it| it.folding_range.as_ref()) - .and_then(|it| it.line_folding_only) - .unwrap_or(false), - inlay_hints: InlayHintsOptions { - type_hints: config.inlay_hints_type, - parameter_hints: config.inlay_hints_parameter, - chaining_hints: config.inlay_hints_chaining, - max_length: config.inlay_hints_max_length, - }, - cargo_watch: CheckOptions { - enable: config.cargo_watch_enable, - args: config.cargo_watch_args, - command: config.cargo_watch_command, - all_targets: config.cargo_watch_all_targets, - }, - rustfmt_args: config.rustfmt_args, - vscode_lldb: config.vscode_lldb, - } - }; - WorldState::new( ws_roots, workspaces, config.lru_capacity, &globs, Watch(!config.use_client_watching), - options, + get_options(&config, text_document_caps), feature_flags, ) }; @@ -243,17 +249,16 @@ pub fn main_loop( break; }; } - if let Some(new_server_config) = loop_turn( + loop_turn( &pool, &task_sender, &libdata_sender, &connection, + text_document_caps, &mut world_state, &mut loop_state, event, - )? { - dbg!(new_server_config); - } + )?; } } world_state.analysis_host.request_cancellation(); @@ -360,10 +365,11 @@ fn loop_turn( task_sender: &Sender, libdata_sender: &Sender, connection: &Connection, + text_document_caps: Option<&TextDocumentClientCapabilities>, world_state: &mut WorldState, loop_state: &mut LoopState, event: Event, -) -> Result> { +) -> Result<()> { let loop_start = Instant::now(); // NOTE: don't count blocking select! call as a loop-turn time @@ -374,8 +380,6 @@ fn loop_turn( log::info!("queued count = {}", queue_count); } - let mut new_server_config = None; - match event { Event::Task(task) => { on_task(task, &connection.sender, &mut loop_state.pending_requests, world_state); @@ -411,13 +415,18 @@ fn loop_turn( } if Some(&resp.id) == loop_state.configuration_request_id.as_ref() { loop_state.configuration_request_id.take(); + // TODO kb unwrap-unwrap-unwrap let new_config = serde_json::from_value::>(resp.result.unwrap()) .unwrap() .first() .unwrap() .to_owned(); - new_server_config = Some(new_config); + world_state.update_configuration( + new_config.lru_capacity, + get_options(&new_config, text_document_caps), + get_feature_flags(&new_config, connection), + ); } } }, @@ -488,7 +497,7 @@ fn loop_turn( } } - Ok(new_server_config) + Ok(()) } fn on_task( diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index ca045f93c..d77844a36 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs @@ -199,6 +199,17 @@ impl WorldState { } } + pub fn update_configuration( + &mut self, + lru_capacity: Option, + options: Options, + feature_flags: FeatureFlags, + ) { + self.feature_flags = Arc::new(feature_flags); + self.analysis_host.update_lru_capacity(lru_capacity); + self.options = options; + } + /// Returns a vec of libraries /// FIXME: better API here pub fn process_changes( -- cgit v1.2.3 From 8a23bec2cdd008ff04cb01cdcca1f379f53156a3 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sat, 21 Mar 2020 00:01:47 +0200 Subject: Style fixes --- crates/rust-analyzer/src/main_loop.rs | 39 +++++++++++++++++++++-------------- editors/code/src/client.ts | 4 ++-- editors/code/src/ctx.ts | 4 ++-- editors/code/src/inlay_hints.ts | 4 +++- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 85bde90bb..a64dccd58 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -413,20 +413,27 @@ fn loop_turn( if !removed { log::error!("unexpected response: {:?}", resp) } - if Some(&resp.id) == loop_state.configuration_request_id.as_ref() { + + if Some(resp.id) == loop_state.configuration_request_id { loop_state.configuration_request_id.take(); - // TODO kb unwrap-unwrap-unwrap - let new_config = - serde_json::from_value::>(resp.result.unwrap()) - .unwrap() - .first() - .unwrap() - .to_owned(); - world_state.update_configuration( - new_config.lru_capacity, - get_options(&new_config, text_document_caps), - get_feature_flags(&new_config, connection), - ); + if let Some(err) = resp.error { + log::error!("failed fetch the server settings: {:?}", err) + } else if resp.result.is_none() { + log::error!("received empty server settings response from the client") + } else { + let new_config = + serde_json::from_value::>(resp.result.unwrap())? + .first() + .expect( + "The client is expected to always send a non-empty config data", + ) + .to_owned(); + world_state.update_configuration( + new_config.lru_capacity, + get_options(&new_config, text_document_caps), + get_feature_flags(&new_config, connection), + ); + } } } }, @@ -657,13 +664,15 @@ fn on_notification( Err(not) => not, }; let not = match notification_cast::(not) { - Ok(_params) => { + Ok(_) => { + // As stated in https://github.com/microsoft/language-server-protocol/issues/676, + // this notification's parameters should be ignored and the actual config queried separately. let request_id = loop_state.next_request_id(); let request = request_new::( request_id.clone(), ConfigurationParams::default(), ); - msg_sender.send(request.into()).unwrap(); + msg_sender.send(request.into())?; loop_state.configuration_request_id.replace(request_id); return Ok(()); diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 0d0832c44..34965e2fb 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -5,7 +5,7 @@ import { Config } from './config'; import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed'; -export function configToOptions(config: Config): object { +export function configToServerOptions(config: Config): object { return { publishDecorations: !config.highlightingSemanticTokens, lruCapacity: config.lruCapacity, @@ -50,7 +50,7 @@ export async function createClient(config: Config, serverPath: string): Promise< const clientOptions: lc.LanguageClientOptions = { documentSelector: [{ scheme: 'file', language: 'rust' }], - initializationOptions: configToOptions(config), + initializationOptions: configToServerOptions(config), traceOutputChannel, middleware: { // Workaround for https://github.com/microsoft/vscode-languageserver-node/issues/576 diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index 934638c6d..d2f49cd23 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -2,7 +2,7 @@ import * as vscode from 'vscode'; import * as lc from 'vscode-languageclient'; import { Config } from './config'; -import { createClient, configToOptions } from './client'; +import { createClient, configToServerOptions } from './client'; import { isRustEditor, RustEditor } from './util'; export class Ctx { @@ -20,7 +20,7 @@ export class Ctx { const res = new Ctx(config, extCtx, client, serverPath); res.pushCleanup(client.start()); await client.onReady(); - client.onRequest('workspace/configuration', _ => [configToOptions(config)]); + client.onRequest('workspace/configuration', _ => [configToServerOptions(config)]); return res; } diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts index 542d1f367..98663e0e3 100644 --- a/editors/code/src/inlay_hints.ts +++ b/editors/code/src/inlay_hints.ts @@ -18,6 +18,8 @@ export function activateInlayHints(ctx: Ctx) { return this.dispose(); } if (!this.updater) this.updater = new HintsUpdater(ctx); + + this.updater.syncCacheAndRenderHints(); }, dispose() { this.updater?.dispose(); @@ -124,7 +126,7 @@ class HintsUpdater implements Disposable { this.syncCacheAndRenderHints(); } - private syncCacheAndRenderHints() { + public syncCacheAndRenderHints() { // FIXME: make inlayHints request pass an array of files? this.sourceFiles.forEach((file, uri) => this.fetchHints(file).then(hints => { if (!hints) return; -- cgit v1.2.3 From bbe59c719725d0d6957623c1e391858bedd21779 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sat, 21 Mar 2020 00:40:02 +0200 Subject: Reload watcher configuration --- crates/rust-analyzer/src/world.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index d77844a36..b0c3c6a06 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs @@ -31,6 +31,23 @@ use crate::{ use ra_db::ExternSourceId; use rustc_hash::{FxHashMap, FxHashSet}; +fn create_watcher(workspaces: &[ProjectWorkspace], options: &Options) -> CheckWatcher { + workspaces + .iter() + .find_map(|w| match w { + ProjectWorkspace::Cargo { cargo, .. } => Some(cargo), + ProjectWorkspace::Json { .. } => None, + }) + .map(|cargo| { + let cargo_project_root = cargo.workspace_root().to_path_buf(); + Some(CheckWatcher::new(&options.cargo_watch, cargo_project_root)) + }) + .unwrap_or_else(|| { + log::warn!("Cargo check watching only supported for cargo workspaces, disabling"); + None + }) +} + #[derive(Debug, Clone)] pub struct Options { pub publish_decorations: bool, @@ -168,20 +185,7 @@ impl WorldState { change.set_crate_graph(crate_graph); // FIXME: Figure out the multi-workspace situation - let check_watcher = workspaces - .iter() - .find_map(|w| match w { - ProjectWorkspace::Cargo { cargo, .. } => Some(cargo), - ProjectWorkspace::Json { .. } => None, - }) - .map(|cargo| { - let cargo_project_root = cargo.workspace_root().to_path_buf(); - Some(CheckWatcher::new(&options.cargo_watch, cargo_project_root)) - }) - .unwrap_or_else(|| { - log::warn!("Cargo check watching only supported for cargo workspaces, disabling"); - None - }); + let check_watcher = create_watcher(&workspaces, &options); let mut analysis_host = AnalysisHost::new(lru_capacity); analysis_host.apply_change(change); @@ -207,6 +211,7 @@ impl WorldState { ) { self.feature_flags = Arc::new(feature_flags); self.analysis_host.update_lru_capacity(lru_capacity); + self.check_watcher = create_watcher(&self.workspaces, &options); self.options = options; } -- cgit v1.2.3 From 392eb74b5f4672b9f3f415246ad6e992e35f4eee Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sat, 21 Mar 2020 11:29:07 +0200 Subject: Remove an obsolete fixme --- crates/rust-analyzer/src/world.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index b0c3c6a06..2b5878ed9 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs @@ -184,7 +184,6 @@ impl WorldState { }); change.set_crate_graph(crate_graph); - // FIXME: Figure out the multi-workspace situation let check_watcher = create_watcher(&workspaces, &options); let mut analysis_host = AnalysisHost::new(lru_capacity); -- cgit v1.2.3 From 590af37bff2b5ec9a692f2468c98acf7f9f492c0 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sat, 21 Mar 2020 23:58:52 +0200 Subject: Small style fix Co-Authored-By: Veetaha --- crates/rust-analyzer/src/main_loop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index a64dccd58..e1fcae136 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -415,7 +415,7 @@ fn loop_turn( } if Some(resp.id) == loop_state.configuration_request_id { - loop_state.configuration_request_id.take(); + loop_state.configuration_request_id = None; if let Some(err) = resp.error { log::error!("failed fetch the server settings: {:?}", err) } else if resp.result.is_none() { -- cgit v1.2.3 From b892a48740eef7a505bfbe2213c42c71e87f0bea Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sun, 22 Mar 2020 00:40:07 +0200 Subject: Code review fixes Co-Authored-By: Veetaha --- crates/rust-analyzer/src/main_loop.rs | 21 +++++++++------------ crates/rust-analyzer/src/world.rs | 1 + editors/code/src/client.ts | 2 +- editors/code/src/inlay_hints.ts | 10 ++++++---- editors/code/src/main.ts | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index e1fcae136..7e96be319 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -417,22 +417,19 @@ fn loop_turn( if Some(resp.id) == loop_state.configuration_request_id { loop_state.configuration_request_id = None; if let Some(err) = resp.error { - log::error!("failed fetch the server settings: {:?}", err) - } else if resp.result.is_none() { - log::error!("received empty server settings response from the client") - } else { - let new_config = - serde_json::from_value::>(resp.result.unwrap())? - .first() - .expect( - "The client is expected to always send a non-empty config data", - ) - .to_owned(); + log::error!("failed to fetch the server settings: {:?}", err) + } else if let Some(result) = resp.result { + let new_config = serde_json::from_value::>(result)? + .first() + .expect("The client is expected to always send a non-empty config data") + .to_owned(); world_state.update_configuration( new_config.lru_capacity, get_options(&new_config, text_document_caps), get_feature_flags(&new_config, connection), ); + } else { + log::error!("received empty server settings response from the client") } } } @@ -673,7 +670,7 @@ fn on_notification( ConfigurationParams::default(), ); msg_sender.send(request.into())?; - loop_state.configuration_request_id.replace(request_id); + loop_state.configuration_request_id = Some(request_id); return Ok(()); } diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index 2b5878ed9..01084f818 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs @@ -32,6 +32,7 @@ use ra_db::ExternSourceId; use rustc_hash::{FxHashMap, FxHashSet}; fn create_watcher(workspaces: &[ProjectWorkspace], options: &Options) -> CheckWatcher { + // FIXME: Figure out the multi-workspace situation workspaces .iter() .find_map(|w| match w { diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 34965e2fb..d72ecc58f 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -5,7 +5,7 @@ import { Config } from './config'; import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed'; -export function configToServerOptions(config: Config): object { +export function configToServerOptions(config: Config) { return { publishDecorations: !config.highlightingSemanticTokens, lruCapacity: config.lruCapacity, diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts index 98663e0e3..6a8bd942e 100644 --- a/editors/code/src/inlay_hints.ts +++ b/editors/code/src/inlay_hints.ts @@ -17,9 +17,11 @@ export function activateInlayHints(ctx: Ctx) { ) { return this.dispose(); } - if (!this.updater) this.updater = new HintsUpdater(ctx); - - this.updater.syncCacheAndRenderHints(); + if (this.updater) { + this.updater.syncCacheAndRenderHints(); + } else { + this.updater = new HintsUpdater(ctx); + } }, dispose() { this.updater?.dispose(); @@ -126,7 +128,7 @@ class HintsUpdater implements Disposable { this.syncCacheAndRenderHints(); } - public syncCacheAndRenderHints() { + syncCacheAndRenderHints() { // FIXME: make inlayHints request pass an array of files? this.sourceFiles.forEach((file, uri) => this.fetchHints(file).then(hints => { if (!hints) return; diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 63d145db0..a46dbde33 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -95,7 +95,7 @@ export async function activate(context: vscode.ExtensionContext) { vscode.workspace.onDidChangeConfiguration( _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }), null, - ctx?.subscriptions, + ctx.subscriptions, ); } -- cgit v1.2.3 From fbef0127ba89e44796ca9594435fd01bbe77c36d Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 24 Mar 2020 21:06:03 +0200 Subject: Small style fix --- crates/rust-analyzer/src/main_loop.rs | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 7e96be319..0ab5b9ef5 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -416,20 +416,27 @@ fn loop_turn( if Some(resp.id) == loop_state.configuration_request_id { loop_state.configuration_request_id = None; - if let Some(err) = resp.error { - log::error!("failed to fetch the server settings: {:?}", err) - } else if let Some(result) = resp.result { - let new_config = serde_json::from_value::>(result)? - .first() - .expect("The client is expected to always send a non-empty config data") - .to_owned(); - world_state.update_configuration( - new_config.lru_capacity, - get_options(&new_config, text_document_caps), - get_feature_flags(&new_config, connection), - ); - } else { - log::error!("received empty server settings response from the client") + let Response { error, result, .. } = resp; + match (error, result) { + (Some(err), _) => { + log::error!("failed to fetch the server settings: {:?}", err) + } + (None, Some(result)) => { + let new_config = serde_json::from_value::>(result)? + .first() + .expect( + "The client is expected to always send a non-empty config data", + ) + .to_owned(); + world_state.update_configuration( + new_config.lru_capacity, + get_options(&new_config, text_document_caps), + get_feature_flags(&new_config, connection), + ); + } + (None, None) => { + log::error!("received empty server settings response from the client") + } } } } -- cgit v1.2.3 From 2a19459ee91ce2ee002c6d5fa4a53bc446d11d60 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 24 Mar 2020 21:43:22 +0200 Subject: Avoid failing on incorrect settings response --- crates/rust-analyzer/src/main_loop.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 0ab5b9ef5..79ea90cc9 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -414,18 +414,23 @@ fn loop_turn( log::error!("unexpected response: {:?}", resp) } - if Some(resp.id) == loop_state.configuration_request_id { + if Some(&resp.id) == loop_state.configuration_request_id.as_ref() { loop_state.configuration_request_id = None; + log::debug!("config update response: '{:?}", resp); let Response { error, result, .. } = resp; - match (error, result) { + + match ( + error, + result.map(|result| serde_json::from_value::>(result)), + ) { (Some(err), _) => { log::error!("failed to fetch the server settings: {:?}", err) } - (None, Some(result)) => { - let new_config = serde_json::from_value::>(result)? + (None, Some(Ok(new_config))) => { + let new_config = new_config .first() .expect( - "The client is expected to always send a non-empty config data", + "the client is expected to always send a non-empty config data", ) .to_owned(); world_state.update_configuration( @@ -434,6 +439,9 @@ fn loop_turn( get_feature_flags(&new_config, connection), ); } + (None, Some(Err(e))) => { + log::error!("failed to parse client config response: {}", e) + } (None, None) => { log::error!("received empty server settings response from the client") } -- cgit v1.2.3 From 8e78371222ac6ce45afd12c143f472e0674834b4 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 30 Mar 2020 13:16:09 +0300 Subject: Rebase fixes --- crates/rust-analyzer/src/world.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index 01084f818..ad096a1d8 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs @@ -31,7 +31,7 @@ use crate::{ use ra_db::ExternSourceId; use rustc_hash::{FxHashMap, FxHashSet}; -fn create_watcher(workspaces: &[ProjectWorkspace], options: &Options) -> CheckWatcher { +fn create_watcher(workspaces: &[ProjectWorkspace], options: &Options) -> Option { // FIXME: Figure out the multi-workspace situation workspaces .iter() -- cgit v1.2.3 From 4c897d8d2dd047e0906d585318866c9ae7a21610 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 30 Mar 2020 14:38:01 +0300 Subject: Fix the endless progress bar issue --- crates/ra_cargo_watch/src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs index c67ec39d4..2692c1bf5 100644 --- a/crates/ra_cargo_watch/src/lib.rs +++ b/crates/ra_cargo_watch/src/lib.rs @@ -95,6 +95,9 @@ impl CheckWatcherThread { } fn run(&mut self, task_send: &Sender, cmd_recv: &Receiver) { + // If we rerun the thread, we need to discard the previous check results first + self.clean_previous_results(task_send); + loop { select! { recv(&cmd_recv) -> cmd => match cmd { @@ -127,6 +130,13 @@ impl CheckWatcherThread { } } + fn clean_previous_results(&self, task_send: &Sender) { + task_send.send(CheckTask::ClearDiagnostics).unwrap(); + task_send + .send(CheckTask::Status(WorkDoneProgress::End(WorkDoneProgressEnd { message: None }))) + .unwrap(); + } + fn should_recheck(&mut self) -> bool { if let Some(_last_update_req) = &self.last_update_req { // We currently only request an update on save, as we need up to -- cgit v1.2.3