public override void Complete(CompletionContext context, ICompletionItem item) { using (context.Editor.Document.OpenUndoGroup()) { base.Complete(context, item); XamlCompletionContext xamlContext = XamlContextResolver.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 XamlCompletionItem && !item.Text.EndsWith(":", StringComparison.Ordinal)) { XamlCompletionItem cItem = item as XamlCompletionItem; 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) { CreateEventHandlerCode(xamlContext, item as NewEventCompletionItem); } if (item is XmlnsCompletionItem) { context.Editor.Caret.Offset++; } 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 IList<ICompletionItem> CreateElementList(XamlCompletionContext context, bool includeAbstract) { if (context.ParseInformation == null) return EmptyList<ICompletionItem>.Instance; List<ICompletionItem> result = new List<ICompletionItem>(); AXmlElement last = context.ParentElement; ITextEditor editor = context.Editor; compilation = SD.ParserService.GetCompilationForFile(editor.FileName); IUnresolvedFile file = context.ParseInformation.UnresolvedFile; foreach (string item in XamlConst.GetAllowedItems(context)) { result.Add(new XamlCompletionItem(item)); } IType rt = null; if (last != null) { if (string.Equals(last.Prefix, context.XamlNamespacePrefix, StringComparison.OrdinalIgnoreCase)) { if (string.Equals(last.LocalName, "Members", StringComparison.OrdinalIgnoreCase)) return result; if (string.Equals(last.LocalName, "Code", StringComparison.OrdinalIgnoreCase)) return result; } // If we have an element that is not a property or an incomplete // definition => interpret element as a type. XamlResolver resolver = new XamlResolver(compilation); int dotIndex = last.LocalName.IndexOf(".", StringComparison.Ordinal) + 1; if (dotIndex < 1 || dotIndex == last.LocalName.Length) { rt = resolver.ResolveType(last.Namespace, last.LocalName.Trim('.')); string contentPropertyName = GetContentPropertyName(rt.GetDefinition()); // If the type has a content property specified, use its type for completion. if (!string.IsNullOrEmpty(contentPropertyName)) { IProperty p = rt.GetProperties(m => m.Name == contentPropertyName).FirstOrDefault(); if (p != null) { rt = p.ReturnType; } } } else { string typeName = last.LocalName.Substring(0, dotIndex - 1); string memberName = last.LocalName.Substring(dotIndex); rt = resolver.ResolveType(last.Namespace, typeName); IMember member = rt.GetMembers(m => m.Name == memberName).FirstOrDefault(); if (member != null) { rt = member.ReturnType; } } } bool parentAdded = false; var utd = file.GetInnermostTypeDefinition(editor.Caret.Location); ITypeDefinition currentTypeDef = null; if (utd != null) { currentTypeDef = utd.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)).GetDefinition(); } MemberLookup memberLookup = new MemberLookup(currentTypeDef, compilation.MainAssembly); IList<ITypeDefinition> possibleTypesInCollection = EmptyList<ITypeDefinition>.Instance; if (rt != null && Extensions.IsListType(rt)) { possibleTypesInCollection = rt.GetMethods(m => m.Parameters.Count == 1 && "Add".Equals(m.Name, StringComparison.Ordinal)) .Select(m => m.Parameters[0].Type.GetDefinition()) .Where(t => t != null) .ToList(); } var items = GetClassesFromContext(context); foreach (var ns in items) { foreach (ITypeDefinition td in ns.Value) { if (td.Kind != TypeKind.Class && (!includeAbstract || td.Kind != TypeKind.Interface)) continue; if (td.IsStatic || (!includeAbstract && td.IsAbstract) || td.IsDerivedFrom(KnownTypeCode.Attribute)) continue; if (td.Kind == TypeKind.Class && !td.GetConstructors().Any(m => memberLookup.IsAccessible(m, false))) continue; if (possibleTypesInCollection.Count > 0 && !possibleTypesInCollection.Any(td.IsDerivedFrom)) continue; string fullName = td.Name; if (!string.IsNullOrEmpty(ns.Key)) fullName = ns.Key + ":" + fullName; XamlCompletionItem item = new XamlCompletionItem(fullName, td); parentAdded = parentAdded || (last != null && item.Text == last.Name); result.Add(item); } } // TODO reimplement this if it is really necessary. // if (!parentAdded && last != null && !last.Name.Contains(".")) { // IClass itemClass = cu.CreateType(last.Namespace, last.LocalName.Trim('.')).GetUnderlyingClass(); // if (itemClass != null) // result.Add(new XamlCodeCompletionItem(itemClass, last.Prefix)); // } return result; }
public IList <ICompletionItem> CreateElementList(XamlCompletionContext context, bool includeAbstract) { if (context.ParseInformation == null) { return(EmptyList <ICompletionItem> .Instance); } List <ICompletionItem> result = new List <ICompletionItem>(); AXmlElement last = context.ParentElement; ITextEditor editor = context.Editor; compilation = SD.ParserService.GetCompilationForFile(editor.FileName); IUnresolvedFile file = context.ParseInformation.UnresolvedFile; foreach (string item in XamlConst.GetAllowedItems(context)) { result.Add(new XamlCompletionItem(item)); } IType rt = null; if (last != null) { if (string.Equals(last.Prefix, context.XamlNamespacePrefix, StringComparison.OrdinalIgnoreCase)) { if (string.Equals(last.LocalName, "Members", StringComparison.OrdinalIgnoreCase)) { return(result); } if (string.Equals(last.LocalName, "Code", StringComparison.OrdinalIgnoreCase)) { return(result); } } // If we have an element that is not a property or an incomplete // definition => interpret element as a type. XamlResolver resolver = new XamlResolver(compilation); int dotIndex = last.LocalName.IndexOf(".", StringComparison.Ordinal) + 1; if (dotIndex < 1 || dotIndex == last.LocalName.Length) { rt = resolver.ResolveType(last.Namespace, last.LocalName.Trim('.')); string contentPropertyName = GetContentPropertyName(rt.GetDefinition()); // If the type has a content property specified, use its type for completion. if (!string.IsNullOrEmpty(contentPropertyName)) { IProperty p = rt.GetProperties(m => m.Name == contentPropertyName).FirstOrDefault(); if (p != null) { rt = p.ReturnType; } } } else { string typeName = last.LocalName.Substring(0, dotIndex - 1); string memberName = last.LocalName.Substring(dotIndex); rt = resolver.ResolveType(last.Namespace, typeName); IMember member = rt.GetMembers(m => m.Name == memberName).FirstOrDefault(); if (member != null) { rt = member.ReturnType; } } } bool parentAdded = false; var utd = file.GetInnermostTypeDefinition(editor.Caret.Location); ITypeDefinition currentTypeDef = null; if (utd != null) { currentTypeDef = utd.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)).GetDefinition(); } MemberLookup memberLookup = new MemberLookup(currentTypeDef, compilation.MainAssembly); IList <ITypeDefinition> possibleTypesInCollection = EmptyList <ITypeDefinition> .Instance; if (rt != null && Extensions.IsListType(rt)) { possibleTypesInCollection = rt.GetMethods(m => m.Parameters.Count == 1 && "Add".Equals(m.Name, StringComparison.Ordinal)) .Select(m => m.Parameters[0].Type.GetDefinition()) .Where(t => t != null) .ToList(); } var items = GetClassesFromContext(context); foreach (var ns in items) { foreach (ITypeDefinition td in ns.Value) { if (td.Kind != TypeKind.Class && (!includeAbstract || td.Kind != TypeKind.Interface)) { continue; } if (td.IsStatic || (!includeAbstract && td.IsAbstract) || td.IsDerivedFrom(KnownTypeCode.Attribute)) { continue; } if (td.Kind == TypeKind.Class && !td.GetConstructors().Any(m => memberLookup.IsAccessible(m, false))) { continue; } if (possibleTypesInCollection.Count > 0 && !possibleTypesInCollection.Any(td.IsDerivedFrom)) { continue; } string fullName = td.Name; if (!string.IsNullOrEmpty(ns.Key)) { fullName = ns.Key + ":" + fullName; } XamlCompletionItem item = new XamlCompletionItem(fullName, td); parentAdded = parentAdded || (last != null && item.Text == last.Name); result.Add(item); } } // TODO reimplement this if it is really necessary. // if (!parentAdded && last != null && !last.Name.Contains(".")) { // IClass itemClass = cu.CreateType(last.Namespace, last.LocalName.Trim('.')).GetUnderlyingClass(); // if (itemClass != null) // result.Add(new XamlCodeCompletionItem(itemClass, last.Prefix)); // } return(result); }