From f912aac2cb94d1770219bc2c25471e0a23bb2d64 Mon Sep 17 00:00:00 2001 From: Nayeem Rahman Date: Mon, 13 Jan 2025 15:31:08 +0000 Subject: [PATCH] fix(lsp): handle pathless untitled URIs (#27637) --- cli/lsp/language_server.rs | 8 +++---- cli/lsp/urls.rs | 23 +++++++++---------- tests/integration/lsp_tests.rs | 40 ++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 35f5374efe..03f63e5f25 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -1419,18 +1419,16 @@ impl Inner { // the file path is only used to determine what formatter should // be used to format the file, so give the filepath an extension // that matches what the user selected as the language - let file_path = document + let ext = document .maybe_language_id() - .and_then(|id| id.as_extension()) - .map(|ext| file_path.with_extension(ext)) - .unwrap_or(file_path); + .and_then(|id| id.as_extension().map(|s| s.to_string())); // it's not a js/ts file, so attempt to format its contents format_file( &file_path, document.content(), &fmt_options, &unstable_options, - None, + ext, ) } }; diff --git a/cli/lsp/urls.rs b/cli/lsp/urls.rs index 91c04f11c0..2aadaf5352 100644 --- a/cli/lsp/urls.rs +++ b/cli/lsp/urls.rs @@ -282,24 +282,26 @@ impl LspUrlMap { } } -/// Convert a e.g. `deno-notebook-cell:` specifier to a `file:` specifier. +/// Convert a e.g. `vscode-notebook-cell:` specifier to a `file:` specifier. /// ```rust /// assert_eq!( /// file_like_to_file_specifier( -/// &Url::parse("deno-notebook-cell:/path/to/file.ipynb#abc").unwrap(), +/// &Url::parse("vscode-notebook-cell:/path/to/file.ipynb#abc").unwrap(), /// ), -/// Some(Url::parse("file:///path/to/file.ipynb.ts?scheme=deno-notebook-cell#abc").unwrap()), +/// Some(Url::parse("file:///path/to/file.ipynb?scheme=untitled#abc").unwrap()), /// ); fn file_like_to_file_specifier(specifier: &Url) -> Option { - if matches!(specifier.scheme(), "untitled" | "deno-notebook-cell") { + if matches!( + specifier.scheme(), + "untitled" | "vscode-notebook-cell" | "deno-notebook-cell" + ) { if let Ok(mut s) = ModuleSpecifier::parse(&format!( - "file://{}", + "file:///{}", &specifier.as_str()[deno_core::url::quirks::internal_components(specifier) - .host_end as usize..], + .host_end as usize..].trim_start_matches('/'), )) { s.query_pairs_mut() .append_pair("scheme", specifier.scheme()); - s.set_path(&format!("{}.ts", s.path())); return Some(s); } } @@ -432,11 +434,11 @@ mod tests { fn test_file_like_to_file_specifier() { assert_eq!( file_like_to_file_specifier( - &Url::parse("deno-notebook-cell:/path/to/file.ipynb#abc").unwrap(), + &Url::parse("vscode-notebook-cell:/path/to/file.ipynb#abc").unwrap(), ), Some( Url::parse( - "file:///path/to/file.ipynb.ts?scheme=deno-notebook-cell#abc" + "file:///path/to/file.ipynb?scheme=vscode-notebook-cell#abc" ) .unwrap() ), @@ -446,8 +448,7 @@ mod tests { &Url::parse("untitled:/path/to/file.ipynb#123").unwrap(), ), Some( - Url::parse("file:///path/to/file.ipynb.ts?scheme=untitled#123") - .unwrap() + Url::parse("file:///path/to/file.ipynb?scheme=untitled#123").unwrap() ), ); } diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs index a25710b2b1..bbeb6e7c13 100644 --- a/tests/integration/lsp_tests.rs +++ b/tests/integration/lsp_tests.rs @@ -11690,6 +11690,46 @@ fn lsp_format_exclude_default_config() { client.shutdown(); } +#[test] +fn lsp_format_untitled() { + let context = TestContextBuilder::new().use_temp_cwd().build(); + let mut client = context.new_lsp_command().build(); + client.initialize_default(); + client.did_open(json!({ + "textDocument": { + "uri": "untitled:Untitled-1", + "languageId": "typescript", + "version": 1, + "text": " console.log();\n", + }, + })); + let res = client.write_request( + "textDocument/formatting", + json!({ + "textDocument": { + "uri": "untitled:Untitled-1", + }, + "options": { + "tabSize": 2, + "insertSpaces": true, + }, + }), + ); + assert_eq!( + res, + json!([ + { + "range": { + "start": { "line": 0, "character": 0 }, + "end": { "line": 0, "character": 2 }, + }, + "newText": "", + }, + ]) + ); + client.shutdown(); +} + #[test] fn lsp_format_json() { let context = TestContextBuilder::new().use_temp_cwd().build();