Exemple #1
0
        IEnumerable <ICompletionItem> CreateEventCompletion(XamlCompletionContext context, ITypeDefinition td)
        {
            IMethod invoker = td.GetMethods(method => method.Name == "Invoke").FirstOrDefault();

            if (invoker != null && context.ActiveElement != null)
            {
                var    item     = context.ActiveElement;
                var    resolver = new XamlAstResolver(compilation, context.ParseInformation);
                var    mrr      = resolver.ResolveAttribute(context.Attribute) as MemberResolveResult;
                IEvent evt;
                if (mrr == null || (evt = mrr.Member as IEvent) == null)
                {
                    return(EmptyList <ICompletionItem> .Instance);
                }
                int offset = XmlEditor.XmlParser.GetActiveElementStartIndex(context.Editor.Document.Text, context.Editor.Caret.Offset);

                if (offset == -1)
                {
                    return(Enumerable.Empty <ICompletionItem>());
                }

                var loc = context.Editor.Document.GetLocation(offset);

                string name = context.ActiveElement.GetAttributeValue("Name");
                if (string.IsNullOrEmpty(name))
                {
                    name = context.ActiveElement.GetAttributeValue(XamlConst.XamlNamespace, "Name");
                }

                return(FindMatchingEventHandlers(context, evt, (string.IsNullOrEmpty(name) ? item.Name : name)));
            }

            return(EmptyList <ICompletionItem> .Instance);
        }
Exemple #2
0
        bool DoMarkupExtensionCompletion(XamlCompletionContext context)
        {
            if (context.Description == XamlContextDescription.InMarkupExtension && context.AttributeValue != null && !context.AttributeValue.IsString)
            {
                if (!XamlBindingOptions.UseExtensionCompletion)
                {
                    return(false);
                }
                var completionList = generator.CreateMarkupExtensionCompletion(context) as XamlCompletionItemList;
                if (completionList == null)
                {
                    return(false);
                }
                string word = context.Editor.GetWordBeforeCaretExtended();
                if (context.PressedKey != '.' && context.PressedKey != '=' && !word.EndsWith(".", StringComparison.Ordinal) && completionList.PreselectionLength == 0)
                {
                    completionList.PreselectionLength = word.Length;
                }
                var insightList = generator.CreateMarkupExtensionInsight(context);
                context.Editor.ShowInsightWindow(insightList);
                context.Editor.ShowCompletionWindow(completionList);
                return(completionList.Items.Any() || insightList.Any());
            }

            return(false);
        }
        IType ResolveTargetType(XamlCompletionContext context, out string typeName, out int dotIndex, bool isPropertyOrEventName = false)
        {
            string targetTypeValue;

            dotIndex = -1;
            if (isPropertyOrEventName && context.AttributeValue.IsString)
            {
                dotIndex = context.AttributeValue.StringValue.IndexOf('.');
            }
            if (dotIndex > 0)
            {
                targetTypeValue = context.AttributeValue.StringValue.Substring(0, dotIndex);
            }
            else
            {
                string element;
                bool   isExplicit;
                if (context.ParentElement.Name.EndsWith("Trigger", StringComparison.Ordinal))
                {
                    element = "Trigger";
                }
                else
                {
                    element = context.ParentElement.Name;
                }
                targetTypeValue = Utils.LookForTargetTypeValue(context, out isExplicit, element);
            }
            AttributeValue value = MarkupExtensionParser.ParseValue(targetTypeValue ?? string.Empty);

            return(resolver.ResolveAttributeValue(context, value, out typeName).Type);
        }
Exemple #4
0
        IList <ICompletionItem> CreatePropertyPathCompletion(XamlCompletionContext context)
        {
            bool  isExplicit;
            IType typeName = GetType(context, out isExplicit);
            IList <ICompletionItem> list = new List <ICompletionItem>();

            string value = context.ValueStartOffset > -1 ? context.RawAttributeValue.Substring(0, Math.Min(context.ValueStartOffset + 1, context.RawAttributeValue.Length)) : "";

            if (value.EndsWithAny(']', ')'))
            {
                return(list);
            }

            var segments = PropertyPathParser.Parse(value).ToList();

            int  completionStart;
            bool isAtDot = false;

            IType 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);
        }
        public bool CtrlSpace(ITextEditor editor)
        {
            compilation = SD.ParserService.GetCompilationForFile(editor.FileName);
            resolver    = new XamlResolver(compilation);

            XamlCompletionContext context = XamlContextResolver.ResolveCompletionContext(editor, ' ');

            context.Forced = true;
            return(CtrlSpace(editor, context));
        }
Exemple #6
0
        IList <ICompletionItem> CreateAttributeList(XamlCompletionContext context, bool includeEvents)
        {
            if (context.ParseInformation == null)
            {
                return(EmptyList <ICompletionItem> .Instance);
            }
            AXmlElement     lastElement = context.ActiveElement;
            IUnresolvedFile file        = context.ParseInformation.UnresolvedFile;
            XamlResolver    resolver    = new XamlResolver(compilation);
            IType           type        = resolver.ResolveType(lastElement.Namespace, lastElement.LocalName.Trim('.'));

            var list = new List <ICompletionItem>();

            string xamlPrefix = context.XamlNamespacePrefix;
            string xKey       = string.IsNullOrEmpty(xamlPrefix) ? "" : xamlPrefix + ":";

            if (lastElement.Prefix == context.XamlNamespacePrefix && XamlConst.IsBuiltin(lastElement.LocalName))
            {
                return(EmptyList <ICompletionItem> .Instance);
            }

            if (lastElement.LocalName.EndsWith(".", StringComparison.OrdinalIgnoreCase) || context.PressedKey == '.')
            {
                if (type.Kind == TypeKind.Unknown)
                {
                    return(EmptyList <ICompletionItem> .Instance);
                }

                if (context.ParentElement != null &&
                    context.ParentElement.LocalName.StartsWith(lastElement.LocalName.TrimEnd('.'), StringComparison.OrdinalIgnoreCase))
                {
                    AddAttributes(type, list, includeEvents);
                }
                AddAttachedProperties(type.GetDefinition(), list);
            }
            else
            {
                if (type.Kind == TypeKind.Unknown)
                {
                    list.Add(new XamlCompletionItem(xKey + "Uid"));
                }
                else
                {
                    AddAttributes(type, list, includeEvents);
                    list.AddRange(GetListOfAttached(context, null, includeEvents, true));
                    list.AddRange(
                        XamlConst.XamlNamespaceAttributes
                        .Where(localName => XamlConst.IsAttributeAllowed(context.InRoot, localName))
                        .Select(item => new XamlCompletionItem(xKey + item))
                        );
                }
            }

            return(list);
        }
 bool CtrlSpace(ITextEditor editor, XamlCompletionContext context)
 {
     if (context.Description == XamlContextDescription.InComment ||
         context.Description == XamlContextDescription.InCData ||
         context.ActiveElement == null)
     {
         return(false);
     }
     if (!context.InAttributeValueOrMarkupExtension)
     {
         XamlCompletionItemList list = generator.CreateListForContext(context);
         string starter = editor.GetWordBeforeCaretExtended().TrimStart('/');
         if (context.Description != XamlContextDescription.None && !string.IsNullOrEmpty(starter))
         {
             if (starter.Contains("."))
             {
                 list.PreselectionLength = starter.Length - starter.IndexOf('.') - 1;
             }
             else
             {
                 list.PreselectionLength = starter.Length;
             }
         }
         editor.ShowCompletionWindow(list);
         return(true);
     }
     // DO NOT USE generator.CreateListForContext here!!! results in endless recursion!!!!
     if (context.Attribute != null)
     {
         if (!DoMarkupExtensionCompletion(context))
         {
             var completionList = new XamlCompletionItemList(context);
             completionList.PreselectionLength = editor.GetWordBeforeCaretExtended().Length;
             if ((context.ActiveElement.Name == "Setter" || context.ActiveElement.Name == "EventSetter") && (context.Attribute.Name == "Property" || context.Attribute.Name == "Value"))
             {
                 DoSetterAndEventSetterCompletion(context, completionList);
                 editor.ShowCompletionWindow(completionList);
             }
             else if ((context.ActiveElement.Name.EndsWith("Trigger", StringComparison.Ordinal) || context.ActiveElement.Name == "Condition") && context.Attribute.Name == "Value")
             {
                 DoTriggerCompletion(context, completionList);
                 editor.ShowCompletionWindow(completionList);
             }
             else if (!DoAttributeCompletion(context, completionList))
             {
                 DoXmlAttributeCompletion(context, completionList);
             }
             return(completionList.Items.Any());
         }
         return(true);
     }
     return(false);
 }
        static void DoTriggerCompletion(XamlCompletionContext context, XamlCompletionItemList completionList)
        {
            bool           isExplicit;
            AttributeValue value = MarkupExtensionParser.ParseValue(CompletionDataHelper.LookForTargetTypeValue(context, out isExplicit, "Trigger") ?? string.Empty);

            IReturnType typeName       = null;
            string      typeNameString = null;

            if (!value.IsString)
            {
                typeNameString = CompletionDataHelper.GetTypeNameFromTypeExtension(value.ExtensionValue, context);
                typeName       = CompletionDataHelper.ResolveType(typeNameString, context);
            }
            else
            {
                typeNameString = value.StringValue;
                typeName       = CompletionDataHelper.ResolveType(value.StringValue, context);
            }

            if (typeName != null)
            {
                switch (context.Attribute.Name)
                {
                case "Value":
                    AttributeValue propType = MarkupExtensionParser.ParseValue(context.ActiveElement.GetAttributeValue("Property") ?? "");
                    if (!propType.IsString)
                    {
                        break;
                    }

                    string name = propType.StringValue;

                    if (!name.Contains("."))
                    {
                        name = typeNameString + "." + name;
                    }

                    context.Description = XamlContextDescription.AtTag;

                    var member = XamlResolver.Resolve(name, context) as MemberResolveResult;

                    if (member == null || member.ResolvedMember == null)
                    {
                        break;
                    }

                    completionList.Items.AddRange(
                        CompletionDataHelper.MemberCompletion(context, member.ResolvedMember.ReturnType, string.Empty)
                        );
                    break;
                }
            }
        }
Exemple #9
0
        IEnumerable <ICompletionItem> GetAllTypes(XamlCompletionContext context)
        {
            var items = GetClassesFromContext(context);

            foreach (var ns in items)
            {
                foreach (var c in ns.Value)
                {
                    if (c.Kind == TypeKind.Class && !c.IsDerivedFrom(KnownTypeCode.Attribute))
                    {
                        yield return(new XamlCompletionItem(ns.Key, c));
                    }
                }
            }
        }
Exemple #10
0
        bool DoStaticExtensionCompletion(XamlCompletionItemList list, XamlCompletionContext context)
        {
            AttributeValue selItem = Utils.GetMarkupExtensionAtPosition(context.AttributeValue.ExtensionValue, context.ValueStartOffset)
                                     .PositionalArguments.LastOrDefault();
            var resolver = new XamlResolver(compilation);

            if (context.PressedKey == '.')
            {
                if (selItem != null && selItem.IsString)
                {
                    var rr = resolver.ResolveAttributeValue(selItem.StringValue, context) as TypeResolveResult;
                    if (rr != null)
                    {
                        list.Items.AddRange(MemberCompletion(context, rr.Type, string.Empty));
                    }
                    return(false);
                }
            }
            else
            {
                if (selItem != null && selItem.IsString)
                {
                    int    index = selItem.StringValue.IndexOf('.');
                    string s     = (index > -1) ? selItem.StringValue.Substring(0, index) : selItem.StringValue;
                    var    rr    = resolver.ResolveAttributeValue(s, context) as TypeResolveResult;
                    if (rr != null && rr.Type.Kind != TypeKind.Unknown)
                    {
                        list.Items.AddRange(MemberCompletion(context, rr.Type, (index == -1) ? "." : string.Empty));

                        list.PreselectionLength = (index > -1) ? selItem.StringValue.Length - index - 1 : 0;

                        return(false);
                    }
                    else
                    {
                        DoStaticTypeCompletion(selItem, list, context);
                    }
                }
                else
                {
                    DoStaticTypeCompletion(selItem, list, context);
                }
            }

            return(true);
        }
Exemple #11
0
        public IEnumerable <ICompletionItem> FindMatchingEventHandlers(XamlCompletionContext context, IEvent member, string targetName)
        {
            ITypeDefinition td = member.ReturnType.GetDefinition();

            if (td == null)
            {
                yield break;
            }

            IMethod delegateInvoker = td.GetMethods(m => m.Name == "Invoke").FirstOrDefault();

            if (delegateInvoker == null)
            {
                yield break;
            }

            if (context.ParseInformation == null)
            {
                yield break;
            }

            var file       = context.ParseInformation.UnresolvedFile;
            var loc        = context.Editor.Caret.Location;
            var unresolved = file.GetInnermostTypeDefinition(loc.Line, loc.Column);

            if (unresolved == null)
            {
                yield break;
            }
            IType type = unresolved.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)).GetDefinition();

            foreach (IMethod method in type.GetMethods(m => m.Parameters.Count == delegateInvoker.Parameters.Count))
            {
                if (!method.ReturnType.Equals(delegateInvoker.ReturnType))
                {
                    continue;
                }

                if (method.Parameters.SequenceEqual(delegateInvoker.Parameters, new ParameterComparer()))
                {
                    yield return(new XamlCompletionItem(method));
                }
            }

            yield return(new NewEventCompletionItem(member, targetName));
        }
        public static IType Resolve(this PropertyPathSegment segment, XamlCompletionContext context, IType 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("(", StringComparison.Ordinal))
            {
                content = content.TrimStart('(');
                if (content.Contains("."))
                {
                    content = content.Remove(content.IndexOf('.'));
                }
            }

            ICompilation compilation = SD.ParserService.GetCompilationForFile(context.Editor.FileName);
            XamlResolver resolver    = new XamlResolver(compilation);

            ResolveResult rr   = resolver.ResolveExpression(content, context);
            IType         type = rr.Type;

            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.Member != null)
                {
                    type = mrr.Member.ReturnType;
                }
            }
            return(type);
        }
        public static XamlCompletionContext ResolveCompletionContext(ITextEditor editor, char typedValue, int offset)
        {
            var binding = editor.GetService(typeof(XamlTextEditorExtension)) as XamlTextEditorExtension;

            if (binding == null)
            {
                throw new InvalidOperationException("Can only use ResolveCompletionContext with a XamlTextEditorExtension.");
            }

            var context = new XamlCompletionContext(ResolveContext(editor.FileName, editor.Document, offset))
            {
                PressedKey = typedValue,
                Editor     = editor
            };

            return(context);
        }
Exemple #14
0
        /// <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);
        }
Exemple #15
0
        public IEnumerable <IInsightItem> CreateMarkupExtensionInsight(XamlCompletionContext context)
        {
            var markup   = Utils.GetMarkupExtensionAtPosition(context.AttributeValue.ExtensionValue, context.ValueStartOffset);
            var resolver = new XamlResolver(compilation);
            var type     = (resolver.ResolveExpression(markup.ExtensionType, context) ?? resolver.ResolveExpression(markup.ExtensionType + "Extension", context)).Type;

            if (type != null)
            {
                var ctors = type
                            .GetMethods(m => m.IsPublic && m.IsConstructor && m.Parameters.Count >= markup.PositionalArguments.Count)
                            .OrderBy(m => m.Parameters.Count);

                foreach (var ctor in ctors)
                {
                    yield return(new MarkupExtensionInsightItem(ctor));
                }
            }
        }
Exemple #16
0
        static IType ResolvePropertyPath(IList <PropertyPathSegment> segments, XamlCompletionContext context, IType parentType, out int lastIndex)
        {
            IType type = parentType;

            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(p => p.IsIndexer).FirstOrDefault();
                        if (prop != null)
                        {
                            type = prop.ReturnType;
                        }
                    }
                    break;

                case SegmentKind.SourceTraversal:
                    // ignore
                    return(null);
                }
            }

            return(type);
        }
Exemple #17
0
        public ICompletionItemList CreateMarkupExtensionCompletion(XamlCompletionContext context)
        {
            var list = new XamlCompletionItemList(context);

            compilation = SD.ParserService.GetCompilationForFile(context.Editor.FileName);
            string visibleValue = context.RawAttributeValue.Substring(0, Utils.MinMax(context.ValueStartOffset, 0, context.RawAttributeValue.Length));

            if (context.PressedKey == '=')
            {
                visibleValue += "=";
            }
            var markup   = Utils.GetMarkupExtensionAtPosition(context.AttributeValue.ExtensionValue, context.ValueStartOffset);
            var resolver = new XamlResolver(compilation);
            var type     = resolver.ResolveExpression(markup.ExtensionType, context).Type;

            if (type.Kind == TypeKind.Unknown)
            {
                type = resolver.ResolveExpression(markup.ExtensionType + "Extension", context).Type;
            }

            if (type.Kind == TypeKind.Unknown)
            {
                list.Items.AddRange(CreateListOfMarkupExtensions(context));
                list.PreselectionLength = markup.ExtensionType.Length;
            }
            else
            {
                if (markup.NamedArguments.Count == 0)
                {
                    if (DoPositionalArgsCompletion(list, context, markup, type))
                    {
                        DoNamedArgsCompletion(list, context, type, markup);
                    }
                }
                else
                {
                    DoNamedArgsCompletion(list, context, type, markup);
                }
            }

            list.SortItems();

            return(list);
        }
Exemple #18
0
        public static MemberResolveResult ResolveMember(string expression, XamlCompletionContext context)
        {
            if (context.ParseInformation == null || string.IsNullOrEmpty(context.Editor.Document.Text))
            {
                return(null);
            }

            var expressionResult = new ExpressionResult(expression, context);

            XamlResolver resolver = new XamlResolver();

            resolver.resolveExpression = expression;
            resolver.caretLine         = expressionResult.Region.BeginLine;
            resolver.caretColumn       = expressionResult.Region.BeginColumn;
            resolver.callingClass      = context.ParseInformation.CompilationUnit.GetInnermostClass(resolver.caretLine, resolver.caretColumn);
            resolver.context           = context;

            return(resolver.ResolveNamedAttribute(expression));
        }
        void DoTriggerCompletion(XamlCompletionContext context, XamlCompletionItemList completionList)
        {
            bool           isExplicit;
            AttributeValue value = MarkupExtensionParser.ParseValue(Utils.LookForTargetTypeValue(context, out isExplicit, "Trigger") ?? string.Empty);
            string         typeNameString;
            var            rr       = resolver.ResolveAttributeValue(context, value, out typeNameString);
            var            typeName = rr.Type;

            if (typeName != null)
            {
                switch (context.Attribute.Name)
                {
                case "Value":
                    AttributeValue propType = MarkupExtensionParser.ParseValue(context.ActiveElement.GetAttributeValue("Property") ?? "");
                    if (!propType.IsString)
                    {
                        break;
                    }

                    string name = propType.StringValue;

                    if (!name.Contains("."))
                    {
                        name = typeNameString + "." + name;
                    }

                    context.Description = XamlContextDescription.AtTag;

                    var 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;
                }
            }
        }
        static bool CreateEventHandlerCode(XamlCompletionContext context, NewEventCompletionItem completionItem)
        {
            IProject project = SD.ProjectService.FindProjectContainingFile(context.Editor.FileName);

            if (project == null)
            {
                return(false);
            }
            var unresolved = context.ParseInformation.UnresolvedFile.TypeDefinition;

            if (unresolved == null)
            {
                return(false);
            }
            var compilation = SD.ParserService.GetCompilationForFile(context.Editor.FileName);
            var definition  = unresolved.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)).GetDefinition();

            project.LanguageBinding.CodeGenerator.InsertEventHandler(definition, completionItem.HandlerName, completionItem.EventType, true);
            return(true);
        }
        void DoXmlAttributeCompletion(XamlCompletionContext context, XamlCompletionItemList completionList)
        {
            if (context.Attribute.Name == "xml:space")
            {
                completionList.Items.AddRange(new[] {
                    new XamlCompletionItem("preserve"),
                    new XamlCompletionItem("default")
                });
            }

            if (context.Attribute.Prefix.Equals("xmlns", StringComparison.OrdinalIgnoreCase) ||
                context.Attribute.Name.Equals("xmlns", StringComparison.OrdinalIgnoreCase))
            {
                completionList.Items.AddRange(generator.CreateListForXmlnsCompletion(compilation));

                ICompletionListWindow window = context.Editor.ShowCompletionWindow(completionList);
                if (window != null)
                {
                    window.Width = 400;
                }
            }
        }
Exemple #22
0
        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)));
        }
        bool DoAttributeCompletion(XamlCompletionContext context, XamlCompletionItemList completionList)
        {
            XamlAstResolver resolver = new XamlAstResolver(compilation, context.ParseInformation);
            ITextEditor     editor   = context.Editor;
            var             mrr      = resolver.ResolveAttribute(context.Attribute) as MemberResolveResult;

            if (mrr != null && mrr.Type.Kind != TypeKind.Unknown)
            {
                completionList.Items.AddRange(generator.MemberCompletion(context, mrr.Type, string.Empty));
                editor.ShowInsightWindow(generator.MemberInsight(mrr));
                editor.ShowCompletionWindow(completionList);
                switch (mrr.Type.FullName)
                {
                case "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;
                    break;

                case "System.Windows.Media.FontFamily":
                    string text      = context.ValueStartOffset > -1 ? context.RawAttributeValue.Substring(0, Math.Min(context.ValueStartOffset, context.RawAttributeValue.Length)) : "";
                    int    lastComma = text.LastIndexOf(',');
                    completionList.PreselectionLength = lastComma == -1 ? context.ValueStartOffset : context.ValueStartOffset - lastComma - 1;
                    break;
                }
            }

            return(completionList.Items.Any());
        }
Exemple #24
0
        public IEnumerable <ICompletionItem> CreateListOfMarkupExtensions(XamlCompletionContext context)
        {
            var markupExtensionType = compilation.FindType(typeof(System.Windows.Markup.MarkupExtension))
                                      .GetDefinition();

            if (markupExtensionType == null)
            {
                yield break;
            }
            string text;

            foreach (var ns in GetClassesFromContext(context))
            {
                foreach (var definition in ns.Value.Where(td => td.IsDerivedFrom(markupExtensionType)))
                {
                    text = definition.Name;
                    if (text.EndsWith("Extension", StringComparison.Ordinal))
                    {
                        text = text.Remove(text.Length - "Extension".Length);
                    }
                    string prefix = ns.Key;
                    if (prefix.Length > 0)
                    {
                        text = prefix + ":" + text;
                    }
                    yield return(new XamlCompletionItem(text, definition));
                }
            }

            text = "Reference";
            if (context.XamlNamespacePrefix != "")
            {
                text = context.XamlNamespacePrefix + ":" + text;
            }
            yield return(new XamlCompletionItem(text));
        }
		bool CtrlSpace(ITextEditor editor, XamlCompletionContext context)
		{
			if (context.Description == XamlContextDescription.InComment
			    || context.Description == XamlContextDescription.InCData
			    || context.ActiveElement == null) {
				return false;
			}
			if (!context.InAttributeValueOrMarkupExtension) {
				XamlCompletionItemList list = generator.CreateListForContext(context);
				string starter = editor.GetWordBeforeCaretExtended().TrimStart('/');
				if (context.Description != XamlContextDescription.None && !string.IsNullOrEmpty(starter)) {
					if (starter.Contains(".")) {
						list.PreselectionLength = starter.Length - starter.IndexOf('.') - 1;
					} else {
						list.PreselectionLength = starter.Length;
					}
				}
				editor.ShowCompletionWindow(list);
				return true;
			}
			// DO NOT USE generator.CreateListForContext here!!! results in endless recursion!!!!
			if (context.Attribute != null) {
				if (!DoMarkupExtensionCompletion(context)) {
					var completionList = new XamlCompletionItemList(context);
					completionList.PreselectionLength = editor.GetWordBeforeCaretExtended().Length;
					if ((context.ActiveElement.Name == "Setter" || context.ActiveElement.Name == "EventSetter") && (context.Attribute.Name == "Property" || context.Attribute.Name == "Value")) {
						DoSetterAndEventSetterCompletion(context, completionList);
						editor.ShowCompletionWindow(completionList);
					} else if ((context.ActiveElement.Name.EndsWith("Trigger", StringComparison.Ordinal) || context.ActiveElement.Name == "Condition") && context.Attribute.Name == "Value") {
						DoTriggerCompletion(context, completionList);
						editor.ShowCompletionWindow(completionList);
					} else if (!DoAttributeCompletion(context, completionList)) {
						DoXmlAttributeCompletion(context, completionList);
					}
					return completionList.Items.Any();
				}
				return true;
			}
			return false;
		}
		public static XamlCompletionContext ResolveCompletionContext(ITextEditor editor, char typedValue, int offset)
		{
			var binding = editor.GetService(typeof(XamlTextEditorExtension)) as XamlTextEditorExtension;
			
			if (binding == null)
				throw new InvalidOperationException("Can only use ResolveCompletionContext with a XamlTextEditorExtension.");
			
			var context = new XamlCompletionContext(ResolveContext(editor.FileName, editor.Document, offset)) {
				PressedKey = typedValue,
				Editor = editor
			};
			
			return context;
		}
		IEnumerable<ICompletionItem> GetAllTypes(XamlCompletionContext context)
		{
			var items = GetClassesFromContext(context);
			
			foreach (var ns in items) {
				foreach (var c in ns.Value) {
					if (c.Kind == TypeKind.Class && !c.IsDerivedFrom(KnownTypeCode.Attribute))
						yield return new XamlCompletionItem(ns.Key, c);
				}
			}
		}
		IEnumerable<ICompletionItem> CreateEventCompletion(XamlCompletionContext context, ITypeDefinition td)
		{
			IMethod invoker = td.GetMethods(method => method.Name == "Invoke").FirstOrDefault();
			if (invoker != null && context.ActiveElement != null) {
				var item = context.ActiveElement;
				var resolver = new XamlAstResolver(compilation, context.ParseInformation);
				var mrr = resolver.ResolveAttribute(context.Attribute) as MemberResolveResult;
				IEvent evt;
				if (mrr == null || (evt = mrr.Member as IEvent) == null)
					return EmptyList<ICompletionItem>.Instance;
				int offset = XmlEditor.XmlParser.GetActiveElementStartIndex(context.Editor.Document.Text, context.Editor.Caret.Offset);
				
				if (offset == -1)
					return Enumerable.Empty<ICompletionItem>();
				
				var loc = context.Editor.Document.GetLocation(offset);
				
				string name = context.ActiveElement.GetAttributeValue("Name");
				if (string.IsNullOrEmpty(name))
					name = context.ActiveElement.GetAttributeValue(XamlConst.XamlNamespace, "Name");
				
				return FindMatchingEventHandlers(context, evt, (string.IsNullOrEmpty(name) ? item.Name : name));
			}
			
			return EmptyList<ICompletionItem>.Instance;
		}
		public IEnumerable<ICompletionItem> CreateListOfMarkupExtensions(XamlCompletionContext context)
		{
			var markupExtensionType = compilation.FindType(typeof(System.Windows.Markup.MarkupExtension))
				.GetDefinition();
			if (markupExtensionType == null)
				yield break;
			string text;
			foreach (var ns in GetClassesFromContext(context)) {
				foreach (var definition in ns.Value.Where(td => td.IsDerivedFrom(markupExtensionType))) {
					text = definition.Name;
					if (text.EndsWith("Extension", StringComparison.Ordinal))
						text = text.Remove(text.Length - "Extension".Length);
					string prefix = ns.Key;
					if (prefix.Length > 0) {
						text = prefix + ":" + text;
					}
					yield return new XamlCompletionItem(text, definition);
				}
			}
			
			text = "Reference";
			if (context.XamlNamespacePrefix != "") {
				text = context.XamlNamespacePrefix + ":" + text;
			}
			yield return new XamlCompletionItem(text);
		}
		bool DoStaticExtensionCompletion(XamlCompletionItemList list, XamlCompletionContext context)
		{
			AttributeValue selItem = Utils.GetMarkupExtensionAtPosition(context.AttributeValue.ExtensionValue, context.ValueStartOffset)
				.PositionalArguments.LastOrDefault();
			var resolver = new XamlResolver(compilation);
			if (context.PressedKey == '.') {
				if (selItem != null && selItem.IsString) {
					var rr = resolver.ResolveAttributeValue(selItem.StringValue, context) as TypeResolveResult;
					if (rr != null)
						list.Items.AddRange(MemberCompletion(context, rr.Type, string.Empty));
					return false;
				}
			} else {
				if (selItem != null && selItem.IsString) {
					int index = selItem.StringValue.IndexOf('.');
					string s = (index > -1) ? selItem.StringValue.Substring(0, index) : selItem.StringValue;
					var rr = resolver.ResolveAttributeValue(s, context) as TypeResolveResult;
					if (rr != null && rr.Type.Kind != TypeKind.Unknown) {
						list.Items.AddRange(MemberCompletion(context, rr.Type, (index == -1) ? "." : string.Empty));
						
						list.PreselectionLength = (index > -1) ? selItem.StringValue.Length - index - 1 : 0;
						
						return false;
					} else
						DoStaticTypeCompletion(selItem, list, context);
				} else {
					DoStaticTypeCompletion(selItem, list, context);
				}
			}
			
			return true;
		}
		static void DoTriggerCompletion(XamlCompletionContext context, XamlCompletionItemList completionList) {
			bool isExplicit;
			AttributeValue value = MarkupExtensionParser.ParseValue(CompletionDataHelper.LookForTargetTypeValue(context, out isExplicit, "Trigger") ?? string.Empty);
			
			IReturnType typeName = null;
			string typeNameString = null;
			
			if (!value.IsString) {
				typeNameString = CompletionDataHelper.GetTypeNameFromTypeExtension(value.ExtensionValue, context);
				typeName = CompletionDataHelper.ResolveType(typeNameString, context);
			} else {
				typeNameString = value.StringValue;
				typeName = CompletionDataHelper.ResolveType(value.StringValue, context);
			}
			
			if (typeName != null) {
				switch (context.Attribute.Name) {
					case "Value":
						AttributeValue propType = MarkupExtensionParser.ParseValue(context.ActiveElement.GetAttributeValue("Property") ?? "");
						if (!propType.IsString)
							break;
						
						string name = propType.StringValue;
						
						if (!name.Contains("."))
							name = typeNameString + "." + name;
						
						context.Description = XamlContextDescription.AtTag;
						
						var member = XamlResolver.Resolve(name, context) as MemberResolveResult;
						
						if (member == null || member.ResolvedMember == null)
							break;
						
						completionList.Items.AddRange(
							CompletionDataHelper.MemberCompletion(context, member.ResolvedMember.ReturnType, string.Empty)
						);
						break;
				}
			}
		}
		public ICompletionItemList CreateMarkupExtensionCompletion(XamlCompletionContext context)
		{
			var list = new XamlCompletionItemList(context);
			compilation = SD.ParserService.GetCompilationForFile(context.Editor.FileName);
			string visibleValue = context.RawAttributeValue.Substring(0, Utils.MinMax(context.ValueStartOffset, 0, context.RawAttributeValue.Length));
			if (context.PressedKey == '=')
				visibleValue += "=";
			var markup = Utils.GetMarkupExtensionAtPosition(context.AttributeValue.ExtensionValue, context.ValueStartOffset);
			var resolver = new XamlResolver(compilation);
			var type = resolver.ResolveExpression(markup.ExtensionType, context).Type;
			if (type.Kind == TypeKind.Unknown)
				type = resolver.ResolveExpression(markup.ExtensionType + "Extension", context).Type;
			
			if (type.Kind == TypeKind.Unknown) {
				list.Items.AddRange(CreateListOfMarkupExtensions(context));
				list.PreselectionLength = markup.ExtensionType.Length;
			} else {
				if (markup.NamedArguments.Count == 0) {
					if (DoPositionalArgsCompletion(list, context, markup, type))
						DoNamedArgsCompletion(list, context, type, markup);
				} else
					DoNamedArgsCompletion(list, context, type, markup);
			}
			
			list.SortItems();
			
			return list;
		}
		void DoXmlAttributeCompletion(XamlCompletionContext context, XamlCompletionItemList completionList)
		{
			if (context.Attribute.Name == "xml:space") {
				completionList.Items.AddRange(new[] {
				                              	new XamlCompletionItem("preserve"),
				                              	new XamlCompletionItem("default")
				                              });
			}
			
			if (context.Attribute.Prefix.Equals("xmlns", StringComparison.OrdinalIgnoreCase) ||
			    context.Attribute.Name.Equals("xmlns", StringComparison.OrdinalIgnoreCase)) {
				completionList.Items.AddRange(generator.CreateListForXmlnsCompletion(compilation));
				
				ICompletionListWindow window = context.Editor.ShowCompletionWindow(completionList);
				if (window != null) {
					window.Width = 400;
				}
			}
		}
Exemple #34
0
        void DoStaticTypeCompletion(AttributeValue selItem, XamlCompletionItemList list, XamlCompletionContext context)
        {
            var items = GetClassesFromContext(context);

            foreach (var ns in items)
            {
                string key = ns.Key;
                if (!string.IsNullOrEmpty(key))
                {
                    key += ":";
                }
                list.Items.AddRange(
                    ns.Value
                    .Where(c => c.Fields.Any(f => f.IsStatic) || c.Properties.Any(p => p.IsStatic))
                    .Select(c => new XamlCompletionItem(key + c.Name, c))
                    );
            }
            if (selItem != null && selItem.IsString)
            {
                list.PreselectionLength = selItem.StringValue.Length;
            }
        }
Exemple #35
0
 public static ResolveResult Resolve(string expression, XamlCompletionContext context)
 {
     return(new XamlResolver().Resolve(new ExpressionResult(expression, context), context.ParseInformation, null));
 }
		public static ResolveResult Resolve(string expression, XamlCompletionContext context)
		{
			return new XamlResolver().Resolve(new ExpressionResult(expression, context), context.ParseInformation, null);
		}
		public static MemberResolveResult ResolveMember(string expression, XamlCompletionContext context)
		{
			if (context.ParseInformation == null || string.IsNullOrEmpty(context.Editor.Document.Text))
				return null;
			
			var expressionResult = new ExpressionResult(expression, context);
			
			XamlResolver resolver = new XamlResolver();
			resolver.resolveExpression = expression;
			resolver.caretLine = expressionResult.Region.BeginLine;
			resolver.caretColumn = expressionResult.Region.BeginColumn;
			resolver.callingClass = context.ParseInformation.CompilationUnit.GetInnermostClass(resolver.caretLine, resolver.caretColumn);
			resolver.context = context;
			
			return resolver.ResolveNamedAttribute(expression);
		}
		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;
			}
		}
		static void DoSetterAndEventSetterCompletion(XamlCompletionContext context, XamlCompletionItemList completionList) {
			bool isExplicit;
			string element = context.ParentElement.Name.EndsWith("Trigger") ? "Trigger" : context.ParentElement.Name;
			AttributeValue value = MarkupExtensionParser.ParseValue(CompletionDataHelper.LookForTargetTypeValue(context, out isExplicit, element) ?? string.Empty);
			
			IReturnType typeName = null;
			string typeNameString = null;
			
			if (!value.IsString) {
				typeNameString = CompletionDataHelper.GetTypeNameFromTypeExtension(value.ExtensionValue, context);
				typeName = CompletionDataHelper.ResolveType(typeNameString, context);
			} else {
				typeNameString = value.StringValue;
				typeName = CompletionDataHelper.ResolveType(value.StringValue, context);
			}
			
			if (typeName != null) {
				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;
						
						var member = XamlResolver.Resolve(name, context) as MemberResolveResult;
						
						if (member == null || member.ResolvedMember == null)
							break;
						
						completionList.Items.AddRange(
							CompletionDataHelper.MemberCompletion(context, member.ResolvedMember.ReturnType, string.Empty)
						);
						break;
					case "Property":
						completionList.Items.AddRange(
							typeName.GetProperties()
							.Where(p => p.IsPublic && p.CanSet)
							.Select(prop => new XamlCodeCompletionItem(prop))
						);
						break;
					case "Event":
						completionList.Items.AddRange(
							typeName.GetEvents()
							.Where(e => e.IsPublic)
							.Select(evt => new XamlCodeCompletionItem(evt))
						);
						break;
					case "Handler":
						var loc3 = context.Editor.Document.OffsetToPosition(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;
						
						var evtMember = XamlResolver.Resolve(evtName, context) as MemberResolveResult;
						
						if (evtMember == null || evtMember.ResolvedMember == null || !(evtMember.ResolvedMember is IEvent) || evtMember.ResolvedMember.ReturnType == null)
							break;
						
						IClass c = (evtMember.ResolvedMember as IEvent).ReturnType.GetUnderlyingClass();
						
						if (c == null)
							break;
						
						IMethod invoker = c.Methods.FirstOrDefault(m => m.Name == "Invoke");
						
						if (invoker == null)
							break;
						
						completionList.Items.AddRange(
							CompletionDataHelper.AddMatchingEventHandlers(context, invoker).Add(new NewEventCompletionItem(evtMember.ResolvedMember as IEvent, typeName.Name))
						);
						break;
				}
			}
		}
		public XamlCompletionItemList CreateListForContext(XamlCompletionContext context)
		{
			XamlCompletionItemList list = new XamlCompletionItemList(context);
			
			ITextEditor editor = context.Editor;
			compilation = SD.ParserService.GetCompilationForFile(editor.FileName);
			XamlAstResolver resolver = new XamlAstResolver(compilation, context.ParseInformation);
			
			switch (context.Description) {
				case XamlContextDescription.None:
					if (context.Forced) {
						list.Items.AddRange(standardElements);
						list.Items.AddRange(CreateElementList(context, false));
						AddClosingTagCompletion(context, list, resolver);
					}
					break;
				case XamlContextDescription.AtTag:
					if ((editor.Caret.Offset > 0 && editor.Document.GetCharAt(editor.Caret.Offset - 1) == '.') || context.PressedKey == '.') {
						list.Items.AddRange(CreateAttributeList(context, false));
					} else {
						list.Items.AddRange(standardElements);
						list.Items.AddRange(CreateElementList(context, false));
						AddClosingTagCompletion(context, list, resolver);
					}
					break;
				case XamlContextDescription.InTag:
					string word = editor.GetWordBeforeCaretExtended();
					
					if (context.PressedKey == '.' || word.Contains(".")) {
						int pos = word.IndexOf(':');
						
						string element = word.Substring(pos + 1, word.Length - pos - 1);
						string className = word;
						int propertyStart = element.IndexOf('.');
						if (propertyStart != -1) {
							element = element.Substring(0, propertyStart).TrimEnd('.');
							className = className.Substring(0, propertyStart + pos + 1).TrimEnd('.');
						}
						
						int caretOffset = editor.Caret.Offset;
						int offset = editor.Document.LastIndexOf(className, caretOffset - word.Length, word.Length, StringComparison.OrdinalIgnoreCase);
						TextLocation loc = editor.Document.GetLocation(offset);
						
						XamlFullParseInformation info = context.ParseInformation;
						XamlResolver nameResolver = new XamlResolver(compilation);
						TypeResolveResult trr = nameResolver.ResolveExpression(className, context) as TypeResolveResult;
						ITypeDefinition typeClass = trr != null ? trr.Type.GetDefinition() : null;
						
						if (typeClass != null && typeClass.HasAttached(true, true))
							list.Items.AddRange(GetListOfAttached(context, typeClass, true, true));
					} else {
						list.Items.AddRange(CreateAttributeList(context, true));
						list.Items.AddRange(standardAttributes);
					}
					break;
				case XamlContextDescription.InAttributeValue:
					new XamlCodeCompletionBinding().CtrlSpace(editor);
					break;
			}
			
			list.SortItems();
			
			return list;
		}
		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)));
		}
        public CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch)
        {
            XamlCompletionContext  context = CompletionDataHelper.ResolveCompletionContext(editor, ch);
            XamlCompletionItemList list;

            if (context.Description == XamlContextDescription.InComment || context.Description == XamlContextDescription.InCData)
            {
                return(CodeCompletionKeyPressResult.None);
            }

            switch (ch)
            {
            case '<':
                context.Description = (context.Description == XamlContextDescription.None) ? XamlContextDescription.AtTag : context.Description;
                list = CompletionDataHelper.CreateListForContext(context);
                editor.ShowCompletionWindow(list);
                return(CodeCompletionKeyPressResult.Completed);

            case '>':
                return(CodeCompletionKeyPressResult.None);

            case '\'':
            case '"':
                if (!XmlParser.IsInsideAttributeValue(editor.Document.Text, editor.Caret.Offset))
                {
                    // count all " or ' chars before the next > char
                    int  search         = editor.Caret.Offset + 1;
                    int  endMarkerCount = 1;
                    char curCh          = editor.Document.GetCharAt(search);
                    while (search < editor.Document.TextLength - 1 && curCh != '>')
                    {
                        if (curCh == ch)
                        {
                            endMarkerCount++;
                        }
                        search++;
                        curCh = editor.Document.GetCharAt(search);
                    }
                    // if the count is odd we need to add an additional " or ' char
                    if (endMarkerCount % 2 != 0)
                    {
                        editor.Document.Insert(editor.Caret.Offset, ch.ToString());
                        editor.Caret.Offset--;
                        this.CtrlSpace(editor);
                        return(CodeCompletionKeyPressResult.Completed);
                    }
                }
                break;

            case '{':                     // starting point for Markup Extension Completion
                if (context.Attribute != null &&
                    XmlParser.IsInsideAttributeValue(editor.Document.Text, editor.Caret.Offset) &&
                    !(context.RawAttributeValue.StartsWith("{}", StringComparison.OrdinalIgnoreCase) && context.RawAttributeValue.Length != 2))
                {
                    if (editor.SelectionLength != 0)
                    {
                        editor.Document.Remove(editor.SelectionStart, editor.SelectionLength);
                    }

                    editor.Document.Insert(editor.Caret.Offset, "{}");
                    editor.Caret.Offset--;

                    this.CtrlSpace(editor);
                    return(CodeCompletionKeyPressResult.EatKey);
                }
                break;

            case '.':
                switch (context.Description)
                {
                case XamlContextDescription.AtTag:
                case XamlContextDescription.InTag:
                    if (context.ActiveElement != null && !XmlParser.IsInsideAttributeValue(editor.Document.Text, editor.Caret.Offset))
                    {
                        list = CompletionDataHelper.CreateListForContext(context);
                        editor.ShowCompletionWindow(list);
                        return(CodeCompletionKeyPressResult.Completed);
                    }
                    break;

                case XamlContextDescription.InMarkupExtension:
                    if (DoMarkupExtensionCompletion(context))
                    {
                        return(CodeCompletionKeyPressResult.Completed);
                    }
                    break;

                case 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 ':':
                if (context.ActiveElement != null && XmlParser.GetQualifiedAttributeNameAtIndex(editor.Document.Text, editor.Caret.Offset) == null)
                {
                    if (context.Attribute != null && !context.Attribute.Name.StartsWith("xmlns", StringComparison.OrdinalIgnoreCase))
                    {
                        list = CompletionDataHelper.CreateListForContext(context);
                        list.PreselectionLength = editor.GetWordBeforeCaretExtended().Length;
                        editor.ShowCompletionWindow(list);
                        return(CodeCompletionKeyPressResult.CompletedIncludeKeyInCompletion);
                    }
                }
                break;

            case '/':                     // ignore '/' when trying to type '/>'
                return(CodeCompletionKeyPressResult.None);

            case '=':
                if (!XmlParser.IsInsideAttributeValue(editor.Document.Text, editor.Caret.Offset))
                {
                    int searchOffset = editor.Caret.Offset;

                    if (editor.SelectionLength != 0)
                    {
                        editor.Document.Remove(editor.SelectionStart, editor.SelectionLength);
                    }

                    while (searchOffset < editor.Document.TextLength - 1)
                    {
                        searchOffset++;
                        if (!char.IsWhiteSpace(editor.Document.GetCharAt(searchOffset)))
                        {
                            break;
                        }
                    }

                    if (searchOffset >= editor.Document.TextLength || editor.Document.GetCharAt(searchOffset) != '"')
                    {
                        editor.Document.Insert(editor.Caret.Offset, "=\"\"");
                        editor.Caret.Offset--;
                    }
                    else
                    {
                        editor.Document.Insert(editor.Caret.Offset, "=");
                        editor.Caret.Offset++;
                    }

                    this.CtrlSpace(editor);
                    return(CodeCompletionKeyPressResult.EatKey);
                }
                else
                {
                    DoMarkupExtensionCompletion(context);
                    return(CodeCompletionKeyPressResult.Completed);
                }

            default:
                if (context.Description != XamlContextDescription.None && !char.IsWhiteSpace(ch))
                {
                    string starter = editor.GetWordBeforeCaretExtended();
                    if (!string.IsNullOrEmpty(starter))
                    {
                        return(CodeCompletionKeyPressResult.None);
                    }
                    trackForced = false;

                    string attributeName = (context.Attribute != null) ? context.Attribute.Name : string.Empty;

                    if (!attributeName.StartsWith("xmlns", StringComparison.OrdinalIgnoreCase))
                    {
                        return(this.CtrlSpace(editor)
                                                                ? CodeCompletionKeyPressResult.CompletedIncludeKeyInCompletion
                                                                : CodeCompletionKeyPressResult.None);
                    }
                    trackForced = true;
                    return(CodeCompletionKeyPressResult.None);
                }
                break;
            }

            return(CodeCompletionKeyPressResult.None);
        }
		/// <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;
		}
        public bool CtrlSpace(ITextEditor editor)
        {
            XamlCompletionContext context = CompletionDataHelper.ResolveCompletionContext(editor, ' ');

            context.Forced = trackForced;

            if (context.Description == XamlContextDescription.InComment || context.Description == XamlContextDescription.InCData)
            {
                return(false);
            }

            if (context.ActiveElement != null)
            {
                if (!XmlParser.IsInsideAttributeValue(editor.Document.Text, editor.Caret.Offset) && context.Description != XamlContextDescription.InAttributeValue)
                {
                    XamlCompletionItemList list = CompletionDataHelper.CreateListForContext(context);
                    string starter = editor.GetWordBeforeCaretExtended().TrimStart('/');
                    if (context.Description != XamlContextDescription.None && !string.IsNullOrEmpty(starter))
                    {
                        if (starter.Contains("."))
                        {
                            list.PreselectionLength = starter.Length - starter.IndexOf('.') - 1;
                        }
                        else
                        {
                            list.PreselectionLength = starter.Length;
                        }
                    }
                    editor.ShowCompletionWindow(list);
                    return(true);
                }
                else
                {
                    // DO NOT USE CompletionDataHelper.CreateListForContext here!!! results in endless recursion!!!!
                    if (context.Attribute != null)
                    {
                        if (!DoMarkupExtensionCompletion(context))
                        {
                            var completionList = new XamlCompletionItemList(context);
                            completionList.PreselectionLength = editor.GetWordBeforeCaretExtended().Length;

                            if ((context.ActiveElement.Name == "Setter" || context.ActiveElement.Name == "EventSetter") &&
                                (context.Attribute.Name == "Property" || context.Attribute.Name == "Value"))
                            {
                                DoSetterAndEventSetterCompletion(context, completionList);
                            }
                            else if ((context.ActiveElement.Name.EndsWith("Trigger") || context.ActiveElement.Name == "Condition") && context.Attribute.Name == "Value")
                            {
                                DoTriggerCompletion(context, completionList);
                            }
                            else
                            {
                                if (context.Attribute.Name == "xml:space")
                                {
                                    completionList.Items.AddRange(new[] { new SpecialCompletionItem("preserve"),
                                                                          new SpecialCompletionItem("default") });
                                }

                                var mrr = XamlResolver.Resolve(context.Attribute.Name, context) as MemberResolveResult;
                                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;
                                    }
                                    else if (mrr.ResolvedType.FullyQualifiedName == "System.Windows.Media.FontFamily")
                                    {
                                        string text      = context.ValueStartOffset > -1 ? context.RawAttributeValue.Substring(0, Math.Min(context.ValueStartOffset, context.RawAttributeValue.Length)) : "";
                                        int    lastComma = text.LastIndexOf(',');
                                        completionList.PreselectionLength = lastComma == -1 ? context.ValueStartOffset : context.ValueStartOffset - lastComma - 1;
                                    }
                                }
                            }

                            completionList.SortItems();

                            if (context.Attribute.Prefix.Equals("xmlns", StringComparison.OrdinalIgnoreCase) ||
                                context.Attribute.Name.Equals("xmlns", StringComparison.OrdinalIgnoreCase))
                            {
                                completionList.Items.AddRange(CompletionDataHelper.CreateListForXmlnsCompletion(context.ProjectContent));
                            }

                            ICompletionListWindow window = editor.ShowCompletionWindow(completionList);

                            if ((context.Attribute.Prefix.Equals("xmlns", StringComparison.OrdinalIgnoreCase) ||
                                 context.Attribute.Name.Equals("xmlns", StringComparison.OrdinalIgnoreCase)) && window != null)
                            {
                                window.Width = 400;
                            }

                            return(completionList.Items.Any());
                        }
                        return(true);
                    }
                }
            }
            return(false);
        }
		void DoStaticTypeCompletion(AttributeValue selItem, XamlCompletionItemList list, XamlCompletionContext context)
		{
			var items = GetClassesFromContext(context);
			foreach (var ns in items) {
				string key = ns.Key;
				if (!string.IsNullOrEmpty(key)) key += ":";
				list.Items.AddRange(
					ns.Value
					.Where(c => c.Fields.Any(f => f.IsStatic) || c.Properties.Any(p => p.IsStatic))
					.Select(c => new XamlCompletionItem(key + c.Name, c))
				);
			}
			if (selItem != null && selItem.IsString) {
				list.PreselectionLength = selItem.StringValue.Length;
			}
		}
		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;
		}
		public IEnumerable<ICompletionItem> FindMatchingEventHandlers(XamlCompletionContext context, IEvent member, string targetName)
		{
			ITypeDefinition td = member.ReturnType.GetDefinition();
			if (td == null) yield break;

			IMethod delegateInvoker = td.GetMethods(m => m.Name == "Invoke").FirstOrDefault();
			if (delegateInvoker == null) yield break;
			
			if (context.ParseInformation == null)
				yield break;
			
			var file = context.ParseInformation.UnresolvedFile;
			var loc = context.Editor.Caret.Location;
			var unresolved = file.GetInnermostTypeDefinition(loc.Line, loc.Column);
			if (unresolved == null)
				yield break;
			IType type = unresolved.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)).GetDefinition();
			foreach (IMethod method in type.GetMethods(m => m.Parameters.Count == delegateInvoker.Parameters.Count)) {
				if (!method.ReturnType.Equals(delegateInvoker.ReturnType))
					continue;
				
				if (method.Parameters.SequenceEqual(delegateInvoker.Parameters, new ParameterComparer())) {
					yield return new XamlCompletionItem(method);
				}
			}
			
			yield return new NewEventCompletionItem(member, targetName);
		}
        static void DoSetterAndEventSetterCompletion(XamlCompletionContext context, XamlCompletionItemList completionList)
        {
            bool           isExplicit;
            string         element = context.ParentElement.Name.EndsWith("Trigger") ? "Trigger" : context.ParentElement.Name;
            AttributeValue value   = MarkupExtensionParser.ParseValue(CompletionDataHelper.LookForTargetTypeValue(context, out isExplicit, element) ?? string.Empty);

            IReturnType typeName       = null;
            string      typeNameString = null;

            if (!value.IsString)
            {
                typeNameString = CompletionDataHelper.GetTypeNameFromTypeExtension(value.ExtensionValue, context);
                typeName       = CompletionDataHelper.ResolveType(typeNameString, context);
            }
            else
            {
                typeNameString = value.StringValue;
                typeName       = CompletionDataHelper.ResolveType(value.StringValue, context);
            }

            if (typeName != null)
            {
                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;
                    }

                    var member = XamlResolver.Resolve(name, context) as MemberResolveResult;

                    if (member == null || member.ResolvedMember == null)
                    {
                        break;
                    }

                    completionList.Items.AddRange(
                        CompletionDataHelper.MemberCompletion(context, member.ResolvedMember.ReturnType, string.Empty)
                        );
                    break;

                case "Property":
                    completionList.Items.AddRange(
                        typeName.GetProperties()
                        .Where(p => p.IsPublic && p.CanSet)
                        .Select(prop => new XamlCodeCompletionItem(prop))
                        );
                    break;

                case "Event":
                    completionList.Items.AddRange(
                        typeName.GetEvents()
                        .Where(e => e.IsPublic)
                        .Select(evt => new XamlCodeCompletionItem(evt))
                        );
                    break;

                case "Handler":
                    var            loc3    = context.Editor.Document.OffsetToPosition(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;
                    }

                    var evtMember = XamlResolver.Resolve(evtName, context) as MemberResolveResult;

                    if (evtMember == null || evtMember.ResolvedMember == null || !(evtMember.ResolvedMember is IEvent) || evtMember.ResolvedMember.ReturnType == null)
                    {
                        break;
                    }

                    IClass c = (evtMember.ResolvedMember as IEvent).ReturnType.GetUnderlyingClass();

                    if (c == null)
                    {
                        break;
                    }

                    IMethod invoker = c.Methods.FirstOrDefault(m => m.Name == "Invoke");

                    if (invoker == null)
                    {
                        break;
                    }

                    completionList.Items.AddRange(
                        CompletionDataHelper.AddMatchingEventHandlers(context, invoker).Add(new NewEventCompletionItem(evtMember.ResolvedMember as IEvent, typeName.Name))
                        );
                    break;
                }
            }
        }
		IList<ICompletionItem> CreatePropertyPathCompletion(XamlCompletionContext context)
		{
			bool isExplicit;
			IType typeName = GetType(context, out isExplicit);
			IList<ICompletionItem> list = new List<ICompletionItem>();
			
			string value = context.ValueStartOffset > -1 ? context.RawAttributeValue.Substring(0, Math.Min(context.ValueStartOffset + 1, context.RawAttributeValue.Length)) : "";
			
			if (value.EndsWithAny(']', ')'))
				return list;
			
			var segments = PropertyPathParser.Parse(value).ToList();
			
			int completionStart;
			bool isAtDot = false;
			
			IType 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;
		}
Exemple #50
0
		/// <summary>
		/// Returns the list of allow XAML2009 completion items.
		/// </summary>
		public static IEnumerable<string> GetAllowedItems(XamlCompletionContext context)
		{
			string xamlPrefix = context.XamlNamespacePrefix;
			string xKey = string.IsNullOrEmpty(xamlPrefix) ? "" : xamlPrefix + ":";
			var compilation = SD.ParserService.GetCompilationForFile(context.Editor.FileName);
			var resolver = new XamlAstResolver(compilation, context.ParseInformation);
			// TODO : add support for x:Key as attribute element (XAML 2009 only)
			
			switch (context.Description) {
				case XamlContextDescription.AtTag:
					if (context.ParentElement != null && string.Equals(context.ParentElement.Name, xKey + "Members", StringComparison.OrdinalIgnoreCase)) {
						yield return xKey + "Member";
						yield return xKey + "Property";
					} else if (context.ParentElement == context.RootElement && context.RootElement.Attributes.Any(attr => string.Equals(attr.Name, xKey + "Class", StringComparison.OrdinalIgnoreCase))) {
						yield return xKey + "Code";
						yield return xKey + "Members";
					} else {
						if (context.ParentElement != null && string.Equals(context.ParentElement.Name, xKey + "Code", StringComparison.OrdinalIgnoreCase))
							yield break;
						yield return xKey + "Array";
						yield return xKey + "Boolean";
						yield return xKey + "Byte";
						yield return xKey + "Char";
						yield return xKey + "Decimal";
						yield return xKey + "Dictionary";
						yield return xKey + "Double";
						yield return xKey + "Int16";
						yield return xKey + "Int32";
						yield return xKey + "Int64";
						yield return xKey + "List";
						yield return xKey + "Object";
						yield return xKey + "Reference";
						yield return xKey + "Single";
						yield return xKey + "String";
						yield return xKey + "TimeSpan";
						yield return xKey + "Uri";
						if (context.RootElement.Attributes.Any(attr => string.Equals(attr.Name, xKey + "Class", StringComparison.OrdinalIgnoreCase)))
							yield return xKey + "Members";
					}
					break;
				case XamlContextDescription.InTag:
					yield return xKey + "Uid";
					if (context.InRoot) {
						yield return xKey + "Class";
						yield return xKey + "ClassModifier";
						yield return xKey + "Subclass";
						yield return xKey + "Name";
					} else {
						var resourceDictionaryType = compilation.FindType(typeof(ResourceDictionary));
						if (context.ActiveElement != null && string.Equals(context.ActiveElement.Name, xKey + "Array", StringComparison.OrdinalIgnoreCase)) {
							yield return "Type";
						} else if (context.ActiveElement != null && string.Equals(context.ActiveElement.Name, xKey + "Member", StringComparison.OrdinalIgnoreCase)) {
							yield return "Name";
						} else if (context.ActiveElement != null && string.Equals(context.ActiveElement.Name, xKey + "Property", StringComparison.OrdinalIgnoreCase)) {
							yield return "Name";
							yield return "Type";
						} else if (context.RootElement.Attributes.Any(attr => string.Equals(attr.Name, xKey + "Class", StringComparison.OrdinalIgnoreCase))) {
							yield return xKey + "FieldModifier";
							yield return xKey + "Name";
						} else {
							yield return xKey + "Name";
						}
						
						if (context.ParentElement != null) {
							var rr = resolver.ResolveElement(context.ParentElement);
							if (rr != null) {
								if (rr.Type.Equals(resourceDictionaryType)) {
									yield return xKey + "Key";
									yield return xKey + "Shared";
								} else if (rr.Type.TypeParameterCount > 0) {
									yield return xKey + "TypeArguments";
								}
							}
						}
					}
					break;
			}
			yield break;
		}
		static IType ResolvePropertyPath(IList<PropertyPathSegment> segments, XamlCompletionContext context, IType parentType, out int lastIndex)
		{
			IType type = parentType;
			
			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(p => p.IsIndexer).FirstOrDefault();
							if (prop != null) {
								type = prop.ReturnType;
							}
						}
						break;
					case SegmentKind.SourceTraversal:
						// ignore
						return null;
				}
			}
			
			return type;
		}
		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;
		}
		static bool CreateEventHandlerCode(XamlCompletionContext context, NewEventCompletionItem completionItem)
		{
			IProject project = SD.ProjectService.FindProjectContainingFile(context.Editor.FileName);
			if (project == null) return false;
			var unresolved = context.ParseInformation.UnresolvedFile.TypeDefinition;
			if (unresolved == null) return false;
			var compilation = SD.ParserService.GetCompilationForFile(context.Editor.FileName);
			var definition = unresolved.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly)).GetDefinition();
			project.LanguageBinding.CodeGenerator.InsertEventHandler(definition, completionItem.HandlerName, completionItem.EventType, true);
			return true;
		}
		IList<ICompletionItem> CreateAttributeList(XamlCompletionContext context, bool includeEvents)
		{
			if (context.ParseInformation == null)
				return EmptyList<ICompletionItem>.Instance;
			AXmlElement lastElement = context.ActiveElement;
			IUnresolvedFile file = context.ParseInformation.UnresolvedFile;
			XamlResolver resolver = new XamlResolver(compilation);
			IType type = resolver.ResolveType(lastElement.Namespace, lastElement.LocalName.Trim('.'));
			
			var list = new List<ICompletionItem>();
			
			string xamlPrefix = context.XamlNamespacePrefix;
			string xKey = string.IsNullOrEmpty(xamlPrefix) ? "" : xamlPrefix + ":";
			
			if (context.Description == XamlContextDescription.InTag)
				list.AddRange(XamlConst.GetAllowedItems(context).Select(item => new XamlCompletionItem(item)));
			
			if (string.Equals(lastElement.Prefix, context.XamlNamespacePrefix, StringComparison.OrdinalIgnoreCase) && XamlConst.IsBuiltin(lastElement.LocalName))
				return list;
			
			if (lastElement.LocalName.EndsWith(".", StringComparison.OrdinalIgnoreCase) || context.PressedKey == '.') {
				if (type.Kind == TypeKind.Unknown)
					return EmptyList<ICompletionItem>.Instance;
				
				if (context.ParentElement != null
				    && context.ParentElement.LocalName.StartsWith(lastElement.LocalName.TrimEnd('.'), StringComparison.OrdinalIgnoreCase)) {
					AddAttributes(type, list, includeEvents);
				}
				AddAttachedProperties(type.GetDefinition(), list);
			} else {
				if (type.Kind != TypeKind.Unknown) {
					AddAttributes(type, list, includeEvents);
					list.AddRange(GetListOfAttached(context, null, includeEvents, true));
				}
			}
			
			return list;
		}
		void DoTriggerCompletion(XamlCompletionContext context, XamlCompletionItemList completionList) {
			bool isExplicit;
			AttributeValue value = MarkupExtensionParser.ParseValue(Utils.LookForTargetTypeValue(context, out isExplicit, "Trigger") ?? string.Empty);
			string typeNameString;
			var rr = resolver.ResolveAttributeValue(context, value, out typeNameString);
			var typeName = rr.Type;

			if (typeName != null) {
				switch (context.Attribute.Name) {
					case "Value":
						AttributeValue propType = MarkupExtensionParser.ParseValue(context.ActiveElement.GetAttributeValue("Property") ?? "");
						if (!propType.IsString)
							break;

						string name = propType.StringValue;

						if (!name.Contains("."))
							name = typeNameString + "." + name;

						context.Description = XamlContextDescription.AtTag;

						var 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;
				}
			}
		}
		public IEnumerable<ICompletionItem> MemberCompletion(XamlCompletionContext context, IType type, string textPrefix = "")
		{
			ITextEditor editor = context.Editor;
			compilation = SD.ParserService.GetCompilationForFile(editor.FileName);
			
			string xamlPrefix = context.XamlNamespacePrefix;
			string xKey = string.IsNullOrEmpty(xamlPrefix) ? "" : xamlPrefix + ":";
			
			if (type.Name == typeof(System.Nullable<>).Name) {
				yield return new XamlCompletionItem("{" + xKey + "Null}");
				type = type.TypeArguments.FirstOrDefault();
				if (type == null) yield break;
			}
			
			ITypeDefinition definition = type.GetDefinition();
			
			if (definition == null) yield break;
			
			definition.IsCollectionType();
			
			switch (definition.KnownTypeCode) {
				case KnownTypeCode.Array:
				case KnownTypeCode.ICollection:
				case KnownTypeCode.ICollectionOfT:
				case KnownTypeCode.IEnumerable:
				case KnownTypeCode.IEnumerableOfT:
					yield return new XamlCompletionItem("{" + xKey + "Array}");
					break;
			}
			
			switch (definition.Kind) {
				case TypeKind.Class:
					IType typeName;
					bool isExplicit, showFull = false;
					switch (definition.FullName) {
						case "System.String":
							// return nothing
							break;
						case "System.Type":
							foreach (var item in CreateElementList(context, true))
								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", StringComparison.Ordinal);
							
							if (!isExplicit && ((context.ValueStartOffset > 0) ? context.RawAttributeValue.Substring(0, context.ValueStartOffset) : "").Contains("."))
								showFull = true;
							
							if (typeName != null) {
								foreach (var item in typeName.GetDependencyProperties(true, !isExplicit, !isReadOnly, showFull))
									yield return item;
							}
							break;
						case "System.Windows.RoutedEvent":
							typeName = GetType(context, out isExplicit);
							
							if (!isExplicit && ((context.ValueStartOffset > 0) ? context.RawAttributeValue.Substring(0, context.ValueStartOffset) : "").Contains("."))
								showFull = true;
							
							if (typeName != null) {
								foreach (var item in typeName.GetRoutedEvents(true, !isExplicit, showFull))
									yield return item;
							}
							break;
						case "System.Windows.Media.FontFamily":
							foreach (var font in Fonts.SystemFontFamilies)
								yield return new XamlCompletionItem(font.FamilyNames.First().Value) { Image = ClassBrowserIconService.Const };
							break;
						default:
							if (context.Description == XamlContextDescription.InMarkupExtension) {
								foreach (IField f in definition.Fields)
									yield return new XamlCompletionItem(textPrefix + f.Name, f);
								foreach (IProperty p in definition.GetProperties(pr => pr.IsPublic && pr.IsStatic && pr.CanGet))
									yield return new XamlCompletionItem(textPrefix + p.Name, p);
							}
							break;
					}
					break;
				case TypeKind.Enum:
					foreach (IField f in definition.Fields)
						yield return new XamlCompletionItem(textPrefix + f.Name, f);
					foreach (IProperty p in definition.Properties.Where(pr => pr.IsPublic && pr.IsStatic && pr.CanGet))
						yield return new XamlCompletionItem(textPrefix + p.Name, p);
					break;
				case TypeKind.Struct:
					switch (definition.FullName) {
						case "System.Boolean":
							yield return new DefaultCompletionItem("True") { Image = ClassBrowserIconService.Const };
							yield return new DefaultCompletionItem("False") { Image = ClassBrowserIconService.Const };
							break;
						case "System.Windows.GridLength":
							yield return new XamlCompletionItem("Auto") { Image = ClassBrowserIconService.Const };
							yield return new XamlCompletionItem("*") { Image = ClassBrowserIconService.Const };
							break;
					}
					break;
				case TypeKind.Delegate:
					foreach (var item in CreateEventCompletion(context, definition))
						yield return item;
					break;
			}
			
			var classes = definition.ParentAssembly
				.GetAllTypeDefinitions()
				.Where(cla => cla.FullName == definition.FullName + "s" ||
				       cla.FullName == definition.FullName + "es");
			foreach (var coll in classes) {
				foreach (var item in coll.Properties)
					yield return new XamlCompletionItem(item);
				foreach (var item in coll.Fields.Where(f => f.IsPublic && f.IsStatic && f.ReturnType.FullName == definition.FullName))
					yield return new XamlCompletionItem(item);
			}
		}
		bool DoAttributeCompletion(XamlCompletionContext context, XamlCompletionItemList completionList)
		{
			XamlAstResolver resolver = new XamlAstResolver(compilation, context.ParseInformation);
			ITextEditor editor = context.Editor;
			var mrr = resolver.ResolveAttribute(context.Attribute) as MemberResolveResult;
			if (mrr != null && mrr.Type.Kind != TypeKind.Unknown) {
				completionList.Items.AddRange(generator.MemberCompletion(context, mrr.Type, string.Empty));
				editor.ShowInsightWindow(generator.MemberInsight(mrr));
				editor.ShowCompletionWindow(completionList);
				switch (mrr.Type.FullName) {
					case "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;
						break;
					case "System.Windows.Media.FontFamily":
						string text = context.ValueStartOffset > -1 ? context.RawAttributeValue.Substring(0, Math.Min(context.ValueStartOffset, context.RawAttributeValue.Length)) : "";
						int lastComma = text.LastIndexOf(',');
						completionList.PreselectionLength = lastComma == -1 ? context.ValueStartOffset : context.ValueStartOffset - lastComma - 1;
						break;
				}
			}
			
			return completionList.Items.Any();
		}
		public IEnumerable<IInsightItem> CreateMarkupExtensionInsight(XamlCompletionContext context)
		{
			var markup = Utils.GetMarkupExtensionAtPosition(context.AttributeValue.ExtensionValue, context.ValueStartOffset);
			var resolver = new XamlResolver(compilation);
			var type = (resolver.ResolveExpression(markup.ExtensionType, context) ?? resolver.ResolveExpression(markup.ExtensionType + "Extension", context)).Type;
			
			if (type != null) {
				var ctors = type
					.GetMethods(m => m.IsPublic && m.IsConstructor && m.Parameters.Count >= markup.PositionalArguments.Count)
					.OrderBy(m => m.Parameters.Count);
				
				foreach (var ctor in ctors)
					yield return new MarkupExtensionInsightItem(ctor);
			}
		}
		bool DoMarkupExtensionCompletion(XamlCompletionContext context)
		{
			if (context.Description == XamlContextDescription.InMarkupExtension && context.AttributeValue != null && !context.AttributeValue.IsString) {
				if (!XamlBindingOptions.UseExtensionCompletion)
					return false;
				XamlCompletionItemList completionList = generator.CreateMarkupExtensionCompletion(context) as XamlCompletionItemList;
				string word = context.Editor.GetWordBeforeCaretExtended();
				if (context.PressedKey != '.' && context.PressedKey != '=' && !word.EndsWith(".", StringComparison.Ordinal) && completionList.PreselectionLength == 0)
					completionList.PreselectionLength = word.Length;
				var insightList = generator.CreateMarkupExtensionInsight(context);
				context.Editor.ShowInsightWindow(insightList);
				context.Editor.ShowCompletionWindow(completionList);
				return completionList.Items.Any() || insightList.Any();
			}

			return false;
		}
        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++;
                }
            }
        }