private void DrawChanges(DrawingContext drawingContext, NormalizedSnapshotSpanCollection changes, Brush brush)
		{
			if (changes.Count > 0)
			{
				double yTop = Math.Floor(_scrollBar.GetYCoordinateOfBufferPosition(changes[0].Start)) + markerStartOffset;
				double yBottom = Math.Ceiling(_scrollBar.GetYCoordinateOfBufferPosition(changes[0].End)) + markerEndOffset;

				for (int i = 1; i < changes.Count; ++i)
				{
					double y = _scrollBar.GetYCoordinateOfBufferPosition(changes[i].Start) + markerStartOffset;
					if (yBottom < y)
					{
						drawingContext.DrawRectangle(
							brush,
							null,
							new Rect(0, yTop, markerWidth, yBottom - yTop));

						yTop = y;
					}

					yBottom = Math.Ceiling(_scrollBar.GetYCoordinateOfBufferPosition(changes[i].End)) + markerEndOffset;
				}

				drawingContext.DrawRectangle(
					brush,
					null,
					new Rect(0, yTop, markerWidth, yBottom - yTop));
			}
		}
Example #2
0
		public void Add(ISynchronousClassifier classifier, NormalizedSnapshotSpanCollection spans, CancellationToken cancellationToken) {
			if (classifier == null)
				throw new ArgumentNullException(nameof(classifier));
			if (spans == null)
				throw new ArgumentNullException(nameof(spans));
			foreach (var span in spans) {
				if (spansCount > 0)
					htmlWriter.WriteRaw(delimiter);
				spansCount++;
				var tagSpans = classifier.GetClassificationSpans(span, cancellationToken);
				var text = span.GetText();
				int pos = span.Start.Position;
				foreach (var tagSpan in tagSpans) {
					if (pos < tagSpan.Span.Start) {
						WriteCss(classificationFormatMap.DefaultTextProperties);
						htmlWriter.WriteSpan(cssWriter.ToString(), text, pos - span.Start.Position, tagSpan.Span.Start.Position - pos);
					}
					WriteCss(classificationFormatMap.GetTextProperties(tagSpan.ClassificationType));
					htmlWriter.WriteSpan(cssWriter.ToString(), text, tagSpan.Span.Start - span.Start.Position, tagSpan.Span.Length);
					pos = tagSpan.Span.End;
				}
				if (pos < span.End) {
					WriteCss(classificationFormatMap.DefaultTextProperties);
					htmlWriter.WriteSpan(cssWriter.ToString(), text, pos - span.Start.Position, span.End.Position - pos);
				}
			}
		}
        public void FormattedStringBuilderEndToEnd1()
        {
            var classificationFormatMap = new MockClassificationFormatMap();
            var htmlMarkupProvider = new HtmlMarkupProvider(
                classificationFormatMap,
                MockClassificationType.Default,
                Brushes.White);
            var classifier = new MockClassifier();

            var formattedStringBuilder = new FormattedStringBuilder(
                htmlMarkupProvider,
                classifier,
                MockClassificationType.Default,
                waitIndicator: null);

            var snapshot = new MockTextSnapshot("bla");
            var spans = new NormalizedSnapshotSpanCollection(new []
            {
                new SnapshotSpan(snapshot, 0, 3)
            });

            var actualResult = formattedStringBuilder.AppendSnapshotSpans(spans);
            var expectedResult = "<pre style=\"font-family:Consolas;font-size:12;color:black;background:white;\">b<span style=\"color:blue;\">l</span>a\r\n</pre>";

            Assert.AreEqual(expectedResult, actualResult);
        }
Example #4
0
 public void GetOverarchingSpan2()
 {
     var spans = new NormalizedSnapshotSpanCollection();
     _selection.SetupGet(x => x.SelectedSpans).Returns(spans).Verifiable();
     Assert.True(TextSelectionUtil.GetOverarchingSelectedSpan(_selection.Object).IsNone());
     _selection.Verify();
 }
Example #5
0
		string GenerateHtmlFragmentCore(NormalizedSnapshotSpanCollection spans, ITextView textView, string delimiter, CancellationToken cancellationToken) {
			ISynchronousClassifier classifier = null;
			try {
				int tabSize;
				IClassificationFormatMap classificationFormatMap;
				if (textView != null) {
					classifier = synchronousViewClassifierAggregatorService.GetSynchronousClassifier(textView);
					classificationFormatMap = classificationFormatMapService.GetClassificationFormatMap(textView);
					tabSize = textView.Options.GetTabSize();
				}
				else {
					classifier = spans.Count == 0 ? null : synchronousClassifierAggregatorService.GetSynchronousClassifier(spans[0].Snapshot.TextBuffer);
					classificationFormatMap = classificationFormatMapService.GetClassificationFormatMap(AppearanceCategoryConstants.TextEditor);
					tabSize = defaultTabSize;
				}
				tabSize = OptionsHelpers.FilterTabSize(tabSize);

				var builder = new HtmlBuilder(classificationFormatMap, delimiter, tabSize);
				if (spans.Count != 0)
					builder.Add(classifier, spans, cancellationToken);
				return builder.Create();
			}
			finally {
				(classifier as IDisposable)?.Dispose();
			}
		}
        public NormalizedSnapshotSpanCollection UncommentSpans(NormalizedSnapshotSpanCollection spans)
        {
            Contract.Requires<ArgumentNullException>(spans != null, "spans");
            Contract.Ensures(Contract.Result<NormalizedSnapshotSpanCollection>() != null);

            throw new NotImplementedException();
        }
Example #7
0
 public void CalculateForBlock3()
 {
     var buffer = EditorUtil.CreateBuffer("dog", "cat", "chicken");
     var col = new NormalizedSnapshotSpanCollection(buffer.GetSpan(0, 2));
     var span = _calcRaw.CalculateForBlock(buffer.GetLine(1).Start.Add(1), col);
     Assert.IsTrue(span.IsMultiple);
     Assert.AreEqual(buffer.GetLine(1).Start.Add(1).GetSpan(2), span.AsMultiple().Item2[0]);
 }
        private static IEnumerable<ITagSpan<OutliningRegionTag>> GetTags(string input)
        {
            var buffer = new FakeTextBuffer(input);
            var tagger = new TemplateOutliningTagger(buffer);

            var snapshotSpans = new NormalizedSnapshotSpanCollection(new SnapshotSpan(buffer.CurrentSnapshot, 0, buffer.CurrentSnapshot.Length));
            return tagger.GetTags(snapshotSpans);
        }
Example #9
0
		public string GenerateHtmlFragment(NormalizedSnapshotSpanCollection spans, string delimiter, CancellationToken cancellationToken) {
			if (spans == null)
				throw new ArgumentNullException(nameof(spans));
			if (delimiter == null)
				throw new ArgumentNullException(nameof(delimiter));

			return GenerateHtmlFragmentCore(spans, null, delimiter, cancellationToken);
		}
Example #10
0
 public void GetOverarchingSpan3()
 {
     var buffer = CreateTextBuffer("foo bar");
     var span = buffer.GetLineRange(0).Extent;
     var col = new NormalizedSnapshotSpanCollection(span);
     _selection.SetupGet(x => x.SelectedSpans).Returns(col).Verifiable();
     Assert.Equal(span, TextSelectionUtil.GetOverarchingSelectedSpan(_selection.Object).Value);
     _selection.Verify();
 }
Example #11
0
 public void GetOverarchingSpan4()
 {
     var buffer = CreateTextBuffer("foo", "baz", "bar");
     var span1 = buffer.GetLineRange(0).Extent;
     var span2 = buffer.GetLineRange(0, 1).Extent;
     var col = new NormalizedSnapshotSpanCollection(new SnapshotSpan[] { span1, span2 });
     _selection.SetupGet(x => x.SelectedSpans).Returns(col).Verifiable();
     Assert.AreEqual(buffer.GetLineRange(0, 1).Extent, TextSelectionUtil.GetOverarchingSelectedSpan(_selection.Object).Value);
     _selection.Verify();
 }
        public static void GetTagsReturnsErrorSpanForSemanticError()
        {
            var buffer = new FakeTextBuffer("<#@ include file=\" \" #>");
            var tagger = new TemplateErrorTagger(buffer);

            var snapshotSpans = new NormalizedSnapshotSpanCollection(new SnapshotSpan(buffer.CurrentSnapshot, 0, buffer.CurrentSnapshot.Length));
            ITagSpan<ErrorTag> errorSpan = tagger.GetTags(snapshotSpans).Single();

            Assert.Equal(new Span(12, 8), errorSpan.Span);
            Assert.Contains("File", (string)errorSpan.Tag.ToolTipContent, StringComparison.OrdinalIgnoreCase);
        }
Example #13
0
 public void ShouldClassifyScenario()
 {
     TestInitialise("Features/gherkin.feature");
     var snapShotSpan = new SnapshotSpan(new MockTextSnapshot(featureFileContent), new Span(0, 15));
     var spanCollection = new NormalizedSnapshotSpanCollection(new[] { snapShotSpan });
     var tags = playTagger.GetTags(spanCollection);
     var tag = tags.First(_ => _.Span.GetText().StartsWith("  Scenario: SC2")).Tag;
     Assert.AreEqual("Scenario: SC2" + Environment.NewLine +
                     "  Given something" + Environment.NewLine +
                     "  When some event occurs" + Environment.NewLine +
                     "  Then there is some outcome", tag.GetText());
 }
        private static bool IsComment(SnapshotPoint position)
        {
            if (position.Position < 2)
                return false;

            var tagger = position.Snapshot.TextBuffer.Properties.GetProperty<ITagger<ClassificationTag>>(jsTaggerType);

            Span span = Span.FromBounds(position.Position - 1, position.Position);
            var spans = new NormalizedSnapshotSpanCollection(new SnapshotSpan(position.Snapshot, span));
            var classifications = tagger.GetTags(spans);

            return classifications.Any(c => c.Tag.ClassificationType.IsOfType("comment"));
        }
        public static IElisionBuffer CreateElisionBufferWithoutIndentation(
            this IProjectionBufferFactoryService factoryService,
            IEditorOptions editorOptions,
            IContentType contentType,
            IEnumerable<SnapshotSpan> exposedSpans)
        {
            var spans = new NormalizedSnapshotSpanCollection(exposedSpans);

            if (spans.Count > 0)
            {
                // BUG(6335): We have to make sure that the spans refer to the current snapshot of
                // the buffer.
                var buffer = spans.First().Snapshot.TextBuffer;
                var currentSnapshot = buffer.CurrentSnapshot;
                spans = new NormalizedSnapshotSpanCollection(
                    spans.Select(s => s.TranslateTo(currentSnapshot, SpanTrackingMode.EdgeExclusive)));
            }

            contentType = contentType ?? factoryService.ProjectionContentType;
            var elisionBuffer = factoryService.CreateElisionBuffer(
                null, spans, ElisionBufferOptions.None, contentType);

            if (spans.Count > 0)
            {
                var snapshot = spans.First().Snapshot;
                var buffer = snapshot.TextBuffer;

                // We need to figure out the shorted indentation level of the exposed lines.  We'll
                // then remove that indentation from all lines.
                var indentationColumn = DetermineIndentationColumn(editorOptions, spans);

                var spansToElide = new List<Span>();

                foreach (var span in spans)
                {
                    var startLineNumber = snapshot.GetLineNumberFromPosition(span.Start);
                    var endLineNumber = snapshot.GetLineNumberFromPosition(span.End);

                    for (var lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++)
                    {
                        var line = snapshot.GetLineFromLineNumber(lineNumber);
                        var lineOffsetOfColumn = line.GetLineOffsetFromColumn(indentationColumn, editorOptions);
                        spansToElide.Add(Span.FromBounds(line.Start, line.Start + lineOffsetOfColumn));
                    }
                }

                elisionBuffer.ElideSpans(new NormalizedSpanCollection(spansToElide));
            }

            return elisionBuffer;
        }
Example #16
0
 public void CalculateForBlock4()
 {
     var buffer = EditorUtil.CreateBuffer("dog again", "cat again", "chicken");
     var col = new NormalizedSnapshotSpanCollection(new SnapshotSpan[]
     {
         buffer.GetLine(0).Start.GetSpan(2),
         buffer.GetLine(1).Start.GetSpan(2)
     });
     var span = _calcRaw.CalculateForBlock(buffer.GetLine(1).Start, col);
     Assert.IsTrue(span.IsMultiple);
     col = span.AsMultiple().item2;
     Assert.AreEqual(buffer.GetLine(1).Start.GetSpan(2), col[0]);
     Assert.AreEqual(buffer.GetLine(2).Start.GetSpan(2), col[1]);
 }
		private IEnumerable<SnapshotSpan> Split(SnapshotSpan span, IEnumerable<SnapshotSpan> remove) {
			var removeNorm = new NormalizedSnapshotSpanCollection(remove);
			foreach (var r in removeNorm.OrderBy(x => x.Start.Position)) {
				if (r.Start < span.End) {
					if (r.Start > span.Start) {
						yield return new SnapshotSpan(span.Start, r.Start);
					}
					if (r.End < span.End) {
						span = new SnapshotSpan(r.End, span.End);
					} else {
						yield break;
					}
				}
			}
			yield return span;
		}
        public void CreateRegionsAround_SelectionAtEndOfDocument()
        {
            var textBuffer = GetCSharpTextBuffer("Outlining1.txt");
              var snapshot = textBuffer.CurrentSnapshot;
              var outlining = SelectionOutliningManager.Get(textBuffer);

              int lineCount = snapshot.LineCount;
              var selectionSpan = GetSpanFromLines(snapshot, lineCount-10, lineCount-1);
              outlining.CreateRegionsAround(selectionSpan);

              // validate GetTags() gives us two spans
              var allDocument = new NormalizedSnapshotSpanCollection(snapshot.GetSpan());
              var tags = outlining.GetTags(allDocument).ToList();

              var span1 = GetSpanFromLines(snapshot, 0, (lineCount - 10)-1);
              Assert.Equal(span1, tags.First());
        }
Example #19
0
        public void ShouldClassifyScenarioWithExamples()
        {
            TestInitialise("Features/gherkin.feature");
            var snapShotSpan = new SnapshotSpan(new MockTextSnapshot(featureFileContent), new Span(0, 15));
            var spanCollection = new NormalizedSnapshotSpanCollection(new[] { snapShotSpan });
            var tags = playTagger.GetTags(spanCollection);
            var tag = tags.First(span => span.Span.GetText().StartsWith("  Scenario: SC1")).Tag;

            Assert.AreEqual("Scenario: SC1" + Environment.NewLine +
                            "  Given numbers [left] and [right]" + Environment.NewLine +
                            "  When I add the numbers" + Environment.NewLine +
                            "  Then the sum is [sum]" + Environment.NewLine +
                            "Examples:" + Environment.NewLine +
                            "     | left | right | sum |" + Environment.NewLine +
                            "     | 1 | 2 | 3 |" + Environment.NewLine +
                            "     | 3 | 4 | 7 |", tag.GetText());
        }
Example #20
0
        public IEnumerable<BracePos> BracesInSpans(NormalizedSnapshotSpanCollection spans)
        {
            if ( ScanIsUnnecessary() ) yield break;

              for ( int i = 0; i < spans.Count; i++ ) {
            var wantedSpan = spans[i];
            EnsureLinesInPreferredSpan(wantedSpan);
            int startIndex = FindIndexOfBraceAtOrAfter(wantedSpan.Start);
            if ( startIndex < 0 ) {
              continue;
            }
            for ( int j = startIndex; j < braces.Count; j++ ) {
              BracePos bp = braces[j];
              if ( bp.Position > wantedSpan.End ) break;
              yield return bp;
            }
              }
        }
		public void Render(DrawingContext drawingContext)
		{
			if (!HighlightWordTaggerProvider.Taggers.ContainsKey(_textView))
			{
				return;
			}

			NormalizedSnapshotSpanCollection spans = new NormalizedSnapshotSpanCollection(new SnapshotSpan(_textView.TextSnapshot, 0, _textView.TextSnapshot.Length));
			IEnumerable<ITagSpan<HighlightWordTag>> tags = HighlightWordTaggerProvider.Taggers[_textView].GetTags(spans);
			List<SnapshotSpan> highlightList = new List<SnapshotSpan>();
			foreach (ITagSpan<HighlightWordTag> highlight in tags)
			{
				highlightList.Add(highlight.Span);
			}

			NormalizedSnapshotSpanCollection highlights = new NormalizedSnapshotSpanCollection(highlightList);

			if (highlights.Count > 0)
			{
				double yTop = Math.Floor(_scrollBar.GetYCoordinateOfBufferPosition(highlights[0].Start)) + markerStartOffset;
				double yBottom = Math.Ceiling(_scrollBar.GetYCoordinateOfBufferPosition(highlights[0].End)) + markerEndOffset;

				for (int i = 1; i < highlights.Count; ++i)
				{
					double y = _scrollBar.GetYCoordinateOfBufferPosition(highlights[i].Start) + markerStartOffset;
					if (yBottom < y)
					{
						drawingContext.DrawRectangle(
							Colors.HighlightsBrush,
							null,
							new Rect(_scrollBar.Width - markerWidth, yTop, markerWidth, yBottom - yTop));

						yTop = y;
					}

					yBottom = Math.Ceiling(_scrollBar.GetYCoordinateOfBufferPosition(highlights[i].End)) + markerEndOffset;
				}

				drawingContext.DrawRectangle(
					Colors.HighlightsBrush,
					null,
					new Rect(_scrollBar.Width - markerWidth, yTop, markerWidth, yBottom - yTop));
			}
		}
		public Classifier(CoffeeOverview overview, IClassificationTypeRegistryService classificationRegistry) {
			this.overview = overview;
			this.clsCoffeeString = classificationRegistry.GetClassificationType(VisualFormatNames.CoffeeString);
			this.clsCoffeeIdentifier = classificationRegistry.GetClassificationType(VisualFormatNames.CoffeeIdentifier);
			this.clsCoffeeKeyword = classificationRegistry.GetClassificationType(VisualFormatNames.CoffeeKeyword);
			this.clsCoffeeNumericLiteral = classificationRegistry.GetClassificationType(VisualFormatNames.CoffeeNumericLiteral);
			this.clsCoffeeComment = classificationRegistry.GetClassificationType(VisualFormatNames.CoffeeComment);
			overview.MultiLinesChanged += (o, e) => {
				if (this.latestSnapshot != null && this.ClassificationChanged != null) {
					var spans = new NormalizedSnapshotSpanCollection(
						e.Added.Concat(e.Removed)
						.Select(x => x.Span.GetSpan(this.latestSnapshot)));
					foreach (var span in spans) {
						var args = new ClassificationChangedEventArgs(span);
						this.ClassificationChanged(this, args);
					}
				}
			};
		}
        public void CreateRegionsAround_PartialLines()
        {
            var textBuffer = GetCSharpTextBuffer("Outlining1.txt");
              var snapshot = textBuffer.CurrentSnapshot;
              var outlining = SelectionOutliningManager.Get(textBuffer);

              var selectionSpan = GetSpanFromLines(snapshot, 9, 15);
              selectionSpan = new SnapshotSpan(selectionSpan.Start + 10, selectionSpan.End - 2);
              outlining.CreateRegionsAround(selectionSpan);

              // validate GetTags() gives us two spans
              var allDocument = new NormalizedSnapshotSpanCollection(snapshot.GetSpan());
              var tags = outlining.GetTags(allDocument).ToList();

              var span1 = GetSpanFromLines(snapshot, 0, 8);
              Assert.Equal(span1, tags.First());

              var span2 = GetSpanFromLines(snapshot, 16, snapshot.LineCount-1);
              Assert.Equal(span2, tags.Last());
        }
Example #24
0
        public void ShouldClassifyScenarioWithInlineTable()
        {
            TestInitialise("Features/gherkin.feature");

            var snapShotSpan = new SnapshotSpan(new MockTextSnapshot(featureFileContent), new Span(0, 15));
            var spanCollection = new NormalizedSnapshotSpanCollection(new[] { snapShotSpan });
            var tags = playTagger.GetTags(spanCollection);
            var tag = tags.First(span => span.Span.GetText().StartsWith("  Scenario: inline table")).Tag;

            Assert.AreEqual("Scenario: inline table" + Environment.NewLine +
                            "  Given the following people exists:" + Environment.NewLine +
                            "     | Name | Country |" + Environment.NewLine +
                            "     | Morgan Persson | Sweden |" + Environment.NewLine +
                            "     | Jimmy Nilsson | Sweden |" + Environment.NewLine +
                            "     | Jimmy bogard | USA |" + Environment.NewLine +
                            "  When I search for people in sweden" + Environment.NewLine +
                            "  Then I should get:" + Environment.NewLine +
                            "     | Name |" + Environment.NewLine +
                            "     | Morgan Persson |" + Environment.NewLine +
                            "     | Jimmy Nilsson |", tag.GetText());
        }
		internal static NormalizedSnapshotSpanCollection[] GetUnifiedChanges(ITextSnapshot snapshot, IEnumerable<IMappingTagSpan<ChangeTag>> tags)
		{
			List<SnapshotSpan>[] unnormalizedChanges = new List<SnapshotSpan>[4]
			{
				null,
				new List<SnapshotSpan>(),
				new List<SnapshotSpan>(),
				new List<SnapshotSpan>()
			};

			foreach (IMappingTagSpan<ChangeTag> change in tags)
			{
				unnormalizedChanges[(int)change.Tag.ChangeTypes].AddRange(change.Span.GetSpans(snapshot));
			}

			NormalizedSnapshotSpanCollection[] changes = new NormalizedSnapshotSpanCollection[4];
			for (int i = 1; (i <= 3); ++i)
			{
				changes[i] = new NormalizedSnapshotSpanCollection(unnormalizedChanges[i]);
			}

			return changes;
		}
Example #26
0
        public string GenerateHtml(NormalizedSnapshotSpanCollection spans, IWpfTextView textView)
        {
            if (spans == null || spans.Count == 0)
            {
                return "";
            }

            // this will trigger loading of the package
            // so we can ensure ToolsOptionsPage gets created and
            // ToolsOptionsPage.Instance gets set
            var dte = (_DTE)_serviceProvider.GetService(typeof(_DTE));
            var props = dte.Properties[CopyAsHtmlPackage.CategoryName, CopyAsHtmlPackage.PageName];

            IClassificationFormatMap formatMap = _classificationFormatMappingService.GetClassificationFormatMap(textView);
            IClassificationType defaultClassificationType = _classificationTypeRegistry.GetClassificationType("text");
            HtmlMarkupProvider htmlMarkupProvider = new HtmlMarkupProvider(
                formatMap,
                defaultClassificationType,
                textView.Background);
            IClassifier classifier = _classifierAggregatorService.GetClassifier(textView.TextBuffer);

            var formattedStringBuilder = new FormattedStringBuilder(
                htmlMarkupProvider,
                classifier,
                defaultClassificationType,
                this.WaitIndicator);

            string result = formattedStringBuilder.AppendSnapshotSpans(spans);

            var classifierDispose = classifier as System.IDisposable;
            if (classifierDispose != null)
            {
                classifierDispose.Dispose();
            }

            return result;
        }
Example #27
0
 public IEnumerable <ITagSpan <TTagType> > GetTags(NormalizedSnapshotSpanCollection spans) => wrappedTagger.GetTags(spans);
Example #28
0
 public IEnumerable <ITagSpan <RenameTrackingTag> > GetTags(NormalizedSnapshotSpanCollection spans)
 {
     return(GetTags(spans, RenameTrackingTag.Instance));
 }
        public bool Find()
        {
            if (string.IsNullOrEmpty(this.SearchTerm))
            {
                throw new InvalidOperationException("You must set a non-empty search term before searching.");
            }

            bool forward = (this.SearchOptions & FindOptions.SearchReverse) != FindOptions.SearchReverse;
            bool wrap    = (this.SearchOptions & FindOptions.Wrap) == FindOptions.Wrap;
            bool regEx   = (this.SearchOptions & FindOptions.UseRegularExpressions) == FindOptions.UseRegularExpressions;

            ITextSnapshot searchSnapshot = _buffer.CurrentSnapshot;

            //There could be a version skew here if someone calls find from inside a text changed callback on the buffer. That probably wouldn't be a good
            //idea but we need to handle it gracefully.
            this.AdvanceToSnapshot(searchSnapshot);

            SnapshotPoint?searchStart = this.CalculateStartPoint(searchSnapshot, wrap, forward);

            if (searchStart.HasValue)
            {
                int index = 0;
                NormalizedSnapshotSpanCollection searchSpans = this.SearchSpans;

                if (searchSpans != null)
                {
                    Debug.Assert(searchSpans.Count > 0);

                    //Index is potentially outside the range of [0...searchSpans.Count-1] but we handle that below.
                    if (!(TextSearchNavigator.TryGetIndexOfContainingSpan(searchSpans, searchStart.Value, out index) || forward))
                    {
                        //For reversed searches, we want the index of the span before the point if we can't get a span that contains the point.
                        --index;
                    }
                }
                else
                {
                    searchSpans = new NormalizedSnapshotSpanCollection(new SnapshotSpan(searchSnapshot, Span.FromBounds(0, searchSnapshot.Length)));
                }

                int searchIterations = searchSpans.Count;
                for (int i = 0; (i < searchIterations); ++i)
                {
                    //index needs to be normalized to [0 ... searchSpans.Count - 1] but could be negative.
                    index = (index + searchSpans.Count) % searchSpans.Count;

                    SnapshotSpan searchSpan = searchSpans[index];
                    if ((i != 0) || (searchStart.Value < searchSpan.Start) || (searchStart.Value > searchSpan.End))
                    {
                        searchStart = forward ? searchSpan.Start : searchSpan.End;
                    }
                    else if (wrap && (i == 0))
                    {
                        //We will need to repeat the search to account for wrap being on and we are not searching everything in searchSpans[0].
                        //This is the same as simply doing a search for i == searchSpans.Count we we can make happen by bumping the number of iterations.
                        ++searchIterations;
                    }

                    foreach (var result in _textSearchService.FindAll(searchSpan, searchStart.Value, this.SearchTerm, this.SearchOptions & ~FindOptions.Wrap))
                    {
                        // As a safety measure, we don't include results of length zero in the navigator unless regular expressions are being used.
                        // Zero width matches could be useful in RegEx when for example somebody is trying to replace the start of the line using the "^"
                        // pattern.
                        if (result.Length == 0 && !regEx)
                        {
                            continue;
                        }
                        else
                        {
                            // We accept the first match
                            this.CurrentResult = result;
                            return(true);
                        }
                    }

                    if (forward)
                    {
                        ++index;
                    }
                    else
                    {
                        --index;
                    }
                }
            }

            // If nothing was found, then clear the current result
            this.ClearCurrentResult();

            return(false);
        }
Example #30
0
        IEnumerable <ITagSpan <ClippyTag> > ITagger <ClippyTag> .GetTags(NormalizedSnapshotSpanCollection spans)
        {
            try
            {
                if (spans == null || spans.FirstOrDefault() == null)
                {
                    return(null);
                }

                if (spans.FirstOrDefault().Snapshot.ContentType.TypeName != "SQL Server Tools")
                {
                    return(null);
                }

                var items = new List <ITagSpan <ClippyTag> >();

                if (_lastCallTime.AddMilliseconds(_lastCallDelay) >= DateTime.Now)
                {
                    return(_lastSpans);
                }

                _lastCallTime = DateTime.Now;

                if (!Monitor.TryEnter(_lock))
                {
                    return(_lastSpans);
                }

                var dte = VsServiceProvider.Get(typeof(DTE));


                if (null == dte || !ClippySettings.Enabled)
                {
                    Monitor.Exit(_lock);
                    return(_lastSpans);
                }

                //if (_store == null)
                //{
                //    _store = new TagStore();
                //    Monitor.Exit(_lock);
                //    return _lastSpans;
                //}

                if (_store.Stopped)
                {
                    _store.Stopped = false;
                    Monitor.Exit(_lock);
                    return(_lastSpans);
                }


                var text = spans.FirstOrDefault().Snapshot.GetText();

                var glyphs = new OperationsBuilder(spans.FirstOrDefault().Snapshot, _store).GetStatementOptions(text);

                foreach (var g in glyphs)
                {
                    if (g.Menu.Count == 0)
                    {
                        continue;
                    }

                    var tag = new ClippyTag(g);

                    var tagSpan = new TagSpan <ClippyTag>(new SnapshotSpan(spans.FirstOrDefault().Snapshot, g.StatementOffset, g.StatementLength), tag);
                    tag.Tagger            = this;
                    tagSpan.Tag.ParentTag = tagSpan;
                    g.Tag = tagSpan.Tag;
                    items.Add(tagSpan);
                }

                Monitor.Exit(_lock);
                _lastSpans = items;
                return(items);
            }
            catch (Exception)
            {
                Monitor.Exit(_lock);
                return(null);
            }
        }
Example #31
0
        /// <summary>
        /// Get misspelled words in the given set of spans
        /// </summary>
        /// <param name="spans">The spans to check</param>
        /// <returns>An enumerable list of misspelling tags</returns>
        private IEnumerable <MisspellingTag> GetMisspellingsInSpans(NormalizedSnapshotSpanCollection spans)
        {
            List <Match> xmlTags = null;
            SnapshotSpan errorSpan, deleteWordSpan;

            Microsoft.VisualStudio.Text.Span lastWord;
            string text, textToParse;
            var    ignoredWords = wordsIgnoredOnce;

            foreach (var span in spans)
            {
                text = span.GetText();

                // Note the location of all XML elements if needed
                if (configuration.IgnoreXmlElementsInText)
                {
                    xmlTags = reXml.Matches(text).OfType <Match>().ToList();
                }

                lastWord = new Microsoft.VisualStudio.Text.Span();

                foreach (var word in GetWordsInText(text))
                {
                    textToParse = text.Substring(word.Start, word.Length);

                    // Spell check the word if it looks like one and is not ignored
                    if (IsProbablyARealWord(textToParse) && (xmlTags == null || xmlTags.Count == 0 ||
                                                             !xmlTags.Any(match => word.Start >= match.Index &&
                                                                          word.Start <= match.Index + match.Length - 1)))
                    {
                        // Check for a doubled word.  This isn't perfect as it won't detected doubled words
                        // across a line break.
                        if (lastWord.Length != 0 && text.Substring(lastWord.Start, lastWord.Length).Equals(
                                textToParse, StringComparison.OrdinalIgnoreCase) && String.IsNullOrWhiteSpace(
                                text.Substring(lastWord.Start + lastWord.Length, word.Start - lastWord.Start - lastWord.Length)))
                        {
                            errorSpan = new SnapshotSpan(span.Start + word.Start, word.Length);

                            // If the doubled word is not being ignored at the current location, return it
                            if (!ignoredWords.Any(w => w.StartPoint == errorSpan.Start && w.Word.Equals(textToParse,
                                                                                                        StringComparison.OrdinalIgnoreCase)))
                            {
                                // Delete the whitespace ahead of it too
                                deleteWordSpan = new SnapshotSpan(span.Start + lastWord.Start + lastWord.Length,
                                                                  word.Length + word.Start - lastWord.Start - lastWord.Length);

                                yield return(new MisspellingTag(errorSpan, deleteWordSpan));

                                lastWord = word;
                                continue;
                            }
                        }

                        lastWord = word;

                        if (!_dictionary.ShouldIgnoreWord(textToParse) && !_dictionary.IsSpelledCorrectly(textToParse))
                        {
                            // Sometimes it flags a word as misspelled if it ends with "'s".  Try checking the
                            // word without the "'s".  If ignored or correct without it, don't flag it.  This
                            // appears to be caused by the definitions in the dictionary rather than Hunspell.
                            if (textToParse.EndsWith("'s", StringComparison.OrdinalIgnoreCase))
                            {
                                textToParse = textToParse.Substring(0, textToParse.Length - 2);

                                if (_dictionary.ShouldIgnoreWord(textToParse) ||
                                    _dictionary.IsSpelledCorrectly(textToParse))
                                {
                                    continue;
                                }

                                textToParse += "'s";
                            }

                            // Some dictionaries include a trailing period on certain words such as "etc." which
                            // we don't include.  If the word is followed by a period, try it with the period to
                            // see if we get a match.  If so, consider it valid.
                            if (word.Start + word.Length < text.Length && text[word.Start + word.Length] == '.')
                            {
                                if (_dictionary.ShouldIgnoreWord(textToParse + ".") ||
                                    _dictionary.IsSpelledCorrectly(textToParse + "."))
                                {
                                    continue;
                                }
                            }

                            errorSpan = new SnapshotSpan(span.Start + word.Start, word.Length);

                            // If the word is not being ignored at the current location, return it and its
                            // suggested corrections.
                            if (!ignoredWords.Any(w => w.StartPoint == errorSpan.Start && w.Word.Equals(textToParse,
                                                                                                        StringComparison.OrdinalIgnoreCase)))
                            {
                                yield return(new MisspellingTag(errorSpan, _dictionary.SuggestCorrections(textToParse)));
                            }
                        }
                    }
                }
            }
        }
        public static IEnumerable <ITagSpan <IOutliningRegionTag> > GetTags(this IGherkinFileScope gherkinFileScope, NormalizedSnapshotSpanCollection spans)
        {
            if (gherkinFileScope == null)
            {
                return(new ITagSpan <IOutliningRegionTag> [0]);
            }

            var result = new List <ITagSpan <IOutliningRegionTag> >();

            foreach (var gherkinFileBlock in gherkinFileScope.GetAllBlocks())
            {
                result.AddRange(gherkinFileBlock.OutliningRegions); //TODO: optimize
            }
            return(result);
        }
Example #33
0
        /// <summary>
        /// Get misspelled words in the given set of spans
        /// </summary>
        /// <param name="spans">The spans to check</param>
        /// <returns>An enumerable list of misspelling tags</returns>
        private IEnumerable <MisspellingTag> GetMisspellingsInSpans(NormalizedSnapshotSpanCollection spans)
        {
            List <Match> rangeExclusions = new List <Match>();
            SnapshotSpan errorSpan, deleteWordSpan;

            Microsoft.VisualStudio.Text.Span lastWord;
            string textToSplit, actualWord, textToCheck;
            int    mnemonicPos;

            // **************************************************************************************************
            // NOTE: If anything changes here, update the related solution/project spell checking code in
            // ToolWindows\SolutionProjectSpellCheckControl.xaml.cs\GetMisspellingsInSpans().
            // **************************************************************************************************
            foreach (var span in spans)
            {
                textToSplit = span.GetText();

                rangeExclusions.Clear();

                // Note the location of all XML elements if needed
                if (configuration.IgnoreXmlElementsInText)
                {
                    rangeExclusions.AddRange(WordSplitter.XmlElement.Matches(textToSplit).Cast <Match>());
                }

                // Add exclusions from the configuration if any
                foreach (var exclude in configuration.ExclusionExpressions)
                {
                    try
                    {
                        rangeExclusions.AddRange(exclude.Matches(textToSplit).Cast <Match>());
                    }
                    catch (RegexMatchTimeoutException ex)
                    {
                        // Ignore expression timeouts
                        Debug.WriteLine(ex);
                    }
                }

                // Get any ignored words specified inline within the span
                foreach (Match m in InlineIgnoredWord.reIgnoreSpelling.Matches(textToSplit))
                {
                    string ignored       = m.Groups["IgnoredWords"].Value;
                    bool   caseSensitive = !String.IsNullOrWhiteSpace(m.Groups["CaseSensitive"].Value);
                    int    start         = m.Groups["IgnoredWords"].Index;

                    foreach (var ignoreSpan in wordSplitter.GetWordsInText(ignored))
                    {
                        var ss = new SnapshotSpan(span.Snapshot, span.Start + start + ignoreSpan.Start,
                                                  ignoreSpan.Length);
                        var match = inlineIgnoredWords.FirstOrDefault(i => i.Span.GetSpan(span.Snapshot).OverlapsWith(ss));

                        if (match != null)
                        {
                            // If the span is already there, ignore it
                            if (match.Word == ss.GetText() && match.CaseSensitive == caseSensitive)
                            {
                                continue;
                            }

                            // If different, replace it
                            inlineIgnoredWords.Remove(match);
                        }

                        var ts = span.Snapshot.CreateTrackingSpan(ss, SpanTrackingMode.EdgeExclusive);

                        inlineIgnoredWords.Add(new InlineIgnoredWord
                        {
                            Word          = ignored.Substring(ignoreSpan.Start, ignoreSpan.Length),
                            CaseSensitive = caseSensitive,
                            Span          = ts,
                            IsNew         = true
                        });
                    }
                }

                lastWord = new Microsoft.VisualStudio.Text.Span();

                foreach (var word in wordSplitter.GetWordsInText(textToSplit))
                {
                    if (isClosed)
                    {
                        yield break;
                    }

                    actualWord = textToSplit.Substring(word.Start, word.Length);

                    if (inlineIgnoredWords.Any(w => w.IsMatch(actualWord)))
                    {
                        continue;
                    }

                    mnemonicPos = actualWord.IndexOf(wordSplitter.Mnemonic);

                    if (mnemonicPos == -1)
                    {
                        textToCheck = actualWord;
                    }
                    else
                    {
                        textToCheck = actualWord.Substring(0, mnemonicPos) + actualWord.Substring(mnemonicPos + 1);
                    }

                    if (unescapeApostrophes && textToCheck.IndexOf("''", StringComparison.Ordinal) != -1)
                    {
                        textToCheck = textToCheck.Replace("''", "'");
                    }

                    // Spell check the word if it looks like one and is not ignored
                    if (wordSplitter.IsProbablyARealWord(textToCheck) && (rangeExclusions.Count == 0 ||
                                                                          !rangeExclusions.Any(match => word.Start >= match.Index &&
                                                                                               word.Start <= match.Index + match.Length - 1)))
                    {
                        errorSpan = new SnapshotSpan(span.Start + word.Start, word.Length);

                        // Check for a doubled word.  This isn't perfect as it won't detected doubled words
                        // across a line break.
                        if (configuration.DetectDoubledWords && lastWord.Length != 0 &&
                            textToSplit.Substring(lastWord.Start, lastWord.Length).Equals(actualWord,
                                                                                          StringComparison.OrdinalIgnoreCase) && String.IsNullOrWhiteSpace(textToSplit.Substring(
                                                                                                                                                               lastWord.Start + lastWord.Length, word.Start - lastWord.Start - lastWord.Length)))
                        {
                            // If the doubled word is not being ignored at the current location, return it
                            if (!wordsIgnoredOnce.Any(w => w.StartPoint == errorSpan.Start && w.Word.Equals(actualWord,
                                                                                                            StringComparison.OrdinalIgnoreCase)))
                            {
                                // Delete the whitespace ahead of it too
                                deleteWordSpan = new SnapshotSpan(span.Start + lastWord.Start + lastWord.Length,
                                                                  word.Length + word.Start - lastWord.Start - lastWord.Length);

                                yield return(new MisspellingTag(errorSpan, deleteWordSpan));

                                lastWord = word;
                                continue;
                            }
                        }

                        lastWord = word;

                        // If the word is not being ignored, perform the other checks
                        if (!this.Dictionary.ShouldIgnoreWord(textToCheck) && !wordsIgnoredOnce.Any(
                                w => w.StartPoint == errorSpan.Start && w.Word.Equals(actualWord,
                                                                                      StringComparison.OrdinalIgnoreCase)))
                        {
                            // Handle code analysis dictionary checks first as they may be not be recognized as
                            // correctly spelled words but have alternate handling.
                            if (configuration.CadOptions.TreatDeprecatedTermsAsMisspelled &&
                                configuration.DeprecatedTerms.TryGetValue(textToCheck, out string preferredTerm))
                            {
                                yield return(new MisspellingTag(MisspellingType.DeprecatedTerm, errorSpan,
                                                                new[] { new SpellingSuggestion(null, preferredTerm) }));

                                continue;
                            }

                            if (configuration.CadOptions.TreatCompoundTermsAsMisspelled &&
                                configuration.CompoundTerms.TryGetValue(textToCheck, out preferredTerm))
                            {
                                yield return(new MisspellingTag(MisspellingType.CompoundTerm, errorSpan,
                                                                new[] { new SpellingSuggestion(null, preferredTerm) }));

                                continue;
                            }

                            if (configuration.CadOptions.TreatUnrecognizedWordsAsMisspelled &&
                                configuration.UnrecognizedWords.TryGetValue(textToCheck, out IList <string> spellingAlternates))
                            {
                                yield return(new MisspellingTag(MisspellingType.UnrecognizedWord, errorSpan,
                                                                spellingAlternates.Select(a => new SpellingSuggestion(null, a))));

                                continue;
                            }

                            if (!this.Dictionary.IsSpelledCorrectly(textToCheck))
                            {
                                // Sometimes it flags a word as misspelled if it ends with "'s".  Try checking the
                                // word without the "'s".  If ignored or correct without it, don't flag it.  This
                                // appears to be caused by the definitions in the dictionary rather than Hunspell.
                                if (textToCheck.EndsWith("'s", StringComparison.OrdinalIgnoreCase) ||
                                    textToCheck.EndsWith("\u2019s", StringComparison.OrdinalIgnoreCase))
                                {
                                    string aposEss = textToCheck.Substring(textToCheck.Length - 2);

                                    textToCheck = textToCheck.Substring(0, textToCheck.Length - 2);

                                    if (this.Dictionary.ShouldIgnoreWord(textToCheck) ||
                                        this.Dictionary.IsSpelledCorrectly(textToCheck))
                                    {
                                        continue;
                                    }

                                    textToCheck += aposEss;
                                }

                                // Some dictionaries include a trailing period on certain words such as "etc." which
                                // we don't include.  If the word is followed by a period, try it with the period to
                                // see if we get a match.  If so, consider it valid.
                                if (word.Start + word.Length < textToSplit.Length && textToSplit[word.Start + word.Length] == '.')
                                {
                                    if (this.Dictionary.ShouldIgnoreWord(textToCheck + ".") ||
                                        this.Dictionary.IsSpelledCorrectly(textToCheck + "."))
                                    {
                                        continue;
                                    }
                                }

                                yield return(new MisspellingTag(errorSpan)
                                {
                                    EscapeApostrophes = unescapeApostrophes
                                });
                            }
                        }
                    }
                }
            }
        }
        internal IEnumerable <ClassifiedSpan> GetIdentifiersInSpans(Workspace workspace, SemanticModel model, NormalizedSnapshotSpanCollection spans)
        {
            var classifiedSpans = spans.SelectMany(span =>
            {
                var textSpan = TextSpan.FromBounds(span.Start, span.End);
                return(Classifier.GetClassifiedSpans(model, textSpan, workspace));
            });

            return(classifiedSpans.Where(span => ColorCoderClassificationTypeNames.SupportedClassificationTypeNames.Contains(span.ClassificationType,
                                                                                                                             StringComparer.InvariantCultureIgnoreCase)));
        }
Example #35
0
        /// <summary>
        /// Check for misspellings in the given set of dirty spans
        /// </summary>
        /// <param name="dirtySpans">The enumerable list of dirty spans to check for misspellings</param>
        private void CheckSpellings(IEnumerable <SnapshotSpan> dirtySpans)
        {
            ITextSnapshot snapshot = _buffer.CurrentSnapshot;

            foreach (var dirtySpan in dirtySpans)
            {
                var dirty = dirtySpan.TranslateTo(snapshot, SpanTrackingMode.EdgeInclusive);

                // We have to go back to the UI thread to get natural text spans
                List <SnapshotSpan> naturalTextSpans = new List <SnapshotSpan>();
                OnForegroundThread(() => naturalTextSpans = GetNaturalLanguageSpansForDirtySpan(dirty).ToList());

                var naturalText = new NormalizedSnapshotSpanCollection(
                    naturalTextSpans.Select(span => span.TranslateTo(snapshot, SpanTrackingMode.EdgeInclusive)));

                List <MisspellingTag> currentMisspellings = new List <MisspellingTag>(_misspellings);
                List <MisspellingTag> newMisspellings     = new List <MisspellingTag>();

                int removed = currentMisspellings.RemoveAll(tag => tag.ToTagSpan(snapshot).Span.OverlapsWith(dirty));

                newMisspellings.AddRange(GetMisspellingsInSpans(naturalText));

                // Also remove empties
                removed += currentMisspellings.RemoveAll(tag => tag.ToTagSpan(snapshot).Span.IsEmpty);

                // If anything has been updated, we need to send out a change event
                if (newMisspellings.Count != 0 || removed != 0)
                {
                    currentMisspellings.AddRange(newMisspellings);

                    _dispatcher.Invoke(new Action(() =>
                    {
                        if (_isClosed)
                        {
                            return;
                        }

                        _misspellings = currentMisspellings;

                        var temp = TagsChanged;
                        if (temp != null)
                        {
                            temp(this, new SnapshotSpanEventArgs(dirty));
                        }
                    }));
                }
            }

            lock (_dirtySpanLock)
            {
                if (_isClosed)
                {
                    return;
                }

                if (_dirtySpans.Count != 0)
                {
                    _dispatcher.BeginInvoke(new Action(() => ScheduleUpdate()));
                }
            }
        }
Example #36
0
 static NormalizedSnapshotSpanCollection SymmetricDifference(NormalizedSnapshotSpanCollection first, NormalizedSnapshotSpanCollection second)
 {
     return(NormalizedSnapshotSpanCollection.Union(
                NormalizedSnapshotSpanCollection.Difference(first, second),
                NormalizedSnapshotSpanCollection.Difference(second, first)));
 }
        internal IEnumerable <ITagSpan <IClassificationTag> > GetClassificationTags(ProviderCache cache, NormalizedSnapshotSpanCollection spans, Dictionary <string, IClassificationType> classificationTypeDictionary)
        {
            var snapshot = spans[0].Snapshot;
            IEnumerable <ClassifiedSpan> classifiedSpans = GetIdentifiersInSpans(cache.Workspace, cache.SemanticModel, spans);

            foreach (var classifiedSpan in classifiedSpans)
            {
                var node   = GetExpression(cache.SyntaxRoot.FindNode(classifiedSpan.TextSpan));
                var symbol = cache.SemanticModel.GetSymbolInfo(node).Symbol ?? cache.SemanticModel.GetDeclaredSymbol(node);
                yield return(GetTagSpan(node, classifiedSpan, snapshot, symbol, classificationTypeDictionary));
            }
        }
 public IEnumerable <ITagSpan <GlyphTextMarkerGlyphTag> > GetTags(NormalizedSnapshotSpanCollection spans) =>
 service.GetGlyphTextMarkerGlyphTags(spans);
        public static IEnumerable<ITagSpan<IOutliningRegionTag>> GetTags(this IGherkinFileScope gherkinFileScope, NormalizedSnapshotSpanCollection spans)
        {
            if (gherkinFileScope == null)
                return new ITagSpan<IOutliningRegionTag>[0];

            var result = new List<ITagSpan<IOutliningRegionTag>>();
            foreach (var gherkinFileBlock in gherkinFileScope.GetAllBlocks())
            {
                result.AddRange(gherkinFileBlock.OutliningRegions); //TODO: optimize
            }
            return result;
        }
Example #40
0
 public static Mock<IMappingSpan> CreateMappingSpan(SnapshotSpan[] spans, MockRepository factory = null)
 {
     factory = factory ?? new MockRepository(MockBehavior.Strict);
     var col = new NormalizedSnapshotSpanCollection(spans);
     var mock = factory.Create<IMappingSpan>();
     mock.Setup(x => x.GetSpans(spans[0].Snapshot)).Returns(col);
     mock.Setup(x => x.GetSpans(spans[0].Snapshot.TextBuffer)).Returns(col);
     return mock;
 }
        // To produce adornments that don't obscure the text, the adornment tags
        // should have zero length spans. Overriding this method allows control
        // over the tag spans.
        protected override IEnumerable <Tuple <SnapshotSpan, PositionAffinity?, ColorTag> > GetAdornmentData(NormalizedSnapshotSpanCollection spans)
        {
            if (spans.Count == 0)
            {
                yield break;
            }

            ITextSnapshot snapshot = spans[0].Snapshot;

            var colorTags = this.colorTagger.GetTags(spans);

            foreach (IMappingTagSpan <ColorTag> dataTagSpan in colorTags)
            {
                NormalizedSnapshotSpanCollection colorTagSpans = dataTagSpan.Span.GetSpans(snapshot);

                // Ignore data tags that are split by projection.
                // This is theoretically possible but unlikely in current scenarios.
                if (colorTagSpans.Count != 1)
                {
                    continue;
                }

                SnapshotSpan adornmentSpan = new SnapshotSpan(colorTagSpans[0].Start, 0);

                yield return(Tuple.Create(adornmentSpan, (PositionAffinity?)PositionAffinity.Successor, dataTagSpan.Tag));
            }
        }
Example #42
0
 /// <param name="spans">Spans to provide adornment data for. These spans do not necessarily correspond to text lines.</param>
 /// <remarks>
 /// If adornments need to be updated, call <see cref="RaiseTagsChanged"/> or <see cref="InavlidateSpans"/>.
 /// This will, indirectly, cause <see cref="GetAdornmentData"/> to be called.
 /// </remarks>
 /// <returns>
 /// A sequence of:
 ///  * adornment data for each adornment to be displayed
 ///  * the span of text that should be elided for that adornment (zero length spans are acceptable)
 ///  * and affinity of the adornment (this should be null if and only if the elided span has a length greater than zero)
 /// </returns>
 protected abstract IEnumerable <Tuple <SnapshotSpan, PositionAffinity?, TData> > GetAdornmentData(NormalizedSnapshotSpanCollection spans);
Example #43
0
        public IEnumerable <ITagSpan <AsmTokenTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            DateTime time1 = DateTime.Now;

            if (spans.Count == 0)
            {  //there is no content in the buffer
                yield break;
            }

            foreach (SnapshotSpan curSpan in spans)
            {
                ITextSnapshotLine containingLine = curSpan.Start.GetContainingLine();

                string line = containingLine.GetText().ToUpper();
                var    pos  = new List <(int BeginPos, int Length, bool IsLabel)>(AsmSourceTools.SplitIntoKeywordPos(line));

                int offset    = containingLine.Start.Position;
                int nKeywords = pos.Count;

                for (int k = 0; k < nKeywords; k++)
                {
                    string asmToken = NasmIntelTokenTagger.Keyword(pos[k], line);
                    // keyword starts with a remark char
                    if (AsmSourceTools.IsRemarkChar(asmToken[0]))
                    {
                        yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), this._remark));

                        continue;
                    }

                    // keyword k is a label definition
                    if (pos[k].IsLabel)
                    {
                        SnapshotSpan labelDefSpan = NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan);
                        //AsmDudeToolsStatic.Output_INFO("MasmTokenTagger:GetTags: found label " + asmToken +" at line "+containingLine.LineNumber);
                        if (asmToken.Equals("@@"))
                        {
                            // TODO: special MASM label, for the moment, ignore it, later: check whether it is used etc.
                        }
                        else
                        {
                            var v = Make_AsmTokenTag_LabelDef(containingLine.LineNumber);
                            yield return(new TagSpan <AsmTokenTag>(labelDefSpan, v));
                        }
                        continue;
                    }

                    AsmTokenType keywordType = this._asmDudeTools.Get_Token_Type_Intel(asmToken);
                    switch (keywordType)
                    {
                    case AsmTokenType.Jump:
                    {
                        yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), this._jump));

                        k++;         // goto the next word
                        if (k == nKeywords)
                        {
                            break;
                        }

                        string asmToken2 = NasmIntelTokenTagger.Keyword(pos[k], line);
                        switch (asmToken2)
                        {
                        case "$":
                        case "@B":
                        case "@F":
                        {
                            // TODO: special MASM label, for the moment, ignore it, later: check whether it is used etc.
                            break;
                        }

                        case "WORD":
                        case "DWORD":
                        case "QWORD":
                        case "SHORT":
                        case "NEAR":
                        {
                            yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), this._misc));

                            k++;
                            if (k == nKeywords)
                            {
                                break;
                            }
                            string asmToken3 = NasmIntelTokenTagger.Keyword(pos[k], line);
                            switch (asmToken3)
                            {
                            case "$":
                            case "@B":
                            case "@F":
                            {
                                // TODO: special MASM label, for the moment, ignore it, later: check whether it is used etc.
                                break;
                            }

                            case "PTR":
                            {
                                yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), this._misc));

                                break;
                            }

                            default:
                            {
                                yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), Make_AsmTokenTag_Label(containingLine.LineNumber)));

                                break;
                            }
                            }
                            break;
                        }

                        default:
                        {
                            if (RegisterTools.IsRegister(asmToken2))
                            {
                                yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), this._register));
                            }
                            else
                            {
                                yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), Make_AsmTokenTag_Label(containingLine.LineNumber)));
                            }
                            break;
                        }
                        }
                        break;
                    }

                    case AsmTokenType.UNKNOWN:     // asmToken is not a known keyword, check if it is numerical
                    {
                        //if (AsmTools.AsmSourceTools.Evaluate_Constant(asmToken, true).Valid)
                        if (AsmTools.AsmSourceTools.Parse_Constant(asmToken, true).Valid)
                        {
                            yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), this._constant));
                        }
                        else if (asmToken.StartsWith("\"") && asmToken.EndsWith("\""))
                        {
                            yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), this._constant));
                        }
                        else
                        {
                            bool isUnknown = true;

                            // do one word lookahead; see whether we can understand the current unknown word
                            if ((k + 1) < nKeywords)
                            {
                                k++;
                                string nextKeyword = NasmIntelTokenTagger.Keyword(pos[k], line);
                                switch (nextKeyword)
                                {
                                case "PROC":
                                case "EQU":
                                case "LABEL":
                                {
                                    yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k - 1], offset, curSpan), this._labelDef));

                                    yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), this._directive));

                                    isUnknown = false;
                                    break;
                                }

                                case "PROTO":
                                {                 // a proto is considered a label definition but it should not clash with other label definitions
                                    yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k - 1], offset, curSpan), this._labelDef_PROTO));

                                    yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), this._directive));

                                    isUnknown = false;
                                    break;
                                }

                                default:
                                {
                                    k--;
                                    break;
                                }
                                }
                            }

                            // do one word look back; see whether we can understand the current unknown word
                            if (k > 0)
                            {
                                string previousKeyword = NasmIntelTokenTagger.Keyword(pos[k - 1], line);
                                switch (previousKeyword)
                                {
                                case "ALIAS":
                                {
                                    yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), this._labelDef));

                                    isUnknown = false;
                                    break;
                                }

                                case "INCLUDE":
                                {
                                    yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), this._constant));

                                    isUnknown = false;
                                    break;
                                }

                                default:
                                {
                                    break;
                                }
                                }
                            }

                            if (isUnknown)
                            {
                                yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), this._UNKNOWN));
                            }
                        }
                        break;
                    }

                    case AsmTokenType.Directive:
                    {
                        AssemblerEnum assember = this._asmDudeTools.Get_Assembler(asmToken);
                        if (assember.HasFlag(AssemblerEnum.MASM))         // this MASM token-tagger only tags MASM directives
                        {
                            yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), this._directive));

                            switch (asmToken)
                            {
                            case "INVOKE":
                            {
                                k++;                 // goto the next word
                                if (k == nKeywords)
                                {
                                    break;
                                }

                                string asmToken2 = NasmIntelTokenTagger.Keyword(pos[k], line);
                                yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), Make_AsmTokenTag_Label(containingLine.LineNumber)));

                                break;
                            }

                            case "EXTRN":
                            case "EXTERN":
                            {
                                k++;                 // goto the next word
                                if (k == nKeywords)
                                {
                                    break;
                                }

                                string asmToken2 = NasmIntelTokenTagger.Keyword(pos[k], line);
                                yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), this._labelDef_PROTO));

                                break;
                            }
                            }
                        }
                    }
                    break;

                    default:
                    {
                        yield return(new TagSpan <AsmTokenTag>(NasmIntelTokenTagger.New_Span(pos[k], offset, curSpan), new AsmTokenTag(keywordType)));

                        break;
                    }
                    }
                }
            }
            AsmDudeToolsStatic.Print_Speed_Warning(time1, "MasmTokenTagger");
        }
Example #44
0
 IEnumerable <ITagSpan <TTag> > ITagger <TTag> .GetTags(NormalizedSnapshotSpanCollection col)
 {
     return(Tagger.GetTags(col));
 }
Example #45
0
        public IEnumerable <ITagSpan <NM_TokenTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            foreach (SnapshotSpan curSpan in spans)
            {
                ITextSnapshotLine containingLine = curSpan.Start.GetContainingLine();
                int      curLoc = containingLine.Start.Position;
                int      start_span;
                int      temp_finish;
                var      containing_edited = Dictionary_asm.RemoveAux(containingLine.GetText(), out start_span, out temp_finish);
                string[] tokens            = containing_edited.Split(' ');

                Dictionary_asm.AddCustomLine(containingLine.GetText());
                foreach (string nm_Token in tokens)
                {
                    var temp_token = nm_Token;
                    int macro_size;
                    if (_NM_Types.ContainsKey(temp_token))
                    {
                        var tokenSpan = new SnapshotSpan(curSpan.Snapshot, new Span(curLoc + start_span, nm_Token.Length));
                        if (tokenSpan.IntersectsWith(curSpan))
                        {
                            yield return(new TagSpan <NM_TokenTag>(tokenSpan,
                                                                   new NM_TokenTag(_NM_Types[temp_token])));
                        }
                    }
                    else if (Dictionary_asm.IsQuoted(temp_token))
                    {
                        var tokenSpan = new SnapshotSpan(curSpan.Snapshot, new Span(curLoc + start_span, nm_Token.Length));
                        if (tokenSpan.IntersectsWith(curSpan))
                        {
                            yield return(new TagSpan <NM_TokenTag>(tokenSpan,
                                                                   new NM_TokenTag(_NM_Types["Quote"])));
                        }
                    }
                    else if (Dictionary_asm.IsNumber(temp_token))
                    {
                        var tokenSpan = new SnapshotSpan(curSpan.Snapshot, new Span(curLoc + start_span, nm_Token.Length));
                        if (tokenSpan.IntersectsWith(curSpan))
                        {
                            yield return(new TagSpan <NM_TokenTag>(tokenSpan,
                                                                   new NM_TokenTag(_NM_Types["Number"])));
                        }
                    }
                    else if (Dictionary_asm.IsCustomLabel(containingLine.GetText()) || Dictionary_asm.CustomLabel.Contains(nm_Token.ToLower()))
                    {
                        var tokenSpan = new SnapshotSpan(curSpan.Snapshot, new Span(curLoc + start_span, nm_Token.Length));
                        if (tokenSpan.IntersectsWith(curSpan))
                        {
                            yield return(new TagSpan <NM_TokenTag>(tokenSpan,
                                                                   new NM_TokenTag(_NM_Types["Custom_label"])));
                        }
                    }
                    else if (Dictionary_asm.IsMacro(nm_Token, out macro_size))
                    {
                        var tokenSpan = new SnapshotSpan(curSpan.Snapshot, new Span(curLoc + start_span, macro_size));
                        if (tokenSpan.IntersectsWith(curSpan))
                        {
                            yield return(new TagSpan <NM_TokenTag>(tokenSpan,
                                                                   new NM_TokenTag(_NM_Types["Macro"])));
                        }
                    }

                    else if (Dictionary_asm.IsComment(nm_Token))
                    {
                        var tokenSpan = new SnapshotSpan(curSpan.Snapshot, new Span(curLoc + start_span, containingLine.Length - containingLine.GetText().IndexOf(nm_Token)));
                        if (tokenSpan.IntersectsWith(curSpan))
                        {
                            yield return(new TagSpan <NM_TokenTag>(tokenSpan,
                                                                   new NM_TokenTag(_NM_Types["Comment"])));
                        }
                        break;
                    }
                    //add an extra char location because of the space
                    curLoc += nm_Token.Length + 1;
                }
            }
        }
Example #46
0
        public async Task LargeNumberOfSpans()
        {
            using (var workspace = TestWorkspace.CreateCSharp(@"class Program
{
    void M()
    {
        int z = 0;
        z = z + z + z + z + z + z + z + z + z + z +
            z + z + z + z + z + z + z + z + z + z +
            z + z + z + z + z + z + z + z + z + z +
            z + z + z + z + z + z + z + z + z + z +
            z + z + z + z + z + z + z + z + z + z +
            z + z + z + z + z + z + z + z + z + z +
            z + z + z + z + z + z + z + z + z + z +
            z + z + z + z + z + z + z + z + z + z +
            z + z + z + z + z + z + z + z + z + z +
            z + z + z + z + z + z + z + z + z + z;
    }
}"))
            {
                List <ITagSpan <TestTag> > tagProducer(SnapshotSpan span, CancellationToken cancellationToken)
                {
                    return(new List <ITagSpan <TestTag> >()
                    {
                        new TagSpan <TestTag>(span, new TestTag())
                    });
                }

                var asyncListener = new AsynchronousOperationListener();

                WpfTestRunner.RequireWpfFact($"{nameof(AsynchronousTaggerTests)}.{nameof(LargeNumberOfSpans)} creates asynchronous taggers");

                var notificationService = workspace.GetService <IForegroundNotificationService>();

                var eventSource    = CreateEventSource();
                var taggerProvider = new TestTaggerProvider(
                    workspace.ExportProvider.GetExportedValue <IThreadingContext>(),
                    tagProducer,
                    eventSource,
                    workspace,
                    asyncListener,
                    notificationService);

                var document   = workspace.Documents.First();
                var textBuffer = document.TextBuffer;
                var snapshot   = textBuffer.CurrentSnapshot;
                var tagger     = taggerProvider.CreateTagger <TestTag>(textBuffer);

                using (IDisposable disposable = (IDisposable)tagger)
                {
                    var spans         = Enumerable.Range(0, 101).Select(i => new Span(i * 4, 1));
                    var snapshotSpans = new NormalizedSnapshotSpanCollection(snapshot, spans);

                    eventSource.SendUpdateEvent();

                    await asyncListener.CreateWaitTask();

                    var tags = tagger.GetTags(snapshotSpans);

                    Assert.Equal(1, tags.Count());
                }
            }
        }
Example #47
0
        public IEnumerable <ITagSpan <IErrorTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            if (spans.Count == 0)
            {  // there is no content in the buffer
                yield break;
            }

            bool labelGraph_Enabled   = this._labelGraph.Enabled;
            bool asmSimulator_Enabled = this._asmSimulator.Enabled;

            if (!labelGraph_Enabled && !asmSimulator_Enabled)
            {   // nothing to decorate
                yield break;
            }

            DateTime time1 = DateTime.Now;

            //TODO move the followign boolean to constructor
            bool Decorate_Undefined_Labels   = labelGraph_Enabled && Settings.Default.IntelliSense_Decorate_Undefined_Labels;
            bool Decorate_Clashing_Labels    = labelGraph_Enabled && Settings.Default.IntelliSense_Decorate_Clashing_Labels;
            bool Decorate_Undefined_Includes = labelGraph_Enabled && Settings.Default.IntelliSense_Show_Undefined_Includes;

            bool Decorate_Registers_Known_Register_Values = asmSimulator_Enabled && Settings.Default.AsmSim_Decorate_Registers;
            bool Decorate_Syntax_Errors            = asmSimulator_Enabled && Settings.Default.AsmSim_Decorate_Syntax_Errors;
            bool Decorate_Unimplemented            = asmSimulator_Enabled && Settings.Default.AsmSim_Decorate_Unimplemented;
            bool Decorate_Usage_Of_Undefined       = asmSimulator_Enabled && Settings.Default.AsmSim_Decorate_Usage_Of_Undefined;
            bool Decorate_Redundant_Instructions   = asmSimulator_Enabled && Settings.Default.AsmSim_Decorate_Redundant_Instructions;
            bool Decorate_Unreachable_Instructions = asmSimulator_Enabled && Settings.Default.AsmSim_Decorate_Unreachable_Instructions;

            bool Show_Syntax_Error_Error_List = asmSimulator_Enabled && Settings.Default.AsmSim_Show_Syntax_Errors;
            bool Show_Usage_Of_Undefined      = asmSimulator_Enabled && Settings.Default.AsmSim_Show_Usage_Of_Undefined;

            AssemblerEnum usedAssember = AsmDudeToolsStatic.Used_Assembler;

            foreach (IMappingTagSpan <AsmTokenTag> asmTokenTag in this._aggregator.GetTags(spans))
            {
                SnapshotSpan tagSpan = asmTokenTag.Span.GetSpans(this._sourceBuffer)[0];
                //AsmDudeToolsStatic.Output_INFO(string.Format("SquigglesTagger:GetTags: found keyword \"{0}\"", tagSpan.GetText()));

                int lineNumber = AsmDudeToolsStatic.Get_LineNumber(tagSpan);

                switch (asmTokenTag.Tag.Type)
                {
                case AsmTokenType.Label:
                {
                    if (Decorate_Undefined_Labels)
                    {
                        string label = tagSpan.GetText();
                        string full_Qualified_Label = AsmDudeToolsStatic.Make_Full_Qualified_Label(asmTokenTag.Tag.Misc, label, usedAssember);

                        if (this._labelGraph.Has_Label(full_Qualified_Label))
                        {
                            // Nothing to report
                        }
                        else
                        {
                            //AsmDudeToolsStatic.Output_INFO(string.Format("SquigglesTagger:GetTags: found label \"{0}\"; full-label \"{1}\"", label, full_Qualified_Label));

                            if (usedAssember == AssemblerEnum.MASM)
                            {
                                if (this._labelGraph.Has_Label(label))
                                {
                                    // TODO: is this always a valid label? Nothing to report
                                }
                                else
                                {
                                    var toolTipContent = this.Undefined_Label_Tool_Tip_Content();
                                    yield return(new TagSpan <IErrorTag>(tagSpan, new ErrorTag(PredefinedErrorTypeNames.SyntaxError, toolTipContent)));
                                }
                            }
                            else
                            {
                                var toolTipContent = this.Undefined_Label_Tool_Tip_Content();
                                yield return(new TagSpan <IErrorTag>(tagSpan, new ErrorTag(PredefinedErrorTypeNames.SyntaxError, toolTipContent)));
                            }
                        }
                    }
                    break;
                }

                case AsmTokenType.LabelDef:
                {
                    if (Decorate_Clashing_Labels)
                    {
                        string label = tagSpan.GetText();
                        string full_Qualified_Label = AsmDudeToolsStatic.Make_Full_Qualified_Label(asmTokenTag.Tag.Misc, label, usedAssember);

                        if (this._labelGraph.Has_Label_Clash(full_Qualified_Label))
                        {
                            var toolTipContent = this.Label_Clash_Tool_Tip_Content(full_Qualified_Label);

                            //PredefinedErrorTypeNames.Warning is green
                            //PredefinedErrorTypeNames.SyntaxError is red
                            //PredefinedErrorTypeNames.CompilerError is blue
                            //PredefinedErrorTypeNames.Suggestion is NOTHING
                            //PredefinedErrorTypeNames.OtherError is purple

                            yield return(new TagSpan <IErrorTag>(tagSpan, new ErrorTag(PredefinedErrorTypeNames.SyntaxError, toolTipContent)));
                        }
                    }
                    break;
                }

                case AsmTokenType.Register:
                {
                    if (Decorate_Registers_Known_Register_Values)
                    {
                        Rn regName = RegisterTools.ParseRn(tagSpan.GetText());
                        //AsmDudeToolsStatic.Output_INFO("SquigglesTagger:GetTags: found register " + regName + " at line " + lineNumber);
                        bool preCompute = false;
                        var(HasValue1, Bussy1) = this._asmSimulator.Has_Register_Value(regName, lineNumber, true, preCompute);
                        if (!Bussy1)
                        {
                            var(HasValue2, Bussy2) = this._asmSimulator.Has_Register_Value(regName, lineNumber, false, preCompute);
                            if (!Bussy2)
                            {
                                if ((HasValue1 || HasValue2))
                                {           // only show squiggles to indicate that information is available
                                            //AsmDudeToolsStatic.Output_INFO("SquigglesTagger:GetTags: adding squiggles for register " + regName + " at line " + lineNumber);
                                    yield return(new TagSpan <IErrorTag>(tagSpan, new ErrorTag(PredefinedErrorTypeNames.Warning)));
                                }
                            }
                        }
                    }
                    break;
                }

                case AsmTokenType.Mnemonic:
                {
                    if (Decorate_Syntax_Errors || Decorate_Unimplemented)
                    {
                        if (this._asmSimulator.Is_Implemented(lineNumber))
                        {
                            if (Decorate_Syntax_Errors && this._asmSimulator.Has_Syntax_Error(lineNumber))
                            {
                                string message = AsmSourceTools.Linewrap("Syntax Error: " + this._asmSimulator.Get_Syntax_Error(lineNumber).Message, AsmDudePackage.maxNumberOfCharsInToolTips);
                                yield return(new TagSpan <IErrorTag>(tagSpan, new ErrorTag(PredefinedErrorTypeNames.SyntaxError, message)));
                            }
                        }
                        else if (Decorate_Unimplemented)
                        {
                            string message = AsmSourceTools.Linewrap("Info: Instruction " + tagSpan.GetText() + " is not (yet) supported by the simulator.", AsmDudePackage.maxNumberOfCharsInToolTips);
                            yield return(new TagSpan <IErrorTag>(tagSpan, new ErrorTag(PredefinedErrorTypeNames.CompilerError, message)));
                        }
                    }
                    if (Decorate_Usage_Of_Undefined)
                    {
                        if (this._asmSimulator.Has_Usage_Undefined_Warning(lineNumber))
                        {
                            string message = AsmSourceTools.Linewrap("Semantic Warning: " + this._asmSimulator.Get_Usage_Undefined_Warning(lineNumber).Message, AsmDudePackage.maxNumberOfCharsInToolTips);
                            yield return(new TagSpan <IErrorTag>(tagSpan, new ErrorTag(PredefinedErrorTypeNames.OtherError, message)));
                        }
                    }
                    if (Decorate_Redundant_Instructions)
                    {
                        if (this._asmSimulator.Has_Redundant_Instruction_Warning(lineNumber))
                        {
                            string message = AsmSourceTools.Linewrap("Semantic Warning: " + this._asmSimulator.Get_Redundant_Instruction_Warning(lineNumber).Message, AsmDudePackage.maxNumberOfCharsInToolTips);
                            yield return(new TagSpan <IErrorTag>(tagSpan, new ErrorTag(PredefinedErrorTypeNames.OtherError, message)));
                        }
                    }
                    if (Decorate_Unreachable_Instructions)
                    {
                        if (this._asmSimulator.Has_Unreachable_Instruction_Warning(lineNumber))
                        {
                            string message = AsmSourceTools.Linewrap("Semantic Warning: " + this._asmSimulator.Get_Unreachable_Instruction_Warning(lineNumber).Message, AsmDudePackage.maxNumberOfCharsInToolTips);
                            yield return(new TagSpan <IErrorTag>(tagSpan, new ErrorTag(PredefinedErrorTypeNames.OtherError, message)));
                        }
                    }
                    break;
                }

                case AsmTokenType.Constant:
                {
                    if (Decorate_Undefined_Includes)
                    {
                        foreach (var tup in this._labelGraph.Undefined_Includes)
                        {
                            if (tup.LineNumber == lineNumber)         //TODO this is inefficient!
                            {
                                var toolTipContent = "Could not resolve include \"" + tagSpan.GetText() + "\"";
                                yield return(new TagSpan <IErrorTag>(tagSpan, new ErrorTag(PredefinedErrorTypeNames.SyntaxError, toolTipContent)));

                                break;         // leave the foreach loop
                            }
                        }
                    }
                    break;
                }

                default: break;
                }
            }
            AsmDudeToolsStatic.Print_Speed_Warning(time1, "SquiggleTagger");
        }
Example #48
0
        // Produces tags on the snapshot that this tagger is current with.
        private IEnumerable <TagSpan <IntraTextAdornmentTag> > GetAdornmentTagsOnSnapshot(NormalizedSnapshotSpanCollection spans)
        {
            if (spans.Count == 0)
            {
                yield break;
            }

            ITextSnapshot snapshot = spans[0].Snapshot;

            // Since WPF UI objects have state (like mouse hover or animation) and are relatively expensive to create and lay out,
            // this code tries to reuse controls as much as possible.
            // The controls are stored in this.adornmentCache between the calls.

            // Mark which adornments fall inside the requested spans with Keep=false
            // so that they can be removed from the cache if they no longer correspond to data tags.
            HashSet <SnapshotSpan> toRemove = new HashSet <SnapshotSpan>();

            foreach (var ar in this._adornmentCache)
            {
                if (spans.IntersectsWith(new NormalizedSnapshotSpanCollection(ar.Key)))
                {
                    toRemove.Add(ar.Key);
                }
            }

            foreach (var spanDataPair in GetAdornmentData(spans).Distinct(new Comparer()))
            {
                // Look up the corresponding adornment or create one if it's new.
                TAdornment       adornment;
                SnapshotSpan     snapshotSpan  = spanDataPair.Item1;
                PositionAffinity?affinity      = spanDataPair.Item2;
                TData            adornmentData = spanDataPair.Item3;
                if (this._adornmentCache.TryGetValue(snapshotSpan, out adornment))
                {
                    if (UpdateAdornment(adornment, adornmentData))
                    {
                        toRemove.Remove(snapshotSpan);
                    }
                }
                else
                {
                    adornment = CreateAdornment(adornmentData, snapshotSpan);

                    if (adornment == null)
                    {
                        continue;
                    }

                    // Get the adornment to measure itself. Its DesiredSize property is used to determine
                    // how much space to leave between text for this adornment.
                    // Note: If the size of the adornment changes, the line will be reformatted to accommodate it.
                    // Note: Some adornments may change size when added to the view's visual tree due to inherited
                    // dependency properties that affect layout. Such options can include SnapsToDevicePixels,
                    // UseLayoutRounding, TextRenderingMode, TextHintingMode, and TextFormattingMode. Making sure
                    // that these properties on the adornment match the view's values before calling Measure here
                    // can help avoid the size change and the resulting unnecessary re-format.
                    adornment.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

                    this._adornmentCache.Add(snapshotSpan, adornment);
                }

                yield return(new TagSpan <IntraTextAdornmentTag>(snapshotSpan, new IntraTextAdornmentTag(adornment, null, affinity)));
            }

            foreach (var snapshotSpan in toRemove)
            {
                this._adornmentCache.Remove(snapshotSpan);
            }
        }
Example #49
0
 public IEnumerable <ITagSpan <IOutliningRegionTag> > GetTags(NormalizedSnapshotSpanCollection spans)
 {
     return(_outliningRegions);
 }
        private IEnumerable <ITagSpan <IClassificationTag> > GetTagsImpl(
            Cache doc,
            NormalizedSnapshotSpanCollection spans)
        {
            var snapshot = spans[0].Snapshot;

            IEnumerable <ClassifiedSpan> classifiedSpans =
                GetClassifiedSpans(doc.Workspace, doc.SemanticModel, spans);

            foreach (var span in classifiedSpans)
            {
                var node   = GetExpression(doc.SyntaxRoot.FindNode(span.TextSpan));
                var symbol = doc.SemanticModel.GetSymbolInfo(node).Symbol;
                if (symbol == null)
                {
                    symbol = doc.SemanticModel.GetDeclaredSymbol(node);
                }
                if (symbol == null)
                {
                    continue;
                }
                switch (symbol.Kind)
                {
                case SymbolKind.Field:
                    switch (span.ClassificationType)
                    {
                    case NewClassificationTypeNames.ConstantName:
                    case NewClassificationTypeNames.FieldName:
                        yield return(span.TextSpan.ToTagSpan(snapshot, _fieldType));

                        break;

                    case NewClassificationTypeNames.EnumMemberName:
                        yield return(span.TextSpan.ToTagSpan(snapshot, _enumFieldType));

                        break;
                    }
                    break;

                case SymbolKind.Method:
                    var methodSymbol = (IMethodSymbol)symbol;
                    switch (span.ClassificationType)
                    {
                    case ClassificationTypeNames.Identifier:
                        if (IsConstructor(methodSymbol))
                        {
                            yield return(span.TextSpan.ToTagSpan(snapshot, _constructorType));
                        }
                        //local function definition
                        else if (methodSymbol.MethodKind == LocalMethodKind)
                        {
                            yield return(span.TextSpan.ToTagSpan(snapshot, _localFunctionType));
                        }
                        else if (methodSymbol.IsExtensionMethod)
                        {
                            yield return(span.TextSpan.ToTagSpan(snapshot, _extensionMethodType));
                        }
                        break;

                    case NewClassificationTypeNames.ExtensionMethodName:
                        yield return(span.TextSpan.ToTagSpan(snapshot, _extensionMethodType));

                        break;

                    case NewClassificationTypeNames.MethodName:
                        //local function call
                        if (methodSymbol.MethodKind == LocalMethodKind)
                        {
                            yield return(span.TextSpan.ToTagSpan(snapshot, _localFunctionType));
                        }
                        //static method call
                        else if (methodSymbol.MethodKind == MethodKind.Ordinary && methodSymbol.IsStatic)
                        {
                            yield return(span.TextSpan.ToTagSpan(snapshot, _staticMethodType));
                        }
                        //other method call
                        else
                        {
                            yield return(span.TextSpan.ToTagSpan(snapshot, _normalMethodType));
                        }
                        break;
                    }
                    break;

                case SymbolKind.TypeParameter:
                    yield return(span.TextSpan.ToTagSpan(snapshot, _typeParameterType));

                    break;

                case SymbolKind.Parameter:
                    yield return(span.TextSpan.ToTagSpan(snapshot, _parameterType));

                    break;

                case SymbolKind.Namespace:
                    yield return(span.TextSpan.ToTagSpan(snapshot, _namespaceType));

                    break;

                case SymbolKind.Property:
                    yield return(span.TextSpan.ToTagSpan(snapshot, _propertyType));

                    break;

                case SymbolKind.Local:
                    yield return(span.TextSpan.ToTagSpan(snapshot, _localType));

                    break;

                case SymbolKind.Event:
                    yield return(span.TextSpan.ToTagSpan(snapshot, _eventType));

                    break;

                case SymbolKind.NamedType:
                    if (IsSpecialType(symbol))
                    {
                        yield return(span.TextSpan.ToTagSpan(snapshot, _typeSpecialType));
                    }
                    else
                    {
                        switch (span.ClassificationType)
                        {
                        case ClassificationTypeNames.StructName:
                            yield return(span.TextSpan.ToTagSpan(snapshot, _structType));

                            break;

                        case ClassificationTypeNames.ClassName:
                            yield return(span.TextSpan.ToTagSpan(snapshot, _classType));

                            break;

                        case ClassificationTypeNames.InterfaceName:
                            yield return(span.TextSpan.ToTagSpan(snapshot, _interfaceType));

                            break;

                        case ClassificationTypeNames.DelegateName:
                            yield return(span.TextSpan.ToTagSpan(snapshot, _delegateType));

                            break;

                        case ClassificationTypeNames.EnumName:
                            yield return(span.TextSpan.ToTagSpan(snapshot, _enumType));

                            break;
                        }
                    }
                    break;
                }
            }
        }
Example #51
0
 IEnumerable <ITagSpan <IErrorTag> > ITagger <IErrorTag> .GetTags(NormalizedSnapshotSpanCollection spans)
 {
     return(GetTags(spans, new ErrorTag(PredefinedErrorTypeNames.Suggestion)));
 }
 public IEnumerable <ITagSpan <SpaceNegotiatingAdornmentTag> > GetTags(NormalizedSnapshotSpanCollection spans) =>
 intraTextAdornmentService.GetTags(spans);
Example #53
0
 public IEnumerable <ITagSpan <GlyphTextMarkerGlyphTag> > GetGlyphTextMarkerGlyphTags(NormalizedSnapshotSpanCollection spans)
 {
     foreach (var info in GetMarkers(spans, startOfSpanOnly: true))
     {
         var imgRef = info.Marker.GlyphImageReference;
         if (imgRef != null)
         {
             yield return(new TagSpan <GlyphTextMarkerGlyphTag>(info.Span, new GlyphTextMarkerGlyphTag(imgRef.Value, info.Marker.ZIndex)));
         }
     }
 }
Example #54
0
        public IEnumerable <ITagSpan <NASMTokenTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            foreach (SnapshotSpan curSpan in spans)
            {
                ITextSnapshotLine containingLine = curSpan.Start.GetContainingLine();
                int curLoc = containingLine.Start.Position;

                string[] tokens = Split(containingLine.GetText().ToLower(), _delimiters.ToCharArray());

                NASMTokenTypes overrideType = NASMTokenTypes.Default;

                foreach (string token in tokens)
                {
                    NASMTokenTypes type = GetTokenType(token);

                    SnapshotSpan tokenSpan;

                    if (type == NASMTokenTypes.Comment)
                    {
                        tokenSpan = new SnapshotSpan(curSpan.Snapshot, new Span(curLoc, containingLine.End.Position - curLoc));

                        if (tokenSpan.IntersectsWith(curSpan))
                        {
                            yield return(new TagSpan <NASMTokenTag>(tokenSpan, new NASMTokenTag(type)));

                            break;
                        }
                    }


                    if (overrideType == NASMTokenTypes.String)
                    {
                        if (type == NASMTokenTypes.String)
                        {
                            overrideType = NASMTokenTypes.Default;
                        }
                        else
                        {
                            type = overrideType;
                        }
                    }
                    else
                    {
                        if (type == NASMTokenTypes.String)
                        {
                            overrideType = NASMTokenTypes.String;
                        }
                    }

                    if (overrideType == NASMTokenTypes.Character)
                    {
                        if (type == NASMTokenTypes.Character)
                        {
                            overrideType = NASMTokenTypes.Default;
                        }
                        else
                        {
                            type = NASMTokenTypes.Character;
                        }
                    }
                    else
                    {
                        if (type == NASMTokenTypes.Character)
                        {
                            overrideType = NASMTokenTypes.Character;
                        }
                    }

                    tokenSpan = new SnapshotSpan(curSpan.Snapshot, new Span(curLoc, token.Length));

                    if (tokenSpan.IntersectsWith(curSpan))
                    {
                        yield return(new TagSpan <NASMTokenTag>(tokenSpan, new NASMTokenTag(type)));
                    }

                    //add an extra char location because of the space
                    curLoc += token.Length;
                }
            }
        }
        public bool Replace()
        {
            if (this.ReplaceTerm == null)
            {
                throw new InvalidOperationException("Can't replace with a null value. Set ReplaceTerm before performing a replace operation.");
            }

            if (!this.CurrentResult.HasValue)
            {
                throw new InvalidOperationException("Need to have a current result before being able to replace. Perform a FindNext or FindPrevious operation first.");
            }

            bool forward = (this.SearchOptions & FindOptions.SearchReverse) != FindOptions.SearchReverse;
            bool regEx   = (this.SearchOptions & FindOptions.UseRegularExpressions) == FindOptions.UseRegularExpressions;

            //This may not be the text buffer's current snapshot but that is the desired behavior. We're replacing the current result
            //with the replace tuern.
            SnapshotSpan  result          = this.CurrentResult.Value;
            ITextSnapshot replaceSnapshot = result.Snapshot;

            SnapshotPoint searchStart = forward ? result.Start : result.End;

            SnapshotSpan searchSpan;
            NormalizedSnapshotSpanCollection searchSpans = this.SearchSpans;

            if ((searchSpans != null) && (searchSpans.Count > 0))
            {
                //There could be a version skew here.
                if (searchSpans[0].Snapshot != replaceSnapshot)
                {
                    searchSpans = new  NormalizedSnapshotSpanCollection(replaceSnapshot, TextSearchNavigator.TranslateTo(searchSpans[0].Snapshot, searchSpans, replaceSnapshot));
                }

                int index;
                if (!TextSearchNavigator.TryGetIndexOfContainingSpan(searchSpans, searchStart, out index))
                {
                    // If the match is outside of the search range, then we should noop
                    return(false);
                }
                searchSpan = searchSpans[index];
            }
            else
            {
                searchSpan = new SnapshotSpan(replaceSnapshot, 0, replaceSnapshot.Length);
            }

            searchSpan = forward ? new SnapshotSpan(searchStart, searchSpan.End) : new SnapshotSpan(searchSpan.Start, searchStart);

            //Ask the search engine to find the actual span we need to replace (& the corresponding replacement string).
            string       replacementValue = null;
            SnapshotSpan?toReplace        = _textSearchService.FindForReplace(searchSpan, this.SearchTerm, this.ReplaceTerm, this.SearchOptions, out replacementValue);

            if (toReplace.HasValue)
            {
                using (ITextEdit edit = _buffer.CreateEdit())
                {
                    Span replacementSpan = toReplace.Value.TranslateTo(edit.Snapshot, SpanTrackingMode.EdgeInclusive);

                    if (!edit.Replace(replacementSpan, replacementValue))
                    {
                        // The edit failed for some reason, perhaps read-only regions?
                        return(false);
                    }

                    edit.Apply();

                    if (edit.Canceled)
                    {
                        // The edit failed, most likely a handler of the changed event forced the edit to be canceled.
                        return(false);
                    }
                }

                return(true);
            }

            return(false);
        }
Example #56
0
        private static IEnumerable <ITagSpan <ISemanticBlockTag> > GetTags(CodeBlock block, NormalizedSnapshotSpanCollection spans)
        {
            if (spans.IntersectsWith(new NormalizedSnapshotSpanCollection(block.Span)))
            {
                yield return(new TagSpan <ISemanticBlockTag>(block.Span, block));

                foreach (var child in block.Children)
                {
                    foreach (var tag in GetTags(child, spans))
                    {
                        yield return(tag);
                    }
                }
            }
        }
            public override void PostprocessMouseLeftButtonUp(MouseButtonEventArgs e)
            {
                Point pos = GetLocation(e);
                var oLine = GetLineAt(clickPos);
                var cLine = GetLineAt(pos);
                if ( oLine != cLine || cLine == null ) return;
                // find what outlining regions start on the current line
                // if it's one of ours, remove it.
                SnapshotSpan span = new SnapshotSpan(cLine.Start, cLine.End);
                var spans = new NormalizedSnapshotSpanCollection(span);

                foreach ( var tag in tagAggregator.GetTags(spans) ) {
                  if ( !(tag.Tag is OutliningGlyphTag) ) continue;
                  var tagSpan = tag.GetSpan(cLine.Snapshot);
                  if ( tagSpan.IsEmpty ) continue;
                  // we might see tags that cover this region, but
                  // don't start on the selected line
                  if ( TagStartsOnViewLine(tagSpan, cLine) ) {
                RemoveOutlineAt(tagSpan.Start);
                e.Handled = true;
                  }
                  break;
                }
            }
Example #58
0
        public IEnumerable <ITagSpan <TextMarkerTag> > GetTags(NormalizedSnapshotSpanCollection spans)
        {
            DateTime oStart, oEnd;
            TimeSpan timeSpan;

            oStart = DateTime.Now;

            WriteOutputMessage("Start get brackets: " + oStart.ToString("hh:mm:ss.fff"));

            if (spans.Count == 0)   //there is no content in the buffer
            {
                yield break;
            }

            if (CurrentChar == null || SourceBuffer == null)
            {
                yield break;
            }

            //don't do anything if the current SnapshotPoint is not initialized or at the end of the buffer
            if (!CurrentChar.HasValue || CurrentChar.Value.Position >= CurrentChar.Value.Snapshot.Length)
            {
                yield break;
            }


            //hold on to a snapshot of the current character
            SnapshotPoint ssp = CurrentChar.Value;

            //if the requested snapshot isn't the same as the one the brace is on, translate our spans to the expected snapshot
            if (spans[0].Snapshot != ssp.Snapshot)
            {
                ssp = ssp.TranslateTo(spans[0].Snapshot, PointTrackingMode.Positive);
            }

            //get the current char and the previous char
            char          currentText = '\0';
            char          lastText    = '\0';
            SnapshotSpan  pairSpan    = new SnapshotSpan();
            SnapshotPoint lastChar    = new SnapshotPoint();

            try
            {
                if (ssp.Position < ssp.Snapshot.Length)
                {
                    currentText = ssp.GetChar();
                    lastChar    = ssp == 0 ? ssp : ssp - 1; //if ssp is 0 (beginning of buffer), don't move it back
                    lastText    = lastChar.GetChar();
                }
                else
                {
                    yield break;
                }
            }
            catch (Exception)
            {
                yield break;
            }


            // use the tokens stored in the buffer properties
            XSharpTokens   xTokens = null;
            IList <IToken> tokens  = null;
            int            offset  = 0;

            if (m_braceList.ContainsKey(currentText) || (m_braceList.ContainsValue(lastText))) //FM#081219 #1 - Only need to get the tokens if either of these conditions is true
            {
                if (SourceBuffer.Properties != null && SourceBuffer.Properties.ContainsProperty(typeof(XSharpTokens)))
                {
                    xTokens = SourceBuffer.Properties.GetProperty <XSharpTokens>(typeof(XSharpTokens));
                    if (xTokens == null || xTokens.TokenStream == null || xTokens.SnapShot == null)
                    {
                        yield break;
                    }

                    tokens = xTokens.TokenStream.GetTokens();
                    if (tokens == null)
                    {
                        yield break;
                    }

                    if (xTokens.SnapShot.Version != ssp.Snapshot.Version)
                    {
                        // get source from the start of the file until the current entity
                        var xfile  = SourceBuffer.GetFile();
                        var member = XSharpTokenTools.FindMemberAtPosition(ssp.Position, xfile);
                        if (member != null)
                        {
                            try
                            {
                                var    sourceWalker = new SourceWalker(xfile);
                                string text         = ssp.Snapshot.GetText();
                                var    length       = Math.Min(member.Interval.Width, text.Length - member.Interval.Start);
                                text   = text.Substring(member.Interval.Start, length); //FM#081219 #2 - We are in a 'member'. For brace matching we should only ever need to look to the end of this member
                                offset = member.Interval.Start;
                                WriteOutputMessage("Start sourceWalker.Lex: " + DateTime.Now.ToString("hh:mm:ss.fff"));
                                var stream = (BufferedTokenStream)sourceWalker.Lex(text);
                                WriteOutputMessage("End sourceWalker.Lex: " + DateTime.Now.ToString("hh:mm:ss.fff"));
                                tokens = stream.GetTokens();
                            }
                            catch (Exception e)
                            {
                                // if it crashes, that might be because the snapshot used for the Lex/Parse is no more
                                // so, we may have a too much difference
                                // we do not break but simply use the 'old' tokens
                                System.Diagnostics.Debug.WriteLine(e.Message);
                            }
                        }
                    }
                }
            }

            // First, try to match Simple chars
            if (m_braceList.ContainsKey(currentText))   //the key is the open brace
            {
                char closeChar;
                m_braceList.TryGetValue(currentText, out closeChar);
                if (BraceMatchingTagger.FindMatchingCloseChar(ssp, currentText, closeChar, out pairSpan, tokens, offset) == true)
                {
                    yield return(new TagSpan <TextMarkerTag>(new SnapshotSpan(ssp, 1), new TextMarkerTag("blue")));

                    yield return(new TagSpan <TextMarkerTag>(pairSpan, new TextMarkerTag("blue")));
                }
            }
            else if (m_braceList.ContainsValue(lastText))    //the value is the close brace, which is the *previous* character
            {
                var open = from n in m_braceList
                           where n.Value.Equals(lastText)
                           select n.Key;
                if (BraceMatchingTagger.FindMatchingOpenChar(lastChar, (char)open.ElementAt <char>(0), lastText, out pairSpan, tokens, offset) == true)
                {
                    yield return(new TagSpan <TextMarkerTag>(new SnapshotSpan(lastChar, 1), new TextMarkerTag("blue")));

                    yield return(new TagSpan <TextMarkerTag>(pairSpan, new TextMarkerTag("blue")));
                }
            }
            else
            {
                // Second, try to Match Keywords
                // Try to retrieve an already parsed list of Tags
                XSharpClassifier xsClassifier = null;
                if (SourceBuffer.Properties.ContainsProperty(typeof(XSharpClassifier)))
                {
                    xsClassifier = SourceBuffer.Properties[typeof(XSharpClassifier)] as XSharpClassifier;
                }

                if (xsClassifier != null)
                {
                    ITextSnapshot snapshot = xsClassifier.Snapshot;
                    if (snapshot.Version != ssp.Snapshot.Version)
                    {
                        yield break;
                    }
                    SnapshotSpan Span            = new SnapshotSpan(snapshot, 0, snapshot.Length);
                    var          classifications = xsClassifier.GetTags();
                    // We cannot use SortedList, because we may have several Classification that start at the same position
                    List <ClassificationSpan> sortedTags = new List <ClassificationSpan>();
                    foreach (var tag in classifications)
                    {
                        // Only keep the Brace matching Tags
                        if ((tag.ClassificationType.IsOfType(ColorizerConstants.XSharpBraceOpenFormat)) ||
                            (tag.ClassificationType.IsOfType(ColorizerConstants.XSharpBraceCloseFormat)))
                        {
                            sortedTags.Add(tag);
                        }
                    }
                    sortedTags.Sort((a, b) => a.Span.Start.Position.CompareTo(b.Span.Start.Position) * 1000 + string.Compare(a.ClassificationType.Classification, b.ClassificationType.Classification));
                    //
                    var tags = sortedTags.Where(x => ssp.Position >= x.Span.Start.Position && ssp.Position <= x.Span.End.Position);
                    foreach (var currentTag in tags)
                    {
                        var index = sortedTags.IndexOf(currentTag);
                        if (currentTag.ClassificationType.IsOfType(ColorizerConstants.XSharpBraceOpenFormat))
                        {
                            if (FindMatchingCloseTag(sortedTags, index, snapshot, out pairSpan))
                            {
                                var span = currentTag.Span;
                                yield return(new TagSpan <TextMarkerTag>(span, new TextMarkerTag("bracehighlight")));

                                yield return(new TagSpan <TextMarkerTag>(pairSpan, new TextMarkerTag("bracehighlight")));
                            }
                        }
                        else
                        {
                            if (FindMatchingOpenTag(sortedTags, index, snapshot, out pairSpan))
                            {
                                var span = currentTag.Span;
                                yield return(new TagSpan <TextMarkerTag>(pairSpan, new TextMarkerTag("bracehighlight")));

                                yield return(new TagSpan <TextMarkerTag>(span, new TextMarkerTag("bracehighlight")));
                            }
                        }
                    }
                }
            }

            oEnd     = DateTime.Now;
            timeSpan = oEnd - oStart;

            WriteOutputMessage("Finished get brackets: " + oEnd.ToString("hh:mm:ss.fff"));
            WriteOutputMessage("Finished get brackets - total ms: " + timeSpan.TotalMilliseconds.ToString());
        }
Example #59
0
        public virtual NormalizedSnapshotSpanCollection UncommentSpans(NormalizedSnapshotSpanCollection spans)
        {
            List<SnapshotSpan> result = new List<SnapshotSpan>();

            if (spans.Count == 0)
                return new NormalizedSnapshotSpanCollection();

            var undoHistory = TextUndoHistoryRegistry.RegisterHistory(TextView);
            using (var transaction = undoHistory.CreateTransaction("Uncomment Selection"))
            {
                ITextSnapshot snapshot = spans[0].Snapshot;

                using (var edit = snapshot.TextBuffer.CreateEdit())
                {
                    foreach (var span in spans)
                    {
                        var selection = UncommentSpan(span, edit);
                        result.Add(selection);
                    }

                    edit.Apply();
                }

                if (snapshot != TextView.TextSnapshot)
                    transaction.Complete();
            }

            if (result.Count > 1)
                result.RemoveAll(span => span.IsEmpty);

            var target = TextView.TextBuffer.CurrentSnapshot;
            for (int i = 0; i < result.Count; i++)
            {
                result[i] = result[i].TranslateTo(target, SpanTrackingMode.EdgeInclusive);
            }

            return new NormalizedSnapshotSpanCollection(result);
        }
Example #60
0
        /// <summary>
        /// Find all of the tag regions in the document (snapshot) and notify
        /// listeners of any that changed
        /// </summary>
        void ReparseFile(object sender, TextContentChangedEventArgs args)
        {
            ITextSnapshot snapshot = _buffer.CurrentSnapshot;

            if (snapshot == _snapshot)
            {
                return; // we've already computed the regions for this snapshot
            }
            NormalizedSnapshotSpanCollection difference = new NormalizedSnapshotSpanCollection();
            ScanResult result;

            if (_buffer.Properties.TryGetProperty(bufferTokenTaggerKey, out result) &&
                (result._oldSnapshot == _snapshot) &&
                (result._newSnapshot == snapshot))
            {
                difference = result._difference;
                // save the new baseline
                _regions  = result._regions;
                _snapshot = snapshot;
            }
            else
            {
                List <TokenRegion>  regions          = new List <TokenRegion>();
                List <SnapshotSpan> rescannedRegions = new List <SnapshotSpan>();

                // loop through the changes and check for changes in comments first. If
                // the change is in a comments, we need to rescan starting from the
                // beginning of the comments (which in multi-lined comments, it can
                // be a line that the changes are not on), otherwise, we can just rescan the lines
                // that the changes are on.
                bool          done;
                SnapshotPoint start, end;
                for (int i = 0; i < args.Changes.Count; i++)
                {
                    done = false;
                    // get the span of the lines that the change is on.
                    int cStart = args.Changes[i].NewSpan.Start;
                    int cEnd   = args.Changes[i].NewSpan.End;
                    start = snapshot.GetLineFromPosition(cStart).Start;
                    end   = snapshot.GetLineFromPosition(cEnd).End;
                    SnapshotSpan newSpan = new SnapshotSpan(start, end);
                    foreach (TokenRegion r in _regions)
                    {
                        if (r.Kind == DafnyTokenKind.Comment)
                        {
                            // if the change is in the comments, we want to start scanning from the
                            // the beginning of the comments instead.
                            SnapshotSpan span = r.Span.TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive);
                            if (span.IntersectsWith(newSpan))
                            {
                                start = span.Start.Position < newSpan.Start.Position ? span.Start : newSpan.Start;
                                end   = span.End.Position > newSpan.End.Position ? span.End : newSpan.End;
                                end   = Scan(snapshot.GetText(new SnapshotSpan(start, end)), start, regions, snapshot);
                                // record the regions that we rescanned.
                                rescannedRegions.Add(new SnapshotSpan(start, end));
                                done = true;
                                break;
                            }
                        }
                    }
                    if (!done)
                    {
                        // scan the lines that the change is on to generate the new regions.
                        end = Scan(snapshot.GetText(new SnapshotSpan(start, end)), start, regions, snapshot);
                        // record the span that we rescanned.
                        rescannedRegions.Add(new SnapshotSpan(start, end));
                    }
                }

                List <SnapshotSpan> oldSpans = new List <SnapshotSpan>();
                List <SnapshotSpan> newSpans = new List <SnapshotSpan>();
                // record the newly created spans.
                foreach (TokenRegion r in regions)
                {
                    newSpans.Add(r.Span);
                }
                // loop through the old scan results and remove the ones that
                // are in the regions that are rescanned.
                foreach (TokenRegion r in _regions)
                {
                    SnapshotSpan origSpan = r.Span.TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive);
                    bool         obsolete = false;
                    foreach (SnapshotSpan span in rescannedRegions)
                    {
                        if (origSpan.IntersectsWith(span))
                        {
                            oldSpans.Add(span);
                            obsolete = true;
                            break;
                        }
                    }
                    if (!obsolete)
                    {
                        TokenRegion region = new TokenRegion(origSpan.Start, origSpan.End, r.Kind);
                        regions.Add(region);
                    }
                }

                NormalizedSnapshotSpanCollection oldSpanCollection = new NormalizedSnapshotSpanCollection(oldSpans);
                NormalizedSnapshotSpanCollection newSpanCollection = new NormalizedSnapshotSpanCollection(newSpans);
                difference = SymmetricDifference(oldSpanCollection, newSpanCollection);

                // save the scan result
                _buffer.Properties[bufferTokenTaggerKey] = new ScanResult(_snapshot, snapshot, regions, difference);
                // save the new baseline
                _snapshot = snapshot;
                _regions  = regions;
            }

            var chng = TagsChanged;

            if (chng != null)
            {
                foreach (var span in difference)
                {
                    chng(this, new SnapshotSpanEventArgs(span));
                }
            }
        }