9
9
* Red Hat, Inc. - initial API and implementation
10
10
* Fraunhofer FOKUS
11
11
******************************************************************************/
12
- package com .redhat .devtools .intellij .lsp4ij .command .internal ;
13
-
12
+ package com .redhat .devtools .intellij .lsp4ij .commands ;
14
13
15
14
import com .google .gson .Gson ;
16
15
import com .google .gson .JsonArray ;
17
16
import com .google .gson .JsonObject ;
18
17
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 .*;
23
19
import com .intellij .openapi .actionSystem .ex .ActionUtil ;
20
+ import com .intellij .openapi .actionSystem .impl .SimpleDataContext ;
24
21
import com .intellij .openapi .application .Application ;
25
22
import com .intellij .openapi .application .ApplicationManager ;
26
23
import com .intellij .openapi .editor .Document ;
36
33
import org .eclipse .lsp4j .WorkspaceEdit ;
37
34
import org .eclipse .lsp4j .services .LanguageServer ;
38
35
import org .jetbrains .annotations .NotNull ;
39
- import org .jetbrains .annotations .Nullable ;
40
36
import org .slf4j .Logger ;
41
37
import org .slf4j .LoggerFactory ;
42
38
55
51
public class CommandExecutor {
56
52
private static final Logger LOGGER = LoggerFactory .getLogger (CommandExecutor .class );
57
53
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" );
61
57
62
58
/**
63
59
* 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
66
62
* {@code command} is {@code null}, then this method will do nothing. If neither
67
63
* the server, nor the client are able to handle the command explicitly, a
68
64
* heuristic method will try to interpret the command locally.
69
65
*
70
66
* @param command
71
67
* the LSP Command to be executed. If {@code null} this method will
72
68
* 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
75
71
* @param languageServerId
76
72
* the ID of the language server for which the {@code command} is
77
73
* applicable. If {@code null}, the command will not be executed on
78
74
* the language server.
79
75
*/
80
- public static void executeCommand (Project project , Command command , Document document ,
76
+ public static void executeCommand (Project project , Command command , URI documentUri ,
81
77
String languageServerId ) {
82
78
if (command == null ) {
83
79
return ;
84
80
}
85
- if (executeCommandServerSide (project , command , languageServerId , document )) {
81
+ if (executeCommandServerSide (project , command , documentUri , languageServerId )) {
86
82
return ;
87
83
}
88
- if (executeCommandClientSide (command , document )) {
84
+ if (executeCommandClientSide (project , command , documentUri )) {
89
85
return ;
90
86
}
91
87
// 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
+ }
95
94
}
96
95
}
97
96
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 ) {
100
99
if (languageServerId == null ) {
101
100
return false ;
102
101
}
@@ -107,7 +106,7 @@ private static boolean executeCommandServerSide(Project project, Command command
107
106
}
108
107
109
108
try {
110
- CompletableFuture <LanguageServer > languageServerFuture = getLanguageServerForCommand (project , command , document ,
109
+ CompletableFuture <LanguageServer > languageServerFuture = getLanguageServerForCommand (project , command , documentUri ,
111
110
languageServerDefinition );
112
111
if (languageServerFuture == null ) {
113
112
return false ;
@@ -130,55 +129,48 @@ private static boolean executeCommandServerSide(Project project, Command command
130
129
131
130
private static CompletableFuture <LanguageServer > getLanguageServerForCommand (Project project ,
132
131
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
135
139
.getInitializedLanguageServer (document , languageServerDefinition , serverCapabilities -> {
136
140
ExecuteCommandOptions provider = serverCapabilities .getExecuteCommandProvider ();
137
141
return provider != null && provider .getCommands ().contains (command .getCommand ());
138
142
});
139
- return languageServerFuture ;
140
143
}
141
144
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 ) {
144
146
Application workbench = ApplicationManager .getApplication ();
145
147
if (workbench == null ) {
146
148
return false ;
147
149
}
148
- URI context = LSPIJUtils .toUri (document );
149
- AnAction parameterizedCommand = createEclipseCoreCommand (command , context , workbench );
150
+ AnAction parameterizedCommand = createIDEACoreCommand (command );
150
151
if (parameterizedCommand == null ) {
151
152
return false ;
152
153
}
153
- DataContext dataContext = createDataContext (command , context , workbench );
154
+ DataContext dataContext = createDataContext (project , command , documentUri );
154
155
ActionUtil .invokeAction (parameterizedCommand , dataContext , ActionPlaces .UNKNOWN , null , null );
155
156
return true ;
156
157
}
157
158
158
- private static AnAction createEclipseCoreCommand (Command command , URI context ,
159
- Application workbench ) {
159
+ private static AnAction createIDEACoreCommand (Command command ) {
160
160
// Usually commands are defined via extension point, but we synthesize one on
161
161
// the fly for the command ID, since we do not want downstream users
162
162
// having to define them.
163
163
String commandId = command .getCommand ();
164
164
return ActionManager .getInstance ().getAction (commandId );
165
165
}
166
166
167
- private static DataContext createDataContext (Command command , URI context ,
168
- Application workbench ) {
167
+ private static DataContext createDataContext (Project project , Command command , URI documentUri ) {
169
168
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 ();
182
174
}
183
175
184
176
// TODO consider using Entry/SimpleEntry instead
@@ -197,7 +189,7 @@ private static final class Pair<K, V> {
197
189
* Very empirical and unsafe heuristic to turn unknown command arguments into a
198
190
* workspace edit...
199
191
*/
200
- private static WorkspaceEdit createWorkspaceEdit (List <Object > commandArguments , Document document ) {
192
+ private static WorkspaceEdit createWorkspaceEdit (List <Object > commandArguments , @ NotNull Document document ) {
201
193
WorkspaceEdit res = new WorkspaceEdit ();
202
194
Map <String , List <TextEdit >> changes = new HashMap <>();
203
195
res .setChanges (changes );
0 commit comments