diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/ICSharpCode.TextEditor.csproj b/src/Libraries/ICSharpCode.TextEditor/Project/ICSharpCode.TextEditor.csproj
index 2c081df7a8..b067093c9c 100644
--- a/src/Libraries/ICSharpCode.TextEditor/Project/ICSharpCode.TextEditor.csproj
+++ b/src/Libraries/ICSharpCode.TextEditor/Project/ICSharpCode.TextEditor.csproj
@@ -60,6 +60,7 @@
+
@@ -207,6 +208,7 @@
Configuration\GlobalAssemblyInfo.cs
+
diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/DefaultTextEditorProperties.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/DefaultTextEditorProperties.cs
index 04ff6d8179..4d7a7d59a1 100644
--- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/DefaultTextEditorProperties.cs
+++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/DefaultTextEditorProperties.cs
@@ -40,13 +40,13 @@ namespace ICSharpCode.TextEditor.Document
bool showMatchingBracket = true;
bool showLineNumbers = true;
- bool showSpaces = true;
- bool showTabs = true;
- bool showEOLMarker = true;
+ bool showSpaces = false;
+ bool showTabs = false;
+ bool showEOLMarker = false;
- bool showInvalidLines = true;
+ bool showInvalidLines = false;
- bool isIconBarVisible = true;
+ bool isIconBarVisible = false;
bool enableFolding = true;
bool showHorizontalRuler = false;
bool showVerticalRuler = true;
diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/DefaultHighlightingStrategy.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/DefaultHighlightingStrategy.cs
index c47b7eddbc..3e8f6e4be9 100644
--- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/DefaultHighlightingStrategy.cs
+++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/DefaultHighlightingStrategy.cs
@@ -7,6 +7,7 @@
using System;
using System.Collections.Generic;
+using System.Text;
using System.Drawing;
using System.Windows.Forms;
@@ -620,9 +621,9 @@ namespace ICSharpCode.TextEditor.Document
// Check for SPAN ENDs
if (inSpan) {
if (activeSpan.End != null && activeSpan.End.Length > 0) {
- if (currentLine.MatchExpr(activeSpan.End, i, document, activeSpan.IgnoreCase)) {
+ if (MatchExpr(currentLine, activeSpan.End, i, document, activeSpan.IgnoreCase)) {
PushCurWord(document, ref markNext, words);
- string regex = currentLine.GetRegString(activeSpan.End, i, document);
+ string regex = GetRegString(currentLine, activeSpan.End, i, document);
currentLength += regex.Length;
words.Add(new TextWord(document, currentLine, currentOffset, currentLength, activeSpan.EndColor, false));
currentOffset += currentLength;
@@ -640,9 +641,9 @@ namespace ICSharpCode.TextEditor.Document
foreach (Span span in activeRuleSet.Spans) {
if ((!span.IsBeginSingleWord || currentLength == 0)
&& (!span.IsBeginStartOfLine.HasValue || span.IsBeginStartOfLine.Value == (currentLength == 0 && words.TrueForAll(delegate(TextWord textWord) { return textWord.Type != TextWordType.Word; })))
- && currentLine.MatchExpr(span.Begin, i, document, activeRuleSet.IgnoreCase)) {
+ && MatchExpr(currentLine, span.Begin, i, document, activeRuleSet.IgnoreCase)) {
PushCurWord(document, ref markNext, words);
- string regex = currentLine.GetRegString(span.Begin, i, document);
+ string regex = GetRegString(currentLine, span.Begin, i, document);
if (!OverrideSpan(regex, document, words, span, ref i)) {
currentLength += regex.Length;
@@ -768,5 +769,138 @@ namespace ICSharpCode.TextEditor.Document
currentLength = 0;
}
}
+
+ #region Matching
+ ///
+ /// get the string, which matches the regular expression expr,
+ /// in string s2 at index
+ ///
+ static string GetRegString(LineSegment lineSegment, char[] expr, int index, IDocument document)
+ {
+ int j = 0;
+ StringBuilder regexpr = new StringBuilder();
+
+ for (int i = 0; i < expr.Length; ++i, ++j) {
+ if (index + j >= lineSegment.Length)
+ break;
+
+ switch (expr[i]) {
+ case '@': // "special" meaning
+ ++i;
+ switch (expr[i]) {
+ case '!': // don't match the following expression
+ StringBuilder whatmatch = new StringBuilder();
+ ++i;
+ while (i < expr.Length && expr[i] != '@') {
+ whatmatch.Append(expr[i++]);
+ }
+ break;
+ case '@': // matches @
+ regexpr.Append(document.GetCharAt(lineSegment.Offset + index + j));
+ break;
+ }
+ break;
+ default:
+ if (expr[i] != document.GetCharAt(lineSegment.Offset + index + j)) {
+ return regexpr.ToString();
+ }
+ regexpr.Append(document.GetCharAt(lineSegment.Offset + index + j));
+ break;
+ }
+ }
+ return regexpr.ToString();
+ }
+
+ ///
+ /// returns true, if the get the string s2 at index matches the expression expr
+ ///
+ static bool MatchExpr(LineSegment lineSegment, char[] expr, int index, IDocument document, bool ignoreCase)
+ {
+ for (int i = 0, j = 0; i < expr.Length; ++i, ++j) {
+ switch (expr[i]) {
+ case '@': // "special" meaning
+ ++i;
+ if (i < expr.Length) {
+ switch (expr[i]) {
+ case 'C': // match whitespace or punctuation
+ if (index + j == lineSegment.Offset || index + j >= lineSegment.Offset + lineSegment.Length) {
+ // nothing (EOL or SOL)
+ } else {
+ char ch = document.GetCharAt(lineSegment.Offset + index + j);
+ if (!Char.IsWhiteSpace(ch) && !Char.IsPunctuation(ch)) {
+ return false;
+ }
+ }
+ break;
+ case '!': // don't match the following expression
+ {
+ StringBuilder whatmatch = new StringBuilder();
+ ++i;
+ while (i < expr.Length && expr[i] != '@') {
+ whatmatch.Append(expr[i++]);
+ }
+ if (lineSegment.Offset + index + j + whatmatch.Length < document.TextLength) {
+ int k = 0;
+ for (; k < whatmatch.Length; ++k) {
+ char docChar = ignoreCase ? Char.ToUpperInvariant(document.GetCharAt(lineSegment.Offset + index + j + k)) : document.GetCharAt(lineSegment.Offset + index + j + k);
+ char spanChar = ignoreCase ? Char.ToUpperInvariant(whatmatch[k]) : whatmatch[k];
+ if (docChar != spanChar) {
+ break;
+ }
+ }
+ if (k >= whatmatch.Length) {
+ return false;
+ }
+ }
+// --j;
+ break;
+ }
+ case '-': // don't match the expression before
+ {
+ StringBuilder whatmatch = new StringBuilder();
+ ++i;
+ while (i < expr.Length && expr[i] != '@') {
+ whatmatch.Append(expr[i++]);
+ }
+ if (index - whatmatch.Length >= 0) {
+ int k = 0;
+ for (; k < whatmatch.Length; ++k) {
+ char docChar = ignoreCase ? Char.ToUpperInvariant(document.GetCharAt(lineSegment.Offset + index - whatmatch.Length + k)) : document.GetCharAt(lineSegment.Offset + index - whatmatch.Length + k);
+ char spanChar = ignoreCase ? Char.ToUpperInvariant(whatmatch[k]) : whatmatch[k];
+ if (docChar != spanChar)
+ break;
+ }
+ if (k >= whatmatch.Length) {
+ return false;
+ }
+ }
+// --j;
+ break;
+ }
+ case '@': // matches @
+ if (index + j >= lineSegment.Length || '@' != document.GetCharAt(lineSegment.Offset + index + j)) {
+ return false;
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ {
+ if (index + j >= lineSegment.Length) {
+ return false;
+ }
+ char docChar = ignoreCase ? Char.ToUpperInvariant(document.GetCharAt(lineSegment.Offset + index + j)) : document.GetCharAt(lineSegment.Offset + index + j);
+ char spanChar = ignoreCase ? Char.ToUpperInvariant(expr[i]) : expr[i];
+ if (docChar != spanChar) {
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ return true;
+ }
+ #endregion
}
}
diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/LineManager/DefaultLineManager.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/LineManager/DefaultLineManager.cs
index d658b7bba9..c061c4047c 100644
--- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/LineManager/DefaultLineManager.cs
+++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/LineManager/DefaultLineManager.cs
@@ -77,7 +77,7 @@ namespace ICSharpCode.TextEditor.Document
public void Replace(int offset, int length, string text)
{
-// Console.WriteLine("Replace offset="+offset+" length="+length+" text.Length="+text.Length);
+ Console.WriteLine("Replace offset="+offset+" length="+length+" text.Length="+text.Length);
int lineStart = GetLineNumberForOffset(offset);
int oldNumberOfLines = this.TotalNumberOfLines;
RemoveInternal(offset, length);
@@ -106,6 +106,7 @@ namespace ICSharpCode.TextEditor.Document
int startSegmentOffset = startSegment.Offset;
if (offset + length < startSegmentOffset + startSegment.TotalLength) {
// just removing a part of this line segment
+ startSegment.RemovedLinePart(offset - startSegmentOffset, length);
SetSegmentLength(startSegment, startSegment.TotalLength - length);
return;
}
@@ -113,6 +114,7 @@ namespace ICSharpCode.TextEditor.Document
// possibly remove lines in between if multiple delimiters were deleted
int charactersRemovedInStartLine = startSegmentOffset + startSegment.TotalLength - offset;
Debug.Assert(charactersRemovedInStartLine > 0);
+ startSegment.RemovedLinePart(offset - startSegmentOffset, charactersRemovedInStartLine);
LineSegment endSegment = lineCollection.GetByOffset(offset + length);
@@ -124,6 +126,8 @@ namespace ICSharpCode.TextEditor.Document
}
int endSegmentOffset = endSegment.Offset;
int charactersLeftInEndLine = endSegmentOffset + endSegment.TotalLength - (offset + length);
+ endSegment.RemovedLinePart(0, endSegment.TotalLength - charactersLeftInEndLine);
+ startSegment.MergedWith(endSegment, offset - startSegmentOffset);
SetSegmentLength(startSegment, startSegment.TotalLength - charactersRemovedInStartLine + charactersLeftInEndLine);
startSegment.DelimiterLength = endSegment.DelimiterLength;
// remove all segments between startSegment (excl.) and endSegment (incl.)
@@ -132,6 +136,7 @@ namespace ICSharpCode.TextEditor.Document
do {
segmentToRemove = it.Current;
it.MoveNext();
+ segmentToRemove.Deleted();
lineCollection.RemoveSegment(segmentToRemove);
} while (segmentToRemove != endSegment);
}
@@ -139,9 +144,17 @@ namespace ICSharpCode.TextEditor.Document
void InsertInternal(int offset, string text)
{
LineSegment segment = lineCollection.GetByOffset(offset);
+ DelimiterSegment ds = NextDelimiter(text, 0);
+ if (ds == null) {
+ // no newline is being inserted, all text is inserted in a single line
+ segment.InsertedLinePart(offset - segment.Offset, text.Length);
+ SetSegmentLength(segment, segment.TotalLength + text.Length);
+ return;
+ }
+ LineSegment firstLine = segment;
+ firstLine.InsertedLinePart(offset - firstLine.Offset, ds.Offset);
int lastDelimiterEnd = 0;
- DelimiterSegment ds;
- while ((ds = NextDelimiter(text, lastDelimiterEnd)) != null) {
+ while (ds != null) {
// split line segment at line delimiter
int lineBreakOffset = offset + ds.Offset + ds.Length;
int segmentOffset = segment.Offset;
@@ -152,9 +165,13 @@ namespace ICSharpCode.TextEditor.Document
segment = newSegment;
lastDelimiterEnd = ds.Offset + ds.Length;
+
+ ds = NextDelimiter(text, lastDelimiterEnd);
}
+ firstLine.SplitTo(segment);
// insert rest after last delimiter
if (lastDelimiterEnd != text.Length) {
+ segment.InsertedLinePart(0, text.Length - lastDelimiterEnd);
SetSegmentLength(segment, segment.TotalLength + text.Length - lastDelimiterEnd);
}
}
diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/LineManager/LineSegment.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/LineManager/LineSegment.cs
index 4199407dc1..caa55067b6 100644
--- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/LineManager/LineSegment.cs
+++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/LineManager/LineSegment.cs
@@ -8,6 +8,7 @@
using System;
using System.Collections.Generic;
using System.Drawing;
+using System.Diagnostics;
using System.Text;
namespace ICSharpCode.TextEditor.Document
@@ -32,6 +33,10 @@ namespace ICSharpCode.TextEditor.Document
return null;
}
+ public bool IsDeleted {
+ get { return !treeEntry.IsValid; }
+ }
+
public int LineNumber {
get { return treeEntry.CurrentIndex; }
}
@@ -60,7 +65,7 @@ namespace ICSharpCode.TextEditor.Document
public int DelimiterLength {
get { return delimiterLength; }
- set { delimiterLength = value; }
+ internal set { delimiterLength = value; }
}
// highlighting information
@@ -104,137 +109,140 @@ namespace ICSharpCode.TextEditor.Document
return "[LineSegment: Offset = "+ Offset +", Length = " + Length + ", TotalLength = " + TotalLength + ", DelimiterLength = " + delimiterLength + "]";
}
- // Svante Lidman: reconsider whether it was the right descision to move these methids here.
+ #region Anchor management
+ Util.WeakCollection anchors;
+
+ public TextAnchor CreateAnchor(int column)
+ {
+ TextAnchor anchor = new TextAnchor(this, column);
+ AddAnchor(anchor);
+ return anchor;
+ }
+
+ void AddAnchor(TextAnchor anchor)
+ {
+ Debug.Assert(anchor.Line == this);
+
+ if (anchors == null)
+ anchors = new Util.WeakCollection();
+
+ anchors.Add(anchor);
+ }
+
+ ///
+ /// Is called when the LineSegment is deleted.
+ ///
+ internal void Deleted()
+ {
+ //Console.WriteLine("Deleted");
+ treeEntry = LineSegmentTree.Enumerator.Invalid;
+ if (anchors != null) {
+ foreach (TextAnchor a in anchors) {
+ a.Deleted();
+ }
+ anchors = null;
+ }
+ }
///
- /// get the string, which matches the regular expression expr,
- /// in string s2 at index
+ /// Is called when a part of the line is removed.
///
- internal string GetRegString(char[] expr, int index, IDocument document)
+ internal void RemovedLinePart(int startColumn, int length)
{
- int j = 0;
- StringBuilder regexpr = new StringBuilder();;
+ if (length == 0)
+ return;
+ Debug.Assert(length > 0);
- for (int i = 0; i < expr.Length; ++i, ++j) {
- if (index + j >= this.Length)
- break;
-
- switch (expr[i]) {
- case '@': // "special" meaning
- ++i;
- switch (expr[i]) {
- case '!': // don't match the following expression
- StringBuilder whatmatch = new StringBuilder();
- ++i;
- while (i < expr.Length && expr[i] != '@') {
- whatmatch.Append(expr[i++]);
- }
- break;
- case '@': // matches @
- regexpr.Append(document.GetCharAt(this.Offset + index + j));
- break;
+ //Console.WriteLine("RemovedLinePart " + startColumn + ", " + length);
+ if (anchors != null) {
+ List deletedAnchors = null;
+ foreach (TextAnchor a in anchors) {
+ if (a.ColumnNumber > startColumn) {
+ if (a.ColumnNumber >= startColumn + length) {
+ a.ColumnNumber -= length;
+ } else {
+ if (deletedAnchors == null)
+ deletedAnchors = new List();
+ a.Deleted();
+ deletedAnchors.Add(a);
}
- break;
- default:
- if (expr[i] != document.GetCharAt(this.Offset + index + j)) {
- return regexpr.ToString();
- }
- regexpr.Append(document.GetCharAt(this.Offset + index + j));
- break;
+ }
+ }
+ if (deletedAnchors != null) {
+ foreach (TextAnchor a in deletedAnchors) {
+ anchors.Remove(a);
+ }
}
}
- return regexpr.ToString();
}
///
- /// returns true, if the get the string s2 at index matches the expression expr
+ /// Is called when a part of the line is inserted.
///
- internal bool MatchExpr(char[] expr, int index, IDocument document, bool ignoreCase)
+ internal void InsertedLinePart(int startColumn, int length)
{
- for (int i = 0, j = 0; i < expr.Length; ++i, ++j) {
- switch (expr[i]) {
- case '@': // "special" meaning
- ++i;
- if (i < expr.Length) {
- switch (expr[i]) {
- case 'C': // match whitespace or punctuation
- if (index + j == this.Offset || index + j >= this.Offset + this.Length) {
- // nothing (EOL or SOL)
- } else {
- char ch = document.GetCharAt(this.Offset + index + j);
- if (!Char.IsWhiteSpace(ch) && !Char.IsPunctuation(ch)) {
- return false;
- }
- }
- break;
- case '!': // don't match the following expression
- {
- StringBuilder whatmatch = new StringBuilder();
- ++i;
- while (i < expr.Length && expr[i] != '@') {
- whatmatch.Append(expr[i++]);
- }
- if (this.Offset + index + j + whatmatch.Length < document.TextLength) {
- int k = 0;
- for (; k < whatmatch.Length; ++k) {
- char docChar = ignoreCase ? Char.ToUpperInvariant(document.GetCharAt(this.Offset + index + j + k)) : document.GetCharAt(this.Offset + index + j + k);
- char spanChar = ignoreCase ? Char.ToUpperInvariant(whatmatch[k]) : whatmatch[k];
- if (docChar != spanChar) {
- break;
- }
- }
- if (k >= whatmatch.Length) {
- return false;
- }
- }
-// --j;
- break;
- }
- case '-': // don't match the expression before
- {
- StringBuilder whatmatch = new StringBuilder();
- ++i;
- while (i < expr.Length && expr[i] != '@') {
- whatmatch.Append(expr[i++]);
- }
- if (index - whatmatch.Length >= 0) {
- int k = 0;
- for (; k < whatmatch.Length; ++k) {
- char docChar = ignoreCase ? Char.ToUpperInvariant(document.GetCharAt(this.Offset + index - whatmatch.Length + k)) : document.GetCharAt(this.Offset + index - whatmatch.Length + k);
- char spanChar = ignoreCase ? Char.ToUpperInvariant(whatmatch[k]) : whatmatch[k];
- if (docChar != spanChar)
- break;
- }
- if (k >= whatmatch.Length) {
- return false;
- }
- }
-// --j;
- break;
- }
- case '@': // matches @
- if (index + j >= this.Length || '@' != document.GetCharAt(this.Offset + index + j)) {
- return false;
- }
- break;
- }
- }
- break;
- default:
- {
- if (index + j >= this.Length) {
- return false;
- }
- char docChar = ignoreCase ? Char.ToUpperInvariant(document.GetCharAt(this.Offset + index + j)) : document.GetCharAt(this.Offset + index + j);
- char spanChar = ignoreCase ? Char.ToUpperInvariant(expr[i]) : expr[i];
- if (docChar != spanChar) {
- return false;
- }
- break;
- }
+ if (length == 0)
+ return;
+ Debug.Assert(length > 0);
+
+ //Console.WriteLine("InsertedLinePart " + startColumn + ", " + length);
+ if (anchors != null) {
+ foreach (TextAnchor a in anchors) {
+ if (a.ColumnNumber >= startColumn) {
+ a.ColumnNumber += length;
+ }
+ }
+ }
+ }
+
+ ///
+ /// Is called after another line's content is appended to this line because the newline in between
+ /// was deleted.
+ /// The DefaultLineManager will call Deleted() on the deletedLine after the MergedWith call.
+ ///
+ /// firstLineLength: the length of the line before the merge.
+ ///
+ internal void MergedWith(LineSegment deletedLine, int firstLineLength)
+ {
+ //Console.WriteLine("MergedWith");
+
+ if (deletedLine.anchors != null) {
+ foreach (TextAnchor a in deletedLine.anchors) {
+ a.Line = this;
+ AddAnchor(a);
+ a.ColumnNumber += firstLineLength;
+ }
+ deletedLine.anchors = null;
+ }
+ }
+
+ ///
+ /// Is called after a newline was inserted into this line, splitting it into this and followingLine.
+ ///
+ internal void SplitTo(LineSegment followingLine)
+ {
+ //Console.WriteLine("SplitTo");
+
+ if (anchors != null) {
+ List movedAnchors = null;
+ foreach (TextAnchor a in anchors) {
+ if (a.ColumnNumber > this.Length) {
+ a.Line = followingLine;
+ followingLine.AddAnchor(a);
+ a.ColumnNumber -= this.Length;
+
+ if (movedAnchors == null)
+ movedAnchors = new List();
+ movedAnchors.Add(a);
+ }
+ }
+ if (movedAnchors != null) {
+ foreach (TextAnchor a in movedAnchors) {
+ anchors.Remove(a);
+ }
}
}
- return true;
}
+ #endregion
}
}
diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/LineManager/LineSegmentTree.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/LineManager/LineSegmentTree.cs
index c404612de0..74d4c12ed9 100644
--- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/LineManager/LineSegmentTree.cs
+++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/LineManager/LineSegmentTree.cs
@@ -377,6 +377,12 @@ namespace ICSharpCode.TextEditor.Document
public struct Enumerator : IEnumerator
{
+ ///
+ /// An invalid enumerator value. Calling MoveNext on the invalid enumerator
+ /// will always return false, accessing Current will throw an exception.
+ ///
+ public static readonly Enumerator Invalid = default(Enumerator);
+
internal RedBlackTreeIterator it;
internal Enumerator(RedBlackTreeIterator it)
diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/TextAnchor.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/TextAnchor.cs
new file mode 100644
index 0000000000..2721fb6f5e
--- /dev/null
+++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/TextAnchor.cs
@@ -0,0 +1,88 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace ICSharpCode.TextEditor.Document
+{
+ ///
+ /// Description of TextAnchor.
+ ///
+ public sealed class TextAnchor
+ {
+ static Exception AnchorDeletedError()
+ {
+ return new InvalidOperationException("The text containing the anchor was deleted");
+ }
+
+ LineSegment lineSegment;
+ int columnNumber;
+
+ public LineSegment Line {
+ get {
+ if (lineSegment == null) throw AnchorDeletedError();
+ return lineSegment;
+ }
+ internal set {
+ lineSegment = value;
+ }
+ }
+
+ public bool IsDeleted {
+ get {
+ return lineSegment == null;
+ }
+ }
+
+ public int LineNumber {
+ get {
+ return this.Line.LineNumber;
+ }
+ }
+
+ public int ColumnNumber {
+ get {
+ if (lineSegment == null) throw AnchorDeletedError();
+ return columnNumber;
+ }
+ internal set {
+ columnNumber = value;
+ }
+ }
+
+ public TextLocation Location {
+ get {
+ return new TextLocation(this.ColumnNumber, this.LineNumber);
+ }
+ }
+
+ public int Offset {
+ get {
+ return this.Line.Offset + columnNumber;
+ }
+ }
+
+ internal void Deleted()
+ {
+ lineSegment = null;
+ }
+
+ internal TextAnchor(LineSegment lineSegment, int columnNumber)
+ {
+ this.lineSegment = lineSegment;
+ this.columnNumber = columnNumber;
+ }
+
+ public override string ToString()
+ {
+ if (this.IsDeleted)
+ return "[TextAnchor (deleted)]";
+ else
+ return "[TextAnchor " + this.Location.ToString() + "]";
+ }
+ }
+}
diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/Caret.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/Caret.cs
index db82ab75f8..6335a50751 100644
--- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/Caret.cs
+++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/Caret.cs
@@ -195,7 +195,7 @@ namespace ICSharpCode.TextEditor
void GotFocus(object sender, EventArgs e)
{
hidden = false;
- if (!textArea.MotherTextEditorControl.IsUpdating) {
+ if (!textArea.MotherTextEditorControl.IsInUpdate) {
CreateCaret();
UpdateCaretPosition();
}
@@ -226,7 +226,7 @@ namespace ICSharpCode.TextEditor
oldLine = line;
- if (hidden || textArea.MotherTextEditorControl.IsUpdating) {
+ if (hidden || textArea.MotherTextEditorControl.IsInUpdate) {
return;
}
if (!caretCreated) {
diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextArea.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextArea.cs
index 91013eea6a..1d0ffddd0e 100644
--- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextArea.cs
+++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextArea.cs
@@ -741,7 +741,7 @@ namespace ICSharpCode.TextEditor
///
public void InsertChar(char ch)
{
- bool updating = motherTextEditorControl.IsUpdating;
+ bool updating = motherTextEditorControl.IsInUpdate;
if (!updating) {
BeginUpdate();
}
@@ -783,7 +783,7 @@ namespace ICSharpCode.TextEditor
///
public void InsertString(string str)
{
- bool updating = motherTextEditorControl.IsUpdating;
+ bool updating = motherTextEditorControl.IsInUpdate;
if (!updating) {
BeginUpdate();
}
@@ -824,7 +824,7 @@ namespace ICSharpCode.TextEditor
///
public void ReplaceChar(char ch)
{
- bool updating = motherTextEditorControl.IsUpdating;
+ bool updating = motherTextEditorControl.IsInUpdate;
if (!updating) {
BeginUpdate();
}
diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControl.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControl.cs
index fd558f5bbd..79124d8898 100644
--- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControl.cs
+++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControl.cs
@@ -29,6 +29,7 @@ namespace ICSharpCode.TextEditor
PrintDocument printDocument = null;
+ [Browsable(false)]
public PrintDocument PrintDocument {
get {
if (printDocument == null) {
@@ -128,11 +129,14 @@ namespace ICSharpCode.TextEditor
}
}
+ [Browsable(false)]
public bool EnableUndo {
get {
return Document.UndoStack.CanUndo;
}
}
+
+ [Browsable(false)]
public bool EnableRedo {
get {
return Document.UndoStack.CanRedo;
@@ -216,7 +220,7 @@ namespace ICSharpCode.TextEditor
void CommitUpdateRequested(object sender, EventArgs e)
{
- if (IsUpdating) {
+ if (IsInUpdate) {
return;
}
foreach (TextAreaUpdate update in Document.UpdateQueue) {
diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControlBase.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControlBase.cs
index 263e358ce3..d410773740 100644
--- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControlBase.cs
+++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControlBase.cs
@@ -37,6 +37,7 @@ namespace ICSharpCode.TextEditor
///
protected Dictionary editactions = new Dictionary();
+ [Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ITextEditorProperties TextEditorProperties {
get {
@@ -83,17 +84,6 @@ namespace ICSharpCode.TextEditor
}
}
- ///
- /// true, if the textarea is updating it's status, while
- /// it updates it status no redraw operation occurs.
- ///
- [Browsable(false)]
- public bool IsUpdating {
- get {
- return updateLevel > 0;
- }
- }
-
///
/// The current document
///
@@ -122,6 +112,7 @@ namespace ICSharpCode.TextEditor
[EditorBrowsable(EditorBrowsableState.Always), Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
+ [Editor("System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(System.Drawing.Design.UITypeEditor))]
public override string Text {
get {
return Document.TextContent;
@@ -158,10 +149,14 @@ namespace ICSharpCode.TextEditor
}
}
+ ///
+ /// true, if the textarea is updating it's status, while
+ /// it updates it status no redraw operation occurs.
+ ///
[Browsable(false)]
public bool IsInUpdate {
get {
- return this.updateLevel > 0;
+ return updateLevel > 0;
}
}
@@ -260,7 +255,7 @@ namespace ICSharpCode.TextEditor
/// If true the vertical ruler is shown in the textarea
///
[Category("Appearance")]
- [DefaultValue(false)]
+ [DefaultValue(true)]
[Description("If true the vertical ruler is shown in the textarea")]
public bool ShowVRuler {
get {
@@ -308,7 +303,7 @@ namespace ICSharpCode.TextEditor
/// If true invalid lines are marked in the textarea
///
[Category("Appearance")]
- [DefaultValue(true)]
+ [DefaultValue(false)]
[Description("If true invalid lines are marked in the textarea")]
public bool ShowInvalidLines {
get {
@@ -350,7 +345,7 @@ namespace ICSharpCode.TextEditor
}
[Category("Appearance")]
- [DefaultValue(true)]
+ [DefaultValue(false)]
[Description("If true the icon bar is displayed")]
public bool IsIconBarVisible {
get {
@@ -732,7 +727,7 @@ namespace ICSharpCode.TextEditor
///
public override void Refresh()
{
- if (IsUpdating) {
+ if (IsInUpdate) {
return;
}
base.Refresh();
@@ -755,14 +750,6 @@ namespace ICSharpCode.TextEditor
}
}
- protected virtual void OnChanged(EventArgs e)
- {
- if (Changed != null) {
- Changed(this, e);
- }
- }
-
public event EventHandler FileNameChanged;
- public event EventHandler Changed;
}
}
diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Util/WeakCollection.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Util/WeakCollection.cs
new file mode 100644
index 0000000000..43bdfb7907
--- /dev/null
+++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Util/WeakCollection.cs
@@ -0,0 +1,136 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Collections.Generic;
+
+namespace ICSharpCode.TextEditor.Util
+{
+ ///
+ /// A collection that does not allows its elements to be garbage-collected (unless there are other
+ /// references to the elements). Elements will disappear from the collection when they are
+ /// garbage-collected.
+ ///
+ /// The WeakCollection is not thread-safe, not even for read-only access!
+ /// No methods may be called on the WeakCollection while it is enumerated, not even a Contains or
+ /// creating a second enumerator.
+ /// The WeakCollection does not preserve any order among its contents; the ordering may be different each
+ /// time the collection is enumerated.
+ ///
+ /// Since items may disappear at any time when they are garbage collected, this class
+ /// cannot provide a useful implementation for Count and thus cannot implement the ICollection interface.
+ ///
+ public class WeakCollection : IEnumerable where T : class
+ {
+ readonly List innerList = new List();
+
+ ///
+ /// Adds an element to the collection. Runtime: O(n).
+ ///
+ public void Add(T item)
+ {
+ if (item == null)
+ throw new ArgumentNullException("item");
+ CheckNoEnumerator();
+ if (innerList.Count == innerList.Capacity || (innerList.Count % 32) == 31)
+ innerList.RemoveAll(delegate(WeakReference r) { return !r.IsAlive; });
+ innerList.Add(new WeakReference(item));
+ }
+
+ ///
+ /// Removes all elements from the collection. Runtime: O(n).
+ ///
+ public void Clear()
+ {
+ innerList.Clear();
+ CheckNoEnumerator();
+ }
+
+ ///
+ /// Checks if the collection contains an item. Runtime: O(n).
+ ///
+ public bool Contains(T item)
+ {
+ if (item == null)
+ throw new ArgumentNullException("item");
+ CheckNoEnumerator();
+ foreach (T element in this) {
+ if (item.Equals(element))
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Removes an element from the collection. Returns true if the item is found and removed,
+ /// false when the item is not found.
+ /// Runtime: O(n).
+ ///
+ public bool Remove(T item)
+ {
+ if (item == null)
+ throw new ArgumentNullException("item");
+ CheckNoEnumerator();
+ for (int i = 0; i < innerList.Count;) {
+ T element = (T)innerList[i].Target;
+ if (element == null) {
+ RemoveAt(i);
+ } else if (element == item) {
+ RemoveAt(i);
+ return true;
+ } else {
+ i++;
+ }
+ }
+ return false;
+ }
+
+ void RemoveAt(int i)
+ {
+ int lastIndex = innerList.Count - 1;
+ innerList[i] = innerList[lastIndex];
+ innerList.RemoveAt(lastIndex);
+ }
+
+ bool hasEnumerator;
+
+ void CheckNoEnumerator()
+ {
+ if (hasEnumerator)
+ throw new InvalidOperationException("The WeakCollection is already being enumerated, it cannot be modified at the same time. Ensure you dispose the first enumerator before modifying the WeakCollection.");
+ }
+
+ ///
+ /// Enumerates the collection.
+ /// Each MoveNext() call on the enumerator is O(1), thus the enumeration is O(n).
+ ///
+ public IEnumerator GetEnumerator()
+ {
+ if (hasEnumerator)
+ throw new InvalidOperationException("The WeakCollection is already being enumerated, it cannot be enumerated twice at the same time. Ensure you dispose the first enumerator before using another enumerator.");
+ try {
+ hasEnumerator = true;
+ for (int i = 0; i < innerList.Count;) {
+ T element = (T)innerList[i].Target;
+ if (element == null) {
+ RemoveAt(i);
+ } else {
+ yield return element;
+ i++;
+ }
+ }
+ } finally {
+ hasEnumerator = false;
+ }
+ }
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ }
+}