From 2c5d2285044723985acdbccdd8b0bb033f56270a Mon Sep 17 00:00:00 2001 From: yasirkula Date: Sat, 27 Nov 2021 23:43:29 +0300 Subject: [PATCH] - Command input field autocomplete (via Tab) now remembers the initial text (i.e. 'prefs') and suggests the next matching command at each Tab press (i.e. 'prefs.int', 'prefs.float' and etc.) - Fixed #63 - Log window's CanvasGroup.interactable property doesn't change while switching between popup and log window, resulting in no graphical glitches during the transition - "Auto Focus On Command Input Field" option supports WebGL --- .../IngameDebugConsole.prefab | 2 +- .../Scripts/DebugLogConsole.cs | 27 ++++++++----- .../Scripts/DebugLogManager.cs | 39 +++++++++++++++---- .../Scripts/DebugLogPopup.cs | 2 - package.json | 2 +- 5 files changed, 51 insertions(+), 21 deletions(-) diff --git a/Plugins/IngameDebugConsole/IngameDebugConsole.prefab b/Plugins/IngameDebugConsole/IngameDebugConsole.prefab index 3719f02..f8c24d8 100644 --- a/Plugins/IngameDebugConsole/IngameDebugConsole.prefab +++ b/Plugins/IngameDebugConsole/IngameDebugConsole.prefab @@ -2529,7 +2529,7 @@ CanvasGroup: m_GameObject: {fileID: 183006} m_Enabled: 1 m_Alpha: 0 - m_Interactable: 0 + m_Interactable: 1 m_BlocksRaycasts: 0 m_IgnoreParentGroups: 0 --- !u!1001 &100100000 diff --git a/Plugins/IngameDebugConsole/Scripts/DebugLogConsole.cs b/Plugins/IngameDebugConsole/Scripts/DebugLogConsole.cs index ec1c44e..167eb70 100644 --- a/Plugins/IngameDebugConsole/Scripts/DebugLogConsole.cs +++ b/Plugins/IngameDebugConsole/Scripts/DebugLogConsole.cs @@ -589,22 +589,31 @@ public static void RemoveCommand( MethodInfo method ) } // Returns the first command that starts with the entered argument - public static string GetAutoCompleteCommand( string commandStart ) + public static string GetAutoCompleteCommand( string commandStart, string previousSuggestion ) { - int commandIndex = FindCommandIndex( commandStart ); + int commandIndex = FindCommandIndex( !string.IsNullOrEmpty( previousSuggestion ) ? previousSuggestion : commandStart ); if( commandIndex < 0 ) + { commandIndex = ~commandIndex; + return ( commandIndex < methods.Count && caseInsensitiveComparer.IsPrefix( methods[commandIndex].command, commandStart, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) ) ? methods[commandIndex].command : null; + } - string result = null; - for( int i = commandIndex; i >= 0 && caseInsensitiveComparer.IsPrefix( methods[i].command, commandStart, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ); i-- ) - result = methods[i].command; - - if( result == null ) + // Find the next command that starts with commandStart and is different from previousSuggestion + for( int i = commandIndex + 1; i < methods.Count; i++ ) { - for( int i = commandIndex + 1; i < methods.Count && caseInsensitiveComparer.IsPrefix( methods[i].command, commandStart, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ); i++ ) - result = methods[i].command; + if( caseInsensitiveComparer.Compare( methods[i].command, previousSuggestion, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) == 0 ) + continue; + else if( caseInsensitiveComparer.IsPrefix( methods[i].command, commandStart, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) ) + return methods[i].command; + else + break; } + // Couldn't find a command that follows previousSuggestion and satisfies commandStart, loop back to the beginning of the autocomplete suggestions + string result = null; + for( int i = commandIndex - 1; i >= 0 && caseInsensitiveComparer.IsPrefix( methods[i].command, commandStart, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ); i-- ) + result = methods[i].command; + return result; } diff --git a/Plugins/IngameDebugConsole/Scripts/DebugLogManager.cs b/Plugins/IngameDebugConsole/Scripts/DebugLogManager.cs index 58dff4c..3d3967f 100644 --- a/Plugins/IngameDebugConsole/Scripts/DebugLogManager.cs +++ b/Plugins/IngameDebugConsole/Scripts/DebugLogManager.cs @@ -157,7 +157,7 @@ public class DebugLogManager : MonoBehaviour [Tooltip( "If a log is longer than this limit, it will be truncated. This helps avoid reaching Unity's 65000 vertex limit for UI canvases" )] private int maxLogLength = 10000; -#if UNITY_EDITOR || UNITY_STANDALONE +#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBGL [SerializeField] [Tooltip( "If enabled, on standalone platforms, command input field will automatically be focused (start receiving keyboard input) after opening the console window" )] private bool autoFocusOnCommandInputField = true; @@ -337,6 +337,10 @@ public bool PopupEnabled private int commandInputFieldPrevCaretPos = -1; private int commandInputFieldPrevCaretArgumentIndex = -1; + // Value of the command input field when autocomplete was first requested + private string commandInputFieldAutoCompleteBase; + private bool commandInputFieldAutoCompletedNow; + // Pools for memory efficiency private List pooledLogEntries; private List pooledLogItems; @@ -459,7 +463,7 @@ private void Awake() // Register to UI events commandInputField.onValidateInput += OnValidateCommand; - commandInputField.onValueChanged.AddListener( RefreshCommandSuggestions ); + commandInputField.onValueChanged.AddListener( OnEditCommand ); commandInputField.onEndEdit.AddListener( OnEndEditCommand ); hideButton.onClick.AddListener( HideLogWindow ); clearButton.onClick.AddListener( ClearLogs ); @@ -785,7 +789,6 @@ private void LateUpdate() public void ShowLogWindow() { // Show the log window - logWindowCanvasGroup.interactable = true; logWindowCanvasGroup.blocksRaycasts = true; logWindowCanvasGroup.alpha = 1f; @@ -795,7 +798,7 @@ public void ShowLogWindow() // (in case new entries were intercepted while log window was hidden) recycledListView.OnLogEntriesUpdated( true ); -#if UNITY_EDITOR || UNITY_STANDALONE +#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBGL // Focus on the command input field on standalone platforms when the console is opened if( autoFocusOnCommandInputField ) StartCoroutine( ActivateCommandInputFieldCoroutine() ); @@ -810,7 +813,6 @@ public void ShowLogWindow() public void HideLogWindow() { // Hide the log window - logWindowCanvasGroup.interactable = false; logWindowCanvasGroup.blocksRaycasts = false; logWindowCanvasGroup.alpha = 0f; @@ -832,9 +834,15 @@ private char OnValidateCommand( string text, int charIndex, char addedChar ) { if( !string.IsNullOrEmpty( text ) ) { - string autoCompletedCommand = DebugLogConsole.GetAutoCompleteCommand( text ); - if( !string.IsNullOrEmpty( autoCompletedCommand ) ) + if( string.IsNullOrEmpty( commandInputFieldAutoCompleteBase ) ) + commandInputFieldAutoCompleteBase = text; + + string autoCompletedCommand = DebugLogConsole.GetAutoCompleteCommand( commandInputFieldAutoCompleteBase, text ); + if( !string.IsNullOrEmpty( autoCompletedCommand ) && autoCompletedCommand != text ) + { + commandInputFieldAutoCompletedNow = true; commandInputField.text = autoCompletedCommand; + } } return '\0'; @@ -1027,6 +1035,10 @@ public void SetSnapToBottom( bool snapToBottom ) // Make sure the scroll bar of the scroll rect is adjusted properly internal void ValidateScrollPosition() { + // When scrollbar is snapped to the very bottom of the scroll view, sometimes OnScroll alone doesn't work + if( logItemsScrollRect.verticalNormalizedPosition <= Mathf.Epsilon ) + logItemsScrollRect.verticalNormalizedPosition = 0.0001f; + logItemsScrollRect.OnScroll( nullPointerEventData ); } @@ -1241,6 +1253,17 @@ private void RefreshCommandSuggestions( string command ) } } + // Command input field's text has changed + private void OnEditCommand( string command ) + { + RefreshCommandSuggestions( command ); + + if( !commandInputFieldAutoCompletedNow ) + commandInputFieldAutoCompleteBase = null; + else // This change was caused by autocomplete + commandInputFieldAutoCompletedNow = false; + } + // Command input field has lost focus private void OnEndEditCommand( string command ) { @@ -1525,7 +1548,7 @@ private void CheckScreenCutout() #endif } -#if UNITY_EDITOR || UNITY_STANDALONE +#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBGL private IEnumerator ActivateCommandInputFieldCoroutine() { // Waiting 1 frame before activating commandInputField ensures that the toggleKey isn't captured by it diff --git a/Plugins/IngameDebugConsole/Scripts/DebugLogPopup.cs b/Plugins/IngameDebugConsole/Scripts/DebugLogPopup.cs index 733f12e..dbbcca9 100644 --- a/Plugins/IngameDebugConsole/Scripts/DebugLogPopup.cs +++ b/Plugins/IngameDebugConsole/Scripts/DebugLogPopup.cs @@ -133,7 +133,6 @@ public void OnPointerClick( PointerEventData data ) // Hides the log window and shows the popup public void Show() { - canvasGroup.interactable = true; canvasGroup.blocksRaycasts = true; canvasGroup.alpha = 1f; @@ -147,7 +146,6 @@ public void Show() // Hide the popup public void Hide() { - canvasGroup.interactable = false; canvasGroup.blocksRaycasts = false; canvasGroup.alpha = 0f; diff --git a/package.json b/package.json index e10a414..4f8ca68 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "com.yasirkula.ingamedebugconsole", "displayName": "In-game Debug Console", - "version": "1.5.1", + "version": "1.5.2", "documentationUrl": "https://github.com/yasirkula/UnityIngameDebugConsole", "changelogUrl": "https://github.com/yasirkula/UnityIngameDebugConsole/releases", "licensesUrl": "https://github.com/yasirkula/UnityIngameDebugConsole/blob/master/LICENSE.txt",