From 9b8a650902d16cd730b9a4a20ad26a2927a08580 Mon Sep 17 00:00:00 2001 From: BoykoAlex Date: Tue, 16 Jan 2018 19:38:53 -0500 Subject: [PATCH] IntelliJ Boot-Java plugin based on IntelliJ LSP client plugin --- idea-extensions/idea-boot-java/.gitignore | 3 + idea-extensions/idea-boot-java/README.md | 15 +++ .../resources/META-INF/plugin.xml | 38 ++++++++ .../resources/icons/boot-icon.png | Bin 0 -> 617 bytes .../java/ls/BootJavaPreloadingActivity.scala | 66 +++++++++++++ .../tools/boot/java/ls/HighlightParams.java | 53 +++++++++++ .../tools/boot/java/ls/ProgressParams.java | 89 ++++++++++++++++++ .../java/ls/SpringBootGutterIconRenderer.java | 35 +++++++ .../boot/java/ls/StsLanguageClientImpl.scala | 72 ++++++++++++++ .../boot/java/ls/StsServerDefinition.scala | 13 +++ 10 files changed, 384 insertions(+) create mode 100644 idea-extensions/idea-boot-java/.gitignore create mode 100644 idea-extensions/idea-boot-java/README.md create mode 100644 idea-extensions/idea-boot-java/resources/META-INF/plugin.xml create mode 100644 idea-extensions/idea-boot-java/resources/icons/boot-icon.png create mode 100644 idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/BootJavaPreloadingActivity.scala create mode 100644 idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/HighlightParams.java create mode 100644 idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/ProgressParams.java create mode 100644 idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/SpringBootGutterIconRenderer.java create mode 100644 idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/StsLanguageClientImpl.scala create mode 100644 idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/StsServerDefinition.scala diff --git a/idea-extensions/idea-boot-java/.gitignore b/idea-extensions/idea-boot-java/.gitignore new file mode 100644 index 000000000..2b98bba13 --- /dev/null +++ b/idea-extensions/idea-boot-java/.gitignore @@ -0,0 +1,3 @@ +/resources/server/language-server.jar +/.idea +*.iml diff --git a/idea-extensions/idea-boot-java/README.md b/idea-extensions/idea-boot-java/README.md new file mode 100644 index 000000000..debece184 --- /dev/null +++ b/idea-extensions/idea-boot-java/README.md @@ -0,0 +1,15 @@ +# Spring Boot Java Support for IntelliJ IDEA (_Experimental_) +The support is based on IntelliJ LSP client plugin https://github.com/gtache/intellij-lsp + +## Dev Instructions +1. Clone and import the project into IntelliJ. ()Project is Scala based hence accept whatever IntelliJ suggests about having Scala) +2. Build `boot-java-language-server` maven project from STS4 (https://github.com/spring-projects/sts4/tree/master/headless-services/boot-java-language-server) +3. Copy the built `jar` file into this project `/resources/server` folder and name it `language-server.jar` +4. Install `LSP Support` plugin into IntelliJ as explained here: https://www.jetbrains.com/help/idea/installing-updating-and-uninstalling-repository-plugins.html +5. For some reason it's not enough for the dev env, hence also download the same plugin from https://www.jetbrains.com/help/idea/installing-updating-and-uninstalling-repository-plugins.html +6. Unzip the downloaded file and copy the folder into IntelliJ `pligins` folder +7. Select `idea-boot-java` project in IntelliJ go to `File -> Project Structure...` and then `Platform Settings -> SDKs` +8. Select `IntelliJ IDEA` in the middle pane. Find `+` in the bottom left corner of the right-most pane and click on it (list of jars within IntelliJ SDK) +9. Find all `Jar`s under the `IntelliJ/plugins/LSP` folder, select all of them and press `Open` in the dialog. This will ensure that your target platform has necessary LSP jars +10. Click on `Run -> Run...`, create new `Plugin` launch config. Select `Use classpath of module` to be `idea-boot-java`, select `JRE` to the `IntelliJ IDEA` SDK from step 8 +11. Run the configuration. This should start IntelliJ runtime workbench where `idea-boot-java` LS plugin is available \ No newline at end of file diff --git a/idea-extensions/idea-boot-java/resources/META-INF/plugin.xml b/idea-extensions/idea-boot-java/resources/META-INF/plugin.xml new file mode 100644 index 000000000..19a8b26b5 --- /dev/null +++ b/idea-extensions/idea-boot-java/resources/META-INF/plugin.xml @@ -0,0 +1,38 @@ + + org.spring.tools.boot-java.ls + Spring Boot Java Support + 1.0 + YourCompany + + + most HTML tags may be used + ]]> + + + most HTML tags may be used + ]]> + + + + + + + com.intellij.modules.lang + com.github.gtache.lsp + + + + + + + + + + + + + + \ No newline at end of file diff --git a/idea-extensions/idea-boot-java/resources/icons/boot-icon.png b/idea-extensions/idea-boot-java/resources/icons/boot-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..de88ef0d5ceb61e6e6b141349ae5269c9187a59a GIT binary patch literal 617 zcmV-v0+#)WP)|WK~y-6rIWu)TTv9pKj+1~MB|H5O0)AYOXdvzXI;@+8$XypN@4-;fb1CtKd>3s`+DR9R`50! zjx7bnBBCPF3Q#UZz3B7*CXkX0Sz^_U8fP#zNO!oKVP}}kP=?J z(YKumibjni2wS(d7)gvUHZaC$|0tc0z7VOL7s^NnMt+9w*Hc05(2ukQ>hh+g}2I zj7r)^Tc$|Rz_AA$OZ*xvrV%1H*N%;nCo9KG(J>ctk z21d ranges; + + public HighlightParams() { + } + + public HighlightParams(TextDocumentIdentifier doc, List ranges) { + super(); + this.doc = doc; + this.ranges = ranges; + } + public TextDocumentIdentifier getDoc() { + return doc; + } + public void setDoc(TextDocumentIdentifier doc) { + this.doc = doc; + } + public List getRanges() { + return ranges; + } + public void setRanges(List ranges) { + this.ranges = ranges; + } + + @Override + public String toString() { + return "HighlightParams [doc=" + doc + ", ranges=" + ranges + "]"; + } +} diff --git a/idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/ProgressParams.java b/idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/ProgressParams.java new file mode 100644 index 000000000..e14dcac90 --- /dev/null +++ b/idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/ProgressParams.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2016-2017 Pivotal, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ + +package org.spring.tools.boot.java.ls; + +public class ProgressParams { + + /** + * An id representing the enitity for which progress messages are to be shown. + */ + private String id; + + /** + * Updates the current statusMsg associated with a given the id. If null, then the message + * is cleared. + */ + private String statusMsg; + + + public ProgressParams() { + } + + public ProgressParams(String id, String statusMsg) { + super(); + this.id = id; + this.statusMsg = statusMsg; + } + + @Override + public String toString() { + return "ProgressParams [id=" + id + ", statusMsg=" + statusMsg + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + result = prime * result + ((statusMsg == null) ? 0 : statusMsg.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ProgressParams other = (ProgressParams) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + if (statusMsg == null) { + if (other.statusMsg != null) + return false; + } else if (!statusMsg.equals(other.statusMsg)) + return false; + return true; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getStatusMsg() { + return statusMsg; + } + + public void setStatusMsg(String statusMsg) { + this.statusMsg = statusMsg; + } + +} diff --git a/idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/SpringBootGutterIconRenderer.java b/idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/SpringBootGutterIconRenderer.java new file mode 100644 index 000000000..f7bb40545 --- /dev/null +++ b/idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/SpringBootGutterIconRenderer.java @@ -0,0 +1,35 @@ +package org.spring.tools.boot.java.ls; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import com.intellij.openapi.editor.markup.GutterIconRenderer; +import com.intellij.openapi.util.IconLoader; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +/** + * @author Alex Boyko + */ +public class SpringBootGutterIconRenderer extends GutterIconRenderer { + + public static SpringBootGutterIconRenderer INSTANCE = new SpringBootGutterIconRenderer(); + + private Supplier icon = Suppliers.memoize(() -> IconLoader.getIcon("/icons/boot-icon.png")); + + @Override + public boolean equals(Object o) { + return this == o; + } + + @Override + public int hashCode() { + return 0; + } + + @NotNull + @Override + public Icon getIcon() { + return icon.get(); + } +} diff --git a/idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/StsLanguageClientImpl.scala b/idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/StsLanguageClientImpl.scala new file mode 100644 index 000000000..423020ce5 --- /dev/null +++ b/idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/StsLanguageClientImpl.scala @@ -0,0 +1,72 @@ +package org.spring.tools.boot.java.ls + +import java.awt.Color + +import com.github.gtache.lsp.client.LanguageClientImpl +import com.github.gtache.lsp.client.languageserver.wrapper.LanguageServerWrapper +import com.github.gtache.lsp.editor.EditorEventManager +import com.github.gtache.lsp.utils.FileUtils +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.editor.markup._ +import org.eclipse.lsp4j.Range +import org.eclipse.lsp4j.jsonrpc.services.JsonNotification +import org.eclipse.lsp4j.services.LanguageServer + +import scala.collection.JavaConversions +import scala.collection.mutable.ListBuffer + +/** + * @author Alex Boyko + */ +class StsLanguageClientImpl extends LanguageClientImpl { + + private var serverWrapper: LanguageServerWrapper = _ + private var rangeHighlights = scala.collection.mutable.Map[String, ListBuffer[RangeHighlighter]]() + + override def connect(server: LanguageServer, wrapper: LanguageServerWrapper): Unit = { + super.connect(server, wrapper) + this.serverWrapper = wrapper + } + + @JsonNotification("sts/highlight") + def publishHints(params: HighlightParams): Unit = { + println("Highlight MSG") + val uri = FileUtils.sanitizeURI(params.getDoc.getUri) + val editorManager = this.serverWrapper.getEditorManagerFor(uri) + if (editorManager == null || editorManager.editor == null || editorManager.editor.getDocument == null) { + return + } + val doc = editorManager.editor.getDocument + // Similar to Eclipse UI thread execution + ApplicationManager.getApplication.invokeLater(new Runnable { + override def run(): Unit = { + if (rangeHighlights.get(uri).isDefined) { + rangeHighlights.get(uri).get.foreach(h => editorManager.editor.getMarkupModel.removeHighlighter(h)) + } + val highlighters: ListBuffer[RangeHighlighter] = ListBuffer() + for (r <- JavaConversions.asScalaBuffer(params.getRanges)) { + val startOffset = doc.getLineStartOffset(r.getStart.getLine) + r.getStart.getCharacter + val endOffset = doc.getLineStartOffset(r.getEnd.getLine) + r.getEnd.getCharacter + val attrs = new TextAttributes() + attrs.setEffectType(EffectType.BOXED) + attrs.setEffectColor(StsLanguageClientImpl.SPRING_BOOT_HINT_COLOR) + attrs.setErrorStripeColor(StsLanguageClientImpl.SPRING_BOOT_HINT_COLOR) + val highlighter = editorManager.editor.getMarkupModel.addRangeHighlighter(startOffset, endOffset, HighlighterLayer.ERROR, attrs, HighlighterTargetArea.EXACT_RANGE) + highlighter.setGutterIconRenderer(SpringBootGutterIconRenderer.INSTANCE) + highlighters += highlighter + } + rangeHighlights += Tuple2(uri, highlighters) + } + }) + } + + @JsonNotification("sts/progress") + def progress(progressEvent: ProgressParams): Unit = { + println("Progress MSG") + } + +} + +object StsLanguageClientImpl { + val SPRING_BOOT_HINT_COLOR = new Color(0x32, 0xBA, 0x56) +} diff --git a/idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/StsServerDefinition.scala b/idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/StsServerDefinition.scala new file mode 100644 index 000000000..aad3e1873 --- /dev/null +++ b/idea-extensions/idea-boot-java/src/org/spring/tools/boot/java/ls/StsServerDefinition.scala @@ -0,0 +1,13 @@ +package org.spring.tools.boot.java.ls + +import com.github.gtache.lsp.client.LanguageClientImpl +import com.github.gtache.lsp.client.languageserver.serverdefinition.{CommandServerDefinition, RawCommandServerDefinition, UserConfigurableServerDefinitionObject} + +/** + * @author Alex Boyko + */ +class StsServerDefinition(override val ext: String, override val command: Array[String]) extends RawCommandServerDefinition(ext, command) { + + override def createLanguageClient: LanguageClientImpl = new StsLanguageClientImpl + +}