Skip to content

Commit c50958a

Browse files
scheglovCommit Queue
authored andcommitted
[CMSR] Add LSP command 'Move selected formal parameter(s) left'.
Change-Id: Ia30e9bad9643d80c183d8b17a0d3aae065c30dc7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/310969 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]> Reviewed-by: Samuel Rawlins <[email protected]>
1 parent d3f7940 commit c50958a

File tree

5 files changed

+517
-0
lines changed

5 files changed

+517
-0
lines changed

pkg/analysis_server/lib/src/services/refactoring/agnostic/change_method_signature.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ sealed class Available extends Availability {
7272
});
7373

7474
bool get hasSelectedFormalParametersToConvertToNamed => false;
75+
76+
bool get hasSelectedFormalParametersToMoveLeft => false;
7577
}
7678

7779
/// The supertype return types from [computeSourceChange].
@@ -439,6 +441,36 @@ final class _AvailableWithDeclaration extends Available {
439441

440442
return true;
441443
}
444+
445+
@override
446+
bool get hasSelectedFormalParametersToMoveLeft {
447+
final selected = declaration.selected;
448+
final firstSelected = selected.firstOrNull;
449+
if (firstSelected == null) {
450+
return false;
451+
}
452+
453+
final formalParameterList = declaration.node.formalParameterList;
454+
if (formalParameterList == null) {
455+
return false;
456+
}
457+
458+
final all = formalParameterList.parameters.toList();
459+
final firstSelectedIndex = all.indexOf(firstSelected);
460+
if (firstSelectedIndex < 1) {
461+
return false;
462+
}
463+
464+
final previous = all[firstSelectedIndex - 1];
465+
if (firstSelected.isOptionalPositional && !previous.isOptionalPositional) {
466+
return false;
467+
}
468+
if (firstSelected.isNamed && !previous.isNamed) {
469+
return false;
470+
}
471+
472+
return true;
473+
}
442474
}
443475

444476
final class _AvailableWithExecutableElement extends Available {

pkg/analysis_server/lib/src/services/refactoring/framework/refactoring_processor.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:analysis_server/src/services/refactoring/convert_all_formal_para
88
import 'package:analysis_server/src/services/refactoring/convert_selected_formal_parameters_to_named.dart';
99
import 'package:analysis_server/src/services/refactoring/framework/refactoring_context.dart';
1010
import 'package:analysis_server/src/services/refactoring/framework/refactoring_producer.dart';
11+
import 'package:analysis_server/src/services/refactoring/move_selected_formal_parameters_left.dart';
1112
import 'package:analysis_server/src/services/refactoring/move_top_level_to_file.dart';
1213

1314
/// A function that can be executed to create a refactoring producer.
@@ -20,6 +21,8 @@ class RefactoringProcessor {
2021
ConvertAllFormalParametersToNamed.new,
2122
ConvertSelectedFormalParametersToNamed.commandName:
2223
ConvertSelectedFormalParametersToNamed.new,
24+
MoveSelectedFormalParametersLeft.commandName:
25+
MoveSelectedFormalParametersLeft.new,
2326
MoveTopLevelToFile.commandName: MoveTopLevelToFile.new,
2427
};
2528

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:analysis_server/lsp_protocol/protocol_custom_generated.dart';
6+
import 'package:analysis_server/src/services/refactoring/agnostic/change_method_signature.dart';
7+
import 'package:analysis_server/src/services/refactoring/framework/refactoring_producer.dart';
8+
import 'package:analysis_server/src/services/refactoring/framework/write_invocation_arguments.dart'
9+
show ArgumentsTrailingComma;
10+
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
11+
import 'package:collection/collection.dart';
12+
13+
/// The refactoring that move selected formal parameters one position left
14+
/// in the list of formal parameters.
15+
class MoveSelectedFormalParametersLeft extends RefactoringProducer {
16+
static const String commandName =
17+
'dart.refactor.move_selected_formal_parameters_left';
18+
19+
static const String constTitle = 'Move selected formal parameter(s) left';
20+
21+
MoveSelectedFormalParametersLeft(super.context);
22+
23+
@override
24+
bool get isExperimental => true;
25+
26+
@override
27+
List<CommandParameter> get parameters => const <CommandParameter>[];
28+
29+
@override
30+
String get title => constTitle;
31+
32+
@override
33+
Future<void> compute(
34+
List<Object?> commandArguments,
35+
ChangeBuilder builder,
36+
) async {
37+
final availability = analyzeAvailability(
38+
refactoringContext: refactoringContext,
39+
);
40+
if (availability is! Available) {
41+
return;
42+
}
43+
44+
final selection = await analyzeSelection(
45+
available: availability,
46+
);
47+
48+
if (selection is! ValidSelectionState) {
49+
return;
50+
}
51+
52+
final all = selection.formalParameters.toList();
53+
final selected = all.where((e) => e.isSelected).toList();
54+
55+
final firstSelected = selected.firstOrNull;
56+
if (firstSelected == null) {
57+
return;
58+
}
59+
60+
final firstSelectedIndex = all.indexOf(firstSelected);
61+
if (firstSelectedIndex < 1) {
62+
return;
63+
}
64+
65+
final beforePrevious = all.take(firstSelectedIndex - 1);
66+
final afterPrevious = all.skip(firstSelectedIndex - 1);
67+
final reordered = [
68+
...beforePrevious,
69+
...selected,
70+
...afterPrevious.whereNot(selected.contains),
71+
];
72+
73+
final formalParameterUpdates = reordered.map(
74+
(formalParameter) {
75+
return FormalParameterUpdate(
76+
id: formalParameter.id,
77+
kind: formalParameter.kind,
78+
);
79+
},
80+
).toList();
81+
82+
final signatureUpdate = MethodSignatureUpdate(
83+
formalParameters: formalParameterUpdates,
84+
formalParametersTrailingComma: TrailingComma.ifPresent,
85+
argumentsTrailingComma: ArgumentsTrailingComma.ifPresent,
86+
);
87+
88+
await computeSourceChange(
89+
selectionState: selection,
90+
signatureUpdate: signatureUpdate,
91+
builder: builder,
92+
);
93+
}
94+
95+
@override
96+
bool isAvailable() {
97+
final availability = analyzeAvailability(
98+
refactoringContext: refactoringContext,
99+
);
100+
if (availability is! Available) {
101+
return false;
102+
}
103+
return availability.hasSelectedFormalParametersToMoveLeft;
104+
}
105+
}

0 commit comments

Comments
 (0)