1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
namespace Tango.Scripting.Editors.Utils
{
/// <summary>
/// TextReader implementation that reads text from a rope.
/// </summary>
public sealed class RopeTextReader : TextReader
{
Stack<RopeNode<char>> stack = new Stack<RopeNode<char>>();
RopeNode<char> currentNode;
int indexInsideNode;
/// <summary>
/// Creates a new RopeTextReader.
/// Internally, this method creates a Clone of the rope; so the text reader will always read through the old
/// version of the rope if it is modified. <seealso cref="Rope{T}.Clone()"/>
/// </summary>
public RopeTextReader(Rope<char> rope)
{
if (rope == null)
throw new ArgumentNullException("rope");
// We force the user to iterate through a clone of the rope to keep the API contract of RopeTextReader simple
// (what happens when a rope is modified while iterating through it?)
rope.root.Publish();
// special case for the empty rope:
// leave currentNode initialized to null (RopeTextReader doesn't support empty nodes)
if (rope.Length != 0) {
currentNode = rope.root;
GoToLeftMostLeaf();
}
}
void GoToLeftMostLeaf()
{
while (currentNode.contents == null) {
if (currentNode.height == 0) {
// this is a function node - move to its contained rope
currentNode = currentNode.GetContentNode();
continue;
}
Debug.Assert(currentNode.right != null);
stack.Push(currentNode.right);
currentNode = currentNode.left;
}
Debug.Assert(currentNode.height == 0);
}
/// <inheritdoc/>
public override int Peek()
{
if (currentNode == null)
return -1;
return currentNode.contents[indexInsideNode];
}
/// <inheritdoc/>
public override int Read()
{
if (currentNode == null)
return -1;
char result = currentNode.contents[indexInsideNode++];
if (indexInsideNode >= currentNode.length)
GoToNextNode();
return result;
}
void GoToNextNode()
{
if (stack.Count == 0) {
currentNode = null;
} else {
indexInsideNode = 0;
currentNode = stack.Pop();
GoToLeftMostLeaf();
}
}
/// <inheritdoc/>
public override int Read(char[] buffer, int index, int count)
{
if (currentNode == null)
return 0;
int amountInCurrentNode = currentNode.length - indexInsideNode;
if (count < amountInCurrentNode) {
Array.Copy(currentNode.contents, indexInsideNode, buffer, index, count);
indexInsideNode += count;
return count;
} else {
// read to end of current node
Array.Copy(currentNode.contents, indexInsideNode, buffer, index, amountInCurrentNode);
GoToNextNode();
return amountInCurrentNode;
}
}
}
}
">+ 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(TextDocument 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;
DocumentLine 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 = segment.GetOverlap(line);
if (html.Length > 0)
html.AppendLine("<br>");
html.Append(highlightedLine.ToHtml(s.Offset, s.EndOffset, options));
line = line.NextLine;
}
return html.ToString();
}
/// <summary>
/// Escapes text and writes the result to the StringBuilder.
/// </summary>
internal static void EscapeHtml(StringWriter w, string text, HtmlOptions options)
{
int spaceCount = -1;
foreach (char c in text) {
if (c == ' ') {
if (spaceCount < 0)
w.Write(" ");
else
spaceCount++;
} else if (c == '\t') {
if (spaceCount < 0)
spaceCount = 0;
spaceCount += options.TabSize;
} else {
if (spaceCount == 1) {
w.Write(' ');
} else if (spaceCount >= 1) {
for (int i = 0; i < spaceCount; i++) {
w.Write(" ");
}
}
spaceCount = 0;
switch (c) {
case '<':
w.Write("<");
break;
case '>':
w.Write(">");
break;
case '&':
w.Write("&");
break;
case '"':
w.Write(""");
break;
default:
w.Write(c);
break;
}
}
}
for (int i = 0; i < spaceCount; i++) {
w.Write(" ");
}
}
}
/// <summary>
/// Holds options for converting text to HTML.
/// </summary>
public class HtmlOptions
{
/// <summary>
/// Creates a default HtmlOptions instance.
/// </summary>
public HtmlOptions()
{
this.TabSize = 4;
}
/// <summary>
/// Creates a new HtmlOptions instance that copies applicable options from the <see cref="TextEditorOptions"/>.
/// </summary>
public HtmlOptions(TextEditorOptions options)
: this()
{
if (options == null)
throw new ArgumentNullException("options");
this.TabSize = options.IndentationSize;
}
/// <summary>
/// The amount of spaces a tab gets converted to.
/// </summary>
public int TabSize { get; set; }
/// <summary>
/// Writes the HTML attribute for the style to the text writer.
/// </summary>
public virtual void WriteStyleAttributeForColor(TextWriter writer, HighlightingColor color)
{
if (writer == null)
throw new ArgumentNullException("writer");
if (color == null)
throw new ArgumentNullException("color");
writer.Write(" style=\"");
writer.Write(color.ToCss());
writer.Write("\"");
}
/// <summary>
/// Gets whether the color needs to be written out to HTML.
/// </summary>
public virtual bool ColorNeedsSpanForStyling(HighlightingColor color)
{
if (color == null)
throw new ArgumentNullException("color");
return !string.IsNullOrEmpty(color.ToCss());
}
}
}
|