/// <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<string, AttributeValue>, if at the offset is a named argument. /// </returns> /// <remarks>offset != Caret.Offset, but offset == ValueStartOffset</remarks> public static object GetMarkupDataAtPosition(MarkupExtensionInfo info, int offset) { object previous = info.ExtensionType; int endOffset = info.StartOffset + info.ExtensionType.Length; foreach (var item in info.PositionalArguments) { if (item.StartOffset <= offset && offset <= item.EndOffset) { previous = item.IsString ? item : GetMarkupDataAtPosition(item.ExtensionValue, offset); } endOffset = item.EndOffset; } foreach (var pair in info.NamedArguments) { if (pair.Value.StartOffset <= offset && offset <= pair.Value.EndOffset) { previous = pair.Value.IsString ? pair : GetMarkupDataAtPosition(pair.Value.ExtensionValue, offset); } else if (endOffset <= offset && offset <= pair.Value.StartOffset) { previous = pair; } endOffset = pair.Value.EndOffset; } return(previous); }
string GetTypeNameFromTypeExtension(MarkupExtensionInfo info, XamlContext context) { IType type = ResolveExpression(info.ExtensionType, context).Type; if (type.Kind == TypeKind.Unknown) { type = ResolveExpression(info.ExtensionType + "Extension", context).Type; } if (type.FullName != "System.Windows.Markup.TypeExtension") { return(string.Empty); } var item = info.PositionalArguments.FirstOrDefault(); if (item != null && item.IsString) { return(item.StringValue); } if (info.NamedArguments.TryGetValue("typename", out item)) { if (item.IsString) { return(item.StringValue); } } return(string.Empty); }
/// <remarks>offset != Caret.Offset, but offset == ValueStartOffset</remarks> public static MarkupExtensionInfo GetMarkupExtensionAtPosition(MarkupExtensionInfo info, int offset) { MarkupExtensionInfo tmp = info; foreach (var item in info.PositionalArguments) { int endOffset = item.EndOffset; if (!item.IsClosed) { endOffset++; } if (item.StartOffset < offset && offset < endOffset) { tmp = item.IsString ? tmp : GetMarkupExtensionAtPosition(item.ExtensionValue, offset); } } foreach (var pair in info.NamedArguments) { int endOffset = pair.Value.EndOffset; if (!pair.Value.IsClosed) { endOffset++; } if (pair.Value.StartOffset < offset && offset < endOffset) { tmp = pair.Value.IsString ? tmp : GetMarkupExtensionAtPosition(pair.Value.ExtensionValue, offset); } } return(tmp); }
static void TryAddNamedArgument(this MarkupExtensionInfo info, string name, AttributeValue value) { if (!info.NamedArguments.ContainsKey(name)) { info.NamedArguments.Add(name, value); } }
public AttributeValue(MarkupExtensionInfo value) { if (value == null) { throw new ArgumentNullException("value"); } this.extensionValue = value; }
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 { MarkupExtensionInfo info = Utils.GetMarkupExtensionAtPosition(context.AttributeValue.ExtensionValue, context.ValueStartOffset); TypeResolveResult extensionType = (ResolveElementName(info.ExtensionType + "Extension") ?? ResolveElementName(info.ExtensionType)) as TypeResolveResult; if (extensionType != null && extensionType.ResolvedType != null) { var value = data as AttributeValue; switch (extensionType.ResolvedType.FullyQualifiedName) { case "System.Windows.Markup.StaticExtension": case "System.Windows.Markup.TypeExtension": if (value != null && value.IsString) { return(ResolveElementName(expression) ?? ResolveAttribute(expression)); } goto default; // "fall through" default: if (data is KeyValuePair <string, AttributeValue> ) { var pair = (KeyValuePair <string, AttributeValue>)data; var member = ResolveNamedAttribute(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) ?? ResolveElementName(expression)); } } } break; } } return(null); } }
MemberResolveResult ResolveNamedAttribute(string expression) { MarkupExtensionInfo info = Utils.GetMarkupExtensionAtPosition(context.AttributeValue.ExtensionValue, context.ValueStartOffset); TypeResolveResult extensionType = (ResolveElementName(info.ExtensionType + "Extension") ?? ResolveElementName(info.ExtensionType)) as TypeResolveResult; if (extensionType != null && extensionType.ResolvedType != null) { return(ResolvePropertyName(extensionType.ResolvedType, expression, false)); } return(null); }
public ResolveResult ResolveAttributeValue(string expression, XamlContext context) { if (!context.InAttributeValueOrMarkupExtension) { return(ErrorResolveResult.UnknownError); } if (context.AttributeValue.IsString) { return(ResolveExpression(expression, context)); } MarkupExtensionInfo info = Utils.GetMarkupExtensionAtPosition(context.AttributeValue.ExtensionValue, context.ValueStartOffset); object data = Utils.GetMarkupDataAtPosition(info, context.ValueStartOffset); IType extensionType = ResolveExpression(info.ExtensionType, context).Type; if (extensionType.Kind == TypeKind.Unknown) { extensionType = ResolveExpression(info.ExtensionType + "Extension", context).Type; } if (data is KeyValuePair <string, AttributeValue> ) { var kv = (KeyValuePair <string, AttributeValue>)data; if (kv.Value.StartOffset >= context.ValueStartOffset) { IProperty member = extensionType.GetProperties(p => p.Name == expression).FirstOrDefault(); if (member != null) { return(new MemberResolveResult(new TypeResolveResult(extensionType), member)); } return(new UnknownMemberResolveResult(extensionType, expression, EmptyList <IType> .Instance)); } else { } } return(ResolveExpression(expression, context)); }
/// <remarks>returns true if elements from named args completion should be added afterwards.</remarks> bool DoPositionalArgsCompletion(XamlCompletionItemList list, XamlCompletionContext context, MarkupExtensionInfo markup, IType type) { switch (type.FullName) { case "System.Windows.Markup.ArrayExtension": case "System.Windows.Markup.NullExtension": // x:Null/x:Array does not need completion, ignore it break; case "System.Windows.Markup.StaticExtension": if (context.AttributeValue.ExtensionValue.PositionalArguments.Count <= 1) { return(DoStaticExtensionCompletion(list, context)); } break; case "System.Windows.Markup.TypeExtension": if (context.AttributeValue.ExtensionValue.PositionalArguments.Count <= 1) { list.Items.AddRange(GetClassesFromContext(context).FlattenToList()); AttributeValue selItem = Utils.GetMarkupExtensionAtPosition(context.AttributeValue.ExtensionValue, context.ValueStartOffset) .PositionalArguments.LastOrDefault(); string word = context.Editor.GetWordBeforeCaret().TrimEnd(); if (selItem != null && selItem.IsString && word == selItem.StringValue) { list.PreselectionLength = selItem.StringValue.Length; } } break; default: var ctors = type.GetMethods(m => m.IsPublic && m.IsConstructor && m.Parameters.Count >= markup.PositionalArguments.Count + 1); if (context.Forced) { return(true); } if (ctors.Any() || markup.PositionalArguments.Count == 0) { return(false); } break; } return(true); }
void DoNamedArgsCompletion(XamlCompletionItemList list, XamlCompletionContext context, IType type, MarkupExtensionInfo markup) { if (markup.NamedArguments.Count > 0 && !context.Editor.GetWordBeforeCaret().StartsWith(",", StringComparison.OrdinalIgnoreCase)) { int lastStart = markup.NamedArguments.Max(i => i.Value.StartOffset); var item = markup.NamedArguments.First(p => p.Value.StartOffset == lastStart); if (context.RawAttributeValue.EndsWith("=", StringComparison.OrdinalIgnoreCase) || (item.Value.IsString && item.Value.StringValue.EndsWith(context.Editor.GetWordBeforeCaretExtended(), StringComparison.Ordinal))) { var resolver = new XamlResolver(compilation); MemberResolveResult mrr = resolver.ResolveAttributeValue(item.Key, context) as MemberResolveResult; if (mrr != null && mrr.Member != null && mrr.Member.ReturnType != null) { IType memberType = mrr.Member.ReturnType; list.Items.AddRange(MemberCompletion(context, memberType, string.Empty)); } return; } } list.Items.AddRange(type.GetProperties().Where(p => p.CanSet && p.IsPublic).Select(p => new XamlCompletionItem(p.Name + "=", p))); }
static MarkupExtensionInfo Parse(string text, int offset) { var info = new MarkupExtensionInfo(); string argumentName = null; MarkupExtensionTokenizer tokenizer = new MarkupExtensionTokenizer(text); MarkupExtensionToken token = null; try { token = tokenizer.NextToken(); while (token.Kind != MarkupExtensionTokenKind.EndOfFile) { switch (token.Kind) { case MarkupExtensionTokenKind.OpenBrace: info.StartOffset = token.StartOffset + offset; break; case MarkupExtensionTokenKind.CloseBrace: info.EndOffset = token.EndOffset + offset; break; case MarkupExtensionTokenKind.TypeName: info.ExtensionType = token.Value; break; case MarkupExtensionTokenKind.MemberName: // if there is an open member without a value add the member name if (argumentName != null) { info.TryAddNamedArgument(argumentName, ParseValue("", token.EndOffset + offset)); } argumentName = token.Value; break; case MarkupExtensionTokenKind.String: if (argumentName != null) { info.TryAddNamedArgument(argumentName, ParseValue(token.Value, token.StartOffset + offset)); argumentName = null; } else { info.PositionalArguments.Add(ParseValue(token.Value, token.StartOffset + offset)); } break; } token = tokenizer.NextToken(); } } catch (MarkupExtensionParseException) { // ignore parser errors } finally { if (token != null && argumentName != null) { info.TryAddNamedArgument(argumentName, ParseValue(token.Value, token.StartOffset + offset)); } } return(info); }