Repository: PowerShell/PowerShell
File: src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs (C#)

Code before:
        #endregion Types

        #region Help Topics

        internal static List<CompletionResult> CompleteHelpTopics(CompletionContext context)
        {
            List<CompletionResult> results = new();

            ArrayList helpProviders = context.ExecutionContext.HelpSystem.HelpProviders;
            HelpFileHelpProvider helpFileProvider = null;
            for (int i = helpProviders.Count - 1; i >= 0; i--)
            {
                if (helpProviders[i] is HelpFileHelpProvider provider)
                {
                    helpFileProvider = provider;
                    break;
                }
            }

            Collection<string> filesMatched = MUIFileSearcher.SearchFiles($"{context.WordToComplete}*.help.txt", helpFileProvider.GetExtendedSearchPaths());
            foreach (string path in filesMatched)
            {
                string fileName = Path.GetFileName(path);
                if (fileName.StartsWith("about_", StringComparison.OrdinalIgnoreCase))
                {
                    string topicName = fileName.Substring(0, fileName.LastIndexOf(".help.txt"));
                    results.Add(new CompletionResult(topicName, topicName, CompletionResultType.ParameterValue, topicName));
                }
            }

            return results;
        }

        #endregion Help Topics

        #region Statement Parameters

        internal static List<CompletionResult> CompleteStatementFlags(TokenKind kind, string wordToComplete)
        {
            switch (kind)
            {
                case TokenKind.Switch:

                    Diagnostics.Assert(!string.IsNullOrEmpty(wordToComplete) && wordToComplete[0].IsDash(), "the word to complete should start with '-'");
                    wordToComplete = wordToComplete.Substring(1);
                    bool withColon = wordToComplete.EndsWith(':');
                    wordToComplete = withColon ? wordToComplete.Remove(wordToComplete.Length - 1) : wordToComplete;

                    string enumString = LanguagePrimitives.EnumSingleTypeConverter.EnumValues(typeof(SwitchFlags));
                    string separator = CultureInfo.CurrentUICulture.TextInfo.ListSeparator;
                    string[] enumArray = enumString.Split(separator, StringSplitOptions.RemoveEmptyEntries);

Review comment (suggestion):
```suggestion
                    string topicName = fileName.Substring(0, fileName.Length - ".help.txt".Length);
```

Should always be at the end right? If that's correct we can skip scanning the string.

Code after:
                {
                    results.Add(completion.GetCompletionResult(entry.Key, prefix, suffix));
                }
            }

            results.Sort(static (c1, c2) => string.Compare(c1.ListItemText, c2.ListItemText, StringComparison.OrdinalIgnoreCase));
            return results;
        }

        /// <summary>
        /// Complete a typename.
        /// </summary>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public static IEnumerable<CompletionResult> CompleteType(string typeName)
        {
            // When completing types, we don't care about the runspace, types are visible across the appdomain
            var powershell = (Runspace.DefaultRunspace == null)
                                 ? PowerShell.Create()
                                 : PowerShell.Create(RunspaceMode.CurrentRunspace);

            var helper = new PowerShellExecutionHelper(powershell);
            var executionContext = helper.CurrentPowerShell.Runspace.ExecutionContext;
            return CompleteType(new CompletionContext { WordToComplete = typeName, Helper = helper, ExecutionContext = executionContext });
        }

        internal static List<CompletionResult> CompleteType(CompletionContext context, string prefix = "", string suffix = "")
        {
            var localTypeCache = s_typeCache ?? InitializeTypeCache();

            var results = new List<CompletionResult>();
            var completionTextSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
            var wordToComplete = context.WordToComplete;
            var dots = wordToComplete.Count(static c => c == '.');
            if (dots >= localTypeCache.Length || localTypeCache[dots] == null)
            {
                return results;
            }

            var pattern = WildcardPattern.Get(wordToComplete + "*", WildcardOptions.IgnoreCase);

            foreach (var entry in localTypeCache[dots].Where(e => pattern.IsMatch(e.Key)))
            {
                foreach (var completion in entry.Completions)
                {
                    string namespaceToRemove = GetNamespaceToRemove(context, completion);
                    var completionResult = completion.GetCompletionResult(entry.Key, prefix, suffix, namespaceToRemove);

                    // We might get the same completion result twice. For example, the type cache has:
                    //    DscResource->System.Management.Automation.DscResourceAttribute (from accelerator)
                    //    DscResourceAttribute->System.Management.Automation.DscResourceAttribute (from short type name)