diff --git a/CHANGELOG.md b/CHANGELOG.md index d9e85236..031ac52c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] ### Added +- Navigation (Ctrl-B/Cmd-B) for Nix paths and path-like strings. + - Directories containing a `default.nix` file offer that file as an optional destination. +- Find usages for files and directories in project view referenced by Nix paths. +- Completion of files and subdirectories for Nix paths. ### Changed diff --git a/src/main/java/org/nixos/idea/psi/impl/NixLiteralReferencingElementImpl.java b/src/main/java/org/nixos/idea/psi/impl/NixLiteralReferencingElementImpl.java new file mode 100644 index 00000000..2805a545 --- /dev/null +++ b/src/main/java/org/nixos/idea/psi/impl/NixLiteralReferencingElementImpl.java @@ -0,0 +1,22 @@ +package org.nixos.idea.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiReference; +import org.jetbrains.annotations.NotNull; +import org.nixos.idea.reference.ReferenceUtil; + +public class NixLiteralReferencingElementImpl extends NixExprSimpleImpl { + public NixLiteralReferencingElementImpl(@NotNull ASTNode node) { + super(node); + } + + @Override + public PsiReference @NotNull [] getReferences() { + return ReferenceUtil.getReferences(this); + } + + @Override + public PsiReference getReference() { + return ReferenceUtil.getReference(this); + } +} diff --git a/src/main/java/org/nixos/idea/psi/impl/NixStringReferencingElementImpl.java b/src/main/java/org/nixos/idea/psi/impl/NixStringReferencingElementImpl.java new file mode 100644 index 00000000..d9dab1e9 --- /dev/null +++ b/src/main/java/org/nixos/idea/psi/impl/NixStringReferencingElementImpl.java @@ -0,0 +1,22 @@ +package org.nixos.idea.psi.impl; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiReference; +import org.jetbrains.annotations.NotNull; +import org.nixos.idea.reference.ReferenceUtil; + +public class NixStringReferencingElementImpl extends NixStringPartImpl { + public NixStringReferencingElementImpl(@NotNull ASTNode node) { + super(node); + } + + @Override + public PsiReference @NotNull [] getReferences() { + return ReferenceUtil.getReferences(this); + } + + @Override + public PsiReference getReference() { + return ReferenceUtil.getReference(this); + } +} diff --git a/src/main/java/org/nixos/idea/reference/NixReferenceContributor.java b/src/main/java/org/nixos/idea/reference/NixReferenceContributor.java new file mode 100644 index 00000000..accc0f9b --- /dev/null +++ b/src/main/java/org/nixos/idea/reference/NixReferenceContributor.java @@ -0,0 +1,53 @@ +package org.nixos.idea.reference; + +import com.intellij.psi.*; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference; +import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; +import org.nixos.idea.psi.NixLiteral; +import org.nixos.idea.psi.NixStringText; + +import java.util.Arrays; + +import static com.intellij.patterns.PlatformPatterns.psiElement; +import static com.intellij.patterns.StandardPatterns.or; +import static com.intellij.patterns.StandardPatterns.string; + +public class NixReferenceContributor extends PsiReferenceContributor { + + // Same as the pattern in Nix.flex. + private static final String NIX_PATH_REGEX = "[a-zA-Z0-9._+-]*(\\/[a-zA-Z0-9._+-]+)+\\/?"; + + @Override + public void registerReferenceProviders(@NotNull PsiReferenceRegistrar psiReferenceRegistrar) { + psiReferenceRegistrar.registerReferenceProvider( + or( + psiElement(NixLiteral.class), + psiElement(NixStringText.class) + .withText(string().matches(NIX_PATH_REGEX)) + ), + new NixReferenceProvider() + ); + } + + private static class NixReferenceProvider extends PsiReferenceProvider { + + @Override + public boolean acceptsTarget(@NotNull PsiElement target) { + return target instanceof PsiFileSystemItem; + } + + @Override + public PsiReference @NotNull [] getReferencesByElement(@NotNull PsiElement psiElement, + @NotNull ProcessingContext processingContext) { + FileReferenceSet fileReferenceSet = new FileReferenceSet(psiElement); + FileReference[] references = fileReferenceSet.getAllReferences(); + FileReference lastReference = fileReferenceSet.getLastReference(); + FileReference defaultNixReference = fileReferenceSet.createFileReference(lastReference.getRangeInElement(), lastReference.getIndex() + 1, "default.nix"); + PsiReference[] allReferences = Arrays.copyOf(references, references.length + 1); + allReferences[allReferences.length - 1] = defaultNixReference; + return allReferences; + } + } +} diff --git a/src/main/java/org/nixos/idea/reference/ReferenceUtil.java b/src/main/java/org/nixos/idea/reference/ReferenceUtil.java new file mode 100644 index 00000000..1126c604 --- /dev/null +++ b/src/main/java/org/nixos/idea/reference/ReferenceUtil.java @@ -0,0 +1,18 @@ +package org.nixos.idea.reference; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.intellij.psi.PsiReferenceService; +import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry; +import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; + +public class ReferenceUtil { + public static PsiReference @NotNull [] getReferences(@NotNull PsiElement element) { + return ReferenceProvidersRegistry.getReferencesFromProviders(element, PsiReferenceService.Hints.NO_HINTS); + } + + public static PsiReference getReference(@NotNull PsiElement element) { + return ArrayUtil.getFirstElement(getReferences(element)); + } +} diff --git a/src/main/lang/Nix.bnf b/src/main/lang/Nix.bnf index f60acf61..2a6f67ee 100644 --- a/src/main/lang/Nix.bnf +++ b/src/main/lang/Nix.bnf @@ -169,6 +169,9 @@ expr_simple ::= | legacy_let identifier ::= ID literal ::= INT | FLOAT | PATH | HPATH | SPATH | URI +{ + mixin="org.nixos.idea.psi.impl.NixLiteralReferencingElementImpl" +} parens ::= LPAREN expr recover_parens RPAREN { pin=1 } set ::= [ REC ] LCURLY recover_set (bind recover_set)* RCURLY { pin=2 } list ::= LBRAC recover_list (expr_select recover_list)* RBRAC { pin=1 } @@ -186,6 +189,9 @@ ind_string ::= IND_STRING_OPEN string_part* IND_STRING_CLOSE { pin=1 } ;{ extends("string_text|antiquotation")=string_part } string_part ::= string_text | antiquotation { recoverWhile=string_part_recover } string_text ::= STR | IND_STR +{ + mixin="org.nixos.idea.psi.impl.NixStringReferencingElementImpl" +} antiquotation ::= DOLLAR LCURLY expr recover_antiquotation RCURLY { pin=1 } private recover_antiquotation ::= { recoverWhile=curly_recover } private string_part_recover ::= !(STR | IND_STR | DOLLAR | STRING_CLOSE | IND_STRING_CLOSE) diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 8199fe55..cef3670f 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -37,6 +37,8 @@ id="org.nixos.idea.settings.NixIDEASettings" instance="org.nixos.idea.settings.NixIDEASettings" /> + +