From a97e5eb85d1a8a2a07663abbd9beaae317fdb24d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 1 Apr 2020 18:41:43 +0200 Subject: Centralize all config --- crates/ra_flycheck/src/lib.rs | 12 +- crates/rust-analyzer/src/bin/main.rs | 32 ++- crates/rust-analyzer/src/config.rs | 251 ++++++++-------------- crates/rust-analyzer/src/feature_flags.rs | 77 ------- crates/rust-analyzer/src/lib.rs | 3 +- crates/rust-analyzer/src/main_loop.rs | 43 +--- crates/rust-analyzer/src/world.rs | 20 +- crates/rust-analyzer/tests/heavy_tests/main.rs | 2 +- crates/rust-analyzer/tests/heavy_tests/support.rs | 39 +--- 9 files changed, 151 insertions(+), 328 deletions(-) delete mode 100644 crates/rust-analyzer/src/feature_flags.rs diff --git a/crates/ra_flycheck/src/lib.rs b/crates/ra_flycheck/src/lib.rs index 13494a731..f3d6f8f5f 100644 --- a/crates/ra_flycheck/src/lib.rs +++ b/crates/ra_flycheck/src/lib.rs @@ -22,12 +22,22 @@ use crate::conv::{map_rust_diagnostic_to_lsp, MappedRustDiagnostic}; pub use crate::conv::url_from_path_with_drive_lowercasing; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum FlycheckConfig { CargoCommand { command: String, all_targets: bool, extra_args: Vec }, CustomCommand { command: String, args: Vec }, } +impl Default for FlycheckConfig { + fn default() -> Self { + FlycheckConfig::CargoCommand { + command: "check".to_string(), + all_targets: true, + extra_args: Vec::new(), + } + } +} + /// Flycheck wraps the shared state and communication machinery used for /// running `cargo check` (or other compatible command) and providing /// diagnostics based on the output. diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index a744a6695..483f50ce6 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -5,7 +5,7 @@ mod args; use lsp_server::Connection; -use rust_analyzer::{cli, from_json, show_message, Result, ServerConfig}; +use rust_analyzer::{cli, from_json, Config, Result}; use crate::args::HelpPrinted; @@ -78,24 +78,18 @@ fn run_server() -> Result<()> { .filter(|workspaces| !workspaces.is_empty()) .unwrap_or_else(|| vec![root]); - let server_config = initialize_params - .initialization_options - .and_then(|v| { - from_json::("config", v) - .map_err(|e| { - log::error!("{}", e); - show_message(lsp_types::MessageType::Error, e.to_string(), &connection.sender); - }) - .ok() - }) - .unwrap_or_default(); - - rust_analyzer::main_loop( - workspace_roots, - initialize_params.capabilities, - server_config, - connection, - )?; + let config = { + let mut config = Config::default(); + if let Some(value) = &initialize_params.initialization_options { + config.update(value); + } + if let Some(caps) = &initialize_params.capabilities.text_document { + config.update_caps(caps); + } + config + }; + + rust_analyzer::main_loop(workspace_roots, config, connection)?; log::info!("shutting down IO..."); io_threads.join()?; diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 8a8e42ed8..c07626e5c 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -7,14 +7,11 @@ //! configure the server itself, feature flags are passed into analysis, and //! tweak things like automatic insertion of `()` in completions. -use rustc_hash::FxHashMap; - -use crate::feature_flags::FeatureFlags; use lsp_types::TextDocumentClientCapabilities; use ra_flycheck::FlycheckConfig; use ra_ide::{CompletionConfig, InlayHintsConfig}; use ra_project_model::CargoFeatures; -use serde::{Deserialize, Deserializer}; +use serde::Deserialize; #[derive(Debug, Clone)] pub struct Config { @@ -61,171 +58,109 @@ impl Default for RustfmtConfig { } } -pub(crate) fn get_config( - config: &ServerConfig, - text_document_caps: Option<&TextDocumentClientCapabilities>, -) -> Config { - let feature_flags = get_feature_flags(config); - Config { - publish_decorations: config.publish_decorations, - publish_diagnostics: feature_flags.get("lsp.diagnostics"), - notifications: NotificationsConfig { - workspace_loaded: feature_flags.get("notifications.workspace-loaded"), - cargo_toml_not_found: feature_flags.get("notifications.cargo-toml-not-found"), - }, - 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: InlayHintsConfig { - 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, - }, - completion: CompletionConfig { - enable_postfix_completions: feature_flags.get("completion.enable-postfix"), - add_call_parenthesis: feature_flags.get("completion.insertion.add-call-parenthesis"), - add_call_argument_snippets: feature_flags - .get("completion.insertion.add-argument-snippets"), - }, - call_info_full: feature_flags.get("call-info.full"), - check: if config.cargo_watch_enable { - Some(FlycheckConfig::CargoCommand { - command: config.cargo_watch_command.clone(), - all_targets: config.cargo_watch_all_targets, - extra_args: config.cargo_watch_args.clone(), - }) - } else { - None - }, - rustfmt: RustfmtConfig::Rustfmt { extra_args: config.rustfmt_args.clone() }, - vscode_lldb: config.vscode_lldb, - proc_macro_srv: None, // FIXME: get this from config - lru_capacity: config.lru_capacity, - use_client_watching: config.use_client_watching, - exclude_globs: config.exclude_globs.clone(), - cargo: config.cargo_features.clone(), - with_sysroot: config.with_sysroot, - } -} - -fn get_feature_flags(config: &ServerConfig) -> 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); +impl Default for Config { + fn default() -> Self { + Config { + publish_decorations: false, + publish_diagnostics: true, + notifications: NotificationsConfig { + workspace_loaded: true, + cargo_toml_not_found: true, + }, + supports_location_link: false, + line_folding_only: false, + inlay_hints: InlayHintsConfig { + type_hints: true, + parameter_hints: true, + chaining_hints: true, + max_length: None, + }, + completion: CompletionConfig { + enable_postfix_completions: true, + add_call_parenthesis: true, + add_call_argument_snippets: true, + }, + call_info_full: true, + rustfmt: RustfmtConfig::default(), + check: Some(FlycheckConfig::default()), + vscode_lldb: false, + proc_macro_srv: None, + lru_capacity: None, + use_client_watching: false, + exclude_globs: Vec::new(), + cargo: CargoFeatures::default(), + with_sysroot: true, } } - log::info!("feature_flags: {:#?}", ff); - ff } -/// Client provided initialization options -#[derive(Deserialize, Clone, Debug, PartialEq, Eq)] -#[serde(rename_all = "camelCase", default)] -pub struct ServerConfig { - /// Whether the client supports our custom highlighting publishing decorations. - /// This is different to the highlightingOn setting, which is whether the user - /// wants our custom highlighting to be used. - /// - /// Defaults to `false` - #[serde(deserialize_with = "nullable_bool_false")] - pub publish_decorations: bool, - - pub exclude_globs: Vec, - #[serde(deserialize_with = "nullable_bool_false")] - pub use_client_watching: bool, - - pub lru_capacity: Option, - - #[serde(deserialize_with = "nullable_bool_true")] - pub inlay_hints_type: bool, - #[serde(deserialize_with = "nullable_bool_true")] - pub inlay_hints_parameter: bool, - #[serde(deserialize_with = "nullable_bool_true")] - pub inlay_hints_chaining: bool, - pub inlay_hints_max_length: Option, - - pub cargo_watch_enable: bool, - pub cargo_watch_args: Vec, - pub cargo_watch_command: String, - pub cargo_watch_all_targets: bool, - - /// For internal usage to make integrated tests faster. - #[serde(deserialize_with = "nullable_bool_true")] - pub with_sysroot: bool, +impl Config { + #[rustfmt::skip] + pub fn update(&mut self, value: &serde_json::Value) { + let line_folding_only = self.line_folding_only; + let supports_location_link = self.supports_location_link; + *self = Default::default(); + self.line_folding_only = line_folding_only; + self.supports_location_link = supports_location_link; + + set(value, "publishDecorations", &mut self.publish_decorations); + set(value, "excludeGlobs", &mut self.exclude_globs); + set(value, "useClientWatching", &mut self.use_client_watching); + set(value, "lruCapacity", &mut self.lru_capacity); + + set(value, "inlayHintsType", &mut self.inlay_hints.type_hints); + set(value, "inlayHintsParameter", &mut self.inlay_hints.parameter_hints); + set(value, "inlayHintsChaining", &mut self.inlay_hints.chaining_hints); + set(value, "inlayHintsMaxLength", &mut self.inlay_hints.max_length); + + if let Some(false) = get(value, "cargo_watch_enable") { + self.check = None + } else { + if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets }) = &mut self.check + { + set(value, "cargoWatchArgs", extra_args); + set(value, "cargoWatchCommand", command); + set(value, "cargoWatchAllTargets", all_targets); + } + }; + + set(value, "withSysroot", &mut self.with_sysroot); + if let RustfmtConfig::Rustfmt { extra_args } = &mut self.rustfmt { + set(value, "rustfmtArgs", extra_args); + } - /// Fine grained feature flags to disable specific features. - pub feature_flags: FxHashMap, + set(value, "cargoFeatures/noDefaultFeatures", &mut self.cargo.no_default_features); + set(value, "cargoFeatures/allFeatures", &mut self.cargo.all_features); + set(value, "cargoFeatures/features", &mut self.cargo.features); + set(value, "cargoFeatures/loadOutDirsFromCheck", &mut self.cargo.load_out_dirs_from_check); - pub rustfmt_args: Vec, + set(value, "vscodeLldb", &mut self.vscode_lldb); - /// Cargo feature configurations. - pub cargo_features: CargoFeatures, + set(value, "featureFlags/lsp.diagnostics", &mut self.publish_diagnostics); + set(value, "featureFlags/notifications.workspace-loaded", &mut self.notifications.workspace_loaded); + set(value, "featureFlags/notifications.cargo-toml-not-found", &mut self.notifications.cargo_toml_not_found); + set(value, "featureFlags/completion.enable-postfix", &mut self.completion.enable_postfix_completions); + set(value, "featureFlags/completion.insertion.add-call-parenthesis", &mut self.completion.add_call_parenthesis); + set(value, "featureFlags/completion.insertion.add-argument-snippets", &mut self.completion.add_call_argument_snippets); + set(value, "featureFlags/call-info.full", &mut self.call_info_full); - /// Enabled if the vscode_lldb extension is available. - pub vscode_lldb: bool, -} + fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option { + value.pointer(pointer).and_then(|it| T::deserialize(it).ok()) + } -impl Default for ServerConfig { - fn default() -> ServerConfig { - ServerConfig { - publish_decorations: false, - exclude_globs: Vec::new(), - use_client_watching: false, - lru_capacity: None, - inlay_hints_type: true, - inlay_hints_parameter: true, - inlay_hints_chaining: true, - inlay_hints_max_length: None, - cargo_watch_enable: true, - cargo_watch_args: Vec::new(), - cargo_watch_command: "check".to_string(), - cargo_watch_all_targets: true, - with_sysroot: true, - feature_flags: FxHashMap::default(), - cargo_features: Default::default(), - rustfmt_args: Vec::new(), - vscode_lldb: false, + fn set<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str, slot: &mut T) { + if let Some(new_value) = get(value, pointer) { + *slot = new_value + } } } -} - -/// Deserializes a null value to a bool false by default -fn nullable_bool_false<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let opt = Option::deserialize(deserializer)?; - Ok(opt.unwrap_or(false)) -} -/// Deserializes a null value to a bool true by default -fn nullable_bool_true<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let opt = Option::deserialize(deserializer)?; - Ok(opt.unwrap_or(true)) -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn deserialize_init_options_defaults() { - // check that null == default for both fields - let default = ServerConfig::default(); - assert_eq!(default, serde_json::from_str(r#"{}"#).unwrap()); - assert_eq!( - default, - serde_json::from_str(r#"{"publishDecorations":null, "lruCapacity":null}"#).unwrap() - ); + pub fn update_caps(&mut self, caps: &TextDocumentClientCapabilities) { + if let Some(value) = caps.definition.as_ref().and_then(|it| it.link_support) { + self.supports_location_link = value; + } + if let Some(value) = caps.folding_range.as_ref().and_then(|it| it.line_folding_only) { + self.line_folding_only = value + } } } diff --git a/crates/rust-analyzer/src/feature_flags.rs b/crates/rust-analyzer/src/feature_flags.rs deleted file mode 100644 index dbb3f50a0..000000000 --- a/crates/rust-analyzer/src/feature_flags.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! See docs for `FeatureFlags`. - -use rustc_hash::FxHashMap; - -// FIXME: looks like a much better design is to pass options to each call, -// rather than to have a global ambient feature flags -- that way, the clients -// can issue two successive calls with different options. - -/// Feature flags hold fine-grained toggles for all *user-visible* features of -/// rust-analyzer. -/// -/// The exists such that users are able to disable any annoying feature (and, -/// with many users and many features, some features are bound to be annoying -/// for some users) -/// -/// Note that we purposefully use run-time checked strings, and not something -/// checked at compile time, to keep things simple and flexible. -/// -/// Also note that, at the moment, `FeatureFlags` also store features for -/// `rust-analyzer`. This should be benign layering violation. -#[derive(Debug)] -pub struct FeatureFlags { - flags: FxHashMap, -} - -impl FeatureFlags { - fn new(flags: &[(&str, bool)]) -> FeatureFlags { - let flags = flags - .iter() - .map(|&(name, value)| { - check_flag_name(name); - (name.to_string(), value) - }) - .collect(); - FeatureFlags { flags } - } - - pub fn set(&mut self, flag: &str, value: bool) -> Result<(), ()> { - match self.flags.get_mut(flag) { - None => Err(()), - Some(slot) => { - *slot = value; - Ok(()) - } - } - } - - pub fn get(&self, flag: &str) -> bool { - match self.flags.get(flag) { - None => panic!("unknown flag: {:?}", flag), - Some(value) => *value, - } - } -} - -impl Default for FeatureFlags { - fn default() -> FeatureFlags { - FeatureFlags::new(&[ - ("lsp.diagnostics", true), - ("completion.insertion.add-call-parenthesis", true), - ("completion.insertion.add-argument-snippets", true), - ("completion.enable-postfix", true), - ("call-info.full", true), - ("notifications.workspace-loaded", true), - ("notifications.cargo-toml-not-found", true), - ]) - } -} - -fn check_flag_name(flag: &str) { - for c in flag.bytes() { - match c { - b'a'..=b'z' | b'-' | b'.' => (), - _ => panic!("flag name does not match conventions: {:?}", flag), - } - } -} diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index e50e47b19..6062d0984 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs @@ -37,14 +37,13 @@ mod config; mod world; mod diagnostics; mod semantic_tokens; -mod feature_flags; use serde::de::DeserializeOwned; pub type Result = std::result::Result>; pub use crate::{ + config::Config, caps::server_capabilities, - config::ServerConfig, main_loop::LspError, main_loop::{main_loop, show_message}, }; diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index c973d43fa..00f92dbd5 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -17,9 +17,8 @@ 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, TextDocumentClientCapabilities, WorkDoneProgress, - WorkDoneProgressBegin, WorkDoneProgressCreateParams, WorkDoneProgressEnd, - WorkDoneProgressReport, + NumberOrString, WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressCreateParams, + WorkDoneProgressEnd, WorkDoneProgressReport, }; use ra_flycheck::{url_from_path_with_drive_lowercasing, CheckTask}; use ra_ide::{Canceled, FileId, LibraryData, SourceRootId}; @@ -31,7 +30,7 @@ use serde::{de::DeserializeOwned, Serialize}; use threadpool::ThreadPool; use crate::{ - config::get_config, + config::Config, diagnostics::DiagnosticTask, main_loop::{ pending_requests::{PendingRequest, PendingRequests}, @@ -39,7 +38,7 @@ use crate::{ }, req, world::{WorldSnapshot, WorldState}, - Result, ServerConfig, + Result, }; use req::ConfigurationParams; @@ -65,14 +64,7 @@ impl fmt::Display for LspError { impl Error for LspError {} -pub fn main_loop( - ws_roots: Vec, - client_caps: ClientCapabilities, - config: ServerConfig, - connection: Connection, -) -> Result<()> { - let text_document_caps = client_caps.text_document.as_ref(); - let config = get_config(&config, text_document_caps); +pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) -> Result<()> { log::info!("initial config: {:#?}", config); // Windows scheduler implements priority boosts: if thread waits for an @@ -205,7 +197,6 @@ pub fn main_loop( &task_sender, &libdata_sender, &connection, - text_document_caps, &mut world_state, &mut loop_state, event, @@ -316,7 +307,6 @@ 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, @@ -370,27 +360,14 @@ fn loop_turn( log::debug!("config update response: '{:?}", resp); let Response { error, result, .. } = resp; - match ( - error, - result.map(|result| serde_json::from_value::>(result)), - ) { + match (error, result) { (Some(err), _) => { log::error!("failed to fetch the server settings: {:?}", err) } - (None, Some(Ok(new_config))) => { - let new_config = new_config - .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_config(&new_config, text_document_caps), - ); - } - (None, Some(Err(e))) => { - log::error!("failed to parse client config response: {}", e) + (None, Some(new_config)) => { + let mut config = world_state.config.clone(); + config.update(&new_config); + world_state.update_configuration(config); } (None, None) => { log::error!("received empty server settings response from the client") diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index df1b7ceeb..5674f42ef 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs @@ -11,7 +11,7 @@ use std::{ use crossbeam_channel::{unbounded, Receiver}; use lsp_types::Url; use parking_lot::RwLock; -use ra_flycheck::{url_from_path_with_drive_lowercasing, Flycheck}; +use ra_flycheck::{url_from_path_with_drive_lowercasing, Flycheck, FlycheckConfig}; use ra_ide::{ Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, }; @@ -30,9 +30,7 @@ use crate::{ use ra_db::ExternSourceId; use rustc_hash::{FxHashMap, FxHashSet}; -fn create_flycheck(workspaces: &[ProjectWorkspace], config: &Config) -> Option { - let check_config = config.check.as_ref()?; - +fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) -> Option { // FIXME: Figure out the multi-workspace situation workspaces .iter() @@ -42,7 +40,7 @@ fn create_flycheck(workspaces: &[ProjectWorkspace], config: &Config) -> Option, config: Config) { - self.analysis_host.update_lru_capacity(lru_capacity); - self.flycheck = create_flycheck(&self.workspaces, &config); + pub fn update_configuration(&mut self, config: Config) { + self.analysis_host.update_lru_capacity(config.lru_capacity); + if config.check != self.config.check { + self.flycheck = + config.check.as_ref().and_then(|it| create_flycheck(&self.workspaces, it)); + } + self.config = config; } diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 5af5eaad2..638813311 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -615,7 +615,7 @@ fn main() { message(); } "###, ) .with_config(|config| { - config.cargo_features.load_out_dirs_from_check = true; + config.cargo.load_out_dirs_from_check = true; }) .server(); server.wait_until_workspace_is_loaded(); diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs index d8bed6d7f..c83cb8adb 100644 --- a/crates/rust-analyzer/tests/heavy_tests/support.rs +++ b/crates/rust-analyzer/tests/heavy_tests/support.rs @@ -11,8 +11,7 @@ use lsp_server::{Connection, Message, Notification, Request}; use lsp_types::{ notification::{DidOpenTextDocument, Exit}, request::Shutdown, - ClientCapabilities, DidOpenTextDocumentParams, GotoCapability, TextDocumentClientCapabilities, - TextDocumentIdentifier, TextDocumentItem, Url, WorkDoneProgress, + DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url, WorkDoneProgress, }; use serde::Serialize; use serde_json::{to_string_pretty, Value}; @@ -20,14 +19,14 @@ use tempfile::TempDir; use test_utils::{find_mismatch, parse_fixture}; use req::{ProgressParams, ProgressParamsValue}; -use rust_analyzer::{main_loop, req, ServerConfig}; +use rust_analyzer::{main_loop, req, Config}; pub struct Project<'a> { fixture: &'a str, with_sysroot: bool, tmp_dir: Option, roots: Vec, - config: Option>, + config: Option>, } impl<'a> Project<'a> { @@ -50,7 +49,7 @@ impl<'a> Project<'a> { self } - pub fn with_config(mut self, config: impl Fn(&mut ServerConfig) + 'static) -> Project<'a> { + pub fn with_config(mut self, config: impl Fn(&mut Config) + 'static) -> Project<'a> { self.config = Some(Box::new(config)); self } @@ -78,8 +77,11 @@ impl<'a> Project<'a> { let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect(); - let mut config = - ServerConfig { with_sysroot: self.with_sysroot, ..ServerConfig::default() }; + let mut config = Config { + supports_location_link: true, + with_sysroot: self.with_sysroot, + ..Config::default() + }; if let Some(f) = &self.config { f(&mut config) @@ -105,7 +107,7 @@ pub struct Server { impl Server { fn new( dir: TempDir, - config: ServerConfig, + config: Config, roots: Vec, files: Vec<(PathBuf, String)>, ) -> Server { @@ -116,26 +118,7 @@ impl Server { let _thread = jod_thread::Builder::new() .name("test server".to_string()) - .spawn(move || { - main_loop( - roots, - ClientCapabilities { - workspace: None, - text_document: Some(TextDocumentClientCapabilities { - definition: Some(GotoCapability { - dynamic_registration: None, - link_support: Some(true), - }), - ..Default::default() - }), - window: None, - experimental: None, - }, - config, - connection, - ) - .unwrap() - }) + .spawn(move || main_loop(roots, config, connection).unwrap()) .expect("failed to spawn a thread"); let res = -- cgit v1.2.3