Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -35,9 +35,8 @@
|
||||
<HintPath>..\packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Castle.Windsor, Version=3.3.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Castle.Windsor.3.3.0\lib\net45\Castle.Windsor.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Reference Include="Castle.Windsor, Version=3.4.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Castle.Windsor.3.4.0\lib\net45\Castle.Windsor.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="System" />
|
||||
|
||||
@@ -29,64 +29,70 @@ namespace Filtration.Parser.Services
|
||||
_blockGroupHierarchyBuilder = blockGroupHierarchyBuilder;
|
||||
}
|
||||
|
||||
// Converts a string into an ItemFilterCommentBlock maintaining newlines and spaces but removing # characters
|
||||
public IItemFilterCommentBlock TranslateStringToItemFilterCommentBlock(string inputString, IItemFilterScript parentItemFilterScript)
|
||||
{
|
||||
var itemFilterCommentBlock = new ItemFilterCommentBlock(parentItemFilterScript);
|
||||
|
||||
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, ThemeComponentCollection masterComponentCollection)
|
||||
public IItemFilterBlock TranslateStringToItemFilterBlock(string inputString, IItemFilterScript parentItemFilterScript, bool initialiseBlockGroupHierarchyBuilder = false)
|
||||
{
|
||||
_masterComponentCollection = masterComponentCollection;
|
||||
var block = new ItemFilterBlock();
|
||||
if (initialiseBlockGroupHierarchyBuilder)
|
||||
{
|
||||
_blockGroupHierarchyBuilder.Initialise(parentItemFilterScript.ItemFilterBlockGroups.First());
|
||||
}
|
||||
|
||||
_masterComponentCollection = parentItemFilterScript.ItemFilterScriptSettings.ThemeComponentCollection;
|
||||
var block = new ItemFilterBlock(parentItemFilterScript);
|
||||
var showHideFound = false;
|
||||
|
||||
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(' ');
|
||||
continue;
|
||||
}
|
||||
|
||||
var adjustedLine = line.Replace("#", " # ");
|
||||
var trimmedLine = adjustedLine.TrimStart(' ').TrimEnd(' ');
|
||||
|
||||
var trimmedLine = line.Trim();
|
||||
var spaceOrEndOfLinePos = trimmedLine.IndexOf(" ", StringComparison.Ordinal) > 0 ? trimmedLine.IndexOf(" ", StringComparison.Ordinal) : trimmedLine.Length;
|
||||
|
||||
var lineOption = trimmedLine.Substring(0, spaceOrEndOfLinePos);
|
||||
switch (lineOption)
|
||||
{
|
||||
case "Show":
|
||||
showHideFound = true;
|
||||
block.Action = BlockAction.Show;
|
||||
block.Enabled = true;
|
||||
AddBlockGroupToBlock(block, trimmedLine);
|
||||
break;
|
||||
case "Hide":
|
||||
showHideFound = true;
|
||||
block.Action = BlockAction.Hide;
|
||||
block.Enabled = true;
|
||||
AddBlockGroupToBlock(block, trimmedLine);
|
||||
break;
|
||||
case "ShowDisabled":
|
||||
showHideFound = true;
|
||||
block.Action = BlockAction.Show;
|
||||
block.Enabled = false;
|
||||
AddBlockGroupToBlock(block, trimmedLine);
|
||||
break;
|
||||
case "HideDisabled":
|
||||
{
|
||||
showHideFound = true;
|
||||
block.Action = BlockAction.Hide;
|
||||
block.Enabled = false;
|
||||
AddBlockGroupToBlock(block, trimmedLine);
|
||||
block.Action = lineOption.StartsWith("Show") ? BlockAction.Show : BlockAction.Hide;
|
||||
block.Enabled = !lineOption.EndsWith("Disabled");
|
||||
|
||||
// If block groups are enabled for this script, the comment after Show/Hide is parsed as a block
|
||||
// group hierarchy, if block groups are disabled it is preserved as a simple text comment.
|
||||
if (parentItemFilterScript.ItemFilterScriptSettings.BlockGroupsEnabled)
|
||||
{
|
||||
AddBlockGroupToBlock(block, trimmedLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
block.ActionBlockItem.Comment = GetTextAfterFirstComment(trimmedLine);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "ItemLevel":
|
||||
{
|
||||
AddNumericFilterPredicateItemToBlockItems<ItemLevelBlockItem>(block, trimmedLine);
|
||||
@@ -417,11 +423,11 @@ namespace Filtration.Parser.Services
|
||||
|
||||
private void AddBlockGroupToBlock(IItemFilterBlock block, string inputString)
|
||||
{
|
||||
var blockGroupStart = inputString.IndexOf("#", StringComparison.Ordinal);
|
||||
if (blockGroupStart <= 0) return;
|
||||
var blockGroupText = GetTextAfterFirstComment(inputString);
|
||||
var blockGroups = blockGroupText.Split(new[] { " - " }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(s => s.Trim())
|
||||
.ToList();
|
||||
|
||||
var blockGroupText = inputString.Substring(blockGroupStart + 1);
|
||||
var blockGroups = blockGroupText.Split('-').ToList();
|
||||
if (blockGroups.Count(b => !string.IsNullOrEmpty(b.Trim())) > 0)
|
||||
{
|
||||
block.BlockGroup = _blockGroupHierarchyBuilder.IntegrateStringListIntoBlockGroupHierarchy(blockGroups);
|
||||
@@ -429,6 +435,14 @@ namespace Filtration.Parser.Services
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetTextAfterFirstComment(string inputString)
|
||||
{
|
||||
var blockGroupStart = inputString.IndexOf("#", StringComparison.Ordinal);
|
||||
if (blockGroupStart <= 0) return string.Empty;
|
||||
|
||||
return inputString.Substring(blockGroupStart + 1);
|
||||
}
|
||||
|
||||
private static Color GetColorFromString(string inputString)
|
||||
{
|
||||
var argbValues = Regex.Matches(inputString, @"\s+(\d+)");
|
||||
@@ -455,15 +469,31 @@ namespace Filtration.Parser.Services
|
||||
return new Color();
|
||||
}
|
||||
|
||||
public string TranslateItemFilterBlockBaseToString(IItemFilterBlockBase itemFilterBlockBase)
|
||||
{
|
||||
var itemFilterBlock = itemFilterBlockBase as IItemFilterBlock;
|
||||
if (itemFilterBlock != null) return TranslateItemFilterBlockToString(itemFilterBlock);
|
||||
|
||||
var itemFilterCommentBlock = itemFilterBlockBase as IItemFilterCommentBlock;
|
||||
if (itemFilterCommentBlock != null) return TranslateItemFilterCommentBlockToString(itemFilterCommentBlock);
|
||||
|
||||
throw new InvalidOperationException("Unable to translate unknown ItemFilterBlock type");
|
||||
}
|
||||
|
||||
// TODO: Private
|
||||
public string TranslateItemFilterCommentBlockToString(IItemFilterCommentBlock itemFilterCommentBlock)
|
||||
{
|
||||
// TODO: Handle multi-line
|
||||
// TODO: Tests
|
||||
// TODO: # Section: text?
|
||||
return $"#{itemFilterCommentBlock.Comment}";
|
||||
}
|
||||
|
||||
// This method converts an ItemFilterBlock object into a string. This is used for copying a ItemFilterBlock
|
||||
// to the clipboard, and when saving a ItemFilterScript.
|
||||
// TODO: Private
|
||||
public string TranslateItemFilterBlockToString(IItemFilterBlock block)
|
||||
{
|
||||
if (block.GetType() == typeof (ItemFilterSection))
|
||||
{
|
||||
return "# Section: " + block.Description;
|
||||
}
|
||||
|
||||
var outputString = string.Empty;
|
||||
|
||||
if (!block.Enabled)
|
||||
@@ -482,6 +512,10 @@ namespace Filtration.Parser.Services
|
||||
{
|
||||
outputString += " # " + block.BlockGroup;
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(block.ActionBlockItem?.Comment))
|
||||
{
|
||||
outputString += " #" + block.ActionBlockItem.Comment;
|
||||
}
|
||||
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
foreach (var blockItem in block.BlockItems.Where(b => b.GetType() != typeof(ActionBlockItem)).OrderBy(b => b.SortOrder))
|
||||
|
||||
@@ -2,27 +2,53 @@
|
||||
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;
|
||||
using Filtration.ObjectModel.Factories;
|
||||
using Filtration.Parser.Interface.Services;
|
||||
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
|
||||
{
|
||||
ScriptDescription,
|
||||
ItemFilterBlock,
|
||||
CommentBlock
|
||||
}
|
||||
|
||||
internal class ItemFilterScriptTranslator : IItemFilterScriptTranslator
|
||||
{
|
||||
private readonly IItemFilterBlockTranslator _blockTranslator;
|
||||
private readonly IItemFilterScriptFactory _itemFilterScriptFactory;
|
||||
private readonly IBlockGroupHierarchyBuilder _blockGroupHierarchyBuilder;
|
||||
|
||||
public ItemFilterScriptTranslator(IItemFilterBlockTranslator blockTranslator,
|
||||
IBlockGroupHierarchyBuilder blockGroupHierarchyBuilder)
|
||||
public ItemFilterScriptTranslator(IBlockGroupHierarchyBuilder blockGroupHierarchyBuilder,
|
||||
IItemFilterBlockTranslator blockTranslator,
|
||||
IItemFilterScriptFactory itemFilterScriptFactory)
|
||||
{
|
||||
_blockTranslator = blockTranslator;
|
||||
_blockGroupHierarchyBuilder = blockGroupHierarchyBuilder;
|
||||
_blockTranslator = blockTranslator;
|
||||
_itemFilterScriptFactory = itemFilterScriptFactory;
|
||||
}
|
||||
|
||||
public string PreprocessDisabledBlocks(string inputString)
|
||||
public static string PreprocessDisabledBlocks(string inputString)
|
||||
{
|
||||
bool inDisabledBlock = false;
|
||||
var showHideFound = false;
|
||||
@@ -82,9 +108,9 @@ namespace Filtration.Parser.Services
|
||||
return lines.Aggregate((c, n) => c + Environment.NewLine + n);
|
||||
}
|
||||
|
||||
public ItemFilterScript TranslateStringToItemFilterScript(string inputString)
|
||||
public IItemFilterScript TranslateStringToItemFilterScript(string inputString)
|
||||
{
|
||||
var script = new ItemFilterScript();
|
||||
var script = _itemFilterScriptFactory.Create();
|
||||
_blockGroupHierarchyBuilder.Initialise(script.ItemFilterBlockGroups.First());
|
||||
|
||||
inputString = inputString.Replace("\t", "");
|
||||
@@ -98,12 +124,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.Skip(1).First().StartLine; i++)
|
||||
{
|
||||
if (lines[i].StartsWith("#"))
|
||||
{
|
||||
script.Description += lines[i].Substring(1).Trim(' ') + Environment.NewLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(script.Description))
|
||||
@@ -115,47 +141,94 @@ 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;
|
||||
if (boundary.Value.BoundaryType == ItemFilterBlockBoundaryType.ScriptDescription)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
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.ThemeComponents));
|
||||
|
||||
if (boundary.Value.BoundaryType == ItemFilterBlockBoundaryType.ItemFilterBlock)
|
||||
{
|
||||
script.ItemFilterBlocks.Add(_blockTranslator.TranslateStringToItemFilterBlock(blockString, script));
|
||||
}
|
||||
else
|
||||
{
|
||||
script.ItemFilterBlocks.Add(_blockTranslator.TranslateStringToItemFilterCommentBlock(blockString, script));
|
||||
}
|
||||
}
|
||||
|
||||
_blockGroupHierarchyBuilder.Cleanup();
|
||||
return script;
|
||||
}
|
||||
|
||||
private static LinkedList<int> IdentifyBlockBoundaries(string inputString)
|
||||
|
||||
private static LinkedList<ItemFilterBlockBoundary> IdentifyBlockBoundaries(string inputString)
|
||||
{
|
||||
var blockBoundaries = new LinkedList<int>();
|
||||
var blockBoundaries = new LinkedList<ItemFilterBlockBoundary>();
|
||||
var previousLine = string.Empty;
|
||||
var currentLine = 0;
|
||||
var currentLine = -1;
|
||||
|
||||
var currentItemFilterBlockBoundary = new ItemFilterBlockBoundary(0, ItemFilterBlockBoundaryType.ScriptDescription);
|
||||
|
||||
foreach (var line in new LineReader(() => new StringReader(inputString)))
|
||||
{
|
||||
currentLine++;
|
||||
var trimmedLine = line.TrimStart(' ').TrimEnd(' ');
|
||||
if (trimmedLine.StartsWith("Show") || trimmedLine.StartsWith("Hide") ||
|
||||
trimmedLine.StartsWith("# Section:"))
|
||||
var trimmedLine = line.Trim(' ');
|
||||
|
||||
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) && currentItemFilterBlockBoundary.BoundaryType != ItemFilterBlockBoundaryType.ScriptDescription)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public string TranslateItemFilterScriptToString(ItemFilterScript script)
|
||||
public string TranslateItemFilterScriptToString(IItemFilterScript script)
|
||||
{
|
||||
var outputString = string.Empty;
|
||||
|
||||
@@ -178,7 +251,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)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Castle.Core" version="3.3.3" targetFramework="net461" />
|
||||
<package id="Castle.Windsor" version="3.3.0" targetFramework="net461" />
|
||||
<package id="Castle.Windsor" version="3.4.0" targetFramework="net461" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user