Browse Source

implemented partial XAML markup extension resolving

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4293 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Siegfried Pammer 16 years ago
parent
commit
cc3c85e651
  1. 22
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs
  2. 4
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionInfo.cs
  3. 18
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionParser.cs
  4. 2
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionToken.cs
  5. 8
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionTokenizer.cs
  6. 48
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/Utils.cs
  7. 2
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCompletionItemList.cs
  8. 63
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlResolver.cs

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

@ -53,6 +53,8 @@ namespace ICSharpCode.XamlBinding
int offsetFromValueStart = Utils.GetOffsetFromValueStart(text, offset); int offsetFromValueStart = Utils.GetOffsetFromValueStart(text, offset);
AttributeValue value = null; AttributeValue value = null;
value = MarkupExtensionParser.ParseValue(attributeValue);
XamlContextDescription description = XamlContextDescription.InTag; XamlContextDescription description = XamlContextDescription.InTag;
if (path == null || path.Elements.Count == 0) { if (path == null || path.Elements.Count == 0) {
@ -363,7 +365,7 @@ namespace ICSharpCode.XamlBinding
public static IEnumerable<IInsightItem> CreateMarkupExtensionInsight(XamlCompletionContext context, ParseInformation info, ITextEditor editor) public static IEnumerable<IInsightItem> CreateMarkupExtensionInsight(XamlCompletionContext context, ParseInformation info, ITextEditor editor)
{ {
var markup = GetInnermostMarkup(context.AttributeValue.ExtensionValue); var markup = Utils.GetInnermostMarkup(context.AttributeValue.ExtensionValue);
var trr = ResolveMarkupExtensionType(markup, context); var trr = ResolveMarkupExtensionType(markup, context);
if (trr != null) { if (trr != null) {
@ -384,7 +386,7 @@ namespace ICSharpCode.XamlBinding
var list = new XamlCompletionItemList(); var list = new XamlCompletionItemList();
var path = XmlParser.GetActiveElementStartPathAtIndex(editor.Document.Text, editor.Caret.Offset); var path = XmlParser.GetActiveElementStartPathAtIndex(editor.Document.Text, editor.Caret.Offset);
var markup = GetInnermostMarkup(context.AttributeValue.ExtensionValue); var markup = Utils.GetInnermostMarkup(context.AttributeValue.ExtensionValue);
var trr = ResolveMarkupExtensionType(markup, context); var trr = ResolveMarkupExtensionType(markup, context);
@ -594,22 +596,6 @@ namespace ICSharpCode.XamlBinding
return null; return null;
} }
public static MarkupExtensionInfo GetInnermostMarkup(MarkupExtensionInfo markup)
{
var last = markup.PositionalArguments.LastOrDefault();
if (markup.NamedArguments.Count > 0)
last = markup.NamedArguments.LastOrDefault().Value;
if (last != null) {
if (!last.IsString) {
return GetInnermostMarkup(last.ExtensionValue);
}
}
return markup;
}
public static TypeResolveResult ResolveMarkupExtensionType(MarkupExtensionInfo markup, XamlCompletionContext context) public static TypeResolveResult ResolveMarkupExtensionType(MarkupExtensionInfo markup, XamlCompletionContext context)
{ {
XamlResolver resolver = new XamlResolver(); XamlResolver resolver = new XamlResolver();

4
src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionInfo.cs

@ -21,6 +21,8 @@ namespace ICSharpCode.XamlBinding
public IList<AttributeValue> PositionalArguments { get; private set; } public IList<AttributeValue> PositionalArguments { get; private set; }
public IDictionary<string, AttributeValue> NamedArguments { get; private set; } public IDictionary<string, AttributeValue> NamedArguments { get; private set; }
public int StartOffset { get; set; }
public MarkupExtensionInfo() public MarkupExtensionInfo()
: this(string.Empty, new List<AttributeValue>(), new Dictionary<string, AttributeValue>(StringComparer.OrdinalIgnoreCase)) : this(string.Empty, new List<AttributeValue>(), new Dictionary<string, AttributeValue>(StringComparer.OrdinalIgnoreCase))
{ {
@ -39,6 +41,8 @@ namespace ICSharpCode.XamlBinding
string stringValue; string stringValue;
MarkupExtensionInfo extensionValue; MarkupExtensionInfo extensionValue;
public int StartOffset { get; set; }
public bool IsString { public bool IsString {
get { return stringValue != null; } get { return stringValue != null; }
} }

18
src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionParser.cs

@ -19,25 +19,28 @@ namespace ICSharpCode.XamlBinding
var tokenizer = new MarkupExtensionTokenizer(text); var tokenizer = new MarkupExtensionTokenizer(text);
string argumentName = null; string argumentName = null;
int namedArgsStart = 0;
var token = tokenizer.NextToken(); var token = tokenizer.NextToken();
while (token.Kind != MarkupExtensionTokenKind.EndOfFile) { while (token.Kind != MarkupExtensionTokenKind.EndOfFile) {
switch (token.Kind) { switch (token.Kind) {
case MarkupExtensionTokenKind.TypeName: case MarkupExtensionTokenKind.TypeName:
info.ExtensionType = token.Value; info.ExtensionType = token.Value;
info.StartOffset = token.StartOffset;
break; break;
case MarkupExtensionTokenKind.MemberName: case MarkupExtensionTokenKind.MemberName:
// if there is an open member without a value add the member name // if there is an open member without a value add the member name
if (argumentName != null) if (argumentName != null)
info.NamedArguments.Add(argumentName, new AttributeValue(string.Empty)); info.NamedArguments.Add(argumentName, new AttributeValue(string.Empty));
argumentName = token.Value; argumentName = token.Value;
namedArgsStart = token.StartOffset;
break; break;
case MarkupExtensionTokenKind.String: case MarkupExtensionTokenKind.String:
if (argumentName != null) { if (argumentName != null) {
info.NamedArguments.Add(argumentName, ParseValue(token.Value)); info.NamedArguments.Add(argumentName, ParseValue(token.Value, namedArgsStart));
argumentName = null; argumentName = null;
} else { } else {
info.PositionalArguments.Add(ParseValue(token.Value)); info.PositionalArguments.Add(ParseValue(token.Value, token.StartOffset));
} }
break; break;
} }
@ -51,14 +54,19 @@ namespace ICSharpCode.XamlBinding
} }
public static AttributeValue ParseValue(string text) public static AttributeValue ParseValue(string text)
{
return ParseValue(text, 0);
}
public static AttributeValue ParseValue(string text, int offset)
{ {
if (string.IsNullOrEmpty(text)) if (string.IsNullOrEmpty(text))
return new AttributeValue(string.Empty); return new AttributeValue(string.Empty) { StartOffset = offset };
if (text.StartsWith("{", StringComparison.OrdinalIgnoreCase)) if (text.StartsWith("{", StringComparison.OrdinalIgnoreCase))
return new AttributeValue(Parse(text)); return new AttributeValue(Parse(text)) { StartOffset = offset };
else else
return new AttributeValue(text); return new AttributeValue(text) { StartOffset = offset };
} }
} }
} }

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

@ -14,6 +14,8 @@ namespace ICSharpCode.XamlBinding
public MarkupExtensionTokenKind Kind { get; private set; } public MarkupExtensionTokenKind Kind { get; private set; }
public string Value { get; private set; } public string Value { get; private set; }
public int StartOffset { get; set; }
public MarkupExtensionToken(MarkupExtensionTokenKind kind, string value) public MarkupExtensionToken(MarkupExtensionTokenKind kind, string value)
{ {
this.Kind = kind; this.Kind = kind;

8
src/AddIns/BackendBindings/XamlBinding/XamlBinding/MarkupExtensionTokenizer.cs

@ -27,6 +27,8 @@ namespace ICSharpCode.XamlBinding
string text; string text;
int pos; int pos;
int startPos;
Queue<MarkupExtensionToken> tokens = new Queue<MarkupExtensionToken>(); Queue<MarkupExtensionToken> tokens = new Queue<MarkupExtensionToken>();
/// <summary> /// <summary>
@ -51,7 +53,7 @@ namespace ICSharpCode.XamlBinding
void AddToken(MarkupExtensionTokenKind kind, string val) void AddToken(MarkupExtensionTokenKind kind, string val)
{ {
tokens.Enqueue(new MarkupExtensionToken(kind, val)); tokens.Enqueue(new MarkupExtensionToken(kind, val) { StartOffset = startPos });
} }
void ParseBeginning() void ParseBeginning()
@ -75,16 +77,20 @@ namespace ICSharpCode.XamlBinding
case '}': case '}':
AddToken(MarkupExtensionTokenKind.CloseBrace, "}"); AddToken(MarkupExtensionTokenKind.CloseBrace, "}");
pos++; pos++;
startPos = pos;
break; break;
case '=': case '=':
AddToken(MarkupExtensionTokenKind.Equals, "="); AddToken(MarkupExtensionTokenKind.Equals, "=");
pos++; pos++;
startPos = pos;
break; break;
case ',': case ',':
AddToken(MarkupExtensionTokenKind.Comma, ","); AddToken(MarkupExtensionTokenKind.Comma, ",");
pos++; pos++;
startPos = pos;
break; break;
default: default:
startPos = pos;
MembernameOrString(); MembernameOrString();
break; break;
} }

48
src/AddIns/BackendBindings/XamlBinding/XamlBinding/Utils.cs

@ -206,5 +206,53 @@ namespace ICSharpCode.XamlBinding
return r; return r;
} }
public static MarkupExtensionInfo GetInnermostMarkup(MarkupExtensionInfo markup)
{
var last = markup.PositionalArguments.LastOrDefault();
if (markup.NamedArguments.Count > 0)
last = markup.NamedArguments.LastOrDefault().Value;
if (last != null) {
if (!last.IsString) {
return GetInnermostMarkup(last.ExtensionValue);
}
}
return markup;
}
/// <summary>
/// Gets the of a markup extension at the given position.
/// </summary>
/// <param name="info">The markup extension data to parse.</param>
/// <param name="offset">The offset to look at.</param>
/// <returns>
/// A string, if the at offset is the extension type. <br />
/// An AttributeValue, if at the offset is a positional argument. <br />
/// A KeyValuePair&lt;string, AttributeValue&gt;, if at the offset is a named argument.
/// </returns>
public static object GetMarkupDataAtPosition(MarkupExtensionInfo info, int offset)
{
object previous = info.ExtensionType;
Debug.Print("offset: " + offset);
foreach (var item in info.PositionalArguments) {
if (item.StartOffset > offset)
break;
previous = item.IsString ? item : GetMarkupDataAtPosition(item.ExtensionValue, offset - item.StartOffset);
}
foreach (var pair in info.NamedArguments) {
if (pair.Value.StartOffset > offset)
break;
previous = pair.Value.IsString ? pair.Value : GetMarkupDataAtPosition(pair.Value.ExtensionValue, offset - pair.Value.StartOffset);
}
return previous;
}
} }
} }

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

@ -51,7 +51,7 @@ namespace ICSharpCode.XamlBinding
AttributeValue value = MarkupExtensionParser.ParseValue(valuePart); AttributeValue value = MarkupExtensionParser.ParseValue(valuePart);
if (value != null && !value.IsString) { if (value != null && !value.IsString) {
var markup = CompletionDataHelper.GetInnermostMarkup(value.ExtensionValue); var markup = Utils.GetInnermostMarkup(value.ExtensionValue);
if (markup.NamedArguments.Count > 0 || markup.PositionalArguments.Count > 0) { if (markup.NamedArguments.Count > 0 || markup.PositionalArguments.Count > 0) {
int oldOffset = context.Editor.Caret.Offset; int oldOffset = context.Editor.Caret.Offset;
context.Editor.Caret.Offset = context.StartOffset; context.Editor.Caret.Offset = context.StartOffset;

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

@ -23,6 +23,7 @@ namespace ICSharpCode.XamlBinding
public class XamlResolver : IResolver public class XamlResolver : IResolver
{ {
IClass callingClass; IClass callingClass;
string fileContent;
string resolveExpression; string resolveExpression;
int caretLine, caretColumn; int caretLine, caretColumn;
XamlContext context; XamlContext context;
@ -32,27 +33,59 @@ namespace ICSharpCode.XamlBinding
this.resolveExpression = expressionResult.Expression; this.resolveExpression = expressionResult.Expression;
this.caretLine = expressionResult.Region.BeginLine; this.caretLine = expressionResult.Region.BeginLine;
this.caretColumn = expressionResult.Region.BeginColumn; this.caretColumn = expressionResult.Region.BeginColumn;
this.fileContent = fileContent;
this.callingClass = parseInfo.BestCompilationUnit.GetInnermostClass(caretLine, caretColumn); this.callingClass = parseInfo.BestCompilationUnit.GetInnermostClass(caretLine, caretColumn);
this.context = CompletionDataHelper.ResolveContext(fileContent, parseInfo.MostRecentCompilationUnit.FileName, caretLine, caretColumn); this.context = expressionResult.Context as XamlContext ?? CompletionDataHelper.ResolveContext(fileContent, parseInfo.MostRecentCompilationUnit.FileName, caretLine, caretColumn);
if (context == null)
return null; switch (this.context.Description) {
if (string.IsNullOrEmpty(context.AttributeName)) { case XamlContextDescription.AtTag:
return ResolveElementName(expressionResult.Expression); return ResolveElementName(resolveExpression);
} case XamlContextDescription.InTag:
else if (context.Description == XamlContextDescription.InAttributeValue) { return ResolveAttribute(resolveExpression);
MemberResolveResult mrr = ResolveAttribute(context.AttributeName); case XamlContextDescription.InAttributeValue:
if (mrr != null) { MemberResolveResult mrr = ResolveAttribute(context.AttributeName);
return ResolveAttributeValue(mrr.ResolvedMember, resolveExpression); if (mrr != null) {
} return ResolveAttributeValue(mrr.ResolvedMember, resolveExpression) ?? mrr;
} }
else { break;
// in attribute name case XamlContextDescription.InMarkupExtension:
return ResolveAttribute(resolveExpression); return ResolveMarkupExtension(resolveExpression);
} }
return null; return null;
} }
ResolveResult ResolveMarkupExtension(string expression)
{
if (context.AttributeValue.IsString)
return null;
object data = Utils.GetMarkupDataAtPosition(context.AttributeValue.ExtensionValue, context.ValueStartOffset);
// resolve markup extension type
if ((data as string) == expression) {
return ResolveElementName(expression + "Extension") ?? ResolveElementName(expression);
} else {
var value = data as AttributeValue;
if (value != null && value.IsString) {
return ResolveElementName(expression) ?? ResolveAttribute(expression);
}
if (data is KeyValuePair<string, AttributeValue>) {
var pair = (KeyValuePair<string, AttributeValue>)data;
var member = ResolveAttribute(pair.Key);
if (pair.Value.StartOffset + pair.Key.Length >= context.ValueStartOffset) {
return member;
} else {
if (pair.Value.IsString && member != null)
return ResolveAttributeValue(member.ResolvedMember, expression);
}
}
return null;
}
}
ResolveResult ResolveElementName(string exp) ResolveResult ResolveElementName(string exp)
{ {
string xmlNamespace; string xmlNamespace;

Loading…
Cancel
Save