[analysis_server] Add snippet for function definitions

Fixes https://github.com/Dart-Code/Dart-Code/issues/4017.

Change-Id: I1017be3abe73a8cfcd6354f1c2ca99ad729dcf47
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/247553
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Danny Tuppeny 2022-06-09 16:07:43 +00:00 committed by Commit Bot
parent 4894ae493f
commit 5b3bfe4137
4 changed files with 266 additions and 0 deletions

View file

@ -166,6 +166,47 @@ class DartForLoopSnippetProducer extends DartSnippetProducer {
DartForLoopSnippetProducer._(request);
}
/// Produces a [Snippet] that creates a function definition.
class DartFunctionSnippetProducer extends DartSnippetProducer {
static const prefix = 'fun';
static const label = 'fun';
DartFunctionSnippetProducer._(super.request);
@override
Future<Snippet> compute() async {
final builder = ChangeBuilder(session: request.analysisSession);
final indent = utils.getLinePrefix(request.offset);
await builder.addDartFileEdit(request.filePath, (builder) {
builder.addReplacement(request.replacementRange, (builder) {
void writeIndented(String string) => builder.write('$indent$string');
builder.addSimpleLinkedEdit('returnType', 'void');
builder.write(' ');
builder.addSimpleLinkedEdit('name', 'name');
builder.write('(');
builder.addSimpleLinkedEdit('params', 'params');
builder.writeln(') {');
writeIndented(' ');
builder.selectHere();
builder.writeln();
writeIndented('}');
});
});
return Snippet(
prefix,
label,
'Insert a function definition.',
builder.sourceChange,
);
}
static DartFunctionSnippetProducer newInstance(DartSnippetRequest request) =>
DartFunctionSnippetProducer._(request);
}
/// Produces a [Snippet] that creates an if/else statement.
class DartIfElseSnippetProducer extends DartSnippetProducer {
static const prefix = 'ife';

View file

@ -29,8 +29,10 @@ class DartSnippetManager {
FlutterStatefulWidgetWithAnimationControllerSnippetProducer.newInstance,
FlutterStatelessWidgetSnippetProducer.newInstance,
DartClassSnippetProducer.newInstance,
DartFunctionSnippetProducer.newInstance,
],
SnippetContext.inBlock: [
DartFunctionSnippetProducer.newInstance,
DartDoWhileLoopSnippetProducer.newInstance,
DartForInLoopSnippetProducer.newInstance,
DartForLoopSnippetProducer.newInstance,
@ -42,6 +44,9 @@ class DartSnippetManager {
DartTestBlockSnippetProducer.newInstance,
DartTestGroupBlockSnippetProducer.newInstance,
],
SnippetContext.inClass: [
DartFunctionSnippetProducer.newInstance,
]
};
Future<List<Snippet>> computeSnippets(

View file

@ -2639,6 +2639,71 @@ void f() {
''');
}
Future<void> test_snippets_functionClassMember() async {
final content = '''
class A {
fun^
}
''';
await initializeWithSnippetSupport();
final updated = await expectAndApplySnippet(
content,
prefix: DartFunctionSnippetProducer.prefix,
label: DartFunctionSnippetProducer.label,
);
expect(updated, r'''
class A {
${1:void} ${2:name}(${3:params}) {
$0
}
}
''');
}
Future<void> test_snippets_functionNested() async {
final content = '''
void a() {
fun^
}
''';
await initializeWithSnippetSupport();
final updated = await expectAndApplySnippet(
content,
prefix: DartFunctionSnippetProducer.prefix,
label: DartFunctionSnippetProducer.label,
);
expect(updated, r'''
void a() {
${1:void} ${2:name}(${3:params}) {
$0
}
}
''');
}
Future<void> test_snippets_functionTopLevel() async {
final content = '''
fun^
''';
await initializeWithSnippetSupport();
final updated = await expectAndApplySnippet(
content,
prefix: DartFunctionSnippetProducer.prefix,
label: DartFunctionSnippetProducer.label,
);
expect(updated, r'''
${1:void} ${2:name}(${3:params}) {
$0
}
''');
}
Future<void> test_snippets_if() async {
final content = '''
void f() {

View file

@ -23,6 +23,7 @@ void main() {
defineReflectiveTests(DartTryCatchSnippetProducerTest);
defineReflectiveTests(DartWhileLoopSnippetProducerTest);
defineReflectiveTests(DartClassSnippetProducerTest);
defineReflectiveTests(DartFunctionSnippetProducerTest);
defineReflectiveTests(DartTestBlockSnippetProducerTest);
defineReflectiveTests(DartTestGroupBlockSnippetProducerTest);
});
@ -215,6 +216,160 @@ void f() {
}
}
@reflectiveTest
class DartFunctionSnippetProducerTest extends DartSnippetProducerTest {
@override
final generator = DartFunctionSnippetProducer.newInstance;
@override
String get label => DartFunctionSnippetProducer.label;
@override
String get prefix => DartFunctionSnippetProducer.prefix;
Future<void> test_classMethod() async {
var code = r'''
class A {
^
}''';
final snippet = await expectValidSnippet(code);
expect(snippet.prefix, prefix);
expect(snippet.label, label);
expect(snippet.change.edits, hasLength(1));
code = withoutMarkers(code);
for (var edit in snippet.change.edits) {
code = SourceEdit.applySequence(code, edit.edits);
}
expect(code, '''
class A {
void name(params) {
}
}''');
expect(snippet.change.selection!.file, testFile);
expect(snippet.change.selection!.offset, 36);
expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
{
'positions': [
{'file': testFile, 'offset': 12},
],
'length': 4,
'suggestions': []
},
{
'positions': [
{'file': testFile, 'offset': 17},
],
'length': 4,
'suggestions': []
},
{
'positions': [
{'file': testFile, 'offset': 22},
],
'length': 6,
'suggestions': []
},
]);
}
Future<void> test_nested() async {
var code = r'''
void a() {
^
}''';
final snippet = await expectValidSnippet(code);
expect(snippet.prefix, prefix);
expect(snippet.label, label);
expect(snippet.change.edits, hasLength(1));
code = withoutMarkers(code);
for (var edit in snippet.change.edits) {
code = SourceEdit.applySequence(code, edit.edits);
}
expect(code, '''
void a() {
void name(params) {
}
}''');
expect(snippet.change.selection!.file, testFile);
expect(snippet.change.selection!.offset, 37);
expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
{
'positions': [
{'file': testFile, 'offset': 13},
],
'length': 4,
'suggestions': []
},
{
'positions': [
{'file': testFile, 'offset': 18},
],
'length': 4,
'suggestions': []
},
{
'positions': [
{'file': testFile, 'offset': 23},
],
'length': 6,
'suggestions': []
},
]);
}
Future<void> test_topLevel() async {
var code = r'''
class A {}
^
class B {}''';
final snippet = await expectValidSnippet(code);
expect(snippet.prefix, prefix);
expect(snippet.label, label);
expect(snippet.change.edits, hasLength(1));
code = withoutMarkers(code);
for (var edit in snippet.change.edits) {
code = SourceEdit.applySequence(code, edit.edits);
}
expect(code, '''
class A {}
void name(params) {
}
class B {}''');
expect(snippet.change.selection!.file, testFile);
expect(snippet.change.selection!.offset, 36);
expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
{
'positions': [
{'file': testFile, 'offset': 14},
],
'length': 4,
'suggestions': []
},
{
'positions': [
{'file': testFile, 'offset': 19},
],
'length': 4,
'suggestions': []
},
{
'positions': [
{'file': testFile, 'offset': 24},
],
'length': 6,
'suggestions': []
},
]);
}
}
@reflectiveTest
class DartIfElseSnippetProducerTest extends DartSnippetProducerTest {
@override