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;
            }
        }
Exemplo n.º 2
0
        public override void Complete(CompletionContext context, ICompletionItem item)
        {
            using (context.Editor.Document.OpenUndoGroup()) {
                base.Complete(context, item);

                XamlCompletionContext xamlContext = CompletionDataHelper.ResolveCompletionContext(context.Editor, context.CompletionChar);

                if (xamlContext.Description == XamlContextDescription.None && (context.StartOffset <= 0 || context.Editor.Document.GetCharAt(context.StartOffset - 1) != '<'))
                {
                    context.Editor.Document.Insert(context.StartOffset, "<");
                    context.EndOffset++;
                }

                if (item is XamlCodeCompletionItem)
                {
                    XamlCodeCompletionItem cItem = item as XamlCodeCompletionItem;

                    if (cItem.Entity is IProperty || cItem.Entity is IEvent)
                    {
                        if (xamlContext.Description == XamlContextDescription.InTag)
                        {
                            context.Editor.Document.Insert(context.EndOffset, "=\"\"");
                            context.CompletionCharHandled = context.CompletionChar == '=';
                            context.Editor.Caret.Offset--;
                            new XamlCodeCompletionBinding().CtrlSpace(context.Editor);
                        }
                        else if (xamlContext.Description == XamlContextDescription.InMarkupExtension && !string.IsNullOrEmpty(xamlContext.RawAttributeValue))
                        {
                            string         valuePart = xamlContext.RawAttributeValue.Substring(0, xamlContext.ValueStartOffset);
                            AttributeValue value     = MarkupExtensionParser.ParseValue(valuePart);

                            if (value != null && !value.IsString)
                            {
                                var markup = Utils.GetMarkupExtensionAtPosition(value.ExtensionValue, context.Editor.Caret.Offset);
                                if (markup.NamedArguments.Count > 0 || markup.PositionalArguments.Count > 0)
                                {
                                    int oldOffset = context.Editor.Caret.Offset;
                                    context.Editor.Caret.Offset = context.StartOffset;
                                    string word          = context.Editor.GetWordBeforeCaret().TrimEnd();
                                    int    spaces        = CountWhiteSpacesAtEnd(context.Editor.GetWordBeforeCaret());
                                    int    typeNameStart = markup.ExtensionType.IndexOf(':') + 1;

                                    if (!(word == "." || word == "," || word == ":") && markup.ExtensionType.Substring(typeNameStart, markup.ExtensionType.Length - typeNameStart) != word)
                                    {
                                        context.Editor.Document.Replace(context.Editor.Caret.Offset - spaces, spaces, ", ");
                                        oldOffset += (2 - spaces);
                                    }

                                    context.Editor.Caret.Offset = oldOffset;
                                }
                            }

                            if (cItem.Text.EndsWith("=", StringComparison.OrdinalIgnoreCase))
                            {
                                new XamlCodeCompletionBinding().CtrlSpace(context.Editor);
                            }
                        }
                    }
                }

                if (item is NewEventCompletionItem)
                {
                    NewEventCompletionItem eventItem = item as NewEventCompletionItem;
                    int discriminator;
                    if (CreateEventHandlerCode(context, eventItem, out discriminator))
                    {
                        if (discriminator > 0)
                        {
                            context.Editor.Document.Insert(context.EndOffset, discriminator.ToString());
                        }
                    }
                }

                if (item is XmlnsCompletionItem)
                {
                    context.Editor.Caret.Offset++;
                }

                if (item is XamlCompletionItem && xamlContext.Description == XamlContextDescription.InTag)
                {
                    context.Editor.Document.Insert(context.EndOffset, "=\"\"");
                    context.Editor.Caret.Offset--;
                    new XamlCodeCompletionBinding().CtrlSpace(context.Editor);
                }

                switch (item.Text)
                {
                case "![CDATA[":
                    context.Editor.Document.Insert(context.Editor.Caret.Offset, "]]>");
                    context.Editor.Caret.Offset -= 3;
                    break;

                case "?":
                    context.Editor.Document.Insert(context.Editor.Caret.Offset, "?>");
                    context.Editor.Caret.Offset -= 2;
                    break;

                case "!--":
                    context.Editor.Document.Insert(context.Editor.Caret.Offset, "  -->");
                    context.Editor.Caret.Offset -= 4;
                    break;
                }

                if (item.Text.StartsWith("/", StringComparison.OrdinalIgnoreCase))
                {
                    context.Editor.Document.Insert(context.EndOffset, ">");
                    context.CompletionCharHandled = context.CompletionChar == '>';
                    context.Editor.Caret.Offset++;
                }
            }
        }
        public static XamlContext ResolveContext(FileName fileName, ITextSource fileContent, int offset)
        {
            XamlFullParseInformation info = SD.ParserService.Parse(fileName, fileContent) as XamlFullParseInformation;

            if (info == null)
            {
                throw new Exception("need full parse info!");
            }

            AXmlDocument document    = info.Document;
            AXmlObject   currentData = document.GetChildAtOffset(offset);

            string         attributeName = string.Empty, attributeValue = string.Empty;
            AttributeValue value                = null;
            bool           isRoot               = false;
            bool           wasAXmlElement       = false;
            int            offsetFromValueStart = -1;

            List <AXmlElement> ancestors             = new List <AXmlElement>();
            Dictionary <string, XamlNamespace> xmlns = new Dictionary <string, XamlNamespace>();
            List <string> ignored             = new List <string>();
            string        xamlNamespacePrefix = string.Empty;

            var         item = currentData;
            AXmlElement root = null;

            while (item != document)
            {
                if (item is AXmlElement)
                {
                    AXmlElement element = item as AXmlElement;
                    ancestors.Add(element);
                    foreach (var attr in element.Attributes)
                    {
                        if (attr.IsNamespaceDeclaration)
                        {
                            string prefix = (attr.Name == "xmlns") ? "" : attr.LocalName;
                            if (!xmlns.ContainsKey(prefix))
                            {
                                xmlns.Add(prefix, new XamlNamespace(attr.Value));
                            }
                        }

                        if (attr.LocalName == "Ignorable" && attr.Namespace == XamlConst.MarkupCompatibilityNamespace)
                        {
                            ignored.AddRange(attr.Value.Split(' ', '\t'));
                        }

                        if (string.IsNullOrEmpty(xamlNamespacePrefix) && attr.Value == XamlConst.XamlNamespace)
                        {
                            xamlNamespacePrefix = attr.LocalName;
                        }
                    }

                    if (element.Parent is AXmlDocument)
                    {
                        root = element;
                        if (!wasAXmlElement)
                        {
                            isRoot = true;
                        }
                    }

                    wasAXmlElement = true;
                }

                item = item.Parent;
            }

            XamlContextDescription description = XamlContextDescription.None;

            AXmlElement active = null;
            AXmlElement parent = null;

            if (currentData is AXmlAttribute)
            {
                AXmlAttribute a = currentData as AXmlAttribute;
                int           valueStartOffset = a.ValueSegment.Offset + 1;
                attributeName  = a.Name;
                attributeValue = a.Value;
                value          = MarkupExtensionParser.ParseValue(attributeValue);

                if (offset >= valueStartOffset && (offset < a.EndOffset ||              // if length is < 2 one quote is missing
                                                   (a.ValueSegment.Length <= 1 && offset <= a.EndOffset)))
                {
                    offsetFromValueStart = offset - valueStartOffset;

                    description = XamlContextDescription.InAttributeValue;

                    if (value != null && !value.IsString)
                    {
                        description = XamlContextDescription.InMarkupExtension;
                    }
                    if (attributeValue.StartsWith("{}", StringComparison.Ordinal) && attributeValue.Length > 2)
                    {
                        description = XamlContextDescription.InAttributeValue;
                    }
                }
                else
                {
                    description = XamlContextDescription.InTag;
                }
                active = a.ParentElement;
            }
            else if (currentData is AXmlTag)
            {
                AXmlTag tag = currentData as AXmlTag;
                if (tag.IsStartOrEmptyTag || tag.IsEndTag)
                {
                    if (tag.NameSegment.EndOffset < offset)
                    {
                        description = XamlContextDescription.InTag;
                    }
                    else
                    {
                        description = XamlContextDescription.AtTag;
                    }
                }
                else if (tag.IsComment)
                {
                    description = XamlContextDescription.InComment;
                }
                else if (tag.IsCData)
                {
                    description = XamlContextDescription.InCData;
                }
                active = tag.Parent as AXmlElement;
            }

            if (active != ancestors.FirstOrDefault())
            {
                parent = ancestors.FirstOrDefault();
            }
            else
            {
                parent = ancestors.Skip(1).FirstOrDefault();
            }

            if (active == null)
            {
                active = parent;
            }

            var xAttribute = currentData as AXmlAttribute;

            var context = new XamlContext()
            {
                Description         = description,
                ActiveElement       = active,
                ParentElement       = parent,
                RootElement         = root,
                Ancestors           = ancestors.AsReadOnly(),
                Attribute           = xAttribute,
                InRoot              = isRoot,
                AttributeValue      = value,
                RawAttributeValue   = attributeValue,
                ValueStartOffset    = offsetFromValueStart,
                XmlnsDefinitions    = xmlns,
                ParseInformation    = info,
                IgnoredXmlns        = ignored.AsReadOnly(),
                XamlNamespacePrefix = xamlNamespacePrefix
            };

            return(context);
        }
        void DoSetterAndEventSetterCompletion(XamlCompletionContext context, XamlCompletionItemList completionList)
        {
            string typeNameString;
            int    dotIndex;
            IType  typeName = ResolveTargetType(context, out typeNameString, out dotIndex,
                                                string.Equals(context.Attribute.Name, "Property") ||
                                                string.Equals(context.Attribute.Name, "Event"));

            MemberResolveResult mrr;

            switch (context.Attribute.Name)
            {
            case "Value":
                AttributeValue propType = MarkupExtensionParser.ParseValue(context.ActiveElement.GetAttributeValue("Property") ?? "");

                if (!propType.IsString)
                {
                    break;
                }

                context.Description = XamlContextDescription.AtTag;

                string name = propType.StringValue;

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

                mrr = resolver.ResolveExpression(name, context) as MemberResolveResult;

                if (mrr == null || mrr.Member == null)
                {
                    break;
                }

                completionList.Items.AddRange(
                    generator.MemberCompletion(context, mrr.Member.ReturnType, string.Empty)
                    );
                break;

            case "Property":
                completionList.Items.AddRange(
                    typeName.GetProperties()
                    .Where(p => p.IsPublic && p.CanSet)
                    .Select(prop => new XamlCompletionItem(prop))
                    );
                if (dotIndex == -1)
                {
                    completionList.Items.AddRange(
                        generator.GetTypesForPropEventNameCompletion(context, true)
                        );
                }
                break;

            case "Event":
                completionList.Items.AddRange(
                    typeName.GetEvents()
                    .Where(e => e.IsPublic)
                    .Select(evt => new XamlCompletionItem(evt))
                    );
                if (dotIndex == -1)
                {
                    completionList.Items.AddRange(
                        generator.GetTypesForPropEventNameCompletion(context, true)
                        );
                }
                break;

            case "Handler":
                var            loc3    = context.Editor.Document.GetLocation(XmlParser.GetActiveElementStartIndex(context.Editor.Document.Text, context.Editor.Caret.Offset));
                AttributeValue evtType = MarkupExtensionParser.ParseValue(context.ActiveElement.GetAttributeValue("Event") ?? "");
                if (!evtType.IsString)
                {
                    break;
                }

                string evtName = evtType.StringValue;

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

                mrr = resolver.ResolveExpression(evtName, context) as MemberResolveResult;
                if (mrr == null)
                {
                    break;
                }
                var member = mrr.Member as IEvent;
                if (member == null)
                {
                    break;
                }

                completionList.Items.AddRange(generator.FindMatchingEventHandlers(context, member, typeName.Name));
                break;
            }
        }