-
-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #79 from NixOS/symbols
Variable resolution via experimental Symbols API
- Loading branch information
Showing
33 changed files
with
2,848 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
src/main/java/org/nixos/idea/lang/references/NixNavigationTarget.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package org.nixos.idea.lang.references; | ||
|
||
import com.intellij.model.Pointer; | ||
import com.intellij.openapi.util.TextRange; | ||
import com.intellij.platform.backend.navigation.NavigationRequest; | ||
import com.intellij.platform.backend.navigation.NavigationTarget; | ||
import com.intellij.platform.backend.presentation.TargetPresentation; | ||
import com.intellij.psi.SmartPointerManager; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
import org.jetbrains.annotations.TestOnly; | ||
import org.nixos.idea.psi.NixPsiElement; | ||
|
||
@SuppressWarnings("UnstableApiUsage") | ||
public final class NixNavigationTarget implements NavigationTarget { | ||
|
||
private final @NotNull NixPsiElement myIdentifier; | ||
private final @NotNull TargetPresentation myTargetPresentation; | ||
private @Nullable Pointer<NavigationTarget> myPointer; | ||
|
||
public NixNavigationTarget(@NotNull NixPsiElement identifier, @NotNull TargetPresentation targetPresentation) { | ||
myIdentifier = identifier; | ||
myTargetPresentation = targetPresentation; | ||
} | ||
|
||
private NixNavigationTarget(@NotNull Pointer<NavigationTarget> pointer, | ||
@NotNull NixPsiElement identifier, | ||
@NotNull TargetPresentation targetPresentation) { | ||
myIdentifier = identifier; | ||
myTargetPresentation = targetPresentation; | ||
myPointer = pointer; | ||
} | ||
|
||
@TestOnly | ||
TextRange getRangeInFile() { | ||
return myIdentifier.getTextRange(); | ||
} | ||
|
||
@Override | ||
public @NotNull Pointer<NavigationTarget> createPointer() { | ||
if (myPointer == null) { | ||
TargetPresentation targetPresentation = myTargetPresentation; | ||
myPointer = Pointer.uroborosPointer( | ||
SmartPointerManager.createPointer(myIdentifier), | ||
(identifier, pointer) -> new NixNavigationTarget(pointer, identifier, targetPresentation)); | ||
} | ||
return myPointer; | ||
} | ||
|
||
@Override | ||
public @NotNull TargetPresentation computePresentation() { | ||
return myTargetPresentation; | ||
} | ||
|
||
@Override | ||
public @Nullable NavigationRequest navigationRequest() { | ||
return NavigationRequest.sourceNavigationRequest(myIdentifier.getContainingFile(), myIdentifier.getTextRange()); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
src/main/java/org/nixos/idea/lang/references/NixScopeReference.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.nixos.idea.lang.references; | ||
|
||
import org.jetbrains.annotations.NotNull; | ||
import org.nixos.idea.lang.references.symbol.NixSymbol; | ||
import org.nixos.idea.psi.NixPsiElement; | ||
|
||
import java.util.Collection; | ||
|
||
@SuppressWarnings("UnstableApiUsage") | ||
public final class NixScopeReference extends NixSymbolReference { | ||
|
||
public NixScopeReference(@NotNull NixPsiElement element, @NotNull NixPsiElement identifier, @NotNull String variableName) { | ||
super(element, identifier, variableName); | ||
} | ||
|
||
@Override | ||
public @NotNull Collection<NixSymbol> resolveReference() { | ||
return myElement.getScope().resolveVariable(myName); | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
src/main/java/org/nixos/idea/lang/references/NixSymbolDeclaration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package org.nixos.idea.lang.references; | ||
|
||
import com.intellij.model.psi.PsiSymbolDeclaration; | ||
import com.intellij.openapi.util.TextRange; | ||
import com.intellij.platform.backend.navigation.NavigationTarget; | ||
import com.intellij.platform.backend.presentation.TargetPresentation; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
import org.nixos.idea.lang.references.symbol.NixUserSymbol; | ||
import org.nixos.idea.psi.NixPsiElement; | ||
import org.nixos.idea.util.TextRangeFactory; | ||
|
||
@SuppressWarnings("UnstableApiUsage") | ||
public final class NixSymbolDeclaration implements PsiSymbolDeclaration { | ||
|
||
private final @NotNull NixPsiElement myDeclarationElement; | ||
private final @NotNull NixPsiElement myIdentifier; | ||
private final @NotNull NixUserSymbol mySymbol; | ||
private final @NotNull String myDeclarationElementName; | ||
private final @Nullable String myDeclarationElementType; | ||
|
||
public NixSymbolDeclaration(@NotNull NixPsiElement declarationElement, @NotNull NixPsiElement identifier, | ||
@NotNull NixUserSymbol symbol, | ||
@NotNull String declarationElementName, @Nullable String declarationElementType) { | ||
myDeclarationElement = declarationElement; | ||
myIdentifier = identifier; | ||
mySymbol = symbol; | ||
myDeclarationElementName = declarationElementName; | ||
myDeclarationElementType = declarationElementType; | ||
} | ||
|
||
public @NotNull NixPsiElement getIdentifier() { | ||
return myIdentifier; | ||
} | ||
|
||
public @NotNull NavigationTarget navigationTarget() { | ||
return new NixNavigationTarget(myIdentifier, TargetPresentation.builder(mySymbol.presentation()) | ||
.presentableText(myDeclarationElementName) | ||
.containerText(myDeclarationElementType) | ||
.presentation()); | ||
} | ||
|
||
@Override | ||
public @NotNull NixPsiElement getDeclaringElement() { | ||
return myDeclarationElement; | ||
} | ||
|
||
@Override | ||
public @NotNull TextRange getRangeInDeclaringElement() { | ||
return TextRangeFactory.relative(myIdentifier, myDeclarationElement); | ||
} | ||
|
||
@Override | ||
public @NotNull NixUserSymbol getSymbol() { | ||
return mySymbol; | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
src/main/java/org/nixos/idea/lang/references/NixSymbolReference.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package org.nixos.idea.lang.references; | ||
|
||
import com.intellij.model.Symbol; | ||
import com.intellij.model.psi.PsiSymbolReference; | ||
import com.intellij.openapi.util.TextRange; | ||
import com.intellij.psi.PsiElement; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.nixos.idea.lang.references.symbol.NixSymbol; | ||
import org.nixos.idea.psi.NixPsiElement; | ||
import org.nixos.idea.util.TextRangeFactory; | ||
|
||
@SuppressWarnings("UnstableApiUsage") | ||
public abstract class NixSymbolReference implements PsiSymbolReference { | ||
|
||
protected final @NotNull NixPsiElement myElement; | ||
protected final @NotNull NixPsiElement myIdentifier; | ||
protected final @NotNull String myName; | ||
|
||
protected NixSymbolReference(@NotNull NixPsiElement element, @NotNull NixPsiElement identifier, @NotNull String name) { | ||
myElement = element; | ||
myIdentifier = identifier; | ||
myName = name; | ||
} | ||
|
||
public @NotNull NixPsiElement getIdentifier() { | ||
return myIdentifier; | ||
} | ||
|
||
@Override | ||
public @NotNull PsiElement getElement() { | ||
return myElement; | ||
} | ||
|
||
@Override | ||
public @NotNull TextRange getRangeInElement() { | ||
return TextRangeFactory.relative(myIdentifier, myElement); | ||
} | ||
|
||
@Override | ||
public boolean resolvesTo(@NotNull Symbol target) { | ||
// Check name as a shortcut to avoid resolving the reference when it cannot match anyway. | ||
return target instanceof NixSymbol t && | ||
myName.equals(t.getName()) && | ||
PsiSymbolReference.super.resolvesTo(target); | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
src/main/java/org/nixos/idea/lang/references/NixUsage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package org.nixos.idea.lang.references; | ||
|
||
import com.intellij.find.usages.api.PsiUsage; | ||
import com.intellij.find.usages.api.ReadWriteUsage; | ||
import com.intellij.find.usages.api.UsageAccess; | ||
import com.intellij.model.Pointer; | ||
import com.intellij.openapi.util.TextRange; | ||
import com.intellij.psi.PsiFile; | ||
import com.intellij.psi.SmartPointerManager; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
import org.nixos.idea.psi.NixPsiElement; | ||
import org.nixos.idea.settings.NixSymbolSettings; | ||
|
||
@SuppressWarnings("UnstableApiUsage") | ||
final class NixUsage implements PsiUsage, ReadWriteUsage { | ||
|
||
private final @NotNull NixPsiElement myIdentifier; | ||
private final boolean myIsDeclaration; | ||
private @Nullable Pointer<NixUsage> myPointer; | ||
|
||
NixUsage(@NotNull NixSymbolDeclaration declaration) { | ||
myIdentifier = declaration.getIdentifier(); | ||
myIsDeclaration = true; | ||
} | ||
|
||
NixUsage(@NotNull NixSymbolReference reference) { | ||
myIdentifier = reference.getIdentifier(); | ||
myIsDeclaration = false; | ||
} | ||
|
||
private NixUsage(@NotNull Pointer<NixUsage> pointer, @NotNull NixPsiElement identifier, boolean isDeclaration) { | ||
myIdentifier = identifier; | ||
myIsDeclaration = isDeclaration; | ||
myPointer = pointer; | ||
} | ||
|
||
@Override | ||
public @NotNull Pointer<NixUsage> createPointer() { | ||
if (myPointer == null) { | ||
boolean isDeclaration = myIsDeclaration; | ||
myPointer = Pointer.uroborosPointer( | ||
SmartPointerManager.createPointer(myIdentifier), | ||
(identifier, pointer) -> new NixUsage(pointer, identifier, isDeclaration)); | ||
} | ||
return myPointer; | ||
} | ||
|
||
@Override | ||
public @NotNull PsiFile getFile() { | ||
return myIdentifier.getContainingFile(); | ||
} | ||
|
||
@Override | ||
public @NotNull TextRange getRange() { | ||
return myIdentifier.getTextRange(); | ||
} | ||
|
||
@Override | ||
public boolean getDeclaration() { | ||
// IDEA removes all instances which return true from the result of the usage search | ||
return !NixSymbolSettings.getInstance().getShowDeclarationsAsUsages() && myIsDeclaration; | ||
} | ||
|
||
@Override | ||
public @Nullable UsageAccess computeAccess() { | ||
return myIsDeclaration ? UsageAccess.Write : UsageAccess.Read; | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
src/main/java/org/nixos/idea/lang/references/NixUsageSearcher.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package org.nixos.idea.lang.references; | ||
|
||
import com.intellij.find.usages.api.Usage; | ||
import com.intellij.find.usages.api.UsageSearchParameters; | ||
import com.intellij.find.usages.api.UsageSearcher; | ||
import com.intellij.model.search.LeafOccurrence; | ||
import com.intellij.model.search.LeafOccurrenceMapper; | ||
import com.intellij.model.search.SearchContext; | ||
import com.intellij.model.search.SearchService; | ||
import com.intellij.psi.PsiElement; | ||
import com.intellij.util.Query; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
import org.nixos.idea.lang.NixLanguage; | ||
import org.nixos.idea.lang.references.symbol.NixSymbol; | ||
import org.nixos.idea.lang.references.symbol.NixUserSymbol; | ||
import org.nixos.idea.psi.NixPsiElement; | ||
import org.nixos.idea.settings.NixSymbolSettings; | ||
|
||
import java.util.Collection; | ||
import java.util.List; | ||
|
||
@SuppressWarnings("UnstableApiUsage") | ||
public final class NixUsageSearcher implements UsageSearcher, LeafOccurrenceMapper.Parameterized<NixSymbol, Usage> { | ||
|
||
@Override | ||
public @NotNull Collection<? extends Usage> collectImmediateResults(@NotNull UsageSearchParameters parameters) { | ||
if (!NixSymbolSettings.getInstance().getEnabled()) { | ||
return List.of(); | ||
} else if (parameters.getTarget() instanceof NixUserSymbol symbol) { | ||
return symbol.getDeclarations().stream().map(NixUsage::new).toList(); | ||
} else { | ||
return List.of(); | ||
} | ||
} | ||
|
||
@Override | ||
public @Nullable Query<? extends Usage> collectSearchRequest(@NotNull UsageSearchParameters parameters) { | ||
if (!NixSymbolSettings.getInstance().getEnabled()) { | ||
return null; | ||
} else if (parameters.getTarget() instanceof NixSymbol symbol) { | ||
String name = symbol.getName(); | ||
return SearchService.getInstance() | ||
.searchWord(parameters.getProject(), name) | ||
.inContexts(SearchContext.IN_CODE_HOSTS, SearchContext.IN_CODE) | ||
.inScope(parameters.getSearchScope()) | ||
.inFilesWithLanguage(NixLanguage.INSTANCE) | ||
.buildQuery(LeafOccurrenceMapper.withPointer(symbol.createPointer(), this)); | ||
} else { | ||
return null; | ||
} | ||
} | ||
|
||
@Override | ||
public @NotNull Collection<? extends Usage> mapOccurrence(@NotNull NixSymbol symbol, @NotNull LeafOccurrence occurrence) { | ||
for (PsiElement element = occurrence.getStart(); element != null && element != occurrence.getScope(); element = element.getParent()) { | ||
if (element instanceof NixPsiElement nixElement) { | ||
List<NixUsage> usages = nixElement.getOwnReferences().stream() | ||
.filter(reference -> reference.resolvesTo(symbol)) | ||
.map(NixUsage::new) | ||
.toList(); | ||
if (!usages.isEmpty()) { | ||
return usages; | ||
} | ||
} | ||
} | ||
return List.of(); | ||
} | ||
} |
Oops, something went wrong.