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

fix(Manupilation): Adding nested Tag renames parent closing element #338 #344

Merged
merged 1 commit into from
Jun 15, 2023
Merged
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 @@ -18,9 +18,10 @@ public enum ParserState
BeforeAttributeValue,
AttributeValue,
AfterAttributeValue,
Error,
}

public ParserState State { get; set; }
public ParserState State { get; private set; }

private readonly ReadOnlyMemory<char> _data;
private int _parserPos;
Expand Down Expand Up @@ -99,6 +100,7 @@ private bool ParseChar()
var i = _parserPos++;
var span = _data.Span;
var c = span[i];
char lastChar;
if (c == '<' && State == ParserState.None)
{
State = ParserState.StartElement;
Expand Down Expand Up @@ -168,6 +170,10 @@ private bool ParseChar()
_attributeNameStart = i;
_attributeNameEnd = null;
}
else if (State == ParserState.InsideElement && c == '<')
{
State = ParserState.Error;
}
else if (State == ParserState.StartAttribute && (c == '=' || char.IsWhiteSpace(c)))
{
State = ParserState.BeforeAttributeValue;
Expand All @@ -186,6 +192,11 @@ private bool ParseChar()
{
State = ParserState.InsideElement;
}
else if (State == ParserState.Error && CheckPrev(i - 1, "<"))
{
State = ParserState.StartElement;
_parserPos--;
}
return true;
}

Expand All @@ -198,7 +209,6 @@ private bool ParseChar()
if (m.Success)
return m.Value.Substring(1);
return null;

}

public string? FindParentAttributeValue(string attributeExpr, int startLevel = 0, int maxLevels = int.MaxValue)
Expand Down Expand Up @@ -277,7 +287,11 @@ public static XmlParser Parse(ReadOnlyMemory<char> data)

public static XmlParser Parse(ReadOnlyMemory<char> data, int start, int end)
{
var rv = new XmlParser(data, start);
var rv = new XmlParser(data, 0);
while(rv.ParserPos < start)
{
rv.ParseChar();
}
for (var i = start; i < end; i++)
{
if (!rv.ParseChar())
Expand All @@ -303,7 +317,8 @@ public bool SeekClosingTag()
// leave initial start element
}

while (NestingLevel != 0)
var currentLevel = NestingLevel;
while (NestingLevel >= currentLevel)
{
if (!ParseChar())
{
Expand All @@ -321,7 +336,7 @@ public bool SeekClosingTag()
// find start of next element
}

return true;
return NestingLevel < currentLevel;
}

public override string ToString()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using Xunit;

namespace CompletionEngineTests.Manipulator;

partial class ManipulatorBasicTests
{
const string nestingRenameSource = """
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ACTest.Views.UserControl1">
<UserControl$
<TextBlock Text="Ciao"/>
</UserControl>
""";

const string nestingRenameExpected = """
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ACTest.Views.UserControl1">
<UserControld
<TextBlock Text="Ciao"/>
</UserControl>
""";

const string scenario2Source = """
<UserControl$ xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ACTest.Views.UserControl1">
<UserControl
<TextBlock Text="Ciao"/>
</UserControl>
""";

const string scenario2Expected = """
<UserControld xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ACTest.Views.UserControl1">
<UserControl
<TextBlock Text="Ciao"/>
</UserControld>
""";

[Theory]
[Scenario("Adding nested Tag renames parent closing element GitHub #338 ", nestingRenameExpected, nestingRenameSource)]
[Scenario("Rename with invalid nested tag", scenario2Expected, scenario2Source)]
public void SynchronizeStartAndEndTag(Scenario scenario)
{
AssertInsertion((string)scenario.Agrument, "d", (string)scenario.Expected);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace CompletionEngineTests.Manipulator
{

public class ManipulatorBasicTests : ManipulatorTestBase
public partial class ManipulatorBasicTests : ManipulatorTestBase
{
[Fact]
public void DoNotInsertToUnclosedTag()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Generic;
using Avalonia.Ide.CompletionEngine;
using Xunit;

Expand Down
45 changes: 45 additions & 0 deletions tests/CompletionEngineTests/Scenario.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Collections.Generic;
using System.Reflection;
using Xunit.Sdk;

namespace CompletionEngineTests;

/// <summary>
/// Test Scenario
/// </summary>
/// <param name="Description"></param>
/// <param name="Expected"></param>
/// <param name="Agrument"></param>
public record class Scenario(string Description, object Expected, object Agrument)
{
public override string ToString()
{
return Description;
}
}

/// <summary>
/// Provides a data source for a data theory, with the data coming from inline values.
/// </summary>
public sealed class ScenarioAttribute : DataAttribute
{
readonly object[] data;

/// <summary>
/// Initializes a new instance of the <see cref="ScenarioAttribute"/> class.
/// </summary>
/// <param name="description">The description of test scenario</param>
/// <param name="expected">The expected value</param>
/// <param name="agrument">The argument of pass to test method.</param>
public ScenarioAttribute(string description, object expected, object agrument)
{
Scenario scenario = new(description, expected, agrument);
data = new object[] { scenario };
}

/// <inheritdoc/>
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
{
yield return data;
}
}