diff --git a/java/java.lsp.server/licenseinfo.xml b/java/java.lsp.server/licenseinfo.xml index f98f29338b9b..b2f957aee746 100644 --- a/java/java.lsp.server/licenseinfo.xml +++ b/java/java.lsp.server/licenseinfo.xml @@ -27,6 +27,11 @@ vscode/src/extension.ts + + src/org/netbeans/modules/java/lsp/server/refactoring/ui/codicon.ttf + src/org/netbeans/modules/java/lsp/server/refactoring/ui/codicon.css + + vscode/.vscodeignore vscode/.eslintrc.json diff --git a/java/java.lsp.server/nbproject/org-netbeans-modules-java-lsp-server.sig b/java/java.lsp.server/nbproject/org-netbeans-modules-java-lsp-server.sig index 398d3c2c50ba..6e1607d163c0 100644 --- a/java/java.lsp.server/nbproject/org-netbeans-modules-java-lsp-server.sig +++ b/java/java.lsp.server/nbproject/org-netbeans-modules-java-lsp-server.sig @@ -1,5 +1,5 @@ #Signature file v4.1 -#Version 1.10.0 +#Version 1.14.0 CLSS public java.lang.Object cons public init() @@ -23,6 +23,35 @@ meth public void notifyLater(org.openide.NotifyDescriptor) supr org.openide.DialogDisplayer hfds context +CLSS public org.netbeans.modules.java.lsp.server.ui.AbstractGlobalActionContext +cons public init() +intf org.openide.util.ContextGlobalProvider +intf org.openide.util.Lookup$Provider +meth public org.openide.util.Lookup createGlobalContext() +meth public org.openide.util.Lookup getLookup() +meth public static <%0 extends java.lang.Object> {%%0} withActionContext(org.openide.util.Lookup,java.util.concurrent.Callable<{%%0}>) +supr java.lang.Object +hcls ContextHolder + +CLSS public org.netbeans.modules.java.lsp.server.ui.AbstractLspHtmlViewer +cons protected init() +innr protected final View +intf org.netbeans.spi.htmlui.HTMLViewerSpi +meth public <%0 extends java.lang.Object> {%%0} component(org.netbeans.modules.java.lsp.server.ui.AbstractLspHtmlViewer$View,java.lang.Class<{%%0}>) +meth public java.lang.Object createButton(org.netbeans.modules.java.lsp.server.ui.AbstractLspHtmlViewer$View,java.lang.String) +meth public java.lang.String getId(org.netbeans.modules.java.lsp.server.ui.AbstractLspHtmlViewer$View,java.lang.Object) +meth public org.netbeans.modules.java.lsp.server.ui.AbstractLspHtmlViewer$View newView(org.netbeans.spi.htmlui.HTMLViewerSpi$Context) +meth public void runLater(org.netbeans.modules.java.lsp.server.ui.AbstractLspHtmlViewer$View,java.lang.Runnable) +meth public void setEnabled(org.netbeans.modules.java.lsp.server.ui.AbstractLspHtmlViewer$View,java.lang.Object,boolean) +meth public void setText(org.netbeans.modules.java.lsp.server.ui.AbstractLspHtmlViewer$View,java.lang.Object,java.lang.String) +supr java.lang.Object +hfds initial + +CLSS protected final org.netbeans.modules.java.lsp.server.ui.AbstractLspHtmlViewer$View + outer org.netbeans.modules.java.lsp.server.ui.AbstractLspHtmlViewer +supr java.lang.Object +hfds ctx,presenter,ui + CLSS public abstract org.netbeans.modules.java.lsp.server.ui.AbstractLspInputOutputProvider cons protected init() innr public final static LspIO @@ -92,6 +121,7 @@ meth protected abstract java.util.concurrent.CompletableFuture showHtmlPage(org.netbeans.modules.java.lsp.server.protocol.HtmlPageParams) meth public static org.netbeans.modules.java.lsp.server.ui.UIContext find() anno 0 org.netbeans.api.annotations.common.NonNull() meth public static org.netbeans.modules.java.lsp.server.ui.UIContext find(org.openide.util.Lookup) @@ -104,6 +134,16 @@ CLSS public abstract interface org.netbeans.modules.progress.spi.ProgressEnviron meth public abstract org.netbeans.api.progress.ProgressHandle createHandle(java.lang.String,org.openide.util.Cancellable,boolean) meth public abstract org.netbeans.modules.progress.spi.Controller getController() +CLSS public abstract interface org.netbeans.spi.htmlui.HTMLViewerSpi<%0 extends java.lang.Object, %1 extends java.lang.Object> +innr public final static Context +meth public abstract <%0 extends java.lang.Object> {%%0} component({org.netbeans.spi.htmlui.HTMLViewerSpi%0},java.lang.Class<{%%0}>) +meth public abstract java.lang.String getId({org.netbeans.spi.htmlui.HTMLViewerSpi%0},{org.netbeans.spi.htmlui.HTMLViewerSpi%1}) +meth public abstract void runLater({org.netbeans.spi.htmlui.HTMLViewerSpi%0},java.lang.Runnable) +meth public abstract void setEnabled({org.netbeans.spi.htmlui.HTMLViewerSpi%0},{org.netbeans.spi.htmlui.HTMLViewerSpi%1},boolean) +meth public abstract void setText({org.netbeans.spi.htmlui.HTMLViewerSpi%0},{org.netbeans.spi.htmlui.HTMLViewerSpi%1},java.lang.String) +meth public abstract {org.netbeans.spi.htmlui.HTMLViewerSpi%0} newView(org.netbeans.spi.htmlui.HTMLViewerSpi$Context) +meth public abstract {org.netbeans.spi.htmlui.HTMLViewerSpi%1} createButton({org.netbeans.spi.htmlui.HTMLViewerSpi%0},java.lang.String) + CLSS public abstract interface org.netbeans.spi.io.InputOutputProvider<%0 extends java.lang.Object, %1 extends java.io.PrintWriter, %2 extends java.lang.Object, %3 extends java.lang.Object> meth public abstract boolean isIOClosed({org.netbeans.spi.io.InputOutputProvider%0}) anno 1 org.netbeans.api.annotations.common.NonNull() @@ -190,3 +230,27 @@ supr java.lang.Object hfds INSTANCE hcls Trivial +CLSS public abstract interface org.openide.util.ContextGlobalProvider +meth public abstract org.openide.util.Lookup createGlobalContext() + +CLSS public abstract org.openide.util.Lookup +cons public init() +fld public final static org.openide.util.Lookup EMPTY +innr public abstract interface static Provider +innr public abstract static Item +innr public abstract static Result +innr public final static Template +meth public <%0 extends java.lang.Object> java.util.Collection lookupAll(java.lang.Class<{%%0}>) +meth public <%0 extends java.lang.Object> org.openide.util.Lookup$Item<{%%0}> lookupItem(org.openide.util.Lookup$Template<{%%0}>) +meth public <%0 extends java.lang.Object> org.openide.util.Lookup$Result<{%%0}> lookupResult(java.lang.Class<{%%0}>) +meth public abstract <%0 extends java.lang.Object> org.openide.util.Lookup$Result<{%%0}> lookup(org.openide.util.Lookup$Template<{%%0}>) +meth public abstract <%0 extends java.lang.Object> {%%0} lookup(java.lang.Class<{%%0}>) +meth public static org.openide.util.Lookup getDefault() +supr java.lang.Object +hfds LOG,defaultLookup,defaultLookupProvider +hcls DefLookup,Empty + +CLSS public abstract interface static org.openide.util.Lookup$Provider + outer org.openide.util.Lookup +meth public abstract org.openide.util.Lookup getLookup() + diff --git a/java/java.lsp.server/nbproject/project.properties b/java/java.lsp.server/nbproject/project.properties index 13e2c2cd50ca..2d7c0f38f8e7 100644 --- a/java/java.lsp.server/nbproject/project.properties +++ b/java/java.lsp.server/nbproject/project.properties @@ -17,7 +17,7 @@ javac.source=1.8 javac.compilerargs=-Xlint -Xlint:-serial -spec.version.base=1.13.0 +spec.version.base=1.14.0 requires.nb.javac=true lsp.build.dir=vscode/nbcode test.unit.run.cp.extra= diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/Buttons.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/Buttons.java new file mode 100644 index 000000000000..c5489918e5eb --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/Buttons.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.java.lsp.server.htmlui; + +import net.java.html.js.JavaScriptBody; +import org.netbeans.spi.htmlui.HTMLViewerSpi; + +/** + * Helper utilities to deal with HTML buttons. + */ +public final class Buttons { + private Buttons() { + } + + @JavaScriptBody(args = {}, body = "\n" + + "const vscode = acquireVsCodeApi();\n" // this method can be called only once per WebView existance + + "window.close = function() {\n" + + " vscode.postMessage({\n" + + " command: 'dispose',\n" + + " });\n" + + "};\n" + ) + public static native void registerCloseWindow(); + + @JavaScriptBody(args = { "id", "callback" }, javacall = true, body = "\n" + + "var first = false;\n" + + "var footer = document.getElementById('dialog-buttons');\n" + + "if (!footer) {\n" + + " first = true\n" + + " footer = document.createElement('div');\n" + + " footer.id = 'dialog-buttons';\n" + + " footer.classList.add('flex');\n" + + " footer.classList.add('section');\n" + + " document.body.appendChild(footer);\n" + + "}\n" + + "var button = document.createElement('button');\n" + + "button.id = id;\n" + + "button.onclick = function() {;\n" + + " @org.netbeans.modules.java.lsp.server.htmlui.Buttons::clickButton0(Ljava/lang/String;Ljava/lang/Object;)(id, callback);\n" + + "};\n" + + "button.classList.add('regular-button');\n" + + "button.classList.add('vscode-font');\n" + + "if (first) {\n" + + " button.classList.add('align-right');\n" + + "}\n" + + "footer.appendChild(button);\n" + + "return button;\n" + ) + public native static Object createButton0(String id, HTMLViewerSpi.Context callback); + + static void clickButton0(String id, Object callback) { + HTMLViewerSpi.Context ctx = (HTMLViewerSpi.Context) callback; + ctx.onSubmit(id); + } + + @JavaScriptBody(args = { "b" }, body = "return b.id;") + public native static String buttonName0(Object b); + + @JavaScriptBody(args = { "b", "text" }, body = "b.innerHTML = text;") + public native static void buttonText0(Object b, String text); + + @JavaScriptBody(args = { "b", "disabled" }, body = "return b.disabled = disabled;") + public native static String buttonDisabled0(Object b, boolean disabled); + +} diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ChangeMethodParametersRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ChangeMethodParametersRefactoring.java deleted file mode 100644 index 157fdce6753a..000000000000 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ChangeMethodParametersRefactoring.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.netbeans.modules.java.lsp.server.protocol; - -import com.google.gson.Gson; -import com.sun.source.tree.BlockTree; -import com.sun.source.tree.ClassTree; -import com.sun.source.tree.StatementTree; -import com.sun.source.tree.Tree; -import com.sun.source.util.SourcePositions; -import com.sun.source.util.TreePath; -import com.sun.source.util.Trees; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeKind; -import org.eclipse.lsp4j.ApplyWorkspaceEditParams; -import org.eclipse.lsp4j.CodeAction; -import org.eclipse.lsp4j.CodeActionKind; -import org.eclipse.lsp4j.CodeActionParams; -import org.eclipse.lsp4j.MessageParams; -import org.eclipse.lsp4j.MessageType; -import org.netbeans.api.java.source.ClasspathInfo; -import org.netbeans.api.java.source.CompilationController; -import org.netbeans.api.java.source.CompilationInfo; -import org.netbeans.api.java.source.ElementHandle; -import org.netbeans.api.java.source.JavaSource; -import org.netbeans.api.java.source.SourceUtils; -import org.netbeans.api.java.source.TreePathHandle; -import org.netbeans.api.java.source.TreeUtilities; -import org.netbeans.modules.editor.java.Utilities; -import org.netbeans.modules.java.lsp.server.Utils; -import org.netbeans.modules.parsing.api.ResultIterator; -import org.netbeans.modules.refactoring.java.api.ChangeParametersRefactoring; -import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; -import org.openide.filesystems.FileObject; -import org.openide.util.NbBundle; -import org.openide.util.lookup.ServiceProvider; - -/** - * - * @author Dusan Balek - */ -@ServiceProvider(service = CodeActionsProvider.class, position = 200) -public final class ChangeMethodParametersRefactoring extends CodeRefactoring { - - private static final String CHANGE_METHOD_PARAMS_REFACTORING_KIND = "refactor.change.method.params"; - private static final String CHANGE_METHOD_PARAMS_REFACTORING_COMMAND = "java.refactor.change.method.params"; - - private final Set commands = Collections.singleton(CHANGE_METHOD_PARAMS_REFACTORING_COMMAND); - private final Gson gson = new Gson(); - - @Override - @NbBundle.Messages({ - "DN_ChangeMethodParams=Change Method Parameters...", - }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { - List only = params.getContext().getOnly(); - if (only == null || !only.contains(CodeActionKind.Refactor)) { - return Collections.emptyList(); - } - CompilationController info = CompilationController.get(resultIterator.getParserResult()); - if (info == null || !JavaRefactoringUtils.isRefactorable(info.getFileObject())) { - return Collections.emptyList(); - } - info.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); - int offset = getOffset(info, params.getRange().getStart()); - Trees trees = info.getTrees(); - TreePath path = info.getTreeUtilities().pathFor(offset); - Tree.Kind kind = null; - while (path != null && (kind = path.getLeaf().getKind()) != Tree.Kind.METHOD && kind != Tree.Kind.METHOD_INVOCATION && kind != Tree.Kind.NEW_CLASS && kind != Tree.Kind.MEMBER_REFERENCE) { - path = path.getParentPath(); - } - Element element = null; - FileObject elementSource = null; - if (kind == Tree.Kind.METHOD_INVOCATION || kind == Tree.Kind.NEW_CLASS || kind == Tree.Kind.MEMBER_REFERENCE) { - element = trees.getElement(path); - if (element == null || element.asType().getKind() == TypeKind.ERROR) { - return Collections.emptyList(); - } - elementSource = SourceUtils.getFile(ElementHandle.create(element), info.getClasspathInfo()); - } - if (elementSource == null) { - return Collections.emptyList(); - } - QuickPickItem elementItem = new QuickPickItem(createLabel(info, element, true)); - elementItem.setUserData(new ElementData(element)); - return Collections.singletonList(createCodeAction(Bundle.DN_ChangeMethodParams(), CHANGE_METHOD_PARAMS_REFACTORING_KIND, null, CHANGE_METHOD_PARAMS_REFACTORING_COMMAND, Utils.toUri(elementSource), elementItem)); - } - - @Override - public Set getCommands() { - return commands; - } - - @Override - @NbBundle.Messages({ - "DN_ChangeMethodSignature=Change method signature", - }) - public CompletableFuture processCommand(NbCodeLanguageClient client, String command, List arguments) { - try { - if (arguments.size() > 1) { - String uri = gson.fromJson(gson.toJson(arguments.get(0)), String.class); - QuickPickItem sourceItem = gson.fromJson(gson.toJson(arguments.get(1)), QuickPickItem.class); - String label = sourceItem.getLabel(); - int idx = label.indexOf('('); - client.showInputBox(new ShowInputBoxParams(Bundle.DN_ChangeMethodSignature(), label.substring(idx))).thenAccept(signature -> { - if (signature != null && !signature.isEmpty()) { - changeMethodParams(client, uri, sourceItem, signature); - } - }); - } else { - throw new IllegalArgumentException(String.format("Illegal number of arguments received for command: %s", command)); - } - } catch (Exception ex) { - client.showMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); - } - return CompletableFuture.completedFuture(true); - } - - private void changeMethodParams(NbCodeLanguageClient client, String uri, QuickPickItem source, String signature) { - try { - FileObject file = Utils.fromUri(uri); - ClasspathInfo info = ClasspathInfo.create(file); - JavaSource js = JavaSource.forFileObject(file); - if (js == null) { - throw new IOException("Cannot get JavaSource for: " + uri); - } - ElementHandle handle = gson.fromJson(gson.toJson(source.getUserData()), ElementData.class).toHandle(); - AtomicReference params = new AtomicReference<>(); - StringBuilder ret = new StringBuilder(); - js.runUserActionTask(ci -> { - ci.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); - ExecutableElement method = (ExecutableElement) handle.resolve(ci); - if (method != null) { - TreePath path = ci.getTrees().getPath(method); - if (path != null) { - ExecutableElement el = fromSignature(ci, signature, path); - if (el != null) { - if (method.getReturnType() != el.getReturnType()) { - ret.append(Utilities.getTypeName(ci, el.getReturnType(), true)); - } - params.set(matchParameters(ci, el.getParameters(), method.getParameters())); - } - } - } - }, true); - if (params.get() == null) { - throw new IllegalArgumentException("Error while parsing new method signature."); - } - ChangeParametersRefactoring refactoring = new ChangeParametersRefactoring(TreePathHandle.from(handle, info)); - refactoring.setReturnType(ret.length() > 0 ? ret.toString() : null); - refactoring.setParameterInfo(params.get()); - refactoring.getContext().add(JavaRefactoringUtils.getClasspathInfoFor(file)); - client.applyEdit(new ApplyWorkspaceEditParams(perform(refactoring, "ChangeMethodParameters"))); - } catch (Exception ex) { - client.showMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); - } - } - - private static ExecutableElement fromSignature(CompilationInfo info, String signature, TreePath path) { - int idx = signature.lastIndexOf(':'); - StringBuilder toParse = new StringBuilder("{class _X { public "); - if (idx < 0) { - toParse.append("_X").append(signature); - } else { - toParse.append(signature.substring(idx + 1)).append(" m").append(signature.substring(0, idx)); - } - toParse.append("{}}}"); - SourcePositions[] sp = new SourcePositions[1]; - TreeUtilities treeUtilities = info.getTreeUtilities(); - StatementTree stmt = treeUtilities.parseStatement(toParse.toString(), sp); - if (stmt != null && stmt.getKind() == Tree.Kind.BLOCK) { - treeUtilities.attributeTree(stmt, info.getTrees().getScope(path)); - List stmts = ((BlockTree) stmt).getStatements(); - if (!stmts.isEmpty() && stmts.get(0).getKind() == Tree.Kind.CLASS) { - ClassTree ct = (ClassTree) stmts.get(0); - for (Tree member : ct.getMembers()) { - TreePath memberPath = new TreePath(path, member); - if (!treeUtilities.isSynthetic(memberPath) && member.getKind() == Tree.Kind.METHOD) { - Element element = info.getTrees().getElement(memberPath); - if (element != null && (element.getKind() == ElementKind.METHOD || element.getKind() == ElementKind.CONSTRUCTOR)) { - return (ExecutableElement) element; - } - } - } - } - } - return null; - } - - private static ChangeParametersRefactoring.ParameterInfo[] matchParameters(CompilationInfo info, List params, List orig) { - ChangeParametersRefactoring.ParameterInfo[] result = new ChangeParametersRefactoring.ParameterInfo[params.size()]; - boolean[] used = new boolean[orig.size()]; - for (int idx = 0; idx < params.size(); idx++) { - VariableElement param = params.get(idx); - for (int i = 0; i < orig.size(); i++) { - if (!used[i]) { - VariableElement origParam = orig.get(i); - if (origParam.getSimpleName().contentEquals(param.getSimpleName())) { - result[idx] = new ChangeParametersRefactoring.ParameterInfo(i, param.getSimpleName().toString(), Utilities.getTypeName(info, param.asType(), true).toString(), null); - used[i] = true; - } - } - } - } - for (int idx = 0; idx < params.size(); idx++) { - if (result[idx] == null) { - VariableElement param = params.get(idx); - for (int i = 0; i < orig.size(); i++) { - if (!used[i]) { - VariableElement origParam = orig.get(i); - if (origParam.asType() == param.asType()) { - result[idx] = new ChangeParametersRefactoring.ParameterInfo(i, param.getSimpleName().toString(), Utilities.getTypeName(info, param.asType(), true).toString(), null); - used[i] = true; - } - } - } - } - } - for (int idx = 0; idx < params.size(); idx++) { - if (result[idx] == null) { - VariableElement param = params.get(idx); - result[idx] = idx >= orig.size() || used[idx] - ? new ChangeParametersRefactoring.ParameterInfo(-1, param.getSimpleName().toString(), Utilities.getTypeName(info, param.asType(), true).toString(), defaultValue(param)) - : new ChangeParametersRefactoring.ParameterInfo(idx, param.getSimpleName().toString(), Utilities.getTypeName(info, param.asType(), true).toString(), null); - } - } - return result; - } - - private static String defaultValue(VariableElement param) { - switch(param.asType().getKind()) { - case ARRAY: - case DECLARED: - return "null"; - case BOOLEAN: - return "false"; - case BYTE: - case CHAR: - case DOUBLE: - case FLOAT: - case INT: - case LONG: - case SHORT: - return "0"; - } - return null; - } -} diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java index 5ea0ec7a9523..30910a4cf67c 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java @@ -159,11 +159,11 @@ public ElementData(ElementHandle handle) { this.signature = ElementHandleAccessor.getInstance().getJVMSignature(handle); } - ElementHandle toHandle() { + public ElementHandle toHandle() { return ElementHandleAccessor.getInstance().create(ElementKind.valueOf(kind), signature); } - Element resolve(CompilationInfo info) { + public Element resolve(CompilationInfo info) { return toHandle().resolve(info); } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java new file mode 100644 index 000000000000..627a9611e766 --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java @@ -0,0 +1,363 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.java.lsp.server.refactoring; + +import com.google.gson.Gson; +import com.sun.source.tree.Tree; +import com.sun.source.util.TreePath; +import com.sun.source.util.Trees; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; +import java.util.logging.Level; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeKind; +import net.java.html.json.ComputedProperty; +import net.java.html.json.Function; +import net.java.html.json.Model; +import net.java.html.json.ModelOperation; +import net.java.html.json.Property; +import org.eclipse.lsp4j.ApplyWorkspaceEditParams; +import org.eclipse.lsp4j.CodeAction; +import org.eclipse.lsp4j.CodeActionKind; +import org.eclipse.lsp4j.CodeActionParams; +import org.eclipse.lsp4j.MessageParams; +import org.eclipse.lsp4j.MessageType; +import org.netbeans.api.htmlui.HTMLDialog; +import org.netbeans.api.java.source.ClasspathInfo; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.ElementHandle; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.api.java.source.SourceUtils; +import org.netbeans.api.java.source.TreePathHandle; +import org.netbeans.modules.editor.java.Utilities; +import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.java.lsp.server.protocol.CodeActionsProvider; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient; +import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem; +import org.netbeans.modules.parsing.api.ResultIterator; +import org.netbeans.modules.refactoring.java.api.ChangeParametersRefactoring; +import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; +import org.openide.filesystems.FileObject; +import org.openide.util.Exceptions; +import org.openide.util.NbBundle; +import org.openide.util.RequestProcessor; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author Dusan Balek + */ +@ServiceProvider(service = CodeActionsProvider.class, position = 200) +public final class ChangeMethodParametersRefactoring extends CodeRefactoring { + + private static final String CHANGE_METHOD_PARAMS_REFACTORING_KIND = "refactor.change.method.params"; + private static final String CHANGE_METHOD_PARAMS_REFACTORING_COMMAND = "java.refactor.change.method.params"; + + private final Set commands = Collections.singleton(CHANGE_METHOD_PARAMS_REFACTORING_COMMAND); + private final Gson gson = new Gson(); + + @Override + @NbBundle.Messages({ + "DN_ChangeMethodParams=Change Method Parameters...", + }) + public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + List only = params.getContext().getOnly(); + if (only == null || !only.contains(CodeActionKind.Refactor)) { + return Collections.emptyList(); + } + CompilationController info = CompilationController.get(resultIterator.getParserResult()); + if (info == null || !JavaRefactoringUtils.isRefactorable(info.getFileObject())) { + return Collections.emptyList(); + } + info.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); + int offset = getOffset(info, params.getRange().getStart()); + Trees trees = info.getTrees(); + TreePath path = info.getTreeUtilities().pathFor(offset); + Tree.Kind kind = null; + while (path != null && (kind = path.getLeaf().getKind()) != Tree.Kind.METHOD && kind != Tree.Kind.METHOD_INVOCATION && kind != Tree.Kind.NEW_CLASS && kind != Tree.Kind.MEMBER_REFERENCE) { + path = path.getParentPath(); + } + Element element = null; + FileObject elementSource = null; + if (kind == Tree.Kind.METHOD || kind == Tree.Kind.METHOD_INVOCATION || kind == Tree.Kind.NEW_CLASS || kind == Tree.Kind.MEMBER_REFERENCE) { + element = trees.getElement(path); + if (element == null || element.asType().getKind() == TypeKind.ERROR) { + return Collections.emptyList(); + } + elementSource = SourceUtils.getFile(ElementHandle.create(element), info.getClasspathInfo()); + } + if (elementSource == null) { + return Collections.emptyList(); + } + QuickPickItem elementItem = new QuickPickItem(createLabel(info, element, true)); + elementItem.setUserData(new ElementData(element)); + return Collections.singletonList(createCodeAction(Bundle.DN_ChangeMethodParams(), CHANGE_METHOD_PARAMS_REFACTORING_KIND, null, CHANGE_METHOD_PARAMS_REFACTORING_COMMAND, Utils.toUri(elementSource), elementItem)); + } + + @Override + public Set getCommands() { + return commands; + } + + @Override + @NbBundle.Messages({ + "DN_ChangeMethodSignature=Change method signature", + }) + public CompletableFuture processCommand(NbCodeLanguageClient client, String command, List arguments) { + try { + if (arguments.size() > 1) { + String uri = gson.fromJson(gson.toJson(arguments.get(0)), String.class); + QuickPickItem sourceItem = gson.fromJson(gson.toJson(arguments.get(1)), QuickPickItem.class); + ElementHandle handle = gson.fromJson(gson.toJson(sourceItem.getUserData()), ElementData.class).toHandle(); + FileObject file = Utils.fromUri(uri); + JavaSource js = JavaSource.forFileObject(file); + if (js != null) { + return CompletableFuture.supplyAsync(() -> { + try { + js.runUserActionTask(ci -> { + ci.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); + ExecutableElement method = (ExecutableElement) handle.resolve(ci); + if (method != null) { + Pages.showChangeMethodParametersUI(ci, client, file, handle, method); + } + }, true); + return null; + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + }, RequestProcessor.getDefault()); + } + } else { + throw new IllegalArgumentException(String.format("Illegal number of arguments received for command: %s", command)); + } + } catch (Exception ex) { + client.showMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); + } + return CompletableFuture.completedFuture(true); + } + + private static String defaultValue(String type) { + switch(type) { + case "boolean": + return "false"; + case "byte": + case "char": + case "double": + case "float": + case "int": + case "long": + case "short": + return "0"; + } + return "null"; + } + + @HTMLDialog(url = "ui/ChangeMethodParameters.html") + static HTMLDialog.OnSubmit showChangeMethodParametersUI( + CompilationController ci, + NbCodeLanguageClient client, + FileObject file, + ElementHandle handle, + ExecutableElement method + ) { + ParameterUI[] params = new ParameterUI[method.getParameters().size()]; + for (int i = 0; i < method.getParameters().size(); i++) { + VariableElement param = method.getParameters().get(i); + ChangeParametersRefactoring.ParameterInfo info = new ChangeParametersRefactoring.ParameterInfo(i, param.getSimpleName().toString(), Utilities.getTypeName(ci, param.asType(), true).toString(), null); + params[i] = new ParameterUI(info.getType(), info.getName()); + params[i].assignInfo(info); + } + Modifier mod; + if (method.getModifiers().contains(javax.lang.model.element.Modifier.PUBLIC)) { + mod = Modifier.PUBLIC; + } else if (method.getModifiers().contains(javax.lang.model.element.Modifier.PROTECTED)) { + mod = Modifier.PROTECTED; + } else if (method.getModifiers().contains(javax.lang.model.element.Modifier.PRIVATE)) { + mod = Modifier.PRIVATE; + } else { + mod = Modifier.PACKAGE_PRIVATE; + } + ChangeMethodParameterUI model = new ChangeMethodParameterUI(); + model.withName(method.getSimpleName().toString()) + .withReturnType(Utilities.getTypeName(ci, method.getReturnType(), true).toString()) + .withSelectedModifier(mod) + .withParameters(params) + .assignData(client, file, TreePathHandle.from(handle, ClasspathInfo.create(file))); + model.applyBindings(); + return (id) -> { + if ("accept".equals(id)) { + model.doRefactoring(); + } + return true; // return false, if validation fails + }; + } + + @Model(className = "ChangeMethodParameterUI", targetId = "", instance = true, builder = "with", properties = { + @Property(name = "selectedModifier", type = Modifier.class), + @Property(name = "name", type = String.class), + @Property(name = "returnType", type = String.class), + @Property(name = "parameters", type = ParameterUI.class, array = true) + }) + static final class MethodControl { + + private NbCodeLanguageClient client; + private FileObject file; + private TreePathHandle handle; + + @ModelOperation + void assignData(ChangeMethodParameterUI ui, NbCodeLanguageClient client, FileObject file, TreePathHandle handle) { + this.client = client; + this.file = file; + this.handle = handle; + } + + @ModelOperation + @Function + void doRefactoring(ChangeMethodParameterUI ui) { + try { + ChangeParametersRefactoring refactoring = new ChangeParametersRefactoring(handle); + String returnType = ui.getReturnType(); + refactoring.setReturnType(returnType.length() > 0 ? returnType : null); + List parameters = ui.getParameters(); + ChangeParametersRefactoring.ParameterInfo[] params = new ChangeParametersRefactoring.ParameterInfo[parameters.size()]; + for (int i = 0; i < parameters.size(); i++) { + ParameterUI parameter = parameters.get(i); + parameter.getInfo(i, (idx, info) -> { + if (info != null) { + params[idx] = new ChangeParametersRefactoring.ParameterInfo(info.getOriginalIndex(), parameter.getName(), parameter.getType(), null); + } else { + params[idx] = new ChangeParametersRefactoring.ParameterInfo(-1, parameter.getName(), parameter.getType(), defaultValue(parameter.getType())); + } + }); + } + refactoring.setParameterInfo(params); + refactoring.getContext().add(JavaRefactoringUtils.getClasspathInfoFor(file)); + client.applyEdit(new ApplyWorkspaceEditParams(perform(refactoring, "ChangeMethodParameters"))); + } catch (Exception ex) { + if (client == null) { + Exceptions.printStackTrace( + Exceptions.attachSeverity(ex, Level.SEVERE) + ); + } else { + client.showMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); + } + } + } + + @Function + void moveUpParameter(ChangeMethodParameterUI ui, ParameterUI data) { + final List arr = ui.getParameters(); + int index = arr.indexOf(data); + if (index > 0) { + ParameterUI other = arr.get(index - 1); + arr.set(index, other); + arr.set(index - 1, data); + } + } + + @Function + void moveDownParameter(ChangeMethodParameterUI ui, ParameterUI data) { + final List arr = ui.getParameters(); + int index = arr.indexOf(data); + if (index != -1 && index + 1 < arr.size()) { + ParameterUI other = arr.get(index + 1); + arr.set(index, other); + arr.set(index + 1, data); + } + } + + @Function + void addParameter(ChangeMethodParameterUI ui) { + ui.getParameters().add(new ParameterUI()); + } + + @Function + void removeParameter(ChangeMethodParameterUI ui, ParameterUI data) { + ui.getParameters().remove(data); + } + + @ComputedProperty + static List availableModifiers() { + return Arrays.asList(Modifier.values()); + } + + @ComputedProperty + static String preview( + Modifier selectedModifier, String returnType, String name, List parameters + ) { + StringBuilder sb = new StringBuilder(); + sb.append(selectedModifier != null ? selectedModifier.javaName : "").append(" ").append(returnType); + sb.append(" ").append(name).append("("); + String sep = ""; + for (ParameterUI p : parameters) { + sb.append(sep); + sb.append(p.getType()).append(" ").append(p.getName()); + sep = ", "; + } + sb.append(")"); + return sb.toString(); + } + } + + @Model(className = "ParameterUI", instance = true, properties = { + @Property(name = "type", type = String.class), + @Property(name = "name", type = String.class) + }) + static final class ParamControl { + private ChangeParametersRefactoring.ParameterInfo info; + + @ModelOperation + void assignInfo(ParameterUI model, ChangeParametersRefactoring.ParameterInfo info) { + this.info = info; + } + + @ModelOperation + void getInfo(ParameterUI model, int idx, BiConsumer consumer) { + consumer.accept(idx, info); + } + } + + public static enum Modifier { + PUBLIC("public"), PROTECTED("protected"), PACKAGE_PRIVATE("", "package private"), PRIVATE("private"); + + final String javaName; + final String humanName; + + Modifier(String javaName) { + this(javaName, null); + } + + Modifier(String javaName, String humanName) { + this.javaName = javaName; + this.humanName = humanName; + } + + @Override + public String toString() { + return humanName == null ? javaName : humanName; + } + } +} diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/CodeRefactoring.java similarity index 96% rename from java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeRefactoring.java rename to java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/CodeRefactoring.java index 01494f56b8e7..15545494df6d 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/CodeRefactoring.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.netbeans.modules.java.lsp.server.protocol; +package org.netbeans.modules.java.lsp.server.refactoring; import java.io.File; import java.net.URL; @@ -39,6 +39,7 @@ import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.netbeans.api.java.source.ModificationResult; import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.java.lsp.server.protocol.CodeActionsProvider; import org.netbeans.modules.refactoring.api.AbstractRefactoring; import org.netbeans.modules.refactoring.api.Problem; import org.netbeans.modules.refactoring.api.RefactoringSession; @@ -57,7 +58,7 @@ */ public abstract class CodeRefactoring extends CodeActionsProvider { - protected final WorkspaceEdit perform(AbstractRefactoring refactoring, String name) throws Exception { + protected static final WorkspaceEdit perform(AbstractRefactoring refactoring, String name) throws Exception { RefactoringSession session = RefactoringSession.create(name); Problem p = refactoring.checkParameters(); if (p != null && p.isFatal()) { diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ExtractSuperclassOrInterfaceRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ExtractSuperclassOrInterfaceRefactoring.java similarity index 96% rename from java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ExtractSuperclassOrInterfaceRefactoring.java rename to java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ExtractSuperclassOrInterfaceRefactoring.java index e1e09ec18d10..2bbf35187638 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ExtractSuperclassOrInterfaceRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ExtractSuperclassOrInterfaceRefactoring.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.netbeans.modules.java.lsp.server.protocol; +package org.netbeans.modules.java.lsp.server.refactoring; import com.google.gson.Gson; import com.sun.source.tree.ClassTree; @@ -54,6 +54,11 @@ import org.netbeans.api.java.source.TreePathHandle; import org.netbeans.api.java.source.TreeUtilities; import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.java.lsp.server.protocol.CodeActionsProvider; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient; +import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem; +import org.netbeans.modules.java.lsp.server.protocol.ShowInputBoxParams; +import org.netbeans.modules.java.lsp.server.protocol.ShowQuickPickParams; import org.netbeans.modules.parsing.api.ResultIterator; import org.netbeans.modules.refactoring.api.AbstractRefactoring; import org.netbeans.modules.refactoring.java.api.ExtractInterfaceRefactoring; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/MoveRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/MoveRefactoring.java similarity index 97% rename from java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/MoveRefactoring.java rename to java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/MoveRefactoring.java index 51475e64e5f2..5554da0d0828 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/MoveRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/MoveRefactoring.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.netbeans.modules.java.lsp.server.protocol; +package org.netbeans.modules.java.lsp.server.refactoring; import com.google.gson.Gson; import com.sun.source.tree.ClassTree; @@ -55,6 +55,10 @@ import org.netbeans.api.project.ProjectUtils; import org.netbeans.api.project.SourceGroup; import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.java.lsp.server.protocol.CodeActionsProvider; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient; +import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem; +import org.netbeans.modules.java.lsp.server.protocol.ShowQuickPickParams; import org.netbeans.modules.parsing.api.ResultIterator; import org.netbeans.modules.refactoring.java.api.JavaMoveMembersProperties; import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/PullUpRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PullUpRefactoring.java similarity index 97% rename from java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/PullUpRefactoring.java rename to java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PullUpRefactoring.java index dea79b207b99..86ea3e774c58 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/PullUpRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PullUpRefactoring.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.netbeans.modules.java.lsp.server.protocol; +package org.netbeans.modules.java.lsp.server.refactoring; import com.google.gson.Gson; import com.sun.source.tree.ClassTree; @@ -55,6 +55,10 @@ import org.netbeans.api.java.source.TreePathHandle; import org.netbeans.api.java.source.TreeUtilities; import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.java.lsp.server.protocol.CodeActionsProvider; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient; +import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem; +import org.netbeans.modules.java.lsp.server.protocol.ShowQuickPickParams; import org.netbeans.modules.parsing.api.ResultIterator; import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; import org.netbeans.modules.refactoring.java.api.MemberInfo; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/PushDownRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PushDownRefactoring.java similarity index 96% rename from java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/PushDownRefactoring.java rename to java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PushDownRefactoring.java index 65cc6fde5fff..8291d658a945 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/PushDownRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PushDownRefactoring.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.netbeans.modules.java.lsp.server.protocol; +package org.netbeans.modules.java.lsp.server.refactoring; import com.google.gson.Gson; import com.sun.source.tree.ClassTree; @@ -51,6 +51,10 @@ import org.netbeans.api.java.source.TreePathHandle; import org.netbeans.api.java.source.TreeUtilities; import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.java.lsp.server.protocol.CodeActionsProvider; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient; +import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem; +import org.netbeans.modules.java.lsp.server.protocol.ShowQuickPickParams; import org.netbeans.modules.parsing.api.ResultIterator; import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; import org.netbeans.modules.refactoring.java.api.MemberInfo; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/ChangeMethodParameters.html b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/ChangeMethodParameters.html new file mode 100644 index 000000000000..57d4508acee0 --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/ChangeMethodParameters.html @@ -0,0 +1,79 @@ + + + + + + + + + + + Refactor: Change Method Parameters... + + + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + + +
+
+
+
+ + + + + +
+
+
+ +
+
+ +
+
+

+
+
+ + +
+ + diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/codicon.css b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/codicon.css new file mode 100644 index 000000000000..c2771b5e881e --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/codicon.css @@ -0,0 +1,485 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +@font-face { + font-family: "codicon"; + src: url("./codicon.ttf?9642aa1d48ab4e55aa1bf3f0b8678aa1") format("truetype"); +} + +.codicon[class*='codicon-'] { + font: normal normal normal 16px/1 codicon; + display: inline-block; + text-decoration: none; + text-rendering: auto; + text-align: center; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + user-select: none; + -webkit-user-select: none; + -ms-user-select: none; +} + + +.codicon-add:before { content: "\ea60" } +.codicon-plus:before { content: "\ea60" } +.codicon-gist-new:before { content: "\ea60" } +.codicon-repo-create:before { content: "\ea60" } +.codicon-lightbulb:before { content: "\ea61" } +.codicon-light-bulb:before { content: "\ea61" } +.codicon-repo:before { content: "\ea62" } +.codicon-repo-delete:before { content: "\ea62" } +.codicon-gist-fork:before { content: "\ea63" } +.codicon-repo-forked:before { content: "\ea63" } +.codicon-git-pull-request:before { content: "\ea64" } +.codicon-git-pull-request-abandoned:before { content: "\ea64" } +.codicon-record-keys:before { content: "\ea65" } +.codicon-keyboard:before { content: "\ea65" } +.codicon-tag:before { content: "\ea66" } +.codicon-tag-add:before { content: "\ea66" } +.codicon-tag-remove:before { content: "\ea66" } +.codicon-person:before { content: "\ea67" } +.codicon-person-follow:before { content: "\ea67" } +.codicon-person-outline:before { content: "\ea67" } +.codicon-person-filled:before { content: "\ea67" } +.codicon-git-branch:before { content: "\ea68" } +.codicon-git-branch-create:before { content: "\ea68" } +.codicon-git-branch-delete:before { content: "\ea68" } +.codicon-source-control:before { content: "\ea68" } +.codicon-mirror:before { content: "\ea69" } +.codicon-mirror-public:before { content: "\ea69" } +.codicon-star:before { content: "\ea6a" } +.codicon-star-add:before { content: "\ea6a" } +.codicon-star-delete:before { content: "\ea6a" } +.codicon-star-empty:before { content: "\ea6a" } +.codicon-comment:before { content: "\ea6b" } +.codicon-comment-add:before { content: "\ea6b" } +.codicon-alert:before { content: "\ea6c" } +.codicon-warning:before { content: "\ea6c" } +.codicon-search:before { content: "\ea6d" } +.codicon-search-save:before { content: "\ea6d" } +.codicon-log-out:before { content: "\ea6e" } +.codicon-sign-out:before { content: "\ea6e" } +.codicon-log-in:before { content: "\ea6f" } +.codicon-sign-in:before { content: "\ea6f" } +.codicon-eye:before { content: "\ea70" } +.codicon-eye-unwatch:before { content: "\ea70" } +.codicon-eye-watch:before { content: "\ea70" } +.codicon-circle-filled:before { content: "\ea71" } +.codicon-primitive-dot:before { content: "\ea71" } +.codicon-close-dirty:before { content: "\ea71" } +.codicon-debug-breakpoint:before { content: "\ea71" } +.codicon-debug-breakpoint-disabled:before { content: "\ea71" } +.codicon-debug-hint:before { content: "\ea71" } +.codicon-primitive-square:before { content: "\ea72" } +.codicon-edit:before { content: "\ea73" } +.codicon-pencil:before { content: "\ea73" } +.codicon-info:before { content: "\ea74" } +.codicon-issue-opened:before { content: "\ea74" } +.codicon-gist-private:before { content: "\ea75" } +.codicon-git-fork-private:before { content: "\ea75" } +.codicon-lock:before { content: "\ea75" } +.codicon-mirror-private:before { content: "\ea75" } +.codicon-close:before { content: "\ea76" } +.codicon-remove-close:before { content: "\ea76" } +.codicon-x:before { content: "\ea76" } +.codicon-repo-sync:before { content: "\ea77" } +.codicon-sync:before { content: "\ea77" } +.codicon-clone:before { content: "\ea78" } +.codicon-desktop-download:before { content: "\ea78" } +.codicon-beaker:before { content: "\ea79" } +.codicon-microscope:before { content: "\ea79" } +.codicon-vm:before { content: "\ea7a" } +.codicon-device-desktop:before { content: "\ea7a" } +.codicon-file:before { content: "\ea7b" } +.codicon-file-text:before { content: "\ea7b" } +.codicon-more:before { content: "\ea7c" } +.codicon-ellipsis:before { content: "\ea7c" } +.codicon-kebab-horizontal:before { content: "\ea7c" } +.codicon-mail-reply:before { content: "\ea7d" } +.codicon-reply:before { content: "\ea7d" } +.codicon-organization:before { content: "\ea7e" } +.codicon-organization-filled:before { content: "\ea7e" } +.codicon-organization-outline:before { content: "\ea7e" } +.codicon-new-file:before { content: "\ea7f" } +.codicon-file-add:before { content: "\ea7f" } +.codicon-new-folder:before { content: "\ea80" } +.codicon-file-directory-create:before { content: "\ea80" } +.codicon-trash:before { content: "\ea81" } +.codicon-trashcan:before { content: "\ea81" } +.codicon-history:before { content: "\ea82" } +.codicon-clock:before { content: "\ea82" } +.codicon-folder:before { content: "\ea83" } +.codicon-file-directory:before { content: "\ea83" } +.codicon-symbol-folder:before { content: "\ea83" } +.codicon-logo-github:before { content: "\ea84" } +.codicon-mark-github:before { content: "\ea84" } +.codicon-github:before { content: "\ea84" } +.codicon-terminal:before { content: "\ea85" } +.codicon-console:before { content: "\ea85" } +.codicon-repl:before { content: "\ea85" } +.codicon-zap:before { content: "\ea86" } +.codicon-symbol-event:before { content: "\ea86" } +.codicon-error:before { content: "\ea87" } +.codicon-stop:before { content: "\ea87" } +.codicon-variable:before { content: "\ea88" } +.codicon-symbol-variable:before { content: "\ea88" } +.codicon-array:before { content: "\ea8a" } +.codicon-symbol-array:before { content: "\ea8a" } +.codicon-symbol-module:before { content: "\ea8b" } +.codicon-symbol-package:before { content: "\ea8b" } +.codicon-symbol-namespace:before { content: "\ea8b" } +.codicon-symbol-object:before { content: "\ea8b" } +.codicon-symbol-method:before { content: "\ea8c" } +.codicon-symbol-function:before { content: "\ea8c" } +.codicon-symbol-constructor:before { content: "\ea8c" } +.codicon-symbol-boolean:before { content: "\ea8f" } +.codicon-symbol-null:before { content: "\ea8f" } +.codicon-symbol-numeric:before { content: "\ea90" } +.codicon-symbol-number:before { content: "\ea90" } +.codicon-symbol-structure:before { content: "\ea91" } +.codicon-symbol-struct:before { content: "\ea91" } +.codicon-symbol-parameter:before { content: "\ea92" } +.codicon-symbol-type-parameter:before { content: "\ea92" } +.codicon-symbol-key:before { content: "\ea93" } +.codicon-symbol-text:before { content: "\ea93" } +.codicon-symbol-reference:before { content: "\ea94" } +.codicon-go-to-file:before { content: "\ea94" } +.codicon-symbol-enum:before { content: "\ea95" } +.codicon-symbol-value:before { content: "\ea95" } +.codicon-symbol-ruler:before { content: "\ea96" } +.codicon-symbol-unit:before { content: "\ea96" } +.codicon-activate-breakpoints:before { content: "\ea97" } +.codicon-archive:before { content: "\ea98" } +.codicon-arrow-both:before { content: "\ea99" } +.codicon-arrow-down:before { content: "\ea9a" } +.codicon-arrow-left:before { content: "\ea9b" } +.codicon-arrow-right:before { content: "\ea9c" } +.codicon-arrow-small-down:before { content: "\ea9d" } +.codicon-arrow-small-left:before { content: "\ea9e" } +.codicon-arrow-small-right:before { content: "\ea9f" } +.codicon-arrow-small-up:before { content: "\eaa0" } +.codicon-arrow-up:before { content: "\eaa1" } +.codicon-bell:before { content: "\eaa2" } +.codicon-bold:before { content: "\eaa3" } +.codicon-book:before { content: "\eaa4" } +.codicon-bookmark:before { content: "\eaa5" } +.codicon-debug-breakpoint-conditional-unverified:before { content: "\eaa6" } +.codicon-debug-breakpoint-conditional:before { content: "\eaa7" } +.codicon-debug-breakpoint-conditional-disabled:before { content: "\eaa7" } +.codicon-debug-breakpoint-data-unverified:before { content: "\eaa8" } +.codicon-debug-breakpoint-data:before { content: "\eaa9" } +.codicon-debug-breakpoint-data-disabled:before { content: "\eaa9" } +.codicon-debug-breakpoint-log-unverified:before { content: "\eaaa" } +.codicon-debug-breakpoint-log:before { content: "\eaab" } +.codicon-debug-breakpoint-log-disabled:before { content: "\eaab" } +.codicon-briefcase:before { content: "\eaac" } +.codicon-broadcast:before { content: "\eaad" } +.codicon-browser:before { content: "\eaae" } +.codicon-bug:before { content: "\eaaf" } +.codicon-calendar:before { content: "\eab0" } +.codicon-case-sensitive:before { content: "\eab1" } +.codicon-check:before { content: "\eab2" } +.codicon-checklist:before { content: "\eab3" } +.codicon-chevron-down:before { content: "\eab4" } +.codicon-chevron-left:before { content: "\eab5" } +.codicon-chevron-right:before { content: "\eab6" } +.codicon-chevron-up:before { content: "\eab7" } +.codicon-chrome-close:before { content: "\eab8" } +.codicon-chrome-maximize:before { content: "\eab9" } +.codicon-chrome-minimize:before { content: "\eaba" } +.codicon-chrome-restore:before { content: "\eabb" } +.codicon-circle-outline:before { content: "\eabc" } +.codicon-debug-breakpoint-unverified:before { content: "\eabc" } +.codicon-circle-slash:before { content: "\eabd" } +.codicon-circuit-board:before { content: "\eabe" } +.codicon-clear-all:before { content: "\eabf" } +.codicon-clippy:before { content: "\eac0" } +.codicon-close-all:before { content: "\eac1" } +.codicon-cloud-download:before { content: "\eac2" } +.codicon-cloud-upload:before { content: "\eac3" } +.codicon-code:before { content: "\eac4" } +.codicon-collapse-all:before { content: "\eac5" } +.codicon-color-mode:before { content: "\eac6" } +.codicon-comment-discussion:before { content: "\eac7" } +.codicon-credit-card:before { content: "\eac9" } +.codicon-dash:before { content: "\eacc" } +.codicon-dashboard:before { content: "\eacd" } +.codicon-database:before { content: "\eace" } +.codicon-debug-continue:before { content: "\eacf" } +.codicon-debug-disconnect:before { content: "\ead0" } +.codicon-debug-pause:before { content: "\ead1" } +.codicon-debug-restart:before { content: "\ead2" } +.codicon-debug-start:before { content: "\ead3" } +.codicon-debug-step-into:before { content: "\ead4" } +.codicon-debug-step-out:before { content: "\ead5" } +.codicon-debug-step-over:before { content: "\ead6" } +.codicon-debug-stop:before { content: "\ead7" } +.codicon-debug:before { content: "\ead8" } +.codicon-device-camera-video:before { content: "\ead9" } +.codicon-device-camera:before { content: "\eada" } +.codicon-device-mobile:before { content: "\eadb" } +.codicon-diff-added:before { content: "\eadc" } +.codicon-diff-ignored:before { content: "\eadd" } +.codicon-diff-modified:before { content: "\eade" } +.codicon-diff-removed:before { content: "\eadf" } +.codicon-diff-renamed:before { content: "\eae0" } +.codicon-diff:before { content: "\eae1" } +.codicon-discard:before { content: "\eae2" } +.codicon-editor-layout:before { content: "\eae3" } +.codicon-empty-window:before { content: "\eae4" } +.codicon-exclude:before { content: "\eae5" } +.codicon-extensions:before { content: "\eae6" } +.codicon-eye-closed:before { content: "\eae7" } +.codicon-file-binary:before { content: "\eae8" } +.codicon-file-code:before { content: "\eae9" } +.codicon-file-media:before { content: "\eaea" } +.codicon-file-pdf:before { content: "\eaeb" } +.codicon-file-submodule:before { content: "\eaec" } +.codicon-file-symlink-directory:before { content: "\eaed" } +.codicon-file-symlink-file:before { content: "\eaee" } +.codicon-file-zip:before { content: "\eaef" } +.codicon-files:before { content: "\eaf0" } +.codicon-filter:before { content: "\eaf1" } +.codicon-flame:before { content: "\eaf2" } +.codicon-fold-down:before { content: "\eaf3" } +.codicon-fold-up:before { content: "\eaf4" } +.codicon-fold:before { content: "\eaf5" } +.codicon-folder-active:before { content: "\eaf6" } +.codicon-folder-opened:before { content: "\eaf7" } +.codicon-gear:before { content: "\eaf8" } +.codicon-gift:before { content: "\eaf9" } +.codicon-gist-secret:before { content: "\eafa" } +.codicon-gist:before { content: "\eafb" } +.codicon-git-commit:before { content: "\eafc" } +.codicon-git-compare:before { content: "\eafd" } +.codicon-compare-changes:before { content: "\eafd" } +.codicon-git-merge:before { content: "\eafe" } +.codicon-github-action:before { content: "\eaff" } +.codicon-github-alt:before { content: "\eb00" } +.codicon-globe:before { content: "\eb01" } +.codicon-grabber:before { content: "\eb02" } +.codicon-graph:before { content: "\eb03" } +.codicon-gripper:before { content: "\eb04" } +.codicon-heart:before { content: "\eb05" } +.codicon-home:before { content: "\eb06" } +.codicon-horizontal-rule:before { content: "\eb07" } +.codicon-hubot:before { content: "\eb08" } +.codicon-inbox:before { content: "\eb09" } +.codicon-issue-reopened:before { content: "\eb0b" } +.codicon-issues:before { content: "\eb0c" } +.codicon-italic:before { content: "\eb0d" } +.codicon-jersey:before { content: "\eb0e" } +.codicon-json:before { content: "\eb0f" } +.codicon-kebab-vertical:before { content: "\eb10" } +.codicon-key:before { content: "\eb11" } +.codicon-law:before { content: "\eb12" } +.codicon-lightbulb-autofix:before { content: "\eb13" } +.codicon-link-external:before { content: "\eb14" } +.codicon-link:before { content: "\eb15" } +.codicon-list-ordered:before { content: "\eb16" } +.codicon-list-unordered:before { content: "\eb17" } +.codicon-live-share:before { content: "\eb18" } +.codicon-loading:before { content: "\eb19" } +.codicon-location:before { content: "\eb1a" } +.codicon-mail-read:before { content: "\eb1b" } +.codicon-mail:before { content: "\eb1c" } +.codicon-markdown:before { content: "\eb1d" } +.codicon-megaphone:before { content: "\eb1e" } +.codicon-mention:before { content: "\eb1f" } +.codicon-milestone:before { content: "\eb20" } +.codicon-mortar-board:before { content: "\eb21" } +.codicon-move:before { content: "\eb22" } +.codicon-multiple-windows:before { content: "\eb23" } +.codicon-mute:before { content: "\eb24" } +.codicon-no-newline:before { content: "\eb25" } +.codicon-note:before { content: "\eb26" } +.codicon-octoface:before { content: "\eb27" } +.codicon-open-preview:before { content: "\eb28" } +.codicon-package:before { content: "\eb29" } +.codicon-paintcan:before { content: "\eb2a" } +.codicon-pin:before { content: "\eb2b" } +.codicon-play:before { content: "\eb2c" } +.codicon-run:before { content: "\eb2c" } +.codicon-plug:before { content: "\eb2d" } +.codicon-preserve-case:before { content: "\eb2e" } +.codicon-preview:before { content: "\eb2f" } +.codicon-project:before { content: "\eb30" } +.codicon-pulse:before { content: "\eb31" } +.codicon-question:before { content: "\eb32" } +.codicon-quote:before { content: "\eb33" } +.codicon-radio-tower:before { content: "\eb34" } +.codicon-reactions:before { content: "\eb35" } +.codicon-references:before { content: "\eb36" } +.codicon-refresh:before { content: "\eb37" } +.codicon-regex:before { content: "\eb38" } +.codicon-remote-explorer:before { content: "\eb39" } +.codicon-remote:before { content: "\eb3a" } +.codicon-remove:before { content: "\eb3b" } +.codicon-replace-all:before { content: "\eb3c" } +.codicon-replace:before { content: "\eb3d" } +.codicon-repo-clone:before { content: "\eb3e" } +.codicon-repo-force-push:before { content: "\eb3f" } +.codicon-repo-pull:before { content: "\eb40" } +.codicon-repo-push:before { content: "\eb41" } +.codicon-report:before { content: "\eb42" } +.codicon-request-changes:before { content: "\eb43" } +.codicon-rocket:before { content: "\eb44" } +.codicon-root-folder-opened:before { content: "\eb45" } +.codicon-root-folder:before { content: "\eb46" } +.codicon-rss:before { content: "\eb47" } +.codicon-ruby:before { content: "\eb48" } +.codicon-save-all:before { content: "\eb49" } +.codicon-save-as:before { content: "\eb4a" } +.codicon-save:before { content: "\eb4b" } +.codicon-screen-full:before { content: "\eb4c" } +.codicon-screen-normal:before { content: "\eb4d" } +.codicon-search-stop:before { content: "\eb4e" } +.codicon-server:before { content: "\eb50" } +.codicon-settings-gear:before { content: "\eb51" } +.codicon-settings:before { content: "\eb52" } +.codicon-shield:before { content: "\eb53" } +.codicon-smiley:before { content: "\eb54" } +.codicon-sort-precedence:before { content: "\eb55" } +.codicon-split-horizontal:before { content: "\eb56" } +.codicon-split-vertical:before { content: "\eb57" } +.codicon-squirrel:before { content: "\eb58" } +.codicon-star-full:before { content: "\eb59" } +.codicon-star-half:before { content: "\eb5a" } +.codicon-symbol-class:before { content: "\eb5b" } +.codicon-symbol-color:before { content: "\eb5c" } +.codicon-symbol-constant:before { content: "\eb5d" } +.codicon-symbol-enum-member:before { content: "\eb5e" } +.codicon-symbol-field:before { content: "\eb5f" } +.codicon-symbol-file:before { content: "\eb60" } +.codicon-symbol-interface:before { content: "\eb61" } +.codicon-symbol-keyword:before { content: "\eb62" } +.codicon-symbol-misc:before { content: "\eb63" } +.codicon-symbol-operator:before { content: "\eb64" } +.codicon-symbol-property:before { content: "\eb65" } +.codicon-wrench:before { content: "\eb65" } +.codicon-wrench-subaction:before { content: "\eb65" } +.codicon-symbol-snippet:before { content: "\eb66" } +.codicon-tasklist:before { content: "\eb67" } +.codicon-telescope:before { content: "\eb68" } +.codicon-text-size:before { content: "\eb69" } +.codicon-three-bars:before { content: "\eb6a" } +.codicon-thumbsdown:before { content: "\eb6b" } +.codicon-thumbsup:before { content: "\eb6c" } +.codicon-tools:before { content: "\eb6d" } +.codicon-triangle-down:before { content: "\eb6e" } +.codicon-triangle-left:before { content: "\eb6f" } +.codicon-triangle-right:before { content: "\eb70" } +.codicon-triangle-up:before { content: "\eb71" } +.codicon-twitter:before { content: "\eb72" } +.codicon-unfold:before { content: "\eb73" } +.codicon-unlock:before { content: "\eb74" } +.codicon-unmute:before { content: "\eb75" } +.codicon-unverified:before { content: "\eb76" } +.codicon-verified:before { content: "\eb77" } +.codicon-versions:before { content: "\eb78" } +.codicon-vm-active:before { content: "\eb79" } +.codicon-vm-outline:before { content: "\eb7a" } +.codicon-vm-running:before { content: "\eb7b" } +.codicon-watch:before { content: "\eb7c" } +.codicon-whitespace:before { content: "\eb7d" } +.codicon-whole-word:before { content: "\eb7e" } +.codicon-window:before { content: "\eb7f" } +.codicon-word-wrap:before { content: "\eb80" } +.codicon-zoom-in:before { content: "\eb81" } +.codicon-zoom-out:before { content: "\eb82" } +.codicon-list-filter:before { content: "\eb83" } +.codicon-list-flat:before { content: "\eb84" } +.codicon-list-selection:before { content: "\eb85" } +.codicon-selection:before { content: "\eb85" } +.codicon-list-tree:before { content: "\eb86" } +.codicon-debug-breakpoint-function-unverified:before { content: "\eb87" } +.codicon-debug-breakpoint-function:before { content: "\eb88" } +.codicon-debug-breakpoint-function-disabled:before { content: "\eb88" } +.codicon-debug-stackframe-active:before { content: "\eb89" } +.codicon-debug-stackframe-dot:before { content: "\eb8a" } +.codicon-debug-stackframe:before { content: "\eb8b" } +.codicon-debug-stackframe-focused:before { content: "\eb8b" } +.codicon-debug-breakpoint-unsupported:before { content: "\eb8c" } +.codicon-symbol-string:before { content: "\eb8d" } +.codicon-debug-reverse-continue:before { content: "\eb8e" } +.codicon-debug-step-back:before { content: "\eb8f" } +.codicon-debug-restart-frame:before { content: "\eb90" } +.codicon-debug-alt:before { content: "\eb91" } +.codicon-call-incoming:before { content: "\eb92" } +.codicon-call-outgoing:before { content: "\eb93" } +.codicon-menu:before { content: "\eb94" } +.codicon-expand-all:before { content: "\eb95" } +.codicon-feedback:before { content: "\eb96" } +.codicon-group-by-ref-type:before { content: "\eb97" } +.codicon-ungroup-by-ref-type:before { content: "\eb98" } +.codicon-account:before { content: "\eb99" } +.codicon-bell-dot:before { content: "\eb9a" } +.codicon-debug-console:before { content: "\eb9b" } +.codicon-library:before { content: "\eb9c" } +.codicon-output:before { content: "\eb9d" } +.codicon-run-all:before { content: "\eb9e" } +.codicon-sync-ignored:before { content: "\eb9f" } +.codicon-pinned:before { content: "\eba0" } +.codicon-github-inverted:before { content: "\eba1" } +.codicon-server-process:before { content: "\eba2" } +.codicon-server-environment:before { content: "\eba3" } +.codicon-pass:before { content: "\eba4" } +.codicon-issue-closed:before { content: "\eba4" } +.codicon-stop-circle:before { content: "\eba5" } +.codicon-play-circle:before { content: "\eba6" } +.codicon-record:before { content: "\eba7" } +.codicon-debug-alt-small:before { content: "\eba8" } +.codicon-vm-connect:before { content: "\eba9" } +.codicon-cloud:before { content: "\ebaa" } +.codicon-merge:before { content: "\ebab" } +.codicon-export:before { content: "\ebac" } +.codicon-graph-left:before { content: "\ebad" } +.codicon-magnet:before { content: "\ebae" } +.codicon-notebook:before { content: "\ebaf" } +.codicon-redo:before { content: "\ebb0" } +.codicon-check-all:before { content: "\ebb1" } +.codicon-pinned-dirty:before { content: "\ebb2" } +.codicon-pass-filled:before { content: "\ebb3" } +.codicon-circle-large-filled:before { content: "\ebb4" } +.codicon-circle-large-outline:before { content: "\ebb5" } +.codicon-combine:before { content: "\ebb6" } +.codicon-gather:before { content: "\ebb6" } +.codicon-table:before { content: "\ebb7" } +.codicon-variable-group:before { content: "\ebb8" } +.codicon-type-hierarchy:before { content: "\ebb9" } +.codicon-type-hierarchy-sub:before { content: "\ebba" } +.codicon-type-hierarchy-super:before { content: "\ebbb" } +.codicon-git-pull-request-create:before { content: "\ebbc" } +.codicon-run-above:before { content: "\ebbd" } +.codicon-run-below:before { content: "\ebbe" } +.codicon-notebook-template:before { content: "\ebbf" } +.codicon-debug-rerun:before { content: "\ebc0" } +.codicon-workspace-trusted:before { content: "\ebc1" } +.codicon-workspace-untrusted:before { content: "\ebc2" } +.codicon-workspace-unknown:before { content: "\ebc3" } +.codicon-terminal-cmd:before { content: "\ebc4" } +.codicon-terminal-debian:before { content: "\ebc5" } +.codicon-terminal-linux:before { content: "\ebc6" } +.codicon-terminal-powershell:before { content: "\ebc7" } +.codicon-terminal-tmux:before { content: "\ebc8" } +.codicon-terminal-ubuntu:before { content: "\ebc9" } +.codicon-terminal-bash:before { content: "\ebca" } +.codicon-arrow-swap:before { content: "\ebcb" } +.codicon-copy:before { content: "\ebcc" } +.codicon-person-add:before { content: "\ebcd" } +.codicon-filter-filled:before { content: "\ebce" } +.codicon-wand:before { content: "\ebcf" } +.codicon-debug-line-by-line:before { content: "\ebd0" } +.codicon-inspect:before { content: "\ebd1" } +.codicon-layers:before { content: "\ebd2" } +.codicon-layers-dot:before { content: "\ebd3" } +.codicon-layers-active:before { content: "\ebd4" } +.codicon-compass:before { content: "\ebd5" } +.codicon-compass-dot:before { content: "\ebd6" } +.codicon-compass-active:before { content: "\ebd7" } +.codicon-azure:before { content: "\ebd8" } +.codicon-issue-draft:before { content: "\ebd9" } +.codicon-git-pull-request-closed:before { content: "\ebda" } +.codicon-git-pull-request-draft:before { content: "\ebdb" } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/codicon.ttf b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/codicon.ttf new file mode 100644 index 000000000000..8d844c927960 Binary files /dev/null and b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/codicon.ttf differ diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/refactoring.css b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/refactoring.css new file mode 100644 index 000000000000..98c2534bb190 --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ui/refactoring.css @@ -0,0 +1,169 @@ + + +html, body { + height: 100%; + padding: 0; + margin: 0; +} +body { + display: flex; + flex-direction: column; + overflow-x: scroll; +} +input, select { + width: 100%; + font-family: var(--vscode-editor-font-family) !important; + border: var(--vscode-input-border); + margin-right: 6px !important; + background: var(--vscode-input-background); + color: var(--vscode-input-foreground); + box-sizing: border-box; +} +input:focus, select:focus { + outline-color: var(--vscode-focusBorder); +} +input { + padding: 5px 4px !important; +} +select { + padding: 4px !important; +} +button { + cursor: pointer; +} +label { + display: block; + margin-bottom: 5px; + user-select: none; +} +.vscode-font { + font-family: var(--vscode-font-family); + font-size: var(--vscode-font-size); + text-decoration: none; +} +.button-text { + margin-left: 5px; + vertical-align: text-top; +} +.regular-button { + border: none; + padding: 4px 10px 4px 10px; + margin: 5px; + color: var(--vscode-button-foreground); + background-color: var(--vscode-button-background); +} +.regular-button:hover, .regular-button:focus { + background: var(--vscode-button-hoverBackground); +} +.regular-button:focus { + outline: 1px solid var(--vscode-button-hoverBackground); + outline-offset: 2px; +} +.silent-button { + border: none; + padding: 4px 10px 4px 10px; + margin: 5px; + color: var(--vscode-input-foreground); + background-color: var(--vscode-list-hoverBackground); +} +.silent-button:hover { + color: var(--vscode-button-foreground); + background-color: var(--vscode-button-hoverBackground); +} +.silent-button:focus { + color: var(--vscode-button-foreground); + background-color: var(--vscode-button-hoverBackground); + outline: 1px solid var(--vscode-button-hoverBackground); + outline-offset: 2px; +} +.action-button { + border: none; + border-radius: 4px; + padding: 2px; + margin: 3px 0px; + color: var(--vscode-input-foreground); + background-color: transparent; +} +.action-button:hover { + background-color: var(--vscode-list-inactiveSelectionBackground); +} +.action-button:focus, .action-button:hover:focus { + color: var(--vscode-button-foreground); + background-color: var(--vscode-button-hoverBackground); + outline: none; +} +.params-caption { + margin-bottom: 8px; +} +.filler { + width: 53px; +} +.preview-panel { + margin: 0px; + padding: 10px; + font-family: var(--vscode-editor-font-family) !important; + background-color: var(--vscode-sideBar-background); + cursor: default; +} +.section { + padding: 20px 20px 0px; +} +.section1 { + padding: 0px 10px; +} +.section2 { + padding: 0px 10px; + margin-top: -6px; +} +.vdivider { + margin-bottom: 20px; +} +.hdivider { + margin-left: 6px; +} +.row { + padding: 3px 10px; +} +.row:hover { + background-color: var(--vscode-list-hoverBackground); +} +.row:focus-within { + background-color: var(--vscode-tab-unfocusedInactiveModifiedBorder); +} +.flex { + display: flex; +} +.flex-grow { + flex-grow: 1; + display: block; +} +.flex-vscrollable { + overflow-x: hidden; + overflow-y: auto; +} +.align-right { + margin-left: auto; +} +.add-param { + padding: 0px 15px; + padding-top: 2px; +} \ No newline at end of file diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java index 02e05b249bb7..a1e608787bc4 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractLspHtmlViewer.java @@ -24,13 +24,21 @@ import org.eclipse.lsp4j.MessageType; import org.netbeans.modules.java.lsp.server.htmlui.Browser; import org.netbeans.modules.java.lsp.server.htmlui.Browser.Config; +import org.netbeans.modules.java.lsp.server.htmlui.Buttons; +import static org.netbeans.modules.java.lsp.server.htmlui.Buttons.buttonName0; +import static org.netbeans.modules.java.lsp.server.htmlui.Buttons.buttonText0; import org.netbeans.modules.java.lsp.server.protocol.HtmlPageParams; import org.netbeans.modules.java.lsp.server.protocol.NbCodeClientCapabilities; import org.openide.util.Exceptions; import org.netbeans.spi.htmlui.HTMLViewerSpi; -import org.openide.awt.StatusDisplayer; import org.openide.util.NbBundle; +/** + * Implementation of {@link HTMLViewerSpi} that uses window/showHtmlPage + * extended message of language server protocol to display a page. + * + * @since 1.14 + */ public class AbstractLspHtmlViewer implements HTMLViewerSpi { private final Config initial = new Config(); @@ -44,51 +52,12 @@ public View newView(Context context) { return view; } - @JavaScriptBody(args = {}, body = "\n" - + "const vscode = acquireVsCodeApi();\n" // this method can be called only once per WebView existance - + "window.close = function() {\n" - + " vscode.postMessage({\n" - + " command: 'dispose',\n" - + " });\n" - + "};\n" - ) - private static native void registerCloseWindow(); @Override public Object createButton(View view, String id) { - return createButton0(id, view.ctx); + return Buttons.createButton0(id, view.ctx); } - @JavaScriptBody(args = { "id", "callback" }, javacall = true, body = "\n" - + "var first = false;\n" - + "var footer = document.getElementById('dialog-buttons');\n" - + "if (!footer) {\n" - + " first = true\n" - + " footer = document.createElement('div');\n" - + " footer.id = 'dialog-buttons';\n" - + " footer.classList.add('flex');\n" - + " footer.classList.add('section');\n" - + " document.body.appendChild(footer);\n" - + "}\n" - + "var button = document.createElement('button');\n" - + "button.id = id;\n" - + "button.onclick = function() {;\n" - + " @org.netbeans.modules.java.lsp.server.ui.AbstractLspHtmlViewer::clickButton0(Ljava/lang/String;Ljava/lang/Object;)(id, callback);\n" - + "};\n" - + "button.classList.add('regular-button');\n" - + "button.classList.add('vscode-font');\n" - + "if (first) {\n" - + " button.classList.add('align-right');\n" - + "}\n" - + "footer.appendChild(button);\n" - + "return button;\n" - ) - native static Object createButton0(String id, Context callback); - - static void clickButton0(String id, Object callback) { - Context ctx = (Context) callback; - ctx.onSubmit(id); - } @Override public C component(View view, Class type) { @@ -111,7 +80,7 @@ public void setText(View view, Object b, String text) { @Override public void setEnabled(View view, Object b, boolean enabled) { - buttonDisabled0(b, !enabled); + Buttons.buttonDisabled0(b, !enabled); } @Override @@ -119,17 +88,11 @@ public void runLater(View view, Runnable r) { r.run(); } - @JavaScriptBody(args = { "b" }, body = "return b.id;") - native static String buttonName0(Object b); - - @JavaScriptBody(args = { "b", "text" }, body = "b.innerHTML = text;") - native static void buttonText0(Object b, String text); - - @JavaScriptBody(args = { "b", "disabled" }, body = "return b.disabled = disabled;") - native static String buttonDisabled0(Object b, boolean disabled); - - final class View { - private final Context ctx; + /** View element used by {@link AbstractLspHtmlViewer}. + * @since 1.14 + */ + protected final class View { + final Context ctx; private final UIContext ui; private Browser presenter; @@ -189,7 +152,7 @@ private void load() { }); presenter = new Browser(c); presenter.displayPage(pageUrl, () -> { - registerCloseWindow(); + Buttons.registerCloseWindow(); try { ctx.onPageLoad(); } catch (Exception ex) { diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/TestCodeLanguageClient.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/TestCodeLanguageClient.java index 7b1745f7214b..607f9f63e9fe 100644 --- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/TestCodeLanguageClient.java +++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/TestCodeLanguageClient.java @@ -18,12 +18,19 @@ */ package org.netbeans.modules.java.lsp.server; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import org.eclipse.lsp4j.ApplyWorkspaceEditParams; +import org.eclipse.lsp4j.ApplyWorkspaceEditResponse; +import org.eclipse.lsp4j.ConfigurationParams; import org.eclipse.lsp4j.MessageActionItem; import org.eclipse.lsp4j.MessageParams; +import org.eclipse.lsp4j.ProgressParams; import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.eclipse.lsp4j.ShowMessageRequestParams; +import org.eclipse.lsp4j.WorkDoneProgressCreateParams; import org.netbeans.modules.java.lsp.server.explorer.api.NodeChangedParams; import org.netbeans.modules.java.lsp.server.protocol.DecorationRenderOptions; import org.netbeans.modules.java.lsp.server.protocol.HtmlPageParams; @@ -37,6 +44,26 @@ import org.netbeans.modules.java.lsp.server.protocol.TestProgressParams; public abstract class TestCodeLanguageClient implements NbCodeLanguageClient { + + @Override + public CompletableFuture createProgress(WorkDoneProgressCreateParams params) { + return CompletableFuture.completedFuture(null); + } + + @Override + public void notifyProgress(ProgressParams params) { + } + + @Override + public CompletableFuture applyEdit(ApplyWorkspaceEditParams params) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture> configuration(ConfigurationParams params) { + return CompletableFuture.completedFuture(Collections.emptyList()); + } + @Override public void showStatusBarMessage(ShowStatusMessageParams params) { throw new UnsupportedOperationException(); @@ -49,7 +76,7 @@ public CompletableFuture showHtmlPage(HtmlPageParams params) { @Override public CompletableFuture> showQuickPick(ShowQuickPickParams params) { - throw new UnsupportedOperationException(); + return CompletableFuture.completedFuture(params.getItems().stream().filter(item -> item.isPicked()).collect(Collectors.toList())); } @Override @@ -83,27 +110,25 @@ public NbCodeClientCapabilities getNbCodeCapabilities() { } @Override - public void telemetryEvent(Object arg0) { + public void telemetryEvent(Object params) { throw new UnsupportedOperationException(); } @Override - public void publishDiagnostics(PublishDiagnosticsParams arg0) { - throw new UnsupportedOperationException(); + public void publishDiagnostics(PublishDiagnosticsParams params) { } @Override - public void showMessage(MessageParams arg0) { - throw new UnsupportedOperationException(); + public void showMessage(MessageParams params) { } @Override - public CompletableFuture showMessageRequest(ShowMessageRequestParams arg0) { + public CompletableFuture showMessageRequest(ShowMessageRequestParams params) { throw new UnsupportedOperationException(); } @Override - public void logMessage(MessageParams arg0) { + public void logMessage(MessageParams params) { throw new UnsupportedOperationException(); } diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java index ade2c83e0b37..a95ff42476af 100644 --- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java +++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java @@ -147,6 +147,9 @@ import org.netbeans.junit.NbTestCase; import org.netbeans.modules.java.hints.infrastructure.JavaErrorProvider; import org.netbeans.modules.java.lsp.server.TestCodeLanguageClient; +import org.netbeans.modules.java.lsp.server.refactoring.ChangeMethodParameterUI; +import org.netbeans.modules.java.lsp.server.refactoring.ParameterUI; +import org.netbeans.modules.java.lsp.server.ui.MockHtmlViewer; import org.netbeans.modules.java.source.BootClassPathUtil; import org.netbeans.modules.parsing.impl.indexing.implspi.CacheFolderProvider; import org.netbeans.spi.java.classpath.ClassPathProvider; @@ -4292,6 +4295,9 @@ public CompletableFuture showInputBox(ShowInputBoxParams params) { @Override public CompletableFuture showHtmlPage(HtmlPageParams params) { + ChangeMethodParameterUI ui = MockHtmlViewer.assertDialogShown(params.getUri(), ChangeMethodParameterUI.class); + ui.getParameters().add(1, new ParameterUI("int", "cnt")); + ui.doRefactoring(); return CompletableFuture.completedFuture(null); } }, client.getInputStream(), client.getOutputStream()); diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/MockHtmlViewer.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/MockHtmlViewer.java index ec1ed3d06f58..1d10a3c47e75 100644 --- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/MockHtmlViewer.java +++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ui/MockHtmlViewer.java @@ -25,7 +25,6 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; -import java.util.concurrent.Callable; import net.java.html.BrwsrCtx; import static org.junit.Assert.assertTrue; import org.netbeans.html.boot.spi.Fn; @@ -41,14 +40,7 @@ public final class MockHtmlViewer extends AbstractLspHtmlViewer { private static final Map data = Collections.synchronizedMap(new HashMap<>()); - @Override - public View newView(Context ctx) { - View v = super.newView(ctx); - load(v, ctx.getClassLoader(), ctx.getPage(), ctx::onPageLoad, ctx.getTechIds()); - return v; - } - - private void load(View view, ClassLoader loader, URL pageUrl, Callable initialize, String[] techIds) { + private void load(View view) { UIContext ui = UIContext.find(); String key = UUID.randomUUID().toString(); @@ -56,7 +48,7 @@ private void load(View view, ClassLoader loader, URL pageUrl, Callable i ctx.execute(() -> { Object v; try (Closeable c = Fn.activate(Contexts.find(ctx, Fn.Presenter.class))) { - v = initialize.call(); + v = view.ctx.onPageLoad(); } catch (Exception ex) { MockTech.exception(ctx, ex); } @@ -74,6 +66,15 @@ public static T assertDialogShown(String uri, Class clazz) { return clazz.cast(v); } + @Override + public C component(View view, Class type) { + if (type == Void.class) { + load(view); + return null; + } + throw new ClassCastException(); + } + private BrwsrCtx mockPresenter() { final Fn.Presenter p = new Fn.Presenter() { @Override @@ -134,7 +135,6 @@ public void bind(PropertyBinding pb, Object o, Object data) { @Override public void valueHasMutated(Object data, String string) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override