From 0dbeb774ba9ea618ff1e92b63ab31e5caf3003dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Mon, 13 Sep 2021 20:19:10 +0200 Subject: feat(fmt): add support for configuration file (#11944) This commit adds support for configuration file for "deno fmt" subcommand. It is also respected by LSP when formatting files. Example configuration: { "fmt": { "files": { "include": ["src/"], "exclude": ["src/testdata/"] }, "options": { "useTabs": true, "lineWidth": 80, "indentWidth": 4, "singleQuote": true, "textWrap": "preserve" } } } --- cli/lsp/language_server.rs | 104 ++++++++++++++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 35 deletions(-) (limited to 'cli/lsp/language_server.rs') diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 3f1bfc923..87fc5f7e5 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -336,15 +336,15 @@ impl Inner { Ok(navigation_tree) } - fn merge_user_tsconfig( - &mut self, - maybe_config: &Option, - maybe_root_uri: &Option, - tsconfig: &mut TsConfig, - ) -> Result<(), AnyError> { - self.maybe_config_file = None; - self.maybe_config_uri = None; - if let Some(config_str) = maybe_config { + /// Returns a tuple with parsed `ConfigFile` and `Url` pointing to that file. + /// If there's no config file specified in settings returns `None`. + fn get_config_file_and_url( + &self, + ) -> Result, AnyError> { + let workspace_settings = self.config.get_workspace_settings(); + let maybe_root_uri = self.config.root_uri.clone(); + let maybe_config = workspace_settings.config; + if let Some(config_str) = &maybe_config { if !config_str.is_empty() { info!("Setting TypeScript configuration from: \"{}\"", config_str); let config_url = if let Ok(url) = Url::from_file_path(config_str) { @@ -374,18 +374,34 @@ impl Inner { .ok_or_else(|| anyhow!("Bad uri: \"{}\"", config_url))?; ConfigFile::read(path)? }; - let (value, maybe_ignored_options) = - config_file.to_compiler_options()?; - tsconfig.merge(&value); - self.maybe_config_file = Some(config_file); - self.maybe_config_uri = Some(config_url); - if let Some(ignored_options) = maybe_ignored_options { - // TODO(@kitsonk) turn these into diagnostics that can be sent to the - // client - warn!("{}", ignored_options); - } + return Ok(Some((config_file, config_url))); + } + } + + Ok(None) + } + + fn merge_user_tsconfig( + &mut self, + tsconfig: &mut TsConfig, + ) -> Result<(), AnyError> { + self.maybe_config_file = None; + self.maybe_config_uri = None; + + let maybe_file_and_url = self.get_config_file_and_url()?; + + if let Some((config_file, config_url)) = maybe_file_and_url { + let (value, maybe_ignored_options) = config_file.to_compiler_options()?; + tsconfig.merge(&value); + self.maybe_config_file = Some(config_file); + self.maybe_config_uri = Some(config_url); + if let Some(ignored_options) = maybe_ignored_options { + // TODO(@kitsonk) turn these into diagnostics that can be sent to the + // client + warn!("{}", ignored_options); } } + Ok(()) } @@ -575,20 +591,15 @@ impl Inner { // TODO(@kitsonk) remove for Deno 1.15 "useUnknownInCatchVariables": false, })); - let (maybe_config, maybe_root_uri) = { - let config = &self.config; - let workspace_settings = config.get_workspace_settings(); - if workspace_settings.unstable { - let unstable_libs = json!({ - "lib": ["deno.ns", "deno.window", "deno.unstable"] - }); - tsconfig.merge(&unstable_libs); - } - (workspace_settings.config, config.root_uri.clone()) - }; - if let Err(err) = - self.merge_user_tsconfig(&maybe_config, &maybe_root_uri, &mut tsconfig) - { + let config = &self.config; + let workspace_settings = config.get_workspace_settings(); + if workspace_settings.unstable { + let unstable_libs = json!({ + "lib": ["deno.ns", "deno.window", "deno.unstable"] + }); + tsconfig.merge(&unstable_libs); + } + if let Err(err) = self.merge_user_tsconfig(&mut tsconfig) { self.client.show_message(MessageType::Warning, err).await; } let _ok: bool = self @@ -1015,14 +1026,37 @@ impl Inner { PathBuf::from(params.text_document.uri.path()) }; + let maybe_file_and_url = self.get_config_file_and_url().map_err(|err| { + error!("Unable to parse configuration file: {}", err); + LspError::internal_error() + })?; + + let fmt_options = if let Some((config_file, _)) = maybe_file_and_url { + config_file + .to_fmt_config() + .map_err(|err| { + error!("Unable to parse fmt configuration: {}", err); + LspError::internal_error() + })? + .unwrap_or_default() + } else { + Default::default() + }; + let source = document_data.source().clone(); let text_edits = tokio::task::spawn_blocking(move || { let format_result = match source.module() { - Some(Ok(parsed_module)) => Ok(format_parsed_module(parsed_module)), + Some(Ok(parsed_module)) => { + Ok(format_parsed_module(parsed_module, fmt_options.options)) + } Some(Err(err)) => Err(err.to_string()), None => { // it's not a js/ts file, so attempt to format its contents - format_file(&file_path, source.text_info().text_str()) + format_file( + &file_path, + source.text_info().text_str(), + fmt_options.options, + ) } }; -- cgit v1.2.3