private ReadOnlyCollection <ITagSpan <IntraTextAdornmentTag> > GetTagsCore(SnapshotSpan span) { var list = new List <ITagSpan <IntraTextAdornmentTag> >(); var offset = span.Start.Position; var snapshot = span.Snapshot; // vars used in loop SnapshotSpan cbSpan; CBAdornmentData cbAdornmentData; CBETagControl tagElement; int cbStartPosition; int cbEndPosition; int cbHeaderPosition; string cbHeader; IntraTextAdornmentTag cbTag; SnapshotSpan cbSnapshotSpan; TagSpan <IntraTextAdornmentTag> cbTagSpan; bool isSingleLineComment = false; bool isMultiLineComment = false; #if DEBUG // Stop time if (watch == null) { watch = new System.Diagnostics.Stopwatch(); } watch.Restart(); #endif try { // Find all closing bracets for (int i = 0; i < span.Length; i++) { var position = i + offset; var chr = snapshot[position]; // Skip comments switch (chr) { case '/': if (position > 0) { if (snapshot[position - 1] == '/') { isSingleLineComment = true; } if (snapshot[position - 1] == '*') { if (!isMultiLineComment) { // Multiline comment was not started in this span // Every tag until now was inside a comment foreach (var tag in list) { RemoveFromCache((tag.Tag.Adornment as CBETagControl).AdornmentData); } list.Clear(); } isMultiLineComment = false; } } break; case '*': if (position > 0 && snapshot[position - 1] == '/') { isMultiLineComment = true; } break; case (char)10: isSingleLineComment = false; break; case (char)13: isSingleLineComment = false; break; } if (chr != '}' || isSingleLineComment || isMultiLineComment) { continue; } // getting start and end position of code block cbEndPosition = position; if (position >= 0 && snapshot[position - 1] == '{') { // empty code block {} cbStartPosition = position - 1; cbSpan = new SnapshotSpan(snapshot, cbStartPosition, cbEndPosition - cbStartPosition); } else { // create inner span to navigate to get code block start cbSpan = _TextStructureNavigator.GetSpanOfEnclosing(new SnapshotSpan(snapshot, position - 1, 1)); cbStartPosition = cbSpan.Start; } // Don't display tag for code blocks on same line if (!snapshot.GetText(cbSpan).Contains('\n')) { continue; } // getting the code blocks header cbHeaderPosition = -1; if (snapshot[cbStartPosition] == '{') { // cbSpan does not contain the header cbHeader = GetCodeBlockHeader(cbSpan, out cbHeaderPosition); } else { // cbSpan does contain the header cbHeader = GetCodeBlockHeader(cbSpan, out cbHeaderPosition, position); } // Trim header if (cbHeader != null && cbHeader.Length > 0) { cbHeader = cbHeader.Trim() .Replace(Environment.NewLine, "") .Replace('\t', ' '); // Strip unnecessary spaces while (cbHeader.Contains(" ")) { cbHeader = cbHeader.Replace(" ", " "); } } // Skip tag if option "only when header not visible" if (_VisibleSpan != null && !IsTagVisible(cbHeaderPosition, cbEndPosition, _VisibleSpan, snapshot)) { continue; } var iconMoniker = Microsoft.VisualStudio.Imaging.KnownMonikers.QuestionMark; if (CBETagPackage.CBEDisplayMode != (int)CBEOptionPage.DisplayModes.Text && !string.IsNullOrWhiteSpace(cbHeader) && !cbHeader.Contains("{")) { iconMoniker = IconMonikerSelector.SelectMoniker(cbHeader); } // use cache or create new tag cbAdornmentData = _adornmentCache .Where(o => o.StartPosition == cbStartPosition && o.EndPosition == cbEndPosition) .FirstOrDefault(); if (cbAdornmentData?.Adornment != null) { tagElement = cbAdornmentData.Adornment as CBETagControl; } else { // create new adornment tagElement = new CBETagControl() { Text = cbHeader, IconMoniker = iconMoniker, DisplayMode = CBETagPackage.CBEDisplayMode }; tagElement.TagClicked += Adornment_TagClicked; cbAdornmentData = new CBAdornmentData(cbStartPosition, cbEndPosition, cbHeaderPosition, tagElement); tagElement.AdornmentData = cbAdornmentData; _adornmentCache.Add(cbAdornmentData); } tagElement.LineHeight = _FontSize * CBETagPackage.CBETagScale; // Add new tag to list cbTag = new IntraTextAdornmentTag(tagElement, null); cbSnapshotSpan = new SnapshotSpan(snapshot, position + 1, 0); cbTagSpan = new TagSpan <IntraTextAdornmentTag>(cbSnapshotSpan, cbTag); list.Add(cbTagSpan); } } catch (NullReferenceException) { // May happen, when closing a text editor } #if DEBUG watch.Stop(); if (watch.Elapsed.Milliseconds > 100) { System.Diagnostics.Debug.WriteLine("Time elapsed: " + watch.Elapsed + " on Thread: " + System.Threading.Thread.CurrentThread.ManagedThreadId + " in Span: " + span.Start.Position + ":" + span.End.Position + " length: " + span.Length); } #endif return(new ReadOnlyCollection <ITagSpan <IntraTextAdornmentTag> >(list)); }
private ReadOnlyCollection <ITagSpan <IntraTextAdornmentTag> > GetTagsCore(SnapshotSpan span) { var list = new List <ITagSpan <IntraTextAdornmentTag> >(); var offset = span.Start.Position; var snapshot = span.Snapshot; // vars used in loop var isSingleLineComment = false; var isMultiLineComment = false; // Find all closing bracets for (int i = 0; i < span.Length; i++) { var position = i + offset; // Skip comments switch (snapshot[position]) { case '/': if (position > 0) { if (snapshot[position - 1] == '/') { isSingleLineComment = true; } if (snapshot[position - 1] == '*') { if (!isMultiLineComment) { // Multiline comment was not started in this span // Every tag until now was inside a comment foreach (var tag in list) { RemoveFromCache((tag.Tag.Adornment as CBETagControl).AdornmentData); } list.Clear(); } isMultiLineComment = false; } } break; case '*': if (position > 0 && snapshot[position - 1] == '/') { isMultiLineComment = true; } break; case '\n': case '\r': isSingleLineComment = false; break; } if (snapshot[position] != '}' || isSingleLineComment || isMultiLineComment) { continue; } SnapshotSpan cbSpan; int cbStartPosition; // getting start and end position of code block var cbEndPosition = position; if (position >= 0 && snapshot[position - 1] == '{') { // empty code block {} cbStartPosition = position - 1; cbSpan = new SnapshotSpan(snapshot, position - 1, 1); } else { // create inner span to navigate to get code block start cbSpan = _TextStructureNavigator.GetSpanOfEnclosing(new SnapshotSpan(snapshot, position - 1, 1)); cbStartPosition = cbSpan.Start; } // Don't display tag for code blocks on same line if (!snapshot.GetText(cbSpan).Contains('\n')) { continue; } // getting the code blocks header var cbHeaderPosition = -1; string cbHeader; if (snapshot[cbStartPosition] == '{') { // cbSpan does not contain the header cbHeader = GetCodeBlockHeader(cbSpan, out cbHeaderPosition); } else { // cbSpan does contain the header cbHeader = GetCodeBlockHeader(cbSpan, out cbHeaderPosition, position); } // Trim header if (cbHeader != null && cbHeader.Length > 0) { cbHeader = cbHeader.Trim() .Replace(Environment.NewLine, "") .Replace('\t', ' '); // Strip unnecessary spaces while (cbHeader.Contains(" ")) { cbHeader = cbHeader.Replace(" ", " "); } } // Skip tag if option "only when header not visible" if (_VisibleSpan != null && !IsTagVisible(cbHeaderPosition, cbEndPosition, _VisibleSpan, snapshot)) { continue; } var iconMoniker = Microsoft.VisualStudio.Imaging.KnownMonikers.QuestionMark; if (CBETagPackage.CBEDisplayMode != (int)CBEOptionPage.DisplayModes.Text && !string.IsNullOrWhiteSpace(cbHeader) && !cbHeader.Contains("{")) { iconMoniker = IconMonikerSelector.SelectMoniker(cbHeader); } // use cache or create new tag var cbAdornmentData = _adornmentCache .Find(x => x.StartPosition == cbStartPosition && x.EndPosition == cbEndPosition); CBETagControl tagElement; if (cbAdornmentData?.Adornment != null) { tagElement = cbAdornmentData.Adornment as CBETagControl; } else { // create new adornment tagElement = new CBETagControl() { Text = cbHeader, IconMoniker = iconMoniker, DisplayMode = CBETagPackage.CBEDisplayMode }; tagElement.TagClicked += Adornment_TagClicked; cbAdornmentData = new CBAdornmentData(cbStartPosition, cbEndPosition, cbHeaderPosition, tagElement); tagElement.AdornmentData = cbAdornmentData; _adornmentCache.Add(cbAdornmentData); } tagElement.LineHeight = _FontSize * CBETagPackage.CBETagScale; // Add new tag to list var cbTag = new IntraTextAdornmentTag(tagElement, null); var cbSnapshotSpan = new SnapshotSpan(snapshot, position + 1, 0); var cbTagSpan = new TagSpan <IntraTextAdornmentTag>(cbSnapshotSpan, cbTag); list.Add(cbTagSpan); } return(new ReadOnlyCollection <ITagSpan <IntraTextAdornmentTag> >(list)); }