-
Notifications
You must be signed in to change notification settings - Fork 340
[Property Editor] Add APIs to support refactors from the Property Editor #9202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Goldens change due to Flutter SDK update
@@ -821,7 +821,7 @@ class _RenderScrollSemantics extends RenderProxyBox { | |||
if (child.isTagged(RenderViewport.excludeFromScrolling)) { | |||
excluded.add(child); | |||
} else { | |||
if (!child.hasFlag(SemanticsFlag.isHidden)) { | |||
if (!child.flagsCollection.isHidden) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hasFlag
is deprecated in latest Flutter version, see flutter/flutter#166101
for (final method in LspMethod.values) { | ||
if (method.methodName == methodName) return method; | ||
} | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can this be return LspMethod.values.firstWhereOrNull((method) => method.methodName == methodName)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a minor perf increase I think you could also add something like:
static nameMap = LspMethod.values.asNameMap();
And then look it up as:
return nameMap[methodName];`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! Though we need the method name map instead of the name map, so I've added a static map for method name -> method to use for the look-up.
@@ -501,6 +528,105 @@ class EditableArgumentsResult with Serializable { | |||
}; | |||
} | |||
|
|||
/// Constants for [CodeAction] prefixes used to filter the results returned by | |||
/// an [LspMethod.codeAction] request. | |||
abstract class CodeActionPrefixes { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we add unit tests for all of the new logic in this file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, added editor_client_test
(also added test cases for editArgument
and editableArguments
)
@@ -99,6 +96,7 @@ void main() { | |||
mockEditorClient.getEditableArguments( | |||
textDocument: location.document, | |||
position: location.position, | |||
screenId: 'propertyEditorSidebar', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we use the analytics constant here instead of the raw string?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, done!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a few comments. Mostly minor stuff, but the deserializing of command arguments I do think we need to remove because that's not public API, it should just be round-tripped whatever it is.
for (final method in LspMethod.values) { | ||
if (method.methodName == methodName) return method; | ||
} | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a minor perf increase I think you could also add something like:
static nameMap = LspMethod.values.asNameMap();
And then look it up as:
return nameMap[methodName];`
static const line = 'line'; | ||
static const loggedAction = 'loggedAction'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually don't think DevTools should have any knowledge of these fields that appear within the command arguments. The exact command/arguments are an implementation detail so you should just be sending whatever the values of command
and arguments
back to executeCommand
without ever really looking at them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good, I've removed CodeActionArgument
args: (map[Field.arguments] as List<Object?>? ?? <Object?>[]) | ||
.cast<Map<String, Object?>>() | ||
.map(CodeActionArgument.fromJson) | ||
.toList(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So here, I think we just want args: map[Field.arguments]
and leave it as Object?
, removing the CodeActionArgument
class entirely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed! Thanks
class EditArgumentResponse { | ||
EditArgumentResponse({required this.success, this.errorMessage, errorCode}) | ||
: _errorCode = errorCode; | ||
/// Generic response representing whether a reqeust was a [success]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: reqeust
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, thanks for catching!
/// Requests that the Analysis Server makes a code edit for an argument. | ||
Future<GenericApiResponse> applyRefactor({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dartdoc is stale here (this isn't editing an argument), but maybe these should also just be called executeCommand
since it's more generic than refactors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated dartdoc and renamed to executeCommand
// in the Property Editor by default. | ||
if (FeatureFlags.propertyEditorRefactors) { | ||
// Get any supported refactors for the current position. | ||
refactorsResult = await editorClient.getRefactors( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this await
here means we don't show any of the editable fields until we also have the list of actions. I wonder if we should separate these, so that the editable fields would show immediately (perhaps with any previous actions buttons disabled) and then update the actions after. This might improve performance a little for the most likely case (using the editor and not the refactors).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I've added a TODO for once I tackle displaying the refactor buttons, will decide whether to request the refactors separately then
/// via an [LspMethod.executeCommand] request. | ||
/// | ||
/// For example, "Wrap with Center" or "Wrap with Container". | ||
class CodeAction with Serializable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I would call this CodeActionCommand
just to avoid some confusion (at least for me), because CodeActions according to LSP can actually be one of two things:
typedef CodeAction = CodeActionLiteral | Command
A CodeActionLiteral
is a newer type that supports inline edits, but DTD clients do not support them, and therefore we should always be returning Command
s to you here.
In analysis server code, I'm trying to consistently use CodeAction
to mean the union of CodeActionLiteral
and Command
, and then those names explicitly where only one is allowed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for that context! I've renamed to CodeActionCommand
|
||
List<CodeAction> _extractRefactors(CodeActionResult? result) => | ||
(result?.actions ?? <CodeAction>[]) | ||
.where((action) => action.title != null && action.command != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you seen data where any of these were null? In theory, you should only ever be getting Command
back from textDocument/codeAction
, so both fields should be non-null (except for bugs). If you get a CodeActionLiteral
back (you should not, but other editor LSP clients may) then title
should still always be non-null (per the LSP spec), although command
could be null (and if not, would be a Command
rather than a String
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No I haven't! I added this check just to be safe, though I could also make title
and command
non-nullable if we expect them to always be returned. WDYT?
Work towards #8652
This PR:
editor_client
andapi_classes
to call the APIs added in https://dart-review.googlesource.com/c/sdk/+/428784 to support refactorsThis does not update the UI to show the available refactors. That will be follow-up.
Note: Fetching the available refactors is currently protected by the
propertyEditorRefactors
feature flag.