From 2ba454ceb2b0853b4cad8c91a4d93c11fb323960 Mon Sep 17 00:00:00 2001 From: Joseph Humfrey Date: Tue, 24 Apr 2018 12:12:37 +0100 Subject: [PATCH] Tidy up whitespace in choices by leaving it to runtime to clean --- compiler/InkParser/InkParser_Choices.cs | 25 ++----- compiler/ParsedHierarchy/Choice.cs | 5 -- ink-engine-runtime/Story.cs | 2 +- ink-engine-runtime/StoryState.cs | 30 +++++++- tests/Tests.cs | 91 ++++++++++++++++--------- 5 files changed, 91 insertions(+), 62 deletions(-) diff --git a/compiler/InkParser/InkParser_Choices.cs b/compiler/InkParser/InkParser_Choices.cs index 4473d4d5..8303d61b 100644 --- a/compiler/InkParser/InkParser_Choices.cs +++ b/compiler/InkParser/InkParser_Choices.cs @@ -61,14 +61,6 @@ protected Choice Choice() innerContent = new ContentList (innerTextAndLogic); } - // Trim - if( innerContent ) - TrimChoiceContent (ref innerContent); - else if( optionOnlyContent ) - TrimChoiceContent (ref optionOnlyContent); - else - TrimChoiceContent (ref startContent); - Whitespace (); // Finally, now we know we're at the end of the main choice body, parse @@ -95,8 +87,6 @@ protected Choice Choice() innerContent.AddContent(tags); } - innerContent.AddContent (new Text ("\n")); - // Normal diverts on the end of a choice - simply add to the normal content if (diverts != null) { foreach (var divObj in diverts) { @@ -112,7 +102,10 @@ protected Choice Choice() } } - + // Terminate main content with a newline since this is the end of the line + // Note that this will be redundant if the diverts above definitely take + // the flow away permanently. + innerContent.AddContent (new Text ("\n")); var choice = new Choice (startContent, optionOnlyContent, innerContent); choice.name = optionalName; @@ -125,16 +118,6 @@ protected Choice Choice() return choice; } - - void TrimChoiceContent(ref ContentList content) - { - if (content != null) { - content.TrimTrailingWhitespace (); - if (content.content.Count == 0) { - content = null; - } - } - } protected Expression ChoiceCondition() { diff --git a/compiler/ParsedHierarchy/Choice.cs b/compiler/ParsedHierarchy/Choice.cs index 4882936f..29db8d14 100644 --- a/compiler/ParsedHierarchy/Choice.cs +++ b/compiler/ParsedHierarchy/Choice.cs @@ -223,11 +223,6 @@ public override Runtime.Object GenerateRuntimeObject () _innerContentContainer.AddContentsOfContainer (innerChoiceOnlyContent); } - // Fully parsed choice will be a full line, so it needs to be terminated - if (startContent || innerContent) { - _innerContentContainer.AddContent(new Runtime.StringValue("\n")); - } - if (this.story.countAllVisits) { _innerContentContainer.visitsShouldBeCounted = true; _innerContentContainer.turnIndexShouldBeCounted = true; diff --git a/ink-engine-runtime/Story.cs b/ink-engine-runtime/Story.cs index bd5830e8..977b83f4 100644 --- a/ink-engine-runtime/Story.cs +++ b/ink-engine-runtime/Story.cs @@ -823,7 +823,7 @@ Choice ProcessChoice(ChoicePoint choicePoint) choice.threadAtGeneration = state.callStack.currentThread.Copy (); // Set final text for the choice - choice.text = startText + choiceOnlyText; + choice.text = (startText + choiceOnlyText).Trim(' ', '\t'); return choice; } diff --git a/ink-engine-runtime/StoryState.cs b/ink-engine-runtime/StoryState.cs index f5eaaba1..e0e23ace 100755 --- a/ink-engine-runtime/StoryState.cs +++ b/ink-engine-runtime/StoryState.cs @@ -162,7 +162,7 @@ internal string currentText } } - _currentText = sb.ToString (); + _currentText = CleanOutputWhitespace (sb.ToString ()); _outputStreamTextDirty = false; } @@ -172,6 +172,34 @@ internal string currentText } string _currentText; + string CleanOutputWhitespace (string str) + { + var sb = new StringBuilder (str.Length); + + int currentWhitespaceStart = -1; + + for (int i = 0; i < str.Length; i++) { + var c = str [i]; + + bool isInlineWhitespace = c == ' ' || c == '\t'; + + if (isInlineWhitespace && currentWhitespaceStart == -1) + currentWhitespaceStart = i; + + if (!isInlineWhitespace) { + if (c != '\n' && currentWhitespaceStart > 0) { + sb.Append (str.Substring (currentWhitespaceStart, i - currentWhitespaceStart)); + } + currentWhitespaceStart = -1; + } + + if (!isInlineWhitespace) + sb.Append (c); + } + + return sb.ToString (); + } + internal List currentTags { get diff --git a/tests/Tests.cs b/tests/Tests.cs index 6ee55167..bb81903f 100644 --- a/tests/Tests.cs +++ b/tests/Tests.cs @@ -172,21 +172,21 @@ public void TestBlanksInInlineSequences() Assert.AreEqual( @"1. a -2. +2. 3. b 4. b --- -1. +1. 2. a 3. a --- 1. a -2. -3. +2. +3. --- -1. -2. -3. +1. +2. +3. ".Replace("\r", ""), story.ContinueMaximally().Replace("\r", "")); } @@ -240,7 +240,7 @@ public void TestChoiceDivertsToDone() Assert.AreEqual(1, story.currentChoices.Count); story.ChooseChoiceIndex(0); - Assert.AreEqual("choice\n", story.Continue()); + Assert.AreEqual("choice", story.Continue()); Assert.IsFalse(story.hasError); } @@ -818,7 +818,7 @@ EXTERNAL times(i,str) Assert.AreEqual("15\n", story.Continue()); - Assert.AreEqual("knock knock knock \n", story.Continue()); + Assert.AreEqual("knock knock knock\n", story.Continue()); Assert.AreEqual("MESSAGE: hello world", message); } @@ -1034,7 +1034,7 @@ public void TestImplicitInlineGlueB () } "); - Assert.AreEqual ("A \nX\n", story.ContinueMaximally ()); + Assert.AreEqual ("A\nX\n", story.ContinueMaximally ()); } [Test ()] @@ -1370,8 +1370,7 @@ public void TestNonTextInChoiceInnerContent() story.Continue(); story.ChooseChoiceIndex(0); - Assert.AreEqual("option text. Conditional bit.\n", story.Continue()); - Assert.AreEqual("Next.\n", story.Continue()); + Assert.AreEqual("option text. Conditional bit. Next.\n", story.Continue()); } [Test()] @@ -1829,10 +1828,10 @@ public void TestStringsInChoices() story.ContinueMaximally(); Assert.AreEqual(1, story.currentChoices.Count); - Assert.AreEqual(@" test1 ""test2 test3""", story.currentChoices[0].text); + Assert.AreEqual(@"test1 ""test2 test3""", story.currentChoices[0].text); story.ChooseChoiceIndex(0); - Assert.AreEqual(" test1 test4\n", story.Continue()); + Assert.AreEqual("test1 test4\n", story.Continue()); } [Test()] @@ -2413,10 +2412,10 @@ public void TestTempUsageInOptions () story.Continue (); Assert.AreEqual (1, story.currentChoices.Count); - Assert.AreEqual (" 1", story.currentChoices[0].text); + Assert.AreEqual ("1", story.currentChoices[0].text); story.ChooseChoiceIndex (0); - Assert.AreEqual (" 1\nEnd of choice\nthis another\n", story.ContinueMaximally ()); + Assert.AreEqual ("1\nEnd of choice\nthis another\n", story.ContinueMaximally ()); Assert.AreEqual (0, story.currentChoices.Count); } @@ -3048,7 +3047,7 @@ public void TestTagOnChoice () var txt = story.Continue (); var tags = story.currentTags; - Assert.AreEqual (" Hello\n", txt); // argh need to fix space? + Assert.AreEqual ("Hello", txt); Assert.AreEqual (1, tags.Count); Assert.AreEqual ("hey", tags[0]); } @@ -3145,23 +3144,6 @@ In top external } - - [Test ()] - public void TestStartingLineWithEscapedWhitespace () - { - var storyStr = - @" -hello{1: - \ world -} - "; - - var story = CompileString (storyStr); - - Assert.AreEqual ("hello\n world\n", story.ContinueMaximally ()); - } - - [Test ()] public void TestNewlinesWithStringEval () { @@ -3343,6 +3325,47 @@ public void TestTopFlowTerminatorShouldntKillThreadChoices () } + [Test ()] + public void TestNewlineConsistency () + { + var storyStr = + @" +hello -> world +== world +world +-> END"; + + var story = CompileString (storyStr); + Assert.AreEqual ("hello world\n", story.ContinueMaximally ()); + + storyStr = + @" +* hello -> world +== world +world +-> END"; + story = CompileString (storyStr); + + story.Continue (); + story.ChooseChoiceIndex (0); + Assert.AreEqual ("hello world\n", story.ContinueMaximally ()); + + + storyStr = + @" +* hello + -> world +== world +world +-> END"; + story = CompileString (storyStr); + + story.Continue (); + story.ChooseChoiceIndex (0); + Assert.AreEqual ("hello\nworld\n", story.ContinueMaximally ()); + } + + // Helper compile function protected Story CompileString(string str, bool countAllVisits = false, bool testingErrors = false) {