@@ -139,19 +139,20 @@ impl DiagnosticService {
139139 source_start : u32 ,
140140 diagnostics : Vec < OxcDiagnostic > ,
141141 ) -> Vec < Error > {
142- # [ cfg( test) ]
143- let is_jetbrains = false ;
144- # [ cfg ( not ( test ) ) ]
145- let is_jetbrains =
146- std :: env :: var ( "TERMINAL_EMULATOR" ) . is_ok_and ( |x| x . eq ( "JetBrains-JediTerm" ) ) ;
142+ let is_jetbrains = if cfg ! ( test) {
143+ false
144+ } else {
145+ std :: env :: var ( "TERMINAL_EMULATOR" ) . is_ok_and ( |x| x . eq ( "JetBrains-JediTerm" ) )
146+ } ;
147147
148148 let path_ref = path. as_ref ( ) ;
149- let path_display = if is_jetbrains { from_file_path ( path_ref) } else { None } ;
150- let path_display = path_display. unwrap_or_else ( || {
151- let relative_path = path_ref. strip_prefix ( cwd) . unwrap_or ( path_ref) . to_string_lossy ( ) ;
152- let normalized_path = relative_path. cow_replace ( '\\' , "/" ) ;
153- normalized_path. to_string ( )
154- } ) ;
149+ let path_display = if is_jetbrains { from_file_path ( path_ref) } else { None }
150+ . unwrap_or_else ( || {
151+ let relative_path =
152+ path_ref. strip_prefix ( cwd) . unwrap_or ( path_ref) . to_string_lossy ( ) ;
153+ let normalized_path = relative_path. cow_replace ( '\\' , "/" ) ;
154+ normalized_path. to_string ( )
155+ } ) ;
155156
156157 let source = Arc :: new ( NamedSource :: new ( path_display, source_text. to_owned ( ) ) ) ;
157158 diagnostics
@@ -302,14 +303,17 @@ fn from_file_path<A: AsRef<Path>>(path: A) -> Option<String> {
302303 } ;
303304
304305 if cfg ! ( windows) {
305- // we want to parse a triple-slash path for Windows paths
306+ // we want to write a triple-slash path for Windows paths
306307 // it's a shorthand for `file://localhost/C:/Windows` with the `localhost` omitted.
307- // We encode the driver Letter `C:` as well. LSP Specification allows it.
308- // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#uri
308+ let mut components = fragment. components ( ) ;
309+ let drive = components. next ( ) ;
310+
309311 Some ( format ! (
310- "file:///{}" ,
312+ "file:///{:?}:/{}" ,
313+ drive. unwrap( ) . as_os_str( ) . to_string_lossy( ) ,
311314 percent_encoding:: utf8_percent_encode(
312- & fragment. to_string_lossy( ) . cow_replace( '\\' , "/" ) ,
315+ // Skip the drive character.
316+ & components. collect:: <PathBuf >( ) . to_string_lossy( ) . cow_replace( '\\' , "/" ) ,
313317 & ASCII_SET
314318 )
315319 ) )
@@ -350,3 +354,72 @@ fn strict_canonicalize<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> {
350354 let canon = std:: fs:: canonicalize ( path) ?;
351355 impl_ ( canon)
352356}
357+
358+ #[ cfg( test) ]
359+ mod tests {
360+ use crate :: service:: from_file_path;
361+ use std:: path:: PathBuf ;
362+
363+ fn with_schema ( path : & str ) -> String {
364+ const EXPECTED_SCHEMA : & str = if cfg ! ( windows) { "file:///" } else { "file://" } ;
365+ format ! ( "{EXPECTED_SCHEMA}{path}" )
366+ }
367+
368+ #[ test]
369+ #[ cfg( windows) ]
370+ fn test_idempotent_canonicalization ( ) {
371+ let lhs = strict_canonicalize ( Path :: new ( "." ) ) . unwrap ( ) ;
372+ let rhs = strict_canonicalize ( & lhs) . unwrap ( ) ;
373+ assert_eq ! ( lhs, rhs) ;
374+ }
375+
376+ #[ test]
377+ #[ cfg( unix) ]
378+ fn test_path_to_uri ( ) {
379+ let paths = [
380+ PathBuf :: from ( "/some/path/to/file.txt" ) ,
381+ PathBuf :: from ( "/some/path/to/file with spaces.txt" ) ,
382+ PathBuf :: from ( "/some/path/[[...rest]]/file.txt" ) ,
383+ PathBuf :: from ( "/some/path/to/файл.txt" ) ,
384+ PathBuf :: from ( "/some/path/to/文件.txt" ) ,
385+ ] ;
386+
387+ let expected = [
388+ with_schema ( "/some/path/to/file.txt" ) ,
389+ with_schema ( "/some/path/to/file%20with%20spaces.txt" ) ,
390+ with_schema ( "/some/path/%5B%5B...rest%5D%5D/file.txt" ) ,
391+ with_schema ( "/some/path/to/%D1%84%D0%B0%D0%B9%D0%BB.txt" ) ,
392+ with_schema ( "/some/path/to/%E6%96%87%E4%BB%B6.txt" ) ,
393+ ] ;
394+
395+ for ( path, expected) in paths. iter ( ) . zip ( expected) {
396+ let uri = from_file_path ( path) . unwrap ( ) ;
397+ assert_eq ! ( uri. to_string( ) , expected) ;
398+ }
399+ }
400+
401+ #[ test]
402+ #[ cfg( windows) ]
403+ fn test_path_to_uri_windows ( ) {
404+ let paths = [
405+ PathBuf :: from ( "C:\\ some\\ path\\ to\\ file.txt" ) ,
406+ PathBuf :: from ( "C:\\ some\\ path\\ to\\ file with spaces.txt" ) ,
407+ PathBuf :: from ( "C:\\ some\\ path\\ [[...rest]]\\ file.txt" ) ,
408+ PathBuf :: from ( "C:\\ some\\ path\\ to\\ файл.txt" ) ,
409+ PathBuf :: from ( "C:\\ some\\ path\\ to\\ 文件.txt" ) ,
410+ ] ;
411+
412+ let expected = [
413+ with_schema ( "C:/some/path/to/file.txt" ) ,
414+ with_schema ( "C:/some/path/to/file%20with%20spaces.txt" ) ,
415+ with_schema ( "C:/some/path/%5B%5B...rest%5D%5D/file.txt" ) ,
416+ with_schema ( "C:/some/path/to/%D1%84%D0%B0%D0%B9%D0%BB.txt" ) ,
417+ with_schema ( "C:/some/path/to/%E6%96%87%E4%BB%B6.txt" ) ,
418+ ] ;
419+
420+ for ( path, expected) in paths. iter ( ) . zip ( expected) {
421+ let uri = Uri :: from_file_path ( path) . unwrap ( ) ;
422+ assert_eq ! ( uri. to_string( ) , expected) ;
423+ }
424+ }
425+ }
0 commit comments