Skip to content

Commit be90b4d

Browse files
DanTupCommit Queue
authored and
Commit Queue
committed
[analysis_server] Make LSP executeCommand() a shared handler to support the legacy server
As a pre-cursor to supporting `executeCommand()` over DTD, this converts the handler from an LspHandler to a SharedHandler so it can work with either a base LSP or Legacy server. Not all commands themselves work in both modes, but the executeCommand() handler itself and some basic commands (like `logAction`, which I used for testing) do. Change-Id: I90de88a1870649fb121cc9fa45732b4d03a45504 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425263 Commit-Queue: Elliott Brooks <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Elliott Brooks <[email protected]>
1 parent 2f5dd77 commit be90b4d

13 files changed

+124
-40
lines changed

pkg/analysis_server/lib/src/lsp/handlers/commands/abstract_refactor.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:analysis_server/src/lsp/constants.dart';
1010
import 'package:analysis_server/src/lsp/error_or.dart';
1111
import 'package:analysis_server/src/lsp/handlers/commands/simple_edit_handler.dart';
1212
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
13+
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
1314
import 'package:analysis_server/src/lsp/progress.dart';
1415
import 'package:analysis_server/src/protocol_server.dart';
1516
import 'package:analysis_server/src/services/refactoring/legacy/refactoring.dart';
@@ -22,7 +23,8 @@ final _manager = LspRefactorManager._();
2223

2324
/// A base class for refactoring commands that need to create Refactorings from
2425
/// client-supplied arguments.
25-
abstract class AbstractRefactorCommandHandler extends SimpleEditCommandHandler
26+
abstract class AbstractRefactorCommandHandler
27+
extends SimpleEditCommandHandler<LspAnalysisServer>
2628
with PositionalArgCommandHandler {
2729
AbstractRefactorCommandHandler(super.server);
2830

pkg/analysis_server/lib/src/lsp/handlers/commands/fix_all.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import 'package:analysis_server/src/lsp/temporary_overlay_operation.dart';
1616
import 'package:analysis_server/src/services/correction/bulk_fix_processor.dart';
1717
import 'package:analysis_server/src/utilities/source_change_merger.dart';
1818

19-
class FixAllCommandHandler extends SimpleEditCommandHandler {
19+
class FixAllCommandHandler extends SimpleEditCommandHandler<LspAnalysisServer> {
2020
FixAllCommandHandler(super.server);
2121

2222
@override

pkg/analysis_server/lib/src/lsp/handlers/commands/fix_all_in_workspace.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ import 'package:analysis_server/src/lsp/constants.dart';
77
import 'package:analysis_server/src/lsp/error_or.dart';
88
import 'package:analysis_server/src/lsp/handlers/commands/simple_edit_handler.dart';
99
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
10+
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
1011
import 'package:analysis_server/src/lsp/mapping.dart';
1112
import 'package:analysis_server/src/lsp/progress.dart';
1213
import 'package:analysis_server/src/lsp/source_edits.dart';
1314
import 'package:analysis_server/src/services/correction/bulk_fix_processor.dart';
1415
import 'package:analysis_server_plugin/src/correction/dart_change_workspace.dart';
1516

1617
abstract class AbstractFixAllInWorkspaceCommandHandler
17-
extends SimpleEditCommandHandler {
18+
extends SimpleEditCommandHandler<LspAnalysisServer> {
1819
AbstractFixAllInWorkspaceCommandHandler(super.server);
1920

2021
/// Whether to require confirmation from the user to apply these changes.

pkg/analysis_server/lib/src/lsp/handlers/commands/log_action.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:analysis_server/lsp_protocol/protocol.dart';
6+
import 'package:analysis_server/src/analysis_server.dart';
67
import 'package:analysis_server/src/lsp/error_or.dart';
78
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
89
import 'package:analysis_server/src/lsp/progress.dart';
910

1011
class LogActionCommandHandler
11-
extends CommandHandler<ExecuteCommandParams, Object> {
12+
extends CommandHandler<ExecuteCommandParams, Object, AnalysisServer> {
1213
LogActionCommandHandler(super.server);
1314

1415
@override

pkg/analysis_server/lib/src/lsp/handlers/commands/refactor_command_handler.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:analysis_server/src/lsp/constants.dart';
88
import 'package:analysis_server/src/lsp/error_or.dart';
99
import 'package:analysis_server/src/lsp/handlers/commands/simple_edit_handler.dart';
1010
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
11+
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
1112
import 'package:analysis_server/src/lsp/mapping.dart';
1213
import 'package:analysis_server/src/lsp/progress.dart';
1314
import 'package:analysis_server/src/lsp/source_edits.dart';
@@ -18,7 +19,8 @@ import 'package:analyzer/dart/analysis/results.dart';
1819
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
1920

2021
/// A command handler for any of the commands used to implement refactorings.
21-
class RefactorCommandHandler extends SimpleEditCommandHandler {
22+
class RefactorCommandHandler
23+
extends SimpleEditCommandHandler<LspAnalysisServer> {
2224
@override
2325
final String commandName;
2426

pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:analysis_server/lsp_protocol/protocol.dart';
6+
import 'package:analysis_server/src/analysis_server.dart';
67
import 'package:analysis_server/src/lsp/constants.dart';
78
import 'package:analysis_server/src/lsp/error_or.dart';
89
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
@@ -14,8 +15,8 @@ import 'package:analyzer/src/dart/scanner/scanner.dart' as engine;
1415
import 'package:analyzer/src/generated/parser.dart' as engine;
1516
import 'package:analyzer_plugin/protocol/protocol_common.dart';
1617

17-
abstract class SimpleEditCommandHandler
18-
extends CommandHandler<ExecuteCommandParams, Object> {
18+
abstract class SimpleEditCommandHandler<S extends AnalysisServer>
19+
extends CommandHandler<ExecuteCommandParams, Object, S> {
1920
SimpleEditCommandHandler(super.server);
2021

2122
String get commandName;

pkg/analysis_server/lib/src/lsp/handlers/handler_execute_command.dart

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:analysis_server/lsp_protocol/protocol.dart';
6+
import 'package:analysis_server/src/analysis_server.dart';
67
import 'package:analysis_server/src/lsp/constants.dart';
78
import 'package:analysis_server/src/lsp/error_or.dart';
89
import 'package:analysis_server/src/lsp/handlers/commands/fix_all.dart';
@@ -15,32 +16,41 @@ import 'package:analysis_server/src/lsp/handlers/commands/send_workspace_edit.da
1516
import 'package:analysis_server/src/lsp/handlers/commands/sort_members.dart';
1617
import 'package:analysis_server/src/lsp/handlers/commands/validate_refactor.dart';
1718
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
19+
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
1820
import 'package:analysis_server/src/lsp/progress.dart';
1921
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
2022
import 'package:analysis_server/src/services/refactoring/framework/refactoring_processor.dart';
2123

2224
/// Handles workspace/executeCommand messages by delegating to a specific
2325
/// handler based on the command.
2426
class ExecuteCommandHandler
25-
extends LspMessageHandler<ExecuteCommandParams, Object?> {
26-
final Map<String, CommandHandler<ExecuteCommandParams, Object>>
27+
extends SharedMessageHandler<ExecuteCommandParams, Object?> {
28+
final Map<
29+
String,
30+
CommandHandler<ExecuteCommandParams, Object, AnalysisServer>
31+
>
2732
commandHandlers;
2833

2934
ExecuteCommandHandler(super.server)
3035
: commandHandlers = {
36+
// Commands that can run for any underlying server type.
3137
Commands.sortMembers: SortMembersCommandHandler(server),
3238
Commands.organizeImports: OrganizeImportsCommandHandler(server),
33-
Commands.fixAll: FixAllCommandHandler(server),
34-
Commands.fixAllInWorkspace: FixAllInWorkspaceCommandHandler(server),
35-
Commands.previewFixAllInWorkspace:
36-
PreviewFixAllInWorkspaceCommandHandler(server),
37-
Commands.performRefactor: PerformRefactorCommandHandler(server),
38-
Commands.validateRefactor: ValidateRefactorCommandHandler(server),
3939
Commands.sendWorkspaceEdit: SendWorkspaceEditCommandHandler(server),
4040
Commands.logAction: LogActionCommandHandler(server),
41-
// Add commands for each of the refactorings.
42-
for (var entry in RefactoringProcessor.generators.entries)
43-
entry.key: RefactorCommandHandler(server, entry.key, entry.value),
41+
42+
// Commands that currently require an underlying LSP server.
43+
if (server is LspAnalysisServer) ...{
44+
Commands.fixAll: FixAllCommandHandler(server),
45+
Commands.fixAllInWorkspace: FixAllInWorkspaceCommandHandler(server),
46+
Commands.previewFixAllInWorkspace:
47+
PreviewFixAllInWorkspaceCommandHandler(server),
48+
Commands.performRefactor: PerformRefactorCommandHandler(server),
49+
Commands.validateRefactor: ValidateRefactorCommandHandler(server),
50+
// Add commands for each of the refactorings.
51+
for (var entry in RefactoringProcessor.generators.entries)
52+
entry.key: RefactorCommandHandler(server, entry.key, entry.value),
53+
},
4454
} {
4555
server.executeCommandHandler = this;
4656
}
@@ -52,6 +62,12 @@ class ExecuteCommandHandler
5262
LspJsonHandler<ExecuteCommandParams> get jsonHandler =>
5363
ExecuteCommandParams.jsonHandler;
5464

65+
@override
66+
// TODO(dantup): This will need to be relaxed to support calling over DTD,
67+
// but at that point we must also add this flag to Commands so that we can
68+
// control which commands require trusted callers.
69+
bool get requiresTrustedCaller => true;
70+
5571
@override
5672
Future<ErrorOr<Object?>> handle(
5773
ExecuteCommandParams params,
@@ -70,14 +86,17 @@ class ExecuteCommandHandler
7086
server.analyticsManager.executedCommand(params.command);
7187
}
7288
var workDoneToken = params.workDoneToken;
73-
var progress =
74-
workDoneToken != null
75-
? ProgressReporter.clientProvided(server, workDoneToken)
76-
// Use editor client capabilities, as that's who gets progress
77-
// notifications, not the caller.
78-
: server.editorClientCapabilities?.workDoneProgress ?? false
79-
? ProgressReporter.serverCreated(server)
80-
: ProgressReporter.noop;
89+
ProgressReporter progress = ProgressReporter.noop;
90+
if (server case LspAnalysisServer server) {
91+
progress =
92+
workDoneToken != null
93+
? ProgressReporter.clientProvided(server, workDoneToken)
94+
// Use editor client capabilities, as that's who gets progress
95+
// notifications, not the caller.
96+
: server.editorClientCapabilities?.workDoneProgress ?? false
97+
? ProgressReporter.serverCreated(server)
98+
: ProgressReporter.noop;
99+
}
81100

82101
// To make passing arguments easier in commands, instead of a
83102
// `List<Object?>` we now use `Map<String, Object?>`.

pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ class InitializedLspStateMessageHandler extends InitializedStateMessageHandler {
9292
DocumentLinkHandler.new,
9393
ReferencesHandler.new,
9494
CodeActionHandler.new,
95-
ExecuteCommandHandler.new,
9695
ChangeWorkspaceFoldersHandler.new,
9796
PrepareRenameHandler.new,
9897
RenameHandler.new,
@@ -133,6 +132,7 @@ class InitializedStateMessageHandler extends ServerStateMessageHandler {
133132
DocumentSymbolHandler.new,
134133
EditableArgumentsHandler.new,
135134
EditArgumentHandler.new,
135+
ExecuteCommandHandler.new,
136136
ExperimentalEchoHandler.new,
137137
FormatOnTypeHandler.new,
138138
FormatRangeHandler.new,

pkg/analysis_server/lib/src/lsp/handlers/handlers.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ Iterable<T> convert<T, E>(Iterable<E> items, T? Function(E) converter) {
3636
return items.map(converter).where((item) => item != null).cast<T>();
3737
}
3838

39-
abstract class CommandHandler<P, R> with Handler<R>, HandlerHelperMixin {
39+
abstract class CommandHandler<P, R, S extends AnalysisServer>
40+
with Handler<R>, HandlerHelperMixin {
4041
@override
41-
final LspAnalysisServer server;
42+
final S server;
4243

4344
CommandHandler(this.server);
4445

pkg/analysis_server/test/lsp/request_helpers_mixin.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,25 @@ mixin LspRequestHelpersMixin {
209209
Range entireRange(String code) =>
210210
Range(start: startOfDocPos, end: positionFromOffset(code.length, code));
211211

212+
Future<T> executeCommand<T>(
213+
Command command, {
214+
T Function(Map<String, Object?>)? decoder,
215+
ProgressToken? workDoneToken,
216+
}) {
217+
var request = makeRequest(
218+
Method.workspace_executeCommand,
219+
ExecuteCommandParams(
220+
command: command.command,
221+
arguments: command.arguments,
222+
workDoneToken: workDoneToken,
223+
),
224+
);
225+
return expectSuccessfulResponseTo<T, Map<String, Object?>>(
226+
request,
227+
decoder ?? (result) => result as T,
228+
);
229+
}
230+
212231
void expect(Object? actual, Matcher matcher, {String? reason}) =>
213232
test.expect(actual, matcher, reason: reason);
214233

pkg/analysis_server/test/lsp/server_abstract.dart

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,7 @@ mixin LspAnalysisServerTestMixin on LspRequestHelpersMixin, LspEditHelpersMixin
10481048
return executeCommand(command);
10491049
}
10501050

1051+
@override
10511052
Future<T> executeCommand<T>(
10521053
Command command, {
10531054
T Function(Map<String, Object?>)? decoder,
@@ -1061,17 +1062,10 @@ mixin LspAnalysisServerTestMixin on LspRequestHelpersMixin, LspEditHelpersMixin
10611062
'Is it missing from serverSupportedCommands?',
10621063
);
10631064
}
1064-
var request = makeRequest(
1065-
Method.workspace_executeCommand,
1066-
ExecuteCommandParams(
1067-
command: command.command,
1068-
arguments: command.arguments,
1069-
workDoneToken: workDoneToken,
1070-
),
1071-
);
1072-
return expectSuccessfulResponseTo<T, Map<String, Object?>>(
1073-
request,
1074-
decoder ?? (result) => result as T,
1065+
return super.executeCommand(
1066+
command,
1067+
decoder: decoder,
1068+
workDoneToken: workDoneToken,
10751069
);
10761070
}
10771071

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) 2025, 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.dart';
6+
import 'package:analysis_server/src/lsp/constants.dart';
7+
import 'package:test/test.dart';
8+
import 'package:test_reflective_loader/test_reflective_loader.dart';
9+
10+
import 'abstract_lsp_over_legacy.dart';
11+
12+
void main() {
13+
defineReflectiveSuite(() {
14+
defineReflectiveTests(ExecuteCommandTest);
15+
});
16+
}
17+
18+
@reflectiveTest
19+
class ExecuteCommandTest extends LspOverLegacyTest {
20+
Future<void> test_logAction() async {
21+
var testActionName = 'test.action';
22+
23+
await waitForTasksFinished();
24+
await executeCommand(
25+
Command(
26+
title: 'Log Action',
27+
command: Commands.logAction,
28+
arguments: [
29+
{'action': testActionName},
30+
],
31+
),
32+
);
33+
34+
expect(
35+
server.analyticsManager
36+
.getRequestData(Method.workspace_executeCommand.toString())
37+
.additionalEnumCounts['command']!
38+
.keys,
39+
contains(testActionName),
40+
);
41+
}
42+
}

pkg/analysis_server/test/lsp_over_legacy/test_all.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'document_highlights_test.dart' as document_highlights;
1010
import 'document_symbols_test.dart' as document_symbols;
1111
import 'edit_argument_test.dart' as edit_argument;
1212
import 'editable_arguments_test.dart' as editable_arguments;
13+
import 'execute_command_test.dart' as execute_command;
1314
import 'format_test.dart' as format;
1415
import 'hover_test.dart' as hover;
1516
import 'implementation_test.dart' as implementation;
@@ -28,6 +29,7 @@ void main() {
2829
document_symbols.main();
2930
edit_argument.main();
3031
editable_arguments.main();
32+
execute_command.main();
3133
format.main();
3234
hover.main();
3335
implementation.main();

0 commit comments

Comments
 (0)