This is an automated email from the ASF dual-hosted git repository. dbalek pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push: new 4a4528e LSP: Organize imports action added. (#3317) 4a4528e is described below commit 4a4528e5089acd6a74157964ef1067b2f508fcae Author: Dusan Balek <dusan.ba...@oracle.com> AuthorDate: Mon Nov 15 11:31:20 2021 +0100 LSP: Organize imports action added. (#3317) --- .../ChangeMethodParametersRefactoring.java | 2 +- .../lsp/server/protocol/CodeActionsProvider.java | 35 ++- .../lsp/server/protocol/ConstructorGenerator.java | 103 ++++++--- .../server/protocol/DelegateMethodGenerator.java | 202 +++++++++-------- .../server/protocol/EqualsHashCodeGenerator.java | 87 ++++---- .../ExtractSuperclassOrInterfaceRefactoring.java | 4 +- .../lsp/server/protocol/GetterSetterGenerator.java | 135 ++++++----- .../protocol/ImplementOverrideMethodGenerator.java | 118 +++++----- .../java/lsp/server/protocol/LoggerGenerator.java | 50 +++-- .../java/lsp/server/protocol/MoveRefactoring.java | 4 +- .../server/protocol/OrganizeImportsCodeAction.java | 87 ++++++++ .../lsp/server/protocol/PullUpRefactoring.java | 2 +- .../lsp/server/protocol/PushDownRefactoring.java | 2 +- .../modules/java/lsp/server/protocol/Server.java | 40 +++- .../java/lsp/server/protocol/SurroundWithHint.java | 14 +- .../server/protocol/TextDocumentServiceImpl.java | 45 +++- .../lsp/server/protocol/ToStringGenerator.java | 106 ++++----- .../lsp/server/protocol/WorkspaceServiceImpl.java | 21 +- .../java/lsp/server/protocol/ServerTest.java | 246 +++++++++++++-------- java/java.lsp.server/vscode/package.json | 28 +++ java/java.lsp.server/vscode/src/extension.ts | 2 +- 21 files changed, 857 insertions(+), 476 deletions(-) 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 index 849b4b6..157fdce 100644 --- 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 @@ -108,7 +108,7 @@ public final class ChangeMethodParametersRefactoring extends CodeRefactoring { } 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, CHANGE_METHOD_PARAMS_REFACTORING_COMMAND, Utils.toUri(elementSource), elementItem)); + return Collections.singletonList(createCodeAction(Bundle.DN_ChangeMethodParams(), CHANGE_METHOD_PARAMS_REFACTORING_KIND, null, CHANGE_METHOD_PARAMS_REFACTORING_COMMAND, Utils.toUri(elementSource), elementItem)); } @Override 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 db57677..5ea0ec7 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 @@ -20,7 +20,10 @@ package org.netbeans.modules.java.lsp.server.protocol; import com.sun.source.tree.LineMap; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -47,26 +50,44 @@ import org.netbeans.modules.parsing.api.ResultIterator; public abstract class CodeActionsProvider { public static final String CODE_GENERATOR_KIND = "source.generate"; + public static final String CODE_ACTIONS_PROVIDER_CLASS = "providerClass"; + public static final String DATA = "data"; protected static final String ERROR = "<error>"; //NOI18N public abstract List<CodeAction> getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception; - public abstract Set<String> getCommands(); + public CompletableFuture<CodeAction> resolve(NbCodeLanguageClient client, CodeAction codeAction, Object data) { + return CompletableFuture.completedFuture(codeAction); + } - public abstract CompletableFuture<Object> processCommand(NbCodeLanguageClient client, String command, List<Object> arguments); + public Set<String> getCommands() { + return Collections.emptySet(); + } - protected static int getOffset(CompilationInfo info, Position pos) { - LineMap lm = info.getCompilationUnit().getLineMap(); - return (int) lm.getPosition(pos.getLine() + 1, pos.getCharacter() + 1); + public CompletableFuture<Object> processCommand(NbCodeLanguageClient client, String command, List<Object> arguments) { + return CompletableFuture.completedFuture(false); } - protected static CodeAction createCodeAction(String name, String kind, String command, Object... args) { + protected CodeAction createCodeAction(String name, String kind, Object data, String command, Object... commandArgs) { CodeAction action = new CodeAction(name); action.setKind(kind); - action.setCommand(new Command(name, command, Arrays.asList(args))); + if (command != null) { + action.setCommand(new Command(name, command, Arrays.asList(commandArgs))); + } + if (data != null) { + Map<String, Object> map = new HashMap<>(); + map.put(CODE_ACTIONS_PROVIDER_CLASS, getClass().getName()); + map.put(DATA, data); + action.setData(map); + } return action; } + protected static int getOffset(CompilationInfo info, Position pos) { + LineMap lm = info.getCompilationUnit().getLineMap(); + return (int) lm.getPosition(pos.getLine() + 1, pos.getCharacter() + 1); + } + protected static String createLabel(CompilationInfo info, Element e) { return createLabel(info, e, false); } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ConstructorGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ConstructorGenerator.java index 7086bdd..1528927 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ConstructorGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ConstructorGenerator.java @@ -19,6 +19,8 @@ package org.netbeans.modules.java.lsp.server.protocol; import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; import com.sun.source.tree.ClassTree; import com.sun.source.tree.Tree; import com.sun.source.util.TreePath; @@ -26,8 +28,10 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -43,7 +47,6 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Elements; -import org.eclipse.lsp4j.ApplyWorkspaceEditParams; import org.eclipse.lsp4j.CodeAction; import org.eclipse.lsp4j.CodeActionKind; import org.eclipse.lsp4j.CodeActionParams; @@ -68,9 +71,11 @@ import org.openide.util.lookup.ServiceProvider; @ServiceProvider(service = CodeActionsProvider.class, position = 10) public final class ConstructorGenerator extends CodeActionsProvider { - public static final String GENERATE_CONSTRUCTOR = "java.generate.constructor"; + private static final String URI = "uri"; + private static final String OFFSET = "offset"; + private static final String CONSTRUCTORS = "constructors"; + private static final String FIELDS = "fields"; - private final Set<String> commands = Collections.singleton(GENERATE_CONSTRUCTOR); private final Gson gson = new Gson(); public ConstructorGenerator() { @@ -169,62 +174,101 @@ public final class ConstructorGenerator extends CodeActionsProvider { return Collections.emptyList(); } String uri = Utils.toUri(info.getFileObject()); - return Collections.singletonList(createCodeAction(Bundle.DN_GenerateConstructor(), isSource ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, GENERATE_CONSTRUCTOR, uri, startOffset, constructors, fields)); - } - - @Override - public Set<String> getCommands() { - return commands; + Map<String, Object> data = new HashMap<>(); + data.put(URI, uri); + data.put(OFFSET, startOffset); + data.put(CONSTRUCTORS, constructors); + data.put(FIELDS, fields); + return Collections.singletonList(createCodeAction(Bundle.DN_GenerateConstructor(), isSource ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, data, null)); } @Override @NbBundle.Messages({ "DN_SelectSuperConstructor=Select super constructor", }) - public CompletableFuture<Object> processCommand(NbCodeLanguageClient client, String command, List<Object> arguments) { - if (arguments.size() > 3) { - String uri = gson.fromJson(gson.toJson(arguments.get(0)), String.class); - int offset = gson.fromJson(gson.toJson(arguments.get(1)), Integer.class); - List<QuickPickItem> constructors = Arrays.asList(gson.fromJson(gson.toJson(arguments.get(2)), QuickPickItem[].class)); - List<QuickPickItem> fields = Arrays.asList(gson.fromJson(gson.toJson(arguments.get(3)), QuickPickItem[].class)); + public CompletableFuture<CodeAction> resolve(NbCodeLanguageClient client, CodeAction codeAction, Object data) { + CompletableFuture<CodeAction> future = new CompletableFuture<>(); + try { + String uri = ((JsonObject) data).getAsJsonPrimitive(URI).getAsString(); + int offset = ((JsonObject) data).getAsJsonPrimitive(OFFSET).getAsInt(); + List<QuickPickItem> constructors = Arrays.asList(gson.fromJson(gson.toJson(((JsonObject) data).get(CONSTRUCTORS)), QuickPickItem[].class)); + List<QuickPickItem> fields = Arrays.asList(gson.fromJson(((JsonObject) data).get(FIELDS), QuickPickItem[].class)); if (constructors.size() < 2 && fields.isEmpty()) { - generate(client, uri, offset, constructors, fields); + WorkspaceEdit edit = generate(client, uri, offset, constructors, fields); + if (edit != null) { + codeAction.setEdit(edit); + } + future.complete(codeAction); } else { if (constructors.size() > 1) { client.showQuickPick(new ShowQuickPickParams(Bundle.DN_SelectSuperConstructor(), true, constructors)).thenAccept(selected -> { - if (selected != null) { - selectFields(client, uri, offset, selected, fields); + try { + if (selected != null) { + selectFields(client, uri, offset, selected, fields).handle((edit, ex) -> { + if (ex != null) { + future.completeExceptionally(ex); + } else { + if (edit != null) { + codeAction.setEdit(edit); + } + future.complete(codeAction); + } + return null; + }); + } else { + future.complete(codeAction); + } + } catch (IOException | IllegalArgumentException ex) { + future.completeExceptionally(ex); } }); } else { - selectFields(client, uri, offset, constructors, fields); + selectFields(client, uri, offset, constructors, fields).handle((edit, ex) -> { + if (ex != null) { + future.completeExceptionally(ex); + } else { + if (edit != null) { + codeAction.setEdit(edit); + } + future.complete(codeAction); + } + return null; + }); } } - } else { - client.logMessage(new MessageParams(MessageType.Error, String.format("Illegal number of arguments received for command: %s", command))); + } catch (JsonSyntaxException | IOException | IllegalArgumentException ex) { + future.completeExceptionally(ex); } - return CompletableFuture.completedFuture(true); + return future; } @NbBundle.Messages({ "DN_SelectConstructorFields=Select fields to be initialized by constructor", }) - private void selectFields(NbCodeLanguageClient client, String uri, int offset, List<QuickPickItem> constructors, List<QuickPickItem> fields) { + private CompletableFuture<WorkspaceEdit> selectFields(NbCodeLanguageClient client, String uri, int offset, List<QuickPickItem> constructors, List<QuickPickItem> fields) throws IOException, IllegalArgumentException { + CompletableFuture<WorkspaceEdit> future = new CompletableFuture<>(); if (!fields.isEmpty()) { client.showQuickPick(new ShowQuickPickParams(Bundle.DN_SelectConstructorFields(), true, fields)).thenAccept(selected -> { - if (selected != null) { - generate(client, uri, offset, constructors, selected); + try { + if (selected != null) { + future.complete(generate(client, uri, offset, constructors, selected)); + } else { + future.complete(null); + } + } catch (IOException | IllegalArgumentException ex) { + future.completeExceptionally(ex); } }); } else { - generate(client, uri, offset, constructors, fields); + future.complete(generate(client, uri, offset, constructors, fields)); } + return future; } @NbBundle.Messages({ "DN_ConstructorAlreadyExists=Given constructor already exists", }) - private void generate(NbCodeLanguageClient client, String uri, int offset, List<QuickPickItem> constructors, List<QuickPickItem> fields) { + private WorkspaceEdit generate(NbCodeLanguageClient client, String uri, int offset, List<QuickPickItem> constructors, List<QuickPickItem> fields) throws IOException, IllegalArgumentException { try { FileObject file = Utils.fromUri(uri); JavaSource js = JavaSource.forFileObject(file); @@ -247,11 +291,10 @@ public final class ConstructorGenerator extends CodeActionsProvider { GeneratorUtils.generateConstructors(wc, tp, selectedFields, selectedConstructors, -1); } }); - client.applyEdit(new ApplyWorkspaceEditParams(new WorkspaceEdit(Collections.singletonMap(uri, edits)))); + return edits.isEmpty() ? null : new WorkspaceEdit(Collections.singletonMap(uri, edits)); } catch (GeneratorUtils.DuplicateMemberException dme) { client.showMessage(new MessageParams(MessageType.Info, Bundle.DN_ConstructorAlreadyExists())); - } catch (IOException | IllegalArgumentException ex) { - client.logMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); } + return null; } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/DelegateMethodGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/DelegateMethodGenerator.java index 6f605b1..9673e31 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/DelegateMethodGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/DelegateMethodGenerator.java @@ -19,6 +19,8 @@ package org.netbeans.modules.java.lsp.server.protocol; import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; import com.sun.source.tree.Scope; import com.sun.source.util.TreePath; import com.sun.source.util.Trees; @@ -26,8 +28,9 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; -import java.util.Set; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import javax.lang.model.element.Element; @@ -41,12 +44,9 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Elements; -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.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.WorkspaceEdit; import org.netbeans.api.java.source.CompilationController; @@ -66,14 +66,13 @@ import org.openide.util.lookup.ServiceProvider; @ServiceProvider(service = CodeActionsProvider.class, position = 60) public final class DelegateMethodGenerator extends CodeActionsProvider { - public static final String GENERATE_DELEGATE_METHOD = "java.generate.delegateMethod"; + private static final String URI = "uri"; + private static final String OFFSET = "offset"; + private static final String TYPE = "type"; + private static final String FIELDS = "fields"; - private final Set<String> commands = Collections.singleton(GENERATE_DELEGATE_METHOD); private final Gson gson = new Gson(); - public DelegateMethodGenerator() { - } - @Override @NbBundle.Messages({ "DN_GenerateDelegateMethod=Generate Delegate Method...", @@ -122,108 +121,137 @@ public final class DelegateMethodGenerator extends CodeActionsProvider { String uri = Utils.toUri(info.getFileObject()); QuickPickItem typeItem = new QuickPickItem(createLabel(info, typeElement)); typeItem.setUserData(new ElementData(typeElement)); - return Collections.singletonList(createCodeAction(Bundle.DN_GenerateDelegateMethod(), CODE_GENERATOR_KIND, GENERATE_DELEGATE_METHOD, uri, offset, typeItem, fields)); - } - - @Override - public Set<String> getCommands() { - return commands; + Map<String, Object> data = new HashMap<>(); + data.put(URI, uri); + data.put(OFFSET, offset); + data.put(TYPE, typeItem); + data.put(FIELDS, fields); + return Collections.singletonList(createCodeAction(Bundle.DN_GenerateDelegateMethod(), CODE_GENERATOR_KIND, data, null)); } @Override @NbBundle.Messages({ "DN_SelectDelegateMethodField=Select target field to generate delegates for", }) - public CompletableFuture<Object> processCommand(NbCodeLanguageClient client, String command, List<Object> arguments) { - if (arguments.size() > 3) { - String uri = gson.fromJson(gson.toJson(arguments.get(0)), String.class); - int offset = gson.fromJson(gson.toJson(arguments.get(1)), Integer.class); - QuickPickItem type = gson.fromJson(gson.toJson(arguments.get(2)), QuickPickItem.class); - List<QuickPickItem> fields = Arrays.asList(gson.fromJson(gson.toJson(arguments.get(3)), QuickPickItem[].class)); + public CompletableFuture<CodeAction> resolve(NbCodeLanguageClient client, CodeAction codeAction, Object data) { + CompletableFuture<CodeAction> future = new CompletableFuture<>(); + try { + String uri = ((JsonObject) data).getAsJsonPrimitive(URI).getAsString(); + int offset = ((JsonObject) data).getAsJsonPrimitive(OFFSET).getAsInt(); + QuickPickItem type = gson.fromJson(gson.toJson(((JsonObject) data).get(TYPE)), QuickPickItem.class); + List<QuickPickItem> fields = Arrays.asList(gson.fromJson(((JsonObject) data).get(FIELDS), QuickPickItem[].class)); if (fields.size() == 1) { - selectMethods(client, uri, offset, type, fields.get(0)); + selectMethods(client, uri, offset, type, fields.get(0)).handle((edit, ex) -> { + if (ex != null) { + future.completeExceptionally(ex); + } else { + if (edit != null) { + codeAction.setEdit(edit); + } + future.complete(codeAction); + } + return null; + }); } else { client.showQuickPick(new ShowQuickPickParams(Bundle.DN_SelectDelegateMethodField(), false, fields)).thenAccept(selected -> { - if (selected != null && !selected.isEmpty()) { - selectMethods(client, uri, offset, type, selected.get(0)); + try { + if (selected != null && !selected.isEmpty()) { + selectMethods(client, uri, offset, type, selected.get(0)).handle((edit, ex) -> { + if (ex != null) { + future.completeExceptionally(ex); + } else { + if (edit != null) { + codeAction.setEdit(edit); + } + future.complete(codeAction); + } + return null; + }); + } else { + future.complete(codeAction); + } + } catch (IOException | IllegalArgumentException ex) { + future.completeExceptionally(ex); } }); } - } else { - client.logMessage(new MessageParams(MessageType.Error, String.format("Illegal number of arguments received for command: %s", command))); + } catch (JsonSyntaxException | IOException | IllegalArgumentException ex) { + future.completeExceptionally(ex); } - return CompletableFuture.completedFuture(true); + return future; } @NbBundle.Messages({ "DN_SelectDelegateMethods=Select methods to generate delegates for", }) - private void selectMethods(NbCodeLanguageClient client, String uri, int offset, QuickPickItem type, QuickPickItem selectedField) { - try { - FileObject file = Utils.fromUri(uri); - JavaSource js = JavaSource.forFileObject(file); - if (js == null) { - throw new IOException("Cannot get JavaSource for: " + uri); - } - js.runUserActionTask(info -> { - info.toPhase(JavaSource.Phase.RESOLVED); - TypeElement origin = (TypeElement) gson.fromJson(gson.toJson(type.getUserData()), ElementData.class).resolve(info); - VariableElement field = (VariableElement) gson.fromJson(gson.toJson(selectedField.getUserData()), ElementData.class).resolve(info); - if (origin != null && field != null) { - final ElementUtilities eu = info.getElementUtilities(); - final Trees trees = info.getTrees(); - final Scope scope = info.getTreeUtilities().scopeFor(offset); - ElementUtilities.ElementAcceptor acceptor = new ElementUtilities.ElementAcceptor() { - @Override - public boolean accept(Element e, TypeMirror type) { - if (e.getKind() == ElementKind.METHOD && trees.isAccessible(scope, e, (DeclaredType)type)) { - Element impl = eu.getImplementationOf((ExecutableElement)e, origin); - return impl == null || (!impl.getModifiers().contains(Modifier.FINAL) && impl.getEnclosingElement() != origin); - } - return false; + private CompletableFuture<WorkspaceEdit> selectMethods(NbCodeLanguageClient client, String uri, int offset, QuickPickItem type, QuickPickItem selectedField) throws IOException, IllegalArgumentException { + CompletableFuture<WorkspaceEdit> future = new CompletableFuture<>(); + FileObject file = Utils.fromUri(uri); + JavaSource js = JavaSource.forFileObject(file); + if (js == null) { + throw new IOException("Cannot get JavaSource for: " + uri); + } + js.runUserActionTask(info -> { + info.toPhase(JavaSource.Phase.RESOLVED); + TypeElement origin = (TypeElement) gson.fromJson(gson.toJson(type.getUserData()), ElementData.class).resolve(info); + VariableElement field = (VariableElement) gson.fromJson(gson.toJson(selectedField.getUserData()), ElementData.class).resolve(info); + if (origin != null && field != null) { + final ElementUtilities eu = info.getElementUtilities(); + final Trees trees = info.getTrees(); + final Scope scope = info.getTreeUtilities().scopeFor(offset); + ElementUtilities.ElementAcceptor acceptor = new ElementUtilities.ElementAcceptor() { + @Override + public boolean accept(Element e, TypeMirror type) { + if (e.getKind() == ElementKind.METHOD && trees.isAccessible(scope, e, (DeclaredType)type)) { + Element impl = eu.getImplementationOf((ExecutableElement)e, origin); + return impl == null || (!impl.getModifiers().contains(Modifier.FINAL) && impl.getEnclosingElement() != origin); } - }; - List<QuickPickItem> methods = new ArrayList<>(); - for (ExecutableElement method : ElementFilter.methodsIn(eu.getMembers(field.asType(), acceptor))) { - QuickPickItem item = new QuickPickItem(String.format("%s.%s", field.getSimpleName().toString(), createLabel(info, method))); - item.setUserData(new ElementData(method)); - methods.add(item); + return false; } - client.showQuickPick(new ShowQuickPickParams(Bundle.DN_SelectDelegateMethods(), true, methods)).thenAccept(selected -> { + }; + List<QuickPickItem> methods = new ArrayList<>(); + for (ExecutableElement method : ElementFilter.methodsIn(eu.getMembers(field.asType(), acceptor))) { + QuickPickItem item = new QuickPickItem(String.format("%s.%s", field.getSimpleName().toString(), createLabel(info, method))); + item.setUserData(new ElementData(method)); + methods.add(item); + } + client.showQuickPick(new ShowQuickPickParams(Bundle.DN_SelectDelegateMethods(), true, methods)).thenAccept(selected -> { + try { if (selected != null && !selected.isEmpty()) { - generate(client, uri, offset, selectedField, selected); + future.complete(generate(uri, offset, selectedField, selected)); + } else { + future.complete(null); } - }); - } - }, true); - } catch (IOException | IllegalArgumentException ex) { - client.logMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); - } + } catch (IOException | IllegalArgumentException ex) { + future.completeExceptionally(ex); + } + }); + } else { + future.complete(null); + } + }, true); + return future; } - private void generate(NbCodeLanguageClient client, String uri, int offset, QuickPickItem selectedField, List<QuickPickItem> selectedMethods) { - try { - FileObject file = Utils.fromUri(uri); - JavaSource js = JavaSource.forFileObject(file); - if (js == null) { - throw new IOException("Cannot get JavaSource for: " + uri); - } - List<TextEdit> edits = TextDocumentServiceImpl.modify2TextEdits(js, wc -> { - wc.toPhase(JavaSource.Phase.RESOLVED); - TreePath tp = wc.getTreeUtilities().pathFor(offset); - tp = wc.getTreeUtilities().getPathElementOfKind(TreeUtilities.CLASS_TREE_KINDS, tp); - if (tp != null) { - VariableElement field = (VariableElement) gson.fromJson(gson.toJson(selectedField.getUserData()), ElementData.class).resolve(wc); - List<ExecutableElement> methods = selectedMethods.stream().map(item -> { - ElementData data = gson.fromJson(gson.toJson(item.getUserData()), ElementData.class); - return (ExecutableElement)data.resolve(wc); - }).collect(Collectors.toList()); - org.netbeans.modules.java.editor.codegen.DelegateMethodGenerator.generateDelegatingMethods(wc, tp, field, methods, -1); - } - }); - client.applyEdit(new ApplyWorkspaceEditParams(new WorkspaceEdit(Collections.singletonMap(uri, edits)))); - } catch (IOException | IllegalArgumentException ex) { - client.logMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); + private WorkspaceEdit generate(String uri, int offset, QuickPickItem selectedField, List<QuickPickItem> selectedMethods) throws IOException, IllegalArgumentException { + FileObject file = Utils.fromUri(uri); + JavaSource js = JavaSource.forFileObject(file); + if (js == null) { + throw new IOException("Cannot get JavaSource for: " + uri); } + List<TextEdit> edits = TextDocumentServiceImpl.modify2TextEdits(js, wc -> { + wc.toPhase(JavaSource.Phase.RESOLVED); + TreePath tp = wc.getTreeUtilities().pathFor(offset); + tp = wc.getTreeUtilities().getPathElementOfKind(TreeUtilities.CLASS_TREE_KINDS, tp); + if (tp != null) { + VariableElement field = (VariableElement) gson.fromJson(gson.toJson(selectedField.getUserData()), ElementData.class).resolve(wc); + List<ExecutableElement> methods = selectedMethods.stream().map(item -> { + ElementData data = gson.fromJson(gson.toJson(item.getUserData()), ElementData.class); + return (ExecutableElement)data.resolve(wc); + }).collect(Collectors.toList()); + org.netbeans.modules.java.editor.codegen.DelegateMethodGenerator.generateDelegatingMethods(wc, tp, field, methods, -1); + } + }); + return edits.isEmpty() ? null : new WorkspaceEdit(Collections.singletonMap(uri, edits)); } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/EqualsHashCodeGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/EqualsHashCodeGenerator.java index 67a981b..2554aa2 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/EqualsHashCodeGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/EqualsHashCodeGenerator.java @@ -19,15 +19,17 @@ package org.netbeans.modules.java.lsp.server.protocol; import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; import com.sun.source.tree.Tree; import com.sun.source.util.TreePath; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; +import java.util.HashMap; import java.util.List; -import java.util.Set; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import javax.lang.model.element.ElementKind; @@ -36,12 +38,9 @@ import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.util.ElementFilter; -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.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.WorkspaceEdit; import org.netbeans.api.java.source.CompilationController; @@ -59,16 +58,15 @@ import org.openide.util.lookup.ServiceProvider; @ServiceProvider(service = CodeActionsProvider.class, position = 40) public final class EqualsHashCodeGenerator extends CodeActionsProvider { - public static final String GENERATE_EQUALS = "java.generate.equals"; - public static final String GENERATE_HASH_CODE = "java.generate.hashCode"; - public static final String GENERATE_EQUALS_HASH_CODE = "java.generate.equals.hashCode"; + private static final String KIND = "kind"; + private static final String URI = "uri"; + private static final String OFFSET = "offset"; + private static final String FIELDS = "fields"; + private static final int EQUALS_ONLY = 1; + private static final int HASH_CODE_ONLY = 2; - private final Set<String> commands = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(GENERATE_EQUALS_HASH_CODE, GENERATE_EQUALS, GENERATE_HASH_CODE))); private final Gson gson = new Gson(); - public EqualsHashCodeGenerator() { - } - @Override @NbBundle.Messages({ "DN_GenerateEquals=Generate equals()...", @@ -113,16 +111,11 @@ public final class EqualsHashCodeGenerator extends CodeActionsProvider { String uri = Utils.toUri(info.getFileObject()); if (equalsHashCode[0] == null) { if (equalsHashCode[1] == null) { - return Collections.singletonList(createCodeAction(Bundle.DN_GenerateEqualsHashCode(), CODE_GENERATOR_KIND, GENERATE_EQUALS_HASH_CODE, uri, offset, fields)); + return Collections.singletonList(createCodeAction(Bundle.DN_GenerateEqualsHashCode(), CODE_GENERATOR_KIND, data(0, uri, offset, fields), null)); } - return Collections.singletonList(createCodeAction(Bundle.DN_GenerateEquals(), CODE_GENERATOR_KIND, GENERATE_EQUALS, uri, offset, fields)); + return Collections.singletonList(createCodeAction(Bundle.DN_GenerateEquals(), CODE_GENERATOR_KIND, data(EQUALS_ONLY, uri, offset, fields), null)); } - return Collections.singletonList(createCodeAction(Bundle.DN_GenerateHashCode(), CODE_GENERATOR_KIND, GENERATE_HASH_CODE, uri, offset, fields)); - } - - @Override - public Set<String> getCommands() { - return commands; + return Collections.singletonList(createCodeAction(Bundle.DN_GenerateHashCode(), CODE_GENERATOR_KIND, data(HASH_CODE_ONLY, uri, offset, fields), null)); } @Override @@ -131,22 +124,24 @@ public final class EqualsHashCodeGenerator extends CodeActionsProvider { "DN_SelectHashCode=Select fields to be included in hashCode()", "DN_SelectEqualsHashCode=Select fields to be included in equals() and hashCode()", }) - public CompletableFuture<Object> processCommand(NbCodeLanguageClient client, String command, List<Object> arguments) { - if (arguments.size() > 2) { - String uri = gson.fromJson(gson.toJson(arguments.get(0)), String.class); - int offset = gson.fromJson(gson.toJson(arguments.get(1)), Integer.class); - List<QuickPickItem> fields = Arrays.asList(gson.fromJson(gson.toJson(arguments.get(2)), QuickPickItem[].class)); + public CompletableFuture<CodeAction> resolve(NbCodeLanguageClient client, CodeAction codeAction, Object data) { + CompletableFuture<CodeAction> future = new CompletableFuture<>(); + try { + int kind = ((JsonObject) data).getAsJsonPrimitive(KIND).getAsInt(); + String uri = ((JsonObject) data).getAsJsonPrimitive(URI).getAsString(); + int offset = ((JsonObject) data).getAsJsonPrimitive(OFFSET).getAsInt(); + List<QuickPickItem> fields = Arrays.asList(gson.fromJson(((JsonObject) data).get(FIELDS), QuickPickItem[].class)); String text; - boolean generateEquals = !GENERATE_HASH_CODE.equals(command); - boolean generateHashCode = !GENERATE_EQUALS.equals(command); - switch (command) { - case GENERATE_EQUALS: text = Bundle.DN_SelectEquals(); break; - case GENERATE_HASH_CODE: text = Bundle.DN_SelectHashCode(); break; + boolean generateEquals = HASH_CODE_ONLY != kind; + boolean generateHashCode = EQUALS_ONLY != kind; + switch (kind) { + case EQUALS_ONLY: text = Bundle.DN_SelectEquals(); break; + case HASH_CODE_ONLY: text = Bundle.DN_SelectHashCode(); break; default: text = Bundle.DN_SelectEqualsHashCode(); break; } client.showQuickPick(new ShowQuickPickParams(text, true, fields)).thenAccept(selected -> { - if (selected != null) { - try { + try { + if (selected != null) { FileObject file = Utils.fromUri(uri); JavaSource js = JavaSource.forFileObject(file); if (js == null) { @@ -158,21 +153,33 @@ public final class EqualsHashCodeGenerator extends CodeActionsProvider { tp = wc.getTreeUtilities().getPathElementOfKind(Tree.Kind.CLASS, tp); if (tp != null) { List<VariableElement> selectedFields = selected.stream().map(item -> { - ElementData data = gson.fromJson(gson.toJson(item.getUserData()), ElementData.class); - return (VariableElement)data.resolve(wc); + ElementData userData = gson.fromJson(gson.toJson(item.getUserData()), ElementData.class); + return (VariableElement) userData.resolve(wc); }).collect(Collectors.toList()); org.netbeans.modules.java.editor.codegen.EqualsHashCodeGenerator.generateEqualsAndHashCode(wc, tp, generateEquals ? selectedFields : null, generateHashCode ? selectedFields : null, -1); } }); - client.applyEdit(new ApplyWorkspaceEditParams(new WorkspaceEdit(Collections.singletonMap(uri, edits)))); - } catch (IOException | IllegalArgumentException ex) { - client.logMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); + if (!edits.isEmpty()) { + codeAction.setEdit(new WorkspaceEdit(Collections.singletonMap(uri, edits))); + } } + future.complete(codeAction); + } catch (IOException | IllegalArgumentException ex) { + future.completeExceptionally(ex); } }); - } else { - client.logMessage(new MessageParams(MessageType.Error, String.format("Illegal number of arguments received for command: %s", command))); + } catch(JsonSyntaxException ex) { + future.completeExceptionally(ex); } - return CompletableFuture.completedFuture(true); + return future; + } + + private static Map<String, Object> data(int kind, String uri, int offset, List<QuickPickItem> fields) { + Map<String, Object> data = new HashMap<>(); + data.put(KIND, kind); + data.put(URI, uri); + data.put(OFFSET, offset); + data.put(FIELDS, fields); + return data; } } 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/protocol/ExtractSuperclassOrInterfaceRefactoring.java index 87d4807..e1e09ec 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/protocol/ExtractSuperclassOrInterfaceRefactoring.java @@ -146,10 +146,10 @@ public final class ExtractSuperclassOrInterfaceRefactoring extends CodeRefactori QuickPickItem elementItem = new QuickPickItem(createLabel(info, type)); elementItem.setUserData(new ElementData(type)); if (!type.getKind().isInterface()) { - result.add(createCodeAction(Bundle.DN_ExtractSuperclass(), CodeActionKind.RefactorExtract, EXTRACT_SUPERCLASS_REFACTORING_COMMAND, uri, elementItem, allMembers)); + result.add(createCodeAction(Bundle.DN_ExtractSuperclass(), CodeActionKind.RefactorExtract, null, EXTRACT_SUPERCLASS_REFACTORING_COMMAND, uri, elementItem, allMembers)); } if (!members.isEmpty()) { - result.add(createCodeAction(Bundle.DN_ExtractInterface(), CodeActionKind.RefactorExtract, EXTRACT_INTERFACE_REFACTORING_COMMAND, uri, elementItem, members)); + result.add(createCodeAction(Bundle.DN_ExtractInterface(), CodeActionKind.RefactorExtract, null, EXTRACT_INTERFACE_REFACTORING_COMMAND, uri, elementItem, members)); } } return result; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/GetterSetterGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/GetterSetterGenerator.java index 9841873..c4e3928 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/GetterSetterGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/GetterSetterGenerator.java @@ -19,6 +19,8 @@ package org.netbeans.modules.java.lsp.server.protocol; import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; import com.sun.source.tree.ClassTree; import com.sun.source.tree.Tree; import com.sun.source.util.TreePath; @@ -26,9 +28,11 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -36,12 +40,9 @@ import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.util.ElementFilter; -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.eclipse.lsp4j.Range; import org.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.WorkspaceEdit; @@ -66,16 +67,14 @@ import org.openide.util.lookup.ServiceProvider; @ServiceProvider(service = CodeActionsProvider.class, position = 30) public final class GetterSetterGenerator extends CodeActionsProvider { - public static final String GENERATE_GETTERS = "java.generate.getters"; - public static final String GENERATE_SETTERS = "java.generate.setters"; - public static final String GENERATE_GETTERS_SETTERS = "java.generate.getters.setters"; + private static final String KIND = "kind"; + private static final String URI = "uri"; + private static final String OFFSET = "offset"; + private static final String ALL = "all"; + private static final String FIELDS = "fields"; - private final Set<String> commands = Collections.unmodifiableSet(new HashSet(Arrays.asList(GENERATE_GETTERS, GENERATE_SETTERS, GENERATE_GETTERS_SETTERS))); private final Gson gson = new Gson(); - public GetterSetterGenerator() { - } - @Override @NbBundle.Messages({ "DN_GenerateGetters=Generate Getters...", @@ -101,94 +100,98 @@ public final class GetterSetterGenerator extends CodeActionsProvider { List<CodeAction> result = new ArrayList<>(); if (missingGetters) { String name = pair.first().size() == 1 ? Bundle.DN_GenerateGetterFor(pair.first().iterator().next().getSimpleName().toString()) : Bundle.DN_GenerateGetters(); - result.add(createCodeAction(name, all ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, GENERATE_GETTERS, uri, offset, all, pair.first().stream().map(variableElement -> { + result.add(createCodeAction(name, all ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, data(GeneratorUtils.GETTERS_ONLY, uri, offset, all, pair.first().stream().map(variableElement -> { QuickPickItem item = new QuickPickItem(createLabel(info, variableElement)); item.setUserData(new ElementData(variableElement)); return item; - }).collect(Collectors.toList()))); + }).collect(Collectors.toList())), null)); } if (missingSetters) { String name = pair.second().size() == 1 ? Bundle.DN_GenerateSetterFor(pair.second().iterator().next().getSimpleName().toString()) : Bundle.DN_GenerateSetters(); - result.add(createCodeAction(name, all ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, GENERATE_SETTERS, uri, offset, all, pair.second().stream().map(variableElement -> { + result.add(createCodeAction(name, all ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, data(GeneratorUtils.SETTERS_ONLY, uri, offset, all, pair.second().stream().map(variableElement -> { QuickPickItem item = new QuickPickItem(createLabel(info, variableElement)); item.setUserData(new ElementData(variableElement)); return item; - }).collect(Collectors.toList()))); + }).collect(Collectors.toList())), null)); } if (missingGetters && missingSetters) { pair.first().retainAll(pair.second()); String name = pair.first().size() == 1 ? Bundle.DN_GenerateGetterSetterFor(pair.first().iterator().next().getSimpleName().toString()) : Bundle.DN_GenerateGettersSetters(); - result.add(createCodeAction(name, all ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, GENERATE_GETTERS_SETTERS, uri, offset, all, pair.first().stream().map(variableElement -> { + result.add(createCodeAction(name, all ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, data(0, uri, offset, all, pair.first().stream().map(variableElement -> { QuickPickItem item = new QuickPickItem(createLabel(info, variableElement)); item.setUserData(new ElementData(variableElement)); return item; - }).collect(Collectors.toList()))); + }).collect(Collectors.toList())), null)); } return result; } @Override - public Set<String> getCommands() { - return commands; - } - - @Override @NbBundle.Messages({ "DN_SelectGetters=Select fields to generate getters for", "DN_SelectSetters=Select fields to generate setters for", "DN_SelectGettersSetters=Select fields to generate getters and setters for", }) - public CompletableFuture<Object> processCommand(NbCodeLanguageClient client, String command, List<Object> arguments) { - if (arguments.size() > 3) { - String uri = gson.fromJson(gson.toJson(arguments.get(0)), String.class); - int offset = gson.fromJson(gson.toJson(arguments.get(1)), Integer.class); - boolean all = gson.fromJson(gson.toJson(arguments.get(2)), boolean.class); - List<QuickPickItem> fields = Arrays.asList(gson.fromJson(gson.toJson(arguments.get(3)), QuickPickItem[].class)); - int kind; + public CompletableFuture<CodeAction> resolve(NbCodeLanguageClient client, CodeAction codeAction, Object data) { + CompletableFuture<CodeAction> future = new CompletableFuture<>(); + try { + int kind = ((JsonObject) data).getAsJsonPrimitive(KIND).getAsInt(); + String uri = ((JsonObject) data).getAsJsonPrimitive(URI).getAsString(); + int offset = ((JsonObject) data).getAsJsonPrimitive(OFFSET).getAsInt(); + boolean all = ((JsonObject) data).getAsJsonPrimitive(ALL).getAsBoolean(); + List<QuickPickItem> fields = Arrays.asList(gson.fromJson(((JsonObject) data).get(FIELDS), QuickPickItem[].class)); String text; - switch (command) { - case GENERATE_GETTERS: kind = GeneratorUtils.GETTERS_ONLY; text = Bundle.DN_SelectGetters(); break; - case GENERATE_SETTERS: kind = GeneratorUtils.SETTERS_ONLY; text = Bundle.DN_SelectSetters(); break; - default: kind = 0; text = Bundle.DN_SelectGettersSetters(); break; + switch (kind) { + case GeneratorUtils.GETTERS_ONLY: text = Bundle.DN_SelectGetters(); break; + case GeneratorUtils.SETTERS_ONLY: text = Bundle.DN_SelectSetters(); break; + default: text = Bundle.DN_SelectGettersSetters(); break; } if (all && fields.size() > 1) { client.showQuickPick(new ShowQuickPickParams(text, true, fields)).thenAccept(selected -> { - if (selected != null && !selected.isEmpty()) { - generate(client, kind, uri, offset, selected); + try { + if (selected != null && !selected.isEmpty()) { + WorkspaceEdit edit = generate(kind, uri, offset, selected); + if (edit != null) { + codeAction.setEdit(edit); + } + } + future.complete(codeAction); + } catch (IOException | IllegalArgumentException ex) { + future.completeExceptionally(ex); } }); - } else if (fields.size() == 1) { - generate(client, kind, uri, offset, fields); + } else { + WorkspaceEdit edit = generate(kind, uri, offset, fields); + if (edit != null) { + codeAction.setEdit(edit); + } + future.complete(codeAction); } - } else { - client.logMessage(new MessageParams(MessageType.Error, String.format("Illegal number of arguments received for command: %s", command))); + } catch(JsonSyntaxException | IOException | IllegalArgumentException ex) { + future.completeExceptionally(ex); } - return CompletableFuture.completedFuture(true); + return future; } - private void generate(NbCodeLanguageClient client, int kind, String uri, int offset, List<QuickPickItem> fields) throws IllegalArgumentException { - try { - FileObject file = Utils.fromUri(uri); - JavaSource js = JavaSource.forFileObject(file); - if (js == null) { - throw new IOException("Cannot get JavaSource for: " + uri); - } - List<TextEdit> edits = TextDocumentServiceImpl.modify2TextEdits(js, wc -> { - wc.toPhase(JavaSource.Phase.RESOLVED); - TreePath tp = wc.getTreeUtilities().pathFor(offset); - tp = wc.getTreeUtilities().getPathElementOfKind(TreeUtilities.CLASS_TREE_KINDS, tp); - if (tp != null) { - List<VariableElement> variableElements = fields.stream().map(item -> { - ElementData data = gson.fromJson(gson.toJson(item.getUserData()), ElementData.class); - return (VariableElement) data.resolve(wc); - }).collect(Collectors.toList()); - GeneratorUtils.generateGettersAndSetters(wc, tp, variableElements, kind, -1); - } - }); - client.applyEdit(new ApplyWorkspaceEditParams(new WorkspaceEdit(Collections.singletonMap(uri, edits)))); - } catch (IOException ex) { - client.logMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); + private WorkspaceEdit generate(int kind, String uri, int offset, List<QuickPickItem> fields) throws IOException, IllegalArgumentException { + FileObject file = Utils.fromUri(uri); + JavaSource js = JavaSource.forFileObject(file); + if (js == null) { + throw new IOException("Cannot get JavaSource for: " + uri); } + List<TextEdit> edits = TextDocumentServiceImpl.modify2TextEdits(js, wc -> { + wc.toPhase(JavaSource.Phase.RESOLVED); + TreePath tp = wc.getTreeUtilities().pathFor(offset); + tp = wc.getTreeUtilities().getPathElementOfKind(TreeUtilities.CLASS_TREE_KINDS, tp); + if (tp != null) { + List<VariableElement> variableElements = fields.stream().map(item -> { + ElementData data = gson.fromJson(gson.toJson(item.getUserData()), ElementData.class); + return (VariableElement) data.resolve(wc); + }).collect(Collectors.toList()); + GeneratorUtils.generateGettersAndSetters(wc, tp, variableElements, kind, -1); + } + }); + return edits.isEmpty() ? null : new WorkspaceEdit(Collections.singletonMap(uri, edits)); } private static Pair<Set<VariableElement>, Set<VariableElement>> findMissingGettersSetters(CompilationInfo info, Range range, boolean all) { @@ -254,4 +257,14 @@ public final class GetterSetterGenerator extends CodeActionsProvider { return Pair.of(missingGetters, missingSetters); } + + private static Map<String, Object> data(int kind, String uri, int offset, boolean all, List<QuickPickItem> fields) { + Map<String, Object> data = new HashMap<>(); + data.put(KIND, kind); + data.put(URI, uri); + data.put(OFFSET, offset); + data.put(ALL, all); + data.put(FIELDS, fields); + return data; + } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ImplementOverrideMethodGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ImplementOverrideMethodGenerator.java index 59d0c83..8a398f4 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ImplementOverrideMethodGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ImplementOverrideMethodGenerator.java @@ -19,14 +19,16 @@ package org.netbeans.modules.java.lsp.server.protocol; import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; import com.sun.source.util.TreePath; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; +import java.util.HashMap; import java.util.List; -import java.util.Set; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import javax.lang.model.SourceVersion; @@ -35,12 +37,9 @@ import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; -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.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.WorkspaceEdit; import org.netbeans.api.java.source.CompilationController; @@ -61,15 +60,13 @@ import org.openide.util.lookup.ServiceProvider; @ServiceProvider(service = CodeActionsProvider.class, position = 70) public final class ImplementOverrideMethodGenerator extends CodeActionsProvider { - public static final String GENERATE_IMPLEMENT_METHOD = "java.generate.implementMethod"; - public static final String GENERATE_OVERRIDE_METHOD = "java.generate.overrideMethod"; + private static final String URI = "uri"; + private static final String OFFSET = "offset"; + private static final String IS_IMPLEMET = "isImplement"; + private static final String METHODS = "methods"; - private final Set<String> commands = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(GENERATE_IMPLEMENT_METHOD, GENERATE_OVERRIDE_METHOD))); private final Gson gson = new Gson(); - public ImplementOverrideMethodGenerator() { - } - @Override @NbBundle.Messages({ "DN_GenerateImplementMethod=Generate Implement Method...", @@ -108,7 +105,7 @@ public final class ImplementOverrideMethodGenerator extends CodeActionsProvider implementMethods.add(new QuickPickItem(createLabel(info, method), enclosingTypeName, null, mustImplement, new ElementData(method))); } if (!implementMethods.isEmpty()) { - result.add(createCodeAction(Bundle.DN_GenerateImplementMethod(), CODE_GENERATOR_KIND, GENERATE_IMPLEMENT_METHOD, uri, offset, implementMethods)); + result.add(createCodeAction(Bundle.DN_GenerateImplementMethod(), CODE_GENERATOR_KIND, data(uri, offset, true, implementMethods), null)); } } if (typeElement.getKind().isClass() || typeElement.getKind().isInterface()) { @@ -124,66 +121,75 @@ public final class ImplementOverrideMethodGenerator extends CodeActionsProvider overrideMethods.add(item); } if (!overrideMethods.isEmpty()) { - result.add(createCodeAction(Bundle.DN_GenerateOverrideMethod(), CODE_GENERATOR_KIND, GENERATE_OVERRIDE_METHOD, uri, offset, overrideMethods)); + result.add(createCodeAction(Bundle.DN_GenerateOverrideMethod(), CODE_GENERATOR_KIND, data (uri, offset, false, overrideMethods), null)); } } return result; } @Override - public Set<String> getCommands() { - return commands; - } - - @Override @NbBundle.Messages({ "DN_SelectImplementMethod=Select methods to implement", "DN_SelectOverrideMethod=Select methods to override", }) - public CompletableFuture<Object> processCommand(NbCodeLanguageClient client, String command, List<Object> arguments) { - if (arguments.size() > 2) { - String uri = gson.fromJson(gson.toJson(arguments.get(0)), String.class); - int offset = gson.fromJson(gson.toJson(arguments.get(1)), Integer.class); - List<QuickPickItem> methods = Arrays.asList(gson.fromJson(gson.toJson(arguments.get(2)), QuickPickItem[].class)); - String text = command == GENERATE_IMPLEMENT_METHOD ? Bundle.DN_SelectImplementMethod() : Bundle.DN_SelectOverrideMethod(); - boolean isImplement = command == GENERATE_IMPLEMENT_METHOD; + public CompletableFuture<CodeAction> resolve(NbCodeLanguageClient client, CodeAction codeAction, Object data) { + CompletableFuture<CodeAction> future = new CompletableFuture<>(); + try { + String uri = ((JsonObject) data).getAsJsonPrimitive(URI).getAsString(); + int offset = ((JsonObject) data).getAsJsonPrimitive(OFFSET).getAsInt(); + boolean isImplement = ((JsonObject) data).getAsJsonPrimitive(IS_IMPLEMET).getAsBoolean(); + List<QuickPickItem> methods = Arrays.asList(gson.fromJson(((JsonObject) data).get(METHODS), QuickPickItem[].class)); + String text = isImplement ? Bundle.DN_SelectImplementMethod() : Bundle.DN_SelectOverrideMethod(); client.showQuickPick(new ShowQuickPickParams(text, true, methods)).thenAccept(selected -> { - if (selected != null && !selected.isEmpty()) { - generate(client, uri, offset, isImplement, selected); + try { + if (selected != null && !selected.isEmpty()) { + WorkspaceEdit edit = generate(uri, offset, isImplement, selected); + if (edit != null) { + codeAction.setEdit(edit); + } + } + future.complete(codeAction); + } catch (IOException | IllegalArgumentException ex) { + future.completeExceptionally(ex); } }); - } else { - client.logMessage(new MessageParams(MessageType.Error, String.format("Illegal number of arguments received for command: %s", command))); + } catch(JsonSyntaxException ex) { + future.completeExceptionally(ex); } - return CompletableFuture.completedFuture(true); + return future; } - private void generate(NbCodeLanguageClient client, String uri, int offset, boolean isImplement, List<QuickPickItem> methods) { - try { - FileObject file = Utils.fromUri(uri); - JavaSource js = JavaSource.forFileObject(file); - if (js == null) { - throw new IOException("Cannot get JavaSource for: " + uri); - } - List<TextEdit> edits = TextDocumentServiceImpl.modify2TextEdits(js, wc -> { - wc.toPhase(JavaSource.Phase.RESOLVED); - TreePath tp = wc.getTreeUtilities().pathFor(offset); - tp = wc.getTreeUtilities().getPathElementOfKind(TreeUtilities.CLASS_TREE_KINDS, tp); - if (tp != null) { - List<ExecutableElement> selectedMethods = methods.stream().map(item -> { - ElementData data = gson.fromJson(gson.toJson(item.getUserData()), ElementData.class); - return (ExecutableElement)data.resolve(wc); - }).collect(Collectors.toList()); - if (isImplement) { - GeneratorUtils.generateAbstractMethodImplementations(wc, tp, selectedMethods, -1); - } else { - GeneratorUtils.generateMethodOverrides(wc, tp, selectedMethods, -1); - } - } - }); - client.applyEdit(new ApplyWorkspaceEditParams(new WorkspaceEdit(Collections.singletonMap(uri, edits)))); - } catch (IOException | IllegalArgumentException ex) { - client.logMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); + private WorkspaceEdit generate(String uri, int offset, boolean isImplement, List<QuickPickItem> methods) throws IOException, IllegalArgumentException { + FileObject file = Utils.fromUri(uri); + JavaSource js = JavaSource.forFileObject(file); + if (js == null) { + throw new IOException("Cannot get JavaSource for: " + uri); } + List<TextEdit> edits = TextDocumentServiceImpl.modify2TextEdits(js, wc -> { + wc.toPhase(JavaSource.Phase.RESOLVED); + TreePath tp = wc.getTreeUtilities().pathFor(offset); + tp = wc.getTreeUtilities().getPathElementOfKind(TreeUtilities.CLASS_TREE_KINDS, tp); + if (tp != null) { + List<ExecutableElement> selectedMethods = methods.stream().map(item -> { + ElementData data = gson.fromJson(gson.toJson(item.getUserData()), ElementData.class); + return (ExecutableElement)data.resolve(wc); + }).collect(Collectors.toList()); + if (isImplement) { + GeneratorUtils.generateAbstractMethodImplementations(wc, tp, selectedMethods, -1); + } else { + GeneratorUtils.generateMethodOverrides(wc, tp, selectedMethods, -1); + } + } + }); + return edits == null ? null : new WorkspaceEdit(Collections.singletonMap(uri, edits)); + } + + private static Map<String, Object> data(String uri, int offset, boolean isImplement, List<QuickPickItem> methods) { + Map<String, Object> data = new HashMap<>(); + data.put(URI, uri); + data.put(OFFSET, offset); + data.put(IS_IMPLEMET, isImplement); + data.put(METHODS, methods); + return data; } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LoggerGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LoggerGenerator.java index 824838d..14220ac 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LoggerGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LoggerGenerator.java @@ -19,14 +19,17 @@ package org.netbeans.modules.java.lsp.server.protocol; import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; import com.sun.source.tree.ClassTree; import com.sun.source.tree.VariableTree; import com.sun.source.util.TreePath; import java.io.IOException; import java.util.Collections; import java.util.EnumSet; +import java.util.HashMap; import java.util.List; -import java.util.Set; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.logging.Logger; import javax.lang.model.element.Modifier; @@ -36,12 +39,9 @@ import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; -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.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.WorkspaceEdit; import org.netbeans.api.java.source.CompilationController; @@ -62,9 +62,9 @@ import org.openide.util.lookup.ServiceProvider; @ServiceProvider(service = CodeActionsProvider.class, position = 20) public final class LoggerGenerator extends CodeActionsProvider { - public static final String GENERATE_LOGGER = "java.generate.logger"; + private static final String URI = "uri"; + private static final String OFFSET = "offset"; - private final Set<String> commands = Collections.singleton(GENERATE_LOGGER); private final Gson gson = new Gson(); public LoggerGenerator() { @@ -102,25 +102,24 @@ public final class LoggerGenerator extends CodeActionsProvider { } } String uri = Utils.toUri(info.getFileObject()); - return Collections.singletonList(createCodeAction(Bundle.DN_GenerateLogger(), CODE_GENERATOR_KIND, GENERATE_LOGGER, uri, offset)); - } - - @Override - public Set<String> getCommands() { - return commands; + Map<String, Object> data = new HashMap<>(); + data.put(URI, uri); + data.put(OFFSET, offset); + return Collections.singletonList(createCodeAction(Bundle.DN_GenerateLogger(), CODE_GENERATOR_KIND, data, null)); } @Override @NbBundle.Messages({ "DN_SelectLoggerName=Logger field name", }) - public CompletableFuture<Object> processCommand(NbCodeLanguageClient client, String command, List<Object> arguments) { - if (arguments.size() > 1) { - String uri = gson.fromJson(gson.toJson(arguments.get(0)), String.class); - int offset = gson.fromJson(gson.toJson(arguments.get(1)), Integer.class); + public CompletableFuture<CodeAction> resolve(NbCodeLanguageClient client, CodeAction codeAction, Object data) { + CompletableFuture<CodeAction> future = new CompletableFuture<>(); + try { + String uri = ((JsonObject) data).getAsJsonPrimitive(URI).getAsString(); + int offset = ((JsonObject) data).getAsJsonPrimitive(OFFSET).getAsInt(); client.showInputBox(new ShowInputBoxParams(Bundle.DN_SelectLoggerName(), "LOG")).thenAccept(value -> { - if (value != null && BaseUtilities.isJavaIdentifier(value)) { - try { + try { + if (value != null && BaseUtilities.isJavaIdentifier(value)) { FileObject file = Utils.fromUri(uri); JavaSource js = JavaSource.forFileObject(file); if (js == null) { @@ -136,15 +135,18 @@ public final class LoggerGenerator extends CodeActionsProvider { wc.rewrite(cls, GeneratorUtilities.get(wc).insertClassMember(cls, field)); } }); - client.applyEdit(new ApplyWorkspaceEditParams(new WorkspaceEdit(Collections.singletonMap(uri, edits)))); - } catch (IOException | IllegalArgumentException ex) { - client.logMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); + if (!edits.isEmpty()) { + codeAction.setEdit(new WorkspaceEdit(Collections.singletonMap(uri, edits))); + } } + future.complete(codeAction); + } catch (IOException | IllegalArgumentException ex) { + future.completeExceptionally(ex); } }); - } else { - client.logMessage(new MessageParams(MessageType.Error, String.format("Illegal number of arguments received for command: %s", command))); + } catch (JsonSyntaxException ex) { + future.completeExceptionally(ex); } - return CompletableFuture.completedFuture(true); + return future; } } 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/protocol/MoveRefactoring.java index 9aa18d7..51475e6 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/protocol/MoveRefactoring.java @@ -98,9 +98,9 @@ public final class MoveRefactoring extends CodeRefactoring { if (element != null) { QuickPickItem elementItem = new QuickPickItem(createLabel(info, element)); elementItem.setUserData(new ElementData(element)); - return Collections.singletonList(createCodeAction(Bundle.DN_Move(), MOVE_REFACTORING_KIND, MOVE_REFACTORING_COMMAND, uri, elementItem)); + return Collections.singletonList(createCodeAction(Bundle.DN_Move(), MOVE_REFACTORING_KIND, null, MOVE_REFACTORING_COMMAND, uri, elementItem)); } else { - return Collections.singletonList(createCodeAction(Bundle.DN_Move(), MOVE_REFACTORING_KIND, MOVE_REFACTORING_COMMAND, uri)); + return Collections.singletonList(createCodeAction(Bundle.DN_Move(), MOVE_REFACTORING_KIND, null, MOVE_REFACTORING_COMMAND, uri)); } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/OrganizeImportsCodeAction.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/OrganizeImportsCodeAction.java new file mode 100644 index 0000000..c16187c --- /dev/null +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/OrganizeImportsCodeAction.java @@ -0,0 +1,87 @@ +/* + * 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.JsonPrimitive; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import org.eclipse.lsp4j.CodeAction; +import org.eclipse.lsp4j.CodeActionKind; +import org.eclipse.lsp4j.CodeActionParams; +import org.eclipse.lsp4j.TextEdit; +import org.eclipse.lsp4j.WorkspaceEdit; +import org.netbeans.api.java.source.CompilationController; +import org.netbeans.api.java.source.JavaSource; +import org.netbeans.modules.java.hints.OrganizeImports; +import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.parsing.api.ResultIterator; +import org.openide.filesystems.FileObject; +import org.openide.util.NbBundle; +import org.openide.util.lookup.ServiceProvider; + +/** + * + * @author Dusan Balek + */ +@ServiceProvider(service = CodeActionsProvider.class, position = 90) +public final class OrganizeImportsCodeAction extends CodeActionsProvider { + + @Override + @NbBundle.Messages({ + "DN_OrganizeImports=Organize Imports", + }) + public List<CodeAction> getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + List<String> only = params.getContext().getOnly(); + if (only == null || !only.contains(CodeActionKind.Source) && !only.contains(CodeActionKind.SourceOrganizeImports)) { + return Collections.emptyList(); + } + CompilationController info = CompilationController.get(resultIterator.getParserResult()); + if (info == null) { + return Collections.emptyList(); + } + String uri = Utils.toUri(info.getFileObject()); + return Collections.singletonList(createCodeAction(Bundle.DN_OrganizeImports(), CodeActionKind.SourceOrganizeImports, uri, null)); + } + + @Override + public CompletableFuture<CodeAction> resolve(NbCodeLanguageClient client, CodeAction codeAction, Object data) { + CompletableFuture<CodeAction> future = new CompletableFuture<>(); + try { + String uri = ((JsonPrimitive) data).getAsString(); + FileObject file = Utils.fromUri(uri); + JavaSource js = JavaSource.forFileObject(file); + if (js == null) { + throw new IOException("Cannot get JavaSource for: " + uri); + } + List<TextEdit> edits = TextDocumentServiceImpl.modify2TextEdits(js, wc -> { + wc.toPhase(JavaSource.Phase.RESOLVED); + OrganizeImports.doOrganizeImports(wc, null, false); + }); + if (!edits.isEmpty()) { + codeAction.setEdit(new WorkspaceEdit(Collections.singletonMap(uri, edits))); + } + future.complete(codeAction); + } catch (IOException | IllegalArgumentException ex) { + future.completeExceptionally(ex); + } + return future; + } +} 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/protocol/PullUpRefactoring.java index b146688..dea79b2 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/protocol/PullUpRefactoring.java @@ -115,7 +115,7 @@ public final class PullUpRefactoring extends CodeRefactoring { } QuickPickItem elementItem = new QuickPickItem(createLabel(info, element)); elementItem.setUserData(new ElementData(element)); - return Collections.singletonList(createCodeAction(Bundle.DN_PullUp(), PULL_UP_REFACTORING_KIND, PULL_UP_REFACTORING_COMMAND, uri, offset, elementItem, supertypeItems)); + return Collections.singletonList(createCodeAction(Bundle.DN_PullUp(), PULL_UP_REFACTORING_KIND, null, PULL_UP_REFACTORING_COMMAND, uri, offset, elementItem, supertypeItems)); } @Override 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/protocol/PushDownRefactoring.java index 591f071..65cc6fd 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/protocol/PushDownRefactoring.java @@ -126,7 +126,7 @@ public final class PushDownRefactoring extends CodeRefactoring { } QuickPickItem elementItem = new QuickPickItem(createLabel(info, element)); elementItem.setUserData(new ElementData(element)); - return Collections.singletonList(createCodeAction(Bundle.DN_PushDown(), PUSH_DOWN_REFACTORING_KIND, PUSH_DOWN_REFACTORING_COMMAND, uri, elementItem, members)); + return Collections.singletonList(createCodeAction(Bundle.DN_PushDown(), PUSH_DOWN_REFACTORING_KIND, null, PUSH_DOWN_REFACTORING_COMMAND, uri, elementItem, members)); } @Override diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java index f406c47..386ee69 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java @@ -43,10 +43,13 @@ import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; import com.google.gson.InstanceCreator; +import com.google.gson.JsonObject; import org.eclipse.lsp4j.CodeActionKind; import org.eclipse.lsp4j.CodeActionOptions; import org.eclipse.lsp4j.CodeLensOptions; import org.eclipse.lsp4j.CompletionOptions; +import org.eclipse.lsp4j.ConfigurationItem; +import org.eclipse.lsp4j.ConfigurationParams; import org.eclipse.lsp4j.ExecuteCommandOptions; import org.eclipse.lsp4j.FoldingRangeProviderOptions; import org.eclipse.lsp4j.InitializeParams; @@ -60,6 +63,7 @@ import org.eclipse.lsp4j.SemanticTokensCapabilities; import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.lsp4j.ShowMessageRequestParams; import org.eclipse.lsp4j.TextDocumentSyncKind; +import org.eclipse.lsp4j.TextDocumentSyncOptions; import org.eclipse.lsp4j.WorkDoneProgressCancelParams; import org.eclipse.lsp4j.WorkDoneProgressParams; import org.eclipse.lsp4j.WorkspaceFolder; @@ -280,13 +284,15 @@ public final class Server { static class LanguageServerImpl implements LanguageServer, LanguageClientAware, LspServerState { + private static final String NETBEANS_JAVA_IMPORTS = "netbeans.java.imports"; + // change to a greater throughput if the initialization waits on more processes than just (serialized) project open. private static final RequestProcessor SERVER_INIT_RP = new RequestProcessor(LanguageServerImpl.class.getName()); private static final Logger LOG = Logger.getLogger(LanguageServerImpl.class.getName()); private NbCodeClientWrapper client; - private final TextDocumentService textDocumentService = new TextDocumentServiceImpl(this); - private final WorkspaceService workspaceService = new WorkspaceServiceImpl(this); + private final TextDocumentServiceImpl textDocumentService = new TextDocumentServiceImpl(this); + private final WorkspaceServiceImpl workspaceService = new WorkspaceServiceImpl(this); private final InstanceContent sessionServices = new InstanceContent(); private final Lookup sessionLookup = new ProxyLookup( new AbstractLookup(sessionServices), @@ -610,13 +616,19 @@ public final class Server { private InitializeResult constructInitResponse(JavaSource src) { ServerCapabilities capabilities = new ServerCapabilities(); if (src != null) { - capabilities.setTextDocumentSync(TextDocumentSyncKind.Incremental); + TextDocumentSyncOptions textDocumentSyncOptions = new TextDocumentSyncOptions(); + textDocumentSyncOptions.setChange(TextDocumentSyncKind.Incremental); + textDocumentSyncOptions.setOpenClose(true); + textDocumentSyncOptions.setWillSaveWaitUntil(true); + capabilities.setTextDocumentSync(textDocumentSyncOptions); CompletionOptions completionOptions = new CompletionOptions(); completionOptions.setResolveProvider(true); completionOptions.setTriggerCharacters(Collections.singletonList(".")); capabilities.setCompletionProvider(completionOptions); capabilities.setHoverProvider(true); - capabilities.setCodeActionProvider(new CodeActionOptions(Arrays.asList(CodeActionKind.QuickFix, CodeActionKind.Source, CodeActionKind.Refactor))); + CodeActionOptions codeActionOptions = new CodeActionOptions(Arrays.asList(CodeActionKind.QuickFix, CodeActionKind.Source, CodeActionKind.SourceOrganizeImports, CodeActionKind.Refactor)); + codeActionOptions.setResolveProvider(true); + capabilities.setCodeActionProvider(codeActionOptions); capabilities.setDocumentSymbolProvider(true); capabilities.setDefinitionProvider(true); capabilities.setTypeDefinitionProvider(true); @@ -687,7 +699,9 @@ public final class Server { // chain showIndexingComplete message after initial project open. prjs. thenApply(this::showIndexingCompleted); - + + initializeOptions(); + // but complete the InitializationRequest independently of the project initialization. return CompletableFuture.completedFuture( finishInitialization( @@ -696,6 +710,22 @@ public final class Server { ); } + private void initializeOptions() { + getWorkspaceProjects().thenAccept(projects -> { + if (projects != null && projects.length > 0) { + ConfigurationItem item = new ConfigurationItem(); + FileObject fo = projects[0].getProjectDirectory(); + item.setScopeUri(Utils.toUri(fo)); + item.setSection(NETBEANS_JAVA_IMPORTS); + client.configuration(new ConfigurationParams(Collections.singletonList(item))).thenAccept(c -> { + if (c != null && !c.isEmpty() && c.get(0) instanceof JsonObject) { + workspaceService.updateJavaImportPreferences(fo, (JsonObject) c.get(0)); + } + }); + } + }); + } + public CompletableFuture<Project[]> getWorkspaceProjects() { return workspaceProjects; } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/SurroundWithHint.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/SurroundWithHint.java index 5aad8d4..5424309 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/SurroundWithHint.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/SurroundWithHint.java @@ -134,7 +134,7 @@ public final class SurroundWithHint extends CodeActionsProvider { snippet = sb.append(snippet).toString(); } int idx = label.indexOf(' '); - CodeAction codeAction = createCodeAction(Bundle.DN_SurroundWith(idx < 0 ? label : label.substring(0, idx)), CodeActionKind.RefactorRewrite, COMMAND_INSERT_SNIPPET, Collections.singletonMap(SNIPPET, snippet)); + CodeAction codeAction = createCodeAction(Bundle.DN_SurroundWith(idx < 0 ? label : label.substring(0, idx)), CodeActionKind.RefactorRewrite, null, COMMAND_INSERT_SNIPPET, Collections.singletonMap(SNIPPET, snippet)); if (!edits.isEmpty()) { codeAction.setEdit(new WorkspaceEdit(Collections.singletonMap(params.getTextDocument().getUri(), edits))); } @@ -146,21 +146,11 @@ public final class SurroundWithHint extends CodeActionsProvider { } } if (items.size() > codeActions.size()) { - codeActions.add(createCodeAction(Bundle.DN_SurroundWithAll(), CodeActionKind.RefactorRewrite, COMMAND_SURROUND_WITH, items)); + codeActions.add(createCodeAction(Bundle.DN_SurroundWithAll(), CodeActionKind.RefactorRewrite, null, COMMAND_SURROUND_WITH, items)); } return codeActions; } - @Override - public Set<String> getCommands() { - return Collections.emptySet(); - } - - @Override - public CompletableFuture<Object> processCommand(NbCodeLanguageClient client, String command, List<Object> arguments) { - return CompletableFuture.completedFuture(false); - } - private static Collection<? extends CodeTemplateFilter> getTemplateFilters(Document doc, int startOffset, int endOffset) { String mimeType = DocumentUtilities.getMimeType(doc); Collection<? extends CodeTemplateFilter.Factory> filterFactories = MimeLookup.getLookup(mimeType).lookupAll(CodeTemplateFilter.Factory.class); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java index faa927d..a8ba7bf 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java @@ -132,6 +132,7 @@ import org.eclipse.lsp4j.TextDocumentEdit; import org.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.TypeDefinitionParams; import org.eclipse.lsp4j.VersionedTextDocumentIdentifier; +import org.eclipse.lsp4j.WillSaveTextDocumentParams; import org.eclipse.lsp4j.WorkspaceEdit; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode; @@ -175,6 +176,7 @@ import org.netbeans.modules.java.editor.codegen.GeneratorUtils; import org.netbeans.modules.java.editor.options.MarkOccurencesSettings; import org.netbeans.modules.java.editor.overridden.ComputeOverriding; import org.netbeans.modules.java.editor.overridden.ElementDescription; +import org.netbeans.modules.java.hints.OrganizeImports; import org.netbeans.modules.java.hints.introduce.IntroduceFixBase; import org.netbeans.modules.java.hints.introduce.IntroduceHint; import org.netbeans.modules.java.hints.introduce.IntroduceKind; @@ -233,6 +235,7 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli private static final String COMMAND_RUN_SINGLE = "java.run.single"; // NOI18N private static final String COMMAND_DEBUG_SINGLE = "java.debug.single"; // NOI18N private static final String NETBEANS_JAVADOC_LOAD_TIMEOUT = "netbeans.javadoc.load.timeout";// NOI18N + private static final String NETBEANS_JAVA_ON_SAVE_ORGANIZE_IMPORTS = "netbeans.java.onSave.organizeImports";// NOI18N private static final RequestProcessor BACKGROUND_TASKS = new RequestProcessor(TextDocumentServiceImpl.class.getName(), 1, false, false); private static final RequestProcessor WORKER = new RequestProcessor(TextDocumentServiceImpl.class.getName(), 1, false, false); @@ -1001,7 +1004,23 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli }); return resultFuture; } - + + @Override + public CompletableFuture<CodeAction> resolveCodeAction(CodeAction unresolved) { + JsonObject data = (JsonObject) unresolved.getData(); + if (data != null) { + String providerClass = data.getAsJsonPrimitive(CodeActionsProvider.CODE_ACTIONS_PROVIDER_CLASS).getAsString(); + for (CodeActionsProvider codeGenerator : Lookup.getDefault().lookupAll(CodeActionsProvider.class)) { + try { + if (codeGenerator.getClass().getName().equals(providerClass)) { + return codeGenerator.resolve(client, unresolved, data.get(CodeActionsProvider.DATA)); + } + } catch (Exception ex) { + } + } + } + return CompletableFuture.completedFuture(unresolved); + } @NbBundle.Messages({"# {0} - method name", "LBL_Run=Run {0}", "# {0} - method name", "LBL_Debug=Debug {0}", @@ -1443,6 +1462,30 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli } @Override + public CompletableFuture<List<TextEdit>> willSaveWaitUntil(WillSaveTextDocumentParams params) { + String uri = params.getTextDocument().getUri(); + JavaSource js = getJavaSource(uri); + if (js == null) { + return CompletableFuture.completedFuture(Collections.emptyList()); + } + ConfigurationItem conf = new ConfigurationItem(); + conf.setScopeUri(uri); + conf.setSection(NETBEANS_JAVA_ON_SAVE_ORGANIZE_IMPORTS); + return client.configuration(new ConfigurationParams(Collections.singletonList(conf))).thenApply(c -> { + if (c != null && !c.isEmpty() && ((JsonPrimitive) c.get(0)).getAsBoolean()) { + try { + List<TextEdit> edits = TextDocumentServiceImpl.modify2TextEdits(js, wc -> { + wc.toPhase(JavaSource.Phase.RESOLVED); + OrganizeImports.doOrganizeImports(wc, null, false); + }); + return edits; + } catch (IOException ex) {} + } + return Collections.emptyList(); + }); + } + + @Override public void didSave(DidSaveTextDocumentParams arg0) { //TODO: nothing for now? } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ToStringGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ToStringGenerator.java index 70dc949..f862f38 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ToStringGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ToStringGenerator.java @@ -19,6 +19,8 @@ package org.netbeans.modules.java.lsp.server.protocol; import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; import com.sun.source.tree.ClassTree; import com.sun.source.tree.MethodTree; import com.sun.source.util.TreePath; @@ -26,8 +28,9 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; -import java.util.Set; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import javax.lang.model.element.Element; @@ -35,12 +38,9 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; -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.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.WorkspaceEdit; import org.netbeans.api.java.source.CompilationController; @@ -60,14 +60,12 @@ import org.openide.util.lookup.ServiceProvider; @ServiceProvider(service = CodeActionsProvider.class, position = 50) public final class ToStringGenerator extends CodeActionsProvider { - public static final String GENERATE_TO_STRING = "java.generate.toString"; + private static final String URI = "uri"; + private static final String OFFSET = "offset"; + private static final String FIELDS = "fields"; - private final Set<String> commands = Collections.singleton(GENERATE_TO_STRING); private final Gson gson = new Gson(); - public ToStringGenerator() { - } - @Override @NbBundle.Messages({ "DN_GenerateToString=Generate toString()...", @@ -110,62 +108,70 @@ public final class ToStringGenerator extends CodeActionsProvider { } } String uri = Utils.toUri(info.getFileObject()); - return Collections.singletonList(createCodeAction(Bundle.DN_GenerateToString(), CODE_GENERATOR_KIND, GENERATE_TO_STRING, uri, offset, fields)); - } - - @Override - public Set<String> getCommands() { - return commands; + Map<String, Object> data = new HashMap<>(); + data.put(URI, uri); + data.put(OFFSET, offset); + data.put(FIELDS, fields); + return Collections.singletonList(createCodeAction(Bundle.DN_GenerateToString(), CODE_GENERATOR_KIND, data, null)); } @Override @NbBundle.Messages({ "DN_SelectToString=Select fields to be included in toString()", }) - public CompletableFuture<Object> processCommand(NbCodeLanguageClient client, String command, List<Object> arguments) { - if (arguments.size() > 2) { - String uri = gson.fromJson(gson.toJson(arguments.get(0)), String.class); - int offset = gson.fromJson(gson.toJson(arguments.get(1)), Integer.class); - List<QuickPickItem> fields = Arrays.asList(gson.fromJson(gson.toJson(arguments.get(2)), QuickPickItem[].class)); + public CompletableFuture<CodeAction> resolve(NbCodeLanguageClient client, CodeAction codeAction, Object data) { + CompletableFuture<CodeAction> future = new CompletableFuture<>(); + try { + String uri = ((JsonObject) data).getAsJsonPrimitive(URI).getAsString(); + int offset = ((JsonObject) data).getAsJsonPrimitive(OFFSET).getAsInt(); + List<QuickPickItem> fields = Arrays.asList(gson.fromJson(((JsonObject) data).get(FIELDS), QuickPickItem[].class)); if (fields.isEmpty()) { - generate(client, uri, offset, fields); + WorkspaceEdit edit = generate(uri, offset, fields); + if (edit != null) { + codeAction.setEdit(edit); + } + future.complete(codeAction); } else { client.showQuickPick(new ShowQuickPickParams(Bundle.DN_SelectToString(), true, fields)).thenAccept(selected -> { - if (selected != null) { - generate(client, uri, offset, selected); + try { + if (selected != null) { + WorkspaceEdit edit = generate(uri, offset, fields); + if (edit != null) { + codeAction.setEdit(edit); + } + } + future.complete(codeAction); + } catch (IOException | IllegalArgumentException ex) { + future.completeExceptionally(ex); } }); } - } else { - client.logMessage(new MessageParams(MessageType.Error, String.format("Illegal number of arguments received for command: %s", command))); + } catch (JsonSyntaxException | IOException | IllegalArgumentException ex) { + future.completeExceptionally(ex); } - return CompletableFuture.completedFuture(true); + return future; } - private void generate(NbCodeLanguageClient client, String uri, int offset, List<QuickPickItem> fields) { - try { - FileObject file = Utils.fromUri(uri); - JavaSource js = JavaSource.forFileObject(file); - if (js == null) { - throw new IOException("Cannot get JavaSource for: " + uri); - } - List<TextEdit> edits = TextDocumentServiceImpl.modify2TextEdits(js, wc -> { - wc.toPhase(JavaSource.Phase.RESOLVED); - TreePath tp = wc.getTreeUtilities().pathFor(offset); - tp = wc.getTreeUtilities().getPathElementOfKind(TreeUtilities.CLASS_TREE_KINDS, tp); - if (tp != null) { - ClassTree cls = (ClassTree) tp.getLeaf(); - List<VariableElement> selectedFields = fields.stream().map(item -> { - ElementData data = gson.fromJson(gson.toJson(item.getUserData()), ElementData.class); - return (VariableElement)data.resolve(wc); - }).collect(Collectors.toList()); - MethodTree method = org.netbeans.modules.java.editor.codegen.ToStringGenerator.createToStringMethod(wc, selectedFields, cls.getSimpleName().toString(), true); - wc.rewrite(cls, GeneratorUtilities.get(wc).insertClassMember(cls, method)); - } - }); - client.applyEdit(new ApplyWorkspaceEditParams(new WorkspaceEdit(Collections.singletonMap(uri, edits)))); - } catch (IOException | IllegalArgumentException ex) { - client.logMessage(new MessageParams(MessageType.Error, ex.getLocalizedMessage())); + private WorkspaceEdit generate(String uri, int offset, List<QuickPickItem> fields) throws IOException, IllegalArgumentException { + FileObject file = Utils.fromUri(uri); + JavaSource js = JavaSource.forFileObject(file); + if (js == null) { + throw new IOException("Cannot get JavaSource for: " + uri); } + List<TextEdit> edits = TextDocumentServiceImpl.modify2TextEdits(js, wc -> { + wc.toPhase(JavaSource.Phase.RESOLVED); + TreePath tp = wc.getTreeUtilities().pathFor(offset); + tp = wc.getTreeUtilities().getPathElementOfKind(TreeUtilities.CLASS_TREE_KINDS, tp); + if (tp != null) { + ClassTree cls = (ClassTree) tp.getLeaf(); + List<VariableElement> selectedFields = fields.stream().map(item -> { + ElementData data = gson.fromJson(gson.toJson(item.getUserData()), ElementData.class); + return (VariableElement)data.resolve(wc); + }).collect(Collectors.toList()); + MethodTree method = org.netbeans.modules.java.editor.codegen.ToStringGenerator.createToStringMethod(wc, selectedFields, cls.getSimpleName().toString(), true); + wc.rewrite(cls, GeneratorUtilities.get(wc).insertClassMember(cls, method)); + } + }); + return edits.isEmpty() ? null : new WorkspaceEdit(Collections.singletonMap(uri, edits)); } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java index eb55741..8928119 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java @@ -44,6 +44,7 @@ import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Supplier; import java.util.logging.Logger; +import java.util.prefs.Preferences; import java.util.stream.Collectors; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; @@ -80,6 +81,7 @@ import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectUtils; import org.netbeans.api.project.SourceGroup; import org.netbeans.api.project.ui.OpenProjects; +import org.netbeans.modules.editor.indent.spi.CodeStylePreferences; import org.netbeans.modules.gsf.testrunner.ui.api.TestMethodController; import org.netbeans.modules.gsf.testrunner.ui.api.TestMethodFinder; import org.netbeans.modules.java.lsp.server.LspServerState; @@ -660,8 +662,23 @@ public final class WorkspaceServiceImpl implements WorkspaceService, LanguageCli } @Override - public void didChangeConfiguration(DidChangeConfigurationParams arg0) { - //TODO: no real configuration right now + public void didChangeConfiguration(DidChangeConfigurationParams params) { + server.openedProjects().thenAccept(projects -> { + if (projects != null && projects.length > 0) { + updateJavaImportPreferences(projects[0].getProjectDirectory(), ((JsonObject) params.getSettings()).getAsJsonObject("netbeans").getAsJsonObject("java").getAsJsonObject("imports")); + } + }); + } + + void updateJavaImportPreferences(FileObject fo, JsonObject configuration) { + Preferences prefs = CodeStylePreferences.get(fo, "text/x-java").getPreferences(); + if (prefs != null) { + prefs.put("importGroupsOrder", String.join(";", gson.fromJson(configuration.get("groups"), String[].class))); + prefs.putBoolean("allowConvertToStarImport", true); + prefs.putInt("countForUsingStarImport", configuration.getAsJsonPrimitive("countForUsingStarImport").getAsInt()); + prefs.putBoolean("allowConvertToStaticStarImport", true); + prefs.putInt("countForUsingStaticStarImport", configuration.getAsJsonPrimitive("countForUsingStaticStarImport").getAsInt()); + } } @Override 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 6dd3fbe..bb18841 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 @@ -2818,7 +2818,6 @@ public class ServerTest extends NbTestCase { try (Writer w = new FileWriter(src)) { w.write(code); } - WorkspaceEdit[] edit = new WorkspaceEdit[1]; Launcher<LanguageServer> serverLauncher = LSPLauncher.createClientLauncher(new LspClient() { @Override public void telemetryEvent(Object arg0) { @@ -2845,8 +2844,7 @@ public class ServerTest extends NbTestCase { @Override public CompletableFuture<ApplyWorkspaceEditResponse> applyEdit(ApplyWorkspaceEditParams params) { - edit[0] = params.getEdit(); - return CompletableFuture.completedFuture(new ApplyWorkspaceEditResponse(false)); + throw new UnsupportedOperationException("Not supported yet."); } }, client.getInputStream(), client.getOutputStream()); @@ -2865,9 +2863,12 @@ public class ServerTest extends NbTestCase { .filter(a -> Bundle.DN_GenerateGetterSetterFor("f2").equals(a.getTitle())) .findAny(); assertTrue(generateGetterSetter.isPresent()); - server.getWorkspaceService().executeCommand(new ExecuteCommandParams(generateGetterSetter.get().getCommand().getCommand(), generateGetterSetter.get().getCommand().getArguments())).get(); - assertEquals(1, edit[0].getChanges().size()); - List<TextEdit> fileChanges = edit[0].getChanges().get(uri); + CodeAction resolvedCodeAction = server.getTextDocumentService().resolveCodeAction(generateGetterSetter.get()).get(); + assertNotNull(resolvedCodeAction); + WorkspaceEdit edit = resolvedCodeAction.getEdit(); + assertNotNull(edit); + assertEquals(1, edit.getChanges().size()); + List<TextEdit> fileChanges = edit.getChanges().get(uri); assertNotNull(fileChanges); assertEquals(1, fileChanges.size()); assertEquals(new Range(new Position(6, 0), @@ -2894,7 +2895,6 @@ public class ServerTest extends NbTestCase { try (Writer w = new FileWriter(src)) { w.write(code); } - WorkspaceEdit[] edit = new WorkspaceEdit[1]; Launcher<LanguageServer> serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() { @Override public void telemetryEvent(Object arg0) { @@ -2921,8 +2921,7 @@ public class ServerTest extends NbTestCase { @Override public CompletableFuture<ApplyWorkspaceEditResponse> applyEdit(ApplyWorkspaceEditParams params) { - edit[0] = params.getEdit(); - return CompletableFuture.completedFuture(new ApplyWorkspaceEditResponse(false)); + throw new UnsupportedOperationException("Not supported yet."); } @Override @@ -2981,13 +2980,12 @@ public class ServerTest extends NbTestCase { .filter(a -> Bundle.DN_GenerateConstructor().equals(a.getTitle())) .findAny(); assertTrue(generateConstructor.isPresent()); - server.getWorkspaceService().executeCommand(new ExecuteCommandParams(generateConstructor.get().getCommand().getCommand(), generateConstructor.get().getCommand().getArguments())).get(); - int cnt = 0; - while(edit[0] == null && cnt++ < 10) { - Thread.sleep(1000); - } - assertEquals(1, edit[0].getChanges().size()); - List<TextEdit> fileChanges = edit[0].getChanges().get(uri); + CodeAction resolvedCodeAction = server.getTextDocumentService().resolveCodeAction(generateConstructor.get()).get(); + assertNotNull(resolvedCodeAction); + WorkspaceEdit edit = resolvedCodeAction.getEdit(); + assertNotNull(edit); + assertEquals(1, edit.getChanges().size()); + List<TextEdit> fileChanges = edit.getChanges().get(uri); assertNotNull(fileChanges); assertEquals(1, fileChanges.size()); assertEquals(new Range(new Position(3, 0), @@ -3010,7 +3008,6 @@ public class ServerTest extends NbTestCase { try (Writer w = new FileWriter(src)) { w.write(code); } - WorkspaceEdit[] edit = new WorkspaceEdit[1]; Launcher<LanguageServer> serverLauncher = LSPLauncher.createClientLauncher(new LspClient() { @Override public void telemetryEvent(Object arg0) { @@ -3037,8 +3034,7 @@ public class ServerTest extends NbTestCase { @Override public CompletableFuture<ApplyWorkspaceEditResponse> applyEdit(ApplyWorkspaceEditParams params) { - edit[0] = params.getEdit(); - return CompletableFuture.completedFuture(new ApplyWorkspaceEditResponse(false)); + throw new UnsupportedOperationException("Not supported yet."); } }, client.getInputStream(), client.getOutputStream()); @@ -3049,7 +3045,7 @@ public class ServerTest extends NbTestCase { server.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(new TextDocumentItem(uri, "java", 0, code))); VersionedTextDocumentIdentifier id = new VersionedTextDocumentIdentifier(src.toURI().toString(), 1); List<Either<Command, CodeAction>> codeActions = server.getTextDocumentService().codeAction(new CodeActionParams(id, new Range(new Position(3, 0), new Position(3, 0)), new CodeActionContext(Arrays.asList(), Arrays.asList(CodeActionKind.Source)))).get(); - assertEquals(9, codeActions.size()); + assertEquals(10, codeActions.size()); Optional<CodeAction> generateGetterSetter = codeActions.stream() .filter(Either::isRight) @@ -3057,9 +3053,12 @@ public class ServerTest extends NbTestCase { .filter(a -> Bundle.DN_GenerateGetterSetterFor("f2").equals(a.getTitle())) .findAny(); assertTrue(generateGetterSetter.isPresent()); - server.getWorkspaceService().executeCommand(new ExecuteCommandParams(generateGetterSetter.get().getCommand().getCommand(), generateGetterSetter.get().getCommand().getArguments())).get(); - assertEquals(1, edit[0].getChanges().size()); - List<TextEdit> fileChanges = edit[0].getChanges().get(uri); + CodeAction resolvedCodeAction = server.getTextDocumentService().resolveCodeAction(generateGetterSetter.get()).get(); + assertNotNull(resolvedCodeAction); + WorkspaceEdit edit = resolvedCodeAction.getEdit(); + assertNotNull(edit); + assertEquals(1, edit.getChanges().size()); + List<TextEdit> fileChanges = edit.getChanges().get(uri); assertNotNull(fileChanges); assertEquals(1, fileChanges.size()); assertEquals(new Range(new Position(3, 0), @@ -3076,7 +3075,7 @@ public class ServerTest extends NbTestCase { fileChanges.get(0).getNewText()); server.getTextDocumentService().didChange(new DidChangeTextDocumentParams(id, Arrays.asList(new TextDocumentContentChangeEvent(fileChanges.get(0).getRange(), 0, fileChanges.get(0).getNewText())))); codeActions = server.getTextDocumentService().codeAction(new CodeActionParams(id, new Range(new Position(3, 0), new Position(3, 0)), new CodeActionContext(Arrays.asList(), Arrays.asList(CodeActionKind.Source)))).get(); - assertEquals(7, codeActions.size()); + assertEquals(8, codeActions.size()); Optional<CodeAction> generateGetter = codeActions.stream() .filter(Either::isRight) @@ -3084,9 +3083,12 @@ public class ServerTest extends NbTestCase { .filter(a -> Bundle.DN_GenerateGetterFor("f1").equals(a.getTitle())) .findAny(); assertTrue(generateGetter.isPresent()); - server.getWorkspaceService().executeCommand(new ExecuteCommandParams(generateGetter.get().getCommand().getCommand(), generateGetter.get().getCommand().getArguments())).get(); - assertEquals(1, edit[0].getChanges().size()); - fileChanges = edit[0].getChanges().get(uri); + resolvedCodeAction = server.getTextDocumentService().resolveCodeAction(generateGetter.get()).get(); + assertNotNull(resolvedCodeAction); + edit = resolvedCodeAction.getEdit(); + assertNotNull(edit); + assertEquals(1, edit.getChanges().size()); + fileChanges = edit.getChanges().get(uri); assertNotNull(fileChanges); assertEquals(1, fileChanges.size()); assertEquals(new Range(new Position(11, 0), @@ -3108,7 +3110,6 @@ public class ServerTest extends NbTestCase { try (Writer w = new FileWriter(src)) { w.write(code); } - WorkspaceEdit[] edit = new WorkspaceEdit[1]; Launcher<LanguageServer> serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() { @Override public void telemetryEvent(Object arg0) { @@ -3135,8 +3136,7 @@ public class ServerTest extends NbTestCase { @Override public CompletableFuture<ApplyWorkspaceEditResponse> applyEdit(ApplyWorkspaceEditParams params) { - edit[0] = params.getEdit(); - return CompletableFuture.completedFuture(new ApplyWorkspaceEditResponse(false)); + throw new UnsupportedOperationException("Not supported yet."); } @Override @@ -3187,7 +3187,7 @@ public class ServerTest extends NbTestCase { server.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(new TextDocumentItem(uri, "java", 0, code))); VersionedTextDocumentIdentifier id = new VersionedTextDocumentIdentifier(src.toURI().toString(), 1); List<Either<Command, CodeAction>> codeActions = server.getTextDocumentService().codeAction(new CodeActionParams(id, new Range(new Position(2, 0), new Position(2, 0)), new CodeActionContext(Arrays.asList(), Arrays.asList(CodeActionKind.Source)))).get(); - assertEquals(7, codeActions.size()); + assertEquals(8, codeActions.size()); Optional<CodeAction> generateConstructor = codeActions.stream() .filter(Either::isRight) @@ -3195,13 +3195,12 @@ public class ServerTest extends NbTestCase { .filter(a -> Bundle.DN_GenerateConstructor().equals(a.getTitle())) .findAny(); assertTrue(generateConstructor.isPresent()); - server.getWorkspaceService().executeCommand(new ExecuteCommandParams(generateConstructor.get().getCommand().getCommand(), generateConstructor.get().getCommand().getArguments())).get(); - int cnt = 0; - while(edit[0] == null && cnt++ < 10) { - Thread.sleep(1000); - } - assertEquals(1, edit[0].getChanges().size()); - List<TextEdit> fileChanges = edit[0].getChanges().get(uri); + CodeAction resolvedCodeAction = server.getTextDocumentService().resolveCodeAction(generateConstructor.get()).get(); + assertNotNull(resolvedCodeAction); + WorkspaceEdit edit = resolvedCodeAction.getEdit(); + assertNotNull(edit); + assertEquals(1, edit.getChanges().size()); + List<TextEdit> fileChanges = edit.getChanges().get(uri); assertNotNull(fileChanges); assertEquals(1, fileChanges.size()); assertEquals(new Range(new Position(2, 0), @@ -3239,7 +3238,6 @@ public class ServerTest extends NbTestCase { try (Writer w = new FileWriter(src)) { w.write(code); } - WorkspaceEdit[] edit = new WorkspaceEdit[1]; Launcher<LanguageServer> serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() { @Override public void telemetryEvent(Object arg0) { @@ -3266,8 +3264,7 @@ public class ServerTest extends NbTestCase { @Override public CompletableFuture<ApplyWorkspaceEditResponse> applyEdit(ApplyWorkspaceEditParams params) { - edit[0] = params.getEdit(); - return CompletableFuture.completedFuture(new ApplyWorkspaceEditResponse(false)); + throw new UnsupportedOperationException("Not supported yet."); } @Override @@ -3318,7 +3315,7 @@ public class ServerTest extends NbTestCase { server.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(new TextDocumentItem(uri, "java", 0, code))); VersionedTextDocumentIdentifier id = new VersionedTextDocumentIdentifier(src.toURI().toString(), 1); List<Either<Command, CodeAction>> codeActions = server.getTextDocumentService().codeAction(new CodeActionParams(id, new Range(new Position(5, 0), new Position(5, 0)), new CodeActionContext(Arrays.asList(), Arrays.asList(CodeActionKind.Source)))).get(); - assertEquals(9, codeActions.size()); + assertEquals(10, codeActions.size()); Optional<CodeAction> generateEquals = codeActions.stream() .filter(Either::isRight) @@ -3326,13 +3323,12 @@ public class ServerTest extends NbTestCase { .filter(a -> Bundle.DN_GenerateEquals().equals(a.getTitle())) .findAny(); assertTrue(generateEquals.isPresent()); - server.getWorkspaceService().executeCommand(new ExecuteCommandParams(generateEquals.get().getCommand().getCommand(), generateEquals.get().getCommand().getArguments())).get(); - int cnt = 0; - while(edit[0] == null && cnt++ < 10) { - Thread.sleep(1000); - } - assertEquals(1, edit[0].getChanges().size()); - List<TextEdit> fileChanges = edit[0].getChanges().get(uri); + CodeAction resolvedCodeAction = server.getTextDocumentService().resolveCodeAction(generateEquals.get()).get(); + assertNotNull(resolvedCodeAction); + WorkspaceEdit edit = resolvedCodeAction.getEdit(); + assertNotNull(edit); + assertEquals(1, edit.getChanges().size()); + List<TextEdit> fileChanges = edit.getChanges().get(uri); assertNotNull(fileChanges); assertEquals(1, fileChanges.size()); assertEquals(new Range(new Position(13, 0), @@ -3368,7 +3364,6 @@ public class ServerTest extends NbTestCase { try (Writer w = new FileWriter(src)) { w.write(code); } - WorkspaceEdit[] edit = new WorkspaceEdit[1]; Launcher<LanguageServer> serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() { @Override public void telemetryEvent(Object arg0) { @@ -3395,8 +3390,7 @@ public class ServerTest extends NbTestCase { @Override public CompletableFuture<ApplyWorkspaceEditResponse> applyEdit(ApplyWorkspaceEditParams params) { - edit[0] = params.getEdit(); - return CompletableFuture.completedFuture(new ApplyWorkspaceEditResponse(false)); + throw new UnsupportedOperationException("Not supported yet."); } @Override @@ -3447,7 +3441,7 @@ public class ServerTest extends NbTestCase { server.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(new TextDocumentItem(uri, "java", 0, code))); VersionedTextDocumentIdentifier id = new VersionedTextDocumentIdentifier(src.toURI().toString(), 1); List<Either<Command, CodeAction>> codeActions = server.getTextDocumentService().codeAction(new CodeActionParams(id, new Range(new Position(2, 0), new Position(2, 0)), new CodeActionContext(Arrays.asList(), Arrays.asList(CodeActionKind.Source)))).get(); - assertEquals(7, codeActions.size()); + assertEquals(8, codeActions.size()); Optional<CodeAction> generateToString = codeActions.stream() .filter(Either::isRight) @@ -3455,13 +3449,12 @@ public class ServerTest extends NbTestCase { .filter(a -> Bundle.DN_GenerateToString().equals(a.getTitle())) .findAny(); assertTrue(generateToString.isPresent()); - server.getWorkspaceService().executeCommand(new ExecuteCommandParams(generateToString.get().getCommand().getCommand(), generateToString.get().getCommand().getArguments())).get(); - int cnt = 0; - while(edit[0] == null && cnt++ < 10) { - Thread.sleep(1000); - } - assertEquals(1, edit[0].getChanges().size()); - List<TextEdit> fileChanges = edit[0].getChanges().get(uri); + CodeAction resolvedCodeAction = server.getTextDocumentService().resolveCodeAction(generateToString.get()).get(); + assertNotNull(resolvedCodeAction); + WorkspaceEdit edit = resolvedCodeAction.getEdit(); + assertNotNull(edit); + assertEquals(1, edit.getChanges().size()); + List<TextEdit> fileChanges = edit.getChanges().get(uri); assertNotNull(fileChanges); assertEquals(1, fileChanges.size()); assertEquals(new Range(new Position(2, 0), @@ -3488,7 +3481,6 @@ public class ServerTest extends NbTestCase { try (Writer w = new FileWriter(src)) { w.write(code); } - WorkspaceEdit[] edit = new WorkspaceEdit[1]; Launcher<LanguageServer> serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() { @Override public void telemetryEvent(Object arg0) { @@ -3515,8 +3507,7 @@ public class ServerTest extends NbTestCase { @Override public CompletableFuture<ApplyWorkspaceEditResponse> applyEdit(ApplyWorkspaceEditParams params) { - edit[0] = params.getEdit(); - return CompletableFuture.completedFuture(new ApplyWorkspaceEditResponse(false)); + throw new UnsupportedOperationException("Not supported yet."); } @Override @@ -3567,7 +3558,7 @@ public class ServerTest extends NbTestCase { server.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(new TextDocumentItem(uri, "java", 0, code))); VersionedTextDocumentIdentifier id = new VersionedTextDocumentIdentifier(src.toURI().toString(), 1); List<Either<Command, CodeAction>> codeActions = server.getTextDocumentService().codeAction(new CodeActionParams(id, new Range(new Position(2, 0), new Position(2, 0)), new CodeActionContext(Arrays.asList(), Arrays.asList(CodeActionKind.Source)))).get(); - assertEquals(7, codeActions.size()); + assertEquals(8, codeActions.size()); Optional<CodeAction> generateDelegateMethod = codeActions.stream() .filter(Either::isRight) @@ -3575,13 +3566,12 @@ public class ServerTest extends NbTestCase { .filter(a -> Bundle.DN_GenerateDelegateMethod().equals(a.getTitle())) .findAny(); assertTrue(generateDelegateMethod.isPresent()); - server.getWorkspaceService().executeCommand(new ExecuteCommandParams(generateDelegateMethod.get().getCommand().getCommand(), generateDelegateMethod.get().getCommand().getArguments())).get(); - int cnt = 0; - while(edit[0] == null && cnt++ < 10) { - Thread.sleep(1000); - } - assertEquals(1, edit[0].getChanges().size()); - List<TextEdit> fileChanges = edit[0].getChanges().get(uri); + CodeAction resolvedCodeAction = server.getTextDocumentService().resolveCodeAction(generateDelegateMethod.get()).get(); + assertNotNull(resolvedCodeAction); + WorkspaceEdit edit = resolvedCodeAction.getEdit(); + assertNotNull(edit); + assertEquals(1, edit.getChanges().size()); + List<TextEdit> fileChanges = edit.getChanges().get(uri); assertNotNull(fileChanges); assertEquals(2, fileChanges.size()); assertEquals(new Range(new Position(0, 0), @@ -3612,7 +3602,6 @@ public class ServerTest extends NbTestCase { try (Writer w = new FileWriter(src)) { w.write(code); } - WorkspaceEdit[] edit = new WorkspaceEdit[1]; Launcher<LanguageServer> serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() { @Override public void telemetryEvent(Object arg0) { @@ -3639,8 +3628,7 @@ public class ServerTest extends NbTestCase { @Override public CompletableFuture<ApplyWorkspaceEditResponse> applyEdit(ApplyWorkspaceEditParams params) { - edit[0] = params.getEdit(); - return CompletableFuture.completedFuture(new ApplyWorkspaceEditResponse(false)); + throw new UnsupportedOperationException("Not supported yet."); } @Override @@ -3691,7 +3679,7 @@ public class ServerTest extends NbTestCase { server.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(new TextDocumentItem(uri, "java", 0, code))); VersionedTextDocumentIdentifier id = new VersionedTextDocumentIdentifier(src.toURI().toString(), 1); List<Either<Command, CodeAction>> codeActions = server.getTextDocumentService().codeAction(new CodeActionParams(id, new Range(new Position(2, 0), new Position(2, 0)), new CodeActionContext(Arrays.asList(), Arrays.asList(CodeActionKind.Source)))).get(); - assertEquals(7, codeActions.size()); + assertEquals(8, codeActions.size()); Optional<CodeAction> generateOverrideMethod = codeActions.stream() .filter(Either::isRight) @@ -3699,13 +3687,12 @@ public class ServerTest extends NbTestCase { .filter(a -> Bundle.DN_GenerateOverrideMethod().equals(a.getTitle())) .findAny(); assertTrue(generateOverrideMethod.isPresent()); - server.getWorkspaceService().executeCommand(new ExecuteCommandParams(generateOverrideMethod.get().getCommand().getCommand(), generateOverrideMethod.get().getCommand().getArguments())).get(); - int cnt = 0; - while(edit[0] == null && cnt++ < 10) { - Thread.sleep(1000); - } - assertEquals(1, edit[0].getChanges().size()); - List<TextEdit> fileChanges = edit[0].getChanges().get(uri); + CodeAction resolvedCodeAction = server.getTextDocumentService().resolveCodeAction(generateOverrideMethod.get()).get(); + assertNotNull(resolvedCodeAction); + WorkspaceEdit edit = resolvedCodeAction.getEdit(); + assertNotNull(edit); + assertEquals(1, edit.getChanges().size()); + List<TextEdit> fileChanges = edit.getChanges().get(uri); assertNotNull(fileChanges); assertEquals(1, fileChanges.size()); assertEquals(new Range(new Position(2, 0), @@ -3733,7 +3720,6 @@ public class ServerTest extends NbTestCase { try (Writer w = new FileWriter(src)) { w.write(code); } - WorkspaceEdit[] edit = new WorkspaceEdit[1]; Launcher<LanguageServer> serverLauncher = LSPLauncher.createClientLauncher(new NbCodeLanguageClient() { @Override public void telemetryEvent(Object arg0) { @@ -3760,8 +3746,7 @@ public class ServerTest extends NbTestCase { @Override public CompletableFuture<ApplyWorkspaceEditResponse> applyEdit(ApplyWorkspaceEditParams params) { - edit[0] = params.getEdit(); - return CompletableFuture.completedFuture(new ApplyWorkspaceEditResponse(false)); + throw new UnsupportedOperationException("Not supported yet."); } @Override @@ -3812,7 +3797,7 @@ public class ServerTest extends NbTestCase { server.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(new TextDocumentItem(uri, "java", 0, code))); VersionedTextDocumentIdentifier id = new VersionedTextDocumentIdentifier(src.toURI().toString(), 1); List<Either<Command, CodeAction>> codeActions = server.getTextDocumentService().codeAction(new CodeActionParams(id, new Range(new Position(2, 0), new Position(2, 0)), new CodeActionContext(Arrays.asList(), Arrays.asList(CodeActionKind.Source)))).get(); - assertEquals(7, codeActions.size()); + assertEquals(8, codeActions.size()); Optional<CodeAction> generateLogger = codeActions.stream() .filter(Either::isRight) @@ -3820,13 +3805,12 @@ public class ServerTest extends NbTestCase { .filter(a -> Bundle.DN_GenerateLogger().equals(a.getTitle())) .findAny(); assertTrue(generateLogger.isPresent()); - server.getWorkspaceService().executeCommand(new ExecuteCommandParams(generateLogger.get().getCommand().getCommand(), generateLogger.get().getCommand().getArguments())).get(); - int cnt = 0; - while(edit[0] == null && cnt++ < 10) { - Thread.sleep(1000); - } - assertEquals(1, edit[0].getChanges().size()); - List<TextEdit> fileChanges = edit[0].getChanges().get(uri); + CodeAction resolvedCodeAction = server.getTextDocumentService().resolveCodeAction(generateLogger.get()).get(); + assertNotNull(resolvedCodeAction); + WorkspaceEdit edit = resolvedCodeAction.getEdit(); + assertNotNull(edit); + assertEquals(1, edit.getChanges().size()); + List<TextEdit> fileChanges = edit.getChanges().get(uri); assertNotNull(fileChanges); assertEquals(2, fileChanges.size()); assertEquals(new Range(new Position(0, 0), @@ -3842,6 +3826,82 @@ public class ServerTest extends NbTestCase { fileChanges.get(1).getNewText()); } + public void testSourceActionOrganizeImports() throws Exception { + File src = new File(getWorkDir(), "Test.java"); + src.getParentFile().mkdirs(); + String code = "import java.util.List;\n" + + "import java.util.ArrayList;\n" + + "import java.util.Collection;\n" + + "\n" + + "public class Test {\n" + + " private final List<String> names = new ArrayList<>();\n" + + "}\n"; + try (Writer w = new FileWriter(src)) { + w.write(code); + } + Launcher<LanguageServer> serverLauncher = LSPLauncher.createClientLauncher(new LspClient() { + @Override + public void telemetryEvent(Object arg0) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void publishDiagnostics(PublishDiagnosticsParams params) { + } + + @Override + public void showMessage(MessageParams arg0) { + } + + @Override + public CompletableFuture<MessageActionItem> showMessageRequest(ShowMessageRequestParams arg0) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void logMessage(MessageParams arg0) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public CompletableFuture<ApplyWorkspaceEditResponse> applyEdit(ApplyWorkspaceEditParams params) { + throw new UnsupportedOperationException("Not supported yet."); + } + + }, client.getInputStream(), client.getOutputStream()); + serverLauncher.startListening(); + LanguageServer server = serverLauncher.getRemoteProxy(); + server.initialize(new InitializeParams()).get(); + String uri = src.toURI().toString(); + server.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(new TextDocumentItem(uri, "java", 0, code))); + VersionedTextDocumentIdentifier id = new VersionedTextDocumentIdentifier(src.toURI().toString(), 1); + List<Either<Command, CodeAction>> codeActions = server.getTextDocumentService().codeAction(new CodeActionParams(id, new Range(new Position(6, 0), new Position(6, 0)), new CodeActionContext(Arrays.asList(), Arrays.asList(CodeActionKind.Source)))).get(); + assertEquals(8, codeActions.size()); + Optional<CodeAction> organizeImports = + codeActions.stream() + .filter(Either::isRight) + .map(Either::getRight) + .filter(a -> Bundle.DN_OrganizeImports().equals(a.getTitle())) + .findAny(); + assertTrue(organizeImports.isPresent()); + CodeAction resolvedCodeAction = server.getTextDocumentService().resolveCodeAction(organizeImports.get()).get(); + assertNotNull(resolvedCodeAction); + WorkspaceEdit edit = resolvedCodeAction.getEdit(); + assertNotNull(edit); + assertEquals(1, edit.getChanges().size()); + List<TextEdit> fileChanges = edit.getChanges().get(uri); + assertNotNull(fileChanges); + assertEquals(2, fileChanges.size()); + assertEquals(new Range(new Position(0, 0), + new Position(1, 0)), + fileChanges.get(0).getRange()); + assertEquals("", fileChanges.get(0).getNewText()); + assertEquals(new Range(new Position(2, 17), + new Position(2, 27)), + fileChanges.get(1).getRange()); + assertEquals("List", fileChanges.get(1).getNewText()); + } + public void testRenameDocumentChangesCapabilitiesRenameOp() throws Exception { doTestRename(init -> { WorkspaceEditCapabilities wec = new WorkspaceEditCapabilities(); diff --git a/java/java.lsp.server/vscode/package.json b/java/java.lsp.server/vscode/package.json index d2cdd7f..94f9793 100644 --- a/java/java.lsp.server/vscode/package.json +++ b/java/java.lsp.server/vscode/package.json @@ -108,6 +108,34 @@ "type": "integer", "default": 100, "description": "Timeout (in milliseconds) for loading Javadoc in code completion (-1 for unlimited)" + }, + "netbeans.java.onSave.organizeImports": { + "type": "boolean", + "default": true, + "description": "Enable organize imports action on a document save" + }, + "netbeans.java.imports.groups": { + "type": "array", + "description": "Groups of import statements (specified by their package prefixes) and their sorting order. Import statements within a group are ordered alphabetically", + "default": [ + "java", + "javax", + "org", + "com", + "" + ] + }, + "netbeans.java.imports.countForUsingStarImport": { + "type": "integer", + "description": "Class count to use a star-import", + "default": 999, + "minimum": 1 + }, + "netbeans.java.imports.countForUsingStaticStarImport": { + "type": "integer", + "description": "Members count to use a static star-import", + "default": 999, + "minimum": 1 } } }, diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts index 2263916..008d5d8 100644 --- a/java/java.lsp.server/vscode/src/extension.ts +++ b/java/java.lsp.server/vscode/src/extension.ts @@ -568,7 +568,7 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex // Register the server for java documents documentSelector: documentSelectors, synchronize: { - configurationSection: 'java', + configurationSection: 'netbeans.java.imports', fileEvents: [ workspace.createFileSystemWatcher('**/*.java') ] --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org For additional commands, e-mail: commits-h...@netbeans.apache.org For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists