Skip to content

Commit f1744ad

Browse files
DanTupCommit Queue
authored andcommitted
[analysis_server] Support assist CodeActions via Commands when the client does not support codeActionLiterals
This changes assist CodeActions to return Commands if the client does not support codeActionLiterals (code actions with inline edits). The implementation of "applyCodeAction" will just recompute the code action from the textDocument/range/codeActionKind and then send it to the editor via workspace/applyEdit. On it's own, this only means that LSP clients that do not support codeActionLiterals will now get assists, but a future change will make the textDocument/codeAction request available over DTD allowing them to be invoked by clients other than the editor itself. This is currently only assists and not fixes/refactors. Change-Id: I8204a51303b048e3928d5cbadf5aca76e81c82f3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/427224 Reviewed-by: Samuel Rawlins <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent fe43c00 commit f1744ad

14 files changed

+642
-62
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ abstract final class Commands {
104104
/// commands should be sent to the server for execution (as opposed to being
105105
/// executed in the local plugin).
106106
static final serverSupportedCommands = [
107+
applyCodeAction,
107108
sortMembers,
108109
organizeImports,
109110
fixAll,
@@ -116,6 +117,7 @@ abstract final class Commands {
116117
// Add commands for each of the new refactorings.
117118
...RefactoringProcessor.generators.keys,
118119
];
120+
static const applyCodeAction = 'dart.edit.codeAction.apply';
119121
static const sortMembers = 'dart.edit.sortMembers';
120122
static const organizeImports = 'dart.edit.organizeImports';
121123
static const fixAll = 'dart.edit.fixAll';

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

Lines changed: 104 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
/// @docImport 'package:analysis_server/src/lsp/handlers/commands/apply_code_action.dart';
6+
library;
7+
58
import 'dart:async';
69

710
import 'package:analysis_server/lsp_protocol/protocol.dart';
811
import 'package:analysis_server/src/lsp/client_capabilities.dart';
912
import 'package:analysis_server/src/lsp/constants.dart';
1013
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
1114
import 'package:analysis_server/src/lsp/mapping.dart';
15+
import 'package:analysis_server/src/protocol_server.dart'
16+
hide AnalysisOptions, Position;
1217
import 'package:analysis_server/src/protocol_server.dart' as protocol;
1318
import 'package:analysis_server/src/request_handler_mixin.dart';
1419
import 'package:analyzer/dart/analysis/analysis_options.dart';
@@ -33,35 +38,83 @@ abstract class AbstractCodeActionsProducer
3338
final int offset;
3439
final int length;
3540
final bool Function(CodeActionKind?) shouldIncludeKind;
36-
final LspClientCapabilities capabilities;
41+
42+
/// The capabilities of the caller making the request for [CodeAction]s.
43+
final LspClientCapabilities callerCapabilities;
44+
45+
/// The capabilities of the editor (which may or may not be the same as
46+
/// [callerCapabilities] depending on whether the request came from the editor
47+
/// or another client - such as over DTD).
48+
final LspClientCapabilities editorCapabilities;
3749

3850
final AnalysisOptions analysisOptions;
3951

4052
@override
4153
final LspAnalysisServer server;
4254

55+
/// Whether [CodeAction]s can be [Command]s or not.
56+
///
57+
/// This is usually true (because there is no capability for this), however
58+
/// it will be disabled by [ApplyCodeActionCommandHandler] so that we can't
59+
/// recursively return command-based actions.
60+
final bool allowCommands;
61+
62+
/// Whether [CodeAction]s can be [CodeActionLiteral]s or not.
63+
///
64+
/// This is usually based on the callers capabilities, however
65+
/// for [ApplyCodeActionCommandHandler] it will be based on the editor's
66+
/// capabilities since it will compute the edits and send them to the editor
67+
/// directly.
68+
final bool allowCodeActionLiterals;
69+
4370
AbstractCodeActionsProducer(
4471
this.server,
4572
this.file,
4673
this.lineInfo, {
4774
required this.offset,
4875
required this.length,
4976
required this.shouldIncludeKind,
50-
required this.capabilities,
77+
required this.callerCapabilities,
78+
required this.editorCapabilities,
79+
required this.allowCommands,
80+
required this.allowCodeActionLiterals,
5181
required this.analysisOptions,
5282
});
5383

54-
String get name;
84+
Set<DiagnosticTag> get callerSupportedDiagnosticTags =>
85+
callerCapabilities.diagnosticTags;
5586

56-
String get path => file.path;
87+
bool get callerSupportsCodeDescription =>
88+
callerCapabilities.diagnosticCodeDescription;
5789

58-
Set<DiagnosticTag> get supportedDiagnosticTags => capabilities.diagnosticTags;
90+
bool get editorSupportsApplyEdit => editorCapabilities.applyEdit;
5991

60-
bool get supportsApplyEdit => capabilities.applyEdit;
92+
String get name;
6193

62-
bool get supportsCodeDescription => capabilities.diagnosticCodeDescription;
94+
String get path => file.path;
6395

64-
bool get supportsLiterals => capabilities.literalCodeActions;
96+
/// Creates a command to apply a CodeAction later.
97+
Command createApplyCodeActionCommand(
98+
String title,
99+
CodeActionKind kind,
100+
String? loggedId,
101+
OptionalVersionedTextDocumentIdentifier textDocument,
102+
Range range,
103+
) {
104+
return Command(
105+
title: title,
106+
command: Commands.applyCodeAction,
107+
// The arguments here must match those in `ApplyCodeActionCommandHandler`.
108+
arguments: [
109+
{
110+
'textDocument': textDocument,
111+
'range': range,
112+
'kind': kind,
113+
'loggedAction': loggedId,
114+
},
115+
],
116+
);
117+
}
65118

66119
/// Creates a CodeAction to apply this assist.
67120
///
@@ -87,7 +140,7 @@ abstract class AbstractCodeActionsProducer
87140
command: createLogActionCommand(loggedAssistId),
88141
edit: createWorkspaceEdit(
89142
server,
90-
capabilities,
143+
editorCapabilities,
91144
change,
92145
allowSnippets: true,
93146
filePath: path,
@@ -96,6 +149,45 @@ abstract class AbstractCodeActionsProducer
96149
);
97150
}
98151

152+
/// Creates a [CodeAction] that is:
153+
///
154+
/// - a [CodeActionLiteral] if [allowCodeActionLiterals], or
155+
/// - a [Command] for [Commands.applyCodeAction] if [allowCommands], or
156+
/// - null
157+
CodeAction? createCodeActionLiteralOrApplyCommand(
158+
String path,
159+
OptionalVersionedTextDocumentIdentifier textDocument,
160+
Range range,
161+
LineInfo lineInfo,
162+
SourceChange change,
163+
CodeActionKind kind,
164+
String? loggedAssistId,
165+
) {
166+
if (allowCodeActionLiterals) {
167+
return CodeAction.t1(
168+
createAssistCodeActionLiteral(
169+
change,
170+
kind,
171+
loggedAssistId,
172+
path,
173+
lineInfo,
174+
),
175+
);
176+
} else if (allowCommands) {
177+
return CodeAction.t2(
178+
createApplyCodeActionCommand(
179+
change.message,
180+
kind,
181+
loggedAssistId,
182+
textDocument,
183+
range,
184+
),
185+
);
186+
} else {
187+
return null;
188+
}
189+
}
190+
99191
/// Create an LSP [Diagnostic] for [diagnostic].
100192
@protected
101193
Diagnostic createDiagnostic(
@@ -107,8 +199,8 @@ abstract class AbstractCodeActionsProducer
107199
server.uriConverter,
108200
(_) => lineInfo,
109201
protocol.newAnalysisError_fromEngine(result, diagnostic),
110-
supportedTags: supportedDiagnosticTags,
111-
clientSupportsCodeDescription: supportsCodeDescription,
202+
supportedTags: callerSupportedDiagnosticTags,
203+
clientSupportsCodeDescription: callerSupportsCodeDescription,
112204
);
113205
}
114206

@@ -137,7 +229,7 @@ abstract class AbstractCodeActionsProducer
137229
command: createLogActionCommand(loggedFixId),
138230
edit: createWorkspaceEdit(
139231
server,
140-
capabilities,
232+
editorCapabilities,
141233
change,
142234
allowSnippets: true,
143235
filePath: path,

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ class AnalysisOptionsCodeActionsProducer extends AbstractCodeActionsProducer {
2626
required super.offset,
2727
required super.length,
2828
required super.shouldIncludeKind,
29-
required super.capabilities,
29+
required super.editorCapabilities,
30+
required super.callerCapabilities,
31+
required super.allowCodeActionLiterals,
32+
required super.allowCommands,
3033
required super.analysisOptions,
3134
});
3235

@@ -43,7 +46,8 @@ class AnalysisOptionsCodeActionsProducer extends AbstractCodeActionsProducer {
4346
OperationPerformance? performance,
4447
) async {
4548
// These fixes are only provided as literal CodeActions.
46-
if (!supportsLiterals) {
49+
if (!allowCodeActionLiterals) {
50+
// TODO(dantup): Support this (via createCodeActionLiteralOrApplyCommand)
4751
return [];
4852
}
4953

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

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
/// @docImport 'package:analysis_server/src/lsp/handlers/commands/apply_code_action.dart';
56
/// @docImport 'package:language_server_protocol/protocol_special.dart';
67
/// @docImport 'package:analysis_server/src/lsp/handlers/handler_code_actions.dart';
78
library;
@@ -28,8 +29,14 @@ import 'package:collection/collection.dart' show groupBy;
2829
import 'package:path/src/context.dart';
2930

3031
/// A helper class for computing [CodeAction]s that is used by both the
31-
/// [CodeActionHandler] and an upcoming command handler.
32-
class CodeActionComputer with HandlerHelperMixin<LspAnalysisServer> {
32+
/// [CodeActionHandler] and [ApplyCodeActionCommandHandler].
33+
class CodeActionComputer
34+
with
35+
HandlerHelperMixin<
36+
// TODO(dantup): Make this (and the code action producers) work with
37+
// either server.
38+
LspAnalysisServer
39+
> {
3340
/// The text document to compute code actions for.
3441
final TextDocumentIdentifier textDocument;
3542

@@ -55,15 +62,20 @@ class CodeActionComputer with HandlerHelperMixin<LspAnalysisServer> {
5562
/// Whether [CodeAction]s can be [CodeActionLiteral]s or not.
5663
///
5764
/// This is usually based on the callers capabilities, however
58-
/// for [ApplyCodeActionCommandHandler] it will be based on the editors
65+
/// for [ApplyCodeActionCommandHandler] it will be based on the editor's
5966
/// capabilities since it will compute the edits and send them to the editor
6067
/// directly.
6168
final bool allowCodeActionLiterals;
6269

6370
final OperationPerformanceImpl performance;
6471

65-
/// The capabilities of the client.
66-
final LspClientCapabilities capabilities;
72+
/// The capabilities of the caller making the request for [CodeAction]s.
73+
final LspClientCapabilities callerCapabilities;
74+
75+
/// The capabilities of the editor (which may or may not be the same as
76+
/// [callerCapabilities] depending on whether the request came from the editor
77+
/// or another client - such as over DTD).
78+
final LspClientCapabilities editorCapabilities;
6779

6880
@override
6981
final LspAnalysisServer server;
@@ -79,7 +91,8 @@ class CodeActionComputer with HandlerHelperMixin<LspAnalysisServer> {
7991
this.server,
8092
this.textDocument,
8193
this.range, {
82-
required this.capabilities,
94+
required this.editorCapabilities,
95+
required this.callerCapabilities,
8396
required this.only,
8497
required this.supportedKinds,
8598
required this.triggerKind,
@@ -226,7 +239,10 @@ class CodeActionComputer with HandlerHelperMixin<LspAnalysisServer> {
226239
libraryResult,
227240
unit,
228241
shouldIncludeKind: shouldIncludeKind,
229-
capabilities: capabilities,
242+
editorCapabilities: editorCapabilities,
243+
callerCapabilities: callerCapabilities,
244+
allowCodeActionLiterals: allowCodeActionLiterals,
245+
allowCommands: allowCommands,
230246
triggerKind: triggerKind,
231247
analysisOptions: analysisOptions,
232248
willBeDeduplicated: true,
@@ -240,7 +256,10 @@ class CodeActionComputer with HandlerHelperMixin<LspAnalysisServer> {
240256
offset: offset,
241257
length: length,
242258
shouldIncludeKind: shouldIncludeKind,
243-
capabilities: capabilities,
259+
editorCapabilities: editorCapabilities,
260+
callerCapabilities: callerCapabilities,
261+
allowCodeActionLiterals: allowCodeActionLiterals,
262+
allowCommands: allowCommands,
244263
analysisOptions: analysisOptions,
245264
),
246265
if (isAnalysisOptions)
@@ -252,7 +271,10 @@ class CodeActionComputer with HandlerHelperMixin<LspAnalysisServer> {
252271
offset: offset,
253272
length: length,
254273
shouldIncludeKind: shouldIncludeKind,
255-
capabilities: capabilities,
274+
editorCapabilities: editorCapabilities,
275+
callerCapabilities: callerCapabilities,
276+
allowCodeActionLiterals: allowCodeActionLiterals,
277+
allowCommands: allowCommands,
256278
analysisOptions: analysisOptions,
257279
),
258280
PluginCodeActionsProducer(
@@ -263,7 +285,10 @@ class CodeActionComputer with HandlerHelperMixin<LspAnalysisServer> {
263285
offset: offset,
264286
length: length,
265287
shouldIncludeKind: shouldIncludeKind,
266-
capabilities: capabilities,
288+
editorCapabilities: editorCapabilities,
289+
callerCapabilities: callerCapabilities,
290+
allowCodeActionLiterals: allowCodeActionLiterals,
291+
allowCommands: allowCommands,
267292
analysisOptions: analysisOptions,
268293
),
269294
];

0 commit comments

Comments
 (0)