Browse Source
Usage: TextAnchor anchor = document.GetLineSegment(lineNumber).CreateAnchor(columnNumber); anchor.LineNumber and anchor.ColumnNumber are updated when text is inserted/removed in the document. anchor.IsDeleted will be true when the text location containing the anchor was removed. LineSegment gets an IsDeleted property, so a LineSegment reference can be used as anchor for a line. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2683 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
12 changed files with 541 additions and 159 deletions
@ -0,0 +1,88 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
|
||||||
|
namespace ICSharpCode.TextEditor.Document |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Description of TextAnchor.
|
||||||
|
/// </summary>
|
||||||
|
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() + "]"; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,136 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace ICSharpCode.TextEditor.Util |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
public class WeakCollection<T> : IEnumerable<T> where T : class |
||||||
|
{ |
||||||
|
readonly List<WeakReference> innerList = new List<WeakReference>(); |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds an element to the collection. Runtime: O(n).
|
||||||
|
/// </summary>
|
||||||
|
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)); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes all elements from the collection. Runtime: O(n).
|
||||||
|
/// </summary>
|
||||||
|
public void Clear() |
||||||
|
{ |
||||||
|
innerList.Clear(); |
||||||
|
CheckNoEnumerator(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the collection contains an item. Runtime: O(n).
|
||||||
|
/// </summary>
|
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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).
|
||||||
|
/// </summary>
|
||||||
|
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."); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enumerates the collection.
|
||||||
|
/// Each MoveNext() call on the enumerator is O(1), thus the enumeration is O(n).
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerator<T> 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(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue