Skip to content

Commit

Permalink
Land #839: Autocomplete Erlang SDK module names and functions in thos…
Browse files Browse the repository at this point in the history
…e modules.
  • Loading branch information
KronicDeth committed Sep 30, 2017
2 parents d074ee5 + 6ded888 commit ff00b04
Show file tree
Hide file tree
Showing 27 changed files with 729 additions and 150 deletions.
4 changes: 4 additions & 0 deletions gen/org/elixir_lang/psi/ElixirAlias.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions gen/org/elixir_lang/psi/ElixirAtom.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions gen/org/elixir_lang/psi/ElixirMatchedQualifiedAlias.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions gen/org/elixir_lang/psi/ElixirUnmatchedQualifiedAlias.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions gen/org/elixir_lang/psi/impl/ElixirAliasImpl.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions gen/org/elixir_lang/psi/impl/ElixirAtomImpl.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion src/org/elixir_lang/Elixir.bnf
Expand Up @@ -2772,7 +2772,10 @@ atom ::= COLON (ATOM_FRAGMENT | quote)
"com.intellij.psi.NavigatablePsiElement"
"org.elixir_lang.psi.Quotable"
]
methods = [quote]
methods = [
getReference
quote
]
}

private infixComma ::= COMMA EOL*
Expand Down
93 changes: 93 additions & 0 deletions src/org/elixir_lang/Reference.java
@@ -0,0 +1,93 @@
package org.elixir_lang;

import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StubIndex;
import com.intellij.util.Function;
import org.elixir_lang.psi.NamedElement;
import org.elixir_lang.psi.stub.index.AllName;
import org.jetbrains.annotations.NotNull;

import java.util.Collection;
import java.util.Collections;
import java.util.stream.Stream;

public class Reference {
@NotNull
public static Collection<String> indexedNameCollection(@NotNull Project project) {
return StubIndex.getInstance().getAllKeys(AllName.KEY, project);
}

@NotNull
public static Stream<String> indexedNameStream(@NotNull Project project) {
return indexedNameCollection(project).stream();
}

/**
* Iterates over each navigation element for the PsiElements with {@code name} in {@code project}.
*
* @param project Whose index to search for {@code name}
* @param name Name to search for in {@code project} StubIndex
* @param function return {@code false} to stop iteration early
* @return {@code true} if all calls to {@code function} returned {@code true}
*/
public static boolean forEachNavigationElement(@NotNull Project project,
@NotNull String name,
@NotNull Function<PsiElement, Boolean> function) {
Collection<NamedElement> namedElementCollection = namedElementCollection(project, name);

return forEachNavigationElement(namedElementCollection, function);
}

/**
* Iterates over each navigation element for the PsiElements in {@code psiElementCollection}.
*
* @param psiElementCollection Collection of PsiElements that aren't guaranteed to be navigation elements, such as
* the binary elements in {@code .beam} files.
* @param function Return {@code false} to stop processing and abandon enumeration early
* @return {@code true} if all calls to {@code function} returned {@code true}
*/
private static boolean forEachNavigationElement(@NotNull Collection<? extends PsiElement> psiElementCollection,
@NotNull Function<PsiElement, Boolean> function) {
boolean keepProcessing = true;

for (PsiElement psiElement : psiElementCollection) {
/* The psiElement may be a ModuleImpl from a .beam. Using #getNaviationElement() ensures a source
(either true source or decompiled) is used. */
keepProcessing = function.fun(psiElement.getNavigationElement());

if (!keepProcessing) {
break;
}
}

return keepProcessing;
}

public static Collection<NamedElement> namedElementCollection(@NotNull Project project, @NotNull String name) {
return namedElementCollection(project, GlobalSearchScope.allScope(project), name);
}

public static Collection<NamedElement> namedElementCollection(@NotNull Project project,
@NotNull GlobalSearchScope scope,
@NotNull String name) {
Collection<NamedElement> namedElementCollection;

if (DumbService.isDumb(project)) {
namedElementCollection = Collections.emptyList();
} else {
namedElementCollection = StubIndex.getElements(
AllName.KEY,
name,
project,
scope,
NamedElement.class
);
}

return namedElementCollection;

}
}
Expand Up @@ -8,22 +8,21 @@
import com.intellij.psi.PsiElement;
import com.intellij.util.ProcessingContext;
import org.apache.commons.lang.math.IntRange;
import org.elixir_lang.psi.ElixirEndOfExpression;
import org.elixir_lang.psi.ElixirTypes;
import org.elixir_lang.psi.call.Call;
import org.elixir_lang.psi.impl.ElixirPsiImplUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static org.elixir_lang.psi.impl.ElixirPsiImplUtil.macroChildCalls;
import static org.elixir_lang.psi.impl.ElixirPsiImplUtil.maybeModularNameToModular;
import static org.elixir_lang.structure_view.element.CallDefinitionClause.nameArityRange;

public class CallDefinitionClause extends CompletionProvider<CompletionParameters> {
/*
* Private Instance Methods
*/

@NotNull
private static Iterable<LookupElement> callDefinitionClauseLookupElements(@NotNull Call scope) {
Call[] childCalls = macroChildCalls(scope);
Expand Down Expand Up @@ -61,39 +60,57 @@ private static Iterable<LookupElement> callDefinitionClauseLookupElements(@NotNu
return lookupElementList;
}

/*
* Protected Instance Methods
*/

@Override
protected void addCompletions(@NotNull CompletionParameters parameters,
ProcessingContext context,
@NotNull CompletionResultSet resultSet) {
@Nullable
private static PsiElement maybeModularName(@NotNull CompletionParameters parameters) {
PsiElement originalPosition = parameters.getOriginalPosition();
PsiElement originalParent;
PsiElement maybeModularName = null;

if (originalPosition != null) {
originalParent = originalPosition.getParent();
PsiElement originalParent = originalPosition.getParent();

if (originalParent != null) {
PsiElement grandParent = originalParent.getParent();

if (grandParent instanceof org.elixir_lang.psi.qualification.Qualified) {
org.elixir_lang.psi.qualification.Qualified qualifiedGrandParent = (org.elixir_lang.psi.qualification.Qualified) grandParent;
PsiElement qualifier = qualifiedGrandParent.qualifier();
org.elixir_lang.psi.qualification.Qualified qualifiedGrandParent =
(org.elixir_lang.psi.qualification.Qualified) grandParent;
maybeModularName = qualifiedGrandParent.qualifier();
} else if (originalParent instanceof ElixirEndOfExpression) {
final int originalParentOffset = originalParent.getTextOffset();

if (originalParentOffset > 0) {
final PsiElement previousElement =
parameters.getOriginalFile().findElementAt(originalParentOffset - 1);

if (previousElement != null &&
previousElement.getNode().getElementType() == ElixirTypes.DOT_OPERATOR) {
maybeModularName = previousElement.getPrevSibling();
}
}
}
}
}

Call modular = ElixirPsiImplUtil.maybeAliasToModular(qualifier, qualifier.getContainingFile());
return maybeModularName;
}

if (modular != null) {
if (resultSet.getPrefixMatcher().getPrefix().endsWith(".")) {
resultSet = resultSet.withPrefixMatcher("");
}
@Override
protected void addCompletions(@NotNull CompletionParameters parameters,
ProcessingContext context,
@NotNull CompletionResultSet resultSet) {
PsiElement maybeModularName = maybeModularName(parameters);

resultSet.addAllElements(
callDefinitionClauseLookupElements(modular)
);
}
if (maybeModularName != null) {
Call modular = maybeModularNameToModular(maybeModularName, maybeModularName.getContainingFile());

if (modular != null) {
if (resultSet.getPrefixMatcher().getPrefix().endsWith(".")) {
resultSet = resultSet.withPrefixMatcher("");
}

resultSet.addAllElements(
callDefinitionClauseLookupElements(modular)
);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/org/elixir_lang/psi/Import.java
Expand Up @@ -271,7 +271,7 @@ private static Call modular(@NotNull Call importCall) {
Call modular = null;

if (finalArguments != null && finalArguments.length >= 1) {
modular = maybeAliasToModular(finalArguments[0], importCall.getParent());
modular = maybeModularNameToModular(finalArguments[0], importCall.getParent());
}

return modular;
Expand Down

0 comments on commit ff00b04

Please sign in to comment.