diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HighlightedLineMergeTests.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HighlightedLineMergeTests.cs new file mode 100644 index 0000000000..b6a88f6c31 --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HighlightedLineMergeTests.cs @@ -0,0 +1,166 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Linq; +using ICSharpCode.NRefactory.Editor; +using NUnit.Framework; + +namespace ICSharpCode.AvalonEdit.Highlighting +{ + [TestFixture] + public class HighlightedLineMergeTests + { + IDocument document = new ReadOnlyDocument(new string(' ', 20)); + + [Test] + public void SimpleMerge1() + { + HighlightedLine baseLine = new HighlightedLine(document, document.GetLineByNumber(1)); + baseLine.Sections.Add(MakeSection(0, 1, "B")); + + HighlightedLine additionalLine = new HighlightedLine(document, document.GetLineByNumber(1)); + additionalLine.Sections.Add(MakeSection(0, 2, "A")); + + baseLine.MergeWith(additionalLine); + // The additional section gets split up so that it fits into the tree structure + Assert.That(baseLine.Sections, Is.EqualTo( + new[] { + MakeSection(0, 1, "B"), + MakeSection(0, 1, "A"), + MakeSection(1, 2, "A") + }).Using(new SectionComparer())); + } + + [Test] + public void SimpleMerge2() + { + HighlightedLine baseLine = new HighlightedLine(document, document.GetLineByNumber(1)); + baseLine.Sections.Add(MakeSection(0, 1, "B")); + baseLine.Sections.Add(MakeSection(0, 1, "BN")); + + HighlightedLine additionalLine = new HighlightedLine(document, document.GetLineByNumber(1)); + additionalLine.Sections.Add(MakeSection(0, 2, "A")); + + baseLine.MergeWith(additionalLine); + // The additional section gets split up so that it fits into the tree structure + Assert.That(baseLine.Sections, Is.EqualTo( + new[] { + MakeSection(0, 1, "B"), + MakeSection(0, 1, "BN"), + MakeSection(0, 1, "A"), + MakeSection(1, 2, "A") + }).Using(new SectionComparer())); + } + + HighlightedSection MakeSection(int start, int end, string name) + { + return new HighlightedSection { Offset = start, Length = end - start, Color = new HighlightingColor { Name = name }}; + } + + class SectionComparer : IEqualityComparer + { + public bool Equals(HighlightedSection a, HighlightedSection b) + { + return a.Offset == b.Offset && a.Length == b.Length && a.Color.Name == b.Color.Name; + } + + public int GetHashCode(HighlightedSection obj) + { + return obj.Offset; + } + } + + #region Automatic Test + /* + const int combinations = 6 * 3 * 4 * 3 * 3 * 4; + HighlightingColor[] baseLineColors = { + new HighlightingColor { Name = "Base-A" }, + new HighlightingColor { Name = "Base-B" }, + new HighlightingColor { Name = "Base-N" }, + new HighlightingColor { Name = "Base-C" } + }; + HighlightingColor[] additionalLineColors = { + new HighlightingColor { Name = "Add-A" }, + new HighlightingColor { Name = "Add-B" }, + new HighlightingColor { Name = "Add-N" }, + new HighlightingColor { Name = "Add-C" } + }; + + HighlightedLine BuildHighlightedLine(int num, HighlightingColor[] colors) + { + // We are build a HighlightedLine with 4 segments: + // A B C (top-level) and N nested within B. + // These are the integers controlling the generating process: + + int aStart = GetNum(ref num, 5); // start offset of A + int aLength = GetNum(ref num, 2); // length of A + + int bDistance = GetNum(ref num, 3); // distance from start of B to end of A + int bStart = aStart + aLength + bDistance; + int nDistance = GetNum(ref num, 2); // distance from start of B to start of N, range 0-2 + int nLength = GetNum(ref num, 2); // length of N + int bEndDistance = GetNum(ref num, 2); // distance from end of N to end of B + int bLength = nDistance + nLength + bEndDistance; + + int cDistance = GetNum(ref num, 3); // distance from end of B to start of C + int cStart = bStart + bLength + cDistance; + int cLength = 1; + Assert.AreEqual(0, num); + + var documentLine = document.GetLineByNumber(1); + HighlightedLine line = new HighlightedLine(document, documentLine); + line.Sections.Add(new HighlightedSection { Offset = aStart, Length = aLength, Color = colors[0] }); + line.Sections.Add(new HighlightedSection { Offset = bStart, Length = bLength, Color = colors[1] }); + line.Sections.Add(new HighlightedSection { Offset = bStart + nDistance, Length = nLength, Color = colors[2] }); + line.Sections.Add(new HighlightedSection { Offset = cStart, Length = cLength, Color = colors[3] }); + + return line; + } + + /// + /// Gets a number between 0 and max (inclusive) + /// + int GetNum(ref int num, int max) + { + int result = num % (max+1); + num = num / (max + 1); + return result; + } + + [Test] + public void TestAll() + { + for (int c1 = 0; c1 < combinations; c1++) { + HighlightedLine line1 = BuildHighlightedLine(c1, additionalLineColors); + for (int c2 = 0; c2 < combinations; c2++) { + HighlightedLine line2 = BuildHighlightedLine(c2, baseLineColors); + HighlightingColor[] expectedPerCharColors = new HighlightingColor[document.TextLength]; + ApplyColors(expectedPerCharColors, line2); + ApplyColors(expectedPerCharColors, line1); + try { + line2.MergeWith(line1); + } catch (InvalidOperationException ex) { + throw new InvalidOperationException(string.Format("Error for c1 = {0}, c2 = {1}", c1, c2), ex); + } + + HighlightingColor[] actualPerCharColors = new HighlightingColor[document.TextLength]; + ApplyColors(actualPerCharColors, line2); + Assert.AreEqual(expectedPerCharColors, actualPerCharColors, string.Format("c1 = {0}, c2 = {1}", c1, c2)); + } + } + } + + void ApplyColors(HighlightingColor[] perCharColors, HighlightedLine line) + { + foreach (var section in line.Sections) { + for (int i = 0; i < section.Length; i++) { + perCharColors[section.Offset + i] = section.Color; + } + } + } + */ + #endregion + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/ICSharpCode.AvalonEdit.Tests.csproj b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/ICSharpCode.AvalonEdit.Tests.csproj index 3e9a5c7875..3697ef15d0 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/ICSharpCode.AvalonEdit.Tests.csproj +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/ICSharpCode.AvalonEdit.Tests.csproj @@ -80,6 +80,7 @@ + diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs index 97a14d2908..99f80dcd18 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs @@ -324,7 +324,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion // 5 = match start // 4 = match CamelCase when length of query is 1 or 2 characters // 3 = match substring case sensitive - // 2 = match sustring + // 2 = match substring // 1 = match CamelCase // -1 = no match if (query == itemText) diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedLine.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedLine.cs index c5530dd6d7..912b4ba8c0 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedLine.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedLine.cs @@ -140,19 +140,23 @@ namespace ICSharpCode.AvalonEdit.Highlighting while (insertionStack.Peek() < insertionEndPos) { int end = insertionStack.Pop(); // insert the portion from newSectionStart to end + if (end > newSectionStart) { + this.Sections.Insert(pos++, new HighlightedSection { + Offset = newSectionStart, + Length = end - newSectionStart, + Color = color + }); + newSectionStart = end; + } + } + if (insertionEndPos > newSectionStart) { this.Sections.Insert(pos++, new HighlightedSection { Offset = newSectionStart, - Length = end - newSectionStart, + Length = insertionEndPos - newSectionStart, Color = color }); - newSectionStart = end; + newSectionStart = insertionEndPos; } - this.Sections.Insert(pos++, new HighlightedSection { - Offset = newSectionStart, - Length = insertionEndPos - newSectionStart, - Color = color - }); - newSectionStart = insertionEndPos; } #endregion diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedSection.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedSection.cs index 167badc019..63ec1a1efa 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedSection.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedSection.cs @@ -29,5 +29,11 @@ namespace ICSharpCode.AvalonEdit.Highlighting /// Gets the highlighting color associated with the highlighted section. /// public HighlightingColor Color { get; set; } + + /// + public override string ToString() + { + return string.Format("[HighlightedSection ({0}-{1})={2}]", Offset, Offset + Length, Color); + } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColor.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColor.cs index 0aaeed6c01..ec8fc39670 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColor.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColor.cs @@ -117,7 +117,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting /// public override string ToString() { - return "[" + GetType() + " " + (string.IsNullOrEmpty(this.Name) ? ToCss() : this.Name) + "]"; + return "[" + GetType().Name + " " + (string.IsNullOrEmpty(this.Name) ? ToCss() : this.Name) + "]"; } } }