Change LSP edit mapping to support multi-file edits

Change-Id: I1f29b8b49d27b4e3b7f44ea86aa1a33c7b6ee48b
Reviewed-on: https://dart-review.googlesource.com/c/86926
Commit-Queue: Danny Tuppeny <dantup@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Danny Tuppeny 2018-12-12 07:27:20 +00:00 committed by commit-bot@chromium.org
parent 566ae2490d
commit 1c1a5a99ed
4 changed files with 61 additions and 45 deletions

View file

@ -8,6 +8,7 @@ import 'package:analysis_server/src/lsp/constants.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
import 'package:analysis_server/src/lsp/mapping.dart';
import 'package:analysis_server/src/lsp/source_edits.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/error/error.dart' as engine;
import 'package:analyzer/src/dart/scanner/scanner.dart' as engine;
@ -34,9 +35,7 @@ abstract class SimpleEditCommandHandler
final workspaceEdit = toWorkspaceEdit(
server.clientCapabilities?.workspace,
docIdentifier,
unit.lineInfo,
edits,
[new FileEditInformation(docIdentifier, unit.lineInfo, edits)],
);
// Send the edit to the client via a applyEdit request (this is a request

View file

@ -14,6 +14,9 @@ import 'package:analysis_server/src/lsp/mapping.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
typedef ActionHandler = Future<List<Either2<Command, CodeAction>>> Function(
HashSet<CodeActionKind>, bool, String, Range, ResolvedUnitResult);
class CodeActionHandler extends MessageHandler<CodeActionParams,
List<Either2<Command, CodeAction>>> {
CodeActionHandler(LspAnalysisServer server) : super(server);
@ -53,71 +56,78 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
clientSupportedCodeActionKinds,
clientSupportsLiteralCodeActions,
path.result,
params.range,
unit));
}
List<Either2<Command, CodeAction>> _getAssistActions(
Future<List<Either2<Command, CodeAction>>> _getAssistActions(
HashSet<CodeActionKind> clientSupportedCodeActionKinds,
bool clientSupportsLiteralCodeActions,
String path,
Range range,
ResolvedUnitResult unit,
) {
) async {
// TODO(dantup): Implement assists.
return [];
}
ErrorOr<List<Either2<Command, CodeAction>>> _getCodeActions(
Future<ErrorOr<List<Either2<Command, CodeAction>>>> _getCodeActions(
HashSet<CodeActionKind> clientSupportedCodeActionKinds,
bool clientSupportsLiteralCodeActions,
String path,
Range range,
ResolvedUnitResult unit,
) {
) async {
// Join the results of computing all of our different types.
final allActions = [
final List<ActionHandler> handlers = [
_getSourceActions,
_getAssistActions,
_getRefactorActions,
_getFixActions,
]
.expand((f) => f(
clientSupportedCodeActionKinds,
clientSupportsLiteralCodeActions,
path,
unit,
))
.toList();
return success(allActions);
];
final futures = handlers.map((f) => f(
clientSupportedCodeActionKinds,
clientSupportsLiteralCodeActions,
path,
range,
unit,
));
final results = await Future.wait(futures);
final flatResults = results.expand((x) => x).toList();
return success(flatResults);
}
List<Either2<Command, CodeAction>> _getFixActions(
Future<List<Either2<Command, CodeAction>>> _getFixActions(
HashSet<CodeActionKind> clientSupportedCodeActionKinds,
bool clientSupportsLiteralCodeActions,
String path,
Range range,
ResolvedUnitResult unit,
) {
) async {
// TODO(dantup): Implement fixes.
return [];
}
List<Either2<Command, CodeAction>> _getRefactorActions(
Future<List<Either2<Command, CodeAction>>> _getRefactorActions(
HashSet<CodeActionKind> clientSupportedCodeActionKinds,
bool clientSupportsLiteralCodeActions,
String path,
Range range,
ResolvedUnitResult unit,
) {
) async {
// TODO(dantup): Implement refactors.
return [];
}
/// Gets "Source" CodeActions, which are actions that apply to whole files of
/// source such as Sort Members and Organise Imports.
List<Either2<Command, CodeAction>> _getSourceActions(
Future<List<Either2<Command, CodeAction>>> _getSourceActions(
HashSet<CodeActionKind> clientSupportedCodeActionKinds,
bool clientSupportsLiteralCodeActions,
String path,
Range range,
ResolvedUnitResult unit,
) {
) async {
// The source actions supported are only valid for Dart files.
if (!AnalysisEngine.isDartFileName(path)) {
return [];

View file

@ -7,12 +7,14 @@ import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/constants.dart' as lsp;
import 'package:analysis_server/src/lsp/dartdoc.dart';
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart' as lsp;
import 'package:analysis_server/src/lsp/source_edits.dart';
import 'package:analysis_server/src/protocol_server.dart' as server
hide AnalysisError;
import 'package:analyzer/dart/analysis/results.dart' as server;
import 'package:analyzer/error/error.dart' as server;
import 'package:analyzer/source/line_info.dart' as server;
import 'package:analyzer/src/generated/source.dart' as server;
import 'package:analyzer_plugin/utilities/fixes/fixes.dart' as server;
const languageSourceName = 'dart';
@ -486,14 +488,10 @@ lsp.SignatureHelp toSignatureHelp(List<lsp.MarkupKind> preferredFormats,
);
}
lsp.TextDocumentEdit toTextDocumentEdit(
VersionedTextDocumentIdentifier doc,
server.LineInfo lineInfo,
List<server.SourceEdit> edits,
) {
lsp.TextDocumentEdit toTextDocumentEdit(FileEditInformation edit) {
return new TextDocumentEdit(
doc,
edits.map((e) => toTextEdit(lineInfo, e)).toList(),
edit.doc,
edit.edits.map((e) => toTextEdit(edit.lineInfo, e)).toList(),
);
}
@ -506,9 +504,7 @@ lsp.TextEdit toTextEdit(server.LineInfo lineInfo, server.SourceEdit edit) {
lsp.WorkspaceEdit toWorkspaceEdit(
WorkspaceClientCapabilities capabilities,
VersionedTextDocumentIdentifier doc,
server.LineInfo lineInfo,
List<server.SourceEdit> edits,
List<FileEditInformation> edits,
) {
final clientSupportsTextDocumentEdits =
capabilities?.workspaceEdit?.documentChanges == true;
@ -520,23 +516,22 @@ lsp.WorkspaceEdit toWorkspaceEdit(
List<
Either4<TextDocumentEdit, CreateFile, RenameFile,
DeleteFile>>>.t1(
[toTextDocumentEdit(doc, lineInfo, edits)],
edits.map(toTextDocumentEdit).toList(),
));
} else {
return new WorkspaceEdit(
toWorkspaceEditChanges(doc, lineInfo, edits), null);
return new WorkspaceEdit(toWorkspaceEditChanges(edits), null);
}
}
Map<String, List<TextEdit>> toWorkspaceEditChanges(
VersionedTextDocumentIdentifier doc,
server.LineInfo lineInfo,
List<server.SourceEdit> edits,
) {
// TODO(dantup): Fix codegen for WorkspaceEditChanges to be Map<String, TextEdit>
return Map<String, List<TextEdit>>.fromEntries(
edits.map((e) => new MapEntry(doc.uri, [toTextEdit(lineInfo, e)])),
);
List<FileEditInformation> edits) {
createEdit(FileEditInformation file) {
final edits =
file.edits.map((edit) => toTextEdit(file.lineInfo, edit)).toList();
return new MapEntry(file.doc.uri, edits);
}
return Map<String, List<TextEdit>>.fromEntries(edits.map(createEdit));
}
lsp.MarkupContent _asMarkup(

View file

@ -1,6 +1,8 @@
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/src/lsp/mapping.dart';
import 'package:analysis_server/src/protocol_server.dart' as server
show SourceEdit;
import 'package:analyzer/source/line_info.dart';
import 'package:dart_style/dart_style.dart';
@ -59,3 +61,13 @@ List<TextEdit> generateEditsForFormatting(String unformattedSource) {
)
];
}
/// Helper class that bundles up all information required when converting server
/// SourceEdits into LSP-compatible WorkspaceEdits.
class FileEditInformation {
final VersionedTextDocumentIdentifier doc;
final LineInfo lineInfo;
final List<server.SourceEdit> edits;
FileEditInformation(this.doc, this.lineInfo, this.edits);
}