/// <summary>
        /// Finds the next command for auto completion
        /// </summary>
        /// <param name="partialCommand">The partial command being completed</param>
        /// <param name="lastResult">The last result returned. Null to get the first match</param>
        /// <param name="registries">The list of registries to search for matches</param>
        /// <returns>The next command matching the partial string</returns>
        public static string FindNextCommand(ReadOnlySpan <char> partialCommand, ReadOnlySpan <char> lastResult, IEnumerable <TerminalRegistry> registries)
        {         //****************************************
            ReadOnlySpan <char> CommandText, PartialText;
            ReadOnlySpan <char> Prefix       = default;
            ReadOnlySpan <char> InstanceName = default;

            int CharIndex;

            TerminalTypeSet?     TypeSet = null;
            TerminalTypeInstance?TypeInstance;

            var PartialMatches = new List <string>();

            //****************************************

            if (partialCommand.StartsWith("help ".AsSpan(), StringComparison.InvariantCultureIgnoreCase))
            {
                partialCommand = partialCommand.Slice(5);

                Prefix = "Help ".AsSpan();
            }

            //****************************************

            // Find the first word (split on a space)
            CharIndex = partialCommand.IndexOf(' ');

            // If there's a space, we're parsing an Instance Type and optional Instance Name, with a partial Command/Variable
            if (CharIndex != -1)
            {
                CommandText = partialCommand.Slice(0, CharIndex);
                PartialText = partialCommand.Slice(CharIndex + 1);

                CharIndex = CommandText.IndexOf('.');

                // Split into Type and Name if necessary
                if (CharIndex != -1)
                {
                    InstanceName = CommandText.Slice(CharIndex + 1);
                    CommandText  = CommandText.Slice(0, CharIndex);
                }

                foreach (var Registry in registries)
                {
                    if (Registry.TryGetTypeSet(CommandText, out TypeSet))
                    {
                        break;
                    }
                }

                // If the instance type doesn't match, return the partial command as is
                if (TypeSet == null)
                {
                    return(Prefix.Concat(partialCommand));
                }

                if (InstanceName == null)
                {
                    TypeInstance = TypeSet.Default;
                    CommandText  = TypeSet.TypeName.AsSpan();
                }
                else
                {
                    if (!TypeSet.TryGetNamedInstance(InstanceName, out TypeInstance))
                    {
                        return(Prefix.Concat(partialCommand));
                    }

                    CommandText = $"{TypeSet.TypeName}.{TypeInstance.Name}".AsSpan();
                }

                // If the instance doesn't exist, return as is
                if (TypeInstance == null)
                {
                    return(Prefix.Concat(partialCommand));
                }

                // Add matching commands
                foreach (var MyCommand in TypeInstance.Type.Commands)
                {
                    if (MyCommand.Name.StartsWith(PartialText, StringComparison.InvariantCultureIgnoreCase))
                    {
                        PartialMatches.Add(CommandText.Concat(" ", MyCommand.Name));
                    }
                }

                // Add matching variables
                foreach (var MyVariable in TypeInstance.Type.Variables)
                {
                    if (MyVariable.Name.StartsWith(PartialText, StringComparison.InvariantCultureIgnoreCase))
                    {
                        PartialMatches.Add(CommandText.Concat(" ", MyVariable.Name));
                    }
                }
            }
            else
            {
                CharIndex = partialCommand.IndexOf('.');

                // If there's a dot, we're parsing an Instance Type, with a partial Instance Name
                if (CharIndex != -1)
                {
                    CommandText = partialCommand.Slice(0, CharIndex);
                    PartialText = partialCommand.Slice(CharIndex + 1);

                    foreach (var MyRegistry in registries)
                    {
                        if (MyRegistry.TryGetTypeSet(CommandText, out TypeSet))
                        {
                            break;
                        }
                    }

                    // If the instance type doesn't match, return the partial command as is
                    if (TypeSet == null)
                    {
                        return(Prefix.Concat(partialCommand));
                    }

                    foreach (var MyInstanceName in TypeSet.Instances)
                    {
                        if (MyInstanceName.StartsWith(PartialText, StringComparison.InvariantCultureIgnoreCase))
                        {
                            PartialMatches.Add(string.Format("{0}.{1}", TypeSet.TypeName, MyInstanceName));
                        }
                    }
                }
                else
                {
                    // No dot, we're parsing a partial Command/Variable/Instance Type
                    foreach (var Registry in registries)
                    {
                        // Add matching commands
                        foreach (var Command in Registry.Commands)
                        {
                            if (Command.Name.StartsWith(partialCommand, StringComparison.InvariantCultureIgnoreCase))
                            {
                                PartialMatches.Add(Command.Name);
                            }
                        }

                        // Add matching variables (with an equals sign, so they can't be the same as commands)
                        foreach (var Variable in Registry.Variables)
                        {
                            if (Variable.Name.StartsWith(partialCommand, StringComparison.InvariantCultureIgnoreCase))
                            {
                                PartialMatches.Add(Variable.Name);
                            }
                        }

                        foreach (var Instance in Registry.DefaultInstances)
                        {
                            foreach (var Command in Instance.Type.Commands)
                            {
                                if (Command.Name.StartsWith(partialCommand, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    PartialMatches.Add(Command.Name);
                                }
                            }

                            // Add matching variables (with an equals sign, so they can't be the same as commands)
                            foreach (var Variable in Instance.Type.Variables)
                            {
                                if (Variable.Name.StartsWith(partialCommand, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    PartialMatches.Add(Variable.Name);
                                }
                            }
                        }

                        // Add matching type sets
                        foreach (var Type in Registry.TypeSets)
                        {
                            // Only add ones that have an instance
                            if (Type.TypeName.StartsWith(partialCommand, StringComparison.InvariantCultureIgnoreCase) && Type.HasInstance)
                            {
                                PartialMatches.Add(Type.TypeName);
                            }
                        }
                    }
                }
            }

            //****************************************

            // Any results?
            if (PartialMatches.Count == 0)
            {
                return("");
            }

            // Sort them, so we can pick the next matching result
            PartialMatches.Sort();

            if (lastResult != null)
            {
                // Find one greater than our last match (user has requested the next one)
                foreach (var NextCommand in PartialMatches)
                {
                    if (NextCommand.AsSpan().CompareTo(lastResult, StringComparison.OrdinalIgnoreCase) > 0)
                    {
                        return(Prefix.Concat(NextCommand));
                    }
                }
                // Nothing greater, go back to the start
            }

            return(Prefix.Concat(PartialMatches[0]));
        }