///// <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); }
/// <summary> /// Creates a HTML fragment from a part of a document. /// </summary> /// <param name="document">The document to create HTML from.</param> /// <param name="highlighter">The highlighter used to highlight the document. <c>null</c> is valid and will create HTML without any highlighting.</param> /// <param name="segment">The part of the document to create HTML for. You can pass <c>null</c> to create HTML for the whole document.</param> /// <param name="options">The options for the HTML creation.</param> /// <returns>HTML code for the document part.</returns> public static string CreateHtmlFragment(IDocument document, IHighlighter highlighter, ISegment segment, HtmlOptions options) { if (document == null) { throw new ArgumentNullException("document"); } if (options == null) { throw new ArgumentNullException("options"); } if (highlighter != null && highlighter.Document != document) { throw new ArgumentException("Highlighter does not belong to the specified document."); } if (segment == null) { segment = new SimpleSegment(0, document.TextLength); } StringBuilder html = new StringBuilder(); int segmentEndOffset = segment.EndOffset; IDocumentLine line = document.GetLineByOffset(segment.Offset); while (line != null && line.Offset < segmentEndOffset) { HighlightedLine highlightedLine; if (highlighter != null) { highlightedLine = highlighter.HighlightLine(line.LineNumber); } else { highlightedLine = new HighlightedLine(document, line); } SimpleSegment s = SimpleSegment.GetOverlap(segment, line); if (html.Length > 0) { html.AppendLine("<br>"); } html.Append(highlightedLine.ToHtml(s.Offset, s.EndOffset, options)); line = line.NextLine; } return(html.ToString()); }
/// <summary> /// Sets the TextDataFormat.Html on the data object to the specified html fragment. /// This helper methods takes care of creating the necessary CF_HTML header. /// </summary> //public static void SetHtml(DataObject dataObject, string htmlFragment) //{ // if (dataObject == null) // throw new ArgumentNullException("dataObject"); // if (htmlFragment == null) // throw new ArgumentNullException("htmlFragment"); // string htmlStart = @"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.0 Transitional//EN"">" + Environment.NewLine // + "<HTML>" + Environment.NewLine // + "<BODY>" + Environment.NewLine // + "<!--StartFragment-->" + Environment.NewLine; // string htmlEnd = "<!--EndFragment-->" + Environment.NewLine + "</BODY>" + Environment.NewLine + "</HTML>" + Environment.NewLine; // string dummyHeader = BuildHeader(0, 0, 0, 0); // // the offsets are stored as UTF-8 bytes (see CF_HTML documentation) // int startHTML = dummyHeader.Length; // int startFragment = startHTML + htmlStart.Length; // int endFragment = startFragment + Encoding.UTF8.GetByteCount(htmlFragment); // int endHTML = endFragment + htmlEnd.Length; // string cf_html = BuildHeader(startHTML, endHTML, startFragment, endFragment) + htmlStart + htmlFragment + htmlEnd; // Debug.WriteLine(cf_html); // dataObject.SetText(cf_html, TextDataFormat.Html); //} /// <summary> /// Creates a HTML fragment from a part of a document. /// </summary> /// <param name="document">The document to create HTML from.</param> /// <param name="highlighter">The highlighter used to highlight the document. <c>null</c> is valid and will create HTML without any highlighting.</param> /// <param name="segment">The part of the document to create HTML for. You can pass <c>null</c> to create HTML for the whole document.</param> /// <param name="options">The options for the HTML creation.</param> /// <returns>HTML code for the document part.</returns> public static string CreateHtmlFragment(IDocument document, IHighlighter highlighter, ISegment segment, HtmlOptions options) { if (document == null) { throw new ArgumentNullException(nameof(document)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } if (highlighter != null && highlighter.Document != document) { throw new ArgumentException("Highlighter does not belong to the specified document."); } if (segment == null) { segment = new SimpleSegment(0, document.TextLength); } var html = new StringBuilder(); var segmentEndOffset = segment.EndOffset; var line = document.GetLineByOffset(segment.Offset); while (line != null && line.Offset < segmentEndOffset) { // ReSharper disable once UnusedVariable var highlightedLine = highlighter != null?highlighter.HighlightLine(line.LineNumber) : new HighlightedLine(document, line); if (html.Length > 0) { html.AppendLine("<br>"); } // TODO: html var s = SimpleSegment.GetOverlap(segment, line); html.Append(highlightedLine.ToHtml(s.Offset, s.EndOffset, options)); line = line.NextLine; } return(html.ToString()); }
void targetElement_TextChanged(object sender, EventArgs e) { // Don't copy text if the segments overlap (we would get an endless loop). // This can happen if the user deletes the text between the replaceable element and the bound element. if (SimpleSegment.GetOverlap(segment, targetElement.Segment) == SimpleSegment.Invalid) { int offset = segment.Offset; int length = segment.Length; string text = boundElement.ConvertText(targetElement.Text); if (length != text.Length || text != context.Document.GetText(offset, length)) { // Call replace only if we're actually changing something. // Without this check, we would generate an empty undo group when the user pressed undo. context.Document.Replace(offset, length, text); if (length == 0) { // replacing an empty anchor segment with text won't enlarge it, so we have to recreate it segment = new AnchorSegment(context.Document, offset, text.Length); } } } }
/// <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 (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; 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 (options.ColorNeedsSpanForStyling(e.Color)) { 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()); }