mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 11:42:11 +00:00
New Quick Asists for Flutter: 'Replace with child' and 'Replace with children'.
R=brianwilkerson@google.com, devoncarew@google.com Bug: https://github.com/flutter/flutter-intellij/issues/1283 Change-Id: Ic50de9739cdab5cd82649dcbd8370c5e728d2ee3 https://github.com/flutter/flutter-intellij/issues/1756 Reviewed-on: https://dart-review.googlesource.com/40240 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Devon Carew <devoncarew@google.com>
This commit is contained in:
parent
87a395bd09
commit
59716fede1
|
@ -77,6 +77,8 @@ class DartAssistKind {
|
|||
const AssistKind('EXTRACT_CLASS', 30, "Extract class into file '{0}'");
|
||||
static const FLUTTER_CONVERT_TO_STATEFUL_WIDGET = const AssistKind(
|
||||
"FLUTTER_CONVERT_TO_STATEFUL_WIDGET", 30, "Convert to StatefulWidget");
|
||||
static const FLUTTER_REPLACE_WITH_CHILDREN = const AssistKind(
|
||||
"FLUTTER_REPLACE_WITH_CHILDREN", 30, "Replace with children");
|
||||
static const IMPORT_ADD_SHOW =
|
||||
const AssistKind('IMPORT_ADD_SHOW', 30, "Add explicit 'show' combinator");
|
||||
static const INTRODUCE_LOCAL_CAST_TYPE = const AssistKind(
|
||||
|
|
|
@ -143,6 +143,8 @@ class AssistProcessor {
|
|||
await _addProposal_convertToStatefulWidget();
|
||||
await _addProposal_encapsulateField();
|
||||
await _addProposal_exchangeOperands();
|
||||
await _addProposal_flutterReplaceWithChild();
|
||||
await _addProposal_flutterReplaceWithChildren();
|
||||
await _addProposal_importAddShow();
|
||||
await _addProposal_introduceLocalTestedType();
|
||||
await _addProposal_invertIf();
|
||||
|
@ -1406,6 +1408,71 @@ class AssistProcessor {
|
|||
_addAssistFromBuilder(changeBuilder, DartAssistKind.EXCHANGE_OPERANDS);
|
||||
}
|
||||
|
||||
Future<Null> _addProposal_flutterReplaceWithChild() async {
|
||||
var widgetCreation = flutter.identifyNewExpression(node);
|
||||
if (widgetCreation == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var childArgument = flutter.findChildArgument(widgetCreation);
|
||||
if (childArgument == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// child: new ThisWidget(child: ourChild)
|
||||
// children: [foo, new ThisWidget(child: ourChild), bar]
|
||||
DartChangeBuilder changeBuilder = new DartChangeBuilder(session);
|
||||
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
|
||||
var childExpression = childArgument.expression;
|
||||
var childText = utils.getNodeText(childExpression);
|
||||
var indentOld = utils.getLinePrefix(childExpression.offset);
|
||||
var indentNew = utils.getLinePrefix(widgetCreation.offset);
|
||||
childText = _replaceSourceIndent(childText, indentOld, indentNew);
|
||||
builder.addSimpleReplacement(range.node(widgetCreation), childText);
|
||||
});
|
||||
_addAssistFromBuilder(
|
||||
changeBuilder, DartAssistKind.FLUTTER_REPLACE_WITH_CHILDREN);
|
||||
}
|
||||
|
||||
Future<Null> _addProposal_flutterReplaceWithChildren() async {
|
||||
var widgetCreation = flutter.identifyNewExpression(node);
|
||||
if (widgetCreation == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We can inline the list of our children only into another list.
|
||||
var widgetParentNode = widgetCreation.parent;
|
||||
if (widgetParentNode is! ListLiteral) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare the list of our children.
|
||||
List<Expression> childrenExpressions;
|
||||
{
|
||||
var childrenArgument = flutter.findChildrenArgument(widgetCreation);
|
||||
var childrenExpression = childrenArgument?.expression;
|
||||
if (childrenExpression is ListLiteral &&
|
||||
childrenExpression.elements.isNotEmpty) {
|
||||
childrenExpressions = childrenExpression.elements;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DartChangeBuilder changeBuilder = new DartChangeBuilder(session);
|
||||
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
|
||||
var firstChild = childrenExpressions.first;
|
||||
var lastChild = childrenExpressions.last;
|
||||
var childText = utils.getRangeText(range.startEnd(firstChild, lastChild));
|
||||
var indentOld = utils.getLinePrefix(firstChild.offset);
|
||||
var indentNew = utils.getLinePrefix(widgetCreation.offset);
|
||||
childText = _replaceSourceIndent(childText, indentOld, indentNew);
|
||||
builder.addSimpleReplacement(range.node(widgetCreation), childText);
|
||||
});
|
||||
_addAssistFromBuilder(
|
||||
changeBuilder, DartAssistKind.FLUTTER_REPLACE_WITH_CHILDREN);
|
||||
}
|
||||
|
||||
Future<Null> _addProposal_importAddShow() async {
|
||||
// prepare ImportDirective
|
||||
ImportDirective importDirective =
|
||||
|
|
|
@ -101,14 +101,23 @@ void convertChildToChildren2(
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the named expression representing the 'child' argument of the given
|
||||
* [newExpr], or null if none.
|
||||
* Return the named expression representing the `child` argument of the given
|
||||
* [newExpr], or `null` if none.
|
||||
*/
|
||||
NamedExpression findChildArgument(InstanceCreationExpression newExpr) =>
|
||||
newExpr.argumentList.arguments.firstWhere(
|
||||
(arg) => arg is NamedExpression && arg.name.label.name == 'child',
|
||||
orElse: () => null);
|
||||
|
||||
/**
|
||||
* Return the named expression representing the `children` argument of the
|
||||
* given [newExpr], or `null` if none.
|
||||
*/
|
||||
NamedExpression findChildrenArgument(InstanceCreationExpression newExpr) =>
|
||||
newExpr.argumentList.arguments.firstWhere(
|
||||
(arg) => arg is NamedExpression && arg.name.label.name == 'children',
|
||||
orElse: () => null);
|
||||
|
||||
/**
|
||||
* Return the Flutter instance creation expression that is the value of the
|
||||
* 'child' argument of the given [newExpr], or null if none.
|
||||
|
|
|
@ -2628,6 +2628,182 @@ main() {
|
|||
''');
|
||||
}
|
||||
|
||||
test_flutterReplaceWithChild_OK_childIntoChild_multiLine() async {
|
||||
addFlutterPackage();
|
||||
await resolveTestUnit('''
|
||||
import 'package:flutter/material.dart';
|
||||
main() {
|
||||
new Column(
|
||||
children: <Widget>[
|
||||
new Center(
|
||||
child: new /*caret*/Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: new Center(
|
||||
heightFactor: 0.5,
|
||||
child: new Text('foo'),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
''');
|
||||
_setCaretLocation();
|
||||
await assertHasAssist(DartAssistKind.FLUTTER_REPLACE_WITH_CHILDREN, '''
|
||||
import 'package:flutter/material.dart';
|
||||
main() {
|
||||
new Column(
|
||||
children: <Widget>[
|
||||
new Center(
|
||||
child: new Center(
|
||||
heightFactor: 0.5,
|
||||
child: new Text('foo'),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_flutterReplaceWithChild_OK_childIntoChild_singleLine() async {
|
||||
addFlutterPackage();
|
||||
await resolveTestUnit('''
|
||||
import 'package:flutter/material.dart';
|
||||
main() {
|
||||
new Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: new /*caret*/Center(
|
||||
heightFactor: 0.5,
|
||||
child: new Text('foo'),
|
||||
),
|
||||
);
|
||||
}
|
||||
''');
|
||||
_setCaretLocation();
|
||||
await assertHasAssist(DartAssistKind.FLUTTER_REPLACE_WITH_CHILDREN, '''
|
||||
import 'package:flutter/material.dart';
|
||||
main() {
|
||||
new Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: new Text('foo'),
|
||||
);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_flutterReplaceWithChild_OK_childIntoChildren() async {
|
||||
addFlutterPackage();
|
||||
await resolveTestUnit('''
|
||||
import 'package:flutter/material.dart';
|
||||
main() {
|
||||
new Column(
|
||||
children: <Widget>[
|
||||
new Text('foo'),
|
||||
new /*caret*/Center(
|
||||
heightFactor: 0.5,
|
||||
child: new Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: new Text('bar'),
|
||||
),
|
||||
),
|
||||
new Text('baz'),
|
||||
],
|
||||
);
|
||||
}
|
||||
''');
|
||||
_setCaretLocation();
|
||||
await assertHasAssist(DartAssistKind.FLUTTER_REPLACE_WITH_CHILDREN, '''
|
||||
import 'package:flutter/material.dart';
|
||||
main() {
|
||||
new Column(
|
||||
children: <Widget>[
|
||||
new Text('foo'),
|
||||
new Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: new Text('bar'),
|
||||
),
|
||||
new Text('baz'),
|
||||
],
|
||||
);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_flutterReplaceWithChildren_BAD_parentChild() async {
|
||||
addFlutterPackage();
|
||||
await resolveTestUnit('''
|
||||
import 'package:flutter/material.dart';
|
||||
main() {
|
||||
new Center(
|
||||
child: new /*caret*/Row(
|
||||
children: [
|
||||
new Text('aaa'),
|
||||
new Text('bbb'),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
''');
|
||||
_setCaretLocation();
|
||||
await assertNoAssist(DartAssistKind.FLUTTER_REPLACE_WITH_CHILDREN);
|
||||
}
|
||||
|
||||
test_flutterReplaceWithChildren_OK_intoChildren() async {
|
||||
addFlutterPackage();
|
||||
await resolveTestUnit('''
|
||||
import 'package:flutter/material.dart';
|
||||
main() {
|
||||
new Column(
|
||||
children: <Widget>[
|
||||
new Text('aaa'),
|
||||
new /*caret*/Column(
|
||||
children: [
|
||||
new Row(
|
||||
children: [
|
||||
new Text('bbb'),
|
||||
new Text('ccc'),
|
||||
],
|
||||
),
|
||||
new Row(
|
||||
children: [
|
||||
new Text('ddd'),
|
||||
new Text('eee'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
new Text('fff'),
|
||||
],
|
||||
);
|
||||
}
|
||||
''');
|
||||
_setCaretLocation();
|
||||
await assertHasAssist(DartAssistKind.FLUTTER_REPLACE_WITH_CHILDREN, '''
|
||||
import 'package:flutter/material.dart';
|
||||
main() {
|
||||
new Column(
|
||||
children: <Widget>[
|
||||
new Text('aaa'),
|
||||
new Row(
|
||||
children: [
|
||||
new Text('bbb'),
|
||||
new Text('ccc'),
|
||||
],
|
||||
),
|
||||
new Row(
|
||||
children: [
|
||||
new Text('ddd'),
|
||||
new Text('eee'),
|
||||
],
|
||||
),
|
||||
new Text('fff'),
|
||||
],
|
||||
);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
test_importAddShow_BAD_hasShow() async {
|
||||
await resolveTestUnit('''
|
||||
import 'dart:math' show PI;
|
||||
|
|
|
@ -138,7 +138,7 @@ export 'package:flutter/painting.dart';
|
|||
export 'package:flutter/rendering.dart';
|
||||
|
||||
class Center extends StatelessWidget {
|
||||
const Center({Widget child, Key key});
|
||||
const Center({Key key, double heightFactor, Widget child});
|
||||
}
|
||||
|
||||
class Column extends Flex {
|
||||
|
|
Loading…
Reference in a new issue