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>
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart
index 202b79d..24c7b7d 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart
@@ -8,6 +8,7 @@
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 @@
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
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index 2deb2ca..cb8ecd3 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -14,6 +14,9 @@
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 @@
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 [];
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index dc7f763..acf79d6 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -7,12 +7,14 @@
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.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.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 @@
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(
diff --git a/pkg/analysis_server/lib/src/lsp/source_edits.dart b/pkg/analysis_server/lib/src/lsp/source_edits.dart
index 200ac92..76cee3ef 100644
--- a/pkg/analysis_server/lib/src/lsp/source_edits.dart
+++ b/pkg/analysis_server/lib/src/lsp/source_edits.dart
@@ -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 @@
)
];
}
+
+/// 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);
+}