@@ -15,6 +15,7 @@ use deno_semver::jsr::JsrPackageReqReference;
1515use deno_semver:: package:: PackageNv ;
1616use import_map:: ImportMap ;
1717use indexmap:: IndexSet ;
18+ use lsp_types:: CompletionItem ;
1819use lsp_types:: CompletionList ;
1920use node_resolver:: NodeResolutionKind ;
2021use node_resolver:: ResolutionMode ;
@@ -159,10 +160,11 @@ pub async fn get_import_completions(
159160 document_modules : & DocumentModules ,
160161 resolver : & LspResolver ,
161162) -> Option < lsp:: CompletionResponse > {
162- let maybe_import_map = resolver
163+ let maybe_import_maps = resolver
163164 . get_scoped_resolver ( module. scope . as_deref ( ) )
164165 . as_workspace_resolver ( )
165- . maybe_import_map ( ) ;
166+ . maybe_import_maps ( )
167+ . collect :: < Vec < _ > > ( ) ;
166168 let ( text, _, graph_range) = module. dependency_at_position ( position) ?;
167169 let resolution_mode = graph_range
168170 . resolution_mode
@@ -206,11 +208,11 @@ pub async fn get_import_completions(
206208 Some ( lsp:: CompletionResponse :: List ( completion_list) )
207209 }
208210 _ => {
209- match get_import_map_completions (
211+ match get_import_maps_completions (
210212 & module. specifier ,
211213 text,
212214 & range,
213- maybe_import_map ,
215+ & maybe_import_maps ,
214216 ) {
215217 Some ( completion_list) => {
216218 // completions for import map specifiers
@@ -286,7 +288,7 @@ pub async fn get_import_completions(
286288 } )
287289 . collect ( ) ;
288290 let mut is_incomplete = false ;
289- if let Some ( import_map) = maybe_import_map {
291+ for import_map in maybe_import_maps {
290292 items. extend ( get_base_import_map_completions (
291293 import_map,
292294 & module. specifier ,
@@ -363,49 +365,65 @@ fn get_import_map_completions(
363365 _specifier : & ModuleSpecifier ,
364366 text : & str ,
365367 range : & lsp:: Range ,
366- maybe_import_map : Option < & ImportMap > ,
367- ) -> Option < CompletionList > {
368- if !text. is_empty ( )
369- && let Some ( import_map) = maybe_import_map
370- {
371- let mut specifiers = IndexSet :: new ( ) ;
372- for key in import_map. imports ( ) . keys ( ) {
373- // for some reason, the import_map stores keys that begin with `/` as
374- // `file:///` in its index, so we have to reverse that here
375- let key = if key. starts_with ( "file://" ) {
376- FILE_PROTO_RE . replace ( key, "" ) . to_string ( )
377- } else {
378- key. to_string ( )
379- } ;
380- if key. starts_with ( text) && key != text {
381- specifiers. insert ( key. trim_end_matches ( '/' ) . to_string ( ) ) ;
382- }
383- }
384- if !specifiers. is_empty ( ) {
385- let items = specifiers
386- . into_iter ( )
387- . map ( |specifier| lsp:: CompletionItem {
388- label : specifier. clone ( ) ,
389- kind : Some ( lsp:: CompletionItemKind :: FILE ) ,
390- detail : Some ( "(import map)" . to_string ( ) ) ,
391- sort_text : Some ( "1" . to_string ( ) ) ,
392- text_edit : Some ( lsp:: CompletionTextEdit :: Edit ( lsp:: TextEdit {
393- range : * range,
394- new_text : specifier,
395- } ) ) ,
396- commit_characters : Some (
397- IMPORT_COMMIT_CHARS . iter ( ) . map ( |& c| c. into ( ) ) . collect ( ) ,
398- ) ,
399- ..Default :: default ( )
400- } )
401- . collect ( ) ;
402- return Some ( CompletionList {
403- items,
404- is_incomplete : false ,
405- } ) ;
368+ import_map : & ImportMap ,
369+ ) -> Vec < CompletionItem > {
370+ if text. is_empty ( ) {
371+ return vec ! [ ] ;
372+ }
373+ let mut specifiers = IndexSet :: new ( ) ;
374+ for key in import_map. imports ( ) . keys ( ) {
375+ // for some reason, the import_map stores keys that begin with `/` as
376+ // `file:///` in its index, so we have to reverse that here
377+ let key = if key. starts_with ( "file://" ) {
378+ FILE_PROTO_RE . replace ( key, "" ) . to_string ( )
379+ } else {
380+ key. to_string ( )
381+ } ;
382+ if key. starts_with ( text) && key != text {
383+ specifiers. insert ( key. trim_end_matches ( '/' ) . to_string ( ) ) ;
406384 }
407385 }
408- None
386+ if specifiers. is_empty ( ) {
387+ return vec ! [ ] ;
388+ }
389+ specifiers
390+ . into_iter ( )
391+ . map ( |specifier| lsp:: CompletionItem {
392+ label : specifier. clone ( ) ,
393+ kind : Some ( lsp:: CompletionItemKind :: FILE ) ,
394+ detail : Some ( "(import map)" . to_string ( ) ) ,
395+ sort_text : Some ( "1" . to_string ( ) ) ,
396+ text_edit : Some ( lsp:: CompletionTextEdit :: Edit ( lsp:: TextEdit {
397+ range : * range,
398+ new_text : specifier,
399+ } ) ) ,
400+ commit_characters : Some (
401+ IMPORT_COMMIT_CHARS . iter ( ) . map ( |& c| c. into ( ) ) . collect ( ) ,
402+ ) ,
403+ ..Default :: default ( )
404+ } )
405+ . collect ( )
406+ }
407+ fn get_import_maps_completions < ' i > (
408+ _specifier : & ModuleSpecifier ,
409+ text : & str ,
410+ range : & lsp:: Range ,
411+ import_maps : & [ & ImportMap ] ,
412+ ) -> Option < CompletionList > {
413+ if text. is_empty ( ) || import_maps. is_empty ( ) {
414+ return None ;
415+ }
416+ let mut out = CompletionList {
417+ is_incomplete : false ,
418+ items : vec ! [ ] ,
419+ } ;
420+
421+ for import_map in import_maps {
422+ out. items . extend ( get_import_map_completions (
423+ _specifier, text, range, import_map,
424+ ) )
425+ }
426+ Some ( out)
409427}
410428
411429/// Return local completions that are relative to the base specifier.
0 commit comments