Skip to content

Commit

Permalink
Merge pull request #344 from workgroupengineering/fixes/Issue_338
Browse files Browse the repository at this point in the history
fix(Manupilation): Adding nested Tag renames parent closing element #338
  • Loading branch information
maxkatz6 authored Jun 15, 2023
2 parents 0b7a126 + e490a30 commit 46f4e1f
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 9 deletions.
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;
}
}

0 comments on commit 46f4e1f

Please sign in to comment.