first commit
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace ICSharpCode.TextEditor.Document
|
||||
{
|
||||
public class GapTextBufferStrategy : ITextBufferStrategy
|
||||
{
|
||||
#if DEBUG
|
||||
int creatorThread = System.Threading.Thread.CurrentThread.ManagedThreadId;
|
||||
|
||||
void CheckThread()
|
||||
{
|
||||
if (System.Threading.Thread.CurrentThread.ManagedThreadId != creatorThread)
|
||||
throw new InvalidOperationException("GapTextBufferStategy is not thread-safe!");
|
||||
}
|
||||
#endif
|
||||
|
||||
char[] buffer = new char[0];
|
||||
string cachedContent;
|
||||
|
||||
int gapBeginOffset = 0;
|
||||
int gapEndOffset = 0;
|
||||
int gapLength = 0; // gapLength == gapEndOffset - gapBeginOffset
|
||||
|
||||
const int minGapLength = 128;
|
||||
const int maxGapLength = 2048;
|
||||
|
||||
public int Length {
|
||||
get {
|
||||
return buffer.Length - gapLength;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetContent(string text)
|
||||
{
|
||||
if (text == null) {
|
||||
text = string.Empty;
|
||||
}
|
||||
cachedContent = text;
|
||||
buffer = text.ToCharArray();
|
||||
gapBeginOffset = gapEndOffset = gapLength = 0;
|
||||
}
|
||||
|
||||
public char GetCharAt(int offset)
|
||||
{
|
||||
#if DEBUG
|
||||
CheckThread();
|
||||
#endif
|
||||
|
||||
if (offset < 0 || offset >= Length) {
|
||||
throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset < " + Length.ToString());
|
||||
}
|
||||
|
||||
return offset < gapBeginOffset ? buffer[offset] : buffer[offset + gapLength];
|
||||
}
|
||||
|
||||
public string GetText(int offset, int length)
|
||||
{
|
||||
#if DEBUG
|
||||
CheckThread();
|
||||
#endif
|
||||
|
||||
if (offset < 0 || offset > Length) {
|
||||
throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset <= " + Length.ToString());
|
||||
}
|
||||
if (length < 0 || offset + length > Length) {
|
||||
throw new ArgumentOutOfRangeException("length", length, "0 <= length, offset(" + offset + ")+length <= " + Length.ToString());
|
||||
}
|
||||
if (offset == 0 && length == Length) {
|
||||
if (cachedContent != null)
|
||||
return cachedContent;
|
||||
else
|
||||
return cachedContent = GetTextInternal(offset, length);
|
||||
} else {
|
||||
return GetTextInternal(offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
string GetTextInternal(int offset, int length)
|
||||
{
|
||||
int end = offset + length;
|
||||
|
||||
if (end < gapBeginOffset) {
|
||||
return new string(buffer, offset, length);
|
||||
}
|
||||
|
||||
if (offset > gapBeginOffset) {
|
||||
return new string(buffer, offset + gapLength, length);
|
||||
}
|
||||
|
||||
int block1Size = gapBeginOffset - offset;
|
||||
int block2Size = end - gapBeginOffset;
|
||||
|
||||
StringBuilder buf = new StringBuilder(block1Size + block2Size);
|
||||
buf.Append(buffer, offset, block1Size);
|
||||
buf.Append(buffer, gapEndOffset, block2Size);
|
||||
return buf.ToString();
|
||||
}
|
||||
|
||||
public void Insert(int offset, string text)
|
||||
{
|
||||
Replace(offset, 0, text);
|
||||
}
|
||||
|
||||
public void Remove(int offset, int length)
|
||||
{
|
||||
Replace(offset, length, string.Empty);
|
||||
}
|
||||
|
||||
public void Replace(int offset, int length, string text)
|
||||
{
|
||||
if (text == null) {
|
||||
text = string.Empty;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
CheckThread();
|
||||
#endif
|
||||
|
||||
if (offset < 0 || offset > Length) {
|
||||
throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset <= " + Length.ToString());
|
||||
}
|
||||
if (length < 0 || offset + length > Length) {
|
||||
throw new ArgumentOutOfRangeException("length", length, "0 <= length, offset+length <= " + Length.ToString());
|
||||
}
|
||||
|
||||
cachedContent = null;
|
||||
|
||||
// Math.Max is used so that if we need to resize the array
|
||||
// the new array has enough space for all old chars
|
||||
PlaceGap(offset, text.Length - length);
|
||||
gapEndOffset += length; // delete removed text
|
||||
text.CopyTo(0, buffer, gapBeginOffset, text.Length);
|
||||
gapBeginOffset += text.Length;
|
||||
gapLength = gapEndOffset - gapBeginOffset;
|
||||
if (gapLength > maxGapLength) {
|
||||
MakeNewBuffer(gapBeginOffset, minGapLength);
|
||||
}
|
||||
}
|
||||
|
||||
void PlaceGap(int newGapOffset, int minRequiredGapLength)
|
||||
{
|
||||
if (gapLength < minRequiredGapLength) {
|
||||
// enlarge gap
|
||||
MakeNewBuffer(newGapOffset, minRequiredGapLength);
|
||||
} else {
|
||||
while (newGapOffset < gapBeginOffset) {
|
||||
buffer[--gapEndOffset] = buffer[--gapBeginOffset];
|
||||
}
|
||||
while (newGapOffset > gapBeginOffset) {
|
||||
buffer[gapBeginOffset++] = buffer[gapEndOffset++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MakeNewBuffer(int newGapOffset, int newGapLength)
|
||||
{
|
||||
if (newGapLength < minGapLength) newGapLength = minGapLength;
|
||||
|
||||
char[] newBuffer = new char[Length + newGapLength];
|
||||
if (newGapOffset < gapBeginOffset) {
|
||||
// gap is moving backwards
|
||||
|
||||
// first part:
|
||||
Array.Copy(buffer, 0, newBuffer, 0, newGapOffset);
|
||||
// moving middle part:
|
||||
Array.Copy(buffer, newGapOffset, newBuffer, newGapOffset + newGapLength, gapBeginOffset - newGapOffset);
|
||||
// last part:
|
||||
Array.Copy(buffer, gapEndOffset, newBuffer, newBuffer.Length - (buffer.Length - gapEndOffset), buffer.Length - gapEndOffset);
|
||||
} else {
|
||||
// gap is moving forwards
|
||||
// first part:
|
||||
Array.Copy(buffer, 0, newBuffer, 0, gapBeginOffset);
|
||||
// moving middle part:
|
||||
Array.Copy(buffer, gapEndOffset, newBuffer, gapBeginOffset, newGapOffset - gapBeginOffset);
|
||||
// last part:
|
||||
int lastPartLength = newBuffer.Length - (newGapOffset + newGapLength);
|
||||
Array.Copy(buffer, buffer.Length - lastPartLength, newBuffer, newGapOffset + newGapLength, lastPartLength);
|
||||
}
|
||||
|
||||
gapBeginOffset = newGapOffset;
|
||||
gapEndOffset = newGapOffset + newGapLength;
|
||||
gapLength = newGapLength;
|
||||
buffer = newBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
namespace ICSharpCode.TextEditor.Document
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface to describe a sequence of characters that can be edited.
|
||||
/// </summary>
|
||||
public interface ITextBufferStrategy
|
||||
{
|
||||
/// <value>
|
||||
/// The current length of the sequence of characters that can be edited.
|
||||
/// </value>
|
||||
int Length {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a string of characters into the sequence.
|
||||
/// </summary>
|
||||
/// <param name="offset">
|
||||
/// offset where to insert the string.
|
||||
/// </param>
|
||||
/// <param name="text">
|
||||
/// text to be inserted.
|
||||
/// </param>
|
||||
void Insert(int offset, string text);
|
||||
|
||||
/// <summary>
|
||||
/// Removes some portion of the sequence.
|
||||
/// </summary>
|
||||
/// <param name="offset">
|
||||
/// offset of the remove.
|
||||
/// </param>
|
||||
/// <param name="length">
|
||||
/// number of characters to remove.
|
||||
/// </param>
|
||||
void Remove(int offset, int length);
|
||||
|
||||
/// <summary>
|
||||
/// Replace some portion of the sequence.
|
||||
/// </summary>
|
||||
/// <param name="offset">
|
||||
/// offset.
|
||||
/// </param>
|
||||
/// <param name="length">
|
||||
/// number of characters to replace.
|
||||
/// </param>
|
||||
/// <param name="text">
|
||||
/// text to be replaced with.
|
||||
/// </param>
|
||||
void Replace(int offset, int length, string text);
|
||||
|
||||
/// <summary>
|
||||
/// Fetches a string of characters contained in the sequence.
|
||||
/// </summary>
|
||||
/// <param name="offset">
|
||||
/// Offset into the sequence to fetch
|
||||
/// </param>
|
||||
/// <param name="length">
|
||||
/// number of characters to copy.
|
||||
/// </param>
|
||||
string GetText(int offset, int length);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a specific char of the sequence.
|
||||
/// </summary>
|
||||
/// <param name="offset">
|
||||
/// Offset of the char to get.
|
||||
/// </param>
|
||||
char GetCharAt(int offset);
|
||||
|
||||
/// <summary>
|
||||
/// This method sets the stored content.
|
||||
/// </summary>
|
||||
/// <param name="text">
|
||||
/// The string that represents the character sequence.
|
||||
/// </param>
|
||||
void SetContent(string text);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace ICSharpCode.TextEditor.Document
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple implementation of the ITextBuffer interface implemented using a
|
||||
/// string.
|
||||
/// Only for fall-back purposes.
|
||||
/// </summary>
|
||||
public class StringTextBufferStrategy : ITextBufferStrategy
|
||||
{
|
||||
string storedText = "";
|
||||
|
||||
public int Length {
|
||||
get {
|
||||
return storedText.Length;
|
||||
}
|
||||
}
|
||||
|
||||
public void Insert(int offset, string text)
|
||||
{
|
||||
if (text != null) {
|
||||
storedText = storedText.Insert(offset, text);
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(int offset, int length)
|
||||
{
|
||||
storedText = storedText.Remove(offset, length);
|
||||
}
|
||||
|
||||
public void Replace(int offset, int length, string text)
|
||||
{
|
||||
Remove(offset, length);
|
||||
Insert(offset, text);
|
||||
}
|
||||
|
||||
public string GetText(int offset, int length)
|
||||
{
|
||||
if (length == 0) {
|
||||
return "";
|
||||
}
|
||||
if (offset == 0 && length >= storedText.Length) {
|
||||
return storedText;
|
||||
}
|
||||
return storedText.Substring(offset, Math.Min(length, storedText.Length - offset));
|
||||
}
|
||||
|
||||
public char GetCharAt(int offset)
|
||||
{
|
||||
if (offset == Length) {
|
||||
return '\0';
|
||||
}
|
||||
return storedText[offset];
|
||||
}
|
||||
|
||||
public void SetContent(string text)
|
||||
{
|
||||
storedText = text;
|
||||
}
|
||||
|
||||
public StringTextBufferStrategy()
|
||||
{
|
||||
}
|
||||
|
||||
public static ITextBufferStrategy CreateTextBufferFromFile(string fileName)
|
||||
{
|
||||
if (!File.Exists(fileName)) {
|
||||
throw new System.IO.FileNotFoundException(fileName);
|
||||
}
|
||||
StringTextBufferStrategy s = new StringTextBufferStrategy();
|
||||
s.SetContent(Util.FileReader.ReadFileContent(fileName, Encoding.Default));
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user