Skip to content
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

Revert back to 0591c7026e0972ff2f2da0be7caf26f1590e73f6 #8377

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
Expand All @@ -18,10 +17,11 @@

namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert;

internal sealed class AutoClosingTagOnAutoInsertProvider : IOnAutoInsertProvider
internal class AutoClosingTagOnAutoInsertProvider : RazorOnAutoInsertProvider
{
// From http://dev.w3.org/html5/spec/Overview.html#elements-0
private static readonly ImmutableHashSet<string> s_voidElements = ImmutableHashSet.Create(StringComparer.OrdinalIgnoreCase,
private static readonly IReadOnlyList<string> s_voidElements = new[]
{
"area",
"base",
"br",
Expand All @@ -39,40 +39,43 @@ internal sealed class AutoClosingTagOnAutoInsertProvider : IOnAutoInsertProvider
"source",
"track",
"wbr"
);
private static readonly ImmutableHashSet<string> s_voidElementsCaseSensitive = s_voidElements.WithComparer(StringComparer.Ordinal);
};

private readonly IOptionsMonitor<RazorLSPOptions> _optionsMonitor;
private readonly ILogger<IOnAutoInsertProvider> _logger;

public AutoClosingTagOnAutoInsertProvider(IOptionsMonitor<RazorLSPOptions> optionsMonitor, ILoggerFactory loggerFactory)
: base(loggerFactory)
{
if (optionsMonitor is null)
{
throw new ArgumentNullException(nameof(optionsMonitor));
}

if (loggerFactory is null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}

_optionsMonitor = optionsMonitor;
_logger = loggerFactory.CreateLogger<IOnAutoInsertProvider>();
}

public string TriggerCharacter => ">";
public override string TriggerCharacter => ">";

public bool TryResolveInsertion(Position position, FormattingContext context, [NotNullWhen(true)] out TextEdit? edit, out InsertTextFormat format)
public override bool TryResolveInsertion(Position position, FormattingContext context, [NotNullWhen(true)] out TextEdit? edit, out InsertTextFormat format)
{
if (position is null)
{
throw new ArgumentNullException(nameof(position));
}

if (context is null)
{
throw new ArgumentNullException(nameof(context));
}

if (!_optionsMonitor.CurrentValue.AutoClosingTags)
{
format = default;
edit = default;
return false;
}

if (!position.TryGetAbsoluteIndex(context.SourceText, _logger, out var afterCloseAngleIndex))
if (!position.TryGetAbsoluteIndex(context.SourceText, Logger, out var afterCloseAngleIndex))
{
format = default;
edit = default;
Expand All @@ -94,26 +97,28 @@ public bool TryResolveInsertion(Position position, FormattingContext context, [N
NewText = $"$0</{tagName}>",
Range = new Range { Start = position, End = position },
};

return true;
}
else
{
Debug.Assert(autoClosingBehavior == AutoClosingBehavior.SelfClosing);

Debug.Assert(autoClosingBehavior == AutoClosingBehavior.SelfClosing);

format = InsertTextFormat.Plaintext;
format = InsertTextFormat.Plaintext;

// Need to replace the `>` with ' />$0' or '/>$0' depending on if there's prefixed whitespace.
var insertionText = char.IsWhiteSpace(context.SourceText[afterCloseAngleIndex - 2]) ? "/" : " /";
var insertionPosition = new Position(position.Line, position.Character - 1);
edit = new TextEdit()
{
NewText = insertionText,
Range = new Range
// Need to replace the `>` with ' />$0' or '/>$0' depending on if there's prefixed whitespace.
var insertionText = char.IsWhiteSpace(context.SourceText[afterCloseAngleIndex - 2]) ? "/" : " /";
var insertionPosition = new Position(position.Line, position.Character - 1);
var insertionRange = new Range
{
Start = insertionPosition,
End = insertionPosition
}
};
};
edit = new TextEdit()
{
NewText = insertionText,
Range = insertionRange
};

}

return true;
}
Expand All @@ -131,14 +136,12 @@ private static bool TryResolveAutoClosingBehavior(FormattingContext context, int
return false;
}

if (owner.Parent is MarkupStartTagSyntax
{
ForwardSlash: null,
Parent: MarkupElementSyntax htmlElement
} startTag)
if (owner.Parent is MarkupStartTagSyntax startTag &&
startTag.ForwardSlash is null &&
startTag.Parent is MarkupElementSyntax htmlElement)
{
var unescapedTagName = startTag.Name.Content;
autoClosingBehavior = InferAutoClosingBehavior(unescapedTagName, caseSensitive: false);
autoClosingBehavior = InferAutoClosingBehavior(unescapedTagName);

if (autoClosingBehavior == AutoClosingBehavior.EndTag && !CouldAutoCloseParentOrSelf(unescapedTagName, htmlElement))
{
Expand All @@ -153,17 +156,15 @@ private static bool TryResolveAutoClosingBehavior(FormattingContext context, int
return true;
}

if (owner.Parent is MarkupTagHelperStartTagSyntax
{
ForwardSlash: null,
Parent: MarkupTagHelperElementSyntax tagHelperElement
} startTagHelper)
if (owner.Parent is MarkupTagHelperStartTagSyntax startTagHelper &&
startTagHelper.ForwardSlash is null &&
startTagHelper.Parent is MarkupTagHelperElementSyntax tagHelperElement)
{
name = startTagHelper.Name.Content;

if (!TryGetTagHelperAutoClosingBehavior(tagHelperElement.TagHelperInfo.BindingResult, out autoClosingBehavior))
{
autoClosingBehavior = InferAutoClosingBehavior(name, caseSensitive: true);
autoClosingBehavior = InferAutoClosingBehavior(name, tagNameComparer: StringComparer.Ordinal);
}

if (autoClosingBehavior == AutoClosingBehavior.EndTag && !CouldAutoCloseParentOrSelf(name, tagHelperElement))
Expand Down Expand Up @@ -192,10 +193,8 @@ private static bool TryEnsureOwner_WorkaroundCompilerQuirks(int afterCloseAngleI
return false;
}

if (currentOwner.Parent is MarkupElementSyntax
{
StartTag: not null
} parentElement)
if (currentOwner.Parent is MarkupElementSyntax parentElement &&
parentElement.StartTag != null)
{
// In cases where a user types ">" in a C# code block there can be uncertainty as to "who owns" the edge of the element. Reason being that the tag
// could be malformed and you could be in a situation like this:
Expand All @@ -212,10 +211,8 @@ private static bool TryEnsureOwner_WorkaroundCompilerQuirks(int afterCloseAngleI
currentOwner = parentElement.StartTag.CloseAngle;
}
}
else if (currentOwner.Parent is MarkupTagHelperElementSyntax
{
StartTag: not null
} parentTagHelperElement)
else if (currentOwner.Parent is MarkupTagHelperElementSyntax parentTagHelperElement &&
parentTagHelperElement.StartTag != null)
{
// Same reasoning as the above block here.

Expand All @@ -240,7 +237,8 @@ private static bool TryEnsureOwner_WorkaroundCompilerQuirks(int afterCloseAngleI
var closeAngleSourceChange = new SourceChange(closeAngleIndex, length: 0, newText: string.Empty);
currentOwner = syntaxTree.Root.LocateOwner(closeAngleSourceChange);
}
else if (currentOwner.Parent is MarkupEndTagSyntax or MarkupTagHelperEndTagSyntax)
else if (currentOwner.Parent is MarkupEndTagSyntax ||
currentOwner.Parent is MarkupTagHelperEndTagSyntax)
{
// Quirk: https://github.com/dotnet/aspnetcore/issues/33919#issuecomment-870233627
// When tags are nested within each other within a C# block like:
Expand All @@ -253,13 +251,18 @@ private static bool TryEnsureOwner_WorkaroundCompilerQuirks(int afterCloseAngleI
// The owner will be the </div>. Note this does not happen outside of C# blocks.

var closeAngleSourceChange = new SourceChange(afterCloseAngleIndex - 1, length: 0, newText: string.Empty);
currentOwner = syntaxTree.Root.LocateOwner(closeAngleSourceChange) switch
currentOwner = syntaxTree.Root.LocateOwner(closeAngleSourceChange);

// Get the real closing angle if we get the quote from an attribute syntax. See https://github.com/dotnet/razor-tooling/issues/5694
switch (currentOwner)
{
// Get the real closing angle if we get the quote from an attribute syntax. See https://github.com/dotnet/razor-tooling/issues/5694
MarkupTextLiteralSyntax { Parent.Parent: MarkupStartTagSyntax startTag } => startTag.CloseAngle,
MarkupTextLiteralSyntax { Parent.Parent: MarkupTagHelperStartTagSyntax startTagHelper } => startTagHelper.CloseAngle,
var owner => owner
};
case MarkupTextLiteralSyntax { Parent.Parent: MarkupStartTagSyntax startTag }:
currentOwner = startTag.CloseAngle;
break;
case MarkupTextLiteralSyntax { Parent.Parent: MarkupTagHelperStartTagSyntax startTagHelper }:
currentOwner = startTagHelper.CloseAngle;
break;
}
}
else if (currentOwner.Parent is MarkupStartTagSyntax startTag &&
startTag.OpenAngle.Position == afterCloseAngleIndex)
Expand Down Expand Up @@ -320,11 +323,11 @@ private static bool TryEnsureOwner_WorkaroundCompilerQuirks(int afterCloseAngleI
return true;
}

private static AutoClosingBehavior InferAutoClosingBehavior(string name, bool caseSensitive)
private static AutoClosingBehavior InferAutoClosingBehavior(string name, StringComparer? tagNameComparer = null)
{
var voidElements = caseSensitive ? s_voidElementsCaseSensitive : s_voidElements;
tagNameComparer ??= StringComparer.OrdinalIgnoreCase;

if (voidElements.Contains(name))
if (s_voidElements.Contains(name, tagNameComparer))
{
return AutoClosingBehavior.SelfClosing;
}
Expand Down Expand Up @@ -427,7 +430,7 @@ private static bool CouldAutoCloseParentOrSelf(string currentTagName, SyntaxNode
}

node = node.Parent;
} while (node is not null);
} while (node != null);

return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,37 @@

namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert;

internal sealed class CloseTextTagOnAutoInsertProvider : IOnAutoInsertProvider
internal class CloseTextTagOnAutoInsertProvider : RazorOnAutoInsertProvider
{
private readonly IOptionsMonitor<RazorLSPOptions> _optionsMonitor;
private readonly ILogger<IOnAutoInsertProvider> _logger;

public CloseTextTagOnAutoInsertProvider(IOptionsMonitor<RazorLSPOptions> optionsMonitor, ILoggerFactory loggerFactory)
public CloseTextTagOnAutoInsertProvider(
IOptionsMonitor<RazorLSPOptions> optionsMonitor,
ILoggerFactory loggerFactory)
: base(loggerFactory)
{
if (optionsMonitor is null)
{
throw new ArgumentNullException(nameof(optionsMonitor));
}

if (loggerFactory is null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}

_optionsMonitor = optionsMonitor;
_logger = loggerFactory.CreateLogger<IOnAutoInsertProvider>();
}

public string TriggerCharacter => ">";
public override string TriggerCharacter => ">";

public bool TryResolveInsertion(Position position, FormattingContext context, [NotNullWhen(true)] out TextEdit? edit, out InsertTextFormat format)
public override bool TryResolveInsertion(Position position, FormattingContext context, [NotNullWhen(true)] out TextEdit? edit, out InsertTextFormat format)
{
if (position is null)
{
throw new ArgumentNullException(nameof(position));
}

if (context is null)
{
throw new ArgumentNullException(nameof(context));
}

if (!_optionsMonitor.CurrentValue.AutoClosingTags)
{
// We currently only support auto-closing tags our onType formatter.
Expand All @@ -48,7 +54,7 @@ public bool TryResolveInsertion(Position position, FormattingContext context, [N
return false;
}

if (!IsAtTextTag(context, position, _logger))
if (!IsAtTextTag(context, position, Logger))
{
format = default;
edit = default;
Expand All @@ -75,14 +81,14 @@ private static bool IsAtTextTag(FormattingContext context, Position position, IL
return false;
}

var change = new SourceChange(absoluteIndex - 1, 0, string.Empty);
absoluteIndex -= 1;
var change = new SourceChange(absoluteIndex, 0, string.Empty);
var owner = syntaxTree.Root.LocateOwner(change);
// Make sure the end </text> tag doesn't already exist
if (owner?.Parent is MarkupStartTagSyntax
{
IsMarkupTransition: true,
Parent: MarkupElementSyntax { EndTag: null }
} startTag)
if (owner?.Parent != null &&
owner.Parent is MarkupStartTagSyntax startTag &&
startTag.IsMarkupTransition &&
startTag.Parent is MarkupElementSyntax element &&
element.EndTag is null) // Make sure the end </text> tag doesn't already exist
{
Debug.Assert(string.Equals(startTag.Name.Content, SyntaxConstants.TextTagName, StringComparison.Ordinal), "MarkupTransition that is not a <text> tag.");

Expand Down

This file was deleted.

Loading