From 70684d140ed85280de1618644b4a0d6e65fef4e4 Mon Sep 17 00:00:00 2001 From: d4vid Date: Sun, 15 Jun 2025 22:03:58 +0200 Subject: [PATCH] Add basic tab completion --- .../ConsoleImprovements.csproj | 3 + .../ConsoleImprovements/manifest.jecs | 4 +- .../src/client/CommandHistoryPatch.cs | 39 +++++++++ .../ConsoleImprovements/src/client/Trie.cs | 87 +++++++++++++++++++ README.md | 3 +- 5 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 ConsoleImprovements/ConsoleImprovements/src/client/Trie.cs diff --git a/ConsoleImprovements/ConsoleImprovements.csproj b/ConsoleImprovements/ConsoleImprovements.csproj index 5a92203..7a624b5 100644 --- a/ConsoleImprovements/ConsoleImprovements.csproj +++ b/ConsoleImprovements/ConsoleImprovements.csproj @@ -44,5 +44,8 @@ $(LogicWorldGameLocation)\Logic_World_Data\Managed\UnityEngine.UI.dll + + $(LogicWorldGameLocation)\Logic_World_Data\Managed\LICC.dll + diff --git a/ConsoleImprovements/ConsoleImprovements/manifest.jecs b/ConsoleImprovements/ConsoleImprovements/manifest.jecs index 1c8938e..1f43c4e 100644 --- a/ConsoleImprovements/ConsoleImprovements/manifest.jecs +++ b/ConsoleImprovements/ConsoleImprovements/manifest.jecs @@ -1,8 +1,8 @@ ID: D4VID_ConsoleImprovements Name: ConsoleImprovements Author: D4VID -Version: 1.1.2 -Priority: 0 +Version: 1.2.0 +Priority: -90 ClientOnly: true Dependencies: - HarmonyForLogicWorld diff --git a/ConsoleImprovements/ConsoleImprovements/src/client/CommandHistoryPatch.cs b/ConsoleImprovements/ConsoleImprovements/src/client/CommandHistoryPatch.cs index ac9945b..62803aa 100644 --- a/ConsoleImprovements/ConsoleImprovements/src/client/CommandHistoryPatch.cs +++ b/ConsoleImprovements/ConsoleImprovements/src/client/CommandHistoryPatch.cs @@ -1,9 +1,11 @@ +using System.Collections; using System.Reflection; using System.Collections.Generic; using EccsLogicWorldAPI.Shared.AccessHelper; using FancyInput; using HarmonyLib; using JimmysUnityUtilities; +using LICC; using LogicLog; using TMPro; using Console = FancyPantsConsole.Console; @@ -17,6 +19,7 @@ namespace ConsoleImprovements.Client { private static LinkedList _history = new LinkedList(); private static LinkedListNode? _command; + private static Trie _commandRegistry = new Trie(); public static bool Prepare(ILogicLogger logger) { _logger = logger; @@ -24,6 +27,21 @@ namespace ConsoleImprovements.Client { // Get access to the rich text string inside the MessageData class _commandInputFieldField = Fields.getPrivate(typeof(Console), "CommandInputField"); + CommandConsole commandConsole = CommandConsole.Current; + // ICommandRegistryInternal + var registry = Fields.getPrivate(typeof(CommandConsole), "CommandRegistry").GetValue(commandConsole); + // CommandRegistry.CommandCollectionByName + var commandCollection = Properties.get(registry, "AllRegisteredCommands").GetValue(registry); + // IEnumerable + var commands = (IEnumerable) Methods.getPublic(commandCollection, "EnumerateAllCommands").Invoke(commandCollection, null)!; + + foreach (var command in commands) { + var nameProperty = Properties.getPublic(command, "Name"); + var hiddenProperty = Properties.getPublic(command, "Hidden"); + if ((bool) hiddenProperty.GetValue(command)!) continue; + _commandRegistry.AddEntry((string) nameProperty.GetValue(command)!); + } + return true; } @@ -65,6 +83,27 @@ namespace ConsoleImprovements.Client { } } + if (RawInput.Tab.DownThisFrame()) { + TMP_InputField? commandInputField = _commandInputFieldField!.GetValue(__instance) as TMP_InputField; + if (commandInputField == null) { + _logger.Error("Cannot get CommandInputField value"); + return true; + } + + string current = commandInputField.text; + string? completed = _commandRegistry.LookupNext(current, out Trie.Node? node); + if (completed != null) { + if (completed == current) { + List commands = node?.CollectChildren(completed)!; + if (commands.Count > 0) { + _logger.Info($"Available commands: {string.Join(", ", commands)}"); + } + } else { + UpdateCommandTextField(__instance, completed); + } + } + } + return true; // Resume original functionality } diff --git a/ConsoleImprovements/ConsoleImprovements/src/client/Trie.cs b/ConsoleImprovements/ConsoleImprovements/src/client/Trie.cs new file mode 100644 index 0000000..be60748 --- /dev/null +++ b/ConsoleImprovements/ConsoleImprovements/src/client/Trie.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ConsoleImprovements.Client { + + /// + /// A crude implementation of the trie data structure for fast lookups + /// + public class Trie { + private readonly Node _root = new Node() { + Children = new Dictionary() + }; + + /// + /// Add a new string entry to the structure + /// + public void AddEntry(string str) { + Node current = _root; + foreach (char ch in str.ToLower()) { + if (!current.Children.TryGetValue(ch, out Node? next)) { + next = new Node(); + current.Children[ch] = next; + } + + current = next; + } + + current.End = true; + } + + /// + /// Look up how the given string may continue + /// + /// The string to base the search on + /// outputs the reached node which is either an end node or has multiple children + /// Continuation of the prefix (including the prefix) + public string? LookupNext(string prefix, out Node? node) { + string lowercase = prefix.ToLower(); + Node current = _root; + foreach (char ch in lowercase) { + if (!current.Children.TryGetValue(ch, out Node? next)) { + node = null; + return null; + } + + current = next; + } + + var commonBuilder = new StringBuilder(lowercase); + while (current.Children.Count == 1) { + if (current.End) { + break; + } + + KeyValuePair single = current.Children.First(); + commonBuilder.Append(single.Key); + current = single.Value; + } + + node = current; + return commonBuilder.ToString(); + } + + public class Node { + public bool End; + public Dictionary Children = new Dictionary(); + + /// + /// Get all possible strings that can be made from the children of this node + /// + /// Pass in the previously obtained string path to this node + public List CollectChildren(string prefix) { + var collected = new List(); + if (End) { + collected.Add(prefix.ToLower()); + } + + foreach ((char ch, Node node) in Children) { + collected.AddRange(node.CollectChildren(prefix + ch)); + } + + return collected; + } + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 7be4be0..36dc6f4 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # Console Improvements Mod -This mod does 2 things: +This mod does 3 things: 1. It removes the `> ` prefix from copied commands 2. Adds a command history that can be cycled using up and down arrow keys +3. Adds tab completion ## Dependencies