Send cursor position and linked edit groups down with quick fixes (#442)
diff --git a/doc/generated/dartservices.dart b/doc/generated/dartservices.dart
index 383784a..a83bd79 100644
--- a/doc/generated/dartservices.dart
+++ b/doc/generated/dartservices.dart
@@ -471,7 +471,9 @@
class CandidateFix {
core.List<SourceEdit> edits;
+ core.List<LinkedEditGroup> linkedEditGroups;
core.String message;
+ core.int selectionOffset;
CandidateFix();
@@ -481,9 +483,17 @@
.map<SourceEdit>((value) => new SourceEdit.fromJson(value))
.toList();
}
+ if (_json.containsKey("linkedEditGroups")) {
+ linkedEditGroups = (_json["linkedEditGroups"] as core.List)
+ .map<LinkedEditGroup>((value) => new LinkedEditGroup.fromJson(value))
+ .toList();
+ }
if (_json.containsKey("message")) {
message = _json["message"];
}
+ if (_json.containsKey("selectionOffset")) {
+ selectionOffset = _json["selectionOffset"];
+ }
}
core.Map<core.String, core.Object> toJson() {
@@ -492,9 +502,16 @@
if (edits != null) {
_json["edits"] = edits.map((value) => (value).toJson()).toList();
}
+ if (linkedEditGroups != null) {
+ _json["linkedEditGroups"] =
+ linkedEditGroups.map((value) => (value).toJson()).toList();
+ }
if (message != null) {
_json["message"] = message;
}
+ if (selectionOffset != null) {
+ _json["selectionOffset"] = selectionOffset;
+ }
return _json;
}
}
@@ -703,6 +720,82 @@
}
}
+class LinkedEditGroup {
+ /// The length of the regions that should be edited simultaneously.
+ core.int length;
+
+ /// The positions of the regions that should be edited simultaneously.
+ core.List<core.int> positions;
+
+ /// Pre-computed suggestions for what every region might want to be changed
+ /// to.
+ core.List<LinkedEditSuggestion> suggestions;
+
+ LinkedEditGroup();
+
+ LinkedEditGroup.fromJson(core.Map _json) {
+ if (_json.containsKey("length")) {
+ length = _json["length"];
+ }
+ if (_json.containsKey("positions")) {
+ positions = (_json["positions"] as core.List).cast<core.int>();
+ }
+ if (_json.containsKey("suggestions")) {
+ suggestions = (_json["suggestions"] as core.List)
+ .map<LinkedEditSuggestion>(
+ (value) => new LinkedEditSuggestion.fromJson(value))
+ .toList();
+ }
+ }
+
+ core.Map<core.String, core.Object> toJson() {
+ final core.Map<core.String, core.Object> _json =
+ new core.Map<core.String, core.Object>();
+ if (length != null) {
+ _json["length"] = length;
+ }
+ if (positions != null) {
+ _json["positions"] = positions;
+ }
+ if (suggestions != null) {
+ _json["suggestions"] =
+ suggestions.map((value) => (value).toJson()).toList();
+ }
+ return _json;
+ }
+}
+
+class LinkedEditSuggestion {
+ /// The kind of value being proposed.
+ core.String kind;
+
+ /// The value that could be used to replace all of the linked edit regions.
+ core.String value;
+
+ LinkedEditSuggestion();
+
+ LinkedEditSuggestion.fromJson(core.Map _json) {
+ if (_json.containsKey("kind")) {
+ kind = _json["kind"];
+ }
+ if (_json.containsKey("value")) {
+ value = _json["value"];
+ }
+ }
+
+ core.Map<core.String, core.Object> toJson() {
+ final core.Map<core.String, core.Object> _json =
+ new core.Map<core.String, core.Object>();
+ if (kind != null) {
+ _json["kind"] = kind;
+ }
+ if (value != null) {
+ _json["value"] = value;
+ }
+ return _json;
+ }
+}
+
class ProblemAndFixes {
core.List<CandidateFix> fixes;
core.int length;
diff --git a/doc/generated/dartservices.json b/doc/generated/dartservices.json
index 31f3744..172319c 100644
--- a/doc/generated/dartservices.json
+++ b/doc/generated/dartservices.json
@@ -1,6 +1,6 @@
{
"kind": "discovery#restDescription",
- "etag": "9511ad5e62f9a85d39dbd491c411705fd3876af8",
+ "etag": "3782b4a662b81bc2c7a01a7d5e7e9021a4debd44",
"discoveryVersion": "v1",
"id": "dartservices:v1",
"name": "dartservices",
@@ -189,6 +189,16 @@
"items": {
"$ref": "SourceEdit"
}
+ },
+ "selectionOffset": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "linkedEditGroups": {
+ "type": "array",
+ "items": {
+ "$ref": "LinkedEditGroup"
+ }
}
}
},
@@ -209,6 +219,46 @@
}
}
},
+ "LinkedEditGroup": {
+ "id": "LinkedEditGroup",
+ "type": "object",
+ "properties": {
+ "positions": {
+ "type": "array",
+ "description": "The positions of the regions that should be edited simultaneously.",
+ "items": {
+ "type": "integer",
+ "format": "int32"
+ }
+ },
+ "length": {
+ "type": "integer",
+ "description": "The length of the regions that should be edited simultaneously.",
+ "format": "int32"
+ },
+ "suggestions": {
+ "type": "array",
+ "description": "Pre-computed suggestions for what every region might want to be changed to.",
+ "items": {
+ "$ref": "LinkedEditSuggestion"
+ }
+ }
+ }
+ },
+ "LinkedEditSuggestion": {
+ "id": "LinkedEditSuggestion",
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "string",
+ "description": "The value that could be used to replace all of the linked edit regions."
+ },
+ "kind": {
+ "type": "string",
+ "description": "The kind of value being proposed."
+ }
+ }
+ },
"AssistsResponse": {
"id": "AssistsResponse",
"type": "object",
diff --git a/lib/src/analysis_server.dart b/lib/src/analysis_server.dart
index 671ca68..952d874 100644
--- a/lib/src/analysis_server.dart
+++ b/lib/src/analysis_server.dart
@@ -347,14 +347,34 @@
return api.SourceEdit.fromChanges(
sourceEdit.offset, sourceEdit.length, sourceEdit.replacement);
}).toList();
- assists.add(
- api.CandidateFix.fromEdits(sourceChange.message, apiSourceEdits));
+
+ assists.add(api.CandidateFix.fromEdits(
+ sourceChange.message,
+ apiSourceEdits,
+ sourceChange.selection?.offset,
+ _convertLinkedEditGroups(sourceChange.linkedEditGroups),
+ ));
}
}
return assists;
}
+ /// Convert a list of the analysis server's [LinkedEditGroup]s into the API's
+ /// equivalent.
+ static List<api.LinkedEditGroup> _convertLinkedEditGroups(
+ List<LinkedEditGroup> groups) {
+ return groups?.map<api.LinkedEditGroup>((g) {
+ return api.LinkedEditGroup(
+ g.positions?.map((p) => p.offset)?.toList(),
+ g.length,
+ g.suggestions
+ ?.map((s) => api.LinkedEditSuggestion(s.value, s.kind))
+ ?.toList(),
+ );
+ })?.toList();
+ }
+
/// Cleanly shutdown the Analysis Server.
Future<dynamic> shutdown() {
// TODO(jcollins-g): calling dispose() sometimes prevents
diff --git a/lib/src/api_classes.dart b/lib/src/api_classes.dart
index b907e4b..cfca8ec 100644
--- a/lib/src/api_classes.dart
+++ b/lib/src/api_classes.dart
@@ -183,14 +183,52 @@
[this.fixes, this.problemMessage, this.offset, this.length]);
}
+class LinkedEditSuggestion {
+ @ApiProperty(
+ description: 'The value that could be used to replace all of the linked '
+ 'edit regions.')
+ final String value;
+
+ @ApiProperty(description: 'The kind of value being proposed.')
+ final String kind;
+
+ LinkedEditSuggestion(this.value, this.kind);
+}
+
+class LinkedEditGroup {
+ @ApiProperty(
+ description: 'The positions of the regions that should be edited '
+ 'simultaneously.')
+ final List<int> positions;
+
+ @ApiProperty(
+ description: 'The length of the regions that should be edited '
+ 'simultaneously.')
+ final int length;
+
+ @ApiProperty(
+ description: 'Pre-computed suggestions for what every region might want '
+ 'to be changed to.')
+ final List<LinkedEditSuggestion> suggestions;
+
+ LinkedEditGroup(this.positions, this.length, this.suggestions);
+}
+
/// Represents a possible way of solving an Analysis Problem.
class CandidateFix {
final String message;
final List<SourceEdit> edits;
+ final int selectionOffset;
+ final List<LinkedEditGroup> linkedEditGroups;
CandidateFix() : this.fromEdits();
- CandidateFix.fromEdits([this.message, this.edits]);
+ CandidateFix.fromEdits([
+ this.message,
+ this.edits,
+ this.selectionOffset,
+ this.linkedEditGroups,
+ ]);
}
/// Represents a reformatting of the code.
@@ -231,6 +269,7 @@
/// The response from the `/assists` service call.
class AssistsResponse {
final List<CandidateFix> assists;
+
AssistsResponse(this.assists);
}