Repository: microsoft/PowerToys
File: src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Commands/MainListPage.cs (C#)

Code before:
        lock (commands)
        {
            UpdateFallbacks(newSearch, commands.ToImmutableArray());

            // Cleared out the filter text? easy. Reset _filteredItems, and bail out.
            if (string.IsNullOrEmpty(newSearch))
            {
                _filteredItems = null;
                RaiseItemsChanged(commands.Count);
                return;
            }

            // If the new string doesn't start with the old string, then we can't
            // re-use previous results. Reset _filteredItems, and keep er moving.
            if (!newSearch.StartsWith(oldSearch, StringComparison.CurrentCultureIgnoreCase))
            {
                _filteredItems = null;
            }

            // If we don't have any previous filter results to work with, start
            // with a list of all our commands & apps.
            if (_filteredItems == null)
            {
                _filteredItems = commands;

                if (_tlcManager.CommandProviders.Any(static t => t is { Id: AllAppsCommandProvider.WellKnownId, IsActive: true }))
                {
                    IEnumerable<IListItem> apps = AllAppsCommandProvider.Page.GetItems();
                    _filteredItems = _filteredItems.Concat(apps);
                }
            }

            // Produce a list of everything that matches the current filter.
            _filteredItems = ListHelpers.FilterList<IListItem>(_filteredItems, SearchText, ScoreTopLevelItem);
            RaiseItemsChanged(_filteredItems.Count());
        }
    }

    private void UpdateFallbacks(string newSearch, IReadOnlyList<TopLevelViewModel> commands)
    {
        // fire and forget
        _ = Task.Run(() =>
        {
            var needsToUpdate = false;

            foreach (var command in commands)
            {
                var changedVisibility = command.SafeUpdateFallbackTextSynchronous(newSearch);
                needsToUpdate = needsToUpdate || changedVisibility;
            }


Review comment (suggestion):
I've to change this, `_tlcManager.CommandProviders` can be modified by another thread

Code after:
            lock (_tlcManager.TopLevelCommands)
            {
                return _tlcManager
                    .TopLevelCommands
                    .Where(tlc => !string.IsNullOrEmpty(tlc.Title))
                    .ToArray();
            }
        }
        else
        {
            lock (_tlcManager.TopLevelCommands)
            {
                return _filteredItems?.ToArray() ?? [];
            }
        }
    }

    public override void UpdateSearchText(string oldSearch, string newSearch)
    {
        // Handle changes to the filter text here
        if (!string.IsNullOrEmpty(SearchText))
        {
            var aliases = _serviceProvider.GetService<AliasManager>()!;
            if (aliases.CheckAlias(newSearch))
            {
                return;
            }
        }

        var commands = _tlcManager.TopLevelCommands;
        lock (commands)
        {
            UpdateFallbacks(newSearch, commands.ToImmutableArray());

            // Cleared out the filter text? easy. Reset _filteredItems, and bail out.
            if (string.IsNullOrEmpty(newSearch))
            {
                _filteredItems = null;
                RaiseItemsChanged(commands.Count);
                return;
            }

            // If the new string doesn't start with the old string, then we can't
            // re-use previous results. Reset _filteredItems, and keep er moving.
            if (!newSearch.StartsWith(oldSearch, StringComparison.CurrentCultureIgnoreCase))
            {
                _filteredItems = null;
            }

            // If the internal state has changed, reset _filteredItems to reset the list.
            if (_filteredItemsIncludesApps != _includeApps)