private static AutocompletionContextResult FindAutocompletionContext(IConsoleInput consoleInput) { var result = new AutocompletionContextResult { StartIndex = 0 }; for (int i = Math.Min(consoleInput.CaretIndex, consoleInput.Length - 1); i >= 0; i--) { if (consoleInput[i] == FunctionEndSymbol) { result.Context = AutocompletionContext.Regular; break; } if (consoleInput[i] == FunctionStartSymbol) { result.Context = AutocompletionContext.Method; result.StartIndex = i + 1; break; } } return(result); }
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; } } }