Files
OpenRA/OpenRA.Mods.Common/Widgets/Logic/TabCompletionLogic.cs
RoosterDragon 8dec998d8f Fix tab completion to work for all available commands.
Commands are registered in WorldLoaded event handlers, and IngameChatLogic takes all registered commands and provides tab completion. However IngameChatLogic is also created during WorldLoaded via LoadWidgetAtGameStart. No initialization order is enforced between commands and LoadWidgetAtGameStart, so they can appear in any order.

If a command gets registered before LoadWidgetAtGameStart runs, then it will get tab completion. If it gets registered after then no tab completion is available, even though the command can still be used and appears when using '/help'.

To fix this, we allow the tab completion to check for available commands lazily, meaning it will check for available commands every time the tab key is pressed. This means it will always have the full list of commands available regardless of the initialization order.
2022-07-26 16:42:18 +02:00

81 lines
2.0 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2022 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets.Logic
{
public class TabCompletionLogic : ChromeLogic
{
IList<string> candidates = new List<string>();
int currentCandidateIndex = 0;
string lastCompleted;
string prefix;
string suffix;
public IEnumerable<string> Commands { get; set; }
public IList<string> Names { get; set; }
public string Complete(string text)
{
if (string.IsNullOrWhiteSpace(text))
return text;
if (lastCompleted == text && candidates.Count > 0)
{
lastCompleted = prefix + candidates[++currentCandidateIndex % candidates.Count] + suffix;
return lastCompleted;
}
var toComplete = "";
if (text.StartsWith("/") && Commands != null)
{
prefix = "/";
suffix = "";
toComplete = text.Substring(1);
candidates = Commands.Where(x => x.StartsWith(toComplete, StringComparison.InvariantCultureIgnoreCase)).ToList();
}
else if (Names != null)
{
var oneWord = text.Contains(' ');
if (oneWord)
{
prefix = text.Substring(0, text.LastIndexOf(' ') + 1);
suffix = "";
toComplete = text.Substring(prefix.Length);
}
else
{
prefix = "";
suffix = ": ";
toComplete = text;
}
candidates = Names.Where(x => x.StartsWith(toComplete, StringComparison.InvariantCultureIgnoreCase)).ToList();
}
else
return text;
currentCandidateIndex = 0;
if (candidates.Count == 0)
return text;
lastCompleted = prefix + candidates[currentCandidateIndex] + suffix;
return lastCompleted;
}
}
}