// 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.Globalization; using ICSharpCode.NRefactory; using ICSharpCode.AvalonEdit.Document; namespace ICSharpCode.AvalonEdit { /// /// Represents a text location with a visual column. /// public struct TextViewPosition : IEquatable, IComparable { int line, column, visualColumn; bool isAtEndOfLine; /// /// Gets/Sets Location. /// public TextLocation Location { get { return new TextLocation(line, column); } set { line = value.Line; column = value.Column; } } /// /// Gets/Sets the line number. /// public int Line { get { return line; } set { line = value; } } /// /// Gets/Sets the (text) column number. /// public int Column { get { return column; } set { column = value; } } /// /// Gets/Sets the visual column number. /// Can be -1 (meaning unknown visual column). /// public int VisualColumn { get { return visualColumn; } set { visualColumn = value; } } /// /// 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. /// public bool IsAtEndOfLine { get { return isAtEndOfLine; } set { isAtEndOfLine = value; } } /// /// Creates a new TextViewPosition instance. /// public TextViewPosition(int line, int column, int visualColumn) { this.line = line; this.column = column; this.visualColumn = visualColumn; this.isAtEndOfLine = false; } /// /// Creates a new TextViewPosition instance. /// public TextViewPosition(int line, int column) : this(line, column, -1) { } /// /// Creates a new TextViewPosition instance. /// public TextViewPosition(TextLocation location, int visualColumn) { this.line = location.Line; this.column = location.Column; this.visualColumn = visualColumn; this.isAtEndOfLine = false; } /// /// Creates a new TextViewPosition instance. /// public TextViewPosition(TextLocation location) : this(location, -1) { } /// public override string ToString() { return string.Format(CultureInfo.InvariantCulture, "[TextViewPosition Line={0} Column={1} VisualColumn={2} IsAtEndOfLine={3}]", this.line, this.column, this.visualColumn, this.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 else return false; } /// public override int GetHashCode() { int 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 this.Line == other.Line && this.Column == other.Column && this.VisualColumn == other.VisualColumn && this.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 = this.Location.CompareTo(other.Location); if (r != 0) return r; r = this.visualColumn.CompareTo(other.visualColumn); if (r != 0) return r; if (isAtEndOfLine && !other.isAtEndOfLine) return -1; else if (!isAtEndOfLine && other.isAtEndOfLine) return 1; return 0; } } }