// 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.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Windows;
using Tango.Scripting.Editors.Document;
namespace Tango.Scripting.Editors.Highlighting
{
/// <summary>
/// Allows copying HTML text to the clipboard.
/// </summary>
public static class HtmlClipboard
{
/// <summary>
/// Builds a header for the CF_HTML clipboard format.
/// </summary>
static string BuildHeader(int startHTML, int endHTML, int startFragment, int endFragment)
{
StringBuilder b = new StringBuilder();
b.AppendLine("Version:0.9");
b.AppendLine("StartHTML:" + startHTML.ToString("d8", CultureInfo.InvariantCulture));
b.AppendLine("EndHTML:" + endHTML.ToString("d8", CultureInfo.InvariantCulture));
b.AppendLine("StartFragment:" + startFragment.ToString("d8", CultureInfo.InvariantCulture));
b.AppendLine("EndFragment:" + endFragment.ToString("d8", CultureInfo.InvariantCulture));
return b.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>
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */// 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.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Serialization;
using System.Text;
namespace Tango.Scripting.Editors.Utils
{
/// <summary>
/// A kind of List<T>, but more efficient for random insertions/removal.
/// Also has cheap Clone() and SubRope() implementations.
/// </summary>
/// <remarks>
/// This class is not thread-safe: multiple concurrent write operations or writes concurrent to reads have undefined behaviour.
/// Concurrent reads, however, are safe.
/// However, clones of a rope are safe to use on other threads even though they share data with the original rope.
/// </remarks>
[Serializable]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
public sealed class Rope<T> : IList<T>, ICloneable
{
internal RopeNode<T> root;
internal Rope(RopeNode<T> root)
{
this.root = root;
root.CheckInvariants();
}
/// <summary>
/// Creates a new rope representing the empty string.
/// </summary>
public Rope()
{
// we'll construct the empty rope as a clone of an imaginary static empty rope
this.root = RopeNode<T>.emptyRopeNode;
root.CheckInvariants();
}
/// <summary>
/// Creates a rope from the specified input.
/// This operation runs in O(N).
/// </summary>
/// <exception cref="ArgumentNullException">input is null.</exception>
public Rope(IEnumerable<T> input)
{
if (input == null)
throw new ArgumentNullException("input");
Rope<T> inputRope = input as Rope<T>;
if (inputRope != null) {
// clone ropes instead of copying them
inputRope.root.Publish();
this.root = inputRope.root;
} else {
string text = input as string;
if (text != null) {
// if a string is IEnumerable<T>, then T must be char
((Rope<char>)(object)this).root = CharRope.InitFromString(text);
} else {
T[] arr = ToArray(input);
this.root = RopeNode<T>.CreateFromArray(arr, 0, arr.Length);
}
}
this.root.CheckInvariants();
}
/// <summary>
/// Creates a rope from a part of the array.
/// This operation runs in O(N).
/// </summary>
/// <exception cref="ArgumentNullException">input is null.</exception>
public Rope(T[] array, int arrayIndex, int count)
{
VerifyArrayWithRange(array, arrayIndex, count);
this.root = RopeNode<T>.CreateFromArray(array, arrayIndex, count);
this.root.CheckInvariants();
}
/// <summary>
/// Creates a new rope that lazily initalizes its content.
/// </summary>
/// <param name="length">The length of the rope that will be lazily loaded.</param>
/// <param name="initializer">
/// The callback that provides the content for this rope.
/// <paramref name="initializer"/> will be called exactly once when the content of this rope is first requested.
/// It must return a rope with the specified length.
/// Because the initializer function is not called when a rope is cloned, and such clones may be used on another threads,
/// it is possible for the initializer callback to occur on any thread.
/// </param>
/// <remarks>
/// Any modifications inside the rope will also cause the content to be initialized.
/// However, insertions at the beginning and the end, as well as inserting this rope into another or
/// using the <see cref="Concat(Rope{T},Rope{T})"/> method, allows constructions of larger ropes where parts are
/// lazily loaded.
/// However, even methods like Concat may sometimes cause the initializer function to be called, e.g. when
/// two short ropes are concatenated.
/// </remarks>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
public Rope(int length, Func<Rope<T>> initializer)
{
if (initializer == null)
throw new ArgumentNullException("initializer");
if (length < 0)
throw new ArgumentOutOfRangeException("length", length, "Length must not be negative");
if (length == 0) {
this.root = RopeNode<T>.emptyRopeNode;
} else {
this.root = new FunctionNode<T>(length, initializer);
}
this.root.CheckInvariants();
}
static T[] ToArray(IEnumerable<T> input)
{
T[] arr = input as T[];
return arr ?? input.ToArray();
}
/// <summary>
/// Clones t