// 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;
}
}
}