7
7
8
8
import com .google .common .annotations .VisibleForTesting ;
9
9
import com .google .common .collect .Lists ;
10
- import com .google .common .util .concurrent .Uninterruptibles ;
11
10
import com .google .dart .server .AnalysisServerListenerAdapter ;
12
11
import com .google .dart .server .ResponseListener ;
13
- import com .google .gson .JsonArray ;
14
12
import com .google .gson .JsonElement ;
15
13
import com .google .gson .JsonObject ;
16
14
import com .google .gson .JsonPrimitive ;
17
15
import com .intellij .openapi .Disposable ;
16
+ import com .intellij .openapi .application .Application ;
18
17
import com .intellij .openapi .application .ApplicationManager ;
19
18
import com .intellij .openapi .project .Project ;
20
19
import com .intellij .openapi .util .Disposer ;
21
- import com .intellij .openapi .util .io .FileUtil ;
22
- import com .intellij .openapi .vfs .VirtualFile ;
23
20
import com .intellij .util .Consumer ;
24
21
import com .jetbrains .lang .dart .analyzer .DartAnalysisServerService ;
25
22
import io .flutter .utils .JsonUtils ;
26
- import org .dartlang .analysis .server .protocol .*;
23
+ import org .dartlang .analysis .server .protocol .AnalysisError ;
24
+ import org .dartlang .analysis .server .protocol .FlutterOutline ;
25
+ import org .dartlang .analysis .server .protocol .FlutterService ;
27
26
import org .jetbrains .annotations .NotNull ;
28
27
import org .jetbrains .annotations .Nullable ;
29
28
30
29
import java .util .*;
31
- import java .util .concurrent .CompletableFuture ;
32
- import java .util .concurrent .CountDownLatch ;
33
- import java .util .concurrent .TimeUnit ;
34
- import java .util .concurrent .atomic .AtomicReference ;
35
30
36
31
public class FlutterDartAnalysisServer implements Disposable {
37
32
private static final String FLUTTER_NOTIFICATION_OUTLINE = "flutter.outline" ;
38
- private static final String FLUTTER_NOTIFICATION_OUTLINE_KEY = "\" flutter.outline\" " ;
39
33
40
34
@ NotNull final Project project ;
41
35
@@ -70,7 +64,9 @@ public String getSdkVersion() {
70
64
return getAnalysisService ().getSdkVersion ();
71
65
}
72
66
73
- /** @noinspection BooleanMethodIsAlwaysInverted*/
67
+ /**
68
+ * @noinspection BooleanMethodIsAlwaysInverted
69
+ */
74
70
public boolean isServerConnected () {
75
71
return !getSdkVersion ().isEmpty ();
76
72
}
@@ -108,18 +104,19 @@ public void computedErrors(String file, List<AnalysisError> errors) {
108
104
}
109
105
110
106
public void addOutlineListener (@ NotNull final String filePath , @ NotNull final FlutterOutlineListener listener ) {
111
- if (!isServerConnected ()) {
107
+ if (!isServerConnected ()) {
112
108
return ;
113
109
}
114
110
synchronized (fileOutlineListeners ) {
115
- final List <FlutterOutlineListener > listeners = fileOutlineListeners .computeIfAbsent (getAnalysisService ().getLocalFileUri (filePath ), k -> new ArrayList <>());
111
+ final List <FlutterOutlineListener > listeners =
112
+ fileOutlineListeners .computeIfAbsent (getAnalysisService ().getLocalFileUri (filePath ), k -> new ArrayList <>());
116
113
listeners .add (listener );
117
114
}
118
115
addSubscription (FlutterService .OUTLINE , filePath );
119
116
}
120
117
121
118
public void removeOutlineListener (@ NotNull final String filePath , @ NotNull final FlutterOutlineListener listener ) {
122
- if (!isServerConnected ()) {
119
+ if (!isServerConnected ()) {
123
120
return ;
124
121
}
125
122
final boolean removeSubscription ;
@@ -138,7 +135,7 @@ public void removeOutlineListener(@NotNull final String filePath, @NotNull final
138
135
* Note that <code>filePath</code> must be an absolute path.
139
136
*/
140
137
private void addSubscription (@ NotNull final String service , @ NotNull final String filePath ) {
141
- if (!isServerConnected ()) {
138
+ if (!isServerConnected ()) {
142
139
return ;
143
140
}
144
141
final List <String > files = subscriptions .computeIfAbsent (service , k -> new ArrayList <>());
@@ -155,7 +152,7 @@ private void addSubscription(@NotNull final String service, @NotNull final Strin
155
152
* Note that <code>filePath</code> must be an absolute path.
156
153
*/
157
154
private void removeSubscription (@ NotNull final String service , @ NotNull final String filePath ) {
158
- if (!isServerConnected ()) {
155
+ if (!isServerConnected ()) {
159
156
return ;
160
157
}
161
158
final String filePathOrUri = getAnalysisService ().getLocalFileUri (filePath );
@@ -166,89 +163,39 @@ private void removeSubscription(@NotNull final String service, @NotNull final St
166
163
}
167
164
168
165
private void sendSubscriptions () {
169
- if (!isServerConnected ()) {
166
+ if (!isServerConnected ()) {
170
167
return ;
171
168
}
172
169
DartAnalysisServerService analysisService = getAnalysisService ();
173
170
final String id = analysisService .generateUniqueId ();
174
- analysisService .sendRequest (id , FlutterRequestUtilities .generateAnalysisSetSubscriptions (id , subscriptions ));
175
- }
176
-
177
- @ NotNull
178
- public List <SourceChange > edit_getAssists (@ NotNull VirtualFile file , int offset , int length ) {
179
- DartAnalysisServerService analysisService = getAnalysisService ();
180
- return analysisService .edit_getAssists (file , offset , length );
181
- }
182
-
183
- @ Nullable
184
- public CompletableFuture <List <FlutterWidgetProperty >> getWidgetDescription (@ NotNull VirtualFile file , int _offset ) {
185
- final CompletableFuture <List <FlutterWidgetProperty >> result = new CompletableFuture <>();
186
- final String filePath = FileUtil .toSystemDependentName (file .getPath ());
187
- DartAnalysisServerService analysisService = getAnalysisService ();
188
- final int offset = analysisService .getOriginalOffset (file , _offset );
189
-
190
- final String id = analysisService .generateUniqueId ();
191
- synchronized (responseConsumers ) {
192
- responseConsumers .put (id , (resultObject ) -> {
193
- try {
194
- final JsonArray propertiesObject = resultObject .getAsJsonArray ("properties" );
195
- final ArrayList <FlutterWidgetProperty > properties = new ArrayList <>();
196
- for (JsonElement propertyObject : propertiesObject ) {
197
- properties .add (FlutterWidgetProperty .fromJson (propertyObject .getAsJsonObject ()));
198
- }
199
- result .complete (properties );
200
- }
201
- catch (Throwable ignored ) {
202
- }
203
- });
171
+ if (id != null ) {
172
+ analysisService .sendRequest (id , FlutterRequestUtilities .generateAnalysisSetSubscriptions (id , subscriptions ));
204
173
}
205
-
206
- final JsonObject request = FlutterRequestUtilities .generateFlutterGetWidgetDescription (id , filePath , offset );
207
- analysisService .sendRequest (id , request );
208
-
209
- return result ;
210
174
}
211
175
212
-
213
- @ Nullable
214
- public SourceChange setWidgetPropertyValue (int propertyId , FlutterWidgetPropertyValue value ) {
215
- final CountDownLatch latch = new CountDownLatch (1 );
216
- final AtomicReference <SourceChange > result = new AtomicReference <>();
217
- DartAnalysisServerService analysisService = getAnalysisService ();
218
- final String id = analysisService .generateUniqueId ();
219
- synchronized (responseConsumers ) {
220
- responseConsumers .put (id , (resultObject ) -> {
221
- try {
222
- final JsonObject propertiesObject = resultObject .getAsJsonObject ("change" );
223
- result .set (SourceChange .fromJson (propertiesObject ));
224
- }
225
- catch (Throwable ignored ) {
176
+ private void processString (@ Nullable String jsonString ) {
177
+ if (jsonString == null ) return ;
178
+ if (isDisposed ) return ;
179
+ Application application = ApplicationManager .getApplication ();
180
+ if (application != null ) {
181
+ application .executeOnPooledThread (() -> {
182
+ // Short circuit just in case we have been disposed in the time it took
183
+ // for us to get around to listening for the response.
184
+ if (isDisposed ) return ;
185
+ JsonElement jsonElement = JsonUtils .parseString (jsonString );
186
+ if (jsonElement != null ) {
187
+ processResponse (jsonElement .getAsJsonObject ());
226
188
}
227
- latch .countDown ();
228
189
});
229
190
}
230
-
231
- final JsonObject request = FlutterRequestUtilities .generateFlutterSetWidgetPropertyValue (id , propertyId , value );
232
- analysisService .sendRequest (id , request );
233
-
234
- Uninterruptibles .awaitUninterruptibly (latch , 100 , TimeUnit .MILLISECONDS );
235
- return result .get ();
236
- }
237
-
238
- private void processString (String jsonString ) {
239
- if (isDisposed ) return ;
240
- ApplicationManager .getApplication ().executeOnPooledThread (() -> {
241
- // Short circuit just in case we have been disposed in the time it took
242
- // for us to get around to listening for the response.
243
- if (isDisposed ) return ;
244
- processResponse (JsonUtils .parseString (jsonString ).getAsJsonObject ());
245
- });
246
191
}
247
192
248
193
/**
249
194
* Handle the given {@link JsonObject} response.
250
195
*/
251
- private void processResponse (JsonObject response ) {
196
+ private void processResponse (@ Nullable JsonObject response ) {
197
+ if (response == null ) return ;
198
+
252
199
final JsonElement eventName = response .get ("event" );
253
200
if (eventName != null && eventName .isJsonPrimitive ()) {
254
201
processNotification (response , eventName );
@@ -284,6 +231,7 @@ private void processResponse(JsonObject response) {
284
231
/**
285
232
* Attempts to handle the given {@link JsonObject} as a notification.
286
233
*/
234
+ @ SuppressWarnings ("DataFlowIssue" ) // Ignore for de-marshalling JSON objects.
287
235
private void processNotification (JsonObject response , @ NotNull JsonElement eventName ) {
288
236
// If we add code to handle more event types below, update the filter in processString().
289
237
final String event = eventName .getAsString ();
@@ -304,7 +252,9 @@ private void processNotification(JsonObject response, @NotNull JsonElement event
304
252
}
305
253
if (listenersUpdated != null ) {
306
254
for (FlutterOutlineListener listener : listenersUpdated ) {
307
- listener .outlineUpdated (file , outline , instrumentedCode );
255
+ if (listener != null && file != null ) {
256
+ listener .outlineUpdated (file , outline , instrumentedCode );
257
+ }
308
258
}
309
259
}
310
260
}
0 commit comments