void PushColor(HighlightingColor color) { if (highlightedLine == null) { return; } if (color == null) { highlightedSectionStack.Push(null); } else if (lastPoppedSection != null && lastPoppedSection.Color == color && lastPoppedSection.Offset + lastPoppedSection.Length == position + lineStartOffset) { highlightedSectionStack.Push(lastPoppedSection); lastPoppedSection = null; } else { HighlightedSection hs = new HighlightedSection { Offset = position + lineStartOffset, Color = color }; highlightedLine.Sections.Add(hs); highlightedSectionStack.Push(hs); lastPoppedSection = null; } }
/// <summary> /// Validates that the sections are sorted correctly, and that they are not overlapping. /// </summary> /// <seealso cref="Sections"/> public void ValidateInvariants() { var line = this; int lineStartOffset = line.DocumentLine.Offset; int lineEndOffset = line.DocumentLine.EndOffset; for (int i = 0; i < line.Sections.Count; i++) { HighlightedSection s1 = line.Sections[i]; if (s1.Offset < lineStartOffset || s1.Length < 0 || s1.Offset + s1.Length > lineEndOffset) { throw new InvalidOperationException("Section is outside line bounds"); } for (int j = i + 1; j < line.Sections.Count; j++) { HighlightedSection s2 = line.Sections[j]; if (s2.Offset >= s1.Offset + s1.Length) { // s2 is after s1 } else if (s2.Offset >= s1.Offset && s2.Offset + s2.Length <= s1.Offset + s1.Length) { // s2 is nested within s1 } else { throw new InvalidOperationException("Sections are overlapping or incorrectly sorted."); } } } }
/// <summary> /// Produces HTML code for a section of the line, with <span class="colorName"> tags. /// </summary> public string ToHtml(int startOffset, int endOffset, HtmlOptions options) { if (options == null) { throw new ArgumentNullException("options"); } int documentLineStartOffset = this.DocumentLine.Offset; int documentLineEndOffset = documentLineStartOffset + this.DocumentLine.Length; if (startOffset < documentLineStartOffset || startOffset > documentLineEndOffset) { throw new ArgumentOutOfRangeException("startOffset", startOffset, "Value must be between " + documentLineStartOffset + " and " + documentLineEndOffset); } if (endOffset < startOffset || endOffset > documentLineEndOffset) { throw new ArgumentOutOfRangeException("endOffset", endOffset, "Value must be between startOffset and " + documentLineEndOffset); } ISegment requestedSegment = new SimpleSegment(startOffset, endOffset - startOffset); List <HtmlElement> elements = new List <HtmlElement>(); for (int i = 0; i < this.Sections.Count; i++) { HighlightedSection s = this.Sections[i]; if (s.GetOverlap(requestedSegment).Length > 0) { elements.Add(new HtmlElement(s.Offset, i, false, s.Color)); elements.Add(new HtmlElement(s.Offset + s.Length, i, true, s.Color)); } } elements.Sort(); TextDocument document = this.Document; StringWriter w = new StringWriter(CultureInfo.InvariantCulture); int textOffset = startOffset; foreach (HtmlElement e in elements) { int newOffset = Math.Min(e.Offset, endOffset); if (newOffset > startOffset) { HtmlClipboard.EscapeHtml(w, document.GetText(textOffset, newOffset - textOffset), options); } textOffset = Math.Max(textOffset, newOffset); if (e.IsEnd) { w.Write("</span>"); } else { w.Write("<span"); options.WriteStyleAttributeForColor(w, e.Color); w.Write('>'); } } HtmlClipboard.EscapeHtml(w, document.GetText(textOffset, endOffset - textOffset), options); return(w.ToString()); }
/// <summary> /// Produces HTML code for a section of the line, with <span class="colorName"> tags. /// </summary> public string ToHtml(int startOffset, int endOffset, HtmlOptions options) { if (options == null) { throw new ArgumentNullException("options"); } int documentLineStartOffset = this.DocumentLine.Offset; int documentLineEndOffset = documentLineStartOffset + this.DocumentLine.Length; if (startOffset < documentLineStartOffset || startOffset > documentLineEndOffset) { throw new ArgumentOutOfRangeException("startOffset", startOffset, "Value must be between " + documentLineStartOffset + " and " + documentLineEndOffset); } if (endOffset < startOffset || endOffset > documentLineEndOffset) { throw new ArgumentOutOfRangeException("endOffset", endOffset, "Value must be between startOffset and " + documentLineEndOffset); } ISegment requestedSegment = new SimpleSegment(startOffset, endOffset - startOffset); List <HtmlElement> elements = new List <HtmlElement>(); for (int i = 0; i < this.Sections.Count; i++) { HighlightedSection s = this.Sections[i]; if (s.GetOverlap(requestedSegment).Length > 0) { elements.Add(new HtmlElement(s.Offset, i, false, s.Color)); elements.Add(new HtmlElement(s.Offset + s.Length, i, true, s.Color)); } } elements.Sort(); TextDocument document = DocumentLine.Document; StringBuilder b = new StringBuilder(); int textOffset = startOffset; foreach (HtmlElement e in elements) { int newOffset = Math.Min(e.Offset, endOffset); if (newOffset > startOffset) { HtmlClipboard.EscapeHtml(b, document.GetText(textOffset, newOffset - textOffset), options); } textOffset = newOffset; if (e.IsEnd) { b.Append("</span>"); } else { b.Append("<span style=\""); b.Append(e.Color.ToCss()); b.Append("\">"); } } HtmlClipboard.EscapeHtml(b, document.GetText(textOffset, endOffset - textOffset), options); return(b.ToString()); }
/// <summary> /// Writes a part of the highlighted line to the RichTextWriter. /// </summary> internal void WriteTo(RichTextWriter writer, int startOffset, int endOffset) { if (writer == null) { throw new ArgumentNullException("writer"); } int documentLineStartOffset = this.DocumentLine.Offset; int documentLineEndOffset = documentLineStartOffset + this.DocumentLine.Length; if (startOffset < documentLineStartOffset || startOffset > documentLineEndOffset) { throw new ArgumentOutOfRangeException("startOffset", startOffset, "Value must be between " + documentLineStartOffset + " and " + documentLineEndOffset); } if (endOffset < startOffset || endOffset > documentLineEndOffset) { throw new ArgumentOutOfRangeException("endOffset", endOffset, "Value must be between startOffset and " + documentLineEndOffset); } ISegment requestedSegment = new SimpleSegment(startOffset, endOffset - startOffset); List <HtmlElement> elements = new List <HtmlElement>(); for (int i = 0; i < this.Sections.Count; i++) { HighlightedSection s = this.Sections[i]; if (SimpleSegment.GetOverlap(s, requestedSegment).Length > 0) { elements.Add(new HtmlElement(s.Offset, i, false, s.Color)); elements.Add(new HtmlElement(s.Offset + s.Length, i, true, s.Color)); } } elements.Sort(); IDocument document = this.Document; int textOffset = startOffset; foreach (HtmlElement e in elements) { int newOffset = Math.Min(e.Offset, endOffset); if (newOffset > startOffset) { document.WriteTextTo(writer, textOffset, newOffset - textOffset); } textOffset = Math.Max(textOffset, newOffset); if (e.IsEnd) { writer.EndSpan(); } else { writer.BeginSpan(e.Color); } } document.WriteTextTo(writer, textOffset, endOffset - textOffset); }
void PopColor() { if (highlightedLine == null) return; HighlightedSection s = highlightedSectionStack.Pop(); if (s != null) { s.Length = (position + lineStartOffset) - s.Offset; if (s.Length == 0) highlightedLine.Sections.Remove(s); else lastPoppedSection = s; } }
void ResetColorStack() { Debug.Assert(position == 0); lastPoppedSection = null; if (highlightedLine == null) { highlightedSectionStack = null; } else { highlightedSectionStack = new Stack<HighlightedSection>(); foreach (HighlightingSpan span in spanStack.Reverse()) { PushColor(span.SpanColor); } } }
private void HighlightLine(HighlightLineEventArgs e, ImmutableArray<SpanInfo> spans) { var line = e.Line; foreach (var span in spans) { var start = line.Offset; var end = line.Offset + line.Length; if (start > span.Span.EndPos || end < span.Span.StartPos) continue; var spanClassId = span.SpanClassId; var color = _highlightingStyles[spanClassId]; var startOffset = Math.Max(line.Offset, span.Span.StartPos); var endOffset = Math.Min(line.EndOffset, span.Span.EndPos); var section = new HighlightedSection { Offset = startOffset, Length = endOffset - startOffset, Color = color }; e.Sections.Add(section); } }
void PushColor(HighlightingColor color) { if (highlightedLine == null) return; if (color == null) { highlightedSectionStack.Push(null); } else if (lastPoppedSection != null && lastPoppedSection.Color == color && lastPoppedSection.Offset + lastPoppedSection.Length == position + lineStartOffset) { highlightedSectionStack.Push(lastPoppedSection); lastPoppedSection = null; } else { HighlightedSection hs = new HighlightedSection { Offset = position + lineStartOffset, Color = color }; highlightedLine.Sections.Add(hs); highlightedSectionStack.Push(hs); lastPoppedSection = null; } }
/// <summary> /// Merges the additional line into this line. /// </summary> public void MergeWith(HighlightedLine additionalLine) { if (additionalLine == null) { return; } #if DEBUG ValidateInvariants(); additionalLine.ValidateInvariants(); #endif int pos = 0; Stack <int> activeSectionEndOffsets = new Stack <int>(); int lineEndOffset = this.DocumentLine.EndOffset; activeSectionEndOffsets.Push(lineEndOffset); foreach (HighlightedSection newSection in additionalLine.Sections) { int newSectionStart = newSection.Offset; // Track the existing sections using the stack, up to the point where // we need to insert the first part of the newSection while (pos < this.Sections.Count) { HighlightedSection s = this.Sections[pos]; if (newSection.Offset < s.Offset) { break; } while (s.Offset > activeSectionEndOffsets.Peek()) { activeSectionEndOffsets.Pop(); } activeSectionEndOffsets.Push(s.Offset + s.Length); pos++; } // Now insert the new section // Create a copy of the stack so that we can track the sections we traverse // during the insertion process: Stack <int> insertionStack = new Stack <int>(activeSectionEndOffsets.Reverse()); // The stack enumerator reverses the order of the elements, so we call Reverse() to restore // the original order. int i; for (i = pos; i < this.Sections.Count; i++) { HighlightedSection s = this.Sections[i]; if (newSection.Offset + newSection.Length <= s.Offset) { break; } // Insert a segment in front of s: Insert(ref i, ref newSectionStart, s.Offset, newSection.Color, insertionStack); while (s.Offset > insertionStack.Peek()) { insertionStack.Pop(); } insertionStack.Push(s.Offset + s.Length); } Insert(ref i, ref newSectionStart, newSection.Offset + newSection.Length, newSection.Color, insertionStack); } #if DEBUG ValidateInvariants(); #endif }
private void textBox1_HighlightLine(object sender, HighlightLineEventArgs e) { if (_parseResult == null) return; try { var line = e.Line; var spans = new List<SpanInfo>(); var timer = Stopwatch.StartNew(); _parseResult.GetSpans(line.Offset, line.EndOffset, spans); _highlightingTimeSpan = timer.Elapsed; _highlightingTime.Text = _highlightingTimeSpan.ToString(); foreach (var span in spans) { HighlightingColor color; if (_highlightingStyles.TryGetValue(span.SpanClass.Name, out color)) { var startOffset = Math.Max(line.Offset, span.Span.StartPos); var endOffset = Math.Min(line.EndOffset, span.Span.EndPos); var section = new HighlightedSection { Offset = startOffset, Length = endOffset - startOffset, Color = color }; e.Sections.Add(section); } } } catch (Exception ex) { Debug.WriteLine(ex.Message); } }
private void textBox1_HighlightLine(object sender, HighlightLineEventArgs e) { if (_parseResult == null) return; try { var line = e.Line; var spans = new HashSet<SpanInfo>(); _parseResult.GetSpans(line.Offset, line.EndOffset, spans); var astRoot = _astRoot; if (astRoot != null) { var visitor = new CollectSymbolsAstVisitor(new NSpan(line.Offset, line.EndOffset)); astRoot.Accept(visitor); foreach (var spanInfo in visitor.SpanInfos) spans.Add(spanInfo); } foreach (var span in spans) { HighlightingColor color; if (!_highlightingStyles.TryGetValue(span.SpanClass.FullName, out color)) { color = MakeHighlightingColor(span.SpanClass); _highlightingStyles.Add(span.SpanClass.FullName, color); } var startOffset = Math.Max(line.Offset, span.Span.StartPos); var endOffset = Math.Min(line.EndOffset, span.Span.EndPos); var section = new HighlightedSection { Offset = startOffset, Length = endOffset - startOffset, Color = color }; e.Sections.Add(section); } } catch (Exception ex) { Debug.WriteLine(ex.GetType().Name + ":" + ex.Message); } }