Browse Source

XamlBinding:

- added unit tests
- moved XamlColorizer to separate thread
- fixed NullReferenceException in XamlResolver

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4383 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Siegfried Pammer 17 years ago
parent
commit
e5604030b1
  1. 73
      src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/ExtensionsTests.cs
  2. 71
      src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/ResolveContextTests.cs
  3. 3
      src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/XamlBinding.Tests.csproj
  4. 189
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizer.cs
  5. 6
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizerServer.cs
  6. 2
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlResolver.cs

73
src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/ExtensionsTests.cs

@ -0,0 +1,73 @@ @@ -0,0 +1,73 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
// <version>$Revision$</version>
// </file>
using System;
using NUnit.Framework;
namespace ICSharpCode.XamlBinding.Tests
{
[TestFixture]
public class ExtensionsTests
{
[Test]
public void StringReplaceTest1()
{
string text = "Hello World!";
int index = 0;
int length = 5;
string newText = "Bye";
string result = text.Replace(index, length, newText);
string expected = "Bye World!";
Assert.AreEqual(expected, result);
}
[Test]
public void StringReplaceTest2()
{
string text = "My Hello World!";
int index = 3;
int length = 5;
string newText = "Bye";
string result = text.Replace(index, length, newText);
string expected = "My Bye World!";
Assert.AreEqual(expected, result);
}
[Test]
public void StringReplaceTest3()
{
string text = "Hello World!";
int index = 6;
int length = 5;
string newText = "Byte";
string result = text.Replace(index, length, newText);
string expected = "Hello Byte!";
Assert.AreEqual(expected, result);
}
[Test]
public void StringReplaceTest4()
{
string text = "Hello World!";
int index = 11;
int length = 1;
string newText = "?";
string result = text.Replace(index, length, newText);
string expected = "Hello World?";
Assert.AreEqual(expected, result);
}
}
}

71
src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/ResolveContextTests.cs

@ -0,0 +1,71 @@ @@ -0,0 +1,71 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.XmlEditor;
using System;
using NUnit.Framework;
namespace ICSharpCode.XamlBinding.Tests
{
[TestFixture]
public class ResolveContextTests
{
[Test]
public void ContextNoneDescriptionTest()
{
string xaml = "<Grid>\n\t<CheckBox x:Name=\"asdf\" Background=\"Aqua\" Content=\"{x:Static Cursors.Arrow}\" />\n</Grid>";
XamlContext context = CompletionDataHelper.ResolveContext(xaml, "", 2, 1);
Assert.AreEqual(XamlContextDescription.None, context.Description);
}
[Test]
public void ContextNoneDescriptionTest2()
{
string xaml = "<Grid>\n\t<CheckBox x:Name=\"asdf\" Background=\"Aqua\" Content=\"{x:Static Cursors.Arrow}\" />\n</Grid>";
XamlContext context = CompletionDataHelper.ResolveContext(xaml, "", 1, 7);
Assert.AreEqual(XamlContextDescription.None, context.Description);
}
[Test]
public void ContextNoneDescriptionTest3()
{
string xaml = "<Grid>\n\t<CheckBox x:Name=\"asdf\" Background=\"Aqua\" Content=\"{x:Static Cursors.Arrow}\" />\n</Grid>";
XamlContext context = CompletionDataHelper.ResolveContext(xaml, "", 3, 1);
Assert.AreEqual(XamlContextDescription.None, context.Description);
}
[Test]
public void ContextAtTagDescriptionTest()
{
string xaml = "<Grid>\n\t<CheckBox x:Name=\"asdf\" Background=\"Aqua\" Content=\"{x:Static Cursors.Arrow}\" />\n</Grid>";
XamlContext context = CompletionDataHelper.ResolveContext(xaml, "", 1, 2);
Assert.AreEqual(XamlContextDescription.AtTag, context.Description);
}
[Test]
public void ContextAtTagDescriptionTest2()
{
string xaml = "<Grid>\n\t<CheckBox x:Name=\"asdf\" Background=\"Aqua\" Content=\"{x:Static Cursors.Arrow}\" />\n</Grid>";
XamlContext context = CompletionDataHelper.ResolveContext(xaml, "", 2, 11);
Assert.AreEqual(XamlContextDescription.AtTag, context.Description);
}
[Test]
public void ContextInTagDescriptionTest()
{
string xaml = "<Grid>\n\t<CheckBox x:Name=\"asdf\" Background=\"Aqua\" Content=\"{x:Static Cursors.Arrow}\" />\n</Grid>";
XamlContext context = CompletionDataHelper.ResolveContext(xaml, "", 2, 26);
Assert.AreEqual(XamlContextDescription.InTag, context.Description);
}
}
}

3
src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/XamlBinding.Tests.csproj

@ -53,8 +53,10 @@ @@ -53,8 +53,10 @@
<Compile Include="..\..\..\..\Main\GlobalAssemblyInfo.cs">
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="ExtensionsTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="MarkupExtensionTests.cs" />
<Compile Include="ResolveContextTests.cs" />
<Compile Include="UtilsTests.cs" />
<Compile Include="XamlExpressionFinderTests.cs" />
<Compile Include="XmlTests.cs" />
@ -63,6 +65,7 @@ @@ -63,6 +65,7 @@
<ProjectReference Include="..\..\..\..\Main\ICSharpCode.SharpDevelop.Dom\Project\ICSharpCode.SharpDevelop.Dom.csproj">
<Project>{924EE450-603D-49C1-A8E5-4AFAA31CE6F3}</Project>
<Name>ICSharpCode.SharpDevelop.Dom</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\..\DisplayBindings\XmlEditor\Project\XmlEditor.csproj">
<Project>{DCA2703D-250A-463E-A68A-07ED105AE6BD}</Project>

189
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizer.cs

@ -6,8 +6,11 @@ @@ -6,8 +6,11 @@
// </file>
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.SharpDevelop;
@ -15,24 +18,135 @@ using ICSharpCode.SharpDevelop.Dom; @@ -15,24 +18,135 @@ using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.XmlEditor;
using System.Diagnostics;
using System.Windows.Threading;
namespace ICSharpCode.XamlBinding
{
using Tasks = System.Threading.Tasks;
public class XamlColorizer : DocumentColorizingTransformer
{
static readonly XamlColorizerSettings defaultSettings = new XamlColorizerSettings();
public struct Highlight {
public IMember Member { get; set; }
public HighlightingInfo Info { get; set; }
}
public sealed class HighlightTask {
// input
public string FileContent { get; private set; }
public string FileName { get; private set; }
public string LineText { get; private set; }
public int LineNumber { get; private set; }
public int Offset { get; private set; }
TextView textView;
public HighlightTask(string fileContent, string fileName, DocumentLine line, TextView textView)
{
this.FileContent = fileContent;
this.FileName = fileName;
this.LineText = line.Text;
this.LineNumber = line.LineNumber;
this.Offset = line.Offset;
this.task = new System.Threading.Tasks.Task(Process);
this.textView = textView;
}
IList<Highlight> results;
// output
public IList<Highlight> GetResults()
{
return results;
}
public bool IsStillValid(DocumentLine line)
{
return this.Offset == line.Offset && this.LineText == line.Text;
}
Tasks.Task task;
public void Start()
{
task.Start();
}
public void Cancel()
{
if (task != null)
task.Cancel();
}
public bool IsCompleted {
get {
return task.IsCompleted;
}
}
void Process()
{
List<Highlight> results = new List<Highlight>();
foreach (HighlightingInfo info in GetInfo()) {
IMember member = null;
if (!info.Token.StartsWith("xmlns")) {
MemberResolveResult rr = new XamlResolver().Resolve(info.GetExpressionResult(), info.Context.ParseInformation, FileContent) as MemberResolveResult;
member = (rr != null) ? rr.ResolvedMember : null;
}
results.Add(new Highlight() { Member = member, Info = info });
}
this.results = results;
WorkbenchSingleton.SafeThreadAsyncCall(InvokeRedraw);
}
void InvokeRedraw()
{
textView.Redraw(this.Offset, this.LineText.Length, DispatcherPriority.Background);
}
IEnumerable<HighlightingInfo> GetInfo()
{
int index = -1;
int ltCharIndex = -1;
XamlContext context = null;
List<HighlightingInfo> infos = new List<HighlightingInfo>();
do {
index = LineText.IndexOf('=', index + 1);
if (index > -1) {
context = CompletionDataHelper.ResolveContext(FileContent, FileName, LineNumber, index + 1);
if (!string.IsNullOrEmpty(context.AttributeName)) {
int startIndex = LineText.Substring(0, index).LastIndexOf(context.AttributeName);
infos.Add(new HighlightingInfo(context.AttributeName, startIndex, startIndex + context.AttributeName.Length, Offset, context));
}
}
} while (index > -1);
return infos;
}
}
XamlColorizerSettings settings = defaultSettings;
string fileContent;
string fileName;
ParseInformation parseInfo;
XamlResolver resolver = new XamlResolver();
Dictionary<int, HighlightTask> highlightCache = new Dictionary<int, HighlightTask>();
public IViewContent Content { get; set; }
public XamlColorizer(IViewContent content)
public AvalonEdit.Rendering.TextView TextView { get; set; }
public XamlColorizer(IViewContent content, TextView textView)
{
this.Content = content;
this.TextView = textView;
}
protected override void Colorize(ITextRunConstructionContext context)
@ -42,7 +156,6 @@ namespace ICSharpCode.XamlBinding @@ -42,7 +156,6 @@ namespace ICSharpCode.XamlBinding
if (document == null)
return;
this.parseInfo = ParserService.GetParseInformation(Content.PrimaryFileName);
this.fileContent = document.GetDocumentForFile(this.Content.PrimaryFile).CreateSnapshot().Text;
this.fileName = this.Content.PrimaryFileName;
@ -51,45 +164,37 @@ namespace ICSharpCode.XamlBinding @@ -51,45 +164,37 @@ namespace ICSharpCode.XamlBinding
protected override void ColorizeLine(DocumentLine line)
{
if (!line.IsDeleted) {
HighlightingInfo[] infos = GetInfoForLine(line);
foreach (HighlightingInfo info in infos) {
MemberResolveResult rr = resolver.Resolve(info.GetExpressionResult(), parseInfo, fileContent) as MemberResolveResult;
IMember member = (rr != null) ? rr.ResolvedMember : null;
if (member != null) {
if (member is IEvent)
ChangeLinePart(line.Offset + info.StartOffset, line.Offset + info.EndOffset, HighlightEvent);
else
ChangeLinePart(line.Offset + info.StartOffset, line.Offset + info.EndOffset, HighlightProperty);
} else {
if (info.Token.StartsWith("xmlns"))
ChangeLinePart(line.Offset + info.StartOffset, line.Offset + info.EndOffset, HighlightNamespaceDeclaration);
}
if (line.IsDeleted)
return;
if (!highlightCache.ContainsKey(line.LineNumber)) {
HighlightTask task = new HighlightTask(this.fileContent, this.fileName, line, this.TextView);
task.Start();
highlightCache.Add(line.LineNumber, task);
} else {
HighlightTask task = highlightCache[line.LineNumber];
if (task.IsCompleted && task.IsStillValid(line)) {
task.GetResults().ForEach(result => ColorizeMember(result.Info, line, result.Member));
} else {
task.Cancel();
task = new HighlightTask(this.fileContent, this.fileName, line, this.TextView);
task.Start();
highlightCache[line.LineNumber] = task;
}
}
}
HighlightingInfo[] GetInfoForLine(DocumentLine line)
void ColorizeMember(HighlightingInfo info, DocumentLine line, IMember member)
{
int index = -1;
int ltCharIndex = -1;
XamlContext context = null;
List<HighlightingInfo> infos = new List<HighlightingInfo>();
do {
index = line.Text.IndexOf('=', index + 1);
if (index > -1) {
context = CompletionDataHelper.ResolveContext(this.fileContent, this.fileName, line.LineNumber, index + 1);
if (!string.IsNullOrEmpty(context.AttributeName)) {
int startIndex = line.Text.Substring(0, index).LastIndexOf(context.AttributeName);
infos.Add(new HighlightingInfo(context.AttributeName, startIndex, startIndex + context.AttributeName.Length, line.Offset, context));
}
}
} while (index > -1);
return infos.ToArray();
if (member != null) {
if (member is IEvent)
ChangeLinePart(line.Offset + info.StartOffset, line.Offset + info.EndOffset, HighlightEvent);
else
ChangeLinePart(line.Offset + info.StartOffset, line.Offset + info.EndOffset, HighlightProperty);
} else {
if (info.Token.StartsWith("xmlns"))
ChangeLinePart(line.Offset + info.StartOffset, line.Offset + info.EndOffset, HighlightNamespaceDeclaration);
}
}
void HighlightProperty(VisualLineElement element)
@ -110,7 +215,7 @@ namespace ICSharpCode.XamlBinding @@ -110,7 +215,7 @@ namespace ICSharpCode.XamlBinding
element.TextRunProperties.SetBackgroundBrush(settings.NamespaceDeclarationBackgroundBrush);
}
struct HighlightingInfo
public struct HighlightingInfo
{
public static readonly HighlightingInfo Empty = new HighlightingInfo(string.Empty, 0, 0, 0, new XamlContext());
@ -154,4 +259,4 @@ namespace ICSharpCode.XamlBinding @@ -154,4 +259,4 @@ namespace ICSharpCode.XamlBinding
}
}
}
}
}

6
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizerServer.cs

@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.XmlEditor;
using System;
using System.IO;
using ICSharpCode.AvalonEdit.Rendering;
@ -32,9 +33,10 @@ namespace ICSharpCode.XamlBinding @@ -32,9 +33,10 @@ namespace ICSharpCode.XamlBinding
ITextEditorProvider textEditor = e.Content as ITextEditorProvider;
if (textEditor != null) {
TextView textView = textEditor.TextEditor.GetService(typeof(TextView)) as TextView;
if (textView != null)
textView.LineTransformers.Add(new XamlColorizer(e.Content));
textView.LineTransformers.Add(new XamlColorizer(e.Content, textView));
}
}
}
}
}

2
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlResolver.cs

@ -235,7 +235,7 @@ namespace ICSharpCode.XamlBinding @@ -235,7 +235,7 @@ namespace ICSharpCode.XamlBinding
{
if (propertyOrEvent == null)
return null;
if (propertyOrEvent is IEvent) {
if (propertyOrEvent is IEvent && callingClass != null) {
return new MethodGroupResolveResult(callingClass, null, callingClass.DefaultReturnType, expression);
}

Loading…
Cancel
Save