// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team // // Permission is hereby granted, free of charge, to any person obtaining a copy of this // software and associated documentation files (the "Software"), to deal in the Software // without restriction, including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons // to whom the Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or // substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; using Unity.CodeEditor.Document; namespace Unity.CodeEditor { /// /// Represents a text location with a visual column. /// internal struct TextViewPosition : IEquatable, IComparable { /// /// Gets/Sets Location. /// internal TextLocation Location { get => new TextLocation(Line, Column); set { Line = value.Line; Column = value.Column; } } /// /// Gets/Sets the line number. /// internal int Line { get; set; } /// /// Gets/Sets the (text) column number. /// internal int Column { get; set; } /// /// Gets/Sets the visual column number. /// Can be -1 (meaning unknown visual column). /// internal int VisualColumn { get; set; } /// /// When word-wrap is enabled and a line is wrapped at a position where there is no space character; /// then both the end of the first TextLine and the beginning of the second TextLine /// refer to the same position in the document, and also have the same visual column. /// In this case, the IsAtEndOfLine property is used to distinguish between the two cases: /// the value true indicates that the position refers to the end of the previous TextLine; /// the value false indicates that the position refers to the beginning of the next TextLine. /// /// If this position is not at such a wrapping position, the value of this property has no effect. /// internal bool IsAtEndOfLine { get; set; } /// /// Creates a new TextViewPosition instance. /// internal TextViewPosition(int line, int column, int visualColumn) { Line = line; Column = column; VisualColumn = visualColumn; IsAtEndOfLine = false; } /// /// Creates a new TextViewPosition instance. /// internal TextViewPosition(int line, int column) : this(line, column, -1) { } /// /// Creates a new TextViewPosition instance. /// internal TextViewPosition(TextLocation location, int visualColumn) { Line = location.Line; Column = location.Column; VisualColumn = visualColumn; IsAtEndOfLine = false; } /// /// Creates a new TextViewPosition instance. /// internal TextViewPosition(TextLocation location) : this(location, -1) { } /// public override string ToString() { return string.Format(CultureInfo.InvariantCulture, "[TextViewPosition Line={0} Column={1} VisualColumn={2} IsAtEndOfLine={3}]", Line, Column, VisualColumn, IsAtEndOfLine); } #region Equals and GetHashCode implementation // The code in this region is useful if you want to use this structure in collections. // If you don't need it, you can just remove the region and the ": IEquatable" declaration. /// public override bool Equals(object obj) { if (obj is TextViewPosition) return Equals((TextViewPosition)obj); // use Equals method below return false; } /// [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] public override int GetHashCode() { var hashCode = IsAtEndOfLine ? 115817 : 0; unchecked { hashCode += 1000000007 * Line.GetHashCode(); hashCode += 1000000009 * Column.GetHashCode(); hashCode += 1000000021 * VisualColumn.GetHashCode(); } return hashCode; } /// /// Equality test. /// public bool Equals(TextViewPosition other) { return Line == other.Line && Column == other.Column && VisualColumn == other.VisualColumn && IsAtEndOfLine == other.IsAtEndOfLine; } /// /// Equality test. /// public static bool operator ==(TextViewPosition left, TextViewPosition right) { return left.Equals(right); } /// /// Inequality test. /// public static bool operator !=(TextViewPosition left, TextViewPosition right) { return !(left.Equals(right)); // use operator == and negate result } #endregion /// public int CompareTo(TextViewPosition other) { int r = Location.CompareTo(other.Location); if (r != 0) return r; r = VisualColumn.CompareTo(other.VisualColumn); if (r != 0) return r; if (IsAtEndOfLine && !other.IsAtEndOfLine) return -1; if (!IsAtEndOfLine && other.IsAtEndOfLine) return 1; return 0; } } }