diff options
| author | Victoria Plitt <Victoria.Plitt@twine-s.com> | 2019-04-08 13:49:55 +0300 |
|---|---|---|
| committer | Victoria Plitt <Victoria.Plitt@twine-s.com> | 2019-04-08 13:49:55 +0300 |
| commit | fc8a05358a92cc3c77c5f1e30d536807ef0614fd (patch) | |
| tree | c65f696ebd60f3790145721307c255e5a339923f /Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/TextSegment.cs | |
| parent | b4a71931ea52636c6b36376aa9d71697ccf73524 (diff) | |
| download | Tango-fc8a05358a92cc3c77c5f1e30d536807ef0614fd.tar.gz Tango-fc8a05358a92cc3c77c5f1e30d536807ef0614fd.zip | |
were added scripting projects
Diffstat (limited to 'Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/TextSegment.cs')
| -rw-r--r-- | Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/TextSegment.cs | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/TextSegment.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/TextSegment.cs new file mode 100644 index 000000000..d1834c214 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/TextSegment.cs @@ -0,0 +1,248 @@ +// 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; + +namespace Tango.Scripting.Editors.Document +{ + /// <summary> + /// A segment that can be put into a <see cref="TextSegmentCollection{T}"/>. + /// </summary> + /// <remarks> + /// <para> + /// A <see cref="TextSegment"/> can be stand-alone or part of a <see cref="TextSegmentCollection{T}"/>. + /// If the segment is stored inside a TextSegmentCollection, its Offset and Length will be updated by that collection. + /// </para> + /// <para> + /// When the document changes, the offsets of all text segments in the TextSegmentCollection will be adjusted accordingly. + /// Start offsets move like <see cref="AnchorMovementType">AnchorMovementType.AfterInsertion</see>, + /// end offsets move like <see cref="AnchorMovementType">AnchorMovementType.BeforeInsertion</see> + /// (i.e. the segment will always stay as small as possible).</para> + /// <para> + /// If a document change causes a segment to be deleted completely, it will be reduced to length 0, but segments are + /// never automatically removed from the collection. + /// Segments with length 0 will never expand due to document changes, and they move as <c>AfterInsertion</c>. + /// </para> + /// <para> + /// Thread-safety: a TextSegmentCollection that is connected to a <see cref="TextDocument"/> may only be used on that document's owner thread. + /// A disconnected TextSegmentCollection is safe for concurrent reads, but concurrent access is not safe when there are writes. + /// Keep in mind that reading the Offset properties of a text segment inside the collection is a read access on the + /// collection; and setting an Offset property of a text segment is a write access on the collection. + /// </para> + /// </remarks> + /// <seealso cref="ISegment"/> + /// <seealso cref="AnchorSegment"/> + /// <seealso cref="TextSegmentCollection{T}"/> + public class TextSegment : ISegment + { + internal ISegmentTree ownerTree; + internal TextSegment left, right, parent; + + /// <summary> + /// The color of the segment in the red/black tree. + /// </summary> + internal bool color; + + /// <summary> + /// The "length" of the node (distance to previous node) + /// </summary> + internal int nodeLength; + + /// <summary> + /// The total "length" of this subtree. + /// </summary> + internal int totalNodeLength; // totalNodeLength = nodeLength + left.totalNodeLength + right.totalNodeLength + + /// <summary> + /// The length of the segment (do not confuse with nodeLength). + /// </summary> + internal int segmentLength; + + /// <summary> + /// distanceToMaxEnd = Max(segmentLength, + /// left.distanceToMaxEnd + left.Offset - Offset, + /// left.distanceToMaxEnd + right.Offset - Offset) + /// </summary> + internal int distanceToMaxEnd; + + int ISegment.Offset { + get { return StartOffset; } + } + + /// <summary> + /// Gets whether this segment is connected to a TextSegmentCollection and will automatically + /// update its offsets. + /// </summary> + protected bool IsConnectedToCollection { + get { + return ownerTree != null; + } + } + + /// <summary> + /// Gets/Sets the start offset of the segment. + /// </summary> + /// <remarks> + /// When setting the start offset, the end offset will change, too: the Length of the segment will stay constant. + /// </remarks> + public int StartOffset { + get { + // If the segment is not connected to a tree, we store the offset in "nodeLength". + // Otherwise, "nodeLength" contains the distance to the start offset of the previous node + Debug.Assert(!(ownerTree == null && parent != null)); + Debug.Assert(!(ownerTree == null && left != null)); + + TextSegment n = this; + int offset = n.nodeLength; + if (n.left != null) + offset += n.left.totalNodeLength; + while (n.parent != null) { + if (n == n.parent.right) { + if (n.parent.left != null) + offset += n.parent.left.totalNodeLength; + offset += n.parent.nodeLength; + } + n = n.parent; + } + return offset; + } + set { + if (value < 0) + throw new ArgumentOutOfRangeException("value", "Offset must not be negative"); + if (this.StartOffset != value) { + // need a copy of the variable because ownerTree.Remove() sets this.ownerTree to null + ISegmentTree ownerTree = this.ownerTree; + if (ownerTree != null) { + ownerTree.Remove(this); + nodeLength = value; + ownerTree.Add(this); + } else { + nodeLength = value; + } + OnSegmentChanged(); + } + } + } + + /// <summary> + /// Gets/Sets the end offset of the segment. + /// </summary> + /// <remarks> + /// Setting the end offset will change the length, the start offset will stay constant. + /// </remarks> + public int EndOffset { + get { + return StartOffset + Length; + } + set { + int newLength = value - StartOffset; + if (newLength < 0) + throw new ArgumentOutOfRangeException("value", "EndOffset must be greater or equal to StartOffset"); + Length = newLength; + } + } + + /// <summary> + /// Gets/Sets the length of the segment. + /// </summary> + /// <remarks> + /// Setting the length will change the end offset, the start offset will stay constant. + /// </remarks> + public int Length { + get { + return segmentLength; + } + set { + if (value < 0) + throw new ArgumentOutOfRangeException("value", "Length must not be negative"); + if (segmentLength != value) { + segmentLength = value; + if (ownerTree != null) + ownerTree.UpdateAugmentedData(this); + OnSegmentChanged(); + } + } + } + + /// <summary> + /// This method gets called when the StartOffset/Length/EndOffset properties are set. + /// It is not called when StartOffset/Length/EndOffset change due to document changes + /// </summary> + protected virtual void OnSegmentChanged() + { + } + + internal TextSegment LeftMost { + get { + TextSegment node = this; + while (node.left != null) + node = node.left; + return node; + } + } + + internal TextSegment RightMost { + get { + TextSegment node = this; + while (node.right != null) + node = node.right; + return node; + } + } + + /// <summary> + /// Gets the inorder successor of the node. + /// </summary> + internal TextSegment Successor { + get { + if (right != null) { + return right.LeftMost; + } else { + TextSegment node = this; + TextSegment oldNode; + do { + oldNode = node; + node = node.parent; + // go up until we are coming out of a left subtree + } while (node != null && node.right == oldNode); + return node; + } + } + } + + /// <summary> + /// Gets the inorder predecessor of the node. + /// </summary> + internal TextSegment Predecessor { + get { + if (left != null) { + return left.RightMost; + } else { + TextSegment node = this; + TextSegment oldNode; + do { + oldNode = node; + node = node.parent; + // go up until we are coming out of a right subtree + } while (node != null && node.left == oldNode); + return node; + } + } + } + + #if DEBUG + internal string ToDebugString() + { + return "[nodeLength=" + nodeLength + " totalNodeLength=" + totalNodeLength + + " distanceToMaxEnd=" + distanceToMaxEnd + " MaxEndOffset=" + (StartOffset + distanceToMaxEnd) + "]"; + } + #endif + + /// <inheritdoc/> + public override string ToString() + { + return "[" + GetType().Name + " Offset=" + StartOffset + " Length=" + Length + " EndOffset=" + EndOffset + "]"; + } + } +} |
