private int BuildCompletionsForMarkupExtension(MetadataProperty property, List <Completion> completions, string fullText, XmlParser state, string data, string currentAssemblyName) { 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 ?? "", attached: false, hasSetter: true) .Select(x => new Completion(x, x + "=", x, CompletionKind.Property))); 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(t, attribName)); } } else if (attribName.Contains(".")) { if (t.SupportCtorArgument != MetadataTypeCtorArgument.Type) { var split = attribName.Split('.'); var type = split[0]; var prop = split[1]; var mType = _helper.LookupType(type); if (mType != null && t.SupportCtorArgument == MetadataTypeCtorArgument.HintValues) { var hints = FilterHintValues(mType, prop, currentAssemblyName, state); completions.AddRange(hints.Select(x => new Completion(x, $"{type}.{x}", x, GetCompletionKindForHintValues(mType)))); } var props = _helper.FilterPropertyNames(type, prop, attached: false, hasSetter: false, staticGetter: true); completions.AddRange(props.Select(x => new Completion(x, $"{type}.{x}", x, CompletionKind.StaticProperty))); } } 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)); } } } else { var defaultProp = t?.Properties.FirstOrDefault(p => p.Name == ""); if (defaultProp?.Type?.HasHintValues ?? false) { completions.AddRange(GetHintCompletions(defaultProp.Type, ext.AttributeName ?? "", currentAssemblyName, fullText, state)); } } } if (ext.State == MarkupExtensionParser.ParserStateType.AttributeValue || ext.State == MarkupExtensionParser.ParserStateType.BeforeAttributeValue) { var prop = _helper.LookupProperty(transformedName, ext.AttributeName); if (prop?.Type?.HasHintValues == true) { var start = data.Substring(ext.CurrentValueStart); completions.AddRange(GetHintCompletions(prop.Type, start, currentAssemblyName, fullText, state)); } } return(forcedStart ?? ext.CurrentValueStart); }
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); }
private IEnumerable <Completion> FilterHintValuesForBindingPath(MetadataType bindingPathType, string entered, string currentAssemblyName, string fullText, XmlParser state) { IEnumerable <Completion> forPropertiesFromType(MetadataType filterType, string filter, Func <string, string> fmtInsertText = null) { if (filterType != null) { foreach (var propertyName in _helper.FilterPropertyNames(filterType, filter, false, false)) { yield return(new Completion(propertyName, fmtInsertText?.Invoke(propertyName) ?? propertyName, propertyName, CompletionKind.Property)); } } } IEnumerable <Completion> forProperties(string filterType, string filter, Func <string, string> fmtInsertText = null) => forPropertiesFromType(_helper.LookupType(filterType ?? ""), filter, fmtInsertText); if (string.IsNullOrEmpty(entered)) { return(forProperties(state.FindParentAttributeValue("(x\\:)?DataType"), entered)); } var values = entered.Split('.'); if (values.Length == 1) { if (values[0].StartsWith("$parent[")) { return(_helper.FilterTypes(entered.Substring("$parent[".Length)) .Select(v => new Completion(v.Key, $"$parent[{v.Key}].", v.Key, CompletionKind.Class))); } else if (values[0].StartsWith("#")) { var nameMatch = Regex.Matches(fullText, $"\\s(?:(x\\:)?Name)=\"(?<AttribValue>[\\w\\:\\s\\|\\.]+)\""); if (nameMatch.Count > 0) { var result = new List <Completion>(); foreach (Match m in nameMatch) { if (m.Success) { var name = m.Groups["AttribValue"].Value; result.Add(new Completion(name, $"#{name}", name, CompletionKind.Class)); } } return(result); } return(Array.Empty <Completion>()); } return(forProperties(state.FindParentAttributeValue("(x\\:)?DataType"), entered)); } string type = values[0]; int i; if (values[0].StartsWith("$")) { i = 1; type = "Control"; if (values[0] == "$self") //current control type { type = state.GetParentTagName(0); } else if (values[0] == "$parent") //parent control in the xaml { type = state.GetParentTagName(1) ?? "Control"; } else if (values[0].StartsWith("$parent[")) //extract parent type { type = values[0].Substring("$parent[".Length, values[0].Length - "$parent[".Length - 1); } } else if (values[0].StartsWith("#")) { i = 1; //todo: find the control type etc ??? type = "Control"; } else { i = 0; type = state.FindParentAttributeValue("(x\\:)?DataType"); } var mdType = _helper.LookupType(type ?? ""); while (mdType != null && i < values.Length - 1 && !string.IsNullOrEmpty(values[i])) { if (i <= 1 && values[i] == "DataContext") { //assume parent.datacontext is x:datatype so we have some intelisence type = state.FindParentAttributeValue("(x\\:)?DataType"); mdType = _helper.LookupType(type); } else { mdType = mdType.Properties.FirstOrDefault(p => p.Name == values[i])?.Type; type = mdType?.FullName; } i++; } return(forPropertiesFromType(mdType, values[i], p => $"{string.Join(".", values.Take(i).ToArray())}.{p}")); }
private List <Completion> GetHintCompletions(MetadataType type, string entered, string currentAssemblyName = null, string fullText = null, XmlParser state = null) { var kind = GetCompletionKindForHintValues(type); var completions = FilterHintValues(type, entered, currentAssemblyName, state) .Select(val => new Completion(val, kind)).ToList(); if (type.FullName == "{BindingPath}" && state != null) { completions.AddRange(FilterHintValuesForBindingPath(type, entered, currentAssemblyName, fullText, state)); } return(completions); }
public IEnumerable <string> FilterHintValues(MetadataType type, string entered, string currentAssemblyName, XmlParser state) { entered = entered ?? ""; if (type == null) { yield break; } if (!string.IsNullOrEmpty(currentAssemblyName) && type.XamlContextHintValuesFunc != null) { foreach (var v in type.XamlContextHintValuesFunc(currentAssemblyName, type, null).Where(v => v.StartsWith(entered, StringComparison.OrdinalIgnoreCase))) { yield return(v); } } foreach (var v in type.HintValues.Where(v => v.StartsWith(entered, StringComparison.OrdinalIgnoreCase))) { yield return(v); } }
public CompletionSet GetCompletions(Metadata metadata, string fullText, int pos, string currentAssemblyName = null) { string textToCursor = fullText.Substring(0, pos); _helper.SetMetadata(metadata, textToCursor, currentAssemblyName); if (_helper.Metadata == null) { return(null); } if (fullText.Length == 0 || pos == 0) { return(null); } var state = XmlParser.Parse(textToCursor); var completions = new List <Completion>(); int curStart = state.CurrentValueStart ?? 0; if (state.State == XmlParser.ParserState.StartElement) { var tagName = state.TagName; if (tagName.StartsWith("/")) { if (textToCursor.Length < 2) { return(null); } var closingState = XmlParser.Parse(textToCursor.Substring(0, textToCursor.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, attached: sameType ? (bool?)null : true, hasSetter: false) .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 } string attributeSuffix = "=\"\""; int attributeOffset = 2; if (fullText.Length > pos && fullText[pos] == '=') { // attribute already has value, we are editing name only attributeSuffix = ""; attributeOffset = 0; } 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], attached: true, hasSetter: true) .Select(x => new Completion(x, x + attributeSuffix, x, CompletionKind.AttachedProperty, x.Length + attributeOffset))); completions.AddRange(_helper.FilterEventNames(split[0], split[1], attached: true) .Select(v => new Completion(v, v + attributeSuffix, v, CompletionKind.AttachedEvent, v.Length + attributeOffset))); } else { completions.AddRange(_helper.FilterPropertyNames(state.TagName, state.AttributeName, attached: false, hasSetter: true) .Select(x => new Completion(x, x + attributeSuffix, x, CompletionKind.Property, x.Length + attributeOffset))); completions.AddRange(_helper.FilterEventNames(state.TagName, state.AttributeName, attached: false) .Select(v => new Completion(v, v + attributeSuffix, v, CompletionKind.Event, v.Length + attributeOffset))); 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 + attributeSuffix, v.Key, CompletionKind.Class, v.Key.Length + attributeOffset))); if (targetType?.IsAvaloniaObjectType == true) { completions.AddRange( _helper.FilterTypeNames(state.AttributeName, withAttachedPropertiesOrEventsOnly: 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, fullText, state, textToCursor.Substring(state.CurrentValueStart.Value), currentAssemblyName); } else { prop = prop ?? _helper.LookupType(state.AttributeName)?.Properties.FirstOrDefault(p => p.Name == ""); if (prop?.Type?.HasHintValues == true) { var search = textToCursor.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:")) { IEnumerable <string> filterNamespaces(Func <string, bool> predicate) { var result = metadata.Namespaces.Keys.Where(predicate).ToList(); result.Sort((x, y) => x.CompareTo(y)); return(result); } if (state.AttributeValue.StartsWith("clr-namespace:")) { completions.AddRange( filterNamespaces(v => v.StartsWith(state.AttributeValue)) .Select(v => new Completion(v.Substring("clr-namespace:".Length), v, v, CompletionKind.Namespace))); } else { if ("using:".StartsWith(state.AttributeValue)) { completions.Add(new Completion("using:", CompletionKind.Namespace)); } if ("clr-namespace:".StartsWith(state.AttributeValue)) { completions.Add(new Completion("clr-namespace:", CompletionKind.Namespace)); } completions.AddRange( filterNamespaces( 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))); } } else if (state.TagName == "Setter" && (state.AttributeName == "Value" || state.AttributeName == "Property")) { ProcessStyleSetter(state.AttributeName, state, completions, currentAssemblyName); } } } if (completions.Count != 0) { return new CompletionSet() { Completions = completions, StartPosition = curStart } } ; return(null); }
public CloseXmlTagManipulation(XmlParser state, ReadOnlyMemory <char> text, int position) { _state = state; _text = text; _position = position; }
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); }
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); if (targetType?.IsAvaloniaObjectType == true) { completions.AddRange( _helper.FilterTypeNames(state.AttributeName, 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)); } 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(prop.Type, search)); } 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))); } } } } if (completions.Count != 0) { return new CompletionSet() { Completions = completions, StartPosition = curStart } } ; return(null); }