private Stack <string> FindAccessorChain(IConsoleInput consoleInput, int chainEndIndex)
        {
            _accessorChain.Clear();
            while (true)
            {
                int indices    = FindBoundaryIndices(consoleInput, chainEndIndex);
                int startIndex = indices & 0xff;
                int length     = indices >> 16;

                string chainLink = consoleInput.Substring(startIndex, length).Trim();
                _accessorChain.Push(chainLink);

                int previousLinkEndIndex = FindPreviousLinkEndIndex(consoleInput, startIndex - 1);
                if (chainEndIndex < 0)
                {
                    return(_accessorChain);
                }

                AutocompletionType chainType = FindAutocompleteType(consoleInput, startIndex);
                if (chainType == AutocompletionType.Accessor)
                {
                    chainEndIndex = previousLinkEndIndex;
                    continue;
                }
                break;
            }
            return(_accessorChain);
        }
        public void Autocomplete(IConsoleInput consoleInput, bool isNextValue)
        {
            // Which context we in, method or regular.
            AutocompletionContextResult contextResult = FindAutocompletionContext(consoleInput);
            Type typeToPrefer = null;

            if (contextResult.Context == AutocompletionContext.Method)
            {
                long newCommandLength_whichParamAt_newStartIndex_numParams = FindParamIndexNewStartIndexAndNumParams(consoleInput, contextResult.StartIndex);
                int  chainEndIndex = FindPreviousLinkEndIndex(consoleInput, contextResult.StartIndex - 1);
                if (chainEndIndex >= 0)
                {
                    Stack <string> accessorChain = FindAccessorChain(consoleInput, chainEndIndex);
                    Member         lastChainLink = FindLastChainLinkMember(accessorChain);
                    if (lastChainLink?.ParameterInfo != null)
                    {
                        var             numParams = (int)(newCommandLength_whichParamAt_newStartIndex_numParams & 0xff);
                        ParameterInfo[] overload  = null;
                        for (int i = numParams; i <= lastChainLink.ParameterInfo.Max(x => x.Length); i++)
                        {
                            ParameterInfo[] overloadCandidate = lastChainLink.ParameterInfo.FirstOrDefault(x => x.Length == i);
                            if (overloadCandidate != null)
                            {
                                overload = overloadCandidate;
                                break;
                            }
                        }
                        if (overload != null)
                        {
                            var paramIndex = newCommandLength_whichParamAt_newStartIndex_numParams >> 32 & 0xff;
                            if (overload.Length > paramIndex)
                            {
                                typeToPrefer = overload[paramIndex].ParameterType;
                            }
                        }
                    }
                }
            }

            int                autocompleteBoundaryIndices = FindBoundaryIndices(consoleInput, consoleInput.CaretIndex);
            int                startIndex     = autocompleteBoundaryIndices & 0xff;
            int                length         = autocompleteBoundaryIndices >> 16;
            string             command        = consoleInput.Substring(startIndex, length);
            AutocompletionType completionType = FindAutocompleteType(consoleInput, startIndex);

            if (completionType == AutocompletionType.Regular)
            {
                if (typeToPrefer == null || !string.IsNullOrWhiteSpace(command))
                {
                    FindAutocompleteForEntries(consoleInput, InstancesAndStatics, command, startIndex, isNextValue);
                }
                else
                {
                    FindAutocompleteForEntries(consoleInput, GetAvailableNamesForType(typeToPrefer), command, startIndex, isNextValue);
                }
            }
            else // Accessor or assignment or method.
            {
                // We also need to find the value for whatever was before the type accessor.
                int chainEndIndex = FindPreviousLinkEndIndex(consoleInput, startIndex - 1);
                if (chainEndIndex < 0)
                {
                    return;
                }

                Stack <string> accessorChain = FindAccessorChain(consoleInput, chainEndIndex);
                Member         lastChainLink = FindLastChainLinkMember(accessorChain);
                // If no types were found, that means we are assigning a new variable.
                // Provide all autocomplete entries in that scenario.
                if (lastChainLink == null)
                {
                    FindAutocompleteForEntries(consoleInput, InstancesAndStatics, command, startIndex, isNextValue);
                    return;
                }

                switch (completionType)
                {
                case AutocompletionType.Accessor:
                    MemberCollection autocompleteValues;
                    if (lastChainLink.IsInstance)
                    {
                        _interpreter.InstanceMembers.TryGetValue(lastChainLink.Type, out autocompleteValues);
                    }
                    else
                    {
                        _interpreter.StaticMembers.TryGetValue(lastChainLink.Type, out autocompleteValues);
                    }
                    if (autocompleteValues == null)
                    {
                        break;
                    }
                    FindAutocompleteForEntries(consoleInput, autocompleteValues.Names, command, startIndex, isNextValue);
                    break;

                case AutocompletionType.Assignment:
                    FindAutocompleteForEntries(
                        consoleInput,
                        GetAvailableNamesForType(lastChainLink.Type),
                        command,
                        startIndex,
                        isNextValue);
                    break;
                }
            }
        }
        private static void FindAutocompleteForEntries(IConsoleInput consoleInput, IList <string> autocompleteEntries,
                                                       string command, int startIndex, bool isNextValue, AutocompletionType completionType)
        {
            int index = autocompleteEntries.IndexOf(x => x.Equals(command, StringComparison.Ordinal));

            if (index == -1 || consoleInput.LastAutocompleteEntry == null)
            {
                consoleInput.LastAutocompleteEntry = command;
            }

            string inputEntry             = consoleInput.LastAutocompleteEntry;
            Func <string, bool> predicate = x => x.StartsWith(inputEntry, StringComparison.Ordinal);
            int firstIndex = autocompleteEntries.IndexOf(predicate);

            if (firstIndex == -1)
            {
                return;
            }
            int lastIndex = autocompleteEntries.LastIndexOf(predicate);

            if (index == -1)
            {
                index = firstIndex - 1;
            }

            if (isNextValue)
            {
                index++;
                if (index > lastIndex)
                {
                    index = firstIndex;
                }
            }
            else
            {
                index--;
                if (index < firstIndex)
                {
                    index = lastIndex;
                }
            }
            string autocompleteValue = autocompleteEntries[index];

            //if (completionType == AutocompletionType.Regular)
            //    autocompleteValue = nameof(ExpandoWrapper.globals) + AccessorSymbol + autocompleteValue;

            SetAutocompleteValue(consoleInput, startIndex, autocompleteValue);
        }