public IEnumerable <ITagSpan <TextMarkerTag> > GetTags(NormalizedSnapshotSpanCollection spans) { DateTime oStart, oEnd; TimeSpan timeSpan; oStart = DateTime.Now; Debug("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 { currentText = ssp.GetChar(); lastChar = ssp == 0 ? ssp : ssp - 1; //if ssp is 0 (beginning of buffer), don't move it back lastText = lastChar.GetChar(); } 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(); text = text.Substring(member.Interval.Start, member.Interval.Width); //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; Debug("Start sourceWalker.Lex: " + DateTime.Now.ToString("hh:mm:ss.fff")); var stream = (BufferedTokenStream)sourceWalker.Lex(text); Debug("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; Debug("Finished get brackets: " + oEnd.ToString("hh:mm:ss.fff")); Debug("Finished get brackets - total ms: " + timeSpan.TotalMilliseconds.ToString()); }
public IEnumerable <ITagSpan <TextMarkerTag> > GetTags(NormalizedSnapshotSpanCollection spans) { if (spans.Count == 0) //there is no content in the buffer { 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 currentChar = 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 != currentChar.Snapshot) { //currentChar = currentChar.TranslateTo(spans[0].Snapshot, PointTrackingMode.Positive); yield break; } //get the current char and the previous char char currentText = '\0'; char lastText = '\0'; SnapshotSpan pairSpan = new SnapshotSpan(); SnapshotPoint lastChar = new SnapshotPoint(); try { currentText = currentChar.GetChar(); lastChar = currentChar == 0 ? currentChar : currentChar - 1; //if currentChar is 0 (beginning of buffer), don't move it back lastText = lastChar.GetChar(); } catch (Exception) { } // use the tokens stored in the buffer properties XSharpTokens xTokens = null; IList <IToken> tokens = null; int offset = 0; if (SourceBuffer.Properties.ContainsProperty(typeof(XSharpTokens))) { xTokens = SourceBuffer.Properties.GetProperty <XSharpTokens>(typeof(XSharpTokens)); if (xTokens.SnapShot.Version != currentChar.Snapshot.Version) { // get source from the start of the file until the current entity var xfile = SourceBuffer.GetFile(); var member = XSharpTokenTools.FindMemberAtPosition(currentChar.Position, xfile); if (member != null) { try { offset = member.Interval.Start; var length = member.Interval.Width; if (offset + length > currentChar.Snapshot.Length) { length = currentChar.Snapshot.Length - offset; } // string text = currentChar.Snapshot.GetText(offset, length); var reporter = new ErrorIgnorer(); ITokenStream tokenStream; XSharpParseOptions parseoptions; var prj = xfile.Project.ProjectNode; parseoptions = prj.ParseOptions; bool ok = XSharp.Parser.VsParser.Lex(text, xfile.FullPath, parseoptions, reporter, out tokenStream); var bstream = tokenStream as BufferedTokenStream; tokens = bstream.GetTokens(); } catch { // 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 yield break; } } } else { tokens = xTokens.TokenStream.GetTokens(); } } // 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(currentChar, currentText, closeChar, out pairSpan, tokens, offset) == true) { yield return(new TagSpan <TextMarkerTag>(new SnapshotSpan(currentChar, 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 != currentChar.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)); // int indexTag = sortedTags.FindIndex(x => currentChar.Position >= x.Span.Start.Position && currentChar.Position <= x.Span.End.Position); if (indexTag != -1) { var currentTag = sortedTags[indexTag]; if (currentTag.ClassificationType.IsOfType(ColorizerConstants.XSharpBraceOpenFormat)) { if (FindMatchingCloseTag(sortedTags, indexTag, 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, indexTag, 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"))); } } } } } }