/AvalonEdit/ICSharpCode.AvalonEdit/Document/ISegment.cs

http://github.com/icsharpcode/ILSpy · C# · 219 lines · 133 code · 27 blank · 59 comment · 15 complexity · 94d8d1f69c862f5fa623e612f0a1e7c2 MD5 · raw file

  1. // Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
  2. // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
  3. using System;
  4. using System.Diagnostics;
  5. using ICSharpCode.AvalonEdit.Utils;
  6. using System.Globalization;
  7. namespace ICSharpCode.AvalonEdit.Document
  8. {
  9. /// <summary>
  10. /// An (Offset,Length)-pair.
  11. /// </summary>
  12. /// <seealso cref="TextSegment"/>
  13. /// <seealso cref="AnchorSegment"/>
  14. public interface ISegment
  15. {
  16. /// <summary>
  17. /// Gets the start offset of the segment.
  18. /// </summary>
  19. int Offset { get; }
  20. /// <summary>
  21. /// Gets the length of the segment.
  22. /// </summary>
  23. /// <remarks>Must not be negative.</remarks>
  24. int Length { get; }
  25. /// <summary>
  26. /// Gets the end offset of the segment.
  27. /// </summary>
  28. /// <remarks>EndOffset = Offset + Length;</remarks>
  29. int EndOffset { get; }
  30. }
  31. static class SegmentExtensions
  32. {
  33. /// <summary>
  34. /// Gets whether the segment contains the offset.
  35. /// </summary>
  36. /// <returns>
  37. /// True, if offset is between segment.Start and segment.End (inclusive); otherwise, false.
  38. /// </returns>
  39. public static bool Contains(this ISegment segment, int offset)
  40. {
  41. int start = segment.Offset;
  42. int end = start + segment.Length;
  43. return offset >= start && offset <= end;
  44. }
  45. /// <summary>
  46. /// Gets the overlapping portion of the segments.
  47. /// Returns SimpleSegment.Invalid if the segments don't overlap.
  48. /// </summary>
  49. public static SimpleSegment GetOverlap(this ISegment segment, ISegment other)
  50. {
  51. int start = Math.Max(segment.Offset, other.Offset);
  52. int end = Math.Min(segment.EndOffset, other.EndOffset);
  53. if (end < start)
  54. return SimpleSegment.Invalid;
  55. else
  56. return new SimpleSegment(start, end - start);
  57. }
  58. }
  59. /// <summary>
  60. /// Represents a simple segment (Offset,Length pair) that is not automatically updated
  61. /// on document changes.
  62. /// </summary>
  63. struct SimpleSegment : IEquatable<SimpleSegment>, ISegment
  64. {
  65. public static readonly SimpleSegment Invalid = new SimpleSegment(-1, -1);
  66. public readonly int Offset, Length;
  67. int ISegment.Offset {
  68. get { return Offset; }
  69. }
  70. int ISegment.Length {
  71. get { return Length; }
  72. }
  73. public int EndOffset {
  74. get {
  75. return Offset + Length;
  76. }
  77. }
  78. public SimpleSegment(int offset, int length)
  79. {
  80. this.Offset = offset;
  81. this.Length = length;
  82. }
  83. public SimpleSegment(ISegment segment)
  84. {
  85. Debug.Assert(segment != null);
  86. this.Offset = segment.Offset;
  87. this.Length = segment.Length;
  88. }
  89. public override int GetHashCode()
  90. {
  91. unchecked {
  92. return Offset + 10301 * Length;
  93. }
  94. }
  95. public override bool Equals(object obj)
  96. {
  97. return (obj is SimpleSegment) && Equals((SimpleSegment)obj);
  98. }
  99. public bool Equals(SimpleSegment other)
  100. {
  101. return this.Offset == other.Offset && this.Length == other.Length;
  102. }
  103. public static bool operator ==(SimpleSegment left, SimpleSegment right)
  104. {
  105. return left.Equals(right);
  106. }
  107. public static bool operator !=(SimpleSegment left, SimpleSegment right)
  108. {
  109. return !left.Equals(right);
  110. }
  111. public override string ToString()
  112. {
  113. return "[Offset=" + Offset.ToString(CultureInfo.InvariantCulture) + ", Length=" + Length.ToString(CultureInfo.InvariantCulture) + "]";
  114. }
  115. }
  116. /// <summary>
  117. /// A segment using <see cref="TextAnchor"/>s as start and end positions.
  118. /// </summary>
  119. /// <remarks>
  120. /// <para>
  121. /// For the constructors creating new anchors, the start position will be AfterInsertion and the end position will be BeforeInsertion.
  122. /// Should the end position move before the start position, the segment will have length 0.
  123. /// </para>
  124. /// </remarks>
  125. /// <seealso cref="ISegment"/>
  126. /// <seealso cref="TextSegment"/>
  127. public sealed class AnchorSegment : ISegment
  128. {
  129. readonly TextAnchor start, end;
  130. /// <inheritdoc/>
  131. public int Offset {
  132. get { return start.Offset; }
  133. }
  134. /// <inheritdoc/>
  135. public int Length {
  136. get {
  137. // Math.Max takes care of the fact that end.Offset might move before start.Offset.
  138. return Math.Max(0, end.Offset - start.Offset);
  139. }
  140. }
  141. /// <inheritdoc/>
  142. public int EndOffset {
  143. get {
  144. // Math.Max takes care of the fact that end.Offset might move before start.Offset.
  145. return Math.Max(start.Offset, end.Offset);
  146. }
  147. }
  148. /// <summary>
  149. /// Creates a new AnchorSegment using the specified anchors.
  150. /// The anchors must have <see cref="TextAnchor.SurviveDeletion"/> set to true.
  151. /// </summary>
  152. public AnchorSegment(TextAnchor start, TextAnchor end)
  153. {
  154. if (start == null)
  155. throw new ArgumentNullException("start");
  156. if (end == null)
  157. throw new ArgumentNullException("end");
  158. if (!start.SurviveDeletion)
  159. throw new ArgumentException("Anchors for AnchorSegment must use SurviveDeletion", "start");
  160. if (!end.SurviveDeletion)
  161. throw new ArgumentException("Anchors for AnchorSegment must use SurviveDeletion", "end");
  162. this.start = start;
  163. this.end = end;
  164. }
  165. /// <summary>
  166. /// Creates a new AnchorSegment that creates new anchors.
  167. /// </summary>
  168. public AnchorSegment(TextDocument document, ISegment segment)
  169. : this(document, ThrowUtil.CheckNotNull(segment, "segment").Offset, segment.Length)
  170. {
  171. }
  172. /// <summary>
  173. /// Creates a new AnchorSegment that creates new anchors.
  174. /// </summary>
  175. public AnchorSegment(TextDocument document, int offset, int length)
  176. {
  177. if (document == null)
  178. throw new ArgumentNullException("document");
  179. this.start = document.CreateAnchor(offset);
  180. this.start.SurviveDeletion = true;
  181. this.start.MovementType = AnchorMovementType.AfterInsertion;
  182. this.end = document.CreateAnchor(offset + length);
  183. this.end.SurviveDeletion = true;
  184. this.end.MovementType = AnchorMovementType.BeforeInsertion;
  185. }
  186. /// <inheritdoc/>
  187. public override string ToString()
  188. {
  189. return "[Offset=" + Offset.ToString(CultureInfo.InvariantCulture) + ", EndOffset=" + EndOffset.ToString(CultureInfo.InvariantCulture) + "]";
  190. }
  191. }
  192. }