Ejemplo n.º 1
0
        static int FindNextChild(TrackingSpanNode <T> root, SnapshotPoint point, int currentChildIndex)
        {
            // If we're already at the end, there's no need to continue searching
            if (currentChildIndex == root.Children.Count - 1)
            {
                return(currentChildIndex + 1);
            }

            return(FindChild(point, root.Children, left: true, lo: currentChildIndex + 1).Index);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Create a tracking span tree for the given buffer.
        /// </summary>
        /// <param name="buffer">The buffer that all the spans in this tree are in.</param>
        /// <param name="keepTrackingCurrent">The tree should not allow tracking spans to point
        /// to old versions, at the expense of walking the tree on every text change.</param>
        public TrackingSpanTree(ITextBuffer buffer, bool keepTrackingCurrent)
        {
            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            Buffer = buffer;
            Count  = 0;

            // Leave the tracking span parameter as null, since it is
            // never used (assumed to always be the entire buffer)
            Root = new TrackingSpanNode <T>(default(T), null);

            if (keepTrackingCurrent)
            {
                buffer.Changed += OnBufferChanged;
            }
        }
Ejemplo n.º 3
0
        static bool RemoveItemFromRoot(T item, SnapshotSpan span, TrackingSpanNode <T> root)
        {
            if (root.Children.Count == 0)
            {
                return(false);
            }

            var result = FindChild(span.Start, root.Children, left: true);

            if (result.Index < 0 || result.Index >= root.Children.Count)
            {
                return(false);
            }

            // Search from this index onward (there may be empty regions in the way)
            for (int i = result.Index; i < root.Children.Count; i++)
            {
                var          child     = root.Children[i];
                SnapshotSpan childSpan = child.TrackingSpan.GetSpan(span.Snapshot);

                // Check to see if we've walked past it
                if (childSpan.Start > span.End)
                {
                    return(false);
                }
                else if (childSpan == span && object.Equals(child.Item, item))
                {
                    root.Children.RemoveAt(i);
                    root.Children.InsertRange(i, child.Children);
                    return(true);
                }
                else if (childSpan.Contains(span))
                {
                    if (RemoveItemFromRoot(item, span, child))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Try to add an item to the tree with the given tracking span.
        /// </summary>
        /// <param name="item">The item to add to the tree.</param>
        /// <param name="trackingSpan">The tracking span it is associated with.</param>
        /// <returns>The newly added node, if the item was successfully added; <c>null</c> if adding the item to the tree would
        /// violate the well-formedness of the tree.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="trackingSpan"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">If the tracking mode of <paramref name="trackingSpan"/> is not <see cref="SpanTrackingMode.EdgeExclusive"/>.</exception>
        public TrackingSpanNode <T> TryAddItem(T item, ITrackingSpan trackingSpan)
        {
            if (trackingSpan == null)
            {
                throw new ArgumentNullException(nameof(trackingSpan));
            }

            if (trackingSpan.TrackingMode != SpanTrackingMode.EdgeExclusive)
            {
                throw new ArgumentException("The tracking mode of the given tracking span must be SpanTrackingMode.EdgeExclusive", nameof(trackingSpan));
            }

            SnapshotSpan         spanToAdd = trackingSpan.GetSpan(Buffer.CurrentSnapshot);
            TrackingSpanNode <T> node      = new TrackingSpanNode <T>(item, trackingSpan);

            var newNode = TryAddNodeToRoot(node, spanToAdd, Root);

            if (newNode != null)
            {
                Count++;
            }

            return(newNode);
        }
Ejemplo n.º 5
0
        static TrackingSpanNode <T> TryAddNodeToRoot(TrackingSpanNode <T> newNode, SnapshotSpan span, TrackingSpanNode <T> root)
        {
            var children = root.Children;

            if (children.Count == 0)
            {
                children.Add(newNode);
                return(newNode);
            }

            FindResult leftResult  = FindIndexForAdd(span.Start, children, left: true);
            FindResult rightResult = FindIndexForAdd(span.End, children, left: false);

            // See if we can add the node anywhere

            // The indices cross if the searches fail, and the node is inside a gap.
            if (leftResult.Index > rightResult.Index)
            {
                // Case #1: If the new node should go in a gap between two nodes, just insert it in the correct location
                Debug.Assert(leftResult.Type == FindResultType.Outer || rightResult.Type == FindResultType.Outer);

                children.Insert(leftResult.Index, newNode);
                return(newNode);
            }
            else
            {
                if (leftResult.Type == FindResultType.Inner || rightResult.Type == FindResultType.Inner)
                {
                    // Case #2: The new node is contained entirely in a single child node, so add it to that child
                    //  Check the nodes at either end of the resulting indices (they may not be the same index due to
                    //  0-length nodes that abut the correct child).
                    if (children[leftResult.Index].TrackingSpan.GetSpan(span.Snapshot).Contains(span))
                    {
                        return(TryAddNodeToRoot(newNode, span, children[leftResult.Index]));
                    }
                    if (leftResult.Index != rightResult.Index && children[rightResult.Index].TrackingSpan.GetSpan(span.Snapshot).Contains(span))
                    {
                        return(TryAddNodeToRoot(newNode, span, children[rightResult.Index]));
                    }

                    // This fails if the node isn't fully contained in a single child
                }
                else
                {
                    // Case #3: The new node contains any number of children, so we:
                    int start = leftResult.Index;
                    int count = rightResult.Index - leftResult.Index + 1;

                    // a) Add all the children this should contain to the new node,
                    newNode.Children.AddRange(children.Skip(start).Take(count));
                    // b) Remove them from the existing root node, and
                    children.RemoveRange(start, count);
                    // c) Add the new node in their place
                    children.Insert(start, newNode);

                    return(newNode);
                }
            }

            // We couldn't find a place to add this node, so return failure
            return(null);
        }
Ejemplo n.º 6
0
        static IEnumerable <TrackingSpanNode <T> > FindNodes(NormalizedSnapshotSpanCollection spans, TrackingSpanNode <T> root, bool recurse = true, bool contained = false)
        {
            if (spans == null || spans.Count == 0 || root.Children.Count == 0)
            {
                yield break;
            }

            int          requestIndex   = 0;
            SnapshotSpan currentRequest = spans[requestIndex];

            // Find the first child
            FindResult findResult = FindChild(currentRequest.Start, root.Children, left: true);
            int        childIndex = findResult.Index;

            if (childIndex >= root.Children.Count)
            {
                yield break;
            }

            ITextSnapshot snapshot     = currentRequest.Snapshot;
            SnapshotSpan  currentChild = root.Children[childIndex].TrackingSpan.GetSpan(snapshot);

            while (requestIndex < spans.Count && childIndex < root.Children.Count)
            {
                if (currentRequest.Start > currentChild.End)
                {
                    // Find the next child
                    childIndex = FindNextChild(root, currentRequest.Start, childIndex);

                    if (childIndex < root.Children.Count)
                    {
                        currentChild = root.Children[childIndex].TrackingSpan.GetSpan(snapshot);
                    }
                }
                else if (currentChild.Start > currentRequest.End)
                {
                    // Skip to the next request
                    if (++requestIndex < spans.Count)
                    {
                        currentRequest = spans[requestIndex];
                    }
                }
                else
                {
                    // Yield the region then move to the next
                    if (!contained || currentRequest.Contains(currentChild))
                    {
                        yield return(root.Children[childIndex]);
                    }

                    if (recurse)
                    {
                        foreach (var result in FindNodes(spans, root.Children[childIndex], recurse, contained))
                        {
                            yield return(result);
                        }
                    }

                    // Find the next child
                    childIndex = FindNextChild(root, currentRequest.Start, childIndex);

                    if (childIndex < root.Children.Count)
                    {
                        currentChild = root.Children[childIndex].TrackingSpan.GetSpan(snapshot);
                    }
                }
            }
        }
Ejemplo n.º 7
0
 /// <summary>
 /// Check if a given node is a toplevel node (has no parents).
 /// </summary>
 /// <param name="node">The node to check.</param>
 /// <returns><c>true</c> if the node has no parent node.</returns>
 public bool IsNodeTopLevel(TrackingSpanNode <T> node)
 {
     return(Root.Children.Contains(node));
 }