From f270cb3bde656cd4aa32f66bb0e00c0fc7fcede4 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Tue, 5 Dec 2023 19:59:59 +0000 Subject: [PATCH] Fix handling of empty indented MiniYAML comments. An empty MiniYaml comment that was indented was previously not recognized, and instead parsed as a key named '#'. Now, indented comments are recognized as comments, which matches the behaviour for unindented lines. --- OpenRA.Game/MiniYaml.cs | 8 ++--- OpenRA.Test/OpenRA.Game/MiniYamlTest.cs | 45 ++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/OpenRA.Game/MiniYaml.cs b/OpenRA.Game/MiniYaml.cs index 3d160b3994..833b5d2731 100644 --- a/OpenRA.Game/MiniYaml.cs +++ b/OpenRA.Game/MiniYaml.cs @@ -258,9 +258,6 @@ namespace OpenRA } } - if (parsedLines.Count > 0 && parsedLines[^1].Level < level - 1) - throw new YamlException($"Bad indent in miniyaml at {location}"); - // Extract key, value, comment from line as `: #` // The # character is allowed in the value if escaped (\#). // Leading and trailing whitespace is always trimmed from keys. @@ -282,7 +279,7 @@ namespace OpenRA if (commentStart < 0 && line[i] == '#' && (i == 0 || line[i - 1] != '\\')) { commentStart = i + 1; - if (commentStart <= keyLength) + if (i <= keyStart + keyLength) keyLength = i - keyStart; else valueLength = i - valueStart; @@ -320,6 +317,9 @@ namespace OpenRA if (!key.IsEmpty || !discardCommentsAndWhitespace) { + if (parsedLines.Count > 0 && parsedLines[^1].Level < level - 1) + throw new YamlException($"Bad indent in miniyaml at {location}"); + while (parsedLines.Count > 0 && parsedLines[^1].Level > level) BuildCompletedSubNode(level); diff --git a/OpenRA.Test/OpenRA.Game/MiniYamlTest.cs b/OpenRA.Test/OpenRA.Game/MiniYamlTest.cs index 90a4d6721a..93fd45dd9b 100644 --- a/OpenRA.Test/OpenRA.Game/MiniYamlTest.cs +++ b/OpenRA.Test/OpenRA.Game/MiniYamlTest.cs @@ -613,14 +613,41 @@ TestB: # Parent: # comment without value # Indented comment node + # + # Double Indented comment node + # + # Triple Indented comment node + # First: value containing a \# character Second: value # node with inline comment Third: value # Fourth: # + Fifth# embedded comment: + Sixth# embedded comment: still a comment + Seventh# embedded comment: still a comment # more comment +".Replace("\r\n", "\n"); + + var canonicalYaml = @" +# Top level comment node +# +Parent: # comment without value + # Indented comment node + # + # Double Indented comment node + # + # Triple Indented comment node + # + First: value containing a \# character + Second: value # node with inline comment + Third: value # + Fourth: # + Fifth: # embedded comment: + Sixth: # embedded comment: still a comment + Seventh: # embedded comment: still a comment # more comment ".Replace("\r\n", "\n"); var result = MiniYaml.FromString(yaml, discardCommentsAndWhitespace: false).WriteToString(); - Assert.AreEqual(yaml, result); + Assert.AreEqual(canonicalYaml, result); } [TestCase(TestName = "Comments should be removed when discardCommentsAndWhitespace is false")] @@ -628,15 +655,31 @@ Parent: # comment without value { const string Yaml = @" # Top level comment node +# Parent: # comment without value # Indented comment node + # + # Double Indented comment node + # + # Triple Indented comment node + # First: value containing a \# character Second: value # node with inline comment + Third: value # + Fourth: # + Fifth# embedded comment: + Sixth# embedded comment: still a comment + Seventh# embedded comment: still a comment # more comment "; var strippedYaml = @"Parent: First: value containing a \# character Second: value + Third: value + Fourth: + Fifth: + Sixth: + Seventh: ".Replace("\r\n", "\n"); var result = MiniYaml.FromString(Yaml).WriteToString();