blob: 2e75ddda4181e075e42c96d9becab287515633f0 [file] [log] [blame]
// 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.
import 'dart:collection';
import 'dart:core';
import 'package:analysis_server/protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/source.dart';
/// Instances of the class [ExecutionDomainHandler] implement a [RequestHandler]
/// that handles requests in the `execution` domain.
class ExecutionDomainHandler implements RequestHandler {
/// The analysis server that is using this handler to process requests.
final AnalysisServer server;
/// The next execution context identifier to be returned.
int nextContextId = 0;
/// A table mapping execution context id's to the root of the context.
final Map<String, String> contextMap = HashMap<String, String>();
/// Initialize a newly created handler to handle requests for the given
/// [server].
ExecutionDomainHandler(this.server);
/// Implement the `execution.createContext` request.
Response createContext(Request request) {
var file = ExecutionCreateContextParams.fromRequest(request).contextRoot;
var contextId = (nextContextId++).toString();
contextMap[contextId] = file;
return ExecutionCreateContextResult(contextId).toResponse(request.id);
}
/// Implement the `execution.deleteContext` request.
Response deleteContext(Request request) {
var contextId = ExecutionDeleteContextParams.fromRequest(request).id;
contextMap.remove(contextId);
return ExecutionDeleteContextResult().toResponse(request.id);
}
/// Implement the 'execution.getSuggestions' request.
void getSuggestions(Request request) async {
// var params = new ExecutionGetSuggestionsParams.fromRequest(request);
// var computer = new RuntimeCompletionComputer(
// server.resourceProvider,
// server.fileContentOverlay,
// server.getAnalysisDriver(params.contextFile),
// params.code,
// params.offset,
// params.contextFile,
// params.contextOffset,
// params.variables,
// params.expressions);
// RuntimeCompletionResult completionResult = await computer.compute();
//
// // Send the response.
// var result = new ExecutionGetSuggestionsResult(
// suggestions: completionResult.suggestions,
// expressions: completionResult.expressions);
// TODO(brianwilkerson) Re-enable this functionality after implementing a
// way of computing suggestions that is compatible with AnalysisSession.
var result = ExecutionGetSuggestionsResult(
suggestions: <CompletionSuggestion>[],
expressions: <RuntimeCompletionExpression>[]);
server.sendResponse(result.toResponse(request.id));
}
@override
Response handleRequest(Request request) {
try {
var requestName = request.method;
if (requestName == EXECUTION_REQUEST_CREATE_CONTEXT) {
return createContext(request);
} else if (requestName == EXECUTION_REQUEST_DELETE_CONTEXT) {
return deleteContext(request);
} else if (requestName == EXECUTION_REQUEST_GET_SUGGESTIONS) {
getSuggestions(request);
return Response.DELAYED_RESPONSE;
} else if (requestName == EXECUTION_REQUEST_MAP_URI) {
return mapUri(request);
} else if (requestName == EXECUTION_REQUEST_SET_SUBSCRIPTIONS) {
return setSubscriptions(request);
}
} on RequestFailure catch (exception) {
return exception.response;
}
return null;
}
/// Implement the 'execution.mapUri' request.
Response mapUri(Request request) {
var params = ExecutionMapUriParams.fromRequest(request);
var contextId = params.id;
var path = contextMap[contextId];
if (path == null) {
return Response.invalidParameter(request, 'id',
'There is no execution context with an id of $contextId');
}
var driver = server.getAnalysisDriver(path);
if (driver == null) {
return Response.invalidExecutionContext(request, contextId);
}
var sourceFactory = driver.sourceFactory;
var file = params.file;
var uri = params.uri;
if (file != null) {
if (uri != null) {
return Response.invalidParameter(request, 'file',
'Either file or uri must be provided, but not both');
}
var resource = server.resourceProvider.getResource(file);
if (!resource.exists) {
return Response.invalidParameter(request, 'file', 'Must exist');
} else if (resource is! File) {
return Response.invalidParameter(
request, 'file', 'Must not refer to a directory');
}
var source = driver.fsState.getFileForPath(file).source;
if (source.uriKind != UriKind.FILE_URI) {
uri = source.uri.toString();
} else {
uri = sourceFactory.restoreUri(source).toString();
}
return ExecutionMapUriResult(uri: uri).toResponse(request.id);
} else if (uri != null) {
var source = sourceFactory.forUri(uri);
if (source == null) {
return Response.invalidParameter(request, 'uri', 'Invalid URI');
}
file = source.fullName;
return ExecutionMapUriResult(file: file).toResponse(request.id);
}
return Response.invalidParameter(
request, 'file', 'Either file or uri must be provided');
}
/// Implement the 'execution.setSubscriptions' request.
Response setSubscriptions(Request request) {
// Under the analysis driver, setSubscriptions() becomes a no-op.
return ExecutionSetSubscriptionsResult().toResponse(request.id);
}
}