Skip to content

Commit 22b94b0

Browse files
fbriconangelozerr
authored andcommitted
feat: add command to update microprofile configuration from LSP4MP
Signed-off-by: Fred Bricon <[email protected]>
1 parent 5ffee3d commit 22b94b0

File tree

14 files changed

+215
-97
lines changed

14 files changed

+215
-97
lines changed

src/main/java/com/redhat/devtools/intellij/lsp4ij/AbstractLSPInlayProvider.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,19 @@
2222
import com.intellij.openapi.actionSystem.AnAction;
2323
import com.intellij.openapi.actionSystem.AnActionEvent;
2424
import com.intellij.openapi.actionSystem.DataContext;
25-
import com.intellij.openapi.actionSystem.DataKey;
2625
import com.intellij.openapi.actionSystem.Presentation;
2726
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
2827
import com.intellij.ui.layout.LCFlags;
2928
import com.intellij.ui.layout.LayoutKt;
29+
import com.redhat.devtools.intellij.lsp4ij.commands.CommandExecutor;
3030
import org.eclipse.lsp4j.Command;
3131
import org.jetbrains.annotations.NotNull;
3232
import org.jetbrains.annotations.Nullable;
3333

3434
import javax.swing.JComponent;
3535
import java.awt.Component;
36-
import java.util.Map;
3736

3837
public abstract class AbstractLSPInlayProvider implements InlayHintsProvider<NoSettings> {
39-
public static final DataKey<Command> LSP_COMMAND = DataKey.create("com.redhat.devtools.intellij.quarkus.lsp4ij.command");
4038

4139
private SettingsKey<NoSettings> key = new SettingsKey<>("LSP.hints");
4240

@@ -92,7 +90,7 @@ protected void executeClientCommand(Component source, Command command) {
9290
if (command != null) {
9391
AnAction action = ActionManager.getInstance().getAction(command.getCommand());
9492
if (action != null) {
95-
DataContext context = SimpleDataContext.getSimpleContext(DataKey.create(LSP_COMMAND.getName()), command, DataManager.getInstance().getDataContext(source));
93+
DataContext context = SimpleDataContext.getSimpleContext(CommandExecutor.LSP_COMMAND, command, DataManager.getInstance().getDataContext(source));
9694
action.actionPerformed(new AnActionEvent(null, context,
9795
ActionPlaces.UNKNOWN, new Presentation(),
9896
ActionManager.getInstance(), 0));

src/main/java/com/redhat/devtools/intellij/lsp4ij/LSPIJUtils.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,19 @@ public static Document getDocument(VirtualFile docFile) {
145145
return FileDocumentManager.getInstance().getDocument(docFile);
146146
}
147147

148+
/**
149+
* Returns the @{@link Document} associated to the given @{@link URI}, or <code>null</code> if there's no match.
150+
* @param documentUri the uri of the Document to return
151+
* @return the @{@link Document} associated to <code>documentUri</code>, or <code>null</code>
152+
*/
153+
public static @Nullable Document getDocument(URI documentUri) {
154+
if (documentUri == null) {
155+
return null;
156+
}
157+
VirtualFile documentFile = findResourceFor(documentUri.toASCIIString());
158+
return getDocument(documentFile);
159+
}
160+
148161
public static @Nullable Module getProject(@Nullable VirtualFile file) {
149162
if (file == null) {
150163
return null;

src/main/java/com/redhat/devtools/intellij/lsp4ij/LanguageServiceAccessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public CompletableFuture<LanguageServer> getInitializedLanguageServer(Document d
120120
throws IOException {
121121
URI initialPath = LSPIJUtils.toUri(document);
122122
LanguageServerWrapper wrapper = getLSWrapperForConnection(document, lsDefinition, initialPath);
123-
if (capabilitiesComply(wrapper, capabilitiesPredicate)) {
123+
if (wrapper != null && capabilitiesComply(wrapper, capabilitiesPredicate)) {
124124
wrapper.connect(document);
125125
return wrapper.getInitializedServer();
126126
}
Lines changed: 40 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,15 @@
99
* Red Hat, Inc. - initial API and implementation
1010
* Fraunhofer FOKUS
1111
******************************************************************************/
12-
package com.redhat.devtools.intellij.lsp4ij.command.internal;
13-
12+
package com.redhat.devtools.intellij.lsp4ij.commands;
1413

1514
import com.google.gson.Gson;
1615
import com.google.gson.JsonArray;
1716
import com.google.gson.JsonObject;
1817
import com.google.gson.JsonPrimitive;
19-
import com.intellij.openapi.actionSystem.ActionManager;
20-
import com.intellij.openapi.actionSystem.ActionPlaces;
21-
import com.intellij.openapi.actionSystem.AnAction;
22-
import com.intellij.openapi.actionSystem.DataContext;
18+
import com.intellij.openapi.actionSystem.*;
2319
import com.intellij.openapi.actionSystem.ex.ActionUtil;
20+
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
2421
import com.intellij.openapi.application.Application;
2522
import com.intellij.openapi.application.ApplicationManager;
2623
import com.intellij.openapi.editor.Document;
@@ -36,7 +33,6 @@
3633
import org.eclipse.lsp4j.WorkspaceEdit;
3734
import org.eclipse.lsp4j.services.LanguageServer;
3835
import org.jetbrains.annotations.NotNull;
39-
import org.jetbrains.annotations.Nullable;
4036
import org.slf4j.Logger;
4137
import org.slf4j.LoggerFactory;
4238

@@ -55,48 +51,51 @@
5551
public class CommandExecutor {
5652
private static final Logger LOGGER = LoggerFactory.getLogger(CommandExecutor.class);
5753

58-
private static final String LSP_COMMAND_CATEGORY_ID = "org.eclipse.lsp4e.commandCategory"; //$NON-NLS-1$
59-
private static final String LSP_COMMAND_PARAMETER_TYPE_ID = "org.eclipse.lsp4e.commandParameterType"; //$NON-NLS-1$
60-
private static final String LSP_PATH_PARAMETER_TYPE_ID = "org.eclipse.lsp4e.pathParameterType"; //$NON-NLS-1$
54+
public static final DataKey<Command> LSP_COMMAND = DataKey.create("com.redhat.devtools.intellij.quarkus.lsp4ij.command");
55+
56+
public static final DataKey<URI> LSP_COMMAND_DOCUMENT_URI = DataKey.create("com.redhat.devtools.intellij.quarkus.lsp4ij.command.documentUri");
6157

6258
/**
6359
* Will execute the given {@code command} either on a language server,
64-
* supporting the command, or on the client, if an {@link IHandler} is
65-
* registered for the ID of the command (see {@link LSPCommandHandler}). If
60+
* supporting the command, or on the client, if an {@link AnAction} is
61+
* registered for the ID of the command. If
6662
* {@code command} is {@code null}, then this method will do nothing. If neither
6763
* the server, nor the client are able to handle the command explicitly, a
6864
* heuristic method will try to interpret the command locally.
6965
*
7066
* @param command
7167
* the LSP Command to be executed. If {@code null} this method will
7268
* do nothing.
73-
* @param document
74-
* the document for which the command was created
69+
* @param documentUri
70+
* the URI of the document for which the command was created
7571
* @param languageServerId
7672
* the ID of the language server for which the {@code command} is
7773
* applicable. If {@code null}, the command will not be executed on
7874
* the language server.
7975
*/
80-
public static void executeCommand(Project project, Command command, Document document,
76+
public static void executeCommand(Project project, Command command, URI documentUri,
8177
String languageServerId) {
8278
if (command == null) {
8379
return;
8480
}
85-
if (executeCommandServerSide(project, command, languageServerId, document)) {
81+
if (executeCommandServerSide(project, command, documentUri, languageServerId)) {
8682
return;
8783
}
88-
if (executeCommandClientSide(command, document)) {
84+
if (executeCommandClientSide(project, command, documentUri)) {
8985
return;
9086
}
9187
// tentative fallback
92-
if (command.getArguments() != null) {
93-
WorkspaceEdit edit = createWorkspaceEdit(command.getArguments(), document);
94-
LSPIJUtils.applyWorkspaceEdit(edit);
88+
if (documentUri != null && command.getArguments() != null) {
89+
Document document = LSPIJUtils.getDocument(documentUri);
90+
if (document != null) {
91+
WorkspaceEdit edit = createWorkspaceEdit(command.getArguments(), document);
92+
LSPIJUtils.applyWorkspaceEdit(edit);
93+
}
9594
}
9695
}
9796

98-
private static boolean executeCommandServerSide(Project project, Command command, String languageServerId,
99-
Document document) {
97+
private static boolean executeCommandServerSide(Project project, Command command,
98+
URI documentUri, String languageServerId) {
10099
if (languageServerId == null) {
101100
return false;
102101
}
@@ -107,7 +106,7 @@ private static boolean executeCommandServerSide(Project project, Command command
107106
}
108107

109108
try {
110-
CompletableFuture<LanguageServer> languageServerFuture = getLanguageServerForCommand(project, command, document,
109+
CompletableFuture<LanguageServer> languageServerFuture = getLanguageServerForCommand(project, command, documentUri,
111110
languageServerDefinition);
112111
if (languageServerFuture == null) {
113112
return false;
@@ -130,55 +129,48 @@ private static boolean executeCommandServerSide(Project project, Command command
130129

131130
private static CompletableFuture<LanguageServer> getLanguageServerForCommand(Project project,
132131
Command command,
133-
Document document, LanguageServersRegistry.LanguageServerDefinition languageServerDefinition) throws IOException {
134-
CompletableFuture<LanguageServer> languageServerFuture = LanguageServiceAccessor.getInstance(project)
132+
URI documentUri, LanguageServersRegistry.LanguageServerDefinition languageServerDefinition) throws IOException {
133+
Document document = LSPIJUtils.getDocument(documentUri);
134+
if (document == null) {
135+
return null;
136+
}
137+
return LanguageServiceAccessor.getInstance(project)
138+
//TODO pass documentUri instead of document, but looks like that implies non-trivial refactoring
135139
.getInitializedLanguageServer(document, languageServerDefinition, serverCapabilities -> {
136140
ExecuteCommandOptions provider = serverCapabilities.getExecuteCommandProvider();
137141
return provider != null && provider.getCommands().contains(command.getCommand());
138142
});
139-
return languageServerFuture;
140143
}
141144

142-
@SuppressWarnings("unused") // ECJ compiler for some reason thinks handlerService == null is always false
143-
private static boolean executeCommandClientSide(Command command, Document document) {
145+
private static boolean executeCommandClientSide(Project project, Command command, URI documentUri) {
144146
Application workbench = ApplicationManager.getApplication();
145147
if (workbench == null) {
146148
return false;
147149
}
148-
URI context = LSPIJUtils.toUri(document);
149-
AnAction parameterizedCommand = createEclipseCoreCommand(command, context, workbench);
150+
AnAction parameterizedCommand = createIDEACoreCommand(command);
150151
if (parameterizedCommand == null) {
151152
return false;
152153
}
153-
DataContext dataContext = createDataContext(command, context, workbench);
154+
DataContext dataContext = createDataContext(project, command, documentUri);
154155
ActionUtil.invokeAction(parameterizedCommand, dataContext, ActionPlaces.UNKNOWN, null, null);
155156
return true;
156157
}
157158

158-
private static AnAction createEclipseCoreCommand(Command command, URI context,
159-
Application workbench) {
159+
private static AnAction createIDEACoreCommand(Command command) {
160160
// Usually commands are defined via extension point, but we synthesize one on
161161
// the fly for the command ID, since we do not want downstream users
162162
// having to define them.
163163
String commandId = command.getCommand();
164164
return ActionManager.getInstance().getAction(commandId);
165165
}
166166

167-
private static DataContext createDataContext(Command command, URI context,
168-
Application workbench) {
167+
private static DataContext createDataContext(Project project, Command command, URI documentUri) {
169168

170-
return new DataContext() {
171-
@Nullable
172-
@Override
173-
public Object getData(@NotNull String dataId) {
174-
if (LSP_COMMAND_PARAMETER_TYPE_ID.equals(dataId)) {
175-
return command;
176-
} else if (LSP_PATH_PARAMETER_TYPE_ID.equals(dataId)) {
177-
return context;
178-
}
179-
return null;
180-
}
181-
};
169+
SimpleDataContext.Builder contextBuilder = SimpleDataContext.builder();
170+
contextBuilder.add(CommonDataKeys.PROJECT, project)
171+
.add(LSP_COMMAND, command)
172+
.add(LSP_COMMAND_DOCUMENT_URI, documentUri);
173+
return contextBuilder.build();
182174
}
183175

184176
// TODO consider using Entry/SimpleEntry instead
@@ -197,7 +189,7 @@ private static final class Pair<K, V> {
197189
* Very empirical and unsafe heuristic to turn unknown command arguments into a
198190
* workspace edit...
199191
*/
200-
private static WorkspaceEdit createWorkspaceEdit(List<Object> commandArguments, Document document) {
192+
private static WorkspaceEdit createWorkspaceEdit(List<Object> commandArguments, @NotNull Document document) {
201193
WorkspaceEdit res = new WorkspaceEdit();
202194
Map<String, List<TextEdit>> changes = new HashMap<>();
203195
res.setChanges(changes);

src/main/java/com/redhat/devtools/intellij/lsp4ij/operations/codeactions/LSPLazyCodeActionIntentionAction.java

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@
2424
import com.intellij.util.IncorrectOperationException;
2525
import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils;
2626
import com.redhat.devtools.intellij.lsp4ij.LanguageServerWrapper;
27+
import com.redhat.devtools.intellij.lsp4ij.commands.CommandExecutor;
2728
import org.apache.commons.lang.StringUtils;
28-
import org.eclipse.lsp4j.*;
29+
import org.eclipse.lsp4j.CodeAction;
30+
import org.eclipse.lsp4j.CodeActionOptions;
31+
import org.eclipse.lsp4j.Command;
32+
import org.eclipse.lsp4j.ServerCapabilities;
2933
import org.eclipse.lsp4j.jsonrpc.messages.Either;
3034
import org.jetbrains.annotations.NotNull;
3135

@@ -71,6 +75,7 @@ public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file
7175

7276
@Override
7377
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
78+
String serverId = getLanguageServerWrapper().serverDefinition.id;
7479
if (codeAction != null) {
7580
if (codeAction.getEdit() == null && codeAction.getCommand() == null && isCodeActionResolveSupported()) {
7681
// Unresolved code action "edit" property. Resolve it.
@@ -80,52 +85,34 @@ public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws
8085
.thenAccept(resolved -> {
8186
ApplicationManager.getApplication().invokeLater(() -> {
8287
DocumentUtil.writeInRunUndoTransparentAction(() -> {
83-
apply(resolved != null ? resolved : codeAction, project);
88+
apply(resolved != null ? resolved : codeAction, project, file, serverId);
8489
});
8590
});
8691
})
8792
);
8893
} else {
89-
apply(codeAction, project);
94+
apply(codeAction, project, file, serverId);
9095
}
9196
} else if (command != null) {
92-
executeCommand(command, project);
97+
executeCommand(command, project, file, serverId);
9398
} else {
9499
// Should never get here
95100
}
96101
}
97102

98-
private void apply(CodeAction codeaction, @NotNull Project project) {
103+
private void apply(CodeAction codeaction, @NotNull Project project, PsiFile file, String serverId ) {
99104
if (codeaction != null) {
100105
if (codeaction.getEdit() != null) {
101106
LSPIJUtils.applyWorkspaceEdit(codeaction.getEdit(), codeaction.getTitle());
102107
}
103108
if (codeaction.getCommand() != null) {
104-
executeCommand(codeaction.getCommand(), project);
109+
executeCommand(codeaction.getCommand(), project, file, serverId);
105110
}
106111
}
107112
}
108113

109-
private void executeCommand(Command command, @NotNull Project project) {
110-
if (!canSupportCommand(command)) {
111-
return;
112-
}
113-
ExecuteCommandParams params = new ExecuteCommandParams();
114-
params.setCommand(command.getCommand());
115-
params.setArguments(command.getArguments());
116-
getLanguageServerWrapper()
117-
.getInitializedServer()
118-
.thenApply(ls -> ls.getWorkspaceService().executeCommand(params)
119-
);
120-
}
121-
122-
private boolean canSupportCommand(Command command) {
123-
ServerCapabilities capabilities = getLanguageServerWrapper().getServerCapabilities();
124-
if (capabilities != null) {
125-
ExecuteCommandOptions provider = capabilities.getExecuteCommandProvider();
126-
return (provider != null && provider.getCommands().contains(command.getCommand()));
127-
}
128-
return false;
114+
private void executeCommand(Command command, @NotNull Project project, PsiFile file, String serverId) {
115+
CommandExecutor.executeCommand(project, command, LSPIJUtils.toUri(file), serverId);
129116
}
130117

131118
private LanguageServerWrapper getLanguageServerWrapper() {

src/main/java/com/redhat/devtools/intellij/lsp4ij/operations/completion/LSPCompletionProposal.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils;
2828
import com.redhat.devtools.intellij.lsp4ij.LanguageServerItem;
2929
import com.redhat.devtools.intellij.lsp4ij.LanguageServiceAccessor;
30-
import com.redhat.devtools.intellij.lsp4ij.command.internal.CommandExecutor;
30+
import com.redhat.devtools.intellij.lsp4ij.commands.CommandExecutor;
3131
import com.redhat.devtools.intellij.lsp4ij.operations.completion.snippet.LspSnippetIndentOptions;
3232
import org.apache.commons.lang.StringUtils;
3333
import org.eclipse.lsp4j.*;
@@ -37,6 +37,7 @@
3737
import org.slf4j.Logger;
3838
import org.slf4j.LoggerFactory;
3939

40+
import java.net.URI;
4041
import java.util.*;
4142
import java.util.concurrent.CancellationException;
4243
import java.util.concurrent.ExecutionException;
@@ -265,25 +266,26 @@ protected void apply(Document document, char trigger, int stateMask, int offset)
265266
// Execute custom command of the completion item if needed
266267
Command command = item.getCommand();
267268
if (command != null) {
268-
executeCustomCommand(command, document);
269+
executeCustomCommand(command, LSPIJUtils.toUri(document));
269270
}
270271
} catch (RuntimeException ex) {
271272
LOGGER.warn(ex.getLocalizedMessage(), ex);
272273
}
273274
}
274275

276+
275277
/**
276278
* Execute custom command of the completion item.
277-
*
278-
* @param document
279+
* @param command
280+
* @param documentUri
279281
*/
280-
private void executeCustomCommand(@NotNull Command command, Document document) {
282+
private void executeCustomCommand(@NotNull Command command, URI documentUri) {
281283
Project project = editor.getProject();
282284
// Execute custom command of the completion item.
283285
LanguageServiceAccessor.getInstance(project)
284286
.resolveServerDefinition(languageServer.getServer()).map(definition -> definition.id)
285287
.ifPresent(id -> {
286-
CommandExecutor.executeCommand(project, command, document, id);
288+
CommandExecutor.executeCommand(project, command, documentUri, id);
287289
});
288290

289291
}

src/main/java/com/redhat/devtools/intellij/lsp4mp4ij/psi/core/command/MicroprofileOpenURIAction.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import com.intellij.ide.BrowserUtil;
55
import com.intellij.openapi.actionSystem.AnAction;
66
import com.intellij.openapi.actionSystem.AnActionEvent;
7-
import com.redhat.devtools.intellij.lsp4ij.operations.codelens.LSPCodelensInlayProvider;
7+
import com.redhat.devtools.intellij.lsp4ij.commands.CommandExecutor;
88

99
import java.util.List;
1010

@@ -20,7 +20,7 @@ public void actionPerformed(AnActionEvent e) {
2020

2121
private String getURL(AnActionEvent e) {
2222
String url = null;
23-
List<Object> arguments = e.getData(LSPCodelensInlayProvider.LSP_COMMAND).getArguments();
23+
List<Object> arguments = e.getData(CommandExecutor.LSP_COMMAND).getArguments();
2424
if (!arguments.isEmpty()) {
2525
Object arg = arguments.get(0);
2626
if (arg instanceof JsonPrimitive) {

0 commit comments

Comments
 (0)