@@ -105,9 +105,13 @@ public AutocompleteResponse complete(const AutocompleteRequest request)
105105 {
106106 return parenCompletion (beforeTokens, tokenArray, request.cursorPosition);
107107 }
108- else if (beforeTokens.length >= 2 && isSelectiveImport(beforeTokens) )
108+ else if (beforeTokens.length >= 2 )
109109 {
110- return selectiveImportCompletion (beforeTokens);
110+ ImportKind kind = determineImportKind(beforeTokens);
111+ if (kind == ImportKind.neither)
112+ return dotCompletion (beforeTokens, tokenArray, request.cursorPosition);
113+ else
114+ return importCompletion (beforeTokens, kind);
111115 }
112116 else
113117 {
@@ -183,6 +187,13 @@ public AutocompleteResponse symbolSearch(const AutocompleteRequest request)
183187/* *****************************************************************************/
184188private :
185189
190+ enum ImportKind
191+ {
192+ selective,
193+ normal,
194+ neither
195+ }
196+
186197/**
187198 * Handles dot completion for identifiers and types.
188199 * Params:
@@ -371,12 +382,12 @@ AutocompleteResponse parenCompletion(T)(T beforeTokens,
371382 return response;
372383}
373384
374- bool isSelectiveImport (T)(T tokens)
385+ ImportKind determineImportKind (T)(T tokens)
375386{
376387 assert (tokens.length > 1 );
377388 size_t i = tokens.length - 1 ;
378- if (! (tokens[i] == tok! " :" || tokens[i] == tok! " ," ))
379- return false ;
389+ if (! (tokens[i] == tok! " :" || tokens[i] == tok! " ," || tokens[i] == tok ! " . " || tokens[i] == tok ! " identifier " ))
390+ return ImportKind.neither ;
380391 bool foundColon = false ;
381392 loop: while (true ) switch (tokens[i].type)
382393 {
@@ -388,16 +399,16 @@ bool isSelectiveImport(T)(T tokens)
388399 case tok! " ." :
389400 case tok! " ," :
390401 if (i == 0 )
391- return false ;
402+ return ImportKind.neither ;
392403 else
393404 i-- ;
394405 break ;
395406 case tok! " import" :
396- return foundColon;
407+ return foundColon ? ImportKind.selective : ImportKind.normal ;
397408 default :
398- return false ;
409+ return ImportKind.neither ;
399410 }
400- return false ;
411+ return ImportKind.neither ;
401412}
402413
403414unittest
@@ -410,13 +421,13 @@ unittest
410421 t ~= Token (tok! " :" );
411422 t ~= Token (tok! " identifier" );
412423 t ~= Token (tok! " ," );
413- assert (isSelectiveImport (t));
424+ assert (determineImportKind (t) == ImportKind.selective );
414425 Token [] t2;
415426 t2 ~= Token (tok! " else" );
416427 t2 ~= Token (tok! " :" );
417- assert (! isSelectiveImport (t2));
428+ assert (determineImportKind (t2) == ImportKind.neither );
418429 import std.stdio ;
419- writeln(" Unittest for isSelectiveImport () passed" );
430+ writeln(" Unittest for determineImportKind () passed" );
420431}
421432
422433/**
@@ -425,27 +436,44 @@ unittest
425436 * import std.algorithm: balancedParens;
426437 * ---
427438 */
428- AutocompleteResponse selectiveImportCompletion (T)(T beforeTokens)
439+ AutocompleteResponse importCompletion (T)(T beforeTokens, ImportKind kind )
429440in
430441{
431442 assert (beforeTokens.length >= 2 );
432443}
433444body
434445{
435446 AutocompleteResponse response;
436- size_t i = beforeTokens.length - 2 ;
437- loop: while (i > 0 ) switch (beforeTokens[i].type)
447+ if (beforeTokens.length <= 2 )
448+ return response;
449+
450+ size_t i = beforeTokens.length - 1 ;
451+
452+ if (kind == ImportKind.normal)
453+ {
454+
455+ while (beforeTokens[i].type != tok! " ," && beforeTokens[i].type != tok! " import" ) i-- ;
456+ setImportCompletions(beforeTokens[i .. $], response);
457+ return response;
458+ }
459+
460+ loop: while (true ) switch (beforeTokens[i].type)
438461 {
439462 case tok! " identifier" :
440463 case tok! " =" :
441464 case tok! " ," :
442465 case tok! " ." :
443- case tok! " :" :
444466 i-- ;
445467 break ;
468+ case tok! " :" :
469+ i-- ;
470+ while (beforeTokens[i].type == tok! " identifier" || beforeTokens[i].type == tok! " ." )
471+ i-- ;
472+ break loop;
446473 default :
447474 break loop;
448475 }
476+
449477 size_t j = i;
450478 loop2: while (j <= beforeTokens.length) switch (beforeTokens[j].type)
451479 {
@@ -467,7 +495,15 @@ body
467495 k++ ;
468496 }
469497 }
470- auto symbols = ModuleCache.getModuleSymbol(ModuleCache.resolveImportLoctation(path));
498+
499+ string resolvedLocation = ModuleCache.resolveImportLoctation(path);
500+ if (resolvedLocation is null )
501+ {
502+ Log .error(" Could not resolve location of " , path);
503+ return response;
504+ }
505+ auto symbols = ModuleCache.getModuleSymbol(resolvedLocation);
506+
471507 import containers.hashset;
472508 HashSet! string h;
473509
@@ -493,6 +529,56 @@ body
493529 return response;
494530}
495531
532+ /**
533+ * Populates the response with completion information for an import statement
534+ * Params:
535+ * tokens = the tokens after the "import" keyword and before the cursor
536+ * response = the response that should be populated
537+ */
538+ void setImportCompletions (T)(T tokens, ref AutocompleteResponse response)
539+ {
540+ response.completionType = CompletionType.identifiers;
541+ auto moduleParts = tokens.filter! (a => a.type == tok! " identifier" ).map! (" a.text" ).array();
542+ string path = buildPath(moduleParts);
543+
544+ bool found = false ;
545+
546+ foreach (importDirectory; ModuleCache.getImportPaths())
547+ {
548+ string p = buildPath(importDirectory, path);
549+ if (! exists(p))
550+ continue ;
551+
552+ found = true ;
553+
554+ foreach (string name; dirEntries(p, SpanMode.shallow))
555+ {
556+ import std.path : baseName;
557+ if (name.baseName.startsWith(" .#" ))
558+ continue ;
559+
560+ if (isFile(name) && (name.endsWith(" .d" ) || name.endsWith(" .di" )))
561+ {
562+ response.completions ~= name.baseName(" .d" ).baseName(" .di" );
563+ response.completionKinds ~= CompletionKind.moduleName;
564+ }
565+ else if (isDir(name))
566+ {
567+ string n = name.baseName();
568+ if (n[0 ] != ' .' )
569+ {
570+ response.completions ~= n;
571+ response.completionKinds ~=
572+ exists(buildPath(name, " package.d" )) || exists(buildPath(name, " package.di" ))
573+ ? CompletionKind.moduleName : CompletionKind.packageName;
574+ }
575+ }
576+ }
577+ }
578+ if (! found)
579+ Log .error(" Could not find " , moduleParts);
580+ }
581+
496582/**
497583 *
498584 */
@@ -666,14 +752,6 @@ void setCompletions(T)(ref AutocompleteResponse response,
666752 Scope* completionScope, T tokens, size_t cursorPosition,
667753 CompletionType completionType, bool isBracket = false , string partial = null )
668754{
669- // Autocomplete module imports instead of symbols
670- if (tokens.length > 0 && tokens[0 ].type == tok! " import" )
671- {
672- if (completionType == CompletionType.identifiers)
673- setImportCompletions(tokens, response);
674- return ;
675- }
676-
677755 // Handle the simple case where we get all symbols in scope and filter it
678756 // based on the currently entered text.
679757 if (partial ! is null && tokens.length == 0 )
@@ -905,49 +983,6 @@ T getExpression(T)(T beforeTokens)
905983 return beforeTokens[i .. $];
906984}
907985
908- /**
909- * Populates the response with completion information for an import statement
910- * Params:
911- * tokens = the tokens after the "import" keyword and before the cursor
912- * response = the response that should be populated
913- */
914- void setImportCompletions (T)(T tokens, ref AutocompleteResponse response)
915- {
916- response.completionType = CompletionType.identifiers;
917- auto moduleParts = tokens.filter! (a => a.type == tok! " identifier" ).map! (" a.text" ).array();
918- string path = buildPath(moduleParts);
919-
920- foreach (importDirectory; ModuleCache.getImportPaths())
921- {
922- string p = buildPath(importDirectory, path);
923- // Log.trace("Checking for ", p);
924- if (! exists(p))
925- continue ;
926-
927- foreach (string name; dirEntries(p, SpanMode.shallow))
928- {
929- import std.path : baseName;
930- if (name.baseName.startsWith(" .#" )) continue ;
931- if (isFile(name) && (name.endsWith(" .d" ) || name.endsWith(" .di" )))
932- {
933- response.completions ~= name.baseName(" .d" ).baseName(" .di" );
934- response.completionKinds ~= CompletionKind.moduleName;
935- }
936- else if (isDir(name))
937- {
938- string n = name.baseName();
939- if (n[0 ] != ' .' )
940- {
941- response.completions ~= n;
942- response.completionKinds ~=
943- exists(buildPath(name, " package.d" )) || exists(buildPath(name, " package.di" ))
944- ? CompletionKind.moduleName : CompletionKind.packageName;
945- }
946- }
947- }
948- }
949- }
950-
951986/**
952987 * Params:
953988 * completionType = the completion type being requested
0 commit comments