Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart

Issue 1531383002: move ReplacementRange into dart specific contributor (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: merge Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 services.completion.dart; 5 library services.completion.dart;
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/provisional/completion/completion_core.dart' 10 import 'package:analysis_server/src/provisional/completion/completion_core.dart'
11 show AnalysisRequest, CompletionContributor, CompletionRequest; 11 show AnalysisRequest, CompletionContributor, CompletionRequest;
12 import 'package:analysis_server/src/provisional/completion/dart/completion_targe t.dart';
13 import 'package:analysis_server/src/services/completion/completion_core.dart'; 12 import 'package:analysis_server/src/services/completion/completion_core.dart';
14 import 'package:analysis_server/src/services/completion/completion_manager.dart' ; 13 import 'package:analysis_server/src/services/completion/completion_manager.dart' ;
15 import 'package:analysis_server/src/services/completion/dart/common_usage_sorter .dart'; 14 import 'package:analysis_server/src/services/completion/dart/common_usage_sorter .dart';
16 import 'package:analysis_server/src/services/completion/dart/contribution_sorter .dart'; 15 import 'package:analysis_server/src/services/completion/dart/contribution_sorter .dart';
17 import 'package:analysis_server/src/services/completion/optype.dart';
18 import 'package:analysis_server/src/services/search/search_engine.dart'; 16 import 'package:analysis_server/src/services/search/search_engine.dart';
19 import 'package:analyzer/file_system/file_system.dart'; 17 import 'package:analyzer/file_system/file_system.dart';
20 import 'package:analyzer/src/generated/ast.dart'; 18 import 'package:analyzer/src/generated/ast.dart';
21 import 'package:analyzer/src/generated/engine.dart'; 19 import 'package:analyzer/src/generated/engine.dart';
22 import 'package:analyzer/src/generated/scanner.dart';
23 import 'package:analyzer/src/generated/source.dart'; 20 import 'package:analyzer/src/generated/source.dart';
24 21
25 /** 22 /**
26 * The base class for contributing code completion suggestions. 23 * The base class for contributing code completion suggestions.
27 */ 24 */
28 abstract class DartCompletionContributor { 25 abstract class DartCompletionContributor {
29 /** 26 /**
30 * Computes the initial set of [CompletionSuggestion]s based on 27 * Computes the initial set of [CompletionSuggestion]s based on
31 * the given completion context. The compilation unit and completion node 28 * the given completion context. The compilation unit and completion node
32 * in the given completion context may not be resolved. 29 * in the given completion context may not be resolved.
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 context, searchEngine, source, newContributors); 81 context, searchEngine, source, newContributors);
85 } 82 }
86 83
87 /** 84 /**
88 * Compute suggestions based upon cached information only 85 * Compute suggestions based upon cached information only
89 * then send an initial response to the client. 86 * then send an initial response to the client.
90 * Return a list of contributors for which [computeFull] should be called 87 * Return a list of contributors for which [computeFull] should be called
91 */ 88 */
92 List<DartCompletionContributor> computeFast( 89 List<DartCompletionContributor> computeFast(
93 DartCompletionRequest request, CompletionPerformance performance) { 90 DartCompletionRequest request, CompletionPerformance performance) {
94 return performance.logElapseTime('computeFast', () { 91 return [];
95 CompilationUnit unit = context.parseCompilationUnit(source);
96 request.unit = unit;
97 request.target = new CompletionTarget.forOffset(unit, request.offset);
98
99 ReplacementRange range =
100 new ReplacementRange.compute(request.offset, request.target);
101 request.replacementOffset = range.offset;
102 request.replacementLength = range.length;
103
104 List<DartCompletionContributor> todo = [];
105 todo.removeWhere((DartCompletionContributor c) {
106 return performance.logElapseTime('computeFast ${c.runtimeType}', () {
107 return c.computeFast(request);
108 });
109 });
110 return todo;
111 });
112 } 92 }
113 93
114 /** 94 /**
115 * If there is remaining work to be done, then wait for the unit to be 95 * If there is remaining work to be done, then wait for the unit to be
116 * resolved and request that each remaining contributor finish their work. 96 * resolved and request that each remaining contributor finish their work.
117 * Return a [Future] that completes when the last notification has been sent. 97 * Return a [Future] that completes when the last notification has been sent.
118 */ 98 */
119 Future computeFull( 99 Future computeFull(
120 DartCompletionRequest request, 100 DartCompletionRequest request,
121 CompletionPerformance performance, 101 CompletionPerformance performance,
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 return null; 173 return null;
194 }, test: (e) => e is AnalysisNotScheduledError); 174 }, test: (e) => e is AnalysisNotScheduledError);
195 } 175 }
196 } 176 }
197 177
198 /** 178 /**
199 * The context in which the completion is requested. 179 * The context in which the completion is requested.
200 */ 180 */
201 class DartCompletionRequest extends CompletionRequestImpl { 181 class DartCompletionRequest extends CompletionRequestImpl {
202 /** 182 /**
203 * The compilation unit in which the completion was requested. This unit
204 * may or may not be resolved when [DartCompletionContributor.computeFast]
205 * is called but is resolved when [DartCompletionContributor.computeFull].
206 */
207 CompilationUnit unit;
208
209 /**
210 * The completion target. This determines what part of the parse tree
211 * will receive the newly inserted text.
212 */
213 CompletionTarget target;
214
215 /**
216 * Information about the types of suggestions that should be included.
217 */
218 OpType _optype;
219
220 /**
221 * The offset of the start of the text to be replaced.
222 * This will be different than the offset used to request the completion
223 * suggestions if there was a portion of an identifier before the original
224 * offset. In particular, the replacementOffset will be the offset of the
225 * beginning of said identifier.
226 */
227 int replacementOffset;
228
229 /**
230 * The length of the text to be replaced if the remainder of the identifier
231 * containing the cursor is to be replaced when the suggestion is applied
232 * (that is, the number of characters in the existing identifier).
233 */
234 int replacementLength;
235
236 /**
237 * The list of suggestions to be sent to the client. 183 * The list of suggestions to be sent to the client.
238 */ 184 */
239 final List<CompletionSuggestion> _suggestions = <CompletionSuggestion>[]; 185 final List<CompletionSuggestion> _suggestions = <CompletionSuggestion>[];
240 186
241 /** 187 /**
242 * The set of completions used to prevent duplicates 188 * The set of completions used to prevent duplicates
243 */ 189 */
244 final Set<String> _completions = new Set<String>(); 190 final Set<String> _completions = new Set<String>();
245 191
246 DartCompletionRequest( 192 DartCompletionRequest(
247 AnalysisContext context, 193 AnalysisContext context,
248 ResourceProvider resourceProvider, 194 ResourceProvider resourceProvider,
249 SearchEngine searchEngine, 195 SearchEngine searchEngine,
250 Source source, 196 Source source,
251 int offset) 197 int offset)
252 : super(context, resourceProvider, searchEngine, source, offset); 198 : super(context, resourceProvider, searchEngine, source, offset);
253 199
254 factory DartCompletionRequest.from(CompletionRequestImpl request) => 200 factory DartCompletionRequest.from(CompletionRequestImpl request) =>
255 new DartCompletionRequest(request.context, request.resourceProvider, 201 new DartCompletionRequest(request.context, request.resourceProvider,
256 request.searchEngine, request.source, request.offset); 202 request.searchEngine, request.source, request.offset);
257 203
258 /** 204 /**
259 * Return the original text from the [replacementOffset] to the [offset]
260 * that can be used to filter the suggestions on the server side.
261 */
262 String get filterText {
263 return context
264 .getContents(source)
265 .data
266 .substring(replacementOffset, offset);
267 }
268
269 /**
270 * Information about the types of suggestions that should be included.
271 * The [target] must be set first.
272 */
273 OpType get optype {
274 if (_optype == null) {
275 _optype = new OpType.forCompletion(target, offset);
276 }
277 return _optype;
278 }
279
280 /**
281 * The list of suggestions to be sent to the client. 205 * The list of suggestions to be sent to the client.
282 */ 206 */
283 Iterable<CompletionSuggestion> get suggestions => _suggestions; 207 Iterable<CompletionSuggestion> get suggestions => _suggestions;
284 208
285 /** 209 /**
286 * Add the given suggestion to the list that is returned to the client as long 210 * Add the given suggestion to the list that is returned to the client as long
287 * as a suggestion with an identical completion has not already been added. 211 * as a suggestion with an identical completion has not already been added.
288 */ 212 */
289 void addSuggestion(CompletionSuggestion suggestion) { 213 void addSuggestion(CompletionSuggestion suggestion) {
290 if (_completions.add(suggestion.completion)) { 214 if (_completions.add(suggestion.completion)) {
291 _suggestions.add(suggestion); 215 _suggestions.add(suggestion);
292 } 216 }
293 } 217 }
294
295 /**
296 * Convert all [CompletionSuggestionKind.INVOCATION] suggestions
297 * to [CompletionSuggestionKind.IDENTIFIER] suggestions.
298 */
299 void convertInvocationsToIdentifiers() {
300 for (int index = _suggestions.length - 1; index >= 0; --index) {
301 CompletionSuggestion suggestion = _suggestions[index];
302 if (suggestion.kind == CompletionSuggestionKind.INVOCATION) {
303 // Create a copy rather than just modifying the existing suggestion
304 // because [DartCompletionCache] may be caching that suggestion
305 // for future completion requests
306 _suggestions[index] = new CompletionSuggestion(
307 CompletionSuggestionKind.IDENTIFIER,
308 suggestion.relevance,
309 suggestion.completion,
310 suggestion.selectionOffset,
311 suggestion.selectionLength,
312 suggestion.isDeprecated,
313 suggestion.isPotential,
314 declaringType: suggestion.declaringType,
315 parameterNames: suggestion.parameterNames,
316 parameterTypes: suggestion.parameterTypes,
317 requiredParameterCount: suggestion.requiredParameterCount,
318 hasNamedParameters: suggestion.hasNamedParameters,
319 returnType: suggestion.returnType,
320 element: suggestion.element);
321 }
322 }
323 }
324 } 218 }
325
326 /**
327 * Utility class for computing the code completion replacement range
328 */
329 class ReplacementRange {
330 int offset;
331 int length;
332
333 ReplacementRange(this.offset, this.length);
334
335 factory ReplacementRange.compute(int requestOffset, CompletionTarget target) {
336 bool isKeywordOrIdentifier(Token token) =>
337 token.type == TokenType.KEYWORD || token.type == TokenType.IDENTIFIER;
338
339 //TODO(danrubel) Ideally this needs to be pushed down into the contributors
340 // but that implies that each suggestion can have a different
341 // replacement offsent/length which would mean an API change
342
343 var entity = target.entity;
344 Token token = entity is AstNode ? entity.beginToken : entity;
345 if (token != null && requestOffset < token.offset) {
346 token = token.previous;
347 }
348 if (token != null) {
349 if (requestOffset == token.offset && !isKeywordOrIdentifier(token)) {
350 // If the insertion point is at the beginning of the current token
351 // and the current token is not an identifier
352 // then check the previous token to see if it should be replaced
353 token = token.previous;
354 }
355 if (token != null && isKeywordOrIdentifier(token)) {
356 if (token.offset <= requestOffset && requestOffset <= token.end) {
357 // Replacement range for typical identifier completion
358 return new ReplacementRange(token.offset, token.length);
359 }
360 }
361 if (token is StringToken) {
362 SimpleStringLiteral uri = new SimpleStringLiteral(token, token.lexeme);
363 Token previous = token.previous;
364 if (previous is KeywordToken) {
365 Keyword keyword = previous.keyword;
366 if (keyword == Keyword.IMPORT ||
367 keyword == Keyword.EXPORT ||
368 keyword == Keyword.PART) {
369 int start = uri.contentsOffset;
370 var end = uri.contentsEnd;
371 if (start <= requestOffset && requestOffset <= end) {
372 // Replacement range for import URI
373 return new ReplacementRange(start, end - start);
374 }
375 }
376 }
377 }
378 }
379 return new ReplacementRange(requestOffset, 0);
380 }
381 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698