void DoSetterAndEventSetterCompletion(XamlCompletionContext context, XamlCompletionItemList completionList) { bool isExplicit; string element = context.ParentElement.Name.EndsWith("Trigger", StringComparison.Ordinal) ? "Trigger" : context.ParentElement.Name; AttributeValue value = MarkupExtensionParser.ParseValue(Utils.LookForTargetTypeValue(context, out isExplicit, element) ?? string.Empty); string typeNameString; var rr = resolver.ResolveAttributeValue(context, value, out typeNameString); IType typeName = rr.Type; MemberResolveResult mrr; switch (context.Attribute.Name) { case "Value": AttributeValue propType = MarkupExtensionParser.ParseValue(context.ActiveElement.GetAttributeValue("Property") ?? ""); if (!propType.IsString) { break; } context.Description = XamlContextDescription.AtTag; string name = propType.StringValue; if (!name.Contains(".")) { name = typeNameString + "." + name; } mrr = resolver.ResolveExpression(name, context) as MemberResolveResult; if (mrr == null || mrr.Member == null) { break; } completionList.Items.AddRange( generator.MemberCompletion(context, mrr.Member.ReturnType, string.Empty) ); break; case "Property": completionList.Items.AddRange( typeName.GetProperties() .Where(p => p.IsPublic && p.CanSet) .Select(prop => new XamlCompletionItem(prop)) ); break; case "Event": completionList.Items.AddRange( typeName.GetEvents() .Where(e => e.IsPublic) .Select(evt => new XamlCompletionItem(evt)) ); break; case "Handler": var loc3 = context.Editor.Document.GetLocation(XmlParser.GetActiveElementStartIndex(context.Editor.Document.Text, context.Editor.Caret.Offset)); AttributeValue evtType = MarkupExtensionParser.ParseValue(context.ActiveElement.GetAttributeValue("Event") ?? ""); if (!evtType.IsString) { break; } string evtName = evtType.StringValue; if (!evtName.Contains(".")) { evtName = typeNameString + "." + evtName; } mrr = resolver.ResolveExpression(evtName, context) as MemberResolveResult; if (mrr == null) { break; } var member = mrr.Member as IEvent; if (member == null) { break; } completionList.Items.AddRange(generator.FindMatchingEventHandlers(context, member, typeName.Name)); break; } }
public override void Complete(CompletionContext context, ICompletionItem item) { using (context.Editor.Document.OpenUndoGroup()) { base.Complete(context, item); XamlCompletionContext xamlContext = CompletionDataHelper.ResolveCompletionContext(context.Editor, context.CompletionChar); if (xamlContext.Description == XamlContextDescription.None && (context.StartOffset <= 0 || context.Editor.Document.GetCharAt(context.StartOffset - 1) != '<')) { context.Editor.Document.Insert(context.StartOffset, "<"); context.EndOffset++; } if (item is XamlCodeCompletionItem) { XamlCodeCompletionItem cItem = item as XamlCodeCompletionItem; if (cItem.Entity is IProperty || cItem.Entity is IEvent) { if (xamlContext.Description == XamlContextDescription.InTag) { context.Editor.Document.Insert(context.EndOffset, "=\"\""); context.CompletionCharHandled = context.CompletionChar == '='; context.Editor.Caret.Offset--; new XamlCodeCompletionBinding().CtrlSpace(context.Editor); } else if (xamlContext.Description == XamlContextDescription.InMarkupExtension && !string.IsNullOrEmpty(xamlContext.RawAttributeValue)) { string valuePart = xamlContext.RawAttributeValue.Substring(0, xamlContext.ValueStartOffset); AttributeValue value = MarkupExtensionParser.ParseValue(valuePart); if (value != null && !value.IsString) { var markup = Utils.GetMarkupExtensionAtPosition(value.ExtensionValue, context.Editor.Caret.Offset); if (markup.NamedArguments.Count > 0 || markup.PositionalArguments.Count > 0) { int oldOffset = context.Editor.Caret.Offset; context.Editor.Caret.Offset = context.StartOffset; string word = context.Editor.GetWordBeforeCaret().TrimEnd(); int spaces = CountWhiteSpacesAtEnd(context.Editor.GetWordBeforeCaret()); int typeNameStart = markup.ExtensionType.IndexOf(':') + 1; if (!(word == "." || word == "," || word == ":") && markup.ExtensionType.Substring(typeNameStart, markup.ExtensionType.Length - typeNameStart) != word) { context.Editor.Document.Replace(context.Editor.Caret.Offset - spaces, spaces, ", "); oldOffset += (2 - spaces); } context.Editor.Caret.Offset = oldOffset; } } if (cItem.Text.EndsWith("=", StringComparison.OrdinalIgnoreCase)) { new XamlCodeCompletionBinding().CtrlSpace(context.Editor); } } } } if (item is NewEventCompletionItem) { NewEventCompletionItem eventItem = item as NewEventCompletionItem; int discriminator; if (CreateEventHandlerCode(context, eventItem, out discriminator)) { if (discriminator > 0) { context.Editor.Document.Insert(context.EndOffset, discriminator.ToString()); } } } if (item is XmlnsCompletionItem) { context.Editor.Caret.Offset++; } if (item is XamlCompletionItem && xamlContext.Description == XamlContextDescription.InTag) { context.Editor.Document.Insert(context.EndOffset, "=\"\""); context.Editor.Caret.Offset--; new XamlCodeCompletionBinding().CtrlSpace(context.Editor); } switch (item.Text) { case "![CDATA[": context.Editor.Document.Insert(context.Editor.Caret.Offset, "]]>"); context.Editor.Caret.Offset -= 3; break; case "?": context.Editor.Document.Insert(context.Editor.Caret.Offset, "?>"); context.Editor.Caret.Offset -= 2; break; case "!--": context.Editor.Document.Insert(context.Editor.Caret.Offset, " -->"); context.Editor.Caret.Offset -= 4; break; } if (item.Text.StartsWith("/", StringComparison.OrdinalIgnoreCase)) { context.Editor.Document.Insert(context.EndOffset, ">"); context.CompletionCharHandled = context.CompletionChar == '>'; context.Editor.Caret.Offset++; } } }
public static XamlContext ResolveContext(FileName fileName, ITextSource fileContent, int offset) { XamlFullParseInformation info = SD.ParserService.Parse(fileName, fileContent) as XamlFullParseInformation; if (info == null) { throw new Exception("need full parse info!"); } AXmlDocument document = info.Document; AXmlObject currentData = document.GetChildAtOffset(offset); string attributeName = string.Empty, attributeValue = string.Empty; AttributeValue value = null; bool isRoot = false; bool wasAXmlElement = false; int offsetFromValueStart = -1; List <AXmlElement> ancestors = new List <AXmlElement>(); Dictionary <string, XamlNamespace> xmlns = new Dictionary <string, XamlNamespace>(); List <string> ignored = new List <string>(); string xamlNamespacePrefix = string.Empty; var item = currentData; AXmlElement root = null; while (item != document) { if (item is AXmlElement) { AXmlElement element = item as AXmlElement; ancestors.Add(element); foreach (var attr in element.Attributes) { if (attr.IsNamespaceDeclaration) { string prefix = (attr.Name == "xmlns") ? "" : attr.LocalName; if (!xmlns.ContainsKey(prefix)) { xmlns.Add(prefix, new XamlNamespace(attr.Value)); } } if (attr.LocalName == "Ignorable" && attr.Namespace == XamlConst.MarkupCompatibilityNamespace) { ignored.AddRange(attr.Value.Split(' ', '\t')); } if (string.IsNullOrEmpty(xamlNamespacePrefix) && attr.Value == XamlConst.XamlNamespace) { xamlNamespacePrefix = attr.LocalName; } } if (element.Parent is AXmlDocument) { root = element; if (!wasAXmlElement) { isRoot = true; } } wasAXmlElement = true; } item = item.Parent; } XamlContextDescription description = XamlContextDescription.None; AXmlElement active = null; AXmlElement parent = null; if (currentData is AXmlAttribute) { AXmlAttribute a = currentData as AXmlAttribute; int valueStartOffset = a.ValueSegment.Offset + 1; attributeName = a.Name; attributeValue = a.Value; value = MarkupExtensionParser.ParseValue(attributeValue); if (offset >= valueStartOffset && (offset < a.EndOffset || // if length is < 2 one quote is missing (a.ValueSegment.Length <= 1 && offset <= a.EndOffset))) { offsetFromValueStart = offset - valueStartOffset; description = XamlContextDescription.InAttributeValue; if (value != null && !value.IsString) { description = XamlContextDescription.InMarkupExtension; } if (attributeValue.StartsWith("{}", StringComparison.Ordinal) && attributeValue.Length > 2) { description = XamlContextDescription.InAttributeValue; } } else { description = XamlContextDescription.InTag; } active = a.ParentElement; } else if (currentData is AXmlTag) { AXmlTag tag = currentData as AXmlTag; if (tag.IsStartOrEmptyTag || tag.IsEndTag) { if (tag.NameSegment.EndOffset < offset) { description = XamlContextDescription.InTag; } else { description = XamlContextDescription.AtTag; } } else if (tag.IsComment) { description = XamlContextDescription.InComment; } else if (tag.IsCData) { description = XamlContextDescription.InCData; } active = tag.Parent as AXmlElement; } if (active != ancestors.FirstOrDefault()) { parent = ancestors.FirstOrDefault(); } else { parent = ancestors.Skip(1).FirstOrDefault(); } if (active == null) { active = parent; } var xAttribute = currentData as AXmlAttribute; var context = new XamlContext() { Description = description, ActiveElement = active, ParentElement = parent, RootElement = root, Ancestors = ancestors.AsReadOnly(), Attribute = xAttribute, InRoot = isRoot, AttributeValue = value, RawAttributeValue = attributeValue, ValueStartOffset = offsetFromValueStart, XmlnsDefinitions = xmlns, ParseInformation = info, IgnoredXmlns = ignored.AsReadOnly(), XamlNamespacePrefix = xamlNamespacePrefix }; return(context); }
void DoSetterAndEventSetterCompletion(XamlCompletionContext context, XamlCompletionItemList completionList) { string typeNameString; int dotIndex; IType typeName = ResolveTargetType(context, out typeNameString, out dotIndex, string.Equals(context.Attribute.Name, "Property") || string.Equals(context.Attribute.Name, "Event")); MemberResolveResult mrr; switch (context.Attribute.Name) { case "Value": AttributeValue propType = MarkupExtensionParser.ParseValue(context.ActiveElement.GetAttributeValue("Property") ?? ""); if (!propType.IsString) { break; } context.Description = XamlContextDescription.AtTag; string name = propType.StringValue; if (!name.Contains(".")) { name = typeNameString + "." + name; } mrr = resolver.ResolveExpression(name, context) as MemberResolveResult; if (mrr == null || mrr.Member == null) { break; } completionList.Items.AddRange( generator.MemberCompletion(context, mrr.Member.ReturnType, string.Empty) ); break; case "Property": completionList.Items.AddRange( typeName.GetProperties() .Where(p => p.IsPublic && p.CanSet) .Select(prop => new XamlCompletionItem(prop)) ); if (dotIndex == -1) { completionList.Items.AddRange( generator.GetTypesForPropEventNameCompletion(context, true) ); } break; case "Event": completionList.Items.AddRange( typeName.GetEvents() .Where(e => e.IsPublic) .Select(evt => new XamlCompletionItem(evt)) ); if (dotIndex == -1) { completionList.Items.AddRange( generator.GetTypesForPropEventNameCompletion(context, true) ); } break; case "Handler": var loc3 = context.Editor.Document.GetLocation(XmlParser.GetActiveElementStartIndex(context.Editor.Document.Text, context.Editor.Caret.Offset)); AttributeValue evtType = MarkupExtensionParser.ParseValue(context.ActiveElement.GetAttributeValue("Event") ?? ""); if (!evtType.IsString) { break; } string evtName = evtType.StringValue; if (!evtName.Contains(".")) { evtName = typeNameString + "." + evtName; } mrr = resolver.ResolveExpression(evtName, context) as MemberResolveResult; if (mrr == null) { break; } var member = mrr.Member as IEvent; if (member == null) { break; } completionList.Items.AddRange(generator.FindMatchingEventHandlers(context, member, typeName.Name)); break; } }