Skip to content

Commit f7b7fe1

Browse files
authored
Some code actions ordering and cleanup (#11659)
There was some feedback on Reddit this morning about code action ordering and Extract to Component being a little "in your face". See https://www.reddit.com/r/Blazor/comments/1jjg3bh/am_i_doing_something_wrong_or_is_intellisense_and/mjq7jp3/?context=3 and the rest of the thread in general. This PR: * Makes sure Extract to Component always last, since it is offered basically everywhere * Makes sure Add Using and Fully Qualify are always first, since they're the most likely code actions people want * Ensures Extract to Code Behind is offered at `$$@code` since previously there would be no light bulb in that situation, but now there is and muscle-memory makes people hit it, which extract the code block to a new component, which is not what they want. Note that the ordering here is only among the Razor code actions. All C# and Html code actions are always still after the Razor code actions, even Extract to Component.
2 parents 909f4d7 + 8ac8129 commit f7b7fe1

15 files changed

+216
-132
lines changed

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/CodeActionsService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ private static async Task<ImmutableArray<RazorVSInternalCodeAction>> Consolidate
246246
{
247247
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
248248

249-
using var codeActions = new PooledArrayBuilder<RazorVSInternalCodeAction>();
249+
using var codeActions = new PooledArrayBuilder<RazorVSInternalCodeAction>(capacity: tasks.Length);
250250

251251
cancellationToken.ThrowIfCancellationRequested();
252252

@@ -255,7 +255,7 @@ private static async Task<ImmutableArray<RazorVSInternalCodeAction>> Consolidate
255255
codeActions.AddRange(result);
256256
}
257257

258-
return codeActions.ToImmutable();
258+
return codeActions.DrainToImmutableOrderedBy(static r => r.Order);
259259
}
260260

261261
private static ImmutableHashSet<string> GetAllAvailableCodeActionNames()

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Models/RazorVSInternalCodeAction.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,10 @@ internal sealed class RazorVSInternalCodeAction : VSInternalCodeAction
1313
[JsonPropertyName("name")]
1414
[DataMember(Name = "name")]
1515
public string? Name { get; set; }
16+
17+
/// <summary>
18+
/// The order code actions should appear. This is not serialized as its just used in the code actions service
19+
/// </summary>
20+
[JsonIgnore]
21+
public int Order { get; set; }
1622
}

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/ExtractToCodeBehindCodeActionProvider.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ public Task<ImmutableArray<RazorVSInternalCodeAction>> ProvideAsync(RazorCodeAct
5757
// When the caret is '@$$code' or '@c$$ode' or '@co$$de' or '@cod$$e' then tree is:
5858
// RazorDirective -> RazorDirectiveBody -> MetaCode
5959
RazorDirectiveBodySyntax { Parent: RazorDirectiveSyntax d } => d,
60+
// When the caret is '$$@code' then tree is:
61+
// RazorDirective
62+
RazorDirectiveSyntax d => d,
6063
_ => null
6164
};
6265
if (directiveNode is null)

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/CodeActions/Razor/RazorCodeActionFactory.cs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ public static RazorVSInternalCodeAction CreateAddComponentUsing(string @namespac
4848
Title = newTagName is null ? title : $"{newTagName} - {title}",
4949
Data = data,
5050
TelemetryId = s_addComponentUsingTelemetryId,
51-
Priority = VSInternalPriorityLevel.High
51+
Priority = VSInternalPriorityLevel.High,
52+
Name = LanguageServerConstants.CodeActions.AddUsing,
53+
// Adding a using for an existing component should be first
54+
Order = -1000,
5255
};
5356
return codeAction;
5457
}
@@ -60,46 +63,51 @@ public static RazorVSInternalCodeAction CreateFullyQualifyComponent(string fully
6063
Title = fullyQualifiedName,
6164
Edit = workspaceEdit,
6265
TelemetryId = s_fullyQualifyComponentTelemetryId,
63-
Priority = VSInternalPriorityLevel.High
66+
Priority = VSInternalPriorityLevel.High,
67+
Name = LanguageServerConstants.CodeActions.FullyQualify,
68+
// Fully qualifying an existing component should be very high, but not quite as high as Add Using
69+
Order = -900,
6470
};
6571
return codeAction;
6672
}
6773

6874
public static RazorVSInternalCodeAction CreateComponentFromTag(RazorCodeActionResolutionParams resolutionParams)
6975
{
70-
var title = SR.Create_Component_FromTag_Title;
7176
var data = JsonSerializer.SerializeToElement(resolutionParams);
7277
var codeAction = new RazorVSInternalCodeAction()
7378
{
74-
Title = title,
79+
Title = SR.Create_Component_FromTag_Title,
7580
Data = data,
7681
TelemetryId = s_createComponentFromTagTelemetryId,
82+
Name = LanguageServerConstants.CodeActions.CreateComponentFromTag,
7783
};
7884
return codeAction;
7985
}
8086

8187
public static RazorVSInternalCodeAction CreateExtractToCodeBehind(RazorCodeActionResolutionParams resolutionParams)
8288
{
83-
var title = SR.ExtractTo_CodeBehind_Title;
8489
var data = JsonSerializer.SerializeToElement(resolutionParams);
8590
var codeAction = new RazorVSInternalCodeAction()
8691
{
87-
Title = title,
92+
Title = SR.ExtractTo_CodeBehind_Title,
8893
Data = data,
8994
TelemetryId = s_createExtractToCodeBehindTelemetryId,
95+
Name = LanguageServerConstants.CodeActions.ExtractToCodeBehindAction,
9096
};
9197
return codeAction;
9298
}
9399

94100
public static RazorVSInternalCodeAction CreateExtractToComponent(RazorCodeActionResolutionParams resolutionParams)
95101
{
96-
var title = SR.ExtractTo_Component_Title;
97102
var data = JsonSerializer.SerializeToElement(resolutionParams);
98103
var codeAction = new RazorVSInternalCodeAction()
99104
{
100-
Title = title,
105+
Title = SR.ExtractTo_Component_Title,
101106
Data = data,
102107
TelemetryId = s_createExtractToComponentTelemetryId,
108+
Name = LanguageServerConstants.CodeActions.ExtractToNewComponentAction,
109+
// Since Extract to Component is offered basically everywhere, always offer it last
110+
Order = 9999
103111
};
104112
return codeAction;
105113
}
@@ -127,7 +135,8 @@ public static RazorVSInternalCodeAction CreateGenerateMethod(VSTextDocumentIdent
127135
{
128136
Title = title,
129137
Data = data,
130-
TelemetryId = s_generateMethodTelemetryId
138+
TelemetryId = s_generateMethodTelemetryId,
139+
Name = LanguageServerConstants.CodeActions.GenerateEventHandler,
131140
};
132141
return codeAction;
133142
}
@@ -155,7 +164,8 @@ public static RazorVSInternalCodeAction CreateAsyncGenerateMethod(VSTextDocument
155164
{
156165
Title = title,
157166
Data = data,
158-
TelemetryId = s_generateAsyncMethodTelemetryId
167+
TelemetryId = s_generateAsyncMethodTelemetryId,
168+
Name = LanguageServerConstants.CodeActions.GenerateAsyncEventHandler,
159169
};
160170
return codeAction;
161171
}

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/LanguageServerConstants.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public static class CodeActions
3535
{
3636
public const string GenerateEventHandler = "GenerateEventHandler";
3737

38+
public const string GenerateAsyncEventHandler = "GenerateAsyncEventHandler";
39+
3840
public const string EditBasedCodeActionCommand = "EditBasedCodeActionCommand";
3941

4042
public const string ExtractToCodeBehindAction = "ExtractToCodeBehind";
@@ -45,6 +47,8 @@ public static class CodeActions
4547

4648
public const string AddUsing = "AddUsing";
4749

50+
public const string FullyQualify = "FullyQualify";
51+
4852
public const string PromoteUsingDirective = "PromoteUsingDirective";
4953

5054
public const string CodeActionFromVSCode = "CodeActionFromVSCode";

0 commit comments

Comments
 (0)