Пример #1
0
        /// <summary>
        ///     Does the location represent a place where an element can be created or replaced by a completion?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <param name="replaceElement">
        ///     The element (if any) that will be replaced by the completion.
        /// </param>
        /// <param name="parentPath">
        ///     If specified, the location's node's parent must have the specified <see cref="XSPath"/>.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an element that can be replaced by completion; otherwise, <c>false</c>.
        /// </returns>
        /// <remarks>
        ///     We can replace "&lt;&gt;" and "&lt;&lt;Element /&gt;".
        /// </remarks>
        public static bool CanCompleteElement(this XmlLocation location, out XSElement replaceElement, XSPath parentPath = null)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            replaceElement = null;

            // Simplest case - we're on whitespace so we can simply insert an element without replacing anything.
            if (location.IsWhitespace(out XSWhitespace whitespace) && (parentPath == null || whitespace.HasParentPath(parentPath)))
            {
                return(true);
            }

            XSElement element;

            if (!location.IsElement(out element))
            {
                return(false);
            }

            if (location.IsElementBetweenAttributes())
            {
                return(false);
            }

            // Check if we need to perform a substition of the element to be replaced (the common case is simply replacing an existing element or partial element).
            if (element.IsValid)
            {
                // Do we have an invalid parent (e.g. "<<Foo />", which yields invalid element named "" with child element named "Foo")?
                bool isParentValid = element.ParentElement?.IsValid ?? true;
                if (!isParentValid)
                {
                    // We can't handle the case where the parent isn't on the same line as the child (since that's not the case outlined above).
                    if (element.ParentElement.Start.LineNumber != location.Node.Start.LineNumber)
                    {
                        return(false);
                    }

                    // But we *can* handle this case by targeting the "parent" element (since that's the element we're actually after anyway).
                    if (location.Node.Start.ColumnNumber - element.ParentElement.Start.ColumnNumber == 1)
                    {
                        element = element.ParentElement;
                    }
                }
            }

            if (parentPath != null && !element.HasParentPath(parentPath))
            {
                return(false);
            }

            replaceElement = element;

            return(true);
        }
Пример #2
0
        /// <summary>
        ///     Does the location represent an element's attributes range (but not a specific attribute)?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <param name="element">
        ///     Receives the <see cref="XSElement"/>.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an element; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsElementBetweenAttributes(this XmlLocation location, out XSElement element)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            if (location.IsElementBetweenAttributes())
            {
                element = (XSElement)location.Node;

                return(true);
            }
            else
            {
                element = null;

                return(false);
            }
        }
Пример #3
0
        /// <summary>
        ///     Does the location represent a place where an attribute can be created or replaced by a completion?
        /// </summary>
        /// <param name="location">
        ///     The XML location.
        /// </param>
        /// <param name="element">
        ///     The element whose attribute will be completed.
        /// </param>
        /// <param name="replaceAttribute">
        ///     The attribute (if any) that will be replaced by the completion.
        /// </param>
        /// <param name="needsPadding">
        ///     An <see cref="PaddingType"/> value indicating what sort of padding (if any) is required before / after the attribute.
        /// </param>
        /// <param name="onElementWithPath">
        ///     If specified, the location's element must have the specified path.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the location represents an element that can be replaced by completion; otherwise, <c>false</c>.
        /// </returns>
        public static bool CanCompleteAttribute(this XmlLocation location, out XSElement element, out XSAttribute replaceAttribute, out PaddingType needsPadding, XSPath onElementWithPath = null)
        {
            if (location == null)
            {
                throw new ArgumentNullException(nameof(location));
            }

            replaceAttribute = null;
            needsPadding     = PaddingType.None;

            XSAttribute attribute;

            if (location.IsAttribute(out attribute) && !location.IsValue())
            {
                element = attribute.Element;
                if (location.Position == attribute.Start)
                {
                    // Since we're on an existing attribute, we'll add a new attribute after it.
                    attribute    = null;
                    needsPadding = PaddingType.Trailing;
                }
            }
            else if (location.IsElementBetweenAttributes(out element))
            {
                if (element.Attributes.Count > 0)
                {
                    // Check if we're directly before an attribute.
                    foreach (XSAttribute currentAttribute in element.Attributes)
                    {
                        if (location.Position == currentAttribute.End)
                        {
                            needsPadding = PaddingType.Leading;
                        }
                        else
                        {
                            continue;
                        }

                        break;
                    }
                }
                else if (location.Position == element.NameRange.End) // We're directly after the name.
                {
                    needsPadding = PaddingType.Leading;
                }
            }
            else if (location.IsElement(out element))
            {
                // Check if we're directly after the name.
                if (location.Position != element.NameRange.End)
                {
                    return(false);
                }

                needsPadding = PaddingType.Leading;
            }
            else
            {
                return(false);
            }

            if (onElementWithPath != null && !element.Path.Matches(onElementWithPath))
            {
                return(false);
            }

            replaceAttribute = attribute;

            return(true);
        }