Browse Source

XamlBinding:

- added PropertyPathTokenizer and PropertyPathParser
- added unit tests

* fixed an "off by one" error in TaskService
* corrected typo in MemberResolveResult documentation

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4600 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Siegfried Pammer 16 years ago
parent
commit
181f8cb775
  1. 267
      src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/ParserTests.cs
  2. 158
      src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/TokenizerTests.cs
  3. 2
      src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/XamlBinding.Tests.csproj
  4. 20
      src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/XmlTests.cs
  5. 175
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs
  6. 99
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/PropertyPathParser.cs
  7. 61
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/PropertyPathSegment.cs
  8. 85
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/PropertyPathTokenizer.cs
  9. 19
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/SegmentKind.cs
  10. 4
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.csproj
  11. 44
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCodeCompletionBinding.cs
  12. 4
      src/Main/Base/Project/Src/Services/Tasks/TaskService.cs
  13. 2
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs

267
src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/ParserTests.cs

@ -0,0 +1,267 @@ @@ -0,0 +1,267 @@
// <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 System.Diagnostics;
using System.Linq;
using NUnit.Framework;
namespace ICSharpCode.XamlBinding.Tests
{
[TestFixture]
public class ParserTests
{
[Test]
public void SimplePropertyTest()
{
string text = "Test";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.PropertyOrType, "Test")
);
}
[Test]
public void SimpleIndexerTest()
{
string text = "[key]";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.Indexer, "key")
);
}
[Test]
public void TwoPartsTest()
{
string text = "propertyName.propertyName2";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.PropertyOrType, "propertyName"),
new PropertyPathSegment(SegmentKind.PropertyOrType, "propertyName2")
);
}
[Test]
public void AttachedPropertyTest()
{
string text = "(ownerType.propertyName)";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.AttachedProperty, "ownerType.propertyName")
);
}
[Test]
public void SourceTraversalTest()
{
string text = "propertyName/propertyNameX";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.SourceTraversal, "propertyName/propertyNameX")
);
}
[Test]
public void MultipleIndexerTest()
{
string text = "[index1,index2]";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.Indexer, "index1,index2")
);
}
[Test]
public void MultipleIndexerTest4()
{
string text = "[ index1 , index2 ]";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.Indexer, "index1,index2")
);
}
[Test]
public void MultipleIndexerTest2()
{
string text = "propertyName[index1,index2]";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.PropertyOrType, "propertyName"),
new PropertyPathSegment(SegmentKind.Indexer, "index1,index2")
);
}
[Test]
public void MultipleIndexerTest3()
{
string text = "propertyName[index1, index2]";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.PropertyOrType, "propertyName"),
new PropertyPathSegment(SegmentKind.Indexer, "index1,index2")
);
}
[Test]
public void ComplexTest()
{
string text = "ColorGrid[20,30].SolidColorBrushResult";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.PropertyOrType, "ColorGrid"),
new PropertyPathSegment(SegmentKind.Indexer, "20,30"),
new PropertyPathSegment(SegmentKind.PropertyOrType, "SolidColorBrushResult")
);
}
[Test]
public void ComplexTest2()
{
string text = "(TextBlock.Background).(SolidColorBrush.Color)";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.AttachedProperty, "TextBlock.Background"),
new PropertyPathSegment(SegmentKind.AttachedProperty, "SolidColorBrush.Color")
);
}
[Test]
public void ComplexTest3()
{
string text = "(TextBlock.Background).(SolidColorBrush.Color).X";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.AttachedProperty, "TextBlock.Background"),
new PropertyPathSegment(SegmentKind.AttachedProperty, "SolidColorBrush.Color"),
new PropertyPathSegment(SegmentKind.PropertyOrType, "X")
);
}
[Test]
public void ComplexTest4()
{
string text = "(TextBlock.Background).(SolidColorBrush.Color).X/Y";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.AttachedProperty, "TextBlock.Background"),
new PropertyPathSegment(SegmentKind.AttachedProperty, "SolidColorBrush.Color"),
new PropertyPathSegment(SegmentKind.SourceTraversal, "X/Y")
);
}
[Test]
public void ComplexTest5()
{
string text = "propertyName.propertyName2[index].propertyName3";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.PropertyOrType, "propertyName"),
new PropertyPathSegment(SegmentKind.PropertyOrType, "propertyName2"),
new PropertyPathSegment(SegmentKind.Indexer, "index"),
new PropertyPathSegment(SegmentKind.PropertyOrType, "propertyName3")
);
}
[Test]
public void ControlChar1()
{
string text = "propertyName.propertyName2[index].";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.PropertyOrType, "propertyName"),
new PropertyPathSegment(SegmentKind.PropertyOrType, "propertyName2"),
new PropertyPathSegment(SegmentKind.Indexer, "index"),
new PropertyPathSegment(SegmentKind.ControlChar, ".")
);
}
[Test]
public void ControlChar2()
{
string text = "(";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.ControlChar, "(")
);
}
[Test]
public void ControlChar3()
{
string text = "test[";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.PropertyOrType, "test"),
new PropertyPathSegment(SegmentKind.ControlChar, "[")
);
}
[Test]
public void ControlChar4()
{
string text = "(testType.";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.AttachedProperty, "(testType"),
new PropertyPathSegment(SegmentKind.ControlChar, ".")
);
}
[Test]
public void ControlChar5()
{
string text = "(testType.prop).(someType.";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.AttachedProperty, "testType.prop"),
new PropertyPathSegment(SegmentKind.AttachedProperty, "(someType"),
new PropertyPathSegment(SegmentKind.ControlChar, ".")
);
}
[Test]
public void MixedTest1()
{
string text = "(testType.prop).(someType.as";
PropertyPathSegment[] result = PropertyPathParser.Parse(text).ToArray();
CompareResults(result,
new PropertyPathSegment(SegmentKind.AttachedProperty, "testType.prop"),
new PropertyPathSegment(SegmentKind.AttachedProperty, "(someType.as")
);
}
void CompareResults(PropertyPathSegment[] result, params PropertyPathSegment[] expected)
{
Assert.AreEqual(expected, result);
}
}
}

158
src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/TokenizerTests.cs

@ -0,0 +1,158 @@ @@ -0,0 +1,158 @@
// <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 System.Linq;
using NUnit.Framework;
namespace ICSharpCode.XamlBinding.Tests
{
[TestFixture]
public class TokenizerTests
{
[Test]
public void SimpleTest()
{
string input = "Test";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "Test");
}
[Test]
public void PropertyGroupTest()
{
string input = "Test.Count";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "Test", ".", "Count");
}
[Test]
public void PropertyGroupDotEndTest()
{
string input = "Test.";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "Test", ".");
}
[Test]
public void PropertyIndexerSimpleTest()
{
string input = "Test[1]";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "Test", "[", "1", "]");
}
[Test]
public void PropertyIndexerMultiTest()
{
string input = "Test[1,2]";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "Test", "[", "1", ",", "2", "]");
}
[Test]
public void PropertyAtIndexerTest()
{
string input = "Test[";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "Test", "[");
}
[Test]
public void PropertyAtCommaTest()
{
string input = "Test[1,";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "Test", "[", "1", ",");
}
[Test]
public void PropertyGroupAfterIndexTest()
{
string input = "Test[1].Property";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "Test", "[", "1", "]", ".", "Property");
}
[Test]
public void PropertyDotAfterIndexTest()
{
string input = "Test[1].";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "Test", "[", "1", "]", ".");
}
[Test]
public void PropertyIndexAtStartTest()
{
string input = "[1].";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "[", "1", "]", ".");
}
[Test]
public void PropertySourceTraversalTest()
{
string input = "propertyName/propertyNameX";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "propertyName", "/", "propertyNameX");
}
[Test]
public void WhitespaceTest()
{
string input = " propertyName / propertyNameX [ 1 , 2 ] .property";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "propertyName", "/", "propertyNameX", "[", "1", ",", "2", "]", ".", "property");
}
[Test]
public void AttachedPropertiesTest()
{
string input = "(typeName.propertyName).(otherType.otherProperty).property";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "(", "typeName", ".", "propertyName", ")", ".", "(", "otherType", ".", "otherProperty", ")", ".", "property");
}
[Test]
public void InvalidStringTest()
{
string input = "(typeName&.propert$$yName).(##otherType . otherProperty).property";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "(", "typeName", ".", "propert", "yName", ")", ".", "(", "otherType", ".", "otherProperty", ")", ".", "property");
}
[Test]
public void InCompletionSituationTest1()
{
string input = "(typeName.";
string[] result = PropertyPathTokenizer.Tokenize(input).ToArray();
CompareResults(result, "(", "typeName", ".");
}
void CompareResults(string[] result, params string[] expected)
{
Assert.AreEqual(expected, result);
}
}
}

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

@ -73,10 +73,12 @@ @@ -73,10 +73,12 @@
<Compile Include="DependencyPropertiesTests.cs" />
<Compile Include="ExtensionsTests.cs" />
<Compile Include="MockTextEditor.cs" />
<Compile Include="ParserTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="MarkupExtensionTests.cs" />
<Compile Include="ResolveContextTests.cs" />
<Compile Include="TextEditorBasedTests.cs" />
<Compile Include="TokenizerTests.cs" />
<Compile Include="UtilsTests.cs" />
<Compile Include="XamlExpressionFinderTests.cs" />
<Compile Include="XmlTests.cs" />

20
src/AddIns/BackendBindings/XamlBinding/XamlBinding.Tests/XmlTests.cs

@ -134,5 +134,25 @@ namespace ICSharpCode.XamlBinding.Tests @@ -134,5 +134,25 @@ namespace ICSharpCode.XamlBinding.Tests
Assert.AreEqual("val1", XmlParser.GetAttributeNameAtIndex(xaml, offset));
}
[Test]
[Ignore]
public void InAttributeValueTest1()
{
string xaml = "<Test val2='' val1=\"\" />";
int offset = "<Test val2='' val1=\"".Length;
Assert.AreEqual(true, XmlParser.IsInsideAttributeValue(xaml, offset));
}
[Test]
[Ignore]
public void InAttributeValueTest2()
{
string xaml = "<Test val2=\"\" val1='' />";
int offset = "<Test val2=\"\" val1='".Length;
Assert.AreEqual(true, XmlParser.IsInsideAttributeValue(xaml, offset));
}
}
}

175
src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs

@ -8,7 +8,6 @@ @@ -8,7 +8,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.SharpDevelop;
@ -340,6 +339,18 @@ namespace ICSharpCode.XamlBinding @@ -340,6 +339,18 @@ namespace ICSharpCode.XamlBinding
return result;
}
public static IEnumerable<ICompletionItem> GetAllTypes(XamlCompletionContext context)
{
var items = GetClassesFromContext(context);
foreach (var ns in items) {
foreach (var c in ns.Value) {
if (c.ClassType == ClassType.Class && !c.DerivesFrom("System.Attribute"))
yield return new XamlCodeCompletionItem(c, ns.Key);
}
}
}
public static IEnumerable<ICompletionItem> CreateListOfMarkupExtensions(XamlCompletionContext context)
{
@ -616,6 +627,16 @@ namespace ICSharpCode.XamlBinding @@ -616,6 +627,16 @@ namespace ICSharpCode.XamlBinding
return false;
}
public static bool EndsWithAny(this string thisValue, params char[] items)
{
foreach (char item in items) {
if (thisValue.EndsWith(item.ToString()))
return true;
}
return false;
}
static IReturnType GetType(XamlCompletionContext context, out bool isExplicit)
{
AttributeValue value = MarkupExtensionParser.ParseValue(LookForTargetTypeValue(context, out isExplicit, "Trigger", "Setter") ?? string.Empty);
@ -656,7 +677,8 @@ namespace ICSharpCode.XamlBinding @@ -656,7 +677,8 @@ namespace ICSharpCode.XamlBinding
bool isExplicit, showFull = false;
IReturnType typeName;
string valueBeforeCaret = (context.ValueStartOffset > 0) ? context.RawAttributeValue.Substring(0, context.ValueStartOffset + 1) : "";
string valueBeforeCaret = (context.ValueStartOffset > 0) ?
context.RawAttributeValue.Substring(0, context.ValueStartOffset + 1) : "";
switch (c.ClassType) {
case ClassType.Class:
@ -669,14 +691,14 @@ namespace ICSharpCode.XamlBinding @@ -669,14 +691,14 @@ namespace ICSharpCode.XamlBinding
yield return item;
break;
case "System.Windows.PropertyPath":
foreach (var item in CreatePropertyPathCompletion(context))
yield return item;
break;
case "System.Windows.DependencyProperty":
typeName = GetType(context, out isExplicit);
bool isReadOnly = context.ActiveElement.Name.EndsWith("Trigger");
Core.LoggingService.Debug("value: " + valueBeforeCaret);
if (!isExplicit && valueBeforeCaret.Contains("."))
showFull = true;
@ -688,8 +710,6 @@ namespace ICSharpCode.XamlBinding @@ -688,8 +710,6 @@ namespace ICSharpCode.XamlBinding
case "System.Windows.RoutedEvent":
typeName = GetType(context, out isExplicit);
Core.LoggingService.Debug("value: " + valueBeforeCaret);
if (!isExplicit && valueBeforeCaret.Contains("."))
showFull = true;
@ -743,6 +763,149 @@ namespace ICSharpCode.XamlBinding @@ -743,6 +763,149 @@ namespace ICSharpCode.XamlBinding
}
}
static IList<ICompletionItem> CreatePropertyPathCompletion(XamlCompletionContext context)
{
bool isExplicit;
IReturnType typeName = GetType(context, out isExplicit);
IList<ICompletionItem> list = new List<ICompletionItem>();
string value = context.ValueStartOffset > -1 ? context.RawAttributeValue.Substring(0, context.ValueStartOffset + 1) : "";
if (value.EndsWithAny(']', ')'))
return list;
var segments = PropertyPathParser.Parse(value).ToList();
int completionStart;
bool isAtDot = false;
IReturnType propertyPathType = ResolvePropertyPath(segments, context, typeName, out completionStart);
if (completionStart < segments.Count) {
PropertyPathSegment seg = segments[completionStart];
switch (seg.Kind) {
case SegmentKind.ControlChar:
if (seg.Content == ".") {
AddAttributes(propertyPathType, list, false);
isAtDot = true;
}
break;
case SegmentKind.AttachedProperty:
AddAttributes(seg.Resolve(context, propertyPathType), list, false);
isAtDot = seg.Content.Contains(".");
break;
case SegmentKind.PropertyOrType:
AddAttributes(propertyPathType, list, false);
isAtDot = true;
break;
}
} else if (typeName != null) {
AddAttributes(typeName, list, false);
}
if (!isAtDot) {
foreach (var item in GetAllTypes(context))
list.Add(item);
}
return list;
}
static IReturnType ResolvePropertyPath(IList<PropertyPathSegment> segments, XamlCompletionContext context, IReturnType parentType, out int lastIndex)
{
IReturnType type = parentType;
TypeResolveResult trr;
for (lastIndex = 0; lastIndex < segments.Count - 1; lastIndex++) {
PropertyPathSegment segment = segments[lastIndex];
switch (segment.Kind) {
case SegmentKind.AttachedProperty:
// do we need to take account of previous results?
type = segment.Resolve(context, null);
break;
case SegmentKind.ControlChar:
if (segment.Content == "[" || segment.Content == "(" || segment.Content == "/")
return null;
return type;
case SegmentKind.PropertyOrType:
type = segment.Resolve(context, type);
break;
case SegmentKind.Indexer:
if (type != null) {
IProperty prop = type.GetProperties().FirstOrDefault(p => p.IsIndexer);
if (prop != null) {
type = prop.ReturnType;
}
}
break;
case SegmentKind.SourceTraversal:
// ignore
return null;
}
}
return type;
}
static IReturnType Resolve(this PropertyPathSegment segment, XamlCompletionContext context, IReturnType previousType)
{
if (segment.Kind == SegmentKind.SourceTraversal)
return previousType;
if (segment.Kind == SegmentKind.ControlChar)
return previousType;
string content = segment.Content;
if (segment.Kind == SegmentKind.AttachedProperty && content.StartsWith("(")) {
content = content.TrimStart('(');
if (content.Contains("."))
content = content.Remove(content.IndexOf('.'));
}
XamlContextDescription tmp = context.Description;
context.Description = XamlContextDescription.InTag;
ResolveResult rr = XamlResolver.Resolve(content, context);
IReturnType type = null;
if (rr is TypeResolveResult)
type = (rr as TypeResolveResult).ResolvedType;
if (previousType != null) {
IMember member = previousType.GetMemberByName(content);
if (member != null)
type = member.ReturnType;
} else {
if (rr is MemberResolveResult) {
MemberResolveResult mrr = rr as MemberResolveResult;
if (mrr.ResolvedMember != null)
type = mrr.ResolvedMember.ReturnType;
}
if (rr is TypeResolveResult)
type = (rr as TypeResolveResult).ResolvedType;
}
context.Description = tmp;
return type;
}
static IMember GetMemberByName(this IReturnType type, string name)
{
if (type == null)
throw new ArgumentNullException("type");
foreach (IMember member in type.GetFields()) {
if (member.Name == name)
return member;
}
foreach (IMember member in type.GetProperties()) {
if (member.Name == name)
return member;
}
return null;
}
static IEnumerable<ICompletionItem> CreateEventCompletion(XamlCompletionContext context, IClass c)
{
IMethod invoker = c.Methods.Where(method => method.Name == "Invoke").FirstOrDefault();

99
src/AddIns/BackendBindings/XamlBinding/XamlBinding/PropertyPathParser.cs

@ -0,0 +1,99 @@ @@ -0,0 +1,99 @@
// <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 System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ICSharpCode.XamlBinding
{
public class PropertyPathParser
{
public static IEnumerable<PropertyPathSegment> Parse(string text)
{
string token = "";
bool inBrace = false;
bool inIndexer = false;
bool isSourceTraversal = false;
string lastToken = "";
foreach (string v in PropertyPathTokenizer.Tokenize(text)) {
lastToken = v;
if (v == "(") {
inBrace = true;
continue;
}
if (v == "[") {
inIndexer = true;
if (!inBrace && !string.IsNullOrEmpty(token)) {
yield return new PropertyPathSegment(SegmentKind.PropertyOrType, token);
token = "";
}
continue;
}
if (v == ")") {
inBrace = false;
if (!string.IsNullOrEmpty(token))
yield return new PropertyPathSegment(SegmentKind.AttachedProperty, token);
token = "";
continue;
}
if (v == "]") {
inIndexer = false;
if (!inBrace && !string.IsNullOrEmpty(token)) {
yield return new PropertyPathSegment(SegmentKind.Indexer, token);
token = "";
}
continue;
}
if (inBrace)
token += v;
else if (inIndexer)
token += v;
else if (v == ".") {
if (!string.IsNullOrEmpty(token))
yield return new PropertyPathSegment(isSourceTraversal ? SegmentKind.SourceTraversal : SegmentKind.PropertyOrType, token);
token = "";
isSourceTraversal = false;
} else if (v == "/") {
token += v;
isSourceTraversal = true;
} else {
token += v;
}
Debug.Print("inBrace: " + inBrace + " token: '" + token + "'");
}
Debug.Print("inBrace: " + inBrace + " token: '" + token + "' lastToken: '" + lastToken + "'");
if (inBrace && !string.IsNullOrEmpty(token)) {
yield return new PropertyPathSegment(SegmentKind.AttachedProperty, "(" + token.Trim('.', '/'));
}
if (!string.IsNullOrEmpty(lastToken)) {
char c = lastToken.First();
if (c == ')' || c == ']')
yield break;
if (PropertyPathTokenizer.ControlChars.Contains(c))
yield return new PropertyPathSegment(SegmentKind.ControlChar, c.ToString());
else if (!inBrace && !string.IsNullOrEmpty(token))
yield return new PropertyPathSegment(isSourceTraversal ? SegmentKind.SourceTraversal : SegmentKind.PropertyOrType, token);
}
}
}
}

61
src/AddIns/BackendBindings/XamlBinding/XamlBinding/PropertyPathSegment.cs

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
// <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 System.Linq;
using System.Collections.Generic;
namespace ICSharpCode.XamlBinding
{
public struct PropertyPathSegment : IEquatable<PropertyPathSegment>
{
public SegmentKind Kind;
public string Content;
public PropertyPathSegment(SegmentKind kind, string content)
{
this.Kind = kind;
this.Content = content;
}
public override string ToString()
{
return "[PropertyPathSegment Kind: " + Kind + ", Content: " + Content + " ]";
}
public override bool Equals(object obj)
{
if (obj is PropertyPathSegment)
return Equals((PropertyPathSegment)obj);
return false;
}
public bool Equals(PropertyPathSegment other)
{
if (other == null)
return false;
return other.Content == this.Content &&
other.Kind == this.Kind;
}
public int GetHashCode(PropertyPathSegment obj)
{
return obj.Content.GetHashCode() ^ obj.Kind.GetHashCode();
}
public static bool operator ==(PropertyPathSegment lhs, PropertyPathSegment rhs)
{
return Equals(lhs, rhs);
}
public static bool operator !=(PropertyPathSegment lhs, PropertyPathSegment rhs)
{
return !(lhs == rhs);
}
}
}

85
src/AddIns/BackendBindings/XamlBinding/XamlBinding/PropertyPathTokenizer.cs

@ -0,0 +1,85 @@ @@ -0,0 +1,85 @@
// <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 System.Linq;
using System.Collections.Generic;
namespace ICSharpCode.XamlBinding
{
public class PropertyPathTokenizer
{
string value;
int offset;
public static readonly char[] ControlChars = new char[] { '.', ',', '(', ')', '[', ']', '/' };
PropertyPathTokenizer(string value)
{
this.value = value;
this.offset = 0;
}
bool NextToken(out string token)
{
token = "";
if (MoveToNext()) {
switch (value[offset]) {
case '.':
case '(':
case ')':
case '[':
case ']':
case ',':
case '/':
token = value[offset].ToString();
offset++;
return true;
default:
string text = "";
while (!AtEnd() && char.IsLetterOrDigit(value[offset])) {
text += value[offset];
offset++;
}
token = text;
return true;
}
}
return false;
}
bool MoveToNext()
{
// skip all invalid chars
while (!AtEnd() && !char.IsLetterOrDigit(value[offset]) && !ControlChars.Contains(value[offset]))
offset++;
return !AtEnd();
}
bool AtEnd()
{
return offset >= value.Length;
}
public static IEnumerable<string> Tokenize(string value)
{
if (value == null)
throw new ArgumentNullException("value");
PropertyPathTokenizer tokenizer = new PropertyPathTokenizer(value);
string token;
while (tokenizer.NextToken(out token))
yield return token;
}
}
}

19
src/AddIns/BackendBindings/XamlBinding/XamlBinding/SegmentKind.cs

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
// <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;
namespace ICSharpCode.XamlBinding
{
public enum SegmentKind {
ControlChar,
PropertyOrType,
AttachedProperty,
Indexer,
SourceTraversal
}
}

4
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.csproj

@ -113,7 +113,11 @@ @@ -113,7 +113,11 @@
</Compile>
<Compile Include="PowerToys\Dialogs\UndoStep.cs" />
<Compile Include="PowerToys\XamlMenuCommand.cs" />
<Compile Include="PropertyPathParser.cs" />
<Compile Include="PropertyPathSegment.cs" />
<Compile Include="PropertyPathTokenizer.cs" />
<Compile Include="QualifiedNameWithLocation.cs" />
<Compile Include="SegmentKind.cs" />
<Compile Include="Utils.cs">
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />

44
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCodeCompletionBinding.cs

@ -90,9 +90,35 @@ namespace ICSharpCode.XamlBinding @@ -90,9 +90,35 @@ namespace ICSharpCode.XamlBinding
list = CompletionDataHelper.CreateListForContext(context);
editor.ShowCompletionWindow(list);
return CodeCompletionKeyPressResult.Completed;
} else if (context.Description == XamlContextDescription.InMarkupExtension) {
if (DoMarkupExtensionCompletion(context))
return CodeCompletionKeyPressResult.Completed;
} else {
if (context.Description == XamlContextDescription.InMarkupExtension) {
if (DoMarkupExtensionCompletion(context))
return CodeCompletionKeyPressResult.Completed;
} else if (context.Description == XamlContextDescription.InAttributeValue) {
if (editor.SelectionLength != 0)
editor.Document.Remove(editor.SelectionStart, editor.SelectionLength);
editor.Document.Insert(editor.Caret.Offset, ".");
this.CtrlSpace(editor);
return CodeCompletionKeyPressResult.EatKey;
}
}
break;
case '(':
case '[':
if (context.Description == XamlContextDescription.InAttributeValue) {
if (editor.SelectionLength != 0)
editor.Document.Remove(editor.SelectionStart, editor.SelectionLength);
if (ch == '(')
editor.Document.Insert(editor.Caret.Offset, "()");
if (ch == '[')
editor.Document.Insert(editor.Caret.Offset, "[]");
editor.Caret.Offset--;
this.CtrlSpace(editor);
return CodeCompletionKeyPressResult.EatKey;
}
break;
case ':':
@ -175,6 +201,7 @@ namespace ICSharpCode.XamlBinding @@ -175,6 +201,7 @@ namespace ICSharpCode.XamlBinding
if (context.AttributeName != null) {
if (!DoMarkupExtensionCompletion(context)) {
var completionList = new XamlCompletionItemList();
completionList.PreselectionLength = editor.GetWordBeforeCaretExtended().Length;
if ((context.ActiveElement.Name == "Setter" || context.ActiveElement.Name == "EventSetter") && context.AttributeName.Name == "Value")
DoSetterAndEventSetterCompletion(context, completionList);
@ -185,11 +212,18 @@ namespace ICSharpCode.XamlBinding @@ -185,11 +212,18 @@ namespace ICSharpCode.XamlBinding
if (mrr != null && mrr.ResolvedType != null) {
completionList.Items.AddRange(CompletionDataHelper.MemberCompletion(context, mrr.ResolvedType, string.Empty));
editor.ShowInsightWindow(CompletionDataHelper.MemberInsight(mrr));
if (mrr.ResolvedType.FullyQualifiedName == "System.Windows.PropertyPath") {
string start = editor.GetWordBeforeCaretExtended();
int index = start.LastIndexOfAny(PropertyPathTokenizer.ControlChars);
if (index + 1 < start.Length)
start = start.Substring(index + 1);
else
start = "";
completionList.PreselectionLength = start.Length;
}
}
}
completionList.PreselectionLength = editor.GetWordBeforeCaretExtended().Length;
completionList.SortItems();
if (context.AttributeName.Prefix.Equals("xmlns", StringComparison.OrdinalIgnoreCase) ||

4
src/Main/Base/Project/Src/Services/Tasks/TaskService.cs

@ -173,8 +173,8 @@ namespace ICSharpCode.SharpDevelop @@ -173,8 +173,8 @@ namespace ICSharpCode.SharpDevelop
foreach (TagComment tag in tagComments) {
newTasks.Add(new Task(fileName,
tag.Key + tag.CommentString,
tag.Region.BeginColumn - 1,
tag.Region.BeginLine - 1,
tag.Region.BeginColumn,
tag.Region.BeginLine,
TaskType.Comment));
}
List<Task> oldTasks = new List<Task>();

2
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs

@ -487,7 +487,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -487,7 +487,7 @@ namespace ICSharpCode.SharpDevelop.Dom
#region MemberResolveResult
/// <summary>
/// The TypeResolveResult is used when an expression was a member
/// The MemberResolveResult is used when an expression was a member
/// (field, property, event or method call).
/// </summary>
/// <example>

Loading…
Cancel
Save