diff --git a/CompletionEngine/Avalonia.Ide.CompletionEngine/Parsing/XmlParser.cs b/CompletionEngine/Avalonia.Ide.CompletionEngine/Parsing/XmlParser.cs index 4b33b498..002f5428 100644 --- a/CompletionEngine/Avalonia.Ide.CompletionEngine/Parsing/XmlParser.cs +++ b/CompletionEngine/Avalonia.Ide.CompletionEngine/Parsing/XmlParser.cs @@ -10,6 +10,7 @@ public class XmlParser public enum ParserState { None, + InsideDeclaration, InsideComment, InsideCdata, StartElement, @@ -76,6 +77,9 @@ public XmlParser(ReadOnlyMemory data, int start = 0) private const string CdataStart = "![CDATA["; private const string CdataEnd = "]]>"; + private const string DeclarationStart = "?"; + private const string DeclarationEnd = "?>"; + private bool CheckPrev(int caret, string checkFor) { var startAt = caret - checkFor.Length + 1; @@ -100,7 +104,6 @@ private bool ParseChar() var i = _parserPos++; var span = _data.Span; var c = span[i]; - char lastChar; if (c == '<' && State == ParserState.None) { State = ParserState.StartElement; @@ -110,6 +113,18 @@ private bool ParseChar() _containingTagStart.Push(i); } + else if (State == ParserState.StartElement && CheckPrev(i, DeclarationStart)) + { + State = ParserState.InsideDeclaration; + } + else if (State == ParserState.InsideDeclaration && CheckPrev(i, DeclarationEnd)) + { + State = ParserState.None; + if (_containingTagStart.Count > 0) + { + _containingTagStart.Pop(); + } + } else if (State == ParserState.StartElement && CheckPrev(i, CommentStart)) { State = ParserState.InsideComment; @@ -117,6 +132,10 @@ private bool ParseChar() else if (State == ParserState.InsideComment && CheckPrev(i, CommentEnd)) { State = ParserState.None; + if (_containingTagStart.Count > 0) + { + _containingTagStart.Pop(); + } } else if (State == ParserState.StartElement && CheckPrev(i, CdataStart)) { @@ -125,6 +144,10 @@ private bool ParseChar() else if (State == ParserState.InsideCdata && CheckPrev(i, CdataEnd)) { State = ParserState.None; + if (_containingTagStart.Count > 0) + { + _containingTagStart.Pop(); + } } else if (State == ParserState.StartElement && char.IsWhiteSpace(c)) { @@ -202,7 +225,11 @@ private bool ParseChar() public string? GetParentTagName(int level) { - if (NestingLevel - level - 1 < 0) + if (State == ParserState.None) + { + level--; + } + if (NestingLevel - level < 0) return null; var start = _containingTagStart.Skip(level).FirstOrDefault(); var m = Regex.Match(_data.Span.Slice(start).ToString(), @"^<[^\s/>]+"); diff --git a/tests/CompletionEngineTests/CompletionEngineTests.csproj b/tests/CompletionEngineTests/CompletionEngineTests.csproj index cff15f03..d2383b9f 100644 --- a/tests/CompletionEngineTests/CompletionEngineTests.csproj +++ b/tests/CompletionEngineTests/CompletionEngineTests.csproj @@ -8,6 +8,17 @@ ..\..\Key.snk + + + + + + + + + + + @@ -16,6 +27,12 @@ + + + + + + diff --git a/tests/CompletionEngineTests/Manipulator/XmlParserTests.cs b/tests/CompletionEngineTests/Manipulator/XmlParserTests.cs deleted file mode 100644 index e91503d7..00000000 --- a/tests/CompletionEngineTests/Manipulator/XmlParserTests.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using Avalonia.Ide.CompletionEngine; -using Xunit; - -namespace CompletionEngineTests.Manipulator -{ - /// - /// Tests for XmlParser behavior on which TextManipulator is dependent - /// - public class XmlParserTests - { - [Fact] - public void Should_BeInNoneState_When_OnClosingBrace() - { - var parser = XmlParser.Parse(""); - Assert.Equal(XmlParser.ParserState.None, parser.State); - } - - [Fact] - public void Should_NotBeInClosingTag_When_StartTag() - { - var p = XmlParser.Parse(" + + diff --git a/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_One_Level_WithComment.xml b/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_One_Level_WithComment.xml new file mode 100644 index 00000000..2ec28fb3 --- /dev/null +++ b/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_One_Level_WithComment.xml @@ -0,0 +1,14 @@ + + + + diff --git a/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_One_Level_With_CDATA.xml b/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_One_Level_With_CDATA.xml new file mode 100644 index 00000000..a227213c --- /dev/null +++ b/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_One_Level_With_CDATA.xml @@ -0,0 +1,17 @@ + + + + + diff --git a/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_One_Level_With_Comment.xml b/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_One_Level_With_Comment.xml new file mode 100644 index 00000000..2ec28fb3 --- /dev/null +++ b/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_One_Level_With_Comment.xml @@ -0,0 +1,14 @@ + + + + diff --git a/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_Two_Level.xml b/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_Two_Level.xml new file mode 100644 index 00000000..673573cc --- /dev/null +++ b/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_Two_Level.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_Two_Level_With_CDATA.xml b/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_Two_Level_With_CDATA.xml new file mode 100644 index 00000000..d2f88721 --- /dev/null +++ b/tests/CompletionEngineTests/Parsing/Fragemts/Should_GetParentTagName_At_Level_Two_Level_With_CDATA.xml @@ -0,0 +1,21 @@ + + + + +