mirror of
https://github.com/Facepunch/sbox-public.git
synced 2025-12-23 22:48:07 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
273 lines
7.6 KiB
C#
273 lines
7.6 KiB
C#
// RichTextKit
|
|
// Copyright © 2019-2020 Topten Software. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
// not use this product except in compliance with the License. You may obtain
|
|
// a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Xml.Schema;
|
|
|
|
namespace Topten.RichTextKit
|
|
{
|
|
/// <summary>
|
|
/// Represents a range of code points in a text document
|
|
/// </summary>
|
|
public struct TextRange
|
|
{
|
|
/// <summary>
|
|
/// Initializes a TextRange
|
|
/// </summary>
|
|
/// <param name="start">The code point index of the start of the range</param>
|
|
/// <param name="end">The code point index of the end of the range</param>
|
|
/// <param name="altPosition">Whether the caret at the end of the range should be displayed in its alternative position</param>
|
|
public TextRange( int start, int end, bool altPosition = false )
|
|
{
|
|
Start = start;
|
|
End = end;
|
|
AltPosition = altPosition;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a TextRange with a non-range position
|
|
/// </summary>
|
|
/// <param name="position">The code point index of the position</param>
|
|
/// <param name="altPosition">Whether the caret should be displayed in its alternative position</param>
|
|
public TextRange( int position, bool altPosition = false )
|
|
{
|
|
Start = position;
|
|
End = position;
|
|
AltPosition = altPosition;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a TextRange from a caret position
|
|
/// </summary>
|
|
/// <param name="position">The code point index of the position</param>
|
|
public TextRange( CaretPosition position )
|
|
{
|
|
Start = position.CodePointIndex;
|
|
End = position.CodePointIndex;
|
|
AltPosition = position.AltPosition;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The code point index of the start of the range
|
|
/// </summary>
|
|
public int Start;
|
|
|
|
/// <summary>
|
|
/// The code point index of the end of the range
|
|
/// </summary>
|
|
public int End;
|
|
|
|
/// <summary>
|
|
/// True if the end of the range should be displayed
|
|
/// with the caret in the alt position
|
|
/// </summary>
|
|
public bool AltPosition;
|
|
|
|
/// <summary>
|
|
/// Get the length of this range
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Will return negative if the range isn't normalized
|
|
/// </remarks>
|
|
public int Length => End - Start;
|
|
|
|
/// <summary>
|
|
/// Offset this text range by the specified amount
|
|
/// </summary>
|
|
/// <param name="delta">The number of code points to offset the range by</param>
|
|
/// <returns>A new TextRange</returns>
|
|
public TextRange Offset( int delta )
|
|
{
|
|
return new TextRange( Start + delta, End + delta, AltPosition );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the reversed text range
|
|
/// </summary>
|
|
public TextRange Reversed
|
|
{
|
|
get
|
|
{
|
|
return new TextRange( End, Start, false );
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the normalized version of the text range
|
|
/// </summary>
|
|
public TextRange Normalized
|
|
{
|
|
get
|
|
{
|
|
if ( Start > End )
|
|
return Reversed;
|
|
else
|
|
return this;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compare this text range to another for equality
|
|
/// </summary>
|
|
/// <param name="other">The text range to compare to</param>
|
|
/// <returns>True if the text ranges are equal</returns>
|
|
public bool IsEqual( TextRange other )
|
|
{
|
|
return other.Start == Start &&
|
|
other.End == End &&
|
|
other.AltPosition == AltPosition;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check if this is actually a range
|
|
/// </summary>
|
|
public bool IsRange => Start != End;
|
|
|
|
/// <summary>
|
|
/// Get the end of the range closer to the start of the document
|
|
/// </summary>
|
|
public int Minimum => Math.Min( Start, End );
|
|
|
|
/// <summary>
|
|
/// Get the end of the range closer to the end of the document
|
|
/// </summary>
|
|
public int Maximum => Math.Max( Start, End );
|
|
|
|
/// <summary>
|
|
/// Gets the end of the range as a caret position
|
|
/// </summary>
|
|
public CaretPosition CaretPosition
|
|
{
|
|
get
|
|
{
|
|
return new CaretPosition( End, AltPosition );
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clamp the text range to a document length
|
|
/// </summary>
|
|
/// <param name="maxCodePointIndex">The max code point index</param>
|
|
/// <returns>A clamped TextRange</returns>
|
|
public TextRange Clamp( int maxCodePointIndex )
|
|
{
|
|
var newStart = Start;
|
|
if ( newStart < 0 )
|
|
newStart = 0;
|
|
if ( newStart > maxCodePointIndex )
|
|
newStart = maxCodePointIndex;
|
|
|
|
var newEnd = End;
|
|
if ( newEnd < 0 )
|
|
newEnd = 0;
|
|
if ( newEnd > maxCodePointIndex )
|
|
newEnd = maxCodePointIndex;
|
|
|
|
return new TextRange( newStart, newEnd, AltPosition );
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Create an updated text range that tries to represent the same
|
|
/// piece of text from before an edit to after the edit.
|
|
/// </summary>
|
|
/// <param name="codePointIndex">The position of the edit</param>
|
|
/// <param name="oldLength">The length of text deleted</param>
|
|
/// <param name="newLength">The length of text inserted</param>
|
|
/// <returns>An updated text range</returns>
|
|
public TextRange UpdateForEdit( int codePointIndex, int oldLength, int newLength )
|
|
{
|
|
int delta = newLength - oldLength;
|
|
|
|
// After this range?
|
|
if ( codePointIndex > Maximum )
|
|
return this;
|
|
|
|
// Before this range?
|
|
if ( codePointIndex + oldLength <= Minimum )
|
|
return new TextRange( Start + delta, End + delta, AltPosition );
|
|
|
|
// Entire range?
|
|
if ( codePointIndex <= Minimum && codePointIndex + oldLength >= Maximum )
|
|
return new TextRange( codePointIndex, codePointIndex, AltPosition );
|
|
|
|
// Inside this range?
|
|
if ( codePointIndex >= Minimum && codePointIndex + oldLength <= Maximum )
|
|
{
|
|
if ( Start < End )
|
|
return new TextRange( Start, End + delta, AltPosition );
|
|
else
|
|
return new TextRange( End, Start + delta, AltPosition );
|
|
}
|
|
|
|
// Overlap start of this range?
|
|
if ( codePointIndex < Minimum && codePointIndex + oldLength >= Minimum )
|
|
{
|
|
if ( Start < End )
|
|
return new TextRange( codePointIndex + newLength, End + delta, AltPosition );
|
|
else
|
|
return new TextRange( Start + delta, codePointIndex + newLength, AltPosition );
|
|
}
|
|
|
|
// Overlap end of this range?
|
|
if ( codePointIndex >= Minimum && codePointIndex + oldLength > Maximum )
|
|
{
|
|
if ( Start < End )
|
|
return new TextRange( Start, codePointIndex, AltPosition );
|
|
else
|
|
return new TextRange( codePointIndex, End, AltPosition );
|
|
}
|
|
|
|
// Should never get here.
|
|
return new TextRange();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a new range that is the union of two other ranges. The
|
|
/// union is the smallest range that contains the other two other
|
|
/// ranges.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The returned range is configured such that the 'b' range
|
|
/// is used for the end position (ie: the caret)
|
|
/// </remarks>
|
|
/// <param name="a">The first text range</param>
|
|
/// <param name="b">The second text range</param>
|
|
/// <returns>A range that encompasses both ranges</returns>
|
|
public static TextRange Union( TextRange a, TextRange b )
|
|
{
|
|
if ( a.Minimum <= b.Minimum )
|
|
{
|
|
return new TextRange(
|
|
Math.Min( a.Minimum, b.Minimum ),
|
|
Math.Max( a.Maximum, b.Maximum ), b.AltPosition );
|
|
}
|
|
else
|
|
{
|
|
return new TextRange(
|
|
Math.Max( a.Maximum, b.Maximum ),
|
|
Math.Min( a.Minimum, b.Minimum ), b.AltPosition );
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override string ToString()
|
|
{
|
|
return $"{Start} → {End} (len: {Length})";
|
|
}
|
|
}
|
|
}
|