Skip to content

Commit 6929f9e

Browse files
committed
Added support for MarkupTagHelperElements
1 parent 74ab788 commit 6929f9e

File tree

2 files changed

+34
-49
lines changed

2 files changed

+34
-49
lines changed

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToComponentCodeActionProvider.cs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,23 +82,32 @@ private static bool IsValidContext(RazorCodeActionContext context)
8282
private static bool IsSelectionValid(RazorCodeActionContext context, RazorSyntaxTree syntaxTree)
8383
{
8484
var owner = syntaxTree.Root.FindInnermostNode(context.Location.AbsoluteIndex, includeWhitespace: true);
85-
var startElementNode = owner?.FirstAncestorOrSelf<MarkupElementSyntax>();
86-
return startElementNode is not null && !IsInsideProperHtmlContent(context, startElementNode) && !HasDiagnosticErrors(startElementNode);
85+
if (owner is null)
86+
{
87+
return false;
88+
}
89+
90+
var startElementNode = owner.FirstAncestorOrSelf<MarkupSyntaxNode>(node => node is MarkupElementSyntax or MarkupTagHelperElementSyntax);
91+
return startElementNode is not null && !HasDiagnosticErrors(startElementNode) && !IsInsideProperHtmlContent(context, owner);
8792
}
8893

89-
private static bool IsInsideProperHtmlContent(RazorCodeActionContext context, MarkupElementSyntax startElementNode)
94+
private static bool IsInsideProperHtmlContent(RazorCodeActionContext context, SyntaxNode owner)
9095
{
91-
// If the provider executes before the user/completion inserts an end tag, the below return fails
92-
if (startElementNode.EndTag.IsMissing)
93-
{
94-
return true;
95-
}
96+
var tryMakeMarkupElement = owner.FirstAncestorOrSelf<MarkupElementSyntax>();
97+
var tryMakeMarkupTagHelperElement = owner.FirstAncestorOrSelf<MarkupTagHelperElementSyntax>();
98+
99+
var isLocationInProperMarkupElement = tryMakeMarkupElement is not null &&
100+
context.Location.AbsoluteIndex > tryMakeMarkupElement.StartTag.Span.End &&
101+
context.Location.AbsoluteIndex < tryMakeMarkupElement.EndTag.SpanStart;
102+
103+
var isLocationInProperMarkupTagHelper = tryMakeMarkupTagHelperElement is not null &&
104+
context.Location.AbsoluteIndex > tryMakeMarkupTagHelperElement.StartTag.Span.End &&
105+
context.Location.AbsoluteIndex < tryMakeMarkupTagHelperElement.EndTag.SpanStart;
96106

97-
return context.Location.AbsoluteIndex > startElementNode.StartTag.Span.End &&
98-
context.Location.AbsoluteIndex < startElementNode.EndTag.SpanStart;
107+
return isLocationInProperMarkupElement || isLocationInProperMarkupTagHelper;
99108
}
100109

101-
private static bool HasDiagnosticErrors(MarkupElementSyntax markupElement)
110+
private static bool HasDiagnosticErrors(MarkupSyntaxNode markupElement)
102111
{
103112
var diagnostics = markupElement.GetDiagnostics();
104113
return diagnostics.Any(d => d.Severity == RazorDiagnosticSeverity.Error);

src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToComponentCodeActionResolver.cs

Lines changed: 14 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ internal sealed class ExtractToComponentCodeActionResolver(
124124

125125
var newComponentContent = newComponentResult.NewContents;
126126
var componentNameAndParams = GenerateComponentNameAndParameters(newComponentResult.Methods, componentName);
127-
127+
128128
var componentDocumentIdentifier = new OptionalVersionedTextDocumentIdentifier { Uri = actionParams.Uri };
129129
var newComponentDocumentIdentifier = new OptionalVersionedTextDocumentIdentifier { Uri = newComponentUri };
130130

@@ -175,7 +175,7 @@ internal sealed record SelectionAnalysisResult
175175
public int ExtractStart;
176176
public int ExtractEnd;
177177
public HashSet<string>? ComponentDependencies;
178-
public HashSet<string>? VariableDependencies;
178+
public HashSet<string>? TentativeVariableDependencies;
179179
}
180180

181181
private static SelectionAnalysisResult TryAnalyzeSelection(RazorCodeDocument codeDocument, ExtractToComponentCodeActionParams actionParams)
@@ -191,20 +191,20 @@ private static SelectionAnalysisResult TryAnalyzeSelection(RazorCodeDocument cod
191191
var (success, extractStart, extractEnd) = TryProcessMultiPointSelection(startElementNode, endElementNode, codeDocument, actionParams);
192192

193193
var dependencyScanRoot = FindNearestCommonAncestor(startElementNode, endElementNode) ?? startElementNode;
194-
var methodDependencies = AddComponentDependenciesInRange(dependencyScanRoot, extractStart, extractEnd);
194+
var componentDependencies = AddComponentDependenciesInRange(dependencyScanRoot, extractStart, extractEnd);
195195
var variableDependencies = AddVariableDependenciesInRange(dependencyScanRoot, extractStart, extractEnd);
196196

197197
return new SelectionAnalysisResult
198198
{
199199
Success = success,
200200
ExtractStart = extractStart,
201201
ExtractEnd = extractEnd,
202-
ComponentDependencies = methodDependencies,
203-
VariableDependencies = variableDependencies,
202+
ComponentDependencies = componentDependencies,
203+
TentativeVariableDependencies = variableDependencies,
204204
};
205205
}
206206

207-
private static (MarkupElementSyntax? Start, MarkupElementSyntax? End) GetStartAndEndElements(RazorCodeDocument codeDocument, ExtractToComponentCodeActionParams actionParams)
207+
private static (MarkupSyntaxNode? Start, MarkupSyntaxNode? End) GetStartAndEndElements(RazorCodeDocument codeDocument, ExtractToComponentCodeActionParams actionParams)
208208
{
209209
var syntaxTree = codeDocument.GetSyntaxTree();
210210
if (syntaxTree is null)
@@ -218,8 +218,8 @@ private static (MarkupElementSyntax? Start, MarkupElementSyntax? End) GetStartAn
218218
return (null, null);
219219
}
220220

221-
var startElementNode = owner.FirstAncestorOrSelf<MarkupElementSyntax>();
222-
if (startElementNode is null || IsInsideProperHtmlContent(actionParams.AbsoluteIndex, startElementNode))
221+
var startElementNode = owner.FirstAncestorOrSelf<MarkupSyntaxNode>(node => node is MarkupTagHelperElementSyntax or MarkupElementSyntax);
222+
if (startElementNode is null)
223223
{
224224
return (null, null);
225225
}
@@ -235,19 +235,7 @@ private static (MarkupElementSyntax? Start, MarkupElementSyntax? End) GetStartAn
235235
return (startElementNode, endElementNode);
236236
}
237237

238-
private static bool IsInsideProperHtmlContent(int absoluteIndex, MarkupElementSyntax startElementNode)
239-
{
240-
// If the provider executes before the user/completion inserts an end tag, the below return fails
241-
if (startElementNode.EndTag.IsMissing)
242-
{
243-
return true;
244-
}
245-
246-
return absoluteIndex > startElementNode.StartTag.Span.End &&
247-
absoluteIndex < startElementNode.EndTag.SpanStart;
248-
}
249-
250-
private static MarkupElementSyntax? TryGetEndElementNode(Position selectionStart, Position selectionEnd, RazorSyntaxTree syntaxTree, SourceText sourceText)
238+
private static MarkupSyntaxNode? TryGetEndElementNode(Position selectionStart, Position selectionEnd, RazorSyntaxTree syntaxTree, SourceText sourceText)
251239
{
252240
if (selectionStart == selectionEnd)
253241
{
@@ -273,7 +261,7 @@ private static bool IsInsideProperHtmlContent(int absoluteIndex, MarkupElementSy
273261
endOwner = previousSibling;
274262
}
275263

276-
return endOwner.FirstAncestorOrSelf<MarkupElementSyntax>();
264+
return endOwner.FirstAncestorOrSelf<MarkupSyntaxNode>(node => node is MarkupTagHelperElementSyntax or MarkupElementSyntax);
277265
}
278266

279267
private static SourceLocation? GetEndLocation(Position selectionEnd, SourceText sourceText)
@@ -295,7 +283,7 @@ private static bool IsInsideProperHtmlContent(int absoluteIndex, MarkupElementSy
295283
/// <param name="actionParams">The parameters for the extraction action, which will be updated.</param>
296284
/// one more line for output
297285
/// <returns>A tuple containing a boolean indicating success, the start of the extraction range, and the end of the extraction range.</returns>
298-
private static (bool success, int extractStart, int extractEnd) TryProcessMultiPointSelection(MarkupElementSyntax startElementNode, MarkupElementSyntax endElementNode, RazorCodeDocument codeDocument, ExtractToComponentCodeActionParams actionParams)
286+
private static (bool success, int extractStart, int extractEnd) TryProcessMultiPointSelection(MarkupSyntaxNode startElementNode, MarkupSyntaxNode endElementNode, RazorCodeDocument codeDocument, ExtractToComponentCodeActionParams actionParams)
299287
{
300288
var extractStart = startElementNode.Span.Start;
301289
var extractEnd = endElementNode.Span.End;
@@ -419,11 +407,9 @@ private static (SyntaxNode? Start, SyntaxNode? End) FindContainingSiblingPair(Sy
419407
private static SyntaxNode? FindNearestCommonAncestor(SyntaxNode node1, SyntaxNode node2)
420408
{
421409
var current = node1;
422-
var secondNodeIsCodeBlock = node2 is CSharpCodeBlockSyntax;
423-
424410
while (current is not null)
425411
{
426-
if (ShouldCheckNode(current, secondNodeIsCodeBlock) && current.Span.Contains(node2.Span))
412+
if (CheckNode(current) && current.Span.Contains(node2.Span))
427413
{
428414
return current;
429415
}
@@ -434,21 +420,11 @@ private static (SyntaxNode? Start, SyntaxNode? End) FindContainingSiblingPair(Sy
434420
return null;
435421
}
436422

437-
// Whenever the multi point selection includes a code block at the end, the logic for finding the nearest common ancestor and containing sibling pair
438-
// should accept nodes of type MarkupBlockSyntax and CSharpCodeBlock each, respectively. ShouldCheckNode() and IsValidNode() handle these cases.
439-
private static bool ShouldCheckNode(SyntaxNode node, bool isCodeBlock)
440-
{
441-
if (isCodeBlock)
442-
{
443-
return node is MarkupElementSyntax or MarkupBlockSyntax;
444-
}
445-
446-
return node is MarkupElementSyntax;
447-
}
423+
private static bool CheckNode(SyntaxNode node) => node is MarkupElementSyntax or MarkupTagHelperElementSyntax or MarkupBlockSyntax;
448424

449425
private static bool IsValidNode(SyntaxNode node, bool isCodeBlock)
450426
{
451-
return node is MarkupElementSyntax || (isCodeBlock && node is CSharpCodeBlockSyntax);
427+
return node is MarkupElementSyntax or MarkupTagHelperElementSyntax || (isCodeBlock && node is CSharpCodeBlockSyntax);
452428
}
453429

454430
private static HashSet<string> AddComponentDependenciesInRange(SyntaxNode root, int extractStart, int extractEnd)

0 commit comments

Comments
 (0)