OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library domain.completion; | 5 library domain.completion; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 | 8 |
9 import 'package:analysis_server/plugin/protocol/protocol.dart'; | 9 import 'package:analysis_server/plugin/protocol/protocol.dart'; |
10 import 'package:analysis_server/src/analysis_server.dart'; | 10 import 'package:analysis_server/src/analysis_server.dart'; |
11 import 'package:analysis_server/src/constants.dart'; | 11 import 'package:analysis_server/src/constants.dart'; |
12 import 'package:analysis_server/src/provisional/completion/completion_core.dart'
; | 12 import 'package:analysis_server/src/provisional/completion/completion_core.dart'
; |
13 import 'package:analysis_server/src/services/completion/completion_core.dart'; | 13 import 'package:analysis_server/src/services/completion/completion_core.dart'; |
14 import 'package:analysis_server/src/services/completion/completion_performance.d
art'; | 14 import 'package:analysis_server/src/services/completion/completion_performance.d
art'; |
15 import 'package:analyzer/src/generated/engine.dart'; | 15 import 'package:analyzer/src/dart/analysis/driver.dart'; |
| 16 import 'package:analyzer/src/generated/engine.dart' hide AnalysisResult; |
| 17 import 'package:analyzer/src/source/source_resource.dart'; |
16 import 'package:analyzer/src/generated/source.dart'; | 18 import 'package:analyzer/src/generated/source.dart'; |
17 | 19 |
18 /** | 20 /** |
19 * Instances of the class [CompletionDomainHandler] implement a [RequestHandler] | 21 * Instances of the class [CompletionDomainHandler] implement a [RequestHandler] |
20 * that handles requests in the search domain. | 22 * that handles requests in the search domain. |
21 */ | 23 */ |
22 class CompletionDomainHandler implements RequestHandler { | 24 class CompletionDomainHandler implements RequestHandler { |
23 /** | 25 /** |
24 * The maximum number of performance measurements to keep. | 26 * The maximum number of performance measurements to keep. |
25 */ | 27 */ |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 // TODO (danrubel) if request is obsolete | 97 // TODO (danrubel) if request is obsolete |
96 // (processAnalysisRequest returns false) | 98 // (processAnalysisRequest returns false) |
97 // then send empty results | 99 // then send empty results |
98 | 100 |
99 return new CompletionResult( | 101 return new CompletionResult( |
100 request.replacementOffset, request.replacementLength, suggestions); | 102 request.replacementOffset, request.replacementLength, suggestions); |
101 } | 103 } |
102 | 104 |
103 @override | 105 @override |
104 Response handleRequest(Request request) { | 106 Response handleRequest(Request request) { |
105 if (server.options.enableNewAnalysisDriver) { | |
106 // TODO(scheglov) implement for the new analysis driver | |
107 String completionId = (_nextCompletionId++).toString(); | |
108 new Future(() { | |
109 sendCompletionNotification(completionId, 0, 0, []); | |
110 }); | |
111 return new CompletionGetSuggestionsResult(completionId) | |
112 .toResponse(request.id); | |
113 } | |
114 if (server.searchEngine == null) { | 107 if (server.searchEngine == null) { |
115 return new Response.noIndexGenerated(request); | 108 return new Response.noIndexGenerated(request); |
116 } | 109 } |
117 return runZoned(() { | 110 runZoned(() { |
118 try { | 111 try { |
119 String requestName = request.method; | 112 String requestName = request.method; |
120 if (requestName == COMPLETION_GET_SUGGESTIONS) { | 113 if (requestName == COMPLETION_GET_SUGGESTIONS) { |
121 return processRequest(request); | 114 processRequest(request); |
122 } | 115 } |
123 } on RequestFailure catch (exception) { | 116 } on RequestFailure catch (exception) { |
124 return exception.response; | 117 return exception.response; |
125 } | 118 } |
126 return null; | 119 return null; |
127 }, onError: (exception, stackTrace) { | 120 }, onError: (exception, stackTrace) { |
128 server.sendServerErrorNotification( | 121 server.sendServerErrorNotification( |
129 'Failed to handle completion domain request: ${request.toJson()}', | 122 'Failed to handle completion domain request: ${request.toJson()}', |
130 exception, | 123 exception, |
131 stackTrace); | 124 stackTrace); |
132 }); | 125 }); |
| 126 return Response.DELAYED_RESPONSE; |
133 } | 127 } |
134 | 128 |
135 /** | 129 /** |
136 * Process a `completion.getSuggestions` request. | 130 * Process a `completion.getSuggestions` request. |
137 */ | 131 */ |
138 Response processRequest(Request request) { | 132 Future<Null> processRequest(Request request) async { |
139 performance = new CompletionPerformance(); | 133 performance = new CompletionPerformance(); |
140 | 134 |
141 // extract and validate params | 135 // extract and validate params |
142 CompletionGetSuggestionsParams params = | 136 CompletionGetSuggestionsParams params = |
143 new CompletionGetSuggestionsParams.fromRequest(request); | 137 new CompletionGetSuggestionsParams.fromRequest(request); |
144 ContextSourcePair contextSource = server.getContextSourcePair(params.file); | 138 |
145 AnalysisContext context = contextSource.context; | 139 AnalysisResult result; |
146 Source source = contextSource.source; | 140 AnalysisContext context; |
147 if (context == null || !context.exists(source)) { | 141 Source source; |
148 return new Response.unknownSource(request); | 142 if (server.options.enableNewAnalysisDriver) { |
149 } | 143 result = await server.getAnalysisResult(params.file); |
150 TimestampedData<String> contents = context.getContents(source); | 144 |
151 if (params.offset < 0 || params.offset > contents.data.length) { | 145 if (result == null) { |
152 return new Response.invalidParameter( | 146 server.sendResponse(new Response.unknownSource(request)); |
153 request, | 147 return; |
154 'params.offset', | 148 } |
155 'Expected offset between 0 and source length inclusive,' | 149 |
156 ' but found ${params.offset}'); | 150 if (params.offset < 0 || params.offset > result.content.length) { |
| 151 server.sendResponse(new Response.invalidParameter( |
| 152 request, |
| 153 'params.offset', |
| 154 'Expected offset between 0 and source length inclusive,' |
| 155 ' but found ${params.offset}')); |
| 156 return; |
| 157 } |
| 158 |
| 159 source = new FileSource( |
| 160 server.resourceProvider.getFile(result.path), result.uri); |
| 161 } else { |
| 162 ContextSourcePair contextSource = |
| 163 server.getContextSourcePair(params.file); |
| 164 |
| 165 context = contextSource.context; |
| 166 source = contextSource.source; |
| 167 if (context == null || !context.exists(source)) { |
| 168 server.sendResponse(new Response.unknownSource(request)); |
| 169 return; |
| 170 } |
| 171 |
| 172 TimestampedData<String> contents = context.getContents(source); |
| 173 if (params.offset < 0 || params.offset > contents.data.length) { |
| 174 server.sendResponse(new Response.invalidParameter( |
| 175 request, |
| 176 'params.offset', |
| 177 'Expected offset between 0 and source length inclusive,' |
| 178 ' but found ${params.offset}')); |
| 179 return; |
| 180 } |
157 } | 181 } |
158 | 182 |
159 recordRequest(performance, context, source, params.offset); | 183 recordRequest(performance, context, source, params.offset); |
160 | 184 |
161 CompletionRequestImpl completionRequest = new CompletionRequestImpl( | 185 CompletionRequestImpl completionRequest = new CompletionRequestImpl( |
| 186 result, |
162 context, | 187 context, |
163 server.resourceProvider, | 188 server.resourceProvider, |
164 server.searchEngine, | 189 server.searchEngine, |
165 source, | 190 source, |
166 params.offset, | 191 params.offset, |
167 performance); | 192 performance); |
168 String completionId = (_nextCompletionId++).toString(); | 193 String completionId = (_nextCompletionId++).toString(); |
169 | 194 |
170 _abortCurrentRequest(); | 195 _abortCurrentRequest(); |
171 _currentRequest = completionRequest; | 196 _currentRequest = completionRequest; |
172 | 197 |
| 198 // initial response without results |
| 199 server.sendResponse(new CompletionGetSuggestionsResult(completionId) |
| 200 .toResponse(request.id)); |
| 201 |
173 // Compute suggestions in the background | 202 // Compute suggestions in the background |
174 computeSuggestions(completionRequest).then((CompletionResult result) { | 203 computeSuggestions(completionRequest).then((CompletionResult result) { |
175 const SEND_NOTIFICATION_TAG = 'send notification'; | 204 const SEND_NOTIFICATION_TAG = 'send notification'; |
176 performance.logStartTime(SEND_NOTIFICATION_TAG); | 205 performance.logStartTime(SEND_NOTIFICATION_TAG); |
177 sendCompletionNotification(completionId, result.replacementOffset, | 206 sendCompletionNotification(completionId, result.replacementOffset, |
178 result.replacementLength, result.suggestions); | 207 result.replacementLength, result.suggestions); |
179 performance.logElapseTime(SEND_NOTIFICATION_TAG); | 208 performance.logElapseTime(SEND_NOTIFICATION_TAG); |
180 | 209 |
181 performance.notificationCount = 1; | 210 performance.notificationCount = 1; |
182 performance.logFirstNotificationComplete('notification 1 complete'); | 211 performance.logFirstNotificationComplete('notification 1 complete'); |
183 performance.suggestionCountFirst = result.suggestions.length; | 212 performance.suggestionCountFirst = result.suggestions.length; |
184 performance.suggestionCountLast = result.suggestions.length; | 213 performance.suggestionCountLast = result.suggestions.length; |
185 performance.complete(); | 214 performance.complete(); |
186 }).whenComplete(() { | 215 }).whenComplete(() { |
187 if (_currentRequest == completionRequest) { | 216 if (_currentRequest == completionRequest) { |
188 _currentRequest = null; | 217 _currentRequest = null; |
189 } | 218 } |
190 }); | 219 }); |
191 | |
192 // initial response without results | |
193 return new CompletionGetSuggestionsResult(completionId) | |
194 .toResponse(request.id); | |
195 } | 220 } |
196 | 221 |
197 /** | 222 /** |
198 * If tracking code completion performance over time, then | 223 * If tracking code completion performance over time, then |
199 * record addition information about the request in the performance record. | 224 * record addition information about the request in the performance record. |
200 */ | 225 */ |
201 void recordRequest(CompletionPerformance performance, AnalysisContext context, | 226 void recordRequest(CompletionPerformance performance, AnalysisContext context, |
202 Source source, int offset) { | 227 Source source, int offset) { |
203 performance.source = source; | 228 performance.source = source; |
204 if (performanceListMaxLength == 0 || context == null || source == null) { | 229 if (performanceListMaxLength == 0 || context == null || source == null) { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
256 final int replacementOffset; | 281 final int replacementOffset; |
257 | 282 |
258 /** | 283 /** |
259 * The suggested completions. | 284 * The suggested completions. |
260 */ | 285 */ |
261 final List<CompletionSuggestion> suggestions; | 286 final List<CompletionSuggestion> suggestions; |
262 | 287 |
263 CompletionResult( | 288 CompletionResult( |
264 this.replacementOffset, this.replacementLength, this.suggestions); | 289 this.replacementOffset, this.replacementLength, this.suggestions); |
265 } | 290 } |
OLD | NEW |