mirror of
https://github.com/dart-lang/sdk
synced 2024-10-04 16:14:50 +00:00
[analysis_server] Extract LSP registration options from ServerCapabilitiesComputer
This is a non-functional refactor that extracts the growing set of capabilities and options from ServerCapabilitiesComputer into files alongside the handlers they relate to. The motivation for this is that for LSP-over-Legacy we'll need to accept client capabilities (and return server capabilities). The server capabilities will be different to the standard LSP ones (they will be a subset, and we might not support dynamic registration - at least initially). However the features we do support will have the same registration options, so to avoid duplicating them this moves the registration options away from the creation of the ServerCapabilities. In future, we might consider further wrapping up a "feature" (which consists of these registration options, and the related handlers), but this change is already quite large and I just wanted to progress capabilities for LSP-over-Legacy so we can handle things like Code Actions (which require executeCommand and possible reverse-requests for applyEdit). Change-Id: Iecd0aa36626fa44826f7d4dbd6e6c0d758075239 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/319840 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
94a0ce7757
commit
acefe9ab6d
|
@ -45,11 +45,48 @@ const dartSignatureHelpTriggerCharacters = <String>['('];
|
|||
/// Characters to trigger formatting when format-on-type is enabled.
|
||||
const dartTypeFormattingCharacters = ['}', ';'];
|
||||
|
||||
/// A [TextDocumentFilterWithScheme] for Analysis Options files.
|
||||
final analysisOptionsFile = TextDocumentFilterWithScheme(
|
||||
language: 'yaml', scheme: 'file', pattern: '**/analysis_options.yaml');
|
||||
|
||||
/// A [ProgressToken] used for reporting progress while the server is analyzing.
|
||||
final analyzingProgressToken = ProgressToken.t2('ANALYZING');
|
||||
|
||||
/// A [TextDocumentFilterWithScheme] for Dart file.
|
||||
final dartFiles =
|
||||
TextDocumentFilterWithScheme(language: 'dart', scheme: 'file');
|
||||
|
||||
final emptyWorkspaceEdit = WorkspaceEdit();
|
||||
|
||||
final fileOperationRegistrationOptions = FileOperationRegistrationOptions(
|
||||
filters: [
|
||||
FileOperationFilter(
|
||||
scheme: 'file',
|
||||
pattern: FileOperationPattern(
|
||||
glob: '**/*.dart',
|
||||
matches: FileOperationPatternKind.file,
|
||||
),
|
||||
),
|
||||
FileOperationFilter(
|
||||
scheme: 'file',
|
||||
pattern: FileOperationPattern(
|
||||
glob: '**/',
|
||||
matches: FileOperationPatternKind.folder,
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
/// A [TextDocumentFilterWithScheme] for Fix Data files.
|
||||
final fixDataFile = TextDocumentFilterWithScheme(
|
||||
language: 'yaml',
|
||||
scheme: 'file',
|
||||
pattern: '**/lib/{fix_data.yaml,fix_data/**.yaml}');
|
||||
|
||||
/// A [TextDocumentFilterWithScheme] for Pubspec files.
|
||||
final pubspecFile = TextDocumentFilterWithScheme(
|
||||
language: 'yaml', scheme: 'file', pattern: '**/pubspec.yaml');
|
||||
|
||||
/// Constants for command IDs that are exchanged between LSP client/server.
|
||||
abstract class Commands {
|
||||
/// A list of all commands IDs that can be sent to the client to inform which
|
||||
|
|
|
@ -9,13 +9,36 @@ import 'package:analysis_server/lsp_protocol/protocol_special.dart';
|
|||
import 'package:analysis_server/src/analysis_server.dart';
|
||||
import 'package:analysis_server/src/computer/computer_call_hierarchy.dart'
|
||||
as call_hierarchy;
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/dart/analysis/session.dart';
|
||||
import 'package:analyzer/source/line_info.dart';
|
||||
import 'package:analyzer/source/source_range.dart';
|
||||
|
||||
typedef StaticOptions
|
||||
= Either3<bool, CallHierarchyOptions, CallHierarchyRegistrationOptions>;
|
||||
|
||||
class CallHierarchyRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
CallHierarchyRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options =>
|
||||
CallHierarchyRegistrationOptions(documentSelector: [dartFiles]);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_prepareCallHierarchy;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either3.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.callHierarchy;
|
||||
}
|
||||
|
||||
/// A handler for `callHierarchy/incoming` that returns the incoming calls for
|
||||
/// the target supplied by the client.
|
||||
class IncomingCallHierarchyHandler extends _AbstractCallHierarchyCallsHandler<
|
||||
|
|
|
@ -4,13 +4,16 @@
|
|||
|
||||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
|
||||
class WorkspaceFoldersHandler
|
||||
typedef StaticOptions = Either2<bool, String>;
|
||||
|
||||
class ChangeWorkspaceFoldersHandler
|
||||
extends LspMessageHandler<DidChangeWorkspaceFoldersParams, void> {
|
||||
// Whether to update analysis roots based on the open workspace folders.
|
||||
bool updateAnalysisRoots;
|
||||
|
||||
WorkspaceFoldersHandler(super.server)
|
||||
ChangeWorkspaceFoldersHandler(super.server)
|
||||
: updateAnalysisRoots =
|
||||
!server.initializationOptions.onlyAnalyzeProjectsWithOpenFiles;
|
||||
|
||||
|
@ -46,3 +49,17 @@ class WorkspaceFoldersHandler
|
|||
return folders.map((wf) => pathContext.fromUri(wf.uri)).toList();
|
||||
}
|
||||
}
|
||||
|
||||
class ChangeWorkspaceFoldersRegistrations extends FeatureRegistration
|
||||
with StaticRegistration<StaticOptions> {
|
||||
ChangeWorkspaceFoldersRegistrations(super.info);
|
||||
|
||||
@override
|
||||
List<LspDynamicRegistration> get dynamicRegistrations => [];
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either2.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => false;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/code_actions/abstract_code_actions_producer.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/code_actions/analysis_options.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/code_actions/dart.dart';
|
||||
|
@ -12,9 +13,12 @@ import 'package:analysis_server/src/lsp/handlers/code_actions/plugins.dart';
|
|||
import 'package:analysis_server/src/lsp/handlers/code_actions/pubspec.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
|
||||
import 'package:collection/collection.dart' show groupBy;
|
||||
|
||||
typedef StaticOptions = Either2<bool, CodeActionOptions>;
|
||||
|
||||
class CodeActionHandler
|
||||
extends LspMessageHandler<CodeActionParams, TextDocumentCodeActionResult> {
|
||||
CodeActionHandler(super.server);
|
||||
|
@ -220,6 +224,36 @@ class CodeActionHandler
|
|||
}
|
||||
}
|
||||
|
||||
class CodeActionRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
CodeActionRegistrations(super.info);
|
||||
|
||||
bool get codeActionLiteralSupport => clientCapabilities.literalCodeActions;
|
||||
|
||||
@override
|
||||
ToJsonable? get options => CodeActionRegistrationOptions(
|
||||
documentSelector: fullySupportedTypes,
|
||||
codeActionKinds: DartCodeActionKind.serverSupportedKinds,
|
||||
);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_codeAction;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions =>
|
||||
// "The `CodeActionOptions` return type is only valid if the client
|
||||
// signals code action literal support via the property
|
||||
// `textDocument.codeAction.codeActionLiteralSupport`."
|
||||
codeActionLiteralSupport
|
||||
? Either2.t2(CodeActionOptions(
|
||||
codeActionKinds: DartCodeActionKind.serverSupportedKinds,
|
||||
))
|
||||
: Either2.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.codeActions;
|
||||
}
|
||||
|
||||
/// Sorts [CodeActionWithPriority]s by priority, and removes duplicates keeping
|
||||
/// the one nearest [range].
|
||||
class _CodeActionSorter {
|
||||
|
|
|
@ -7,8 +7,10 @@ import 'dart:math' as math;
|
|||
import 'package:analysis_server/lsp_protocol/protocol.dart' hide Declaration;
|
||||
import 'package:analysis_server/src/computer/computer_hover.dart';
|
||||
import 'package:analysis_server/src/lsp/client_capabilities.dart';
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analysis_server/src/provisional/completion/completion_core.dart';
|
||||
import 'package:analysis_server/src/services/completion/completion_performance.dart';
|
||||
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
|
||||
|
@ -790,6 +792,66 @@ class CompletionHandler
|
|||
}
|
||||
}
|
||||
|
||||
class CompletionRegistrations extends FeatureRegistration
|
||||
with StaticRegistration<CompletionOptions> {
|
||||
CompletionRegistrations(super.info);
|
||||
|
||||
@override
|
||||
List<LspDynamicRegistration> get dynamicRegistrations {
|
||||
return [
|
||||
// Trigger and commit characters are specific to Dart, so register them
|
||||
// separately to the others.
|
||||
(
|
||||
Method.textDocument_completion,
|
||||
CompletionRegistrationOptions(
|
||||
documentSelector: [dartFiles],
|
||||
triggerCharacters: dartCompletionTriggerCharacters,
|
||||
allCommitCharacters:
|
||||
previewCommitCharacters ? dartCompletionCommitCharacters : null,
|
||||
resolveProvider: true,
|
||||
),
|
||||
),
|
||||
(
|
||||
Method.textDocument_completion,
|
||||
CompletionRegistrationOptions(
|
||||
documentSelector: nonDartCompletionTypes,
|
||||
resolveProvider: true,
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/// Types of documents we support completion for that are not Dart.
|
||||
///
|
||||
/// We use two dynamic registrations because for Dart we support trigger
|
||||
/// characters but for other kinds of files we do not.
|
||||
List<TextDocumentFilterWithScheme> get nonDartCompletionTypes {
|
||||
final pluginTypesExcludingDart =
|
||||
pluginTypes.where((filter) => filter.pattern != '**/*.dart');
|
||||
|
||||
return {
|
||||
...pluginTypesExcludingDart,
|
||||
pubspecFile,
|
||||
analysisOptionsFile,
|
||||
fixDataFile,
|
||||
}.toList();
|
||||
}
|
||||
|
||||
bool get previewCommitCharacters =>
|
||||
clientConfiguration.global.previewCommitCharacters;
|
||||
|
||||
@override
|
||||
CompletionOptions get staticOptions => CompletionOptions(
|
||||
triggerCharacters: dartCompletionTriggerCharacters,
|
||||
allCommitCharacters:
|
||||
previewCommitCharacters ? dartCompletionCommitCharacters : null,
|
||||
resolveProvider: true,
|
||||
);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.completion;
|
||||
}
|
||||
|
||||
/// A set of completion items split into ranked and unranked items.
|
||||
class _CompletionResults {
|
||||
/// Items that can be ranked using their relevance/sortText.
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:analysis_server/protocol/protocol_generated.dart'
|
|||
hide AnalysisGetNavigationParams;
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analysis_server/src/plugin/result_merger.dart';
|
||||
import 'package:analysis_server/src/protocol_server.dart' show NavigationTarget;
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
|
@ -21,6 +22,8 @@ import 'package:analyzer_plugin/utilities/analyzer_converter.dart';
|
|||
import 'package:analyzer_plugin/utilities/navigation/navigation_dart.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
typedef StaticOptions = Either2<bool, DefinitionOptions>;
|
||||
|
||||
class DefinitionHandler extends LspMessageHandler<TextDocumentPositionParams,
|
||||
TextDocumentDefinitionResult> with LspPluginRequestHandlerMixin {
|
||||
DefinitionHandler(super.server);
|
||||
|
@ -269,3 +272,21 @@ class DefinitionHandler extends LspMessageHandler<TextDocumentPositionParams,
|
|||
return parsedLibrary.getElementDeclaration(element);
|
||||
}
|
||||
}
|
||||
|
||||
class DefinitionRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
DefinitionRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options =>
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_definition;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either2.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.definition;
|
||||
}
|
||||
|
|
|
@ -5,10 +5,15 @@
|
|||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/computer/computer_color.dart'
|
||||
show ColorComputer, ColorReference;
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
|
||||
typedef StaticOptions
|
||||
= Either3<bool, DocumentColorOptions, DocumentColorRegistrationOptions>;
|
||||
|
||||
/// Handles textDocument/documentColor requests.
|
||||
///
|
||||
/// This request is sent by the client to the server to request the locations
|
||||
|
@ -58,3 +63,21 @@ class DocumentColorHandler
|
|||
return success(colors.map(toColorInformation).toList());
|
||||
}
|
||||
}
|
||||
|
||||
class DocumentColorRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
DocumentColorRegistrations(super.info);
|
||||
|
||||
@override
|
||||
DocumentColorRegistrationOptions get options =>
|
||||
DocumentColorRegistrationOptions(documentSelector: [dartFiles]);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_documentColor;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either3.t3(options);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.colorProvider;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@ import 'package:analysis_server/src/domains/analysis/occurrences.dart';
|
|||
import 'package:analysis_server/src/domains/analysis/occurrences_dart.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
|
||||
typedef StaticOptions = Either2<bool, DocumentHighlightOptions>;
|
||||
|
||||
class DocumentHighlightsHandler extends SharedMessageHandler<
|
||||
TextDocumentPositionParams, List<DocumentHighlight>?> {
|
||||
|
@ -53,3 +56,21 @@ class DocumentHighlightsHandler extends SharedMessageHandler<
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
class DocumentHighlightsRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
DocumentHighlightsRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options =>
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_documentHighlight;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either2.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.documentHighlights;
|
||||
}
|
||||
|
|
|
@ -7,10 +7,13 @@ import 'package:analysis_server/src/computer/computer_outline.dart';
|
|||
import 'package:analysis_server/src/lsp/client_capabilities.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analysis_server/src/protocol_server.dart' show Outline;
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/source/line_info.dart';
|
||||
|
||||
typedef StaticOptions = Either2<bool, DocumentSymbolOptions>;
|
||||
|
||||
class DocumentSymbolHandler extends SharedMessageHandler<DocumentSymbolParams,
|
||||
TextDocumentDocumentSymbolResult> {
|
||||
DocumentSymbolHandler(super.server);
|
||||
|
@ -138,3 +141,21 @@ class DocumentSymbolHandler extends SharedMessageHandler<DocumentSymbolParams,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DocumentSymbolsRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
DocumentSymbolsRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options =>
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_documentSymbol;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either2.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.documentSymbol;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import 'package:analysis_server/src/lsp/handlers/commands/sort_members.dart';
|
|||
import 'package:analysis_server/src/lsp/handlers/commands/validate_refactor.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/progress.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analysis_server/src/services/refactoring/framework/refactoring_processor.dart';
|
||||
|
||||
/// Handles workspace/executeCommand messages by delegating to a specific
|
||||
|
@ -84,3 +85,20 @@ class ExecuteCommandHandler
|
|||
return handler.handle(message, commandParams, progress, token);
|
||||
}
|
||||
}
|
||||
|
||||
class ExecuteCommandRegistrations extends FeatureRegistration
|
||||
with StaticRegistration<ExecuteCommandOptions> {
|
||||
ExecuteCommandRegistrations(super.info);
|
||||
|
||||
@override
|
||||
List<LspDynamicRegistration> get dynamicRegistrations => [];
|
||||
|
||||
@override
|
||||
ExecuteCommandOptions get staticOptions => ExecuteCommandOptions(
|
||||
commands: Commands.serverSupportedCommands,
|
||||
workDoneProgress: true,
|
||||
);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => false;
|
||||
}
|
||||
|
|
|
@ -6,9 +6,13 @@ import 'package:analysis_server/lsp_protocol/protocol.dart';
|
|||
import 'package:analysis_server/src/computer/computer_folding.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analysis_server/src/protocol_server.dart';
|
||||
import 'package:analyzer/source/line_info.dart';
|
||||
|
||||
typedef StaticOptions
|
||||
= Either3<bool, FoldingRangeOptions, FoldingRangeRegistrationOptions>;
|
||||
|
||||
class FoldingHandler
|
||||
extends LspMessageHandler<FoldingRangeParams, List<FoldingRange>> {
|
||||
FoldingHandler(super.server);
|
||||
|
@ -128,3 +132,21 @@ class FoldingHandler
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FoldingRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
FoldingRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options =>
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_foldingRange;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either3.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.folding;
|
||||
}
|
||||
|
|
|
@ -6,8 +6,11 @@ import 'package:analysis_server/lsp_protocol/protocol.dart';
|
|||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analysis_server/src/lsp/source_edits.dart';
|
||||
|
||||
typedef StaticOptions = DocumentOnTypeFormattingOptions?;
|
||||
|
||||
class FormatOnTypeHandler extends SharedMessageHandler<
|
||||
DocumentOnTypeFormattingParams, List<TextEdit>?> {
|
||||
FormatOnTypeHandler(super.server);
|
||||
|
@ -54,3 +57,35 @@ class FormatOnTypeHandler extends SharedMessageHandler<
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
class FormatOnTypeRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
FormatOnTypeRegistrations(super.info);
|
||||
|
||||
bool get enableFormatter => clientConfiguration.global.enableSdkFormatter;
|
||||
|
||||
@override
|
||||
ToJsonable? get options {
|
||||
return DocumentOnTypeFormattingRegistrationOptions(
|
||||
documentSelector: [dartFiles], // This is currently Dart-specific
|
||||
firstTriggerCharacter: dartTypeFormattingCharacters.first,
|
||||
moreTriggerCharacter: dartTypeFormattingCharacters.skip(1).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_onTypeFormatting;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => enableFormatter
|
||||
? DocumentOnTypeFormattingOptions(
|
||||
firstTriggerCharacter: dartTypeFormattingCharacters.first,
|
||||
moreTriggerCharacter: dartTypeFormattingCharacters.skip(1).toList())
|
||||
: null;
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => enableFormatter && clientDynamic.typeFormatting;
|
||||
|
||||
@override
|
||||
bool get supportsStatic => enableFormatter;
|
||||
}
|
||||
|
|
|
@ -6,8 +6,11 @@ import 'package:analysis_server/lsp_protocol/protocol.dart';
|
|||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analysis_server/src/lsp/source_edits.dart';
|
||||
|
||||
typedef StaticOptions = Either2<bool, DocumentRangeFormattingOptions>;
|
||||
|
||||
class FormatRangeHandler extends SharedMessageHandler<
|
||||
DocumentRangeFormattingParams, List<TextEdit>?> {
|
||||
FormatRangeHandler(super.server);
|
||||
|
@ -53,3 +56,27 @@ class FormatRangeHandler extends SharedMessageHandler<
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
class FormatRangeRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
FormatRangeRegistrations(super.info);
|
||||
|
||||
bool get enableFormatter => clientConfiguration.global.enableSdkFormatter;
|
||||
|
||||
@override
|
||||
ToJsonable? get options => DocumentRangeFormattingRegistrationOptions(
|
||||
documentSelector: [dartFiles], // This is currently Dart-specific
|
||||
);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_rangeFormatting;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either2.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => enableFormatter && clientDynamic.rangeFormatting;
|
||||
|
||||
@override
|
||||
bool get supportsStatic => enableFormatter;
|
||||
}
|
||||
|
|
|
@ -6,8 +6,11 @@ import 'package:analysis_server/lsp_protocol/protocol.dart';
|
|||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analysis_server/src/lsp/source_edits.dart';
|
||||
|
||||
typedef StaticOptions = Either2<bool, DocumentFormattingOptions>;
|
||||
|
||||
class FormattingHandler
|
||||
extends SharedMessageHandler<DocumentFormattingParams, List<TextEdit>?> {
|
||||
FormattingHandler(super.server);
|
||||
|
@ -53,3 +56,26 @@ class FormattingHandler
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
class FormattingRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
FormattingRegistrations(super.info);
|
||||
|
||||
bool get enableFormatter => clientConfiguration.global.enableSdkFormatter;
|
||||
|
||||
@override
|
||||
ToJsonable? get options =>
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_formatting;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either2.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => enableFormatter && clientDynamic.formatting;
|
||||
|
||||
@override
|
||||
bool get supportsStatic => enableFormatter;
|
||||
}
|
||||
|
|
|
@ -8,9 +8,12 @@ import 'package:analysis_server/src/computer/computer_hover.dart';
|
|||
import 'package:analysis_server/src/lsp/dartdoc.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/source/line_info.dart';
|
||||
|
||||
typedef StaticOptions = Either2<bool, HoverOptions>;
|
||||
|
||||
class HoverHandler
|
||||
extends SharedMessageHandler<TextDocumentPositionParams, Hover?> {
|
||||
HoverHandler(super.server);
|
||||
|
@ -105,3 +108,21 @@ class HoverHandler
|
|||
return success(toHover(unit.lineInfo, hover));
|
||||
}
|
||||
}
|
||||
|
||||
class HoverRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
HoverRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options =>
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_hover;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either2.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.hover;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:analysis_server/lsp_protocol/protocol.dart'
|
|||
hide TypeHierarchyItem, Element;
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analysis_server/src/search/type_hierarchy.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
|
@ -13,6 +14,9 @@ import 'package:analyzer/src/dart/ast/utilities.dart';
|
|||
import 'package:analyzer/src/util/performance/operation_performance.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
typedef StaticOptions
|
||||
= Either3<bool, ImplementationOptions, ImplementationRegistrationOptions>;
|
||||
|
||||
class ImplementationHandler
|
||||
extends SharedMessageHandler<TextDocumentPositionParams, List<Location>> {
|
||||
ImplementationHandler(super.server);
|
||||
|
@ -101,3 +105,21 @@ class ImplementationHandler
|
|||
return success(locations);
|
||||
}
|
||||
}
|
||||
|
||||
class ImplementationRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
ImplementationRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options =>
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_implementation;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either3.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.implementation;
|
||||
}
|
||||
|
|
|
@ -4,10 +4,15 @@
|
|||
|
||||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/computer/computer_inlay_hint.dart';
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
|
||||
typedef StaticOptions
|
||||
= Either3<bool, InlayHintOptions, InlayHintRegistrationOptions>;
|
||||
|
||||
class InlayHintHandler
|
||||
extends LspMessageHandler<InlayHintParams, List<InlayHint>> {
|
||||
InlayHintHandler(super.server);
|
||||
|
@ -52,3 +57,25 @@ class InlayHintHandler
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
class InlayHintRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
InlayHintRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options => InlayHintRegistrationOptions(
|
||||
documentSelector: [dartFiles],
|
||||
resolveProvider: false,
|
||||
);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_inlayHint;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either3.t2(
|
||||
InlayHintOptions(resolveProvider: false),
|
||||
);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.inlayHints;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analysis_server/src/protocol_server.dart' show NavigationTarget;
|
||||
import 'package:analysis_server/src/search/element_references.dart';
|
||||
import 'package:analysis_server/src/services/search/search_engine.dart'
|
||||
|
@ -17,6 +18,8 @@ import 'package:analyzer_plugin/src/utilities/navigation/navigation.dart';
|
|||
import 'package:analyzer_plugin/utilities/navigation/navigation_dart.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
typedef StaticOptions = Either2<bool, ReferenceOptions>;
|
||||
|
||||
class ReferencesHandler
|
||||
extends LspMessageHandler<ReferenceParams, List<Location>?> {
|
||||
ReferencesHandler(super.server);
|
||||
|
@ -126,3 +129,21 @@ class ReferencesHandler
|
|||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
class ReferencesRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
ReferencesRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options =>
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_references;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either2.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.references;
|
||||
}
|
||||
|
|
|
@ -8,12 +8,15 @@ import 'package:analysis_server/src/lsp/client_configuration.dart';
|
|||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analysis_server/src/services/refactoring/legacy/refactoring.dart';
|
||||
import 'package:analysis_server/src/services/refactoring/legacy/rename_unit_member.dart';
|
||||
import 'package:analysis_server/src/utilities/extensions/string.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/ast/utilities.dart';
|
||||
|
||||
typedef StaticOptions = Either2<bool, RenameOptions>;
|
||||
|
||||
class PrepareRenameHandler extends LspMessageHandler<TextDocumentPositionParams,
|
||||
TextDocumentPrepareRenameResult> {
|
||||
PrepareRenameHandler(super.server);
|
||||
|
@ -282,3 +285,23 @@ class RenameHandler extends LspMessageHandler<RenameParams, WorkspaceEdit?>
|
|||
return userChoice == UserPromptActions.yes;
|
||||
}
|
||||
}
|
||||
|
||||
class RenameRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
RenameRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options => RenameRegistrationOptions(
|
||||
documentSelector: fullySupportedTypes, prepareProvider: true);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_rename;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => clientCapabilities.renameValidation
|
||||
? Either2<bool, RenameOptions>.t2(RenameOptions(prepareProvider: true))
|
||||
: Either2<bool, RenameOptions>.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.rename;
|
||||
}
|
||||
|
|
|
@ -5,11 +5,16 @@
|
|||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/computer/computer_selection_ranges.dart'
|
||||
hide SelectionRange;
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
|
||||
typedef StaticOptions
|
||||
= Either3<bool, SelectionRangeOptions, SelectionRangeRegistrationOptions>;
|
||||
|
||||
class SelectionRangeHandler
|
||||
extends LspMessageHandler<SelectionRangeParams, List<SelectionRange>?> {
|
||||
SelectionRangeHandler(super.server);
|
||||
|
@ -72,3 +77,21 @@ class SelectionRangeHandler
|
|||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
class SelectionRangeRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
SelectionRangeRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options =>
|
||||
SelectionRangeRegistrationOptions(documentSelector: [dartFiles]);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_selectionRange;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either3.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.selectionRange;
|
||||
}
|
||||
|
|
|
@ -6,12 +6,18 @@ import 'dart:async';
|
|||
|
||||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/computer/computer_highlights.dart';
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analysis_server/src/lsp/semantic_tokens/encoder.dart';
|
||||
import 'package:analysis_server/src/lsp/semantic_tokens/legend.dart';
|
||||
import 'package:analyzer/source/source_range.dart';
|
||||
import 'package:analyzer_plugin/protocol/protocol_common.dart';
|
||||
|
||||
typedef StaticOptions
|
||||
= Either2<SemanticTokensOptions, SemanticTokensRegistrationOptions>;
|
||||
|
||||
abstract class AbstractSemanticTokensHandler<T>
|
||||
extends LspMessageHandler<T, SemanticTokens?>
|
||||
with LspPluginRequestHandlerMixin {
|
||||
|
@ -142,3 +148,34 @@ class SemanticTokensRangeHandler
|
|||
MessageInfo message, CancellationToken token) =>
|
||||
_handleImpl(params.textDocument, token, range: params.range);
|
||||
}
|
||||
|
||||
class SemanticTokensRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
SemanticTokensRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options => SemanticTokensRegistrationOptions(
|
||||
documentSelector: fullySupportedTypes,
|
||||
legend: semanticTokenLegend.lspLegend,
|
||||
full: Either2<bool, SemanticTokensOptionsFull>.t2(
|
||||
SemanticTokensOptionsFull(delta: false),
|
||||
),
|
||||
range: Either2<bool, SemanticTokensOptionsRange>.t1(true),
|
||||
);
|
||||
|
||||
@override
|
||||
Method get registrationMethod =>
|
||||
CustomMethods.semanticTokenDynamicRegistration;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either2.t1(
|
||||
SemanticTokensOptions(
|
||||
legend: semanticTokenLegend.lspLegend,
|
||||
full: Either2.t2(SemanticTokensOptionsFull(delta: false)),
|
||||
range: Either2.t1(true),
|
||||
),
|
||||
);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.semanticTokens;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/computer/computer_signature.dart';
|
||||
import 'package:analysis_server/src/computer/computer_type_arguments_signature.dart';
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/src/dartdoc/dartdoc_directive_info.dart';
|
||||
|
||||
|
@ -129,3 +131,27 @@ class SignatureHelpHandler
|
|||
return typeSignature;
|
||||
}
|
||||
}
|
||||
|
||||
class SignatureHelpRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<SignatureHelpOptions> {
|
||||
SignatureHelpRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options => SignatureHelpRegistrationOptions(
|
||||
documentSelector: fullySupportedTypes,
|
||||
triggerCharacters: dartSignatureHelpTriggerCharacters,
|
||||
retriggerCharacters: dartSignatureHelpRetriggerCharacters,
|
||||
);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_signatureHelp;
|
||||
|
||||
@override
|
||||
SignatureHelpOptions get staticOptions => SignatureHelpOptions(
|
||||
triggerCharacters: dartSignatureHelpTriggerCharacters,
|
||||
retriggerCharacters: dartSignatureHelpRetriggerCharacters,
|
||||
);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.signatureHelp;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ class InitializedLspStateMessageHandler extends InitializedStateMessageHandler {
|
|||
ReferencesHandler.new,
|
||||
CodeActionHandler.new,
|
||||
ExecuteCommandHandler.new,
|
||||
WorkspaceFoldersHandler.new,
|
||||
ChangeWorkspaceFoldersHandler.new,
|
||||
PrepareRenameHandler.new,
|
||||
RenameHandler.new,
|
||||
FoldingHandler.new,
|
||||
|
|
|
@ -7,8 +7,11 @@ import 'dart:async';
|
|||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analysis_server/src/lsp/source_edits.dart';
|
||||
|
||||
typedef StaticOptions = Either2<TextDocumentSyncKind, TextDocumentSyncOptions>;
|
||||
|
||||
class TextDocumentChangeHandler
|
||||
extends LspMessageHandler<DidChangeTextDocumentParams, void> {
|
||||
TextDocumentChangeHandler(super.server);
|
||||
|
@ -108,3 +111,49 @@ class TextDocumentOpenHandler
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
class TextDocumentRegistrations extends FeatureRegistration
|
||||
with StaticRegistration<StaticOptions> {
|
||||
TextDocumentRegistrations(super.info);
|
||||
|
||||
@override
|
||||
List<LspDynamicRegistration> get dynamicRegistrations {
|
||||
return [
|
||||
(
|
||||
Method.textDocument_didOpen,
|
||||
TextDocumentRegistrationOptions(documentSelector: synchronisedTypes),
|
||||
),
|
||||
(
|
||||
Method.textDocument_didClose,
|
||||
TextDocumentRegistrationOptions(documentSelector: synchronisedTypes),
|
||||
),
|
||||
(
|
||||
Method.textDocument_didChange,
|
||||
TextDocumentChangeRegistrationOptions(
|
||||
syncKind: TextDocumentSyncKind.Incremental,
|
||||
documentSelector: synchronisedTypes),
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either2.t2(TextDocumentSyncOptions(
|
||||
openClose: true,
|
||||
change: TextDocumentSyncKind.Incremental,
|
||||
willSave: false,
|
||||
willSaveWaitUntil: false,
|
||||
save: null,
|
||||
));
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.textSync;
|
||||
|
||||
List<TextDocumentFilterWithScheme> get synchronisedTypes {
|
||||
return {
|
||||
...fullySupportedTypes,
|
||||
pubspecFile,
|
||||
analysisOptionsFile,
|
||||
fixDataFile,
|
||||
}.toList();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/ast/syntactic_entity.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
|
@ -17,6 +19,9 @@ import 'package:analyzer/src/dart/element/element.dart' as analyzer;
|
|||
import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
|
||||
import 'package:analyzer_plugin/utilities/analyzer_converter.dart';
|
||||
|
||||
typedef StaticOptions
|
||||
= Either3<bool, TypeDefinitionOptions, TypeDefinitionRegistrationOptions>;
|
||||
|
||||
class TypeDefinitionHandler extends SharedMessageHandler<TypeDefinitionParams,
|
||||
TextDocumentTypeDefinitionResult> with LspPluginRequestHandlerMixin {
|
||||
static const _emptyResult = TextDocumentTypeDefinitionResult.t2([]);
|
||||
|
@ -188,3 +193,22 @@ class TypeDefinitionHandler extends SharedMessageHandler<TypeDefinitionParams,
|
|||
return node.staticType;
|
||||
}
|
||||
}
|
||||
|
||||
class TypeDefinitionRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
TypeDefinitionRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options => TextDocumentRegistrationOptions(
|
||||
documentSelector: [dartFiles], // This is currently Dart-specific
|
||||
);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_typeDefinition;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either3.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.typeDefinition;
|
||||
}
|
||||
|
|
|
@ -8,14 +8,19 @@ import 'package:analysis_server/lsp_protocol/protocol.dart';
|
|||
import 'package:analysis_server/src/analysis_server.dart';
|
||||
import 'package:analysis_server/src/computer/computer_lazy_type_hierarchy.dart'
|
||||
as type_hierarchy;
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analyzer/dart/analysis/results.dart';
|
||||
import 'package:analyzer/dart/analysis/session.dart';
|
||||
import 'package:analyzer/source/line_info.dart';
|
||||
import 'package:analyzer/source/source_range.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
|
||||
typedef StaticOptions
|
||||
= Either3<bool, TypeHierarchyOptions, TypeHierarchyRegistrationOptions>;
|
||||
|
||||
/// A handler for the initial "prepare" request for starting navigation with
|
||||
/// Type Hierarchy.
|
||||
///
|
||||
|
@ -70,6 +75,25 @@ class PrepareTypeHierarchyHandler extends SharedMessageHandler<
|
|||
}
|
||||
}
|
||||
|
||||
class TypeHierarchyRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
TypeHierarchyRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options => TypeHierarchyRegistrationOptions(
|
||||
documentSelector: [dartFiles],
|
||||
);
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.textDocument_prepareTypeHierarchy;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either3.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.typeHierarchy;
|
||||
}
|
||||
|
||||
class TypeHierarchySubtypesHandler extends SharedMessageHandler<
|
||||
TypeHierarchySubtypesParams,
|
||||
TypeHierarchySubtypesResult> with _TypeHierarchyUtils {
|
||||
|
|
|
@ -3,10 +3,14 @@
|
|||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analysis_server/src/services/refactoring/legacy/refactoring.dart';
|
||||
|
||||
typedef StaticOptions = FileOperationRegistrationOptions?;
|
||||
|
||||
class WillRenameFilesHandler
|
||||
extends LspMessageHandler<RenameFilesParams, WorkspaceEdit?> {
|
||||
WillRenameFilesHandler(super.server);
|
||||
|
@ -56,3 +60,28 @@ class WillRenameFilesHandler
|
|||
return success(edit);
|
||||
}
|
||||
}
|
||||
|
||||
class WillRenameFilesRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration, StaticRegistration<StaticOptions> {
|
||||
WillRenameFilesRegistrations(super.info);
|
||||
|
||||
@override
|
||||
FileOperationRegistrationOptions? get options =>
|
||||
fileOperationRegistrationOptions;
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.workspace_willRenameFiles;
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => options;
|
||||
|
||||
@override
|
||||
bool get supportsDynamic =>
|
||||
updateImportsOnRename && clientDynamic.fileOperations;
|
||||
|
||||
@override
|
||||
bool get supportsStatic => updateImportsOnRename;
|
||||
|
||||
bool get updateImportsOnRename =>
|
||||
clientConfiguration.global.updateImportsOnRename;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
|
||||
class WorkspaceDidChangeConfigurationMessageHandler
|
||||
extends LspMessageHandler<DidChangeConfigurationParams, void> {
|
||||
|
@ -28,3 +29,17 @@ class WorkspaceDidChangeConfigurationMessageHandler
|
|||
return success(null);
|
||||
}
|
||||
}
|
||||
|
||||
class WorkspaceDidChangeConfigurationRegistrations extends FeatureRegistration
|
||||
with SingleDynamicRegistration {
|
||||
WorkspaceDidChangeConfigurationRegistrations(super.info);
|
||||
|
||||
@override
|
||||
ToJsonable? get options => null;
|
||||
|
||||
@override
|
||||
Method get registrationMethod => Method.workspace_didChangeConfiguration;
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => clientDynamic.didChangeConfiguration;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,11 @@
|
|||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
|
||||
import 'package:analysis_server/src/lsp/mapping.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
import 'package:analyzer/src/dart/analysis/search.dart' as search;
|
||||
|
||||
typedef StaticOptions = Either2<bool, WorkspaceSymbolOptions>;
|
||||
|
||||
class WorkspaceSymbolHandler extends SharedMessageHandler<WorkspaceSymbolParams,
|
||||
List<SymbolInformation>> {
|
||||
WorkspaceSymbolHandler(super.server);
|
||||
|
@ -115,3 +118,17 @@ class WorkspaceSymbolHandler extends SharedMessageHandler<WorkspaceSymbolParams,
|
|||
containerName: declaration.className ?? declaration.mixinName);
|
||||
}
|
||||
}
|
||||
|
||||
class WorkspaceSymbolRegistrations extends FeatureRegistration
|
||||
with StaticRegistration<StaticOptions> {
|
||||
WorkspaceSymbolRegistrations(super.info);
|
||||
|
||||
@override
|
||||
List<LspDynamicRegistration> get dynamicRegistrations => [];
|
||||
|
||||
@override
|
||||
StaticOptions get staticOptions => Either2.t1(true);
|
||||
|
||||
@override
|
||||
bool get supportsDynamic => false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analysis_server/lsp_protocol/protocol.dart';
|
||||
import 'package:analysis_server/src/lsp/client_capabilities.dart';
|
||||
import 'package:analysis_server/src/lsp/client_configuration.dart';
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_call_hierarchy.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_change_workspace_folders.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_code_actions.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_completion.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_definition.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_document_color.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_document_highlights.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_document_symbols.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_execute_command.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_folding.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_format_on_type.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_format_range.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_formatting.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_hover.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_implementation.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_inlay_hint.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_references.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_rename.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_selection_range.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_semantic_tokens.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_signature_help.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_text_document_changes.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_type_definition.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_type_hierarchy.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_will_rename_files.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_workspace_configuration.dart';
|
||||
import 'package:analysis_server/src/lsp/handlers/handler_workspace_symbols.dart';
|
||||
import 'package:analysis_server/src/lsp/server_capabilities_computer.dart';
|
||||
|
||||
typedef LspDynamicRegistration = (Method, ToJsonable?);
|
||||
|
||||
/// Provides static/dynamic registration info for an LSP feature.
|
||||
abstract class FeatureRegistration {
|
||||
final RegistrationContext _context;
|
||||
|
||||
FeatureRegistration(this._context);
|
||||
|
||||
/// The capabilities of the client.
|
||||
LspClientCapabilities get clientCapabilities => _context.clientCapabilities;
|
||||
|
||||
/// The configuration provided by the client.
|
||||
LspClientConfiguration get clientConfiguration =>
|
||||
_context.clientConfiguration;
|
||||
|
||||
/// A helper to see which features the client supports dynamic registrations
|
||||
/// for. This information is derived from the [ClientCapabilities].
|
||||
ClientDynamicRegistrations get clientDynamic => _context.clientDynamic;
|
||||
|
||||
/// Gets all dynamic registrations for this feature.
|
||||
///
|
||||
/// These registrations should only be used if [supportsDynamic] returns true.
|
||||
List<LspDynamicRegistration> get dynamicRegistrations;
|
||||
|
||||
/// Types of documents that are fully supported by the server.
|
||||
///
|
||||
/// File types like pubspec.yaml, analysis_options.yaml and fix_data files are
|
||||
/// not included here as their support is very limited and do not provide
|
||||
/// functionality in most handlers.
|
||||
List<TextDocumentFilterWithScheme> get fullySupportedTypes {
|
||||
return {
|
||||
dartFiles,
|
||||
...pluginTypes,
|
||||
}.toList();
|
||||
}
|
||||
|
||||
/// Types of documents that loaded plugins are interetsed in.
|
||||
List<TextDocumentFilterWithScheme> get pluginTypes => _context.pluginTypes;
|
||||
|
||||
/// Whether both the client, and this feature, support dynamic registration.
|
||||
bool get supportsDynamic;
|
||||
}
|
||||
|
||||
/// A helper to provide access to all feature registrations.
|
||||
class LspFeatures {
|
||||
final CallHierarchyRegistrations callHierarchy;
|
||||
final ChangeWorkspaceFoldersRegistrations changeNotifications;
|
||||
final CodeActionRegistrations codeActions;
|
||||
final CompletionRegistrations completion;
|
||||
final DefinitionRegistrations definition;
|
||||
final DocumentColorRegistrations colors;
|
||||
final DocumentHighlightsRegistrations documentHighlight;
|
||||
final DocumentSymbolsRegistrations documentSymbol;
|
||||
final ExecuteCommandRegistrations executeCommand;
|
||||
final FoldingRegistrations foldingRange;
|
||||
final FormatOnTypeRegistrations formatOnType;
|
||||
final FormatRangeRegistrations formatRange;
|
||||
final FormattingRegistrations format;
|
||||
final HoverRegistrations hover;
|
||||
final ImplementationRegistrations implementation;
|
||||
final InlayHintRegistrations inlayHint;
|
||||
final ReferencesRegistrations references;
|
||||
final RenameRegistrations rename;
|
||||
final SelectionRangeRegistrations selectionRange;
|
||||
final SemanticTokensRegistrations semanticTokens;
|
||||
final SignatureHelpRegistrations signatureHelp;
|
||||
final TextDocumentRegistrations textDocumentSync;
|
||||
final TypeDefinitionRegistrations typeDefinition;
|
||||
final TypeHierarchyRegistrations typeHierarchy;
|
||||
final WillRenameFilesRegistrations willRename;
|
||||
final WorkspaceDidChangeConfigurationRegistrations
|
||||
workspaceDidChangeConfiguration;
|
||||
final WorkspaceSymbolRegistrations workspaceSymbol;
|
||||
|
||||
LspFeatures(RegistrationContext context)
|
||||
: callHierarchy = CallHierarchyRegistrations(context),
|
||||
changeNotifications = ChangeWorkspaceFoldersRegistrations(context),
|
||||
codeActions = CodeActionRegistrations(context),
|
||||
colors = DocumentColorRegistrations(context),
|
||||
completion = CompletionRegistrations(context),
|
||||
definition = DefinitionRegistrations(context),
|
||||
format = FormattingRegistrations(context),
|
||||
documentHighlight = DocumentHighlightsRegistrations(context),
|
||||
formatOnType = FormatOnTypeRegistrations(context),
|
||||
formatRange = FormatRangeRegistrations(context),
|
||||
documentSymbol = DocumentSymbolsRegistrations(context),
|
||||
executeCommand = ExecuteCommandRegistrations(context),
|
||||
foldingRange = FoldingRegistrations(context),
|
||||
hover = HoverRegistrations(context),
|
||||
implementation = ImplementationRegistrations(context),
|
||||
inlayHint = InlayHintRegistrations(context),
|
||||
references = ReferencesRegistrations(context),
|
||||
rename = RenameRegistrations(context),
|
||||
selectionRange = SelectionRangeRegistrations(context),
|
||||
semanticTokens = SemanticTokensRegistrations(context),
|
||||
signatureHelp = SignatureHelpRegistrations(context),
|
||||
textDocumentSync = TextDocumentRegistrations(context),
|
||||
typeDefinition = TypeDefinitionRegistrations(context),
|
||||
typeHierarchy = TypeHierarchyRegistrations(context),
|
||||
willRename = WillRenameFilesRegistrations(context),
|
||||
workspaceDidChangeConfiguration =
|
||||
WorkspaceDidChangeConfigurationRegistrations(context),
|
||||
workspaceSymbol = WorkspaceSymbolRegistrations(context);
|
||||
|
||||
List<FeatureRegistration> get allFeatures => [
|
||||
callHierarchy,
|
||||
changeNotifications,
|
||||
codeActions,
|
||||
completion,
|
||||
definition,
|
||||
colors,
|
||||
documentHighlight,
|
||||
documentSymbol,
|
||||
executeCommand,
|
||||
foldingRange,
|
||||
formatOnType,
|
||||
formatRange,
|
||||
format,
|
||||
hover,
|
||||
implementation,
|
||||
inlayHint,
|
||||
references,
|
||||
rename,
|
||||
selectionRange,
|
||||
semanticTokens,
|
||||
signatureHelp,
|
||||
textDocumentSync,
|
||||
typeDefinition,
|
||||
typeHierarchy,
|
||||
willRename,
|
||||
workspaceDidChangeConfiguration,
|
||||
workspaceSymbol,
|
||||
];
|
||||
}
|
||||
|
||||
class RegistrationContext {
|
||||
/// A helper to see which features the client supports dynamic registrations
|
||||
/// for. This information is derived from the [ClientCapabilities].
|
||||
final ClientDynamicRegistrations clientDynamic;
|
||||
|
||||
/// Types of documents that loaded plugins are interetsed in.
|
||||
final List<TextDocumentFilterWithScheme> pluginTypes;
|
||||
|
||||
/// The capabilities of the client.
|
||||
final LspClientCapabilities clientCapabilities;
|
||||
|
||||
/// The configuration provided by the client.
|
||||
final LspClientConfiguration clientConfiguration;
|
||||
|
||||
RegistrationContext({
|
||||
required this.clientCapabilities,
|
||||
required this.clientConfiguration,
|
||||
required this.pluginTypes,
|
||||
}) : clientDynamic = ClientDynamicRegistrations(clientCapabilities.raw);
|
||||
}
|
||||
|
||||
/// A helper mixin to simplify feature registrations that only provide a single
|
||||
/// dynamic registration.
|
||||
mixin SingleDynamicRegistration on FeatureRegistration {
|
||||
@override
|
||||
List<LspDynamicRegistration> get dynamicRegistrations {
|
||||
return [(registrationMethod, options)];
|
||||
}
|
||||
|
||||
/// The options to use for static registration if it is to be used.
|
||||
ToJsonable? get options;
|
||||
|
||||
/// The [Method] used for dynamic registration.
|
||||
Method get registrationMethod;
|
||||
}
|
||||
|
||||
/// A helper that adds support for static registration of a feature.
|
||||
mixin StaticRegistration<T> on FeatureRegistration {
|
||||
/// The raw options used for static registration. This should be accessed via
|
||||
/// [staticRegistration] to ensure it's only used when a) static registration
|
||||
/// is supported/enabled and b) dynamic registration is not supported.
|
||||
T get staticOptions;
|
||||
|
||||
/// Only return static registration options if we support static and do not
|
||||
/// support dynamic registration.
|
||||
///
|
||||
/// Some features will override [supportsStatic] to check options, so we must
|
||||
/// check [supportsDynamic] explicitly too.
|
||||
T? get staticRegistration =>
|
||||
supportsStatic && !supportsDynamic ? staticOptions : null;
|
||||
|
||||
/// Whether this feature supports static registration.
|
||||
///
|
||||
/// This is usually `true`, but may be overridden by client settings.
|
||||
bool get supportsStatic => true;
|
||||
}
|
|
@ -7,7 +7,7 @@ import 'package:analysis_server/src/analysis_server.dart';
|
|||
import 'package:analysis_server/src/lsp/client_capabilities.dart';
|
||||
import 'package:analysis_server/src/lsp/constants.dart';
|
||||
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
|
||||
import 'package:analysis_server/src/lsp/semantic_tokens/legend.dart';
|
||||
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
|
||||
|
||||
/// Helper for reading client dynamic registrations which may be omitted by the
|
||||
/// client.
|
||||
|
@ -131,197 +131,74 @@ class ClientDynamicRegistrations {
|
|||
}
|
||||
|
||||
class ServerCapabilitiesComputer {
|
||||
static final fileOperationRegistrationOptions =
|
||||
FileOperationRegistrationOptions(
|
||||
filters: [
|
||||
FileOperationFilter(
|
||||
scheme: 'file',
|
||||
pattern: FileOperationPattern(
|
||||
glob: '**/*.dart',
|
||||
matches: FileOperationPatternKind.file,
|
||||
),
|
||||
),
|
||||
FileOperationFilter(
|
||||
scheme: 'file',
|
||||
pattern: FileOperationPattern(
|
||||
glob: '**/',
|
||||
matches: FileOperationPatternKind.folder,
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
final LspAnalysisServer _server;
|
||||
|
||||
/// List of current registrations.
|
||||
Set<Registration> currentRegistrations = {};
|
||||
var _lastRegistrationId = 0;
|
||||
|
||||
final dartFiles =
|
||||
TextDocumentFilterWithScheme(language: 'dart', scheme: 'file');
|
||||
final pubspecFile = TextDocumentFilterWithScheme(
|
||||
language: 'yaml', scheme: 'file', pattern: '**/pubspec.yaml');
|
||||
final analysisOptionsFile = TextDocumentFilterWithScheme(
|
||||
language: 'yaml', scheme: 'file', pattern: '**/analysis_options.yaml');
|
||||
final fixDataFile = TextDocumentFilterWithScheme(
|
||||
language: 'yaml',
|
||||
scheme: 'file',
|
||||
pattern: '**/lib/{fix_data.yaml,fix_data/**.yaml}');
|
||||
|
||||
ServerCapabilitiesComputer(this._server);
|
||||
|
||||
List<TextDocumentFilterWithScheme> get pluginTypes => AnalysisServer
|
||||
.supportsPlugins
|
||||
? _server.pluginManager.plugins
|
||||
.expand(
|
||||
(plugin) => plugin.currentSession?.interestingFiles ?? const [],
|
||||
)
|
||||
// All published plugins use something like `*.extension` as
|
||||
// interestingFiles. Prefix a `**/` so that the glob matches nested
|
||||
// folders as well.
|
||||
.map((glob) =>
|
||||
TextDocumentFilterWithScheme(scheme: 'file', pattern: '**/$glob'))
|
||||
.toList()
|
||||
: <TextDocumentFilterWithScheme>[];
|
||||
|
||||
ServerCapabilities computeServerCapabilities(
|
||||
LspClientCapabilities clientCapabilities) {
|
||||
final codeActionLiteralSupport = clientCapabilities.literalCodeActions;
|
||||
final renameOptionsSupport = clientCapabilities.renameValidation;
|
||||
final enableFormatter =
|
||||
_server.lspClientConfiguration.global.enableSdkFormatter;
|
||||
final previewCommitCharacters =
|
||||
_server.lspClientConfiguration.global.previewCommitCharacters;
|
||||
LspClientCapabilities clientCapabilities,
|
||||
) {
|
||||
final context = RegistrationContext(
|
||||
clientCapabilities: clientCapabilities,
|
||||
clientConfiguration: _server.lspClientConfiguration,
|
||||
pluginTypes: pluginTypes,
|
||||
);
|
||||
final features = LspFeatures(context);
|
||||
|
||||
final dynamicRegistrations =
|
||||
ClientDynamicRegistrations(clientCapabilities.raw);
|
||||
|
||||
// When adding new capabilities to the server that may apply to specific file
|
||||
// types, it's important to update
|
||||
// [InitializedMessageHandler._performDynamicRegistration()] to notify
|
||||
// supporting clients of this. This avoids clients needing to hard-code the
|
||||
// list of what files types we support (and allows them to avoid sending
|
||||
// requests where we have only partial support for some types).
|
||||
return ServerCapabilities(
|
||||
textDocumentSync: dynamicRegistrations.textSync
|
||||
? null
|
||||
: Either2<TextDocumentSyncKind, TextDocumentSyncOptions>.t2(
|
||||
TextDocumentSyncOptions(
|
||||
// The open/close and sync kind flags are registered dynamically if the
|
||||
// client supports them, so these static registrations are based on whether
|
||||
// the client supports dynamic registration.
|
||||
openClose: true,
|
||||
change: TextDocumentSyncKind.Incremental,
|
||||
willSave: false,
|
||||
willSaveWaitUntil: false,
|
||||
save: null,
|
||||
)),
|
||||
callHierarchyProvider: dynamicRegistrations.callHierarchy
|
||||
? null
|
||||
: Either3<bool, CallHierarchyOptions,
|
||||
CallHierarchyRegistrationOptions>.t1(true),
|
||||
completionProvider: dynamicRegistrations.completion
|
||||
? null
|
||||
: CompletionOptions(
|
||||
triggerCharacters: dartCompletionTriggerCharacters,
|
||||
allCommitCharacters: previewCommitCharacters
|
||||
? dartCompletionCommitCharacters
|
||||
: null,
|
||||
resolveProvider: true,
|
||||
),
|
||||
hoverProvider: dynamicRegistrations.hover
|
||||
? null
|
||||
: Either2<bool, HoverOptions>.t1(true),
|
||||
signatureHelpProvider: dynamicRegistrations.signatureHelp
|
||||
? null
|
||||
: SignatureHelpOptions(
|
||||
triggerCharacters: dartSignatureHelpTriggerCharacters,
|
||||
retriggerCharacters: dartSignatureHelpRetriggerCharacters,
|
||||
),
|
||||
definitionProvider: dynamicRegistrations.definition
|
||||
? null
|
||||
: Either2<bool, DefinitionOptions>.t1(true),
|
||||
implementationProvider: dynamicRegistrations.implementation
|
||||
? null
|
||||
: Either3<bool, ImplementationOptions,
|
||||
ImplementationRegistrationOptions>.t1(
|
||||
true,
|
||||
),
|
||||
referencesProvider: dynamicRegistrations.references
|
||||
? null
|
||||
: Either2<bool, ReferenceOptions>.t1(true),
|
||||
documentHighlightProvider: dynamicRegistrations.documentHighlights
|
||||
? null
|
||||
: Either2<bool, DocumentHighlightOptions>.t1(true),
|
||||
documentSymbolProvider: dynamicRegistrations.documentSymbol
|
||||
? null
|
||||
: Either2<bool, DocumentSymbolOptions>.t1(true),
|
||||
// "The `CodeActionOptions` return type is only valid if the client
|
||||
// signals code action literal support via the property
|
||||
// `textDocument.codeAction.codeActionLiteralSupport`."
|
||||
codeActionProvider: dynamicRegistrations.codeActions
|
||||
? null
|
||||
: codeActionLiteralSupport
|
||||
? Either2<bool, CodeActionOptions>.t2(CodeActionOptions(
|
||||
codeActionKinds: DartCodeActionKind.serverSupportedKinds,
|
||||
))
|
||||
: Either2<bool, CodeActionOptions>.t1(true),
|
||||
colorProvider: dynamicRegistrations.colorProvider
|
||||
? null
|
||||
: Either3<bool, DocumentColorOptions,
|
||||
DocumentColorRegistrationOptions>.t3(
|
||||
DocumentColorRegistrationOptions(documentSelector: [dartFiles])),
|
||||
documentFormattingProvider: dynamicRegistrations.formatting
|
||||
? null
|
||||
: Either2<bool, DocumentFormattingOptions>.t1(enableFormatter),
|
||||
documentOnTypeFormattingProvider: dynamicRegistrations.typeFormatting
|
||||
? null
|
||||
: enableFormatter
|
||||
? DocumentOnTypeFormattingOptions(
|
||||
firstTriggerCharacter: dartTypeFormattingCharacters.first,
|
||||
moreTriggerCharacter:
|
||||
dartTypeFormattingCharacters.skip(1).toList())
|
||||
: null,
|
||||
documentRangeFormattingProvider: dynamicRegistrations.typeFormatting
|
||||
? null
|
||||
: Either2<bool, DocumentRangeFormattingOptions>.t1(enableFormatter),
|
||||
inlayHintProvider: dynamicRegistrations.inlayHints
|
||||
? null
|
||||
: Either3<bool, InlayHintOptions, InlayHintRegistrationOptions>.t2(
|
||||
InlayHintOptions(resolveProvider: false),
|
||||
),
|
||||
renameProvider: dynamicRegistrations.rename
|
||||
? null
|
||||
: renameOptionsSupport
|
||||
? Either2<bool, RenameOptions>.t2(
|
||||
RenameOptions(prepareProvider: true))
|
||||
: Either2<bool, RenameOptions>.t1(true),
|
||||
foldingRangeProvider: dynamicRegistrations.folding
|
||||
? null
|
||||
: Either3<bool, FoldingRangeOptions,
|
||||
FoldingRangeRegistrationOptions>.t1(
|
||||
true,
|
||||
),
|
||||
selectionRangeProvider: dynamicRegistrations.selectionRange
|
||||
? null
|
||||
: Either3<bool, SelectionRangeOptions,
|
||||
SelectionRangeRegistrationOptions>.t1(true),
|
||||
semanticTokensProvider: dynamicRegistrations.semanticTokens
|
||||
? null
|
||||
: Either2<SemanticTokensOptions,
|
||||
SemanticTokensRegistrationOptions>.t1(
|
||||
SemanticTokensOptions(
|
||||
legend: semanticTokenLegend.lspLegend,
|
||||
full: Either2<bool, SemanticTokensOptionsFull>.t2(
|
||||
SemanticTokensOptionsFull(delta: false),
|
||||
),
|
||||
range: Either2<bool, SemanticTokensOptionsRange>.t1(true),
|
||||
),
|
||||
),
|
||||
typeHierarchyProvider: dynamicRegistrations.typeHierarchy
|
||||
? null
|
||||
: Either3<bool, TypeHierarchyOptions,
|
||||
TypeHierarchyRegistrationOptions>.t1(true),
|
||||
executeCommandProvider: ExecuteCommandOptions(
|
||||
commands: Commands.serverSupportedCommands,
|
||||
workDoneProgress: true,
|
||||
),
|
||||
workspaceSymbolProvider: Either2<bool, WorkspaceSymbolOptions>.t1(true),
|
||||
textDocumentSync: features.textDocumentSync.staticRegistration,
|
||||
callHierarchyProvider: features.callHierarchy.staticRegistration,
|
||||
completionProvider: features.completion.staticRegistration,
|
||||
hoverProvider: features.hover.staticRegistration,
|
||||
signatureHelpProvider: features.signatureHelp.staticRegistration,
|
||||
definitionProvider: features.definition.staticRegistration,
|
||||
implementationProvider: features.implementation.staticRegistration,
|
||||
referencesProvider: features.references.staticRegistration,
|
||||
documentHighlightProvider: features.documentHighlight.staticRegistration,
|
||||
documentSymbolProvider: features.documentSymbol.staticRegistration,
|
||||
codeActionProvider: features.codeActions.staticRegistration,
|
||||
colorProvider: features.colors.staticRegistration,
|
||||
documentFormattingProvider: features.format.staticRegistration,
|
||||
documentOnTypeFormattingProvider:
|
||||
features.formatOnType.staticRegistration,
|
||||
documentRangeFormattingProvider: features.formatRange.staticRegistration,
|
||||
inlayHintProvider: features.inlayHint.staticRegistration,
|
||||
renameProvider: features.rename.staticRegistration,
|
||||
foldingRangeProvider: features.foldingRange.staticRegistration,
|
||||
selectionRangeProvider: features.selectionRange.staticRegistration,
|
||||
semanticTokensProvider: features.semanticTokens.staticRegistration,
|
||||
typeDefinitionProvider: features.typeDefinition.staticRegistration,
|
||||
typeHierarchyProvider: features.typeHierarchy.staticRegistration,
|
||||
executeCommandProvider: features.executeCommand.staticRegistration,
|
||||
workspaceSymbolProvider: features.workspaceSymbol.staticRegistration,
|
||||
workspace: ServerCapabilitiesWorkspace(
|
||||
workspaceFolders: WorkspaceFoldersServerCapabilities(
|
||||
supported: true,
|
||||
changeNotifications: Either2<bool, String>.t1(true),
|
||||
changeNotifications: features.changeNotifications.staticRegistration,
|
||||
),
|
||||
fileOperations: dynamicRegistrations.fileOperations
|
||||
? null
|
||||
: FileOperationOptions(
|
||||
willRename: fileOperationRegistrationOptions,
|
||||
),
|
||||
fileOperations: !context.clientDynamic.fileOperations
|
||||
? FileOperationOptions(
|
||||
willRename: features.willRename.staticRegistration,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -334,247 +211,27 @@ class ServerCapabilitiesComputer {
|
|||
/// support and it will be up to them to decide which file types they will
|
||||
/// send requests for.
|
||||
Future<void> performDynamicRegistration() async {
|
||||
final pluginTypes = AnalysisServer.supportsPlugins
|
||||
? _server.pluginManager.plugins
|
||||
.expand(
|
||||
(plugin) => plugin.currentSession?.interestingFiles ?? const [])
|
||||
// All published plugins use something like `*.extension` as
|
||||
// interestingFiles. Prefix a `**/` so that the glob matches nested
|
||||
// folders as well.
|
||||
.map((glob) => TextDocumentFilterWithScheme(
|
||||
scheme: 'file', pattern: '**/$glob'))
|
||||
: <TextDocumentFilterWithScheme>[];
|
||||
final pluginTypesExcludingDart =
|
||||
pluginTypes.where((filter) => filter.pattern != '**/*.dart');
|
||||
|
||||
final fullySupportedTypes = {dartFiles, ...pluginTypes}.toList();
|
||||
|
||||
// Add pubspec + analysis options only for synchronisation. We do not support
|
||||
// things like hovers/formatting/etc. for these files so there's no point
|
||||
// in having the client send those requests (plus, for things like formatting
|
||||
// this could result in the editor reporting "multiple formatters installed"
|
||||
// and prevent a built-in YAML formatter from being selected).
|
||||
final synchronisedTypes = {
|
||||
...fullySupportedTypes,
|
||||
pubspecFile,
|
||||
analysisOptionsFile,
|
||||
fixDataFile,
|
||||
}.toList();
|
||||
|
||||
// Completion is supported for some synchronised files that we don't _fully_
|
||||
// support (eg. YAML). If these gain support for things like hover, we may
|
||||
// wish to move them to fullySupportedTypes but add an exclusion for formatting.
|
||||
final completionSupportedTypesExcludingDart = {
|
||||
// Dart is excluded here at it's registered separately with trigger/commit
|
||||
// characters.
|
||||
...pluginTypesExcludingDart,
|
||||
pubspecFile,
|
||||
analysisOptionsFile,
|
||||
fixDataFile,
|
||||
}.toList();
|
||||
|
||||
final context = RegistrationContext(
|
||||
clientCapabilities: _server.lspClientCapabilities!,
|
||||
clientConfiguration: _server.lspClientConfiguration,
|
||||
pluginTypes: pluginTypes,
|
||||
);
|
||||
final features = LspFeatures(context);
|
||||
final registrations = <Registration>[];
|
||||
|
||||
final enableFormatter =
|
||||
_server.lspClientConfiguration.global.enableSdkFormatter;
|
||||
final previewCommitCharacters =
|
||||
_server.lspClientConfiguration.global.previewCommitCharacters;
|
||||
final updateImportsOnRename =
|
||||
_server.lspClientConfiguration.global.updateImportsOnRename;
|
||||
|
||||
/// Helper for creating registrations with IDs.
|
||||
void register(bool condition, Method method, [ToJsonable? options]) {
|
||||
if (condition == true) {
|
||||
registrations.add(Registration(
|
||||
id: (_lastRegistrationId++).toString(),
|
||||
method: method.toString(),
|
||||
registerOptions: options));
|
||||
}
|
||||
}
|
||||
|
||||
final dynamicRegistrations =
|
||||
ClientDynamicRegistrations(_server.lspClientCapabilities!.raw);
|
||||
|
||||
register(
|
||||
dynamicRegistrations.textSync,
|
||||
Method.textDocument_didOpen,
|
||||
TextDocumentRegistrationOptions(documentSelector: synchronisedTypes),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.textSync,
|
||||
Method.textDocument_didClose,
|
||||
TextDocumentRegistrationOptions(documentSelector: synchronisedTypes),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.textSync,
|
||||
Method.textDocument_didChange,
|
||||
TextDocumentChangeRegistrationOptions(
|
||||
syncKind: TextDocumentSyncKind.Incremental,
|
||||
documentSelector: synchronisedTypes),
|
||||
);
|
||||
// Trigger and commit characters are specific to Dart, so register them
|
||||
// separately to the others.
|
||||
register(
|
||||
dynamicRegistrations.completion,
|
||||
Method.textDocument_completion,
|
||||
CompletionRegistrationOptions(
|
||||
documentSelector: [dartFiles],
|
||||
triggerCharacters: dartCompletionTriggerCharacters,
|
||||
allCommitCharacters:
|
||||
previewCommitCharacters ? dartCompletionCommitCharacters : null,
|
||||
resolveProvider: true,
|
||||
),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.completion,
|
||||
Method.textDocument_completion,
|
||||
CompletionRegistrationOptions(
|
||||
documentSelector: completionSupportedTypesExcludingDart,
|
||||
resolveProvider: true,
|
||||
),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.hover,
|
||||
Method.textDocument_hover,
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.signatureHelp,
|
||||
Method.textDocument_signatureHelp,
|
||||
SignatureHelpRegistrationOptions(
|
||||
documentSelector: fullySupportedTypes,
|
||||
triggerCharacters: dartSignatureHelpTriggerCharacters,
|
||||
retriggerCharacters: dartSignatureHelpRetriggerCharacters,
|
||||
),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.references,
|
||||
Method.textDocument_references,
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.documentHighlights,
|
||||
Method.textDocument_documentHighlight,
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.documentSymbol,
|
||||
Method.textDocument_documentSymbol,
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.colorProvider,
|
||||
// This registration covers both documentColor and colorPresentation.
|
||||
Method.textDocument_documentColor,
|
||||
DocumentColorRegistrationOptions(documentSelector: [dartFiles]),
|
||||
);
|
||||
register(
|
||||
enableFormatter && dynamicRegistrations.formatting,
|
||||
Method.textDocument_formatting,
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
|
||||
);
|
||||
register(
|
||||
enableFormatter && dynamicRegistrations.typeFormatting,
|
||||
Method.textDocument_onTypeFormatting,
|
||||
DocumentOnTypeFormattingRegistrationOptions(
|
||||
documentSelector: [dartFiles], // This one is currently Dart-specific
|
||||
firstTriggerCharacter: dartTypeFormattingCharacters.first,
|
||||
moreTriggerCharacter: dartTypeFormattingCharacters.skip(1).toList(),
|
||||
),
|
||||
);
|
||||
register(
|
||||
enableFormatter && dynamicRegistrations.rangeFormatting,
|
||||
Method.textDocument_rangeFormatting,
|
||||
DocumentRangeFormattingRegistrationOptions(
|
||||
documentSelector: [dartFiles], // This one is currently Dart-specific
|
||||
),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.definition,
|
||||
Method.textDocument_definition,
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.typeDefinition,
|
||||
Method.textDocument_typeDefinition,
|
||||
TextDocumentRegistrationOptions(
|
||||
documentSelector: [dartFiles], // This one is currently Dart-specific
|
||||
),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.implementation,
|
||||
Method.textDocument_implementation,
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.codeActions,
|
||||
Method.textDocument_codeAction,
|
||||
CodeActionRegistrationOptions(
|
||||
documentSelector: fullySupportedTypes,
|
||||
codeActionKinds: DartCodeActionKind.serverSupportedKinds,
|
||||
),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.rename,
|
||||
Method.textDocument_rename,
|
||||
RenameRegistrationOptions(
|
||||
documentSelector: fullySupportedTypes, prepareProvider: true),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.folding,
|
||||
Method.textDocument_foldingRange,
|
||||
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
|
||||
);
|
||||
register(
|
||||
updateImportsOnRename && dynamicRegistrations.fileOperations,
|
||||
Method.workspace_willRenameFiles,
|
||||
fileOperationRegistrationOptions,
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.didChangeConfiguration,
|
||||
Method.workspace_didChangeConfiguration,
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.selectionRange,
|
||||
Method.textDocument_selectionRange,
|
||||
SelectionRangeRegistrationOptions(
|
||||
documentSelector: [dartFiles],
|
||||
),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.callHierarchy,
|
||||
Method.textDocument_prepareCallHierarchy,
|
||||
CallHierarchyRegistrationOptions(
|
||||
documentSelector: [dartFiles],
|
||||
),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.semanticTokens,
|
||||
CustomMethods.semanticTokenDynamicRegistration,
|
||||
SemanticTokensRegistrationOptions(
|
||||
documentSelector: fullySupportedTypes,
|
||||
legend: semanticTokenLegend.lspLegend,
|
||||
full: Either2<bool, SemanticTokensOptionsFull>.t2(
|
||||
SemanticTokensOptionsFull(delta: false),
|
||||
// Collect dynamic registrations for all features.
|
||||
final dynamicRegistrations = features.allFeatures
|
||||
.where((feature) => feature.supportsDynamic)
|
||||
.expand((feature) => feature.dynamicRegistrations);
|
||||
for (final (method, options) in dynamicRegistrations) {
|
||||
registrations.add(
|
||||
Registration(
|
||||
id: (_lastRegistrationId++).toString(),
|
||||
method: method.toString(),
|
||||
registerOptions: options,
|
||||
),
|
||||
range: Either2<bool, SemanticTokensOptionsRange>.t1(true),
|
||||
),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.typeHierarchy,
|
||||
Method.textDocument_prepareTypeHierarchy,
|
||||
TypeHierarchyRegistrationOptions(
|
||||
documentSelector: [dartFiles],
|
||||
),
|
||||
);
|
||||
register(
|
||||
dynamicRegistrations.inlayHints,
|
||||
Method.textDocument_inlayHint,
|
||||
InlayHintRegistrationOptions(
|
||||
documentSelector: [dartFiles],
|
||||
resolveProvider: false,
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
await _applyRegistrations(registrations);
|
||||
}
|
||||
|
|
|
@ -416,8 +416,7 @@ class InitializationTest extends AbstractLspAnalysisServerTest {
|
|||
.any((ds) => ds.pattern == '**/analysis_options.yaml'),
|
||||
isTrue);
|
||||
|
||||
expect(rename,
|
||||
equals(ServerCapabilitiesComputer.fileOperationRegistrationOptions));
|
||||
expect(rename, equals(fileOperationRegistrationOptions));
|
||||
}
|
||||
|
||||
Future<void> test_dynamicRegistration_notSupportedByClient() async {
|
||||
|
@ -463,7 +462,7 @@ class InitializationTest extends AbstractLspAnalysisServerTest {
|
|||
expect(initResult.capabilities.renameProvider, isNotNull);
|
||||
expect(initResult.capabilities.foldingRangeProvider, isNotNull);
|
||||
expect(initResult.capabilities.workspace!.fileOperations!.willRename,
|
||||
equals(ServerCapabilitiesComputer.fileOperationRegistrationOptions));
|
||||
equals(fileOperationRegistrationOptions));
|
||||
expect(initResult.capabilities.selectionRangeProvider, isNotNull);
|
||||
expect(initResult.capabilities.semanticTokensProvider, isNotNull);
|
||||
|
||||
|
|
Loading…
Reference in a new issue