diff --git a/pkg/analyzer_plugin/CHANGELOG.md b/pkg/analyzer_plugin/CHANGELOG.md index d243c8afca54..2368dbea9844 100644 --- a/pkg/analyzer_plugin/CHANGELOG.md +++ b/pkg/analyzer_plugin/CHANGELOG.md @@ -2,6 +2,8 @@ - Remove `elementName()` from `RangeFactory`. Use `fragmentName()` instead. - Breaking changes to `DartFileEditBuilder` and `DartEditBuilder`. - Breaking changes to `AnalyzerConverter`. +- Support for a plugin to send an `AnalysisStatus` notification, featuring an + `isAnalyzing` `bool` field. ## 0.12.0 - Breaking changes to `DartFileEditBuilder`: `convertFunctionFromSyncToAsync` diff --git a/pkg/analyzer_plugin/doc/api.html b/pkg/analyzer_plugin/doc/api.html index 6c4271dce65a..d75922d57fc3 100644 --- a/pkg/analyzer_plugin/doc/api.html +++ b/pkg/analyzer_plugin/doc/api.html @@ -138,6 +138,7 @@

plugin domain

+

Requests

plugin.versionCheck
request: {
   "id": String
   "method": "plugin.versionCheck"
@@ -262,6 +263,26 @@ 

parameters:

isFatal: bool
The stack trace associated with the generation of the error, used for debugging the plugin.

+
plugin.status
notification: {
+  "event": "plugin.status"
+  "params": {
+    "analysis": optional AnalysisStatus
+  }
+}
+

+ Reports the current status of the plugin. Parameters are omitted if there + has been no change in the status represented by that parameter. +

+

+ Only used for "new" analyzer plugins. Legacy plugins should not use + this type. +

+ +

parameters:

analysis: AnalysisStatus (optional)
+ +

+ The current status of analysis (whether analysis is being performed). +

analysis domain

@@ -844,6 +865,7 @@

Types

+
AddContentOverlay: object

A directive to begin overlaying the contents of a file. The supplied @@ -957,7 +979,19 @@

Types

related to a specific list of files.

-
FOLDING
HIGHLIGHTS
NAVIGATION
OCCURRENCES
OUTLINE
ChangeContentOverlay: object
+
FOLDING
HIGHLIGHTS
NAVIGATION
OCCURRENCES
OUTLINE
AnalysisStatus: object
+

+ An indication of the current state of analysis. +

+

+ Only used for "new" analyzer plugins. Legacy plugins should not use + this type. +

+ +
isAnalyzing: bool
+ +

True if analysis is currently being performed.

+
ChangeContentOverlay: object

A directive to modify an existing file content overlay. One or more ranges of text are deleted from the old file content overlay and replaced with @@ -2379,6 +2413,6 @@

Feedback:

offset: int

Index

-

Domains

plugin ()

Requests
Notifications

analysis ()

Requests
Notifications

completion ()

Requests

edit ()

Requests

Types ()

Refactorings ()

+

Domains

plugin ()

Requests
Notifications

analysis ()

Requests
Notifications

completion ()

Requests

edit ()

Requests

Types ()

Refactorings ()

diff --git a/pkg/analyzer_plugin/lib/protocol/protocol_constants.dart b/pkg/analyzer_plugin/lib/protocol/protocol_constants.dart index 51857ecf02ee..f6ab4f800fb3 100644 --- a/pkg/analyzer_plugin/lib/protocol/protocol_constants.dart +++ b/pkg/analyzer_plugin/lib/protocol/protocol_constants.dart @@ -84,6 +84,8 @@ const String PLUGIN_NOTIFICATION_ERROR = 'plugin.error'; const String PLUGIN_NOTIFICATION_ERROR_IS_FATAL = 'isFatal'; const String PLUGIN_NOTIFICATION_ERROR_MESSAGE = 'message'; const String PLUGIN_NOTIFICATION_ERROR_STACK_TRACE = 'stackTrace'; +const String PLUGIN_NOTIFICATION_STATUS = 'plugin.status'; +const String PLUGIN_NOTIFICATION_STATUS_ANALYSIS = 'analysis'; const String PLUGIN_REQUEST_SHUTDOWN = 'plugin.shutdown'; const String PLUGIN_REQUEST_VERSION_CHECK = 'plugin.versionCheck'; const String PLUGIN_REQUEST_VERSION_CHECK_BYTE_STORE_PATH = 'byteStorePath'; diff --git a/pkg/analyzer_plugin/lib/protocol/protocol_generated.dart b/pkg/analyzer_plugin/lib/protocol/protocol_generated.dart index aa3e59b3dfda..4534c27e8e40 100644 --- a/pkg/analyzer_plugin/lib/protocol/protocol_generated.dart +++ b/pkg/analyzer_plugin/lib/protocol/protocol_generated.dart @@ -1337,6 +1337,59 @@ class AnalysisSetSubscriptionsResult implements ResponseResult { int get hashCode => 218088493; } +/// AnalysisStatus +/// +/// { +/// "isAnalyzing": bool +/// } +/// +/// Clients may not extend, implement or mix-in this class. +class AnalysisStatus implements HasToJson { + /// True if analysis is currently being performed. + bool isAnalyzing; + + AnalysisStatus(this.isAnalyzing); + + factory AnalysisStatus.fromJson( + JsonDecoder jsonDecoder, String jsonPath, Object? json, + {ClientUriConverter? clientUriConverter}) { + json ??= {}; + if (json is Map) { + bool isAnalyzing; + if (json.containsKey('isAnalyzing')) { + isAnalyzing = jsonDecoder.decodeBool( + '$jsonPath.isAnalyzing', json['isAnalyzing']); + } else { + throw jsonDecoder.mismatch(jsonPath, 'isAnalyzing'); + } + return AnalysisStatus(isAnalyzing); + } else { + throw jsonDecoder.mismatch(jsonPath, 'AnalysisStatus', json); + } + } + + @override + Map toJson({ClientUriConverter? clientUriConverter}) { + var result = {}; + result['isAnalyzing'] = isAnalyzing; + return result; + } + + @override + String toString() => json.encode(toJson(clientUriConverter: null)); + + @override + bool operator ==(other) { + if (other is AnalysisStatus) { + return isAnalyzing == other.isAnalyzing; + } + return false; + } + + @override + int get hashCode => isAnalyzing.hashCode; +} + /// analysis.updateContent params /// /// { @@ -3623,6 +3676,74 @@ class PluginShutdownResult implements ResponseResult { int get hashCode => 9389109; } +/// plugin.status params +/// +/// { +/// "analysis": optional AnalysisStatus +/// } +/// +/// Clients may not extend, implement or mix-in this class. +class PluginStatusParams implements HasToJson { + /// The current status of analysis (whether analysis is being performed). + AnalysisStatus? analysis; + + PluginStatusParams({this.analysis}); + + factory PluginStatusParams.fromJson( + JsonDecoder jsonDecoder, String jsonPath, Object? json, + {ClientUriConverter? clientUriConverter}) { + json ??= {}; + if (json is Map) { + AnalysisStatus? analysis; + if (json.containsKey('analysis')) { + analysis = AnalysisStatus.fromJson( + jsonDecoder, '$jsonPath.analysis', json['analysis'], + clientUriConverter: clientUriConverter); + } + return PluginStatusParams(analysis: analysis); + } else { + throw jsonDecoder.mismatch(jsonPath, 'plugin.status params', json); + } + } + + factory PluginStatusParams.fromNotification(Notification notification, + {ClientUriConverter? clientUriConverter}) { + return PluginStatusParams.fromJson( + ResponseDecoder(null), 'params', notification.params, + clientUriConverter: clientUriConverter); + } + + @override + Map toJson({ClientUriConverter? clientUriConverter}) { + var result = {}; + var analysis = this.analysis; + if (analysis != null) { + result['analysis'] = + analysis.toJson(clientUriConverter: clientUriConverter); + } + return result; + } + + Notification toNotification({ClientUriConverter? clientUriConverter}) { + return Notification( + 'plugin.status', toJson(clientUriConverter: clientUriConverter)); + } + + @override + String toString() => json.encode(toJson(clientUriConverter: null)); + + @override + bool operator ==(other) { + if (other is PluginStatusParams) { + return analysis == other.analysis; + } + return false; + } + + @override + int get hashCode => analysis.hashCode; +} + /// plugin.versionCheck params /// /// { diff --git a/pkg/analyzer_plugin/test/integration/support/integration_test_methods.dart b/pkg/analyzer_plugin/test/integration/support/integration_test_methods.dart index a8348e836c22..5189e4ea432d 100644 --- a/pkg/analyzer_plugin/test/integration/support/integration_test_methods.dart +++ b/pkg/analyzer_plugin/test/integration/support/integration_test_methods.dart @@ -119,6 +119,22 @@ abstract class IntegrationTestMixin { /// Stream controller for [onPluginError]. late StreamController _onPluginError; + /// Reports the current status of the plugin. Parameters are omitted if there + /// has been no change in the status represented by that parameter. + /// + /// Only used for "new" analyzer plugins. Legacy plugins should not use this + /// type. + /// + /// Parameters + /// + /// analysis: AnalysisStatus (optional) + /// + /// The current status of analysis (whether analysis is being performed). + late Stream onPluginStatus; + + /// Stream controller for [onPluginStatus]. + late StreamController _onPluginStatus; + /// Return the navigation information associated with the given region of the /// given file. If the navigation information for the given file has not yet /// been computed, or the most recently computed navigation information for @@ -661,6 +677,8 @@ abstract class IntegrationTestMixin { void initializeInttestMixin() { _onPluginError = StreamController(sync: true); onPluginError = _onPluginError.stream.asBroadcastStream(); + _onPluginStatus = StreamController(sync: true); + onPluginStatus = _onPluginStatus.stream.asBroadcastStream(); _onAnalysisErrors = StreamController(sync: true); onAnalysisErrors = _onAnalysisErrors.stream.asBroadcastStream(); _onAnalysisFolding = StreamController(sync: true); @@ -688,6 +706,11 @@ abstract class IntegrationTestMixin { _onPluginError .add(PluginErrorParams.fromJson(decoder, 'params', params)); break; + case 'plugin.status': + outOfTestExpect(params, isPluginStatusParams); + _onPluginStatus + .add(PluginStatusParams.fromJson(decoder, 'params', params)); + break; case 'analysis.errors': outOfTestExpect(params, isAnalysisErrorsParams); _onAnalysisErrors diff --git a/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart b/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart index b6775a84de53..efbc05645d21 100644 --- a/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart +++ b/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart @@ -106,6 +106,14 @@ final Matcher isAnalysisErrorType = MatchesEnum('AnalysisErrorType', [ final Matcher isAnalysisService = MatchesEnum('AnalysisService', ['FOLDING', 'HIGHLIGHTS', 'NAVIGATION', 'OCCURRENCES', 'OUTLINE']); +/// AnalysisStatus +/// +/// { +/// "isAnalyzing": bool +/// } +final Matcher isAnalysisStatus = LazyMatcher( + () => MatchesJsonObject('AnalysisStatus', {'isAnalyzing': isBool})); + /// ChangeContentOverlay /// /// { @@ -1324,6 +1332,15 @@ final Matcher isPluginShutdownParams = isNull; /// plugin.shutdown result final Matcher isPluginShutdownResult = isNull; +/// plugin.status params +/// +/// { +/// "analysis": optional AnalysisStatus +/// } +final Matcher isPluginStatusParams = LazyMatcher(() => MatchesJsonObject( + 'plugin.status params', null, + optionalFields: {'analysis': isAnalysisStatus})); + /// plugin.versionCheck params /// /// { diff --git a/pkg/analyzer_plugin/tool/spec/plugin_spec.html b/pkg/analyzer_plugin/tool/spec/plugin_spec.html index 9984810a4c40..f5eb7f67a37c 100644 --- a/pkg/analyzer_plugin/tool/spec/plugin_spec.html +++ b/pkg/analyzer_plugin/tool/spec/plugin_spec.html @@ -144,6 +144,24 @@

Overview

+ +

+ Reports the current status of the plugin. Parameters are omitted if there + has been no change in the status represented by that parameter. +

+

+ Only used for "new" analyzer plugins. Legacy plugins should not use + this type. +

+ + + AnalysisStatus +

+ The current status of analysis (whether analysis is being performed). +

+
+
+

@@ -873,6 +891,28 @@

Types

OUTLINE + +

+ An indication of the current state of analysis. +

+

+ Only used for "new" analyzer plugins. Legacy plugins should not use + this type. +

+ + + bool +

True if analysis is currently being performed.

+
+ +
+

A description of an analysis context.