Mercurial > projects > ldc
diff tango/tango/text/Text.d @ 132:1700239cab2e trunk
[svn r136] MAJOR UNSTABLE UPDATE!!!
Initial commit after moving to Tango instead of Phobos.
Lots of bugfixes...
This build is not suitable for most things.
author | lindquist |
---|---|
date | Fri, 11 Jan 2008 17:57:40 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tango/tango/text/Text.d Fri Jan 11 17:57:40 2008 +0100 @@ -0,0 +1,1396 @@ +/******************************************************************************* + + copyright: Copyright (c) 2005 Kris Bell. All rights reserved + + license: BSD style: $(LICENSE) + + version: Initial release: December 2005 + + author: Kris + + + _Text is a class for storing and manipulating Unicode characters. + + _Text maintains a current "selection", controlled via the mark(), + select() and selectPrior() methods. Each of append(), prepend(), + replace() and remove() operate with respect to the selection. The + select() methods operate with respect to the current selection + also, providing a means of iterating across matched patterns. To + set a selection across the entire content, use the mark() method + with no arguments. + + Indexes and lengths of content always count code units, not code + points. This is similar to traditional ascii string handling, yet + indexing is rarely used in practice due to the selection idiom: + substring indexing is generally implied as opposed to manipulated + directly. This allows for a more streamlined model with regard to + surrogates. + + Strings support a range of functionality, from insert and removal + to utf encoding and decoding. There is also an immutable subset + called TextView, intended to simplify life in a multi-threaded + environment. However, TextView must expose the raw content as + needed and thus immutability depends to an extent upon so-called + "honour" of a callee. D does not enable immutability enforcement + at this time, but this class will be modified to support such a + feature when it arrives - via the slice() method. + + The class is templated for use with char[], wchar[], and dchar[], + and should migrate across encodings seamlessly. In particular, all + functions in tango.text.Util are compatible with _Text content in + any of the supported encodings. In future, this class will become + the principal gateway to the extensive ICU unicode library. + + Note that several common text operations can be constructed through + combining tango.text._Text with tango.text.Util e.g. lines of text + can be processed thusly: + --- + auto source = new Text!(char)("one\ntwo\nthree"); + + foreach (line; Util.lines(source.slice)) + // do something with line + --- + + Substituting patterns within text can be implemented simply and + rather efficiently: + --- + auto dst = new Text!(char); + + foreach (element; Util.patterns ("all cows eat grass", "eat", "chew")) + dst.append (element); + --- + + Speaking a bit like Yoda might be accomplished as follows: + --- + auto dst = new Text!(char); + + foreach (element; Util.delims ("all cows eat grass", " ")) + dst.prepend (element); + --- + + Below is an overview of the API and class hierarchy: + --- + class Text(T) : TextView!(T) + { + // set or reset the content + Text set (T[] chars, bool mutable=true); + Text set (TextView other, bool mutable=true); + + // retreive currently selected text + T[] selection (); + + // get the index and length of the current selection + Span selectionSpan (); + + // mark a selection + Text select (int start=0, int length=int.max); + + // move the selection around + bool select (T c); + bool select (T[] pattern); + bool select (TextView other); + bool selectPrior (T c); + bool selectPrior (T[] pattern); + bool selectPrior (TextView other); + + // append behind current selection + Text append (TextView other); + Text append (T[] text); + Text append (T chr, int count=1); + Text append (int value, options); + Text append (long value, options); + Text append (double value, options); + + // transcode behind current selection + Text encode (char[]); + Text encode (wchar[]); + Text encode (dchar[]); + + // insert before current selection + Text prepend (T[] text); + Text prepend (TextView other); + Text prepend (T chr, int count=1); + + // replace current selection + Text replace (T chr); + Text replace (T[] text); + Text replace (TextView other); + + // remove current selection + Text remove (); + + // clear content + Text clear (); + + // trim leading and trailing whitespace + Text trim (); + + // trim leading and trailing chr instances + Text strip (T chr); + + // truncate at point, or current selection + Text truncate (int point = int.max); + + // reserve some space for inserts/additions + Text reserve (int extra); + } + + class TextView(T) : UniText + { + // hash content + hash_t toHash (); + + // return length of content + uint length (); + + // compare content + bool equals (T[] text); + bool equals (TextView other); + bool ends (T[] text); + bool ends (TextView other); + bool starts (T[] text); + bool starts (TextView other); + int compare (T[] text); + int compare (TextView other); + int opEquals (Object other); + int opCmp (Object other); + + // copy content + T[] copy (T[] dst); + + // return content + T[] slice (); + + // return data type + typeinfo encoding (); + + // replace the comparison algorithm + Comparator comparator (Comparator other); + } + + class UniText + { + // convert content + abstract char[] toString (char[] dst = null); + abstract wchar[] toString16 (wchar[] dst = null); + abstract dchar[] toString32 (dchar[] dst = null); + } + --- + +*******************************************************************************/ + +module tango.text.Text; + +private import Util = tango.text.Util; + +private import Utf = tango.text.convert.Utf; + +private import Float = tango.text.convert.Float; + +private import Integer = tango.text.convert.Integer; + +/******************************************************************************* + +*******************************************************************************/ + +private extern (C) void memmove (void* dst, void* src, uint bytes); + + +/******************************************************************************* + + The mutable Text class actually implements the full API, whereas + the superclasses are purely abstract (could be interfaces instead). + +*******************************************************************************/ + +class Text(T) : TextView!(T) +{ + public alias set opAssign; + public alias append opCatAssign; + private alias TextView!(T) TextViewT; + + private T[] content; + private bool mutable; + private Comparator comparator_; + private uint selectPoint, + selectLength, + contentLength; + + /*********************************************************************** + + Selection span + + ***********************************************************************/ + + public struct Span + { + uint begin, /// index of selection point + length; /// length of selection + } + + /*********************************************************************** + + Create an empty Text with the specified available + space + + ***********************************************************************/ + + this (uint space = 0) + { + content.length = space; + this.comparator_ = &simpleComparator; + } + + /*********************************************************************** + + Create a Text upon the provided content. If said + content is immutable (read-only) then you might consider + setting the 'copy' parameter to false. Doing so will + avoid allocating heap-space for the content until it is + modified via Text methods. This can be useful when + wrapping an array "temporarily" with a stack-based Text + + ***********************************************************************/ + + this (T[] content, bool copy = true) + { + set (content, copy); + this.comparator_ = &simpleComparator; + } + + /*********************************************************************** + + Create a Text via the content of another. If said + content is immutable (read-only) then you might consider + setting the 'copy' parameter to false. Doing so will avoid + allocating heap-space for the content until it is modified + via Text methods. This can be useful when wrapping an array + temporarily with a stack-based Text + + ***********************************************************************/ + + this (TextViewT other, bool copy = true) + { + this (other.slice, copy); + } + + /*********************************************************************** + + Set the content to the provided array. Parameter 'copy' + specifies whether the given array is likely to change. If + not, the array is aliased until such time it is altered via + this class. This can be useful when wrapping an array + "temporarily" with a stack-based Text + + ***********************************************************************/ + + final Text set (T[] chars, bool copy = true) + { + if ((this.mutable = copy) is true) + content = chars.dup; + else + content = chars; + + return select (0, contentLength = chars.length); + } + + /*********************************************************************** + + Replace the content of this Text. If the new content + is immutable (read-only) then you might consider setting the + 'copy' parameter to false. Doing so will avoid allocating + heap-space for the content until it is modified via one of + these methods. This can be useful when wrapping an array + "temporarily" with a stack-based Text + + ***********************************************************************/ + + final Text set (TextViewT other, bool copy = true) + { + return set (other.slice, copy); + } + + /*********************************************************************** + + Explicitly set the current selection + + ***********************************************************************/ + + final Text select (int start=0, int length=int.max) + { + pinIndices (start, length); + selectPoint = start; + selectLength = length; + return this; + } + + /*********************************************************************** + + Return the currently selected content + + ***********************************************************************/ + + final T[] selection () + { + return slice [selectPoint .. selectPoint+selectLength]; + } + + /*********************************************************************** + + Return the index and length of the current selection + + ***********************************************************************/ + + final Span selectionSpan () + { + Span span; + span.begin = selectPoint; + span.length = selectLength; + return span; + } + + /*********************************************************************** + + Find and select the next occurrence of a BMP code point + in a string. Returns true if found, false otherwise + + ***********************************************************************/ + + final bool select (T c) + { + auto s = slice(); + auto x = Util.locate (s, c, selectPoint); + if (x < s.length) + { + select (x, 1); + return true; + } + return false; + } + + /*********************************************************************** + + Find and select the next substring occurrence. Returns + true if found, false otherwise + + ***********************************************************************/ + + final bool select (TextViewT other) + { + return select (other.slice); + } + + /*********************************************************************** + + Find and select the next substring occurrence. Returns + true if found, false otherwise + + ***********************************************************************/ + + final bool select (T[] chars) + { + auto s = slice(); + auto x = Util.locatePattern (s, chars, selectPoint); + if (x < s.length) + { + select (x, chars.length); + return true; + } + return false; + } + + /*********************************************************************** + + Find and select a prior occurrence of a BMP code point + in a string. Returns true if found, false otherwise + + ***********************************************************************/ + + final bool selectPrior (T c) + { + auto s = slice(); + auto x = Util.locatePrior (s, c, selectPoint); + if (x < s.length) + { + select (x, 1); + return true; + } + return false; + } + + /*********************************************************************** + + Find and select a prior substring occurrence. Returns + true if found, false otherwise + + ***********************************************************************/ + + final bool selectPrior (TextViewT other) + { + return selectPrior (other.slice); + } + + /*********************************************************************** + + Find and select a prior substring occurrence. Returns + true if found, false otherwise + + ***********************************************************************/ + + final bool selectPrior (T[] chars) + { + auto s = slice(); + auto x = Util.locatePatternPrior (s, chars, selectPoint); + if (x < s.length) + { + select (x, chars.length); + return true; + } + return false; + } + + /*********************************************************************** + + Append text to this Text + + ***********************************************************************/ + + final Text append (TextViewT other) + { + return append (other.slice); + } + + /*********************************************************************** + + Append text to this Text + + ***********************************************************************/ + + final Text append (T[] chars) + { + return append (chars.ptr, chars.length); + } + + /*********************************************************************** + + Append a count of characters to this Text + + ***********************************************************************/ + + final Text append (T chr, int count=1) + { + uint point = selectPoint + selectLength; + expand (point, count); + return set (chr, point, count); + } + + /*********************************************************************** + + Append an integer to this Text + + ***********************************************************************/ + + final Text append (int v, Integer.Style fmt=Integer.Style.Signed) + { + return append (cast(long) v, fmt); + } + + /*********************************************************************** + + Append a long to this Text + + ***********************************************************************/ + + final Text append (long v, Integer.Style fmt=Integer.Style.Signed) + { + T[64] tmp = void; + return append (Integer.format(tmp, v, fmt)); + } + + /*********************************************************************** + + Append a double to this Text + + ***********************************************************************/ + + final Text append (double v, uint decimals=2, int e=10) + { + T[64] tmp = void; + return append (Float.format(tmp, v, decimals, e)); + } + + /*********************************************************************** + + Insert characters into this Text + + ***********************************************************************/ + + final Text prepend (T chr, int count=1) + { + expand (selectPoint, count); + return set (chr, selectPoint, count); + } + + /*********************************************************************** + + Insert text into this Text + + ***********************************************************************/ + + final Text prepend (T[] other) + { + expand (selectPoint, other.length); + content[selectPoint..selectPoint+other.length] = other; + return this; + } + + /*********************************************************************** + + Insert another Text into this Text + + ***********************************************************************/ + + final Text prepend (TextViewT other) + { + return prepend (other.slice); + } + + /*********************************************************************** + + Append encoded text at the current selection point. The text + is converted as necessary to the appropritate utf encoding. + + ***********************************************************************/ + + final Text encode (char[] s) + { + T[1024] tmp = void; + + static if (is (T == char)) + return append(s); + + static if (is (T == wchar)) + return append (Utf.toString16(s, tmp)); + + static if (is (T == dchar)) + return append (Utf.toString32(s, tmp)); + } + + /// ditto + final Text encode (wchar[] s) + { + T[1024] tmp = void; + + static if (is (T == char)) + return append (Utf.toString(s, tmp)); + + static if (is (T == wchar)) + return append (s); + + static if (is (T == dchar)) + return append (Utf.toString32(s, tmp)); + } + + /// ditto + final Text encode (dchar[] s) + { + T[1024] tmp = void; + + static if (is (T == char)) + return append (Utf.toString(s, tmp)); + + static if (is (T == wchar)) + return append (Utf.toString16(s, tmp)); + + static if (is (T == dchar)) + return append (s); + } + + /// ditto + final Text encode (Object o) + { + return encode (o.toString); + } + + /*********************************************************************** + + Replace a section of this Text with the specified + character + + ***********************************************************************/ + + final Text replace (T chr) + { + return set (chr, selectPoint, selectLength); + } + + /*********************************************************************** + + Replace a section of this Text with the specified + array + + ***********************************************************************/ + + final Text replace (T[] chars) + { + int chunk = chars.length - selectLength; + if (chunk >= 0) + expand (selectPoint, chunk); + else + remove (selectPoint, -chunk); + + content [selectPoint .. selectPoint+chars.length] = chars; + return select (selectPoint, chars.length); + } + + /*********************************************************************** + + Replace a section of this Text with another + + ***********************************************************************/ + + final Text replace (TextViewT other) + { + return replace (other.slice); + } + + /*********************************************************************** + + Remove the selection from this Text and reset the + selection to zero length + + ***********************************************************************/ + + final Text remove () + { + remove (selectPoint, selectLength); + return select (selectPoint, 0); + } + + /*********************************************************************** + + Remove the selection from this Text + + ***********************************************************************/ + + private Text remove (int start, int count) + { + pinIndices (start, count); + if (count > 0) + { + if (! mutable) + realloc (); + + uint i = start + count; + memmove (content.ptr+start, content.ptr+i, (contentLength-i) * T.sizeof); + contentLength -= count; + } + return this; + } + + /*********************************************************************** + + Truncate this string at an optional index. Default behaviour + is to truncate at the current append point. Current selection + is moved to the truncation point, with length 0 + + ***********************************************************************/ + + final Text truncate (int index = int.max) + { + if (index is int.max) + index = selectPoint + selectLength; + + pinIndex (index); + return select (contentLength = index, 0); + } + + /*********************************************************************** + + Clear the string content + + ***********************************************************************/ + + final Text clear () + { + return select (contentLength = 0, 0); + } + + /*********************************************************************** + + Remove leading and trailing whitespace from this Text, + and reset the selection to the trimmed content + + ***********************************************************************/ + + final Text trim () + { + content = Util.trim (slice); + select (0, contentLength = content.length); + return this; + } + + /*********************************************************************** + + Remove leading and trailing matches from this Text, + and reset the selection to the stripped content + + ***********************************************************************/ + + final Text strip (T matches) + { + content = Util.strip (slice, matches); + select (0, contentLength = content.length); + return this; + } + + /*********************************************************************** + + Reserve some extra room + + ***********************************************************************/ + + final Text reserve (uint extra) + { + realloc (extra); + return this; + } + + + + /* ======================== TextView methods ======================== */ + + + + /*********************************************************************** + + Get the encoding type + + ***********************************************************************/ + + final TypeInfo encoding() + { + return typeid(T); + } + + /*********************************************************************** + + Set the comparator delegate. Where other is null, we behave + as a getter only + + ***********************************************************************/ + + final Comparator comparator (Comparator other) + { + auto tmp = comparator_; + if (other) + comparator_ = other; + return tmp; + } + + /*********************************************************************** + + Hash this Text + + ***********************************************************************/ + + override hash_t toHash () + { + return Util.jhash (cast(ubyte*) content.ptr, contentLength * T.sizeof); + } + + /*********************************************************************** + + Return the length of the valid content + + ***********************************************************************/ + + final uint length () + { + return contentLength; + } + + /*********************************************************************** + + Is this Text equal to another? + + ***********************************************************************/ + + final bool equals (TextViewT other) + { + if (other is this) + return true; + return equals (other.slice); + } + + /*********************************************************************** + + Is this Text equal to the provided text? + + ***********************************************************************/ + + final bool equals (T[] other) + { + if (other.length == contentLength) + return Util.matching (other.ptr, content.ptr, contentLength); + return false; + } + + /*********************************************************************** + + Does this Text end with another? + + ***********************************************************************/ + + final bool ends (TextViewT other) + { + return ends (other.slice); + } + + /*********************************************************************** + + Does this Text end with the specified string? + + ***********************************************************************/ + + final bool ends (T[] chars) + { + if (chars.length <= contentLength) + return Util.matching (content.ptr+(contentLength-chars.length), chars.ptr, chars.length); + return false; + } + + /*********************************************************************** + + Does this Text start with another? + + ***********************************************************************/ + + final bool starts (TextViewT other) + { + return starts (other.slice); + } + + /*********************************************************************** + + Does this Text start with the specified string? + + ***********************************************************************/ + + final bool starts (T[] chars) + { + if (chars.length <= contentLength) + return Util.matching (content.ptr, chars.ptr, chars.length); + return false; + } + + /*********************************************************************** + + Compare this Text start with another. Returns 0 if the + content matches, less than zero if this Text is "less" + than the other, or greater than zero where this Text + is "bigger". + + ***********************************************************************/ + + final int compare (TextViewT other) + { + if (other is this) + return 0; + + return compare (other.slice); + } + + /*********************************************************************** + + Compare this Text start with an array. Returns 0 if the + content matches, less than zero if this Text is "less" + than the other, or greater than zero where this Text + is "bigger". + + ***********************************************************************/ + + final int compare (T[] chars) + { + return comparator_ (slice, chars); + } + + /*********************************************************************** + + Return content from this Text + + A slice of dst is returned, representing a copy of the + content. The slice is clipped to the minimum of either + the length of the provided array, or the length of the + content minus the stipulated start point + + ***********************************************************************/ + + final T[] copy (T[] dst) + { + uint i = contentLength; + if (i > dst.length) + i = dst.length; + + return dst [0 .. i] = content [0 .. i]; + } + + /*********************************************************************** + + Return an alias to the content of this TextView. Note + that you are bound by honour to leave this content wholly + unmolested. D surely needs some way to enforce immutability + upon array references + + ***********************************************************************/ + + final T[] slice () + { + return content [0 .. contentLength]; + } + + /*********************************************************************** + + Convert to the UniText types. The optional argument + dst will be resized as required to house the conversion. + To minimize heap allocation during subsequent conversions, + apply the following pattern: + --- + _Text string; + + wchar[] buffer; + wchar[] result = string.utf16 (buffer); + + if (result.length > buffer.length) + buffer = result; + --- + You can also provide a buffer from the stack, but the output + will be moved to the heap if said buffer is not large enough + + ***********************************************************************/ + + final char[] toString (char[] dst = null) + { + static if (is (T == char)) + return slice(); + + static if (is (T == wchar)) + return Utf.toString (slice, dst); + + static if (is (T == dchar)) + return Utf.toString (slice, dst); + } + + /// ditto + final wchar[] toString16 (wchar[] dst = null) + { + static if (is (T == char)) + return Utf.toString16 (slice, dst); + + static if (is (T == wchar)) + return slice; + + static if (is (T == dchar)) + return Utf.toString16 (slice, dst); + } + + /// ditto + final dchar[] toString32 (dchar[] dst = null) + { + static if (is (T == char)) + return Utf.toString32 (slice, dst); + + static if (is (T == wchar)) + return Utf.toString32 (slice, dst); + + static if (is (T == dchar)) + return slice; + } + + /*********************************************************************** + + Compare this Text to another. We compare against other + Strings only. Literals and other objects are not supported + + ***********************************************************************/ + + override int opCmp (Object o) + { + auto other = cast (TextViewT) o; + + if (other is null) + return -1; + + return compare (other); + } + + /*********************************************************************** + + Is this Text equal to the text of something else? + + ***********************************************************************/ + + override int opEquals (Object o) + { + auto other = cast (TextViewT) o; + + if (other) + return equals (other); + + // this can become expensive ... + char[1024] tmp = void; + return this.toString(tmp) == o.toString; + } + + /// ditto + final int opEquals (T[] s) + { + return slice == s; + } + + /*********************************************************************** + + Pin the given index to a valid position. + + ***********************************************************************/ + + private void pinIndex (inout int x) + { + if (x > contentLength) + x = contentLength; + } + + /*********************************************************************** + + Pin the given index and length to a valid position. + + ***********************************************************************/ + + private void pinIndices (inout int start, inout int length) + { + if (start > contentLength) + start = contentLength; + + if (length > (contentLength - start)) + length = contentLength - start; + } + + /*********************************************************************** + + Compare two arrays. Returns 0 if the content matches, less + than zero if A is "less" than B, or greater than zero where + A is "bigger". Where the substrings match, the shorter is + considered "less". + + ***********************************************************************/ + + private int simpleComparator (T[] a, T[] b) + { + uint i = a.length; + if (b.length < i) + i = b.length; + + for (int j, k; j < i; ++j) + if ((k = a[j] - b[j]) != 0) + return k; + + return a.length - b.length; + } + + /*********************************************************************** + + Make room available to insert or append something + + ***********************************************************************/ + + private void expand (uint index, uint count) + { + if (!mutable || (contentLength + count) > content.length) + realloc (count); + + memmove (content.ptr+index+count, content.ptr+index, (contentLength - index) * T.sizeof); + selectLength += count; + contentLength += count; + } + + /*********************************************************************** + + Replace a section of this Text with the specified + character + + ***********************************************************************/ + + private Text set (T chr, uint start, uint count) + { + content [start..start+count] = chr; + return this; + } + + /*********************************************************************** + + Allocate memory due to a change in the content. We handle + the distinction between mutable and immutable here. + + ***********************************************************************/ + + private void realloc (uint count = 0) + { + uint size = (content.length + count + 127) & ~127; + + if (mutable) + content.length = size; + else + { + mutable = true; + T[] x = content; + content = new T[size]; + if (contentLength) + content[0..contentLength] = x; + } + } + + /*********************************************************************** + + Internal method to support Text appending + + ***********************************************************************/ + + private Text append (T* chars, uint count) + { + uint point = selectPoint + selectLength; + expand (point, count); + content[point .. point+count] = chars[0 .. count]; + return this; + } +} + + + +/******************************************************************************* + + Immutable string + +*******************************************************************************/ + +class TextView(T) : UniText +{ + public typedef int delegate (T[] a, T[] b) Comparator; + + /*********************************************************************** + + Return the length of the valid content + + ***********************************************************************/ + + abstract uint length (); + + /*********************************************************************** + + Is this Text equal to another? + + ***********************************************************************/ + + abstract bool equals (TextView other); + + /*********************************************************************** + + Is this Text equal to the the provided text? + + ***********************************************************************/ + + abstract bool equals (T[] other); + + /*********************************************************************** + + Does this Text end with another? + + ***********************************************************************/ + + abstract bool ends (TextView other); + + /*********************************************************************** + + Does this Text end with the specified string? + + ***********************************************************************/ + + abstract bool ends (T[] chars); + + /*********************************************************************** + + Does this Text start with another? + + ***********************************************************************/ + + abstract bool starts (TextView other); + + /*********************************************************************** + + Does this Text start with the specified string? + + ***********************************************************************/ + + abstract bool starts (T[] chars); + + /*********************************************************************** + + Compare this Text start with another. Returns 0 if the + content matches, less than zero if this Text is "less" + than the other, or greater than zero where this Text + is "bigger". + + ***********************************************************************/ + + abstract int compare (TextView other); + + /*********************************************************************** + + Compare this Text start with an array. Returns 0 if the + content matches, less than zero if this Text is "less" + than the other, or greater than zero where this Text + is "bigger". + + ***********************************************************************/ + + abstract int compare (T[] chars); + + /*********************************************************************** + + Return content from this Text. A slice of dst is + returned, representing a copy of the content. The + slice is clipped to the minimum of either the length + of the provided array, or the length of the content + minus the stipulated start point + + ***********************************************************************/ + + abstract T[] copy (T[] dst); + + /*********************************************************************** + + Compare this Text to another + + ***********************************************************************/ + + abstract int opCmp (Object o); + + /*********************************************************************** + + Is this Text equal to another? + + ***********************************************************************/ + + abstract int opEquals (Object other); + + /*********************************************************************** + + Is this Text equal to another? + + ***********************************************************************/ + + abstract int opEquals (T[] other); + + /*********************************************************************** + + Get the encoding type + + ***********************************************************************/ + + abstract TypeInfo encoding(); + + /*********************************************************************** + + Set the comparator delegate + + ***********************************************************************/ + + abstract Comparator comparator (Comparator other); + + /*********************************************************************** + + Hash this Text + + ***********************************************************************/ + + abstract hash_t toHash (); + + /*********************************************************************** + + Return an alias to the content of this TextView. Note + that you are bound by honour to leave this content wholly + unmolested. D surely needs some way to enforce immutability + upon array references + + ***********************************************************************/ + + abstract T[] slice (); +} + + +/******************************************************************************* + + A string abstraction that converts to anything + +*******************************************************************************/ + +class UniText +{ + abstract char[] toString (char[] dst = null); + + abstract wchar[] toString16 (wchar[] dst = null); + + abstract dchar[] toString32 (dchar[] dst = null); + + abstract TypeInfo encoding(); +} + + + +/******************************************************************************* + +*******************************************************************************/ + +debug (UnitTest) +{ + //void main() {} + unittest + { + auto s = new Text!(char); + s = "hello"; + + s.select ("hello"); + assert (s.selection == "hello"); + s.replace ("1"); + assert (s.selection == "1"); + assert (s == "1"); + + assert (s.clear == ""); + + assert (s.append(12345) == "12345"); + assert (s.selection == "12345"); + + //s.append ("fubar"); + s ~= "fubar"; + assert (s.selection == "12345fubar"); + assert (s.select('5')); + assert (s.selection == "5"); + assert (s.remove == "1234fubar"); + assert (s.select("fubar")); + assert (s.selection == "fubar"); + assert (s.select("wumpus") is false); + assert (s.selection == "fubar"); + + assert (s.clear.append(1.2345, 4) == "1.2345"); + + assert (s.clear.append(0xf0, Integer.Style.Binary) == "11110000"); + + assert (s.clear.encode("one"d).toString == "one"); + + assert (Util.splitLines(s.clear.append("a\nb").slice).length is 2); + + assert (s.select.replace("almost ") == "almost "); + foreach (element; Util.patterns ("all cows eat grass", "eat", "chew")) + s.append (element); + assert (s.selection == "almost all cows chew grass"); + } +}