Only lexer-highlight what is shown in CS console (fix max vert overflow)

This commit is contained in:
Sinai
2021-05-10 21:07:27 +10:00
parent 4f50afdddc
commit 1d24af5666
7 changed files with 182 additions and 93 deletions

View File

@ -6,6 +6,7 @@ using System.Text;
using UnityEngine;
using UnityExplorer.UI.IValues;
using System.Reflection;
using UnityExplorer.UI;
#if CPP
using UnhollowerRuntimeLib;
using UnhollowerBaseLib;
@ -70,6 +71,9 @@ namespace UnityExplorer.Tests
public static TestValueStruct AATestStruct;
public static string AAATooLongString = new string('#', UIManager.MAX_INPUTFIELD_CHARS + 2);
public static string AAAMaxString = new string('@', UIManager.MAX_INPUTFIELD_CHARS);
public static TestEnum AATestEnumOne = TestEnum.Neg50;
public static TestEnum2 AATestEnumTwo = TestEnum2.Max;
public static TestFlags AATestFlags = TestFlags.Thirteen;

View File

@ -61,7 +61,7 @@ The following helper methods are available:
private static HashSet<string> usingDirectives;
private static CSConsolePanel Panel => UIManager.CSharpConsole;
private static InputField InputField => Panel.InputField.InputField;
private static InputFieldRef Input => Panel.Input;
// Todo save as config?
public static bool EnableCtrlRShortcut { get; private set; } = true;
@ -78,7 +78,8 @@ The following helper methods are available:
Evaluator.Compile("0 == 0");
Panel.OnInputChanged += OnConsoleInputChanged;
// TODO other panel listeners
Panel.InputScroll.OnScroll += ForceOnContentChange;
// TODO other panel listeners (buttons, etc)
}
catch (Exception ex)
@ -87,6 +88,123 @@ The following helper methods are available:
}
}
// Updating and event listeners
private static readonly KeyCode[] onFocusKeys =
{
KeyCode.Return, KeyCode.Backspace, KeyCode.UpArrow,
KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow
};
public static void Update()
{
if (EnableCtrlRShortcut)
{
if ((InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl))
&& InputManager.GetKeyDown(KeyCode.R))
{
var text = Panel.Input.Text.Trim();
if (!string.IsNullOrEmpty(text))
{
Evaluate(text);
return;
}
}
}
//if (EnableAutoIndent && InputManager.GetKeyDown(KeyCode.Return))
// DoAutoIndent();
//if (EnableAutocompletes && InputField.isFocused)
//{
// if (InputManager.GetMouseButton(0) || onFocusKeys.Any(it => InputManager.GetKeyDown(it)))
// UpdateAutocompletes();
//}
}
private static void ForceOnContentChange()
{
OnConsoleInputChanged(Input.Text);
}
// Invoked at most once per frame
private static void OnConsoleInputChanged(string value)
{
// todo auto indent? or only on enter?
// syntax highlight
LexerHighlightAndSet(value);
// todo update auto completes
// ...
}
private static void LexerHighlightAndSet(string value)
{
int startLine = 0;
int endLine = Input.TextGenerator.lineCount - 1;
if (Input.Rect.rect.height > Panel.InputScroll.ViewportRect.rect.height)
{
// Not all text is displayed.
// Only syntax highlight what we need to.
int topLine = -1;
int bottomLine = -1;
var half = Input.Rect.rect.height * 0.5f;
var top = Input.Rect.rect.height - Input.Rect.anchoredPosition.y;
var bottom = top - Panel.InputScroll.ViewportRect.rect.height;
for (int i = 0; i < Input.TextGenerator.lineCount; i++)
{
var line = Input.TextGenerator.lines[i];
var pos = line.topY + half;
if (topLine == -1 && pos <= top)
topLine = i;
if ((pos - line.height) >= bottom)
bottomLine = i;
}
startLine = Math.Max(0, topLine - 1);
endLine = Math.Min(Input.TextGenerator.lineCount - 1, bottomLine + 1);
}
int startIdx = Input.TextGenerator.lines[startLine].startCharIdx;
int endIdx;
if (endLine >= Input.TextGenerator.lineCount - 1)
endIdx = value.Length - 1;
else
endIdx = Math.Min(value.Length - 1, Input.TextGenerator.lines[endLine + 1].startCharIdx);
var sb = new StringBuilder();
for (int i = 0; i < startLine; i++)
sb.Append('\n');
for (int i = startIdx; i <= endIdx; i++)
sb.Append(value[i]);
Panel.HighlightText.text = Lexer.SyntaxHighlight(sb.ToString());
}
// TODO indenting
//private static void DoAutoIndent()
//{
// int caret = Panel.LastCaretPosition;
// Panel.InputField.Text = Lexer.AutoIndentOnEnter(InputField.text, ref caret);
// InputField.caretPosition = caret;
//
// Panel.InputText.Rebuild(CanvasUpdate.Prelayout);
// InputField.ForceLabelUpdate();
// InputField.Rebuild(CanvasUpdate.Prelayout);
//
// OnConsoleInputChanged(InputField.text);
//}
#region Evaluating console input
public static void ResetConsole(bool logSuccess = true)
@ -149,65 +267,5 @@ The following helper methods are available:
#endregion
// Updating and event listeners
private static readonly KeyCode[] onFocusKeys =
{
KeyCode.Return, KeyCode.Backspace, KeyCode.UpArrow,
KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow
};
public static void Update()
{
if (EnableCtrlRShortcut)
{
if ((InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl))
&& InputManager.GetKeyDown(KeyCode.R))
{
var text = Panel.InputField.Text.Trim();
if (!string.IsNullOrEmpty(text))
{
Evaluate(text);
return;
}
}
}
//if (EnableAutoIndent && InputManager.GetKeyDown(KeyCode.Return))
// DoAutoIndent();
//if (EnableAutocompletes && InputField.isFocused)
//{
// if (InputManager.GetMouseButton(0) || onFocusKeys.Any(it => InputManager.GetKeyDown(it)))
// UpdateAutocompletes();
//}
}
// Invoked at most once per frame
private static void OnConsoleInputChanged(string input)
{
// todo update auto completes
// update syntax highlight
Panel.HighlightText.text = Lexer.SyntaxHighlight(input);
}
// TODO?
//private static void DoAutoIndent()
//{
// int caret = Panel.LastCaretPosition;
// Panel.InputField.Text = Lexer.AutoIndentOnEnter(InputField.text, ref caret);
// InputField.caretPosition = caret;
//
// Panel.InputText.Rebuild(CanvasUpdate.Prelayout);
// InputField.ForceLabelUpdate();
// InputField.Rebuild(CanvasUpdate.Prelayout);
//
// OnConsoleInputChanged(InputField.text);
//}
// Autocompletes
}
}

View File

@ -36,7 +36,7 @@ namespace UnityExplorer.UI.IValues
{
if (s == null)
return false;
return s.Length >= UIManager.MAX_INPUTFIELD_CHARS;
}

View File

@ -22,7 +22,7 @@ namespace UnityExplorer.UI
public InputField InputField;
public Text PlaceholderText;
private readonly RectTransform Rect;
public RectTransform Rect;
public string Text
{
@ -30,6 +30,9 @@ namespace UnityExplorer.UI
set => InputField.text = value;
}
public bool ReachedMaxVerts => TextGenerator.vertexCount >= UIManager.MAX_TEXT_VERTS;
public TextGenerator TextGenerator => InputField.cachedInputTextGenerator;
private bool updatedWanted;
private void OnInputChanged(string value)
@ -41,7 +44,8 @@ namespace UnityExplorer.UI
{
if (updatedWanted)
{
LayoutRebuilder.ForceRebuildLayoutImmediate(Rect);
//LayoutRebuilder.ForceRebuildLayoutImmediate(Rect);
LayoutRebuilder.MarkLayoutForRebuild(Rect);
OnValueChanged?.Invoke(InputField.text);
updatedWanted = false;

View File

@ -18,7 +18,8 @@ namespace UnityExplorer.UI.Panels
public override int MinWidth => 400;
public override int MinHeight => 300;
public InputFieldRef InputField { get; private set; }
public InputFieldScroller InputScroll { get; private set; }
public InputFieldRef Input => InputScroll.InputField;
public Text InputText { get; private set; }
public Text HighlightText { get; private set; }
@ -37,19 +38,20 @@ namespace UnityExplorer.UI.Panels
public void UseSuggestion(string suggestion)
{
string input = InputField.Text;
string input = Input.Text;
input = input.Insert(LastCaretPosition, suggestion);
InputField.Text = input;
Input.Text = input;
m_desiredCaretFix = LastCaretPosition += suggestion.Length;
var color = InputField.InputField.selectionColor;
var color = Input.InputField.selectionColor;
color.a = 0f;
InputField.InputField.selectionColor = color;
Input.InputField.selectionColor = color;
}
private void InvokeOnValueChanged(string value)
{
// Todo show a label instead of just logging
if (value.Length == UIManager.MAX_INPUTFIELD_CHARS)
ExplorerCore.LogWarning($"Reached maximum InputField character length! ({UIManager.MAX_INPUTFIELD_CHARS})");
@ -66,23 +68,23 @@ namespace UnityExplorer.UI.Panels
{
if (!m_fixWaiting)
{
EventSystem.current.SetSelectedGameObject(InputField.UIRoot, null);
EventSystem.current.SetSelectedGameObject(InputScroll.UIRoot, null);
m_fixWaiting = true;
}
else
{
InputField.InputField.caretPosition = m_desiredCaretFix;
InputField.InputField.selectionFocusPosition = m_desiredCaretFix;
var color = InputField.InputField.selectionColor;
Input.InputField.caretPosition = m_desiredCaretFix;
Input.InputField.selectionFocusPosition = m_desiredCaretFix;
var color = Input.InputField.selectionColor;
color.a = m_defaultInputFieldAlpha;
InputField.InputField.selectionColor = color;
Input.InputField.selectionColor = color;
m_fixWaiting = false;
m_desiredCaretFix = -1;
}
}
else if (InputField.InputField.caretPosition > 0)
LastCaretPosition = InputField.InputField.caretPosition;
else if (Input.InputField.caretPosition > 0)
LastCaretPosition = Input.InputField.caretPosition;
}
// Saving
@ -150,14 +152,14 @@ namespace UnityExplorer.UI.Panels
int fontSize = 16;
var inputObj = UIFactory.CreateSrollInputField(this.content, "ConsoleInput", CSConsole.STARTUP_TEXT, out var inputScroller, fontSize);
InputField = inputScroller.InputField;
m_defaultInputFieldAlpha = InputField.InputField.selectionColor.a;
InputField.OnValueChanged += InvokeOnValueChanged;
InputScroll = inputScroller;
m_defaultInputFieldAlpha = Input.InputField.selectionColor.a;
Input.OnValueChanged += InvokeOnValueChanged;
var placeHolderText = InputField.PlaceholderText;
var placeHolderText = Input.PlaceholderText;
placeHolderText.fontSize = fontSize;
InputText = InputField.InputField.textComponent;
InputText = Input.InputField.textComponent;
InputText.supportRichText = false;
InputText.color = new Color(1, 1, 1, 0.65f);

View File

@ -58,6 +58,7 @@ namespace UnityExplorer.UI
internal static readonly Color disabledButtonColor = new Color(0.25f, 0.25f, 0.25f);
public const int MAX_INPUTFIELD_CHARS = 16000;
public const int MAX_TEXT_VERTS = 65000;
public static UIPanel GetPanel(Panels panel)
{

View File

@ -25,6 +25,8 @@ namespace UnityExplorer.UI.Utility
}
}
public Action OnScroll;
internal AutoSliderScrollbar Slider;
internal InputFieldRef InputField;
@ -52,25 +54,40 @@ namespace UnityExplorer.UI.Utility
internal bool m_wantJumpToBottom;
private float m_desiredContentHeight;
private float lastContentPosition;
private float lastViewportHeight;
public override void Update()
{
if (this.ContentRect.localPosition.y != lastContentPosition)
{
lastContentPosition = ContentRect.localPosition.y;
OnScroll?.Invoke();
}
if (ViewportRect.rect.height != lastViewportHeight)
{
lastViewportHeight = ViewportRect.rect.height;
m_updateWanted = true;
}
if (m_updateWanted)
{
m_updateWanted = false;
ProcessInputText();
}
float desiredHeight = Math.Max(m_desiredContentHeight, ViewportRect.rect.height);
float desiredHeight = Math.Max(m_desiredContentHeight, ViewportRect.rect.height);
if (ContentRect.rect.height < desiredHeight)
{
ContentRect.sizeDelta = new Vector2(0, desiredHeight);
this.Slider.UpdateSliderHandle();
}
else if (ContentRect.rect.height > desiredHeight)
{
ContentRect.sizeDelta = new Vector2(0, desiredHeight);
this.Slider.UpdateSliderHandle();
if (ContentRect.rect.height < desiredHeight)
{
ContentRect.sizeDelta = new Vector2(0, desiredHeight);
this.Slider.UpdateSliderHandle();
}
else if (ContentRect.rect.height > desiredHeight)
{
ContentRect.sizeDelta = new Vector2(0, desiredHeight);
this.Slider.UpdateSliderHandle();
}
}
if (m_wantJumpToBottom)
@ -100,6 +117,9 @@ namespace UnityExplorer.UI.Utility
var textGen = InputField.InputField.textComponent.cachedTextGeneratorForLayout;
m_desiredContentHeight = textGen.GetPreferredHeight(m_lastText, texGenSettings) + 10;
// TODO more intelligent jump.
// We can detect if the caret is outside the viewport area.
// jump to bottom
if (InputField.InputField.caretPosition == InputField.Text.Length
&& InputField.Text.Length > 0