rj-action-library/Runtime/Text/TextLinesMapper.cs

233 lines
6.7 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace Rokojori
{
public class TextLinesMapper
{
List<TextLine> _lines;
int _cachedLineIndex;
void Reset()
{
_lines = new List<TextLine>();
_cachedLineIndex = 0;
}
public void Map( string source )
{
Reset();
var currentCharacterIndex = 0;
currentCharacterIndex = NextLineBreak( source, currentCharacterIndex );
var lastCharacterIndex = 0;
var lastLineBreakLength = 0;
var currentLineIndex = 0;
var maxTries = 10000; var currentTries = 0;
// currentTries ++; if ( currentTries == maxTries ) { throw new System.Exception(); }
while ( currentCharacterIndex != -1 )
{
currentTries ++; if ( currentTries == maxTries ) { throw new System.Exception(); }
var currentBreakLength = LineBreakLength( source, currentCharacterIndex );
var lineLength = currentCharacterIndex - lastCharacterIndex;
var lineInfo = new TextLine( currentLineIndex, lastCharacterIndex, lineLength, lastLineBreakLength );
_lines.Add( lineInfo );
lastLineBreakLength = currentBreakLength;
lastCharacterIndex = currentCharacterIndex;
currentLineIndex ++;
currentCharacterIndex = NextLineBreak( source, currentCharacterIndex + currentBreakLength );
}
var endLineLength = source.Length - lastCharacterIndex;
var endLineInfo = new TextLine( currentLineIndex, lastCharacterIndex, endLineLength, lastLineBreakLength );
_lines.Add( endLineInfo );
}
public int numCharacters { get { return _lines[ _lines.Count -1 ].lineEnd + 1; } }
public int numLines { get { return _lines.Count; } }
public string lineInfos
{
get
{
var output = new List<string>();
foreach ( var line in _lines )
{
output.Add( line.info );
}
return Lists.Join( output, ",\n" );
}
}
public TextLine GetLine( int characterIndex )
{
var lineIndex = GetLineIndex( characterIndex );
return lineIndex == -1 ? null : _lines[ lineIndex ];
}
public TextAnchor GetAnchor( int characterIndex, bool forTextEditor )
{
var line = GetLine( characterIndex );
if ( line == null ) { return null; }
return forTextEditor ? line.GetTextEditorAnchor( characterIndex ) : line.GetRawAnchor( characterIndex );
}
public TextSelection GetSelection( int startCharacterIndex, int endCharacterIndex, bool forTextEditor = false )
{
var startAnchor = GetAnchor( startCharacterIndex, forTextEditor );
var endAnchor = GetAnchor( endCharacterIndex, forTextEditor );
if ( startAnchor == null || endAnchor == null ) { return null; }
return new TextSelection( startAnchor, endAnchor );
}
public TextSelection GetTextEditorSelection( int startCharacterIndex, int endCharacterIndex )
{
return GetSelection( startCharacterIndex, endCharacterIndex, true );
}
public string GetTextEditorInfo( int startCharacterIndex, int endCharacterIndex )
{
var selection = GetTextEditorSelection( startCharacterIndex, endCharacterIndex );
if ( selection != null ) { return selection.info; }
return "@chars(" + startCharacterIndex + "," + endCharacterIndex + ")";
}
public string GetTextEditorSnippet( string source, int startCharacterIndex, int endCharacterIndex )
{
var startLine = GetLineIndex( startCharacterIndex );
var endLine = GetLineIndex( endCharacterIndex );
if ( endLine < startLine )
{
var b = endLine; endLine = startLine; startLine = b;
}
var snippet = new StringBuilder();
var lengthMaxLineNumberIndex = ( _lines[ endLine ].textEditorLineIndex + "" ).Length;
for ( var i = startLine; i < endLine; i++ )
{
var line = _lines[ i ];
var lineNumber = _lines[ i ].textEditorLineIndex + "";
while ( lineNumber.Length < lengthMaxLineNumberIndex )
{
lineNumber = "0" + lineNumber;
}
var content = line.GetContent( source );
snippet.Append( lineNumber + ": " );
snippet.Append( content );
snippet.Append( "\n" );
}
return snippet.ToString();
}
public string GetTextEditorInfo( int characterIndex )
{
var anchor = GetAnchor( characterIndex, true );
if ( anchor != null ) { return anchor.info; }
return "@chars(" + characterIndex + ")";
}
TextLine _cachedLine { get { return _lines[ _cachedLineIndex ]; } }
public int GetLineIndex( int characterIndex )
{
if ( _cachedLine.Contains( characterIndex ) )
{
return _cachedLineIndex;
}
if ( _lines.Count == 0 || characterIndex < 0 || characterIndex > numCharacters )
{ return -1; }
var lineContainsCharacterIndex = false;
var lineIndexInRange = true;
var characterIndexIsHigher = _cachedLine.characterIndex < characterIndex;
var searchForward = 1;
var searchBackward = -1 ;
var searchStep = characterIndexIsHigher ? searchForward : searchBackward;
var maxTries = 1000; var currentTries = 0;
// currentTries ++; if ( currentTries == maxTries ) { throw new System.Exception(); }
do
{
currentTries ++; if ( currentTries == maxTries ) { throw new System.Exception(); }
var nextLineIndex = _cachedLineIndex + searchStep;
lineIndexInRange = 0 <= nextLineIndex && nextLineIndex < _lines.Count;
if ( lineIndexInRange )
{
_cachedLineIndex = nextLineIndex;
lineContainsCharacterIndex = _cachedLine.Contains( characterIndex );
}
else
{
lineContainsCharacterIndex = false;
}
}
while ( ! lineContainsCharacterIndex && lineIndexInRange );
if ( lineContainsCharacterIndex )
{
return _cachedLineIndex;
}
return -1;
}
int NextLineBreak( string source, int offset )
{
for ( int i = offset; i < source.Length; i++ )
{
if ( source[ i ] == '\n' || source[ i ] == '\r' )
{
return i;
}
}
return -1;
}
int LineBreakLength( string source, int offset )
{
if ( source[ offset ] == '\r' && ( ( offset + 1 ) < source.Length ) )
{
return source[ offset + 1 ] == '\n' ? 2 : 1;
}
return 1;
}
}
}