Exemple #1
0
        internal ITextSnapshot AdvanceToCurrentSnapshot()
        {
            //We don't need to take a snapshot of the results because the results are only modified on this thread.
            ITextSnapshot oldSnapshot = _results.Snapshot;
            ITextSnapshot newSnapshot = _buffer.CurrentSnapshot;

            if (oldSnapshot != newSnapshot)
            {
                //The results are all on an old snapshot. We need to project them forward (even though that might cause some stale and incorrect
                //results).
                NormalizedSpanCollection newMatches       = TextSearchNavigator.TranslateTo(oldSnapshot, _results.Matches, newSnapshot);
                NormalizedSpanCollection newSearchedSpans = NormalizedSpanCollection.Empty;

                if ((_results.SearchedSpans.Count != 0) && !_options.HasFlag(FindOptions.Multiline))
                {
                    //Advance our record of the spans that have already been searched to the new snapshot as well.
                    newSearchedSpans = BackgroundSearch <T> .TranslateToAndExtend(oldSnapshot, _results.SearchedSpans, newSnapshot);

                    //But remove anything on a TextSnapshotLine that was modified by the change.
                    List <Span>  changedSpansOnNewSnapshot = new List <Span>();
                    ITextVersion version = oldSnapshot.Version;
                    while (version != newSnapshot.Version)
                    {
                        foreach (var change in version.Changes)
                        {
                            changedSpansOnNewSnapshot.Add(BackgroundSearch <T> .Extend(newSnapshot, Tracking.TrackSpanForwardInTime(SpanTrackingMode.EdgeInclusive, change.NewSpan,
                                                                                                                                    version.Next, newSnapshot.Version)));
                        }

                        version = version.Next;
                    }

                    if (changedSpansOnNewSnapshot.Count > 0)
                    {
                        NormalizedSpanCollection changes = new NormalizedSpanCollection(changedSpansOnNewSnapshot);

                        //Remove the spans touched by changes from the spans we've searched
                        newSearchedSpans = NormalizedSpanCollection.Difference(newSearchedSpans, changes);
                    }
                }

                _results = new SearchResults(newSnapshot, newMatches, newSearchedSpans);
            }

            return(newSnapshot);
        }
Exemple #2
0
        internal void ProcessQueue()
        {
            // Ensure the thread that is doing the work is both low priority and also background
            try
            {
                Thread.CurrentThread.Priority = ThreadPriority.Lowest;

                //Only one instance of this thread is running at a time, so we don't need to put locks around the bits that update
                //our state (only the bits that play with the results queue).
                while (true)
                {
                    if (_isDisposed)
                    {
                        return;
                    }

                    NormalizedSnapshotSpanCollection request;
                    lock (_requestQueue)
                    {
                        //Do not dequeue the result here ... if a new request comes in while we are processing this request,
                        //we do not want to start a new thread.
                        request = _requestQueue.Peek();
                    }

                    //Always do searches on the current snapshot of the buffer, migrating results to that snapshot
                    //if needed.
                    ITextSnapshot snapshot = this.AdvanceToCurrentSnapshot();

                    NormalizedSpanCollection requestedSpans;
                    if (_options.HasFlag(FindOptions.Multiline))
                    {
                        //Multi-line searches are all or nothing.
                        if (_results.SearchedSpans.Count == 0)
                        {
                            requestedSpans = new NormalizedSpanCollection(new Span(0, snapshot.Length));
                        }
                        else
                        {
                            Debug.Assert((_results.SearchedSpans.Count == 1) && (_results.SearchedSpans[0].Start == 0) && (_results.SearchedSpans[0].End == snapshot.Length));
                            requestedSpans = NormalizedSpanCollection.Empty;
                        }
                    }
                    else
                    {
                        requestedSpans = BackgroundSearch <T> .TranslateToAndExtend(request[0].Snapshot, request, snapshot);

                        if (_results.SearchedSpans.Count > 0)
                        {
                            if ((_results.SearchedSpans.Count == 1) && (_results.SearchedSpans[0].Start == 0) && (_results.SearchedSpans[0].End == snapshot.Length))
                            {
                                //We've already got results for the entire buffer.
                                requestedSpans = NormalizedSpanCollection.Empty;
                            }
                            else
                            {
                                requestedSpans = NormalizedSpanCollection.Difference(requestedSpans, _results.SearchedSpans);
                            }
                        }
                    }

                    bool dequeueRequest = true;
                    if (requestedSpans.Count > 0)
                    {
                        IList <Span> newMatches = this.FindAll(snapshot, requestedSpans);

                        if (_isDisposed)
                        {
                            return;
                        }

                        if (snapshot == _buffer.CurrentSnapshot)
                        {
                            //The search completed without the buffer changing out from under us, add in the new results.
                            //Remove any stale results in the places we searched (since we do not remove potentially stale results
                            //on a text change, we have to remove them here) and then add in the results we found.
                            if (_options.HasFlag(FindOptions.Multiline))
                            {
                                //Multiline searches are always whole buffer searches, so we can skip the set operations.
                                Debug.Assert(requestedSpans.Count == 1);
                                Debug.Assert(requestedSpans[0].Start == 0);
                                Debug.Assert(requestedSpans[0].Length == snapshot.Length);

                                _results = new SearchResults(snapshot,
                                                             new NormalizedSpanCollection(newMatches),
                                                             new NormalizedSpanCollection(new Span(0, snapshot.Length)));
                            }
                            else
                            {
                                //Remove the stale results.
                                NormalizedSpanCollection m = NormalizedSpanCollection.Difference(_results.Matches, requestedSpans);

                                //Add in the new results.
                                if (newMatches.Count > 0)
                                {
                                    m = NormalizedSpanCollection.Union(m, new NormalizedSpanCollection(newMatches));
                                }

                                //Save the results
                                _results = new SearchResults(snapshot,
                                                             m,
                                                             NormalizedSpanCollection.Union(_results.SearchedSpans, requestedSpans));
                            }

                            //We completed the search & updated the results ... have the tagger to raise the appropriate changed event
                            //on the span we just searched.
                            //
                            //We can't raise the tags changed on just the results since we also need to signal that stale results have
                            //been removed.
                            _callback(snapshot, requestedSpans);
                        }
                        else
                        {
                            //The buffer changed so we can't trust the results we just got (the search may not have completed).
                            //Don't dequeue the request and we'll repeat the process (but on the correct snapshot).
                            dequeueRequest = false;
                        }
                    }

                    if (dequeueRequest)
                    {
                        lock (_requestQueue)
                        {
                            //Nothing should have moved the request out of the queue.
                            Debug.Assert(object.ReferenceEquals(request, _requestQueue.Peek()));

                            _requestQueue.Dequeue();

                            if (_requestQueue.Count == 0)
                            {
                                //No more requests are pending, release the worker thread.
                                return;
                            }
                        }
                    }
                }
            }
            finally
            {
                Thread.CurrentThread.Priority = ThreadPriority.Normal;
            }
        }