예제 #1
0
        /// <summary>
        /// Start a background search for all instances of this.highlight.
        /// </summary>
        /// <returns>
        /// true if a either a search has been queued or if the adornments/margin have been cleared since the highlight was removed.
        /// </returns>
        private bool UpdateMatches(bool wereAdornmentsEnabled = true)
        {
            if (_hasEvents)
            {
                SnapshotSpan?oldHighlightSpan = _highlightSpan;
                string       oldHighlight     = _highlight;

                bool matchWholeWord = _textView.Selection.IsEmpty;
                _highlightSpan = matchWholeWord
                                     ? BackgroundSearch.GetExtentOfWord(_textView.Caret.Position.BufferPosition)
                                     : this.SelectionToHighlightSpan();

                _highlight = (_highlightSpan.HasValue) ? _highlightSpan.Value.GetText() : null;

                //Do a new search if the highlight changed, there is no existing search, or the existing search was on the wrong snapshot.
                if ((_highlight != oldHighlight) || (_search == null) || (_search.Snapshot != _textView.TextSnapshot))
                {
                    //The text of the highlight changes ... restart the search.
                    if (_search != null)
                    {
                        //Stop and blow away the old search (even if it didn't finish, the results are not interesting anymore).
                        _search.Abort();
                        _search = null;
                    }

                    if (_highlight != null)
                    {
                        //The underlying buffer could be very large, meaning that doing the search for all matches on the UI thread
                        //is a bad idea. Do the search on the background thread and use a callback to invalidate the visual when
                        //the entire search has completed.
                        _search = new BackgroundSearch(_textView.TextSnapshot, _highlight, matchWholeWord,
                                                       delegate
                        {
                            //Force the invalidate to happen on the UI thread to satisfy WPF
                            this.Dispatcher.Invoke(DispatcherPriority.Normal,
                                                   new DispatcherOperationCallback(delegate
                            {
                                //Guard against the view closing before dispatcher executes this.
                                if (!_isDisposed)
                                {
                                    this.InvalidateVisual();
                                    this.RedrawAdornments();
                                }
                                return(null);
                            }),
                                                   null);
                        });
                    }
                    else
                    {
                        //no highlight == no adornments or marks.
                        _layer.RemoveAllAdornments();
                        this.InvalidateVisual();
                    }

                    return(true);
                }
                else if ((oldHighlight != null) && wereAdornmentsEnabled && this.AdornmentsActive)
                {
                    //The highlight didn't change and isn't null ... therefore both old & new highlight spans have values. Update the adornments so we don't highlight the
                    //match the caret is on.
                    SnapshotSpan translatedOldHighlightSpan = oldHighlightSpan.Value.TranslateTo(_textView.TextSnapshot, SpanTrackingMode.EdgeInclusive);
                    if (translatedOldHighlightSpan != _highlightSpan.Value)
                    {
                        //The spans moved (e.g. the user moved from this on one line to this on another).
                        //Remove the adornment from the new highlight.
                        _layer.RemoveAdornmentsByVisualSpan(_highlightSpan.Value);

                        //Add an adornment at the old source of the highlight span.
                        Geometry g = _textView.TextViewLines.GetMarkerGeometry(translatedOldHighlightSpan);
                        if (g != null)
                        {
                            _layer.AddAdornment(translatedOldHighlightSpan, null, new GeometryAdornment(_adornmentMatchBrush, g));
                        }
                    }
                }
            }

            return(false);
        }
        /// <summary>
        /// Start a background search for all instances of this.highlight.
        /// </summary>
        private void UpdateMarginMatches(bool force)
        {
            if (((this.matchBrush != null) && this.IsVisible) || (this.adornmentMatchBrush != null))
            {
                SnapshotSpan?oldHighlightSpan = this.highlightSpan;
                string       oldHighlight     = this.highlight;

                this.highlightSpan = BackgroundSearch.GetExtentOfWord(this.textView.Caret.Position.BufferPosition);
                this.highlight     = this.highlightSpan.HasValue ? this.highlightSpan.Value.GetText() : null;

                if ((this.highlight != oldHighlight) || force)
                {
                    //The text of the highlight changes ... restart the search.
                    if (this.search != null)
                    {
                        //Stop and blow away the old search (even if it didn't finish, the results are not interesting anymore).
                        this.search.Abort();
                        this.search = null;
                    }

                    if (this.highlight != null)
                    {
                        //The underlying buffer could be very large, meaning that doing the search for all matches on the UI thread
                        //is a bad idea. Do the search on the background thread and use a callback to invalidate the visual when
                        //the entire search has completed.
                        this.search = new BackgroundSearch(this.textView.TextSnapshot, this.highlight,
                                                           delegate
                        {
                            //Force the invalidate to happen on the UI thread to satisfy WPF
                            this.Dispatcher.Invoke(DispatcherPriority.Normal,
                                                   new DispatcherOperationCallback(delegate
                            {
                                this.InvalidateVisual();
                                this.RedrawAdornments(null);
                                return(null);
                            }),
                                                   null);
                        });
                    }
                    else
                    {
                        //no highlight == no adornments or marks.
                        this.layer.RemoveAllAdornments();
                        this.InvalidateVisual();
                    }
                }
                else if (oldHighlight != null)
                {
                    //The highlight didn't change and isn't null ... therefore both old & new highlight spans have values.
                    SnapshotSpan translatedOldHighlightSpan = oldHighlightSpan.Value.TranslateTo(this.textView.TextSnapshot, SpanTrackingMode.EdgeInclusive);
                    if (translatedOldHighlightSpan != this.highlightSpan.Value)
                    {
                        if (this.adornmentMatchBrush != null)
                        {
                            //The spans moved (e.g. the user moved from this on one line to this on another).
                            //Remove the adornment from the new highlight.
                            this.layer.RemoveAdornmentsByVisualSpan(this.highlightSpan.Value);

                            //Add an adornment at the old source of the highlight span.
                            Geometry g = this.textView.TextViewLines.GetMarkerGeometry(translatedOldHighlightSpan);
                            if (g != null)
                            {
                                this.layer.AddAdornment(translatedOldHighlightSpan, null, new GeometryAdornment(this.adornmentMatchBrush, g));
                            }
                        }

                        //We also need to update the caret position in the margin.
                        this.InvalidateVisual();
                    }
                }
            }
            else if (this.IsVisible && (this.caretBrush != null))
            {
                //Neither the match brush nor the adornment brush exists so we won't be doing a background search.
                //But we are visible and the caret brush exists, so invalidate the visual so that we can update the location of the caret.
                this.InvalidateVisual();
            }
        }