From 11c428e10f75ab8530b174def3cc784e5628a6b8 Mon Sep 17 00:00:00 2001 From: Simon Lindgren Date: Wed, 4 Jul 2012 17:33:34 +0200 Subject: [PATCH] [Utils] Add CompositeFormatStringParser and related classes. --- .../ICSharpCode.NRefactory.Tests.csproj | 2 + .../CompositeFormatStringParserTests.cs | 153 ++++++++++++++++++ .../ICSharpCode.NRefactory.csproj | 7 + .../CompositeFormatStringParser.cs | 148 +++++++++++++++++ .../CompositeFormatStringParser/FormatItem.cs | 93 +++++++++++ .../FormatStringSegmentBase.cs | 66 ++++++++ .../IFormatStringError.cs | 56 +++++++ .../IFormatStringSegment.cs | 48 ++++++ .../TextSegment.cs | 89 ++++++++++ 9 files changed, 662 insertions(+) create mode 100644 ICSharpCode.NRefactory.Tests/Utils/CompositeFormatStringParser/CompositeFormatStringParserTests.cs create mode 100644 ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/CompositeFormatStringParser.cs create mode 100644 ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/FormatItem.cs create mode 100644 ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/FormatStringSegmentBase.cs create mode 100644 ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/IFormatStringError.cs create mode 100644 ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/IFormatStringSegment.cs create mode 100644 ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/TextSegment.cs diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj index 7d7f5a8fcc..8f1eb93056 100644 --- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj +++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj @@ -290,6 +290,7 @@ + @@ -320,6 +321,7 @@ + diff --git a/ICSharpCode.NRefactory.Tests/Utils/CompositeFormatStringParser/CompositeFormatStringParserTests.cs b/ICSharpCode.NRefactory.Tests/Utils/CompositeFormatStringParser/CompositeFormatStringParserTests.cs new file mode 100644 index 0000000000..955c545dc5 --- /dev/null +++ b/ICSharpCode.NRefactory.Tests/Utils/CompositeFormatStringParser/CompositeFormatStringParserTests.cs @@ -0,0 +1,153 @@ +// +// CompositeFormatStringParserTests.cs +// +// Author: +// Simon Lindgren +// +// Copyright (c) 2012 Simon Lindgren +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using NUnit.Framework; +using System.Linq; +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.Utils +{ + [TestFixture] + public class CompositeFormatStringParserTests + { + + IList ParseTest(string format, params IFormatStringSegment[] expectedFormatSegments) + { + var parser = new CompositeFormatStringParser(); + var actualFormatSegments = parser.Parse(format).ToList(); + + Console.WriteLine("Expected format segments:"); + foreach (var item in expectedFormatSegments) { + Console.WriteLine(item.ToString()); + } + Console.WriteLine("Actual format segments:"); + foreach (var item in actualFormatSegments) { + Console.WriteLine(item.ToString()); + } + + Assert.AreEqual(expectedFormatSegments, actualFormatSegments); + return actualFormatSegments; + } + + [Test] + public void Index() + { + ParseTest("{0}", new FormatItem(0) { StartLocation = 0, EndLocation = 3 }); + } + + [Test] + public void PositiveAlignment() + { + ParseTest("{0,4}", new FormatItem(0, 4) { StartLocation = 0, EndLocation = 5 }); + } + + [Test] + public void NegativeAlignment() + { + ParseTest("{0,-4}", new FormatItem(0, -4) { StartLocation = 0, EndLocation = 6 }); + } + + [Test] + public void AlignmentWhiteSpace() + { + ParseTest("{0, -4}", new FormatItem(0, -4) { StartLocation = 0, EndLocation = 7 }); + } + + [Test] + public void SubFormatString() + { + ParseTest("{0:aaaa}", new FormatItem(0, null, "aaaa") { StartLocation = 0, EndLocation = 8 }); + } + + [Test] + public void CompleteFormatItem() + { + ParseTest("{0, -45:aaaa}", new FormatItem(0, -45, "aaaa") { StartLocation = 0, EndLocation = 13 }); + } + + [Test] + public void MultipleCompleteFormatItems() + { + ParseTest("{0, -45:aaaa}{3, 67:bbbb}", + new FormatItem(0, -45, "aaaa") { StartLocation = 0, EndLocation = 13 }, + new FormatItem(3, 67, "bbbb") { StartLocation = 13, EndLocation = 25 }); + } + + [Test] + public void BraceEscape() + { + ParseTest("{{}}", new TextSegment("{}")); + } + + [Test] + public void TextSegment() + { + ParseTest("Some Text", new TextSegment("Some Text")); + } + + [Test] + public void SingleCharacterTextSegment() + { + ParseTest("A", new TextSegment("A")); + } + + [Test] + public void FormatStringWithPrefixText() + { + ParseTest("Some Text {0}", + new TextSegment("Some Text "), + new FormatItem(0) { StartLocation = 10, EndLocation = 13 }); + } + + [Test] + public void FormatStringWithPostfixText() + { + ParseTest("{0} Some Text", + new FormatItem(0) { StartLocation = 0, EndLocation = 3 }, + new TextSegment(" Some Text", 3)); + } + + [Test] + public void FormatStringWithEscapableBracesInSubFormatString() + { + ParseTest("A weird string: {0:{{}}}", + new TextSegment("A weird string: "), + new FormatItem(0, null, "{}") { StartLocation = 16, EndLocation = 24}); + } + + [Test] + public void EndsAfterOpenBrace() + { + var segments = ParseTest("{", new TextSegment("{")); + var segment = segments [0]; + var errors = segment.Errors.ToList(); + Assert.AreEqual(1, errors.Count, "Too many or too few errors."); + var error = errors [0]; + Assert.AreEqual("{{", error.SuggestedReplacementText); + } + } +} + diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 7189df55a6..eedf1377e0 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -233,10 +233,17 @@ + + + + + + + diff --git a/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/CompositeFormatStringParser.cs b/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/CompositeFormatStringParser.cs new file mode 100644 index 0000000000..33a7234973 --- /dev/null +++ b/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/CompositeFormatStringParser.cs @@ -0,0 +1,148 @@ +// +// CompositeFormatStringParser.cs +// +// Authors: +// Simon Lindgren +// +// Copyright (c) 2012 Simon Lindgren +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.Utils +{ + /// + /// Composite format string parser. + /// + /// + /// Implements a complete parser for valid strings as well as + /// error reporting and best-effort parsing for invalid strings. + /// + public class CompositeFormatStringParser + { + /// + /// Parse the specified format string. + /// + /// + /// The format string. + /// + public IEnumerable Parse (string format) + { + // Format string syntax: http://msdn.microsoft.com/en-us/library/txafckwd.aspx + int start = 0; + var length = format.Length; + for (int i = 0; i < length; i++) { + if (format [i] == '{') { + if (i + 1 == length) { + // This is the end of the string. + var textSegment = new TextSegment (format.Substring (start, i - start + 1), start) { + Errors = { + new DefaultFormatStringError { + StartLocation = i, + EndLocation = i + 1, + Message = "Curly braces need to be escaped", + OriginalText = "{", + SuggestedReplacementText = "{{" + } + } + }; + yield return textSegment; + yield break; + } else if (format [i + 1] == '{') { + // Escape sequence; we're still in a text segment + // Skip ahead to the char after the escape sequence + ++i; + continue; + } else { + // This is the end of the text segment and the start of a FormatItem + if (i - start > 0) { + yield return TextSegment.FromUnescapedText (format.Substring (start, i - start)); + start = i; + } + } + + int index; + int? alignment = null; + string argumentFormat = null; + + // Index + ++i; + index = int.Parse (GetUntil (format, ",:}", ref i)); + + // Alignment + if (format [i] == ',') { + ++i; + while (i < length && char.IsWhiteSpace(format [i])) + ++i; + if (format [i] == '-') { + ++i; + alignment = -int.Parse (GetUntil (format, ":}", ref i)); + } else { + alignment = int.Parse (GetUntil (format, ":}", ref i)); + } + + } + + // Format string + if (format [i] == ':') { + ++i; + int begin = i; + while (i < length) { + char c2 = format [i]; + if (c2 != '}') { + ++i; + continue; + } + if (i + 1 < length && format [i + 1] == '}') { + // Step past escape sequence + i += 2; + continue; + } else { + // This is the end of the FormatItem + break; + } + } + argumentFormat = TextSegment.UnEscape (format.Substring (begin, i - begin)); + } + + yield return new FormatItem (index, alignment, argumentFormat) { StartLocation = start, EndLocation = i + 1 }; + + // The next potential text segment starts after this format item + start = i + 1; + } + } + // Handle remaining text + if (start < length) { + yield return new TextSegment (TextSegment.UnEscape (format.Substring (start)), start); + } + } + + string GetUntil (string format, string delimiters, ref int index) + { + int start = index; + while (index < format.Length && !delimiters.Contains(format[index].ToString())) + ++index; + + return format.Substring (start, index - start); + } + + } +} + diff --git a/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/FormatItem.cs b/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/FormatItem.cs new file mode 100644 index 0000000000..e953ab2f74 --- /dev/null +++ b/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/FormatItem.cs @@ -0,0 +1,93 @@ +// +// FormatItem.cs +// +// Author: +// Simon Lindgren +// +// Copyright (c) 2012 Simon Lindgren +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace ICSharpCode.NRefactory.Utils +{ + public class FormatItem : FormatStringSegmentBase + { + public FormatItem (int index, int? alignment = null, string formatString = null) + { + Index = index; + Alignment = alignment; + FormatString = formatString; + } + + public int Index { get; private set; } + + public int? Alignment { get; private set; } + + public string FormatString { get; private set; } + + #region Equality + public override bool Equals (object obj) + { + if (obj == null) + return false; + if (obj.GetType () != typeof(FormatItem)) + return false; + var other = (FormatItem)obj; + + return FieldsEquals (other); + } + + public bool Equals (FormatItem other) + { + if (other == null) + return false; + + return FieldsEquals (other); + } + + bool FieldsEquals (FormatItem other) + { + return Index == other.Index && + Alignment == other.Alignment && + FormatString == other.FormatString && + StartLocation == other.StartLocation && + EndLocation == other.EndLocation; + } + + public override int GetHashCode () + { + unchecked { + int hash = 23; + hash = hash * 37 + Index.GetHashCode (); + hash = hash * 37 + Alignment.GetHashCode (); + hash = hash * 37 + FormatString.GetHashCode (); + hash = hash * 37 + StartLocation.GetHashCode (); + hash = hash * 37 + EndLocation.GetHashCode (); + return hash; + } + } + #endregion + + public override string ToString () + { + return string.Format ("[FormatItem: Index={0}, Alignment={1}, FormatString={2}, StartLocation={3}, EndLocation={4}]", Index, Alignment, FormatString, StartLocation, EndLocation); + } + } + +} diff --git a/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/FormatStringSegmentBase.cs b/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/FormatStringSegmentBase.cs new file mode 100644 index 0000000000..e301e136f2 --- /dev/null +++ b/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/FormatStringSegmentBase.cs @@ -0,0 +1,66 @@ +// +// FormatStringSegmentBase.cs +// +// Author: +// Simon Lindgren +// +// Copyright (c) 2012 Simon Lindgren +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System.Collections.Generic; +using System.Linq; + +namespace ICSharpCode.NRefactory.Utils +{ + /// + /// Composite format string parser. + /// + /// + /// Implements a complete parser for valid strings as well as + /// error reporting and best-effort parsing for invalid strings. + /// + public abstract class FormatStringSegmentBase : IFormatStringSegment + { + public FormatStringSegmentBase () + { + Errors = new List (); + } + + #region IFormatStringSegment implementation + public int StartLocation { get; set; } + + public int EndLocation { get; set; } + + public bool HasErrors { + get { + return Errors.Any (); + } + } + + public IList Errors { get; set; } + + IEnumerable IFormatStringSegment.Errors { + get { + return Errors; + } + } + #endregion + } + +} diff --git a/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/IFormatStringError.cs b/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/IFormatStringError.cs new file mode 100644 index 0000000000..6918c998da --- /dev/null +++ b/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/IFormatStringError.cs @@ -0,0 +1,56 @@ +// +// IFormatStringError.cs +// +// Author: +// Simon Lindgren +// +// Copyright (c) 2012 Simon Lindgren +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace ICSharpCode.NRefactory.Utils +{ + public interface IFormatStringError + { + int StartLocation { get; } + + int EndLocation { get; } + + string Message { get; } + + string OriginalText { get; } + + string SuggestedReplacementText { get; } + } + + class DefaultFormatStringError : IFormatStringError + { + #region IFormatStringError implementation + public int StartLocation { get; set; } + + public int EndLocation { get; set; } + + public string Message { get; set; } + + public string OriginalText { get; set; } + + public string SuggestedReplacementText { get; set; } + #endregion + } +} diff --git a/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/IFormatStringSegment.cs b/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/IFormatStringSegment.cs new file mode 100644 index 0000000000..e686e77882 --- /dev/null +++ b/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/IFormatStringSegment.cs @@ -0,0 +1,48 @@ +// +// IFormatStringSegment.cs +// +// Author: +// Simon Lindgren +// +// Copyright (c) 2012 Simon Lindgren +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.Utils +{ + /// + /// Composite format string parser. + /// + /// + /// Implements a complete parser for valid strings as well as + /// error reporting and best-effort parsing for invalid strings. + /// + public interface IFormatStringSegment + { + int StartLocation { get; set; } + + int EndLocation { get; set; } + + bool HasErrors { get; } + + IEnumerable Errors { get; } + } + +} diff --git a/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/TextSegment.cs b/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/TextSegment.cs new file mode 100644 index 0000000000..2d8f1e0eea --- /dev/null +++ b/ICSharpCode.NRefactory/Utils/CompositeFormatStringParser/TextSegment.cs @@ -0,0 +1,89 @@ +// +// TextSegment.cs +// +// Author: +// Simon Lindgren +// +// Copyright (c) 2012 Simon Lindgren +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace ICSharpCode.NRefactory.Utils +{ + public class TextSegment : FormatStringSegmentBase + { + public TextSegment (string text, int startLocation = 0, int? endLocation = null) + { + Text = text; + StartLocation = startLocation; + EndLocation = endLocation ?? startLocation + text.Length; + } + + public static IFormatStringSegment FromUnescapedText (string text) + { + return new TextSegment (UnEscape (text)); + } + + public static string UnEscape (string unEscaped) + { + return unEscaped.Replace ("{{", "{").Replace ("}}", "}"); + } + + public string Text { get; set; } + + #region Equality + public override bool Equals (object obj) + { + if (obj == null) + return false; + if (obj.GetType () != typeof(TextSegment)) + return false; + var other = (TextSegment)obj; + + return Equals (Text, other.Text); + } + + public bool Equals (TextSegment other) + { + if (other == null) + return false; + + return Equals (Text, other.Text) && + StartLocation == other.StartLocation && + EndLocation == other.EndLocation; + } + + public override int GetHashCode () + { + unchecked { + int hash = 23; + hash = hash * 37 + Text.GetHashCode (); + hash = hash * 37 + StartLocation.GetHashCode (); + hash = hash * 37 + EndLocation.GetHashCode (); + return hash; + } + } + #endregion + + public override string ToString () + { + return string.Format ("[TextSegment: Text={0}, StartLocation={1}, EndLocation={2}]", Text, StartLocation, EndLocation); + } + } +}