From 7efaaae3e1c750cbc645ae15ffe7150f45f6d36e Mon Sep 17 00:00:00 2001 From: DismissedLight <1686188646@qq.com> Date: Sat, 3 Feb 2024 17:26:17 +0800 Subject: [PATCH] fix syntax tree parsing --- .../Control/Text/DescriptionTextBlock.cs | 21 +---- .../Text/Syntax/MiHoYo/MiHoYoLineSyntax.cs | 17 ---- .../Syntax/MiHoYo/MiHoYoPlainTextSyntax.cs | 5 ++ .../Text/Syntax/MiHoYo/MiHoYoSyntaxKind.cs | 1 - .../Text/Syntax/MiHoYo/MiHoYoSyntaxTree.cs | 85 ++++++++----------- .../Control/Text/Syntax/TextPosition.cs | 7 +- 6 files changed, 47 insertions(+), 89 deletions(-) delete mode 100644 src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoLineSyntax.cs diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Text/DescriptionTextBlock.cs b/src/Snap.Hutao/Snap.Hutao/Control/Text/DescriptionTextBlock.cs index 42a60d62..3ef1ab02 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Text/DescriptionTextBlock.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Text/DescriptionTextBlock.cs @@ -46,7 +46,6 @@ internal sealed partial class DescriptionTextBlock : ContentControl private static void OnDescriptionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TextBlock textBlock = (TextBlock)((DescriptionTextBlock)d).Content; - ReadOnlySpan description = SpecialNameHandler.Handle((string)e.NewValue); try { @@ -80,9 +79,6 @@ internal sealed partial class DescriptionTextBlock : ContentControl AppendNode(textBlock, inlines, child); } - break; - case MiHoYoSyntaxKind.Line: - AppendLine(textBlock, inlines, (MiHoYoLineSyntax)node); break; case MiHoYoSyntaxKind.PlainText: AppendPlainText(textBlock, inlines, (MiHoYoPlainTextSyntax)node); @@ -96,19 +92,6 @@ internal sealed partial class DescriptionTextBlock : ContentControl } } - private static void AppendLine(TextBlock textBlock, InlineCollection inlines, MiHoYoLineSyntax line) - { - foreach (MiHoYoSyntaxNode node in line.Children) - { - AppendNode(textBlock, inlines, node); - } - - if (line.HasTailingNewLine) - { - inlines.Add(new LineBreak()); - } - } - private static void AppendPlainText(TextBlock textBlock, InlineCollection inlines, MiHoYoPlainTextSyntax plainText) { // PlainText doesn't have children @@ -131,7 +114,7 @@ internal sealed partial class DescriptionTextBlock : ContentControl targetColor = Rgba32.FromHsl(hsl); } - if (colorText.Children.Count > 0) + if (colorText.Children.Count > 1) { Span span = new() { @@ -155,7 +138,7 @@ internal sealed partial class DescriptionTextBlock : ContentControl private static void AppendItalicText(TextBlock textBlock, InlineCollection inlines, MiHoYoItalicTextSyntax italicText) { - if (italicText.Children.Count > 0) + if (italicText.Children.Count > 1) { Span span = new() { diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoLineSyntax.cs b/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoLineSyntax.cs deleted file mode 100644 index 43711298..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoLineSyntax.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -namespace Snap.Hutao.Control.Text.Syntax.MiHoYo; - -internal sealed class MiHoYoLineSyntax : MiHoYoSyntaxNode -{ - public MiHoYoLineSyntax(bool hasTailingNewLine, string text, int start, int end) - : base(MiHoYoSyntaxKind.Line, text, start, end) - { - HasTailingNewLine = hasTailingNewLine; - } - - public bool HasTailingNewLine { get; } - - public TextPosition TextPosition { get => HasTailingNewLine ? new(Position.Start, Position.Length - 1) : Position; } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoPlainTextSyntax.cs b/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoPlainTextSyntax.cs index 7bf707d8..48ac7b49 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoPlainTextSyntax.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoPlainTextSyntax.cs @@ -9,4 +9,9 @@ internal sealed class MiHoYoPlainTextSyntax : MiHoYoSyntaxNode : base(MiHoYoSyntaxKind.PlainText, text, start, end) { } + + public MiHoYoPlainTextSyntax(string text, TextPosition position) + : base(MiHoYoSyntaxKind.PlainText, text, position) + { + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoSyntaxKind.cs b/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoSyntaxKind.cs index d844920c..48a5eea5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoSyntaxKind.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoSyntaxKind.cs @@ -7,7 +7,6 @@ internal enum MiHoYoSyntaxKind { None, Root, - Line, PlainText, ColorText, ItalicText, diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoSyntaxTree.cs b/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoSyntaxTree.cs index 79cb2296..b9fac712 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoSyntaxTree.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/MiHoYo/MiHoYoSyntaxTree.cs @@ -12,7 +12,7 @@ internal sealed class MiHoYoSyntaxTree public static MiHoYoSyntaxTree Parse(string text) { MiHoYoRootSyntax root = new(text, 0, text.Length); - ParseLines(text, root); + ParseComponents(text, root); MiHoYoSyntaxTree tree = new() { @@ -23,110 +23,93 @@ internal sealed class MiHoYoSyntaxTree return tree; } - private static void ParseLines(string text, MiHoYoRootSyntax syntax) - { - ReadOnlySpan textSpan = text.AsSpan(); - int previousProcessedIndexOfText = 0; - - while (true) - { - int newLineIndexAtSlicedText = textSpan[previousProcessedIndexOfText..].IndexOf('\n'); - - if (newLineIndexAtSlicedText < 0) - { - MiHoYoLineSyntax line = new(false, text, previousProcessedIndexOfText, textSpan.Length); - ParseComponents(text, line); - syntax.Children.Add(line); - break; - } - - MiHoYoLineSyntax lineWithBreaking = new(true, text, previousProcessedIndexOfText, previousProcessedIndexOfText + newLineIndexAtSlicedText + 1); - ParseComponents(text, lineWithBreaking); - syntax.Children.Add(lineWithBreaking); - - previousProcessedIndexOfText = lineWithBreaking.Position.End; - } - } - private static void ParseComponents(string text, MiHoYoSyntaxNode syntax) { TextPosition contentPosition = syntax switch { MiHoYoXmlElementSyntax xmlSyntax => xmlSyntax.ContentPosition, - MiHoYoLineSyntax lineSyntax => lineSyntax.TextPosition, _ => syntax.Position, }; ReadOnlySpan contentSpan = text.AsSpan().Slice(contentPosition.Start, contentPosition.Length); - int previousProcessedIndexOfContent = 0; + int endOfProcessedAtContent = 0; while (true) { - int fullXmlOpeningIndexOfContent = contentSpan[previousProcessedIndexOfContent..].IndexOf('<'); + if (endOfProcessedAtContent >= contentSpan.Length) + { + break; + } + + int indexOfXmlLeftOpeningAtUnprocessedContent = contentSpan[endOfProcessedAtContent..].IndexOf('<'); // End of content - if (fullXmlOpeningIndexOfContent < 0) + if (indexOfXmlLeftOpeningAtUnprocessedContent < 0) { - MiHoYoPlainTextSyntax plainText = new(text, contentPosition.Start + previousProcessedIndexOfContent, contentPosition.End); + TextPosition position = new(contentPosition.Start + endOfProcessedAtContent, contentPosition.End); + MiHoYoPlainTextSyntax plainText = new(text, position); syntax.Children.Add(plainText); break; } // We have plain text between xml elements - if (previousProcessedIndexOfContent < fullXmlOpeningIndexOfContent) + if (indexOfXmlLeftOpeningAtUnprocessedContent > 0) { - MiHoYoPlainTextSyntax plainText = new(text, contentPosition.Start + previousProcessedIndexOfContent, contentPosition.End); + TextPosition position = new(0, indexOfXmlLeftOpeningAtUnprocessedContent); + TextPosition positionAtContent = position.RightShift(endOfProcessedAtContent); + TextPosition positionAtText = positionAtContent.RightShift(contentPosition.Start); + MiHoYoPlainTextSyntax plainText = new(text, positionAtText); syntax.Children.Add(plainText); + endOfProcessedAtContent = positionAtContent.End; + continue; } // Peek the next character after '<' - switch (contentSpan[previousProcessedIndexOfContent + fullXmlOpeningIndexOfContent + 1]) + int indexOfXmlLeftOpeningAtContent = endOfProcessedAtContent + indexOfXmlLeftOpeningAtUnprocessedContent; + switch (contentSpan[indexOfXmlLeftOpeningAtContent + 1]) { case 'c': { - // - // - int colorTagClosingEndOfSlicedContent = IndexOfClosingEnd(contentSpan[fullXmlOpeningIndexOfContent..], out int colorTagLeftClosingEndOfSlicedContent); + int endOfXmlColorRightClosingAtUnprocessedContent = EndOfXmlClosing(contentSpan[indexOfXmlLeftOpeningAtContent..], out int endOfXmlColorLeftClosingAtUnprocessedContent); - MiHoYoColorKind colorKind = colorTagLeftClosingEndOfSlicedContent switch + MiHoYoColorKind colorKind = endOfXmlColorLeftClosingAtUnprocessedContent switch { 17 => MiHoYoColorKind.Rgba, 15 => MiHoYoColorKind.Rgb, _ => throw Must.NeverHappen(), }; - TextPosition positionOfColorElement = new(0, colorTagClosingEndOfSlicedContent); - TextPosition positionAtContent = positionOfColorElement.Add(fullXmlOpeningIndexOfContent); - TextPosition positionAtText = positionAtContent.Add(contentPosition.Start + previousProcessedIndexOfContent); + TextPosition position = new(0, endOfXmlColorRightClosingAtUnprocessedContent); + TextPosition positionAtContent = position.RightShift(endOfProcessedAtContent); + TextPosition positionAtText = positionAtContent.RightShift(contentPosition.Start); MiHoYoColorTextSyntax colorText = new(colorKind, text, positionAtText); ParseComponents(text, colorText); syntax.Children.Add(colorText); - previousProcessedIndexOfContent = positionAtContent.End; + endOfProcessedAtContent = positionAtContent.End; break; } case 'i': { - // sometext 14 - int italicTagClosingEndOfSlicedContent = IndexOfClosingEnd(contentSpan[fullXmlOpeningIndexOfContent..], out _); + int endOfXmlItalicRightClosingAtUnprocessedContent = EndOfXmlClosing(contentSpan[indexOfXmlLeftOpeningAtContent..], out _); - TextPosition positionOfItalicElement = new(0, italicTagClosingEndOfSlicedContent); - TextPosition positionAtContent = positionOfItalicElement.Add(fullXmlOpeningIndexOfContent); - TextPosition positionAtText = positionAtContent.Add(contentPosition.Start + previousProcessedIndexOfContent); + TextPosition position = new(0, endOfXmlItalicRightClosingAtUnprocessedContent); + TextPosition positionAtContent = position.RightShift(endOfProcessedAtContent); + TextPosition positionAtText = positionAtContent.RightShift(contentPosition.Start); MiHoYoItalicTextSyntax italicText = new(text, positionAtText); ParseComponents(text, italicText); syntax.Children.Add(italicText); - previousProcessedIndexOfContent = positionAtContent.End; + endOfProcessedAtContent = positionAtContent.End; break; } } } } - private static int IndexOfClosingEnd(in ReadOnlySpan span, out int leftClosingEnd) + private static int EndOfXmlClosing(in ReadOnlySpan span, out int endOfLeftClosing) { - leftClosingEnd = 0; + endOfLeftClosing = 0; int openingCount = 0; int closingCount = 0; @@ -151,7 +134,7 @@ internal sealed class MiHoYoSyntaxTree if (openingCount is 1 && closingCount is 0) { - leftClosingEnd = current; + endOfLeftClosing = current; } if (openingCount == closingCount) diff --git a/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/TextPosition.cs b/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/TextPosition.cs index 89bf97c9..6b8f0ece 100644 --- a/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/TextPosition.cs +++ b/src/Snap.Hutao/Snap.Hutao/Control/Text/Syntax/TextPosition.cs @@ -22,7 +22,12 @@ internal readonly struct TextPosition get => End - Start; } - public TextPosition Add(int offset) + public TextPosition LeftShift(int offset) + { + return new(Start - offset, End - offset); + } + + public TextPosition RightShift(int offset) { return new(Start + offset, End + offset); }