| // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| library test.services.completion.dart; |
| |
| import 'dart:async'; |
| |
| import 'package:analysis_services/completion/completion_computer.dart'; |
| import 'package:analysis_services/completion/completion_suggestion.dart'; |
| import 'package:analysis_services/search/search_engine.dart'; |
| import 'package:analysis_services/src/completion/imported_type_computer.dart'; |
| import 'package:analyzer/src/generated/ast.dart'; |
| import 'package:analyzer/src/generated/element.dart'; |
| import 'package:analyzer/src/generated/engine.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:analysis_services/src/completion/local_computer.dart'; |
| |
| /** |
| * Manages code completion for a given Dart file completion request. |
| */ |
| class DartCompletionManager extends CompletionManager { |
| final AnalysisContext context; |
| final Source source; |
| final int offset; |
| final SearchEngine searchEngine; |
| final List<CompletionSuggestion> suggestions = []; |
| List<CompletionComputer> computers; |
| |
| DartCompletionManager(this.context, this.source, this.offset, |
| this.searchEngine); |
| |
| @override |
| void compute() { |
| initComputers(); |
| computeFast(); |
| if (!computers.isEmpty) { |
| computeFull(); |
| } |
| } |
| |
| /** |
| * Compute suggestions based upon cached information only |
| * then send an initial response to the client. |
| */ |
| void computeFast() { |
| CompilationUnit unit = context.parseCompilationUnit(source); |
| AstNode node = new NodeLocator.con1(offset).searchWithin(unit); |
| computers.removeWhere((c) => c.computeFast(unit, node, suggestions)); |
| sendResults(computers.isEmpty); |
| } |
| |
| /** |
| * If there is remaining work to be done, then wait for the unit to be |
| * resolved and request that each remaining computer finish their work. |
| */ |
| void computeFull() { |
| waitForAnalysis().then((CompilationUnit unit) { |
| if (unit == null) { |
| sendResults(true); |
| return; |
| } |
| AstNode node = new NodeLocator.con1(offset).searchWithin(unit); |
| int count = computers.length; |
| computers.forEach((c) { |
| c.computeFull(unit, node, suggestions).then((bool changed) { |
| var last = --count == 0; |
| if (changed || last) { |
| sendResults(last); |
| } |
| }); |
| }); |
| }); |
| } |
| |
| /** |
| * Build and initialize the list of completion computers |
| */ |
| void initComputers() { |
| if (computers == null) { |
| computers = [new LocalComputer(), new ImportedTypeComputer()]; |
| } |
| computers.forEach((CompletionComputer c) { |
| c.context = context; |
| c.source = source; |
| c.offset = offset; |
| c.searchEngine = searchEngine; |
| }); |
| } |
| |
| /** |
| * Send the current list of suggestions to the client. |
| */ |
| void sendResults(bool last) { |
| controller.add(new CompletionResult(offset, 0, suggestions, last)); |
| if (last) { |
| controller.close(); |
| } |
| } |
| |
| /** |
| * Wait for analysis to be complete and return the resolved unit |
| * or `null` if the unit could not be resolved. |
| */ |
| Future<CompilationUnit> waitForAnalysis() { |
| LibraryElement library = context.getLibraryElement(source); |
| if (library != null) { |
| var unit = context.getResolvedCompilationUnit(source, library); |
| if (unit != null) { |
| return new Future.value(unit); |
| } |
| } |
| //TODO (danrubel) Determine if analysis is complete but unit not resolved |
| return new Future(waitForAnalysis); |
| } |
| } |