Пример #1
0
            /// <summary>
            ///     Connect sibling nodes.
            /// </summary>
            void ConnectSiblings()
            {
                var discoveredElements = DiscoveredNodes.OfType <XSElement>();

                foreach (XSElement element in discoveredElements)
                {
                    // Join up sibling attributes.
                    XSNode previousSibling = null;
                    foreach (XSAttribute nextSibling in element.Attributes)
                    {
                        nextSibling.PreviousSibling = previousSibling;
                        if (previousSibling != null)
                        {
                            previousSibling.NextSibling = nextSibling;
                        }

                        previousSibling = nextSibling;
                    }

                    previousSibling = null;

                    // Join up sibling content nodes.
                    foreach (XSNode nextSibling in element.Content)
                    {
                        nextSibling.PreviousSibling = previousSibling;
                        if (previousSibling != null)
                        {
                            previousSibling.NextSibling = nextSibling;
                        }

                        previousSibling = nextSibling;
                    }
                }
            }
Пример #2
0
        /// <summary>
        ///     Determine whether the <see cref="XSNode"/>'s parent path is equal to the specified <see cref="XSPath"/>.
        /// </summary>
        /// <param name="node">
        ///     The <see cref="XSNode"/>.
        /// </param>
        /// <param name="parentPath">
        ///     The <see cref="XSPath"/>.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if the node's <see cref="XSPath.Parent"/> path is equal to <paramref name="parentPath"/>; otherwise, <c>false</c>.
        /// </returns>
        public static bool HasParentPath(this XSNode node, XSPath parentPath)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            if (parentPath == null)
            {
                throw new ArgumentNullException(nameof(parentPath));
            }

            XSPath nodeParentPath = node.Path.Parent;

            if (nodeParentPath == null)
            {
                return(false);
            }

            // The common use case for this is checking if an element or attribute matches a relative parent path (e.g. match both Project/ItemGroup and Project/Target/ItemGroup).
            if (parentPath.IsRelative)
            {
                return(nodeParentPath.EndsWith(parentPath));
            }

            return(node.Path.IsChildOf(parentPath));
        }
        /// <summary>
        ///     Inspect the specified location in the XML.
        /// </summary>
        /// <param name="position">
        ///     The location's position.
        /// </param>
        /// <returns>
        ///     An <see cref="XmlLocation"/> representing the result of the inspection.
        /// </returns>
        public XmlLocation Inspect(Position position)
        {
            // Internally, we always use 1-based indexing because this is what the System.Xml APIs (and I'd rather keep things simple).
            position = position.ToOneBased();

            XSNode nodeAtPosition = FindNode(position);

            if (nodeAtPosition == null)
            {
                return(null);
            }

            // If we're on the (seamless, i.e. overlapping) boundary between 2 nodes, select the next node.
            if (nodeAtPosition.NextSibling != null)
            {
                if (position == nodeAtPosition.Range.End && position == nodeAtPosition.NextSibling.Range.Start)
                {
                    Serilog.Log.Debug("XmlLocator.Inspect moves to next sibling ({NodeKind} @ {NodeRange} -> {NextSiblingKind} @ {NextSiblingRange}).",
                                      nodeAtPosition.Kind,
                                      nodeAtPosition.Range,
                                      nodeAtPosition.NextSibling.Kind,
                                      nodeAtPosition.NextSibling.Range
                                      );

                    nodeAtPosition = nodeAtPosition.NextSibling;
                }
            }

            int absolutePosition = _documentPositions.GetAbsolutePosition(position);

            XmlLocationFlags flags            = ComputeLocationFlags(nodeAtPosition, absolutePosition);
            XmlLocation      inspectionResult = new XmlLocation(position, absolutePosition, nodeAtPosition, flags);

            return(inspectionResult);
        }
Пример #4
0
        /// <summary>
        ///     Create a new <see cref="MSBuildObject"/>.
        /// </summary>
        /// <param name="xml">
        ///     A <see cref="SyntaxNode"/> representing the item's corresponding XML.
        /// </param>
        protected MSBuildObject(XSNode xml)
        {
            if (xml == null)
            {
                throw new ArgumentNullException(nameof(xml));
            }

            Xml = xml;
        }
Пример #5
0
        /// <summary>
        ///     Create a new <see cref="XmlLocation"/>.
        /// </summary>
        /// <param name="position">
        ///     The location's position, in line / column form.
        /// </param>
        /// <param name="absolutePosition">
        ///     The location's (0-based) absolute position.
        /// </param>
        /// <param name="node">
        ///     The <see cref="XSNode"/> closest to the location's position.
        /// </param>
        /// <param name="flags">
        ///     <see cref="XmlLocationFlags"/> describing the location.
        /// </param>
        public XmlLocation(Position position, int absolutePosition, XSNode node, XmlLocationFlags flags)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            Position         = position;
            AbsolutePosition = absolutePosition;
            Node             = node;
            Flags            = flags;
        }
Пример #6
0
        /// <summary>
        ///     Determine whether the <see cref="XSNode"/>'s path ends with the specified <see cref="XSPath"/>.
        /// </summary>
        /// <param name="node">
        ///     The <see cref="XSNode"/>.
        /// </param>
        /// <param name="path">
        ///     The <see cref="XSPath"/>.
        /// </param>
        /// <returns>
        ///     <c>true</c>, if <see cref="XSNode.Path"/> ends with <paramref name="path"/>; otherwise, <c>false</c>.
        /// </returns>
        public static bool PathEndsWith(this XSNode node, XSPath path)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }

            return(node.Path.EndsWith(path));
        }
        /// <summary>
        ///     Determine <see cref="XmlLocationFlags"/> for the current position.
        /// </summary>
        /// <returns>
        ///     <see cref="XmlLocationFlags"/> describing the position.
        /// </returns>
        XmlLocationFlags ComputeLocationFlags(XSNode node, int absolutePosition)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            XmlLocationFlags flags = XmlLocationFlags.None;

            if (!node.IsValid)
            {
                flags |= XmlLocationFlags.Invalid;
            }

            switch (node)
            {
            case XSEmptyElement element:
            {
                flags |= XmlLocationFlags.Element | XmlLocationFlags.Empty;

                XmlEmptyElementSyntax syntaxNode = element.ElementNode;

                TextSpan nameSpan = syntaxNode.NameNode?.Span ?? new TextSpan();
                if (nameSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.Name;
                }

                TextSpan attributesSpan = new TextSpan();
                if (syntaxNode.SlashGreaterThanToken != null)     // This is the most accurate way to measure the span of text where the element's attributes can be located.
                {
                    attributesSpan = new TextSpan(start: syntaxNode.NameNode.Span.End, length: syntaxNode.SlashGreaterThanToken.Span.Start - syntaxNode.NameNode.Span.End);
                }
                else if (syntaxNode.AttributesNode != null)
                {
                    attributesSpan = syntaxNode.AttributesNode.FullSpan;     // We don't rely on the span of the syntaxNode.AttributesNode unless we have to, because it's often less accurate than the measurement above.
                }
                if (attributesSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.Attributes;
                }

                break;
            }

            case XSElementWithContent elementWithContent:
            {
                flags |= XmlLocationFlags.Element;

                XmlElementSyntax syntaxNode = elementWithContent.ElementNode;

                TextSpan nameSpan = syntaxNode.NameNode?.Span ?? new TextSpan();
                if (nameSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.Name;
                }

                TextSpan startTagSpan = syntaxNode.StartTag?.Span ?? new TextSpan();
                if (startTagSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.OpeningTag;
                }

                TextSpan attributesSpan = new TextSpan();
                if (syntaxNode.StartTag?.GreaterThanToken != null)     // This is the most accurate way to measure the span of text where the element's attributes can be located.
                {
                    attributesSpan = new TextSpan(start: syntaxNode.NameNode.Span.End, length: syntaxNode.StartTag.GreaterThanToken.Span.Start - syntaxNode.NameNode.Span.End);
                }
                else if (syntaxNode.AttributesNode != null)
                {
                    attributesSpan = syntaxNode.AttributesNode.FullSpan;                                 // We don't rely on the span of the syntaxNode.AttributesNode unless we have to, because it's often less accurate than the measurement above.
                }
                if (attributesSpan.Contains(absolutePosition) || absolutePosition == attributesSpan.End) // In this particular case, we need an inclusive comparison.
                {
                    flags |= XmlLocationFlags.Attributes;
                }

                TextSpan endTagSpan = syntaxNode.EndTag?.Span ?? new TextSpan();
                if (endTagSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.ClosingTag;
                }

                if (absolutePosition >= startTagSpan.End && absolutePosition <= endTagSpan.Start)
                {
                    flags |= XmlLocationFlags.Value;
                }

                break;
            }

            case XSInvalidElement invalidElement:
            {
                flags |= XmlLocationFlags.Element;

                XmlElementSyntaxBase syntaxNode = invalidElement.ElementNode;

                TextSpan nameSpan = syntaxNode.NameNode?.Span ?? new TextSpan();
                if (nameSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.Name;
                }

                TextSpan attributesSpan = syntaxNode.AttributesNode?.FullSpan ?? new TextSpan();
                if (attributesSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.Attributes;
                }

                break;
            }

            case XSAttribute attribute:
            {
                flags |= XmlLocationFlags.Attribute;

                XmlAttributeSyntax syntaxNode = attribute.AttributeNode;

                TextSpan nameSpan = syntaxNode.NameNode?.Span ?? new TextSpan();
                if (nameSpan.Contains(absolutePosition))
                {
                    flags |= XmlLocationFlags.Name;
                }

                TextSpan valueSpan = syntaxNode.ValueNode?.Span ?? new TextSpan();
                if (absolutePosition >= valueSpan.Start + 1 && absolutePosition <= valueSpan.End - 1)
                {
                    flags |= XmlLocationFlags.Value;
                }

                break;
            }

            case XSElementText text:
            {
                flags |= XmlLocationFlags.Text | XmlLocationFlags.Element | XmlLocationFlags.Value;

                break;
            }

            case XSWhitespace whitespace:
            {
                flags |= XmlLocationFlags.Whitespace | XmlLocationFlags.Element | XmlLocationFlags.Value;

                break;
            }
            }

            return(flags);
        }