From 4def27c49dfc0cc39326931723134fa68cd4c501 Mon Sep 17 00:00:00 2001 From: Ben Wallis Date: Sat, 20 May 2017 18:14:28 +0100 Subject: [PATCH] FIL-4 Refactored script parsing to retain isolated comments as a new ItemFilterBlockComment type - UI still needs reworking with new templates and such. --- Filtration.Common/Utilities/LineReader.cs | 8 ++ .../Services/TestItemFilterProcessor.cs | 4 +- .../Services/ItemFilterProcessor.cs | 1 + .../TestItemFilterBlock.cs | 17 ---- Filtration.ObjectModel/ItemFilterBlock.cs | 41 +++++--- Filtration.ObjectModel/ItemFilterScript.cs | 10 +- .../Services/IItemFilterBlockTranslator.cs | 1 + .../Filtration.Parser.Tests.csproj | 3 + .../Properties/Resources.Designer.cs | 31 ++++++ .../Properties/Resources.resx | 9 +- .../Resources/testscript2.txt | 31 ++++++ .../Services/TestItemFilterBlockTranslator.cs | 44 +++------ .../TestItemFilterScriptTranslator.cs | 46 +++++++-- .../Services/ItemFilterBlockTranslator.cs | 33 ++++--- .../Services/ItemFilterScriptTranslator.cs | 95 +++++++++++++++---- .../Services/ThemeService.cs | 2 +- .../ViewModels/ItemFilterBlockViewModel.cs | 1 - .../ViewModels/ItemFilterScriptViewModel.cs | 4 +- 18 files changed, 273 insertions(+), 108 deletions(-) create mode 100644 Filtration.Parser.Tests/Resources/testscript2.txt diff --git a/Filtration.Common/Utilities/LineReader.cs b/Filtration.Common/Utilities/LineReader.cs index 94dea54..1811195 100644 --- a/Filtration.Common/Utilities/LineReader.cs +++ b/Filtration.Common/Utilities/LineReader.cs @@ -2,6 +2,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Text; @@ -21,6 +22,7 @@ namespace Filtration.Common.Utilities /// the stream into text. /// /// Data source + [DebuggerStepThrough] public LineReader(Func streamSource) : this(streamSource, Encoding.UTF8) { @@ -33,6 +35,7 @@ namespace Filtration.Common.Utilities /// Data source /// Encoding to use to decode the stream /// into text + [DebuggerStepThrough] public LineReader(Func streamSource, Encoding encoding) : this(() => new StreamReader(streamSource(), encoding)) { @@ -44,6 +47,7 @@ namespace Filtration.Common.Utilities /// UTF8 is used to decode the file into text. /// /// File to read from + [DebuggerStepThrough] public LineReader(string filename) : this(filename, Encoding.UTF8) { @@ -56,6 +60,7 @@ namespace Filtration.Common.Utilities /// File to read from /// Encoding to use to decode the file /// into text + [DebuggerStepThrough] public LineReader(string filename, Encoding encoding) : this(() => new StreamReader(filename, encoding)) { @@ -66,6 +71,7 @@ namespace Filtration.Common.Utilities /// is only called when the enumerator is fetched /// /// Data source + [DebuggerStepThrough] public LineReader(Func dataSource) { _dataSource = dataSource; @@ -74,6 +80,7 @@ namespace Filtration.Common.Utilities /// /// Enumerates the data source line by line. /// + [DebuggerStepThrough] public IEnumerator GetEnumerator() { using (TextReader reader = _dataSource()) @@ -89,6 +96,7 @@ namespace Filtration.Common.Utilities /// /// Enumerates the data source line by line. /// + [DebuggerStepThrough] IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); diff --git a/Filtration.ItemFilterPreview.Tests/Services/TestItemFilterProcessor.cs b/Filtration.ItemFilterPreview.Tests/Services/TestItemFilterProcessor.cs index 28d1e66..17274f8 100644 --- a/Filtration.ItemFilterPreview.Tests/Services/TestItemFilterProcessor.cs +++ b/Filtration.ItemFilterPreview.Tests/Services/TestItemFilterProcessor.cs @@ -29,7 +29,7 @@ namespace Filtration.ItemFilterPreview.Tests.Services //Arrange var testInputItem = Mock.Of(); var testInputBlock = Mock.Of(); - var testInputScript = Mock.Of(s => s.ItemFilterBlocks == new ObservableCollection {testInputBlock}); + var testInputScript = Mock.Of(s => s.ItemFilterBlocks == new ObservableCollection {testInputBlock}); _testUtility.MockBlockItemMatcher .Setup(b => b.ItemBlockMatch(testInputBlock, testInputItem)) @@ -50,7 +50,7 @@ namespace Filtration.ItemFilterPreview.Tests.Services //Arrange var testInputItem = Mock.Of(); var testInputBlock = Mock.Of(); - var testInputScript = Mock.Of(s => s.ItemFilterBlocks == new ObservableCollection { testInputBlock }); + var testInputScript = Mock.Of(s => s.ItemFilterBlocks == new ObservableCollection { testInputBlock }); _testUtility.MockBlockItemMatcher .Setup(b => b.ItemBlockMatch(testInputBlock, testInputItem)) diff --git a/Filtration.ItemFilterPreview/Services/ItemFilterProcessor.cs b/Filtration.ItemFilterPreview/Services/ItemFilterProcessor.cs index a680185..d385174 100644 --- a/Filtration.ItemFilterPreview/Services/ItemFilterProcessor.cs +++ b/Filtration.ItemFilterPreview/Services/ItemFilterProcessor.cs @@ -31,6 +31,7 @@ namespace Filtration.ItemFilterPreview.Services sw.Restart(); var matchedBlock = itemFilterScript.ItemFilterBlocks + .OfType() .Where(b => !(b is ItemFilterSection)) .FirstOrDefault(block => _blockItemMatcher.ItemBlockMatch(block, item)); diff --git a/Filtration.ObjectModel.Tests/TestItemFilterBlock.cs b/Filtration.ObjectModel.Tests/TestItemFilterBlock.cs index 8afd358..045db54 100644 --- a/Filtration.ObjectModel.Tests/TestItemFilterBlock.cs +++ b/Filtration.ObjectModel.Tests/TestItemFilterBlock.cs @@ -6,23 +6,6 @@ namespace Filtration.ObjectModel.Tests [TestFixture] public class TestItemFilterBlock { - [Test] - public void ItemFilterBlock_BlockCount_ReturnsCorrectNumber() - { - // Arrange - var block = new ItemFilterBlock(); - block.BlockItems.Add(new ItemLevelBlockItem()); - block.BlockItems.Add(new ItemLevelBlockItem()); - block.BlockItems.Add(new ItemLevelBlockItem()); - block.BlockItems.Add(new ItemLevelBlockItem()); - - // Act - var count = block.BlockCount(typeof (ItemLevelBlockItem)); - - // Assert - Assert.AreEqual(4, count); - } - [Test] public void ItemFilterBlock_AddBlockItemAllowed_LessThanMaximum_ReturnsTrue() { diff --git a/Filtration.ObjectModel/ItemFilterBlock.cs b/Filtration.ObjectModel/ItemFilterBlock.cs index f5bcff1..44a1094 100644 --- a/Filtration.ObjectModel/ItemFilterBlock.cs +++ b/Filtration.ObjectModel/ItemFilterBlock.cs @@ -9,7 +9,7 @@ using Filtration.ObjectModel.Extensions; namespace Filtration.ObjectModel { - public interface IItemFilterBlock + public interface IItemFilterBlock : IItemFilterBlockBase { bool Enabled { get; set; } string Description { get; set; } @@ -21,13 +21,32 @@ namespace Filtration.ObjectModel Color DisplayTextColor { get; } Color DisplayBorderColor { get; } double DisplayFontSize { get; } - int BlockCount(Type type); - bool AddBlockItemAllowed(Type type); bool HasBlockItemOfType(); bool HasBlockGroupInParentHierarchy(ItemFilterBlockGroup targetBlockGroup, ItemFilterBlockGroup startingBlockGroup); } - public class ItemFilterBlock : IItemFilterBlock + public interface IItemFilterBlockBase + { + } + + public class ItemFilterBlockBase : IItemFilterBlockBase + { + + } + + public interface IItemFilterCommentBlock : IItemFilterBlockBase + { + string Comment { get; set; } + bool IsSection { get; set; } + } + + public class ItemFilterCommentBlock : ItemFilterBlockBase, IItemFilterCommentBlock + { + public string Comment { get; set; } + public bool IsSection { get; set; } + } + + public class ItemFilterBlock : ItemFilterBlockBase, IItemFilterBlock { private ItemFilterBlockGroup _blockGroup; @@ -43,7 +62,7 @@ namespace Filtration.ObjectModel public ItemFilterBlockGroup BlockGroup { - get { return _blockGroup; } + get => _blockGroup; set { var oldBlockGroup = _blockGroup; @@ -85,15 +104,15 @@ namespace Filtration.ObjectModel public ObservableCollection BlockItems { get; } - public int BlockCount(Type type) - { - return BlockItems?.Count(b => b.GetType() == type) ?? 0; - } - public bool AddBlockItemAllowed(Type type) { + int BlockCount() + { + return BlockItems?.Count(b => b.GetType() == type) ?? 0; + } + var blockItem = (IItemFilterBlockItem)Activator.CreateInstance(type); - return BlockCount(type) < blockItem.MaximumAllowed; + return BlockCount() < blockItem.MaximumAllowed; } public bool HasBlockItemOfType() diff --git a/Filtration.ObjectModel/ItemFilterScript.cs b/Filtration.ObjectModel/ItemFilterScript.cs index 6a730c2..b6f79dd 100644 --- a/Filtration.ObjectModel/ItemFilterScript.cs +++ b/Filtration.ObjectModel/ItemFilterScript.cs @@ -9,7 +9,7 @@ namespace Filtration.ObjectModel { public interface IItemFilterScript { - ObservableCollection ItemFilterBlocks { get; } + ObservableCollection ItemFilterBlocks { get; } ObservableCollection ItemFilterBlockGroups { get; } ThemeComponentCollection ThemeComponents { get; set; } string FilePath { get; set; } @@ -25,7 +25,7 @@ namespace Filtration.ObjectModel { public ItemFilterScript() { - ItemFilterBlocks = new ObservableCollection(); + ItemFilterBlocks = new ObservableCollection(); ItemFilterBlockGroups = new ObservableCollection { new ItemFilterBlockGroup("Root", null) @@ -34,7 +34,7 @@ namespace Filtration.ObjectModel ItemFilterScriptSettings = new ItemFilterScriptSettings(ThemeComponents); } - public ObservableCollection ItemFilterBlocks { get; } + public ObservableCollection ItemFilterBlocks { get; } public ObservableCollection ItemFilterBlockGroups { get; } public ThemeComponentCollection ThemeComponents { get; set; } @@ -59,9 +59,7 @@ namespace Filtration.ObjectModel public void ReplaceColors(ReplaceColorsParameterSet replaceColorsParameterSet) { - foreach ( - var block in - ItemFilterBlocks.Where(b => BlockIsColorReplacementCandidate(replaceColorsParameterSet, b))) + foreach (var block in ItemFilterBlocks.OfType().Where(b => BlockIsColorReplacementCandidate(replaceColorsParameterSet, b))) { if (replaceColorsParameterSet.ReplaceTextColor) { diff --git a/Filtration.Parser.Interface/Services/IItemFilterBlockTranslator.cs b/Filtration.Parser.Interface/Services/IItemFilterBlockTranslator.cs index 54be87e..0d9a1d6 100644 --- a/Filtration.Parser.Interface/Services/IItemFilterBlockTranslator.cs +++ b/Filtration.Parser.Interface/Services/IItemFilterBlockTranslator.cs @@ -8,5 +8,6 @@ namespace Filtration.Parser.Interface.Services IItemFilterBlock TranslateStringToItemFilterBlock(string inputString, IItemFilterScriptSettings itemFilterScriptSettings); string TranslateItemFilterBlockToString(IItemFilterBlock block); void ReplaceAudioVisualBlockItemsFromString(ObservableCollection blockItems, string inputString); + IItemFilterCommentBlock TranslateStringToItemFilterCommentBlock(string inputString); } } \ No newline at end of file diff --git a/Filtration.Parser.Tests/Filtration.Parser.Tests.csproj b/Filtration.Parser.Tests/Filtration.Parser.Tests.csproj index 216294f..26effd4 100644 --- a/Filtration.Parser.Tests/Filtration.Parser.Tests.csproj +++ b/Filtration.Parser.Tests/Filtration.Parser.Tests.csproj @@ -109,6 +109,9 @@ + + + diff --git a/Filtration.Parser.Tests/Properties/Resources.Designer.cs b/Filtration.Parser.Tests/Properties/Resources.Designer.cs index b4a2cb0..4cd12a1 100644 --- a/Filtration.Parser.Tests/Properties/Resources.Designer.cs +++ b/Filtration.Parser.Tests/Properties/Resources.Designer.cs @@ -91,6 +91,37 @@ namespace Filtration.Parser.Tests.Properties { } } + /// + /// Looks up a localized string similar to #Script description + ///#Script description + ///#Script description + ///#Script description + /// + ///#Comment + ///#SomeComment + /// + ///#Blockdescription + ///Show #Flasks - Endgame - Life/Mana - Divine/Eternal - Q10+ - Normal + /// Class "Life Flasks" "Mana Flasks" + /// Rarity Normal + /// DropLevel >= 60 + /// Quality >= 10 + /// SetFontSize 28 + /// SetTextColor 240 240 240 #Normal Item Highlight + /// + ///#commentymccommentface + /// + ///Show #Flasks - Endgame - Life/Mana - Divine/Eternal - Q10+ - Normal + /// Class "Life Flasks" "Mana Flasks" + /// Rarity Normal + /// DropL [rest of string was truncated]";. + /// + public static string testscript2 { + get { + return ResourceManager.GetString("testscript2", resourceCulture); + } + } + /// /// Looks up a localized string similar to ###BETA VERSION 1.0.0.1-8 ///#Please test and let me know via pm on reddit /u/brute_force or @Thiole in game if i am online diff --git a/Filtration.Parser.Tests/Properties/Resources.resx b/Filtration.Parser.Tests/Properties/Resources.resx index 9797aeb..1e13abb 100644 --- a/Filtration.Parser.Tests/Properties/Resources.resx +++ b/Filtration.Parser.Tests/Properties/Resources.resx @@ -118,10 +118,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\Resources\ThioleItemFilter.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 - ..\Resources\testscript.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + ..\Resources\testscript2.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + + ..\Resources\ThioleItemFilter.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + \ No newline at end of file diff --git a/Filtration.Parser.Tests/Resources/testscript2.txt b/Filtration.Parser.Tests/Resources/testscript2.txt new file mode 100644 index 0000000..f9b3a9c --- /dev/null +++ b/Filtration.Parser.Tests/Resources/testscript2.txt @@ -0,0 +1,31 @@ +#Script description +#Script description +#Script description +#Script description + +#Blockdescription +Show #Flasks - Endgame - Life/Mana - Divine/Eternal - Q10+ - Normal + Class "Life Flasks" "Mana Flasks" + Rarity Normal + SetFontSize 28 + + + +# commentymccommentface + +Show + Class "Life Flasks" "Mana Flasks" + Rarity Normal + DropLevel >= 60 + +#commment +#morecomment +#blah + +#anothercomment + +#notpartofblockdescription +#blockdescription2 +Show #TestBlock + Class "Life Flasks" "Mana Flasks" + Rarity Normal \ No newline at end of file diff --git a/Filtration.Parser.Tests/Services/TestItemFilterBlockTranslator.cs b/Filtration.Parser.Tests/Services/TestItemFilterBlockTranslator.cs index ec90142..f2f3acd 100644 --- a/Filtration.Parser.Tests/Services/TestItemFilterBlockTranslator.cs +++ b/Filtration.Parser.Tests/Services/TestItemFilterBlockTranslator.cs @@ -26,6 +26,19 @@ namespace Filtration.Parser.Tests.Services _testUtility = new ItemFilterBlockTranslatorTestUtility(); } + [Test] + public void TranslateStringToItemFilterBlockComment_ReturnsItemFilterBlockCommentWithSpacesNotRemoved() + { + //Arrange + var testInputString = "# This is a comment\r\n# Line 2 \r\n # Test"; + + //Act + var result = _testUtility.Translator.TranslateStringToItemFilterCommentBlock(testInputString); + + //Assert + Assert.AreEqual(" This is a comment\r\n Line 2 \r\n Test", result.Comment); + } + [Test] public void TranslateStringToItemFilterBlock_BlockGroupsEnabled_ActionBlockItemCommentIsNull() { @@ -703,21 +716,6 @@ namespace Filtration.Parser.Tests.Services Assert.AreEqual(2, blockItem.Value); Assert.AreEqual(95, blockItem.SecondValue); } - - [Test] - public void TranslateStringToItemFilterBlock_SectionComment_ReturnsItemFilterSectionObjectWithCorrectDescription() - { - // Arrange - const string testInputSectionDescription = "Wonderful items that you definitely won't want to miss!"; - var inputString = "# Section: " + testInputSectionDescription; - - // Act - var result = _testUtility.Translator.TranslateStringToItemFilterBlock(inputString, Mock.Of()); - - // Assert - Assert.IsInstanceOf(result); - Assert.AreEqual(testInputSectionDescription, result.Description); - } [Test] public void TranslateStringToItemFilterBlock_Everything_ReturnsCorrectObject() @@ -1571,22 +1569,6 @@ namespace Filtration.Parser.Tests.Services Assert.AreEqual(expectedResult, result); } - [Test] - public void TranslateItemFilterBlockToString_Section_ReturnsCorrectString() - { - // Arrange - const string testInputSectionText = "Ermagerd it's a section!"; - var expectedResult = "# Section: " + testInputSectionText; - - _testUtility.TestBlock = new ItemFilterSection { Description = testInputSectionText }; - - // Act - var result = _testUtility.Translator.TranslateItemFilterBlockToString(_testUtility.TestBlock); - - // Assert - Assert.AreEqual(expectedResult, result); - } - [Test] public void TranslateItemFilterBlockToString_DisabledBlock_ReturnsCorrectString() { diff --git a/Filtration.Parser.Tests/Services/TestItemFilterScriptTranslator.cs b/Filtration.Parser.Tests/Services/TestItemFilterScriptTranslator.cs index fab162b..799ec2f 100644 --- a/Filtration.Parser.Tests/Services/TestItemFilterScriptTranslator.cs +++ b/Filtration.Parser.Tests/Services/TestItemFilterScriptTranslator.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using Filtration.ObjectModel; using Filtration.ObjectModel.BlockItemTypes; @@ -9,6 +10,7 @@ using Filtration.Parser.Interface.Services; using Filtration.Parser.Services; using Filtration.Parser.Tests.Properties; using Filtration.Properties; +using FluentAssertions; using Moq; using NUnit.Framework; @@ -75,6 +77,36 @@ namespace Filtration.Parser.Tests.Services // Not crashing out when loading a huge script means this integration test has passed! } + [Test] + public void TranslateStringToItemFilterScript_Blah() + { + // Arrange + var testInput = Resources.testscript2; + + var blockTranslator = new ItemFilterBlockTranslator(_testUtility.MockBlockGroupHierarchyBuilder.Object); + var translator = new ItemFilterScriptTranslator(blockTranslator, _testUtility.MockBlockGroupHierarchyBuilder.Object); + + // Act + var result = translator.TranslateStringToItemFilterScript(testInput); + + // Assert + var expectedResult = Mock.Of(s => s.ItemFilterBlocks == new ObservableCollection + { + Mock.Of(c => c.Description == "Blockdescription"), + Mock.Of(c => c.Comment == " commentymccommentface"), + Mock.Of(), + Mock.Of(c => c.Comment == "commment\r\nmorecomment\r\nblah"), + Mock.Of(c => c.Comment == "anothercomment"), + Mock.Of(c => c.Comment == "notpartofblockdescription "), + Mock.Of(c => c.Description == "blockdescription2") + } && s.ItemFilterBlockGroups == new ObservableCollection { new ItemFilterBlockGroup("Root", null, false) } + && s.ThemeComponents == new ThemeComponentCollection() + && s.ItemFilterScriptSettings == new ItemFilterScriptSettings(new ThemeComponentCollection()) + && s.Description == "Script description\r\nScript description\r\nScript description\r\nScript description"); + + result.ShouldBeEquivalentTo(expectedResult); + } + [Test] public void TranslateItemFilterScriptToString_OneBlock_CallsTranslator() { @@ -221,7 +253,7 @@ namespace Filtration.Parser.Tests.Services // Assert Assert.AreEqual(2, result.ItemFilterBlocks.Count); - var block = result.ItemFilterBlocks.First(l => l.GetType() != typeof(ItemFilterSection)); + var block = result.ItemFilterBlocks.OfType().First(l => l.GetType() != typeof(ItemFilterSection)); Assert.AreEqual(4, block.BlockItems.Count); var baseTypeItem = block.BlockItems.OfType().First(); Assert.AreEqual(2, baseTypeItem.Items.Count); @@ -244,7 +276,7 @@ namespace Filtration.Parser.Tests.Services // Assert Assert.AreEqual("Script edited with Filtration - https://github.com/ben-wallis/Filtration", result.Description); - var firstBlock = result.ItemFilterBlocks.First(); + var firstBlock = result.ItemFilterBlocks.OfType().First(); Assert.IsNull(firstBlock.Description); } @@ -311,9 +343,9 @@ namespace Filtration.Parser.Tests.Services // Assert Assert.AreEqual(3, result.ItemFilterBlocks.Count); - var firstBlock = result.ItemFilterBlocks.First(); - var secondBlock = result.ItemFilterBlocks.Skip(1).First(); - var thirdBlock = result.ItemFilterBlocks.Skip(2).First(); + var firstBlock = result.ItemFilterBlocks.OfType().First(); + var secondBlock = result.ItemFilterBlocks.OfType().Skip(1).First(); + var thirdBlock = result.ItemFilterBlocks.OfType().Skip(2).First(); Assert.AreEqual(3, firstBlock.BlockItems.Count); Assert.AreEqual(5, secondBlock.BlockItems.Count); @@ -344,7 +376,7 @@ namespace Filtration.Parser.Tests.Services // Assert Assert.AreEqual(2, result.ItemFilterBlocks.Count); - var secondBlock = result.ItemFilterBlocks.Skip(1).First(); + var secondBlock = result.ItemFilterBlocks.OfType().Skip(1).First(); Assert.AreEqual("This is a disabled block", secondBlock.Description); } @@ -379,7 +411,7 @@ namespace Filtration.Parser.Tests.Services // Assert Assert.AreEqual(2, result.ItemFilterBlocks.Count); - var secondBlock = result.ItemFilterBlocks.Skip(1).First(); + var secondBlock = result.ItemFilterBlocks.OfType().Skip(1).First(); Assert.AreEqual("This is a disabled block", secondBlock.Description); Assert.AreEqual("My Block Group", secondBlock.BlockGroup.GroupName); } diff --git a/Filtration.Parser/Services/ItemFilterBlockTranslator.cs b/Filtration.Parser/Services/ItemFilterBlockTranslator.cs index 27a78f0..67d6181 100644 --- a/Filtration.Parser/Services/ItemFilterBlockTranslator.cs +++ b/Filtration.Parser/Services/ItemFilterBlockTranslator.cs @@ -29,6 +29,22 @@ namespace Filtration.Parser.Services _blockGroupHierarchyBuilder = blockGroupHierarchyBuilder; } + // Converts a string into an ItemFilterCommentBlock maintaining newlines and spaces but removing # characters + public IItemFilterCommentBlock TranslateStringToItemFilterCommentBlock(string inputString) + { + var itemFilterCommentBlock = new ItemFilterCommentBlock(); + + foreach (var line in new LineReader(() => new StringReader(inputString))) + { + var trimmedLine = line.TrimStart(' ').TrimStart('#'); + itemFilterCommentBlock.Comment += trimmedLine + Environment.NewLine; + } + + itemFilterCommentBlock.Comment = itemFilterCommentBlock.Comment.TrimEnd('\r', '\n'); + + return itemFilterCommentBlock; + } + // This method converts a string into a ItemFilterBlock. This is used for pasting ItemFilterBlocks // and reading ItemFilterScripts from a file. public IItemFilterBlock TranslateStringToItemFilterBlock(string inputString, IItemFilterScriptSettings itemFilterScriptSettings) @@ -39,16 +55,6 @@ namespace Filtration.Parser.Services foreach (var line in new LineReader(() => new StringReader(inputString))) { - - if (line.StartsWith(@"# Section:")) - { - var section = new ItemFilterSection - { - Description = line.Substring(line.IndexOf(":", StringComparison.Ordinal) + 1).Trim() - }; - return section; - } - if (line.StartsWith(@"#") && !showHideFound) { block.Description = line.TrimStart('#').TrimStart(' '); @@ -205,6 +211,7 @@ namespace Filtration.Parser.Services switch (matches.Count) { case 1: + { if (matches[0].Success) { var blockItemValue = new SoundBlockItem @@ -215,7 +222,9 @@ namespace Filtration.Parser.Services block.BlockItems.Add(blockItemValue); } break; + } case 2: + { if (matches[0].Success && matches[1].Success) { var blockItemValue = new SoundBlockItem @@ -226,6 +235,7 @@ namespace Filtration.Parser.Services block.BlockItems.Add(blockItemValue); } break; + } } break; } @@ -436,7 +446,8 @@ namespace Filtration.Parser.Services // to the clipboard, and when saving a ItemFilterScript. public string TranslateItemFilterBlockToString(IItemFilterBlock block) { - if (block.GetType() == typeof (ItemFilterSection)) + // TODO: fix + if (block.GetType() == typeof (ItemFilterCommentBlock)) { return "# Section: " + block.Description; } diff --git a/Filtration.Parser/Services/ItemFilterScriptTranslator.cs b/Filtration.Parser/Services/ItemFilterScriptTranslator.cs index 41173d0..870f94d 100644 --- a/Filtration.Parser/Services/ItemFilterScriptTranslator.cs +++ b/Filtration.Parser/Services/ItemFilterScriptTranslator.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text.RegularExpressions; using Filtration.Common.Utilities; using Filtration.ObjectModel; @@ -10,6 +11,26 @@ using Filtration.Properties; namespace Filtration.Parser.Services { + + internal class ItemFilterBlockBoundary + { + public ItemFilterBlockBoundary(int startLine, ItemFilterBlockBoundaryType itemFilterBlockBoundaryType) + { + StartLine = startLine; + BoundaryType = itemFilterBlockBoundaryType; + } + + public int StartLine { get; set; } + public ItemFilterBlockBoundaryType BoundaryType { get; set; } + + } + + internal enum ItemFilterBlockBoundaryType + { + ItemFilterBlock, + CommentBlock + } + internal class ItemFilterScriptTranslator : IItemFilterScriptTranslator { private readonly IItemFilterBlockTranslator _blockTranslator; @@ -98,12 +119,12 @@ namespace Filtration.Parser.Services var lines = Regex.Split(inputString, "\r\n|\r|\n"); // Process the script header - for (var i = 0; i < conditionBoundaries.First.Value; i++) + for (var i = 0; i < conditionBoundaries.First.Value.StartLine; i++) { if (lines[i].StartsWith("#")) { script.Description += lines[i].Substring(1).Trim(' ') + Environment.NewLine; - } + } } if (!string.IsNullOrEmpty(script.Description)) @@ -115,43 +136,85 @@ namespace Filtration.Parser.Services // and add that object to the ItemFilterBlocks list for (var boundary = conditionBoundaries.First; boundary != null; boundary = boundary.Next) { - var begin = boundary.Value; - var end = boundary.Next?.Value ?? lines.Length; + var begin = boundary.Value.StartLine; + var end = boundary.Next?.Value.StartLine ?? lines.Length; var block = new string[end - begin]; Array.Copy(lines, begin, block, 0, end - begin); var blockString = string.Join("\r\n", block); - script.ItemFilterBlocks.Add(_blockTranslator.TranslateStringToItemFilterBlock(blockString, script.ItemFilterScriptSettings)); + + if (boundary.Value.BoundaryType == ItemFilterBlockBoundaryType.ItemFilterBlock) + { + script.ItemFilterBlocks.Add(_blockTranslator.TranslateStringToItemFilterBlock(blockString, script.ItemFilterScriptSettings)); + } + else + { + script.ItemFilterBlocks.Add(_blockTranslator.TranslateStringToItemFilterCommentBlock(blockString)); + } } _blockGroupHierarchyBuilder.Cleanup(); return script; } - - private static LinkedList IdentifyBlockBoundaries(string inputString) + + private static LinkedList IdentifyBlockBoundaries(string inputString) { - var blockBoundaries = new LinkedList(); + var blockBoundaries = new LinkedList(); var previousLine = string.Empty; - var currentLine = 0; + var currentLine = -1; + + var currentItemFilterBlockBoundary = new ItemFilterBlockBoundary(1, ItemFilterBlockBoundaryType.CommentBlock); foreach (var line in new LineReader(() => new StringReader(inputString))) { currentLine++; var trimmedLine = line.Trim(' '); - if (trimmedLine.StartsWith("Show") || trimmedLine.StartsWith("Hide") || - trimmedLine.StartsWith("# Section:")) + + if (string.IsNullOrWhiteSpace(trimmedLine)) + { + previousLine = line; + continue; + } + + // A line starting with a comment when we're inside a ItemFilterBlock boundary represents the end of that block + // as ItemFilterBlocks cannot have comment lines after the block description + if (trimmedLine.StartsWith("#") && currentItemFilterBlockBoundary?.BoundaryType == ItemFilterBlockBoundaryType.ItemFilterBlock) + { + blockBoundaries.AddLast(currentItemFilterBlockBoundary); + currentItemFilterBlockBoundary = new ItemFilterBlockBoundary(currentLine, ItemFilterBlockBoundaryType.CommentBlock); + } + // A line starting with a comment where the previous line was null represents the start of a new comment (unless we're on the first + // line in which case it's not a new comment). + else if (trimmedLine.StartsWith("#") && string.IsNullOrWhiteSpace(previousLine) && currentLine > 0) + { + if (blockBoundaries.Count > 0) + { + blockBoundaries.AddLast(currentItemFilterBlockBoundary); + } + currentItemFilterBlockBoundary = new ItemFilterBlockBoundary(currentLine, ItemFilterBlockBoundaryType.CommentBlock); + } + + else if (trimmedLine.StartsWith("Show") || trimmedLine.StartsWith("Hide")) { // If the line previous to the Show or Hide line is a comment then we should include that in the block // as it represents the block description. // currentLine > 2 caters for an edge case where the script description is a single line and the first // block has no description. This prevents the script description from being assigned to the first block's description. - blockBoundaries.AddLast(previousLine.StartsWith("#") && !previousLine.StartsWith("# Section:") && - currentLine > 2 - ? currentLine - 2 - : currentLine - 1); + if (!(currentItemFilterBlockBoundary.StartLine == currentLine - 1 && currentItemFilterBlockBoundary.BoundaryType == ItemFilterBlockBoundaryType.CommentBlock)) + { + blockBoundaries.AddLast(currentItemFilterBlockBoundary); + } + currentItemFilterBlockBoundary = new ItemFilterBlockBoundary(previousLine.StartsWith("#") && currentLine > 2 ? currentLine - 1 : currentLine, + ItemFilterBlockBoundaryType.ItemFilterBlock); } + previousLine = line; } + if (blockBoundaries.Last.Value != currentItemFilterBlockBoundary) + { + blockBoundaries.AddLast(currentItemFilterBlockBoundary); + } + return blockBoundaries; } @@ -178,7 +241,7 @@ namespace Filtration.Parser.Services // ReSharper disable once LoopCanBeConvertedToQuery foreach (var block in script.ItemFilterBlocks) { - outputString += _blockTranslator.TranslateItemFilterBlockToString(block) + Environment.NewLine; + outputString += _blockTranslator.TranslateItemFilterBlockToString(block as ItemFilterBlock) + Environment.NewLine; if (Settings.Default.ExtraLineBetweenBlocks) { diff --git a/Filtration.ThemeEditor/Services/ThemeService.cs b/Filtration.ThemeEditor/Services/ThemeService.cs index 95c22b9..360c24f 100644 --- a/Filtration.ThemeEditor/Services/ThemeService.cs +++ b/Filtration.ThemeEditor/Services/ThemeService.cs @@ -44,7 +44,7 @@ namespace Filtration.ThemeEditor.Services break; } - foreach (var block in script.ItemFilterBlocks) + foreach (var block in script.ItemFilterBlocks.OfType()) { foreach (var blockItem in block.BlockItems.Where(i => i.GetType() == targetType)) { diff --git a/Filtration/ViewModels/ItemFilterBlockViewModel.cs b/Filtration/ViewModels/ItemFilterBlockViewModel.cs index 250e4d7..6a07998 100644 --- a/Filtration/ViewModels/ItemFilterBlockViewModel.cs +++ b/Filtration/ViewModels/ItemFilterBlockViewModel.cs @@ -4,7 +4,6 @@ using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; using System.Windows.Media; -using Filtration.Common.ViewModels; using Filtration.ObjectModel; using Filtration.ObjectModel.BlockItemBaseTypes; using Filtration.ObjectModel.BlockItemTypes; diff --git a/Filtration/ViewModels/ItemFilterScriptViewModel.cs b/Filtration/ViewModels/ItemFilterScriptViewModel.cs index c061b84..2ba0149 100644 --- a/Filtration/ViewModels/ItemFilterScriptViewModel.cs +++ b/Filtration/ViewModels/ItemFilterScriptViewModel.cs @@ -320,7 +320,7 @@ namespace Filtration.ViewModels ItemFilterBlockViewModels.Clear(); Script = itemFilterScript; - foreach (var block in Script.ItemFilterBlocks) + foreach (var block in Script.ItemFilterBlocks.OfType()) { var vm = _itemFilterBlockViewModelFactory.Create(); vm.Initialise(block, this); @@ -426,7 +426,7 @@ namespace Filtration.ViewModels var unusedThemeComponents = Script.ThemeComponents.Where( t => - Script.ItemFilterBlocks.Count( + Script.ItemFilterBlocks.OfType().Count( b => b.BlockItems.OfType().Count(i => i.ThemeComponent == t) > 0) == 0).ToList(); if (unusedThemeComponents.Count <= 0) return true;