@@ -200,15 +200,11 @@ pub async fn get_import_completions(
200200 {
201201 // completions for import map specifiers
202202 Some ( lsp:: CompletionResponse :: List ( completion_list) )
203- } else if text. starts_with ( "./" )
204- || text. starts_with ( "../" )
205- || text. starts_with ( '/' )
203+ } else if let Some ( completion_list) =
204+ get_local_completions ( specifier, & text, & range, resolver)
206205 {
207206 // completions for local relative modules
208- Some ( lsp:: CompletionResponse :: List ( CompletionList {
209- is_incomplete : false ,
210- items : get_local_completions ( specifier, & text, & range, resolver) ?,
211- } ) )
207+ Some ( lsp:: CompletionResponse :: List ( completion_list) )
212208 } else if !text. is_empty ( ) {
213209 // completion of modules from a module registry or cache
214210 check_auto_config_registry (
@@ -363,15 +359,15 @@ fn get_local_completions(
363359 text : & str ,
364360 range : & lsp:: Range ,
365361 resolver : & LspResolver ,
366- ) -> Option < Vec < lsp :: CompletionItem > > {
362+ ) -> Option < CompletionList > {
367363 if base. scheme ( ) != "file" {
368364 return None ;
369365 }
370- let parent = base . join ( text) . ok ( ) ? . join ( "." ) . ok ( ) ? ;
366+ let parent = & text [ .. text. char_indices ( ) . rfind ( | ( _ , c ) | * c == '/' ) ? . 0 + 1 ] ;
371367 let resolved_parent = resolver
372368 . as_graph_resolver ( Some ( base) )
373369 . resolve (
374- parent. as_str ( ) ,
370+ parent,
375371 & Range {
376372 specifier : base. clone ( ) ,
377373 start : deno_graph:: Position :: zeroed ( ) ,
@@ -381,62 +377,62 @@ fn get_local_completions(
381377 )
382378 . ok ( ) ?;
383379 let resolved_parent_path = url_to_file_path ( & resolved_parent) . ok ( ) ?;
384- let raw_parent =
385- & text[ ..text. char_indices ( ) . rfind ( |( _, c) | * c == '/' ) ?. 0 + 1 ] ;
386380 if resolved_parent_path. is_dir ( ) {
387381 let cwd = std:: env:: current_dir ( ) . ok ( ) ?;
388- let items = std:: fs:: read_dir ( resolved_parent_path) . ok ( ) ?;
389- Some (
390- items
391- . filter_map ( |de| {
392- let de = de. ok ( ) ?;
393- let label = de. path ( ) . file_name ( ) ?. to_string_lossy ( ) . to_string ( ) ;
394- let entry_specifier = resolve_path ( de. path ( ) . to_str ( ) ?, & cwd) . ok ( ) ?;
395- if entry_specifier == * base {
396- return None ;
397- }
398- let full_text = format ! ( "{raw_parent}{label}" ) ;
399- let text_edit = Some ( lsp:: CompletionTextEdit :: Edit ( lsp:: TextEdit {
400- range : * range,
401- new_text : full_text. clone ( ) ,
402- } ) ) ;
403- let filter_text = Some ( full_text) ;
404- match de. file_type ( ) {
405- Ok ( file_type) if file_type. is_dir ( ) => Some ( lsp:: CompletionItem {
406- label,
407- kind : Some ( lsp:: CompletionItemKind :: FOLDER ) ,
408- detail : Some ( "(local)" . to_string ( ) ) ,
409- filter_text,
410- sort_text : Some ( "1" . to_string ( ) ) ,
411- text_edit,
412- commit_characters : Some (
413- IMPORT_COMMIT_CHARS . iter ( ) . map ( |& c| c. into ( ) ) . collect ( ) ,
414- ) ,
415- ..Default :: default ( )
416- } ) ,
417- Ok ( file_type) if file_type. is_file ( ) => {
418- if is_importable_ext ( & de. path ( ) ) {
419- Some ( lsp:: CompletionItem {
420- label,
421- kind : Some ( lsp:: CompletionItemKind :: FILE ) ,
422- detail : Some ( "(local)" . to_string ( ) ) ,
423- filter_text,
424- sort_text : Some ( "1" . to_string ( ) ) ,
425- text_edit,
426- commit_characters : Some (
427- IMPORT_COMMIT_CHARS . iter ( ) . map ( |& c| c. into ( ) ) . collect ( ) ,
428- ) ,
429- ..Default :: default ( )
430- } )
431- } else {
432- None
433- }
382+ let entries = std:: fs:: read_dir ( resolved_parent_path) . ok ( ) ?;
383+ let items = entries
384+ . filter_map ( |de| {
385+ let de = de. ok ( ) ?;
386+ let label = de. path ( ) . file_name ( ) ?. to_string_lossy ( ) . to_string ( ) ;
387+ let entry_specifier = resolve_path ( de. path ( ) . to_str ( ) ?, & cwd) . ok ( ) ?;
388+ if entry_specifier == * base {
389+ return None ;
390+ }
391+ let full_text = format ! ( "{parent}{label}" ) ;
392+ let text_edit = Some ( lsp:: CompletionTextEdit :: Edit ( lsp:: TextEdit {
393+ range : * range,
394+ new_text : full_text. clone ( ) ,
395+ } ) ) ;
396+ let filter_text = Some ( full_text) ;
397+ match de. file_type ( ) {
398+ Ok ( file_type) if file_type. is_dir ( ) => Some ( lsp:: CompletionItem {
399+ label,
400+ kind : Some ( lsp:: CompletionItemKind :: FOLDER ) ,
401+ detail : Some ( "(local)" . to_string ( ) ) ,
402+ filter_text,
403+ sort_text : Some ( "1" . to_string ( ) ) ,
404+ text_edit,
405+ commit_characters : Some (
406+ IMPORT_COMMIT_CHARS . iter ( ) . map ( |& c| c. into ( ) ) . collect ( ) ,
407+ ) ,
408+ ..Default :: default ( )
409+ } ) ,
410+ Ok ( file_type) if file_type. is_file ( ) => {
411+ if is_importable_ext ( & de. path ( ) ) {
412+ Some ( lsp:: CompletionItem {
413+ label,
414+ kind : Some ( lsp:: CompletionItemKind :: FILE ) ,
415+ detail : Some ( "(local)" . to_string ( ) ) ,
416+ filter_text,
417+ sort_text : Some ( "1" . to_string ( ) ) ,
418+ text_edit,
419+ commit_characters : Some (
420+ IMPORT_COMMIT_CHARS . iter ( ) . map ( |& c| c. into ( ) ) . collect ( ) ,
421+ ) ,
422+ ..Default :: default ( )
423+ } )
424+ } else {
425+ None
434426 }
435- _ => None ,
436427 }
437- } )
438- . collect ( ) ,
439- )
428+ _ => None ,
429+ }
430+ } )
431+ . collect ( ) ;
432+ Some ( CompletionList {
433+ is_incomplete : false ,
434+ items,
435+ } )
440436 } else {
441437 None
442438 }
@@ -921,11 +917,11 @@ mod tests {
921917 } ,
922918 } ,
923919 & Default :: default ( ) ,
924- ) ;
925- assert ! ( actual . is_some ( ) ) ;
926- let actual = actual . unwrap ( ) ;
927- assert_eq ! ( actual. len( ) , 3 ) ;
928- for item in actual {
920+ )
921+ . unwrap ( ) ;
922+ assert ! ( ! actual. is_incomplete ) ;
923+ assert_eq ! ( actual. items . len( ) , 3 ) ;
924+ for item in actual. items {
929925 match item. text_edit {
930926 Some ( lsp:: CompletionTextEdit :: Edit ( text_edit) ) => {
931927 assert ! ( [ "./b" , "./f.mjs" , "./g.json" ]
0 commit comments