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));
        }