Skip to content

Commit

Permalink
Add NixSymbolSettings for user customization
Browse files Browse the repository at this point in the history
  • Loading branch information
JojOatXGME committed May 15, 2024
1 parent 2ec6a06 commit 7a13192
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 12 deletions.
4 changes: 3 additions & 1 deletion src/main/java/org/nixos/idea/lang/references/NixUsage.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
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 {
Expand Down Expand Up @@ -57,7 +58,8 @@ private NixUsage(@NotNull Pointer<NixUsage> pointer, @NotNull NixPsiElement iden

@Override
public boolean getDeclaration() {
return myIsDeclaration;
// IDEA removes all instances which return true from the result of the usage search
return !NixSymbolSettings.getInstance().getShowDeclarationsAsUsages() && myIsDeclaration;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.nixos.idea.lang.references;

import com.intellij.find.usages.api.SearchTarget;
import com.intellij.find.usages.api.Usage;
import com.intellij.find.usages.api.UsageSearchParameters;
import com.intellij.find.usages.api.UsageSearcher;
Expand All @@ -16,6 +15,7 @@
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;
Expand All @@ -25,7 +25,9 @@ public final class NixUsageSearcher implements UsageSearcher, LeafOccurrenceMapp

@Override
public @NotNull Collection<? extends Usage> collectImmediateResults(@NotNull UsageSearchParameters parameters) {
if (parameters.getTarget() instanceof NixUserSymbol symbol) {
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();
Expand All @@ -34,8 +36,9 @@ public final class NixUsageSearcher implements UsageSearcher, LeafOccurrenceMapp

@Override
public @Nullable Query<? extends Usage> collectSearchRequest(@NotNull UsageSearchParameters parameters) {
SearchTarget target = parameters.getTarget();
if (target instanceof NixSymbol symbol) {
if (!NixSymbolSettings.getInstance().getEnabled()) {
return null;
} else if (parameters.getTarget() instanceof NixSymbol symbol) {
String name = symbol.getName();
return SearchService.getInstance()
.searchWord(parameters.getProject(), name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
import org.nixos.idea.lang.highlighter.NixTextAttributes;
import org.nixos.idea.lang.references.NixSymbolDeclaration;
import org.nixos.idea.psi.NixDeclarationHost;
import org.nixos.idea.settings.NixSymbolSettings;

import javax.swing.Icon;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

@SuppressWarnings("UnstableApiUsage")
public final class NixUserSymbol extends NixSymbol
Expand Down Expand Up @@ -93,7 +95,12 @@ public NixUserSymbol(@NotNull NixDeclarationHost host, @NotNull List<String> pat
@Override
public @NotNull Collection<? extends NavigationTarget> getNavigationTargets(@NotNull Project project) {
assert myHost.getProject().equals(project);
return myHost.getDeclarations(myPath).stream().map(NixSymbolDeclaration::navigationTarget).toList();
Stream<NavigationTarget> targets = myHost.getDeclarations(myPath).stream().map(NixSymbolDeclaration::navigationTarget);
if (NixSymbolSettings.getInstance().getJumpToFirstDeclaration()) {
return targets.findFirst().map(List::of).orElse(List.of());
} else {
return targets.toList();
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.nixos.idea.psi.NixParameter;
import org.nixos.idea.psi.NixPsiElement;
import org.nixos.idea.psi.NixPsiUtil;
import org.nixos.idea.settings.NixSymbolSettings;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
Expand Down Expand Up @@ -84,16 +85,20 @@ public final boolean isDeclaringVariables() {
}

private @NotNull Symbols getSymbols() {
if (mySymbols == null) {
MY_SYMBOLS.compareAndSet(this, null, initSymbols());
NixSymbolSettings settings = NixSymbolSettings.getInstance();
Symbols symbols = mySymbols;
if (symbols == null || symbols.isOutdated(settings)) {
MY_SYMBOLS.compareAndSet(this, symbols, initSymbols(settings));
Objects.requireNonNull(mySymbols, "initSymbols() must not return null");
}
return mySymbols;
}

private @NotNull Symbols initSymbols() {
Symbols symbols = new Symbols();
if (this instanceof NixExprLet let) {
private @NotNull Symbols initSymbols(@NotNull NixSymbolSettings settings) {
Symbols symbols = new Symbols(settings);
if (!NixSymbolSettings.getInstance().getEnabled()) {
return symbols;
} else if (this instanceof NixExprLet let) {
collectBindDeclarations(symbols, let.getBindList(), true);
} else if (this instanceof NixExprAttrs attrs) {
collectBindDeclarations(symbols, attrs.getBindList(), NixPsiUtil.isLegacyLet(attrs));
Expand Down Expand Up @@ -140,6 +145,15 @@ private final class Symbols {
private final @NotNull Map<List<String>, List<NixSymbolDeclaration>> myDeclarationsBySymbol = new HashMap<>();
private final @NotNull Map<NixPsiElement, List<NixSymbolDeclaration>> myDeclarationsByElement = new HashMap<>();
private final @NotNull Set<String> myVariables = new HashSet<>();
private final long mySettingsModificationCount;

private Symbols(@NotNull NixSymbolSettings settings) {
mySettingsModificationCount = settings.getStateModificationCount();
}

private boolean isOutdated(@NotNull NixSymbolSettings settings) {
return mySettingsModificationCount != settings.getStateModificationCount();
}

private void addBindAttr(@NotNull NixPsiElement element, @NotNull NixAttrPath attrPath, @NotNull NixUserSymbol.Type type) {
if (!checkDeclarationHost(element)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.nixos.idea.psi.NixExprVar;
import org.nixos.idea.psi.NixPsiElement;
import org.nixos.idea.psi.NixPsiUtil;
import org.nixos.idea.settings.NixSymbolSettings;

import java.util.Collection;
import java.util.List;
Expand Down Expand Up @@ -59,7 +60,9 @@ abstract class AbstractNixPsiElement extends ASTWrapperPsiElement implements Nix
@Override
@SuppressWarnings("UnstableApiUsage")
public final @NotNull Collection<? extends NixSymbolReference> getOwnReferences() {
if (this instanceof NixExprVar) {
if (!NixSymbolSettings.getInstance().getEnabled()) {
return List.of();
} else if (this instanceof NixExprVar) {
return List.of(new NixScopeReference(this, this, getText()));
} else if (this instanceof NixExprSelect) {
// TODO: Attribute reference support
Expand Down
67 changes: 67 additions & 0 deletions src/main/java/org/nixos/idea/settings/NixSymbolConfigurable.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.nixos.idea.settings

import com.intellij.openapi.options.BoundSearchableConfigurable
import com.intellij.openapi.options.Configurable
import com.intellij.openapi.ui.DialogPanel
import com.intellij.ui.components.JBCheckBox
import com.intellij.ui.dsl.builder.Cell
import com.intellij.ui.dsl.builder.bind
import com.intellij.ui.dsl.builder.bindSelected
import com.intellij.ui.dsl.builder.panel
import com.intellij.ui.dsl.builder.selected

class NixSymbolConfigurable :
BoundSearchableConfigurable("Nix Symbols", "org.nixos.idea.settings.NixSymbolConfigurable"),
Configurable.Beta {

override fun createPanel(): DialogPanel {
val settings = NixSymbolSettings.getInstance()
lateinit var enabledCheckBox: Cell<JBCheckBox>
return panel {
row {
enabledCheckBox = checkBox("Use Symbol API to resolve references and find usages")
.bindSelected(settings::enabled)
}
rowsRange {
groupRowsRange("Go To Declaration") {
buttonsGroup {
row {
radioButton("Go to first declaration", true)
radioButton("Ask when symbol has multiple declarations", false)
}.rowComment(
"""
Attribute sets and <code>let</code>-expressions may contain
multiple indirect declarations of the same symbol.
""".trimIndent()
).contextHelp(
"""
The following code block contains three
declarations of “<code>common</code>”:
<pre>
let
zero = 0;
common.a = 1;
common.b = 2;
common.c = 3;
in
common
</pre>
If you run <em>Go To Declaration</em> on the last line,
this setting defines whether
the action jumps directly to <code>common.a</code>
(the first declaration),
or opens a popup asking which declaration you want to see.
""".trimIndent()
)
}.bind(settings::jumpToFirstDeclaration)
}
groupRowsRange("Find Usages") {
row {
checkBox("Show declarations as part of the results")
.bindSelected(settings::showDeclarationsAsUsages)
}
}
}.enabledIf(enabledCheckBox.selected)
}
}
}
30 changes: 30 additions & 0 deletions src/main/java/org/nixos/idea/settings/NixSymbolSettings.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.nixos.idea.settings

import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.BaseState
import com.intellij.openapi.components.SimplePersistentStateComponent
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import org.nixos.idea.settings.SimplePersistentStateComponentHelper.delegate

@State(name = "NixSymbolSettings", storages = [Storage("nix-idea.xml")])
class NixSymbolSettings : SimplePersistentStateComponent<NixSymbolSettings.State>(State()) {

class State : BaseState() {
var enabled by property(true)
var jumpToFirstDeclaration by property(true)
var showDeclarationsAsUsages by property(false)
}

companion object {
@JvmStatic
fun getInstance(): NixSymbolSettings {
return ApplicationManager.getApplication().getService(NixSymbolSettings::class.java)
}
}

var enabled: Boolean by delegate(State::enabled)
var jumpToFirstDeclaration by delegate(State::jumpToFirstDeclaration)
var showDeclarationsAsUsages: Boolean by delegate(State::showDeclarationsAsUsages)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.nixos.idea.settings

import com.intellij.openapi.components.BaseState
import com.intellij.openapi.components.SimplePersistentStateComponent
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KMutableProperty1
import kotlin.reflect.KProperty

internal object SimplePersistentStateComponentHelper {

/**
* Creates property which delegates every access to the given property of the state.
*
* ```kotlin
* @State(name = "SomeSettings", storages = [Storage(...)])
* class SomeSettings : SimplePersistentStateComponent<SomeSettings.State>(State()) {
* class State : BaseState() {
* // The internal storage of the configured values
* var enabled by property(true)
* }
*
* // Makes the property publicly accessible
* var enabled: Boolean by delegate(State::enabled)
* }
* ```
*/
fun <S : BaseState, V> delegate(prop: KMutableProperty1<S, V>): ReadWriteProperty<SimplePersistentStateComponent<S>, V> {
return object : ReadWriteProperty<SimplePersistentStateComponent<S>, V> {
override fun getValue(thisRef: SimplePersistentStateComponent<S>, property: KProperty<*>): V {
return prop.get(thisRef.state)
}

override fun setValue(thisRef: SimplePersistentStateComponent<S>, property: KProperty<*>, value: V) {
prop.set(thisRef.state, value)
}
}
}
}
9 changes: 9 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@
id="org.nixos.idea.settings.NixIDEASettings"
instance="org.nixos.idea.settings.NixIDEASettings" />

<applicationService
serviceImplementation="org.nixos.idea.settings.NixSymbolSettings"/>

<applicationConfigurable
parentId="language"
displayName="Nix Symbols"
id="org.nixos.idea.settings.NixSymbolConfigurable"
instance="org.nixos.idea.settings.NixSymbolConfigurable"/>

<colorSettingsPage
implementation="org.nixos.idea.settings.NixColorSettingsPage" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.intellij.testFramework.fixtures.CodeInsightTestFixture;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DynamicNode;
import org.junit.jupiter.api.TestFactory;
Expand All @@ -29,6 +30,7 @@
import org.nixos.idea.lang.references.symbol.NixSymbol;
import org.nixos.idea.lang.references.symbol.NixUserSymbol;
import org.nixos.idea.psi.NixDeclarationHost;
import org.nixos.idea.settings.NixSymbolSettings;

import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -54,6 +56,11 @@ final class SymbolNavigationTest {
myFixture = fixture;
}

@BeforeEach
void setUp() {
NixSymbolSettings.getInstance().setJumpToFirstDeclaration(false);
}

@TestFactory
Stream<DynamicNode> simple_assignment() {
return createTests("""
Expand Down

0 comments on commit 7a13192

Please sign in to comment.