Closed helin24 closed 1 month ago
I haven't figured it out yet, but when I use this version of DevTools, the sidebar no longer loads in VS Code (it shows a spinner indefinitely - though there are no errors in the console). If I revert to the last commit this was based on, everything works fine.
I'll keep debugging, but if anyone has any ideas what could impact this (nothing in the code looks related to me!), please let me know!
I see the issue... we're creating a second DtdEditorClient
on the same DTD connection. DtdEditorClient
expects to have a one-to-one relationship with a DTD connection, because it calls things like streamListen('Service')
and if there is another user of the connection, it may have already subscribed to that.
To fix this specific issue, we could ensure the theme manager uses the same DtdEditorClient
that the sidebar is using - however I think there may be some additional issues we need to deal with here - which is if DevTools is going to have a single connection to DTD and we may want to subscribe to different kinds of services, we may need a single central class that manages tracking which services are available (since we can only subscribe to the Service
stream once, and if the DtdEditorClient has done it, then other code won't be able to do it and won't know if their services are available).
Some ideas:
DtdEditorClient
always creates its own DTD connection from the URI, regardless of anything elseDtdEditorClient
in DTDManager
that can be used in both places (this fixes the current issue, but doesn't make DTD generally easier to consume multiple services from)DartToolingDaemon
that supports multiple subscribers to _dtd.onEvent('Service')
by tracking the active services internally, and when there's a new subscriber, it re-sends events for the active services and then forwards any new incoming eventsDtdEditorClient
uses them instead of directly interacting with the service stream at all)@DanTup thanks for the debugging and thoughts here!
I'm inclined for this PR to do:
- Create a single DtdEditorClient in DTDManager that can be used in both places (this fixes the current issue, but doesn't make DTD generally easier to consume multiple services from)
It seems odd to create multiple DTD connections for one service (DevTools), and it sounds like options 3 and 4 warrant more consideration outside the scope of this change. What do you think? Also @kenzieschmoll
@helin24 I started trying to share one, but then found that DtdEditorClient.event
is also a single-listener stream, but both the sidebar and theme manager try to listen on it. Making it broadcast could result in lost events depending on the ordering.
So as a simple fix to avoid holding this PR up, I suggest we just use DTD directly here (don't use the editor client). It's a tiny change and I can look at refactoring DtdEditorClient
later (it will be easier when we get rid of the PostMessage implementation, since they share interfaces, and I think we should do that after the next branch for stable).
Here's the diff that uses DTD directly:
PS D:\Dev\Google\devtools> git diff
diff --git a/packages/devtools_app/lib/src/framework/theme_manager.dart b/packages/devtools_app/lib/src/framework/theme_manager.dart
index f79a96b8f..c41bec15d 100644
--- a/packages/devtools_app/lib/src/framework/theme_manager.dart
+++ b/packages/devtools_app/lib/src/framework/theme_manager.dart
@@ -10,7 +10,6 @@ import 'package:dtd/dtd.dart';
import 'package:logging/logging.dart';
import '../service/editor/api_classes.dart';
-import '../service/editor/editor_client.dart';
import '../shared/globals.dart';
final _log = Logger('theme_manager');
@@ -18,17 +17,16 @@ final _log = Logger('theme_manager');
/// Manages changes in theme settings from an editor/IDE.
class EditorThemeManager extends DisposableController
with AutoDisposeControllerMixin {
- EditorThemeManager(DartToolingDaemon dtd)
- : editorClient = DtdEditorClient(dtd);
+ EditorThemeManager(this.dtd);
- final DtdEditorClient editorClient;
+ final DartToolingDaemon dtd;
void listenForThemeChanges() {
autoDisposeStreamSubscription(
- editorClient.event.listen((event) {
- if (event is ThemeChangedEvent) {
+ dtd.onEvent(editorStreamName).listen((event) {
+ if (event.kind == EditorEventKind.themeChanged.toString()) {
final currentTheme = getIdeTheme();
- final newTheme = event.theme;
+ final newTheme = ThemeChangedEvent.fromJson(event.data).theme;
if (currentTheme.isDarkMode != newTheme.isDarkMode) {
updateQueryParameter(
@helin24 @kenzieschmoll btw, just as an FYI in case it comes up... while testing this in VS Code I found a weird bug where query string params (for colors + font size) were being lost. It turns out to be that something in Flutter is decoding encoded #
s in the URL causing anything after them to be treated as a client-side fragment any time we update the URL in updateQueryParameter
.
I've filed https://github.com/flutter/flutter/issues/155992 about it, but as a workaround, it turns out we will parse hex colours from the querystring with or without the hashes, so I'm updating VS Code to instead of doing (%23
is a percent-encoded #
):
&backgroundColor=%23000000
Just doing:
&backgroundColor=000000
This fixes the issue I saw (which is that the background color for dark mode was always black, even when the theme had a slightly different dark shade). If IntelliJ also passes background/foreground colors, it may be worth ensuring it doesn't include the #
to avoid any issue arising from that too.
@helin24 we'll need to also add the .catch
for streamListen
in DtdEditorClient
, like this:
https://github.com/DanTup/devtools/commit/b062884104a3498f1b1e10f785e94a36016975f8
(I think you should be able to easily apply this locally with git fetch https://github.com/DanTup/devtools && git cherry-pick b062884104a3498f1b1e10f785e94a36016975f8
)
With this PR + that change, the sidebar is working fine in VS Code.
(I also fixed that we were using editorServiceName
instead of editorStreamName
in that code - the values are the same so it doesn't change anything, but it was a little misleading).
@DanTup thanks for the patch! I applied it with copy and paste because I got this error from git: fatal: bad object b062884104a3498f1b1e10f785e94a36016975f8
Maybe something related to forks? 🤷
Addresses https://github.com/flutter/flutter-intellij/issues/7626