From 97f3c49e4fbc11033d35b013026693246a530247 Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Fri, 17 Jan 2025 12:14:01 -0800 Subject: [PATCH 1/2] Check for registered LSP service methods before calling them --- .../lib/src/shared/editor/api_classes.dart | 8 ++--- .../lib/src/shared/editor/editor_client.dart | 36 ++++++++++++++++--- .../property_editor/property_editor_view.dart | 29 ++++++++++++--- .../ide_shared/property_editor_test.dart | 6 ++++ 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/packages/devtools_app/lib/src/shared/editor/api_classes.dart b/packages/devtools_app/lib/src/shared/editor/api_classes.dart index aaaea3ba0f7..6efde9348fc 100644 --- a/packages/devtools_app/lib/src/shared/editor/api_classes.dart +++ b/packages/devtools_app/lib/src/shared/editor/api_classes.dart @@ -28,14 +28,14 @@ enum EditorMethod { /// /// [code link]: https://github.com/dart-lang/sdk/blob/ebfcd436da65802a2b20d415afe600b51e432305/pkg/analysis_server/lib/src/lsp/constants.dart#L136 enum LspMethod { - editableArguments( - methodName: 'experimental/dart/textDocument/editableArguments', - ), - editArgument(methodName: 'experimental/dart/textDocument/editArgument'); + editableArguments(methodName: 'dart/textDocument/editableArguments'), + editArgument(methodName: 'dart/textDocument/editArgument'); const LspMethod({required this.methodName}); final String methodName; + + String get experimentalMethodName => 'experimental/$methodName'; } /// Known kinds of events that may come from the editor. diff --git a/packages/devtools_app/lib/src/shared/editor/editor_client.dart b/packages/devtools_app/lib/src/shared/editor/editor_client.dart index 196bb03b99c..65df1065b19 100644 --- a/packages/devtools_app/lib/src/shared/editor/editor_client.dart +++ b/packages/devtools_app/lib/src/shared/editor/editor_client.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'package:devtools_app_shared/utils.dart'; import 'package:dtd/dtd.dart'; +import 'package:flutter/foundation.dart'; import 'package:logging/logging.dart'; import '../analytics/constants.dart'; @@ -37,7 +38,8 @@ class EditorClient extends DisposableController } final service = data.data['service'] as String?; - if (service == null || service != editorServiceName) { + if (service == null || + (service != editorServiceName && service != lspServiceName)) { return; } @@ -59,6 +61,18 @@ class EditorClient extends DisposableController _supportsOpenDevToolsPage = isRegistered; _supportsOpenDevToolsForceExternal = capabilities?[Field.supportsForceExternal] == true; + } else if (method == LspMethod.editArgument.methodName) { + _editArgumentMethodName.value = LspMethod.editArgument.methodName; + } else if (method == LspMethod.editArgument.experimentalMethodName) { + _editArgumentMethodName.value = + LspMethod.editArgument.experimentalMethodName; + } else if (method == LspMethod.editableArguments.methodName) { + _editableArgumentsMethodName.value = + LspMethod.editableArguments.methodName; + } else if (method == + LspMethod.editableArguments.experimentalMethodName) { + _editableArgumentsMethodName.value = + LspMethod.editableArguments.experimentalMethodName; } else { return; } @@ -151,6 +165,14 @@ class EditorClient extends DisposableController _supportsOpenDevToolsForceExternal; var _supportsOpenDevToolsForceExternal = false; + ValueListenable get editArgumentMethodName => + _editArgumentMethodName; + final _editArgumentMethodName = ValueNotifier(null); + + ValueListenable get editableArgumentsMethodName => + _editableArgumentsMethodName; + final _editableArgumentsMethodName = ValueNotifier(null); + /// A stream of [ActiveLocationChangedEvent]s from the edtior. Stream get activeLocationChangedStream => _activeLocationChangedController.stream; @@ -235,8 +257,10 @@ class EditorClient extends DisposableController required TextDocument textDocument, required CursorPosition position, }) async { + final method = editableArgumentsMethodName.value; + if (method == null) return null; final response = await _callLspApi( - LspMethod.editableArguments, + method, params: { 'type': 'Object', // This is required by DTD. 'textDocument': textDocument.toJson(), @@ -256,8 +280,10 @@ class EditorClient extends DisposableController required String name, required T value, }) async { + final method = editArgumentMethodName.value; + if (method == null) return; final response = await _callLspApi( - LspMethod.editArgument, + method, params: { 'type': 'Object', // This is required by DTD. 'textDocument': textDocument.toJson(), @@ -278,10 +304,10 @@ class EditorClient extends DisposableController } Future _callLspApi( - LspMethod method, { + String methodName, { Map? params, }) { - return _dtd.call(lspServiceName, method.methodName, params: params); + return _dtd.call(lspServiceName, methodName, params: params); } } diff --git a/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_view.dart b/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_view.dart index 85e6557d921..11488f860d0 100644 --- a/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_view.dart +++ b/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_view.dart @@ -9,6 +9,7 @@ import 'package:flutter/services.dart'; import '../../../shared/editor/api_classes.dart'; import '../../../shared/primitives/utils.dart'; +import '../../../shared/ui/common_widgets.dart'; import 'property_editor_controller.dart'; class PropertyEditorView extends StatelessWidget { @@ -18,12 +19,28 @@ class PropertyEditorView extends StatelessWidget { @override Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // TODO(elliette): Include widget name and documentation. - _PropertiesList(controller: controller), + return MultiValueListenableBuilder( + listenables: [ + controller.editorClient.editArgumentMethodName, + controller.editorClient.editableArgumentsMethodName, ], + builder: (_, values, _) { + final editArgumentMethodName = values.first as String?; + final editableArgumentsMethodName = values.second as String?; + + if (editArgumentMethodName == null || + editableArgumentsMethodName == null) { + return const CenteredCircularProgressIndicator(); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // TODO(elliette): Include widget name and documentation. + _PropertiesList(controller: controller), + ], + ); + }, ); } } @@ -46,6 +63,8 @@ class _PropertiesList extends StatelessWidget { ? const Center( child: Text( 'No widget properties at the current cursor location.', + textDirection: TextDirection.rtl, + textAlign: TextAlign.left, ), ) : Column( diff --git a/packages/devtools_app/test/standalone_ui/ide_shared/property_editor_test.dart b/packages/devtools_app/test/standalone_ui/ide_shared/property_editor_test.dart index 7221a978b48..0e2aefabc71 100644 --- a/packages/devtools_app/test/standalone_ui/ide_shared/property_editor_test.dart +++ b/packages/devtools_app/test/standalone_ui/ide_shared/property_editor_test.dart @@ -37,6 +37,12 @@ void main() { setGlobal(IdeTheme, IdeTheme()); mockEditorClient = MockEditorClient(); + when( + mockEditorClient.editArgumentMethodName, + ).thenReturn(ValueNotifier(LspMethod.editArgument.methodName)); + when( + mockEditorClient.editableArgumentsMethodName, + ).thenReturn(ValueNotifier(LspMethod.editableArguments.methodName)); when( mockEditorClient.activeLocationChangedStream, ).thenAnswer((_) => eventStream); From a5f59234660083c2b3fecb64e64b1e883876ec3e Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Fri, 17 Jan 2025 12:16:12 -0800 Subject: [PATCH 2/2] Remove accidental change --- .../ide_shared/property_editor/property_editor_view.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_view.dart b/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_view.dart index 11488f860d0..23c24b37811 100644 --- a/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_view.dart +++ b/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_view.dart @@ -63,8 +63,6 @@ class _PropertiesList extends StatelessWidget { ? const Center( child: Text( 'No widget properties at the current cursor location.', - textDirection: TextDirection.rtl, - textAlign: TextAlign.left, ), ) : Column(