115 lines
4.2 KiB
C#
115 lines
4.2 KiB
C#
|
|
using System;
|
||
|
|
using Unity.CodeEditor.Document;
|
||
|
|
using Unity.CodeEditor.Text;
|
||
|
|
using Unity.CodeEditor.Utils;
|
||
|
|
using UnityEngine;
|
||
|
|
|
||
|
|
namespace Unity.CodeEditor.Rendering
|
||
|
|
{
|
||
|
|
internal class VisualLineTextSource : ITextRunConstructionContext, TextFormatter.ITextSource
|
||
|
|
{
|
||
|
|
public VisualLineTextSource(VisualLine visualLine)
|
||
|
|
{
|
||
|
|
VisualLine = visualLine;
|
||
|
|
}
|
||
|
|
|
||
|
|
public VisualLine VisualLine { get; private set; }
|
||
|
|
public TextView TextView { get; set; }
|
||
|
|
public TextDocument Document { get; set; }
|
||
|
|
public TextParagraphProperties TextParagraphProperties { get; set; }
|
||
|
|
|
||
|
|
public TextRun GetTextRun(int textSourceCharacterIndex)
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
foreach (VisualLineElement element in VisualLine.Elements) {
|
||
|
|
if (textSourceCharacterIndex >= element.VisualColumn
|
||
|
|
&& textSourceCharacterIndex < element.VisualColumn + element.VisualLength) {
|
||
|
|
int relativeOffset = textSourceCharacterIndex - element.VisualColumn;
|
||
|
|
TextRun run = element.CreateTextRun(textSourceCharacterIndex, this);
|
||
|
|
if (run == null)
|
||
|
|
throw new ArgumentNullException(element.GetType().Name + ".CreateTextRun");
|
||
|
|
if (run.Length == 0)
|
||
|
|
throw new ArgumentException("The returned TextRun must not have length 0.", element.GetType().Name + ".Length");
|
||
|
|
if (relativeOffset + run.Length > element.VisualLength)
|
||
|
|
throw new ArgumentException("The returned TextRun is too long.", element.GetType().Name + ".CreateTextRun");
|
||
|
|
/*if (run is InlineObjectRun inlineRun) {
|
||
|
|
inlineRun.VisualLine = VisualLine;
|
||
|
|
VisualLine.HasInlineObjects = true;
|
||
|
|
TextView.AddInlineObject(inlineRun);
|
||
|
|
}*/
|
||
|
|
return run;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (TextView.Options.ShowEndOfLine && textSourceCharacterIndex == VisualLine.VisualLength && VisualLine.LastDocumentLine.DelimiterLength > 0) {
|
||
|
|
return CreateTextRunForNewLine();
|
||
|
|
}
|
||
|
|
return new TextEndOfParagraph(1, TextParagraphProperties);
|
||
|
|
} catch (Exception ex) {
|
||
|
|
Debug.Log(ex.ToString());
|
||
|
|
throw;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private TextRun CreateTextRunForNewLine()
|
||
|
|
{
|
||
|
|
string newlineText = "";
|
||
|
|
DocumentLine lastDocumentLine = VisualLine.LastDocumentLine;
|
||
|
|
if (lastDocumentLine.DelimiterLength == 2)
|
||
|
|
{
|
||
|
|
newlineText = TextView.Options.EndOfLineCRLFGlyph;
|
||
|
|
}
|
||
|
|
else if (lastDocumentLine.DelimiterLength == 1)
|
||
|
|
{
|
||
|
|
char newlineChar = Document.GetCharAt(lastDocumentLine.Offset + lastDocumentLine.Length);
|
||
|
|
if (newlineChar == '\r')
|
||
|
|
newlineText = TextView.Options.EndOfLineCRGlyph;
|
||
|
|
else if (newlineChar == '\n')
|
||
|
|
newlineText = TextView.Options.EndOfLineLFGlyph;
|
||
|
|
else
|
||
|
|
newlineText = "?";
|
||
|
|
}
|
||
|
|
|
||
|
|
var p = TextParagraphProperties.Clone();
|
||
|
|
p.SetForegroundColor(TextView.NonPrintableCharacterColor);
|
||
|
|
return new StringTextRun(newlineText, p);
|
||
|
|
}
|
||
|
|
|
||
|
|
internal ReadOnlyMemory<char> GetPrecedingText(int textSourceCharacterIndexLimit)
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
foreach (VisualLineElement element in VisualLine.Elements) {
|
||
|
|
if (textSourceCharacterIndexLimit > element.VisualColumn
|
||
|
|
&& textSourceCharacterIndexLimit <= element.VisualColumn + element.VisualLength) {
|
||
|
|
var span = element.GetPrecedingText(textSourceCharacterIndexLimit, this);
|
||
|
|
if (span.IsEmpty)
|
||
|
|
break;
|
||
|
|
int relativeOffset = textSourceCharacterIndexLimit - element.VisualColumn;
|
||
|
|
if (span.Length > relativeOffset)
|
||
|
|
throw new ArgumentException("The returned TextSpan is too long.", element.GetType().Name + ".GetPrecedingText");
|
||
|
|
return span;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return ReadOnlyMemory<char>.Empty;
|
||
|
|
} catch (Exception ex) {
|
||
|
|
Debug.Log(ex.ToString());
|
||
|
|
throw;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private string _cachedString;
|
||
|
|
private int _cachedStringOffset;
|
||
|
|
|
||
|
|
public StringSegment GetText(int offset, int length)
|
||
|
|
{
|
||
|
|
if (_cachedString != null) {
|
||
|
|
if (offset >= _cachedStringOffset && offset + length <= _cachedStringOffset + _cachedString.Length) {
|
||
|
|
return new StringSegment(_cachedString, offset - _cachedStringOffset, length);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
_cachedStringOffset = offset;
|
||
|
|
return new StringSegment(_cachedString = Document.GetText(offset, length));
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|