Skip to content

Commit

Permalink
Add LSP support (#68) [paid versions of IDEA only]
Browse files Browse the repository at this point in the history
  • Loading branch information
JojOatXGME committed Apr 14, 2024
1 parent 736f766 commit 6880b88
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 6 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
### Added

- Plugin logo for easier recognition
- Experimental Language Server support using IDEA's LSP API (#68)
[(Only works for paid versions of IDEA :disappointed:)](https://blog.jetbrains.com/platform/2023/07/lsp-for-plugin-developers/#supported-ides)

### Changed

Expand Down
5 changes: 3 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import org.jetbrains.changelog.Changelog
import org.jetbrains.changelog.markdownToHTML
import org.jetbrains.intellij.tasks.RunPluginVerifierTask
import org.jetbrains.intellij.tasks.RunPluginVerifierTask.FailureLevel
import java.util.EnumSet

plugins {
id("java")
Expand Down Expand Up @@ -167,7 +168,7 @@ tasks {
}

runPluginVerifier {
failureLevel = RunPluginVerifierTask.FailureLevel.ALL
failureLevel = EnumSet.complementOf(EnumSet.of(FailureLevel.EXPERIMENTAL_API_USAGES))
// Version 1.364 seems to be broken and always complains about supposedly missing 'plugin.xml':
// https://youtrack.jetbrains.com/issue/MP-6388
verifierVersion = "1.307"
Expand Down
7 changes: 4 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
pluginGroup = org.nixos.idea
pluginName = NixIDEA
pluginVersion = 0.4.0.13
pluginSinceBuild = 231
pluginSinceBuild = 232
pluginUntilBuild = 241.*

platformType = IC
platformVersion = 2023.1.6
platformType = IU
# TODO Revert to 2023.2.6?
platformVersion = 2024.1

# Gradle Configuration
# -> https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties
Expand Down
34 changes: 34 additions & 0 deletions src/main/java/org/nixos/idea/lsp/NixLspServerDescriptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.nixos.idea.lsp;

import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.platform.lsp.api.ProjectWideLspServerDescriptor;
import com.intellij.util.execution.ParametersListUtil;
import org.jetbrains.annotations.NotNull;
import org.nixos.idea.file.NixFileType;

import java.util.List;

@SuppressWarnings("UnstableApiUsage")
final class NixLspServerDescriptor extends ProjectWideLspServerDescriptor {

private final String myCommand;

NixLspServerDescriptor(@NotNull Project project, NixLspSettings settings) {
super(project, "Nix");
myCommand = settings.getCommand();
}

@Override
public @NotNull GeneralCommandLine createCommandLine() throws ExecutionException {
List<String> argv = ParametersListUtil.parse(myCommand, false, true);
return new GeneralCommandLine(argv);
}

@Override
public boolean isSupportedFile(@NotNull VirtualFile virtualFile) {
return virtualFile.getFileType() == NixFileType.INSTANCE;
}
}
29 changes: 29 additions & 0 deletions src/main/java/org/nixos/idea/lsp/NixLspServerSupportProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.nixos.idea.lsp;

import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.platform.lsp.api.LspServer;
import com.intellij.platform.lsp.api.LspServerSupportProvider;
import com.intellij.platform.lsp.api.lsWidget.LspServerWidgetItem;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.nixos.idea.file.NixFileType;
import org.nixos.idea.icon.NixIcons;

@SuppressWarnings("UnstableApiUsage")
public final class NixLspServerSupportProvider implements LspServerSupportProvider {
@Override
public void fileOpened(@NotNull Project project, @NotNull VirtualFile virtualFile, @NotNull LspServerStarter lspServerStarter) {
if (virtualFile.getFileType() == NixFileType.INSTANCE) {
NixLspSettings settings = NixLspSettings.getInstance();
if (settings.isEnabled()) {
lspServerStarter.ensureServerStarted(new NixLspServerDescriptor(project, settings));
}
}
}

@Override
public @NotNull LspServerWidgetItem createLspServerWidgetItem(@NotNull LspServer lspServer, @Nullable VirtualFile currentFile) {
return new LspServerWidgetItem(lspServer, currentFile, NixIcons.FILE, NixLspSettingsConfigurable.class);
}
}
54 changes: 54 additions & 0 deletions src/main/java/org/nixos/idea/lsp/NixLspSettings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.nixos.idea.lsp;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.RoamingType;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import org.jetbrains.annotations.NotNull;

@State(name = "NixLspSettings", storages = @Storage(value = "nix-idea-tools.xml", roamingType = RoamingType.LOCAL))
public final class NixLspSettings implements PersistentStateComponent<NixLspSettings.State> {

// Documentation:
// https://plugins.jetbrains.com/docs/intellij/persisting-state-of-components.html

private @NotNull State myState = new State();

public static @NotNull NixLspSettings getInstance() {
return ApplicationManager.getApplication().getService(NixLspSettings.class);
}

public boolean isEnabled() {
return myState.enabled;
}

public void setEnabled(boolean enabled) {
myState.enabled = enabled;
}

public @NotNull String getCommand() {
return myState.command;
}

public void setCommand(@NotNull String command) {
myState.command = command;
}

@SuppressWarnings("ClassEscapesDefinedScope")
@Override
public void loadState(@NotNull State state) {
myState = state;
}

@SuppressWarnings("ClassEscapesDefinedScope")
@Override
public @NotNull State getState() {
return myState;
}

static final class State {
public boolean enabled = false;
public @NotNull String command = "";
}
}
100 changes: 100 additions & 0 deletions src/main/java/org/nixos/idea/lsp/NixLspSettingsConfigurable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package org.nixos.idea.lsp;

import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.NlsContexts;
import com.intellij.platform.lsp.api.LspServerManager;
import com.intellij.ui.RawCommandLineEditor;
import com.intellij.ui.TitledSeparator;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.util.ui.FormBuilder;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.JComponent;
import javax.swing.JPanel;

public class NixLspSettingsConfigurable implements SearchableConfigurable, Configurable.Beta {

private @Nullable JBCheckBox myEnabled;
private @Nullable RawCommandLineEditor myCommand;

@Override
public @NotNull @NonNls String getId() {
return "org.nixos.idea.lsp.NixLspSettings";
}

@Override
public @NlsContexts.ConfigurableName String getDisplayName() {
return "Language Server (LSP)";
}

@Override
public @Nullable JComponent createComponent() {
myEnabled = new JBCheckBox("Enable language server");
myEnabled.addChangeListener(e -> updateUiState());

myCommand = new RawCommandLineEditor();
myCommand.getEditorField().getEmptyText().setText("Command to start Language Server");
myCommand.getEditorField().getAccessibleContext().setAccessibleName("Command to start Language Server");
myCommand.getEditorField().setMargin(myEnabled.getMargin());

// TODO: Add suggestions somehow
//myCommand.getComponentPopupMenu().add(new JBMenuItem("nix --extra-experimental-features "nix-command flakes" run nixpkgs#nil"));

return FormBuilder.createFormBuilder()
.addComponent(myEnabled)
.addComponent(new TitledSeparator("Language Server Configuration"))
.addLabeledComponent("Command: ", myCommand)
.addComponentFillVertically(new JPanel(), 0)
.getPanel();
}

@Override
public void reset() {
assert myEnabled != null;
assert myCommand != null;

NixLspSettings settings = NixLspSettings.getInstance();
myEnabled.setSelected(settings.isEnabled());
myCommand.setText(settings.getCommand());

updateUiState();
}

@SuppressWarnings("UnstableApiUsage")
@Override
public void apply() throws ConfigurationException {
assert myEnabled != null;
assert myCommand != null;

NixLspSettings settings = NixLspSettings.getInstance();
settings.setEnabled(myEnabled.isSelected());
settings.setCommand(myCommand.getText());

for (Project project : ProjectManager.getInstance().getOpenProjects()) {
LspServerManager.getInstance(project).stopAndRestartIfNeeded(NixLspServerSupportProvider.class);
}
}

@Override
public boolean isModified() {
assert myEnabled != null;
assert myCommand != null;

NixLspSettings settings = NixLspSettings.getInstance();
return Configurable.isCheckboxModified(myEnabled, settings.isEnabled()) ||
Configurable.isFieldModified(myCommand.getTextField(), settings.getCommand());
}

private void updateUiState() {
assert myEnabled != null;
assert myCommand != null;

myCommand.setEnabled(myEnabled.isSelected());
}
}
15 changes: 14 additions & 1 deletion src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<vendor>NixOS</vendor>

<depends>com.intellij.modules.lang</depends>
<depends>com.intellij.modules.platform</depends>

<extensions defaultExtensionNs="com.intellij">

Expand Down Expand Up @@ -38,14 +39,26 @@
implementationClass="org.nixos.idea.lang.NixCommenter"/>

<projectConfigurable
groupId="build"
parentId="build"
displayName="NixIDEA Settings"
id="org.nixos.idea.settings.NixIDEASettings"
instance="org.nixos.idea.settings.NixIDEASettings" />

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

<applicationConfigurable
parentId="language"
displayName="Nix Language Server (LSP)"
id="org.nixos.idea.lsp.NixLspSettingsConfigurable"
instance="org.nixos.idea.lsp.NixLspSettingsConfigurable"/>

<applicationService
serviceImplementation="org.nixos.idea.lsp.NixLspSettings"/>

<platform.lsp.serverSupportProvider
implementation="org.nixos.idea.lsp.NixLspServerSupportProvider"/>

</extensions>

</idea-plugin>

0 comments on commit 6880b88

Please sign in to comment.