| // Copyright (c) 2018, 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. | |
| import 'dart:async'; | |
| import 'package:analysis_server/src/protocol_server.dart' | |
| show | |
| CompletionSuggestion, | |
| RuntimeCompletionExpression, | |
| RuntimeCompletionVariable, | |
| SourceEdit; | |
| import 'package:analysis_server/src/provisional/completion/completion_core.dart'; | |
| import 'package:analysis_server/src/services/completion/completion_core.dart'; | |
| import 'package:analysis_server/src/services/completion/completion_performance.dart'; | |
| import 'package:analysis_server/src/services/completion/dart/completion_manager.dart'; | |
| import 'package:analyzer/file_system/file_system.dart'; | |
| import 'package:analyzer/src/dart/analysis/driver.dart'; | |
| import 'package:analyzer/src/dart/analysis/file_state.dart'; | |
| import 'package:analyzer_plugin/protocol/protocol_common.dart'; | |
| import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart'; | |
| class RuntimeCompletionComputer { | |
| final ResourceProvider resourceProvider; | |
| final FileContentOverlay fileContentOverlay; | |
| final AnalysisDriver analysisDriver; | |
| final String code; | |
| final int offset; | |
| final String contextFile; | |
| final int contextOffset; | |
| final List<RuntimeCompletionVariable> variables; | |
| final List<RuntimeCompletionExpression> expressions; | |
| RuntimeCompletionComputer( | |
| this.resourceProvider, | |
| this.fileContentOverlay, | |
| this.analysisDriver, | |
| this.code, | |
| this.offset, | |
| this.contextFile, | |
| this.contextOffset, | |
| this.variables, | |
| this.expressions); | |
| Future<RuntimeCompletionResult> compute() async { | |
| var contextResult = await analysisDriver.getResult(contextFile); | |
| var session = contextResult.session; | |
| const codeMarker = '__code_\_'; | |
| // Insert the code being completed at the context offset. | |
| var changeBuilder = new DartChangeBuilder(session); | |
| int nextImportPrefixIndex = 0; | |
| await changeBuilder.addFileEdit(contextFile, (builder) { | |
| builder.addInsertion(contextOffset, (builder) { | |
| builder.writeln('{'); | |
| // TODO(scheglov) Use variables. | |
| builder.write(codeMarker); | |
| builder.writeln(';'); | |
| builder.writeln('}'); | |
| }); | |
| }, importPrefixGenerator: (uri) => '__prefix${nextImportPrefixIndex++}'); | |
| // Compute the patched context file content. | |
| String targetCode = SourceEdit.applySequence( | |
| contextResult.content, | |
| changeBuilder.sourceChange.edits[0].edits, | |
| ); | |
| // Insert the code being completed. | |
| int targetOffset = targetCode.indexOf(codeMarker) + offset; | |
| targetCode = targetCode.replaceAll(codeMarker, code); | |
| // Update the context file content to include the code being completed. | |
| // Then resolve it, and restore the file to its initial state. | |
| AnalysisResult targetResult; | |
| String contentFileOverlay = fileContentOverlay[contextFile]; | |
| try { | |
| fileContentOverlay[contextFile] = targetCode; | |
| analysisDriver.changeFile(contextFile); | |
| targetResult = await analysisDriver.getResult(contextFile); | |
| } finally { | |
| fileContentOverlay[contextFile] = contentFileOverlay; | |
| analysisDriver.changeFile(contextFile); | |
| } | |
| CompletionContributor contributor = new DartCompletionManager(); | |
| CompletionRequestImpl request = new CompletionRequestImpl( | |
| targetResult, | |
| targetOffset, | |
| new CompletionPerformance(), | |
| ); | |
| var suggestions = await contributor.computeSuggestions(request); | |
| // Remove completions with synthetic import prefixes. | |
| suggestions.removeWhere((s) => s.completion.startsWith('__prefix')); | |
| // TODO(scheglov) Add support for expressions. | |
| var expressions = <RuntimeCompletionExpression>[]; | |
| return new RuntimeCompletionResult(expressions, suggestions); | |
| } | |
| } | |
| /// The result of performing runtime completion. | |
| class RuntimeCompletionResult { | |
| final List<RuntimeCompletionExpression> expressions; | |
| final List<CompletionSuggestion> suggestions; | |
| RuntimeCompletionResult(this.expressions, this.suggestions); | |
| } |