Ejemplo n.º 1
0
        public TextManipulator(string text, int position)
        {
            _position = position;
            _text     = text.AsMemory();

            int parserStart = 0;
            int parserEnd   = 0;

            // To improve performance parse only last tag
            if (text.Length > 0)
            {
                // Findl last < tag
                parserStart = position;
                if (position >= text.Length)
                {
                    parserStart = text.Length - 1;
                }
                parserStart = text.LastIndexOf('<', parserStart);
                if (parserStart < 0)
                {
                    parserStart = 0;
                }


                if (text.Length > position)
                {
                    parserEnd = position;
                }
                else
                {
                    parserEnd = text.Length;
                }
            }


            _state = XmlParser.Parse(_text, parserStart, parserEnd);
        }
Ejemplo n.º 2
0
        public CompletionSet GetCompletions(Metadata metadata, string text, int pos, string currentAssemblyName = null)
        {
            _helper.SetMetadata(metadata, text, currentAssemblyName);

            if (_helper.Metadata == null)
            {
                return(null);
            }

            if (text.Length == 0 || pos == 0)
            {
                return(null);
            }
            text = text.Substring(0, pos);
            var state = XmlParser.Parse(text);

            var completions = new List <Completion>();


            var curStart = state.CurrentValueStart ?? 0;

            if (state.State == XmlParser.ParserState.StartElement)
            {
                var tagName = state.TagName;
                if (tagName.StartsWith("/"))
                {
                    if (text.Length < 2)
                    {
                        return(null);
                    }
                    var closingState = XmlParser.Parse(text.Substring(0, text.Length - 2));

                    var name = closingState.GetParentTagName(0);
                    if (name == null)
                    {
                        return(null);
                    }
                    completions.Add(new Completion("/" + name + ">", CompletionKind.Class));
                }
                else if (tagName.Contains("."))
                {
                    var dotPos   = tagName.IndexOf(".");
                    var typeName = tagName.Substring(0, dotPos);
                    var compName = tagName.Substring(dotPos + 1);
                    curStart = curStart + dotPos + 1;

                    var sameType = state.GetParentTagName(1) == typeName;

                    completions.AddRange(_helper.FilterPropertyNames(typeName, compName, sameType ? (bool?)null : true)
                                         .Select(p => new Completion(p, sameType ? CompletionKind.Property : CompletionKind.AttachedProperty)));
                }
                else
                {
                    completions.AddRange(_helper.FilterTypeNames(tagName).Select(x => new Completion(x, CompletionKind.Class)));
                }
            }
            else if (state.State == XmlParser.ParserState.InsideElement ||
                     state.State == XmlParser.ParserState.StartAttribute)
            {
                if (state.State == XmlParser.ParserState.InsideElement)
                {
                    curStart = pos; //Force completion to be started from current cursor position
                }
                if (state.AttributeName?.Contains(".") == true)
                {
                    var dotPos = state.AttributeName.IndexOf('.');
                    curStart += dotPos + 1;
                    var split = state.AttributeName.Split(new[] { '.' }, 2);
                    completions.AddRange(_helper.FilterPropertyNames(split[0], split[1], true)
                                         .Select(x => new Completion(x, x + "=\"\"", x, CompletionKind.AttachedProperty, x.Length + 2)));
                }
                else
                {
                    completions.AddRange(_helper.FilterPropertyNames(state.TagName, state.AttributeName, false)
                                         .Select(x => new Completion(x, x + "=\"\"", x, CompletionKind.Property, x.Length + 2)));

                    var targetType = _helper.LookupType(state.TagName);
                    completions.AddRange(
                        _helper.FilterTypes(state.AttributeName, xamlDirectiveOnly: true)
                        .Where(t => t.Value.IsValidForXamlContextFunc?.Invoke(currentAssemblyName, targetType, null) ?? true)
                        .Select(v => new Completion(v.Key, v.Key + "=\"\"", v.Key, CompletionKind.Class, v.Key.Length + 2)));

                    if (targetType?.IsAvaloniaObjectType == true)
                    {
                        completions.AddRange(
                            _helper.FilterTypeNames(state.AttributeName, withAttachedPropertiesOnly: true)
                            .Select(v => new Completion(v, v + ".", v, CompletionKind.Class)));
                    }
                }
            }
            else if (state.State == XmlParser.ParserState.AttributeValue)
            {
                MetadataProperty prop;
                if (state.AttributeName.Contains("."))
                {
                    //Attached property
                    var split = state.AttributeName.Split('.');
                    prop = _helper.LookupProperty(split[0], split[1]);
                }
                else
                {
                    prop = _helper.LookupProperty(state.TagName, state.AttributeName);
                }

                //Markup extension, ignore everything else
                if (state.AttributeValue.StartsWith("{"))
                {
                    curStart = state.CurrentValueStart.Value +
                               BuildCompletionsForMarkupExtension(prop, completions,
                                                                  text.Substring(state.CurrentValueStart.Value), currentAssemblyName);
                }
                else
                {
                    prop = prop ?? _helper.LookupType(state.AttributeName)?.Properties.FirstOrDefault(p => p.Name == "");

                    if (prop?.Type?.HasHintValues == true)
                    {
                        var search = text.Substring(state.CurrentValueStart.Value);
                        if (prop.Type.IsCompositeValue)
                        {
                            var last = search.Split(' ', ',').LastOrDefault();
                            curStart = curStart + search.Length - last?.Length ?? 0;
                            search   = last;
                        }

                        completions.AddRange(GetHintCompletions(prop.Type, search, currentAssemblyName));
                    }
                    else if (prop?.Type?.Name == typeof(Type).FullName)
                    {
                        completions.AddRange(_helper.FilterTypeNames(state.AttributeValue).Select(x => new Completion(x, x, x, CompletionKind.Class)));
                    }
                    else if (state.AttributeName == "xmlns" || state.AttributeName.Contains("xmlns:"))
                    {
                        if (state.AttributeValue.StartsWith("clr-namespace:"))
                        {
                            completions.AddRange(
                                metadata.Namespaces.Keys.Where(v => v.StartsWith(state.AttributeValue))
                                .Select(v => new Completion(v.Substring("clr-namespace:".Length), v, v, CompletionKind.Namespace)));
                        }
                        else
                        {
                            if ("clr-namespace:".StartsWith(state.AttributeValue))
                            {
                                completions.Add(new Completion("clr-namespace:", CompletionKind.Namespace));
                            }
                            completions.AddRange(
                                metadata.Namespaces.Keys.Where(
                                    v =>
                                    v.StartsWith(state.AttributeValue) &&
                                    !v.StartsWith("clr-namespace"))
                                .Select(v => new Completion(v, CompletionKind.Namespace)));
                        }
                    }
                    else if (state.AttributeName.EndsWith(":Class"))
                    {
                        if (_helper.Aliases.TryGetValue(state.AttributeName.Replace(":Class", ""), out var ns) && ns == Utils.Xaml2006Namespace)
                        {
                            var asmKey         = $";assembly={currentAssemblyName}";
                            var fullClassNames = _helper.Metadata.Namespaces.Where(v => v.Key.EndsWith(asmKey))
                                                 .SelectMany(v => v.Value.Values.Where(t => t.IsAvaloniaObjectType))
                                                 .Select(v => v.FullName);
                            completions.AddRange(
                                fullClassNames
                                .Where(v => v.StartsWith(state.AttributeValue))
                                .Select(v => new Completion(v, CompletionKind.Class)));
                        }
                    }
                }
            }

            if (completions.Count != 0)
            {
                return new CompletionSet()
                       {
                           Completions = completions, StartPosition = curStart
                       }
            }
            ;
            return(null);
        }
Ejemplo n.º 3
0
        public CompletionSet GetCompletions(Metadata metadata, string text, int pos, string currentAssemblyName = null)
        {
            _helper.SetMetadata(metadata, text, currentAssemblyName);

            if (_helper.Metadata == null)
            {
                return(null);
            }

            if (text.Length == 0 || pos == 0)
            {
                return(null);
            }
            text = text.Substring(0, pos);
            var state = XmlParser.Parse(text);

            var completions = new List <Completion>();


            var curStart = state.CurrentValueStart ?? 0;

            if (state.State == XmlParser.ParserState.StartElement)
            {
                var tagName = state.TagName;
                if (tagName.Contains("."))
                {
                    var dotPos   = tagName.IndexOf(".");
                    var typeName = tagName.Substring(0, dotPos);
                    var compName = tagName.Substring(dotPos + 1);
                    curStart = curStart + dotPos + 1;
                    completions.AddRange(_helper.FilterPropertyNames(typeName, compName).Select(p => new Completion(p, CompletionKind.Enum)));
                }
                else
                {
                    completions.AddRange(_helper.FilterTypeNames(tagName).Select(x => new Completion(x, CompletionKind.Class)));
                }
            }
            else if (state.State == XmlParser.ParserState.InsideElement ||
                     state.State == XmlParser.ParserState.StartAttribute)
            {
                if (state.State == XmlParser.ParserState.InsideElement)
                {
                    curStart = pos; //Force completion to be started from current cursor position
                }
                if (state.AttributeName?.Contains(".") == true)
                {
                    var dotPos = state.AttributeName.IndexOf('.');
                    curStart += dotPos + 1;
                    var split = state.AttributeName.Split(new[] { '.' }, 2);
                    completions.AddRange(_helper.FilterPropertyNames(split[0], split[1], true)
                                         .Select(x => new Completion(x, x + "=\"\"", x, CompletionKind.Property, x.Length + 2)));
                }
                else
                {
                    completions.AddRange(_helper.FilterPropertyNames(state.TagName, state.AttributeName)
                                         .Select(x => new Completion(x, x + "=\"\"", x, CompletionKind.Property, x.Length + 2)));

                    var targetType = _helper.LookupType(state.TagName);

                    if (targetType?.IsAvaloniaObjectType == true)
                    {
                        completions.AddRange(
                            _helper.FilterTypeNames(state.AttributeName, true)
                            .Select(v => new Completion(v, v + ".", v, CompletionKind.Property)));
                    }
                }
            }
            else if (state.State == XmlParser.ParserState.AttributeValue)
            {
                MetadataProperty prop;
                if (state.AttributeName.Contains("."))
                {
                    //Attached property
                    var split = state.AttributeName.Split('.');
                    prop = _helper.LookupProperty(split[0], split[1]);
                }
                else
                {
                    prop = _helper.LookupProperty(state.TagName, state.AttributeName);
                }

                //Markup extension, ignore everything else
                if (state.AttributeValue.StartsWith("{"))
                {
                    curStart = state.CurrentValueStart.Value +
                               BuildCompletionsForMarkupExtension(prop, completions,
                                                                  text.Substring(state.CurrentValueStart.Value));
                }
                else
                {
                    if (prop?.Type?.HasHintValues == true)
                    {
                        var search = text.Substring(state.CurrentValueStart.Value);
                        if (prop.Type.IsCompositeValue)
                        {
                            var last = search.Split(' ', ',').LastOrDefault();
                            curStart = curStart + search.Length - last?.Length ?? 0;
                            search   = last;
                        }

                        completions.AddRange(GetHintCompletions(search, prop.Type.HintValues));
                    }
                    else if (state.AttributeName == "xmlns" || state.AttributeName.Contains("xmlns:"))
                    {
                        if (state.AttributeValue.StartsWith("clr-namespace:"))
                        {
                            completions.AddRange(
                                metadata.Namespaces.Keys.Where(v => v.StartsWith(state.AttributeValue))
                                .Select(v => new Completion(v.Substring("clr-namespace:".Length), v, v, CompletionKind.Namespace)));
                        }
                        else
                        {
                            if ("clr-namespace:".StartsWith(state.AttributeValue))
                            {
                                completions.Add(new Completion("clr-namespace:", CompletionKind.Namespace));
                            }
                            completions.AddRange(
                                metadata.Namespaces.Keys.Where(
                                    v =>
                                    v.StartsWith(state.AttributeValue) &&
                                    !v.StartsWith("clr-namespace"))
                                .Select(v => new Completion(v, CompletionKind.Namespace)));
                        }
                    }
                }
            }

            if (completions.Count != 0)
            {
                return new CompletionSet()
                       {
                           Completions = completions, StartPosition = curStart
                       }
            }
            ;
            return(null);
        }

        List <Completion> GetHintCompletions(string entered, string[] values)
        {
            var completions = new List <Completion>();

            foreach (var val in values)
            {
                if (val.StartsWith(entered, StringComparison.OrdinalIgnoreCase))
                {
                    completions.Add(new Completion(val, CompletionKind.Enum));
                }
            }
            return(completions);
        }

        int BuildCompletionsForMarkupExtension(MetadataProperty property, List <Completion> completions, string data)
        {
            int?forcedStart = null;
            var ext         = MarkupExtensionParser.Parse(data);

            var transformedName = (ext.ElementName ?? "").Trim();

            if (_helper.LookupType(transformedName)?.IsMarkupExtension != true)
            {
                transformedName += "Extension";
            }

            if (ext.State == MarkupExtensionParser.ParserStateType.StartElement)
            {
                completions.AddRange(_helper.FilterTypeNames(ext.ElementName, markupExtensionsOnly: true)
                                     .Select(t => t.EndsWith("Extension") ? t.Substring(0, t.Length - "Extension".Length) : t)
                                     .Select(t => new Completion(t, CompletionKind.MarkupExtension)));
            }
            if (ext.State == MarkupExtensionParser.ParserStateType.StartAttribute ||
                ext.State == MarkupExtensionParser.ParserStateType.InsideElement)
            {
                if (ext.State == MarkupExtensionParser.ParserStateType.InsideElement)
                {
                    forcedStart = data.Length;
                }
                completions.AddRange(_helper.FilterPropertyNames(transformedName, ext.AttributeName ?? "")
                                     .Select(x => new Completion(x, x + "=", x, CompletionKind.MarkupExtension)));

                var attribName = ext.AttributeName ?? "";
                var t          = _helper.LookupType(transformedName);

                bool ctorArgument = ext.AttributesCount == 0;
                //skip ctor hints when some property is already set
                if (t != null && t.IsMarkupExtension && t.SupportCtorArgument != MetadataTypeCtorArgument.None && ctorArgument)
                {
                    if (t.SupportCtorArgument == MetadataTypeCtorArgument.HintValues)
                    {
                        if (t.HasHintValues)
                        {
                            completions.AddRange(GetHintCompletions(attribName, t.HintValues));
                        }
                    }
                    else if (attribName.Contains("."))
                    {
                        if (t.SupportCtorArgument != MetadataTypeCtorArgument.Type)
                        {
                            var split = attribName.Split('.');
                            var type  = split[0];
                            var prop  = split[1];
                            var props = _helper.FilterPropertyNames(type, prop, staticGettersOnly: true, hintValues: true);
                            completions.AddRange(props.Select(x => new Completion(x, $"{type}.{x}", x, CompletionKind.MarkupExtension)));
                        }
                    }
                    else
                    {
                        var types = _helper.FilterTypeNames(attribName,
                                                            staticGettersOnly: t.SupportCtorArgument == MetadataTypeCtorArgument.Object);

                        completions.AddRange(types.Select(x => new Completion(x, x, x, CompletionKind.Class)));

                        if (property?.Type?.HasHintValues == true)
                        {
                            completions.Add(new Completion(property.Type.Name, property.Type.Name + ".", property.Type.Name, CompletionKind.Class));
                        }
                    }
                }
            }
            if (ext.State == MarkupExtensionParser.ParserStateType.AttributeValue ||
                ext.State == MarkupExtensionParser.ParserStateType.BeforeAttributeValue)
            {
                var prop = _helper.LookupProperty(transformedName, ext.AttributeName);
                if (prop?.Type?.HasHintValues == true)
                {
                    var enumStart       = data.Substring(ext.CurrentValueStart);
                    var enumCompletions = GetHintCompletions(enumStart, prop.Type.HintValues);
                    completions.AddRange(enumCompletions);
                }
            }

            return(forcedStart ?? ext.CurrentValueStart);
        }
Ejemplo n.º 4
0
        public CompletionSet GetCompletions(Metadata metadata, string text, int pos)
        {
            _helper.SetMetadata(metadata, text);

            if (_helper.Metadata == null)
            {
                return(null);
            }

            if (text.Length == 0 || pos == 0)
            {
                return(null);
            }
            text = text.Substring(0, pos);
            var state = XmlParser.Parse(text);

            var completions = new List <Completion>();


            var curStart = state.CurrentValueStart ?? 0;

            if (state.State == XmlParser.ParserState.StartElement)
            {
                var tagName = state.TagName;
                if (tagName.Contains("."))
                {
                    var dotPos   = tagName.IndexOf(".");
                    var typeName = tagName.Substring(0, dotPos);
                    var compName = tagName.Substring(dotPos + 1);
                    curStart = curStart + dotPos + 1;
                    completions.AddRange(_helper.FilterPropertyNames(typeName, compName).Select(p => new Completion(p)));
                }
                else
                {
                    completions.AddRange(_helper.FilterTypeNames(tagName).Select(x => new Completion(x)));
                }
            }
            else if (state.State == XmlParser.ParserState.InsideElement ||
                     state.State == XmlParser.ParserState.StartAttribute)
            {
                if (state.State == XmlParser.ParserState.InsideElement)
                {
                    curStart = pos; //Force completion to be started from current cursor position
                }
                if (state.AttributeName?.Contains(".") == true)
                {
                    var dotPos = state.AttributeName.IndexOf('.');
                    curStart += dotPos + 1;
                    var split = state.AttributeName.Split(new[] { '.' }, 2);
                    completions.AddRange(_helper.FilterPropertyNames(split[0], split[1], true)
                                         .Select(x => new Completion(x, x + "=\"\"", x, x.Length + 2)));
                }
                else
                {
                    completions.AddRange(_helper.FilterPropertyNames(state.TagName, state.AttributeName)
                                         .Select(x => new Completion(x, x + "=\"\"", x, x.Length + 2)));
                    completions.AddRange(
                        _helper.FilterTypeNames(state.AttributeName, true)
                        .Select(v => new Completion(v, v + ".", v)));
                }
            }
            else if (state.State == XmlParser.ParserState.AttributeValue)
            {
                MetadataProperty prop;
                if (state.AttributeName.Contains("."))
                {
                    //Attached property
                    var split = state.AttributeName.Split('.');
                    prop = _helper.LookupProperty(split[0], split[1]);
                }
                else
                {
                    prop = _helper.LookupProperty(state.TagName, state.AttributeName);
                }

                //Markup extension, ignore everything else
                if (state.AttributeValue.StartsWith("{"))
                {
                    curStart = state.CurrentValueStart.Value +
                               BuildCompletionsForMarkupExtension(completions,
                                                                  text.Substring(state.CurrentValueStart.Value));
                }
                else
                {
                    if (prop?.Type?.IsEnum == true)
                    {
                        completions.AddRange(GetEnumCompletions(text.Substring(state.CurrentValueStart.Value), prop.Type.EnumValues));
                    }
                    else if (state.AttributeName == "xmlns" || state.AttributeName.Contains("xmlns:"))
                    {
                        if (state.AttributeValue.StartsWith("clr-namespace:"))
                        {
                            completions.AddRange(
                                metadata.Namespaces.Keys.Where(v => v.StartsWith(state.AttributeValue))
                                .Select(v => new Completion(v.Substring("clr-namespace:".Length), v, v)));
                        }
                        else
                        {
                            completions.Add(new Completion("clr-namespace:"));
                            completions.AddRange(
                                metadata.Namespaces.Keys.Where(
                                    v =>
                                    v.StartsWith(state.AttributeValue) &&
                                    !"clr-namespace".StartsWith(state.AttributeValue))
                                .Select(v => new Completion(v)));
                        }
                    }
                }
            }

            if (completions.Count != 0)
            {
                return new CompletionSet()
                       {
                           Completions = completions, StartPosition = curStart
                       }
            }
            ;
            return(null);
        }

        List <Completion> GetEnumCompletions(string entered, string[] enumValues)
        {
            var enumCompletions = new List <Completion>();

            foreach (var val in enumValues)
            {
                if (val.StartsWith(entered, StringComparison.OrdinalIgnoreCase))
                {
                    enumCompletions.Add(new Completion(val));
                }
            }
            return(enumCompletions);
        }

        int BuildCompletionsForMarkupExtension(List <Completion> completions, string data)
        {
            int?forcedStart = null;
            var ext         = MarkupExtensionParser.Parse(data);

            var transformedName = (ext.ElementName ?? "").Trim();

            if (_helper.LookupType(transformedName)?.IsMarkupExtension != true)
            {
                transformedName += "Extension";
            }

            if (ext.State == MarkupExtensionParser.ParserStateType.StartElement)
            {
                completions.AddRange(_helper.FilterTypeNames(ext.ElementName, markupExtensionsOnly: true)
                                     .Select(t => t.EndsWith("Extension") ? t.Substring(0, t.Length - "Extension".Length) : t)
                                     .Select(t => new Completion(t)));
            }
            if (ext.State == MarkupExtensionParser.ParserStateType.StartAttribute ||
                ext.State == MarkupExtensionParser.ParserStateType.InsideElement)
            {
                if (ext.State == MarkupExtensionParser.ParserStateType.InsideElement)
                {
                    forcedStart = data.Length;
                }
                completions.AddRange(_helper.FilterPropertyNames(transformedName, ext.AttributeName ?? "")
                                     .Select(x => new Completion(x, x + "=", x)));
            }
            if (ext.State == MarkupExtensionParser.ParserStateType.AttributeValue ||
                ext.State == MarkupExtensionParser.ParserStateType.BeforeAttributeValue)
            {
                var prop = _helper.LookupProperty(transformedName, ext.AttributeName);
                if (prop?.Type?.IsEnum == true)
                {
                    var enumStart       = data.Substring(ext.CurrentValueStart);
                    var enumCompletions = GetEnumCompletions(enumStart, prop.Type.EnumValues);
                    completions.AddRange(enumCompletions);
                }
            }

            return(forcedStart ?? ext.CurrentValueStart);
        }