mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:49:00 +00:00
[dds/dap] Forward toolEvents on to the DAP client
Progress towards https://github.com/Dart-Code/Dart-Code/issues/4193.
Also related:
- https://github.com/flutter/flutter/pull/118098
- 4981cbffe2
Change-Id: I7b1394a5d5003c24b90733f1898fe368c0485937
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/278515
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
This commit is contained in:
parent
ebab6fb4de
commit
3949fe9aec
7 changed files with 121 additions and 8 deletions
|
@ -1,3 +1,7 @@
|
|||
# 2.7.2
|
||||
- Update DDS protocol version to 1.4.
|
||||
- [DAP] Forward any events from the VM Service's `ToolEvent` stream as `dart.toolEvent` DAP events.
|
||||
|
||||
# 2.7.1
|
||||
- Updated `vm_service` version to >=9.0.0 <11.0.0.
|
||||
- Simplified the DevTools URI composed by DDS.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Dart Development Service Protocol 1.3
|
||||
# Dart Development Service Protocol 1.4
|
||||
|
||||
This document describes _version 1.3_ of the Dart Development Service Protocol.
|
||||
This document describes _version 1.4_ of the Dart Development Service Protocol.
|
||||
This protocol is an extension of the Dart VM Service Protocol and implements it
|
||||
in it's entirety. For details on the VM Service Protocol, see the [Dart VM Service Protocol Specification][service-protocol].
|
||||
|
||||
|
@ -69,6 +69,8 @@ consist of the following:
|
|||
In addition, subscribing to the `Service` stream will result in a `ServiceRegistered`
|
||||
event being sent to the subscribing client for each existing service extension.
|
||||
|
||||
From protocol version 1.4, custom streams of any name can be listened to via DDS.
|
||||
|
||||
## Public RPCs
|
||||
|
||||
The DDS Protocol supports all [public RPCs defined in the VM Service protocol][service-protocol-public-rpcs].
|
||||
|
@ -281,6 +283,7 @@ version | comments
|
|||
1.1 | Added `getDartDevelopmentServiceVersion` RPC.
|
||||
1.2 | Added `getStreamHistory` RPC.
|
||||
1.3 | Added `getAvailableCachedCpuSamples` and `getCachedCpuSamples` RPCs.
|
||||
1.4 | Added the ability to subscribe to custom streams (which can be specified when calling `dart:developer`'s `postEvent`).
|
||||
|
||||
[resume]: https://github.com/dart-lang/sdk/blob/main/runtime/vm/service/service.md#resume
|
||||
[success]: https://github.com/dart-lang/sdk/blob/main/runtime/vm/service/service.md#success
|
||||
|
|
|
@ -160,7 +160,7 @@ abstract class DartDevelopmentService {
|
|||
|
||||
/// The version of the DDS protocol supported by this [DartDevelopmentService]
|
||||
/// instance.
|
||||
static const String protocolVersion = '1.3';
|
||||
static const String protocolVersion = '1.4';
|
||||
}
|
||||
|
||||
class DartDevelopmentServiceException implements Exception {
|
||||
|
|
|
@ -439,6 +439,16 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
|
|||
/// preserve order.
|
||||
Future? _lastOutputEvent;
|
||||
|
||||
/// Capabilities of the DDS instance available in the connected VM Service.
|
||||
///
|
||||
/// If the VM Service is not yet connected, does not have a DDS instance, or
|
||||
/// the version has not been been fetched, all capabilities will be false.
|
||||
_DdsCapabilities _ddsCapabilities = _DdsCapabilities.empty;
|
||||
|
||||
/// The ID of the custom VM Service stream that emits events intended for
|
||||
/// tools/IDEs.
|
||||
static final toolEventStreamId = 'ToolEvent';
|
||||
|
||||
/// Removes any breakpoints or pause behaviour and resumes any paused
|
||||
/// isolates.
|
||||
///
|
||||
|
@ -621,6 +631,18 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
|
|||
final vmService = await _vmServiceConnectUri(uri.toString());
|
||||
logger?.call('Connected to debugger at $uri!');
|
||||
|
||||
// Fetch DDS capabilities.
|
||||
final supportedProtocols = await vmService.getSupportedProtocols();
|
||||
final ddsProtocol = supportedProtocols.protocols
|
||||
?.firstWhereOrNull((protocol) => protocol.protocolName == 'DDS');
|
||||
if (ddsProtocol != null) {
|
||||
_ddsCapabilities = _DdsCapabilities(
|
||||
major: ddsProtocol.major ?? 0,
|
||||
minor: ddsProtocol.minor ?? 0,
|
||||
);
|
||||
}
|
||||
final supportsCustomStreams = _ddsCapabilities.supportsCustomStreams;
|
||||
|
||||
// Send debugger URI to the client.
|
||||
sendDebuggerUris(uri);
|
||||
|
||||
|
@ -637,10 +659,12 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
|
|||
vmService.onLoggingEvent.listen(wrap(handleLoggingEvent)),
|
||||
vmService.onExtensionEvent.listen(wrap(handleExtensionEvent)),
|
||||
vmService.onServiceEvent.listen(wrap(handleServiceEvent)),
|
||||
if (_subscribeToOutputStreams)
|
||||
if (supportsCustomStreams)
|
||||
vmService.onEvent(toolEventStreamId).listen(wrap(handleToolEvent)),
|
||||
if (_subscribeToOutputStreams) ...[
|
||||
vmService.onStdoutEvent.listen(wrap(_handleStdoutEvent)),
|
||||
if (_subscribeToOutputStreams)
|
||||
vmService.onStderrEvent.listen(wrap(_handleStderrEvent)),
|
||||
],
|
||||
]);
|
||||
await Future.wait([
|
||||
vmService.streamListen(vm.EventStreams.kIsolate),
|
||||
|
@ -648,8 +672,11 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
|
|||
vmService.streamListen(vm.EventStreams.kLogging),
|
||||
vmService.streamListen(vm.EventStreams.kExtension),
|
||||
vmService.streamListen(vm.EventStreams.kService),
|
||||
vmService.streamListen(vm.EventStreams.kStdout),
|
||||
vmService.streamListen(vm.EventStreams.kStderr),
|
||||
if (supportsCustomStreams) vmService.streamListen(toolEventStreamId),
|
||||
if (_subscribeToOutputStreams) ...[
|
||||
vmService.streamListen(vm.EventStreams.kStdout),
|
||||
vmService.streamListen(vm.EventStreams.kStderr),
|
||||
],
|
||||
]);
|
||||
|
||||
final vmInfo = await vmService.getVM();
|
||||
|
@ -2028,6 +2055,20 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
|
|||
}
|
||||
}
|
||||
|
||||
@protected
|
||||
@mustCallSuper
|
||||
Future<void> handleToolEvent(vm.Event event) async {
|
||||
await debuggerInitialized;
|
||||
|
||||
sendEvent(
|
||||
RawEventBody({
|
||||
'kind': event.extensionKind,
|
||||
'data': event.extensionData?.data,
|
||||
}),
|
||||
eventType: 'dart.toolEvent',
|
||||
);
|
||||
}
|
||||
|
||||
void _handleStderrEvent(vm.Event event) {
|
||||
_sendOutputStreamEvent('stderr', event);
|
||||
}
|
||||
|
@ -2339,3 +2380,28 @@ class DartLaunchRequestArguments extends DartCommonLaunchAttachRequestArguments
|
|||
static DartLaunchRequestArguments fromJson(Map<String, Object?> obj) =>
|
||||
DartLaunchRequestArguments.fromMap(obj);
|
||||
}
|
||||
|
||||
/// A helper for checking whether the available DDS instance has specific
|
||||
/// capabilities.
|
||||
class _DdsCapabilities {
|
||||
final int major;
|
||||
final int minor;
|
||||
|
||||
static const empty = _DdsCapabilities(major: 0, minor: 0);
|
||||
|
||||
const _DdsCapabilities({required this.major, required this.minor});
|
||||
|
||||
/// Whether the DDS instance supports custom streams via `dart:developer`'s
|
||||
/// `postEvent`.
|
||||
bool get supportsCustomStreams => _isAtLeast(major: 1, minor: 4);
|
||||
|
||||
bool _isAtLeast({required major, required minor}) {
|
||||
if (this.major > major) {
|
||||
return true;
|
||||
} else if (this.major == major && this.minor >= minor) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -420,6 +420,31 @@ main() {
|
|||
await server.exitCode;
|
||||
}
|
||||
});
|
||||
|
||||
test('forwards tool events to client', () async {
|
||||
final testFile = dap.createTestFile(simpleToolEventProgram);
|
||||
|
||||
// Capture any `dart.toolEvent` events.
|
||||
final toolEventsFuture = dap.client.events('dart.toolEvent').toList();
|
||||
|
||||
// Run the script to completion.
|
||||
await Future.wait([
|
||||
dap.client.event('terminated'),
|
||||
dap.client.initialize(),
|
||||
dap.client.launch(testFile.path),
|
||||
], eagerError: true);
|
||||
|
||||
// Verify we got exactly the event in the sample program.
|
||||
final toolEvents = await toolEventsFuture;
|
||||
expect(toolEvents, hasLength(1));
|
||||
final toolEvent = toolEvents.single;
|
||||
expect(toolEvent.body, {
|
||||
'kind': 'navigate',
|
||||
'data': {
|
||||
'file': 'x.dart',
|
||||
},
|
||||
});
|
||||
});
|
||||
// These tests can be slow due to starting up the external server process.
|
||||
}, timeout: Timeout.none);
|
||||
|
||||
|
|
|
@ -199,5 +199,21 @@ const simpleThrowingProgram = r'''
|
|||
}
|
||||
''';
|
||||
|
||||
/// A simple Dart script that sends a `navigate` event to the `ToolEvent`
|
||||
/// stream.
|
||||
const simpleToolEventProgram = r'''
|
||||
import 'dart:developer';
|
||||
|
||||
void main(List<String> args) async {
|
||||
postEvent(
|
||||
'navigate',
|
||||
{
|
||||
'file': 'x.dart',
|
||||
},
|
||||
stream: 'ToolEvent',
|
||||
);
|
||||
}
|
||||
''';
|
||||
|
||||
/// A marker used in some test scripts/tests for where to expected steps.
|
||||
const stepMarker = '// STEP';
|
||||
|
|
|
@ -185,4 +185,3 @@ When running the `--test` debug adapter, `package:test` JSON messages will be pa
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
Loading…
Reference in a new issue