Skip to content

Commit

Permalink
LSP: Organize imports action added. (apache#3317)
Browse files Browse the repository at this point in the history
  • Loading branch information
dbalek authored Nov 15, 2021
1 parent 77cd083 commit 4a4528e
Show file tree
Hide file tree
Showing 21 changed files with 857 additions and 476 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public List<CodeAction> getCodeActions(ResultIterator resultIterator, CodeAction
}
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@

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;
Expand All @@ -47,26 +50,44 @@
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,19 @@
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;
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;
Expand All @@ -43,7 +47,6 @@
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;
Expand All @@ -68,9 +71,11 @@
@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() {
Expand Down Expand Up @@ -169,62 +174,101 @@ public List<CodeAction> getCodeActions(ResultIterator resultIterator, CodeAction
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);
Expand All @@ -247,11 +291,10 @@ private void generate(NbCodeLanguageClient client, String uri, int offset, List<
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;
}
}
Loading

0 comments on commit 4a4528e

Please sign in to comment.