@Override
      protected @NotNull SearchResultPanel createSearchPanel(@NotNull Consumer<? super PluginsGroupComponent> selectionListener) {
        SearchUpDownPopupController marketplaceController = new SearchUpDownPopupController(mySearchTextField) {
          @Override
          protected @NotNull List<String> getAttributes() {
            List<String> attributes = new ArrayList<>();
            attributes.add(SearchWords.TAG.getValue());
            attributes.add(SearchWords.SORT_BY.getValue());
            attributes.add(SearchWords.VENDOR.getValue());
            if (!UpdateSettings.getInstance().getPluginHosts().isEmpty()) {
              attributes.add(SearchWords.REPOSITORY.getValue());
            }
            attributes.add(SearchWords.STAFF_PICKS.getValue());
            attributes.add(SearchWords.SUGGESTED.getValue());
            if (getPluginsViewCustomizer() != NoOpPluginsViewCustomizer.INSTANCE) {
              attributes.add(SearchWords.INTERNAL.getValue());
            }
            return attributes;
          }

          @Override
          protected @Nullable List<String> getValues(@NotNull String attribute) {
            SearchWords word = SearchWords.find(attribute);
            if (word == null) return null;
            return switch (word) {
              case TAG -> {
                if (myTagsSorted == null || myTagsSorted.isEmpty()) {
                  Set<String> allTags = new HashSet<>();
                  for (PluginNode descriptor : CustomPluginRepositoryService.getInstance().getCustomRepositoryPlugins()) {
                    List<String> tags = descriptor.getTags();
                    if (tags != null && !tags.isEmpty()) {
                      allTags.addAll(tags);
                    }
                  }
                  try {
                    ProcessIOExecutorService.INSTANCE.submit(() -> {
                      allTags.addAll(myMarketplaceRequests.getMarketplaceTagsSupplier().get());
                    }).get();
                  }
                  catch (InterruptedException | ExecutionException e) {
                    LOG.error("Error while getting tags from marketplace", e);
                  }
                  myTagsSorted = ContainerUtil.sorted(allTags, String::compareToIgnoreCase);
                }
                yield myTagsSorted;
              }
              case SORT_BY -> ContainerUtil.map(
                Arrays.asList(SortBy.DOWNLOADS, SortBy.NAME, SortBy.RATING, SortBy.UPDATE_DATE),
                sort -> sort.getQuery()
              );
              case VENDOR -> {
                if (myVendorsSorted == null || myVendorsSorted.isEmpty()) {
                  LinkedHashSet<String> vendors = new LinkedHashSet<>();
                  try {
                    ProcessIOExecutorService.INSTANCE.submit(() -> {
                      vendors.addAll(myMarketplaceRequests.getMarketplaceVendorsSupplier().get());
                    }).get();
                  }
                  catch (InterruptedException | ExecutionException e) {
                    LOG.error("Error while getting vendors from marketplace", e);
                  }
                  myVendorsSorted = new ArrayList<>(vendors);
                }
                yield myVendorsSorted;
              }
              case REPOSITORY -> UpdateSettings.getInstance().getPluginHosts();
              case INTERNAL, SUGGESTED, STAFF_PICKS -> null;
            };
          }

          @Override
          protected void showPopupForQuery() {
            showSearchPanel(mySearchTextField.getText());
          }

          @Override
          protected void handleEnter() {
            if (!mySearchTextField.getText().isEmpty()) {
              handleTrigger("marketplace.suggest.popup.enter");
            }
          }

          @Override
          protected void handlePopupListFirstSelection() {
            handleTrigger("marketplace.suggest.popup.select");
          }

          private void handleTrigger(@NonNls String key) {
            if (myPopup != null && myPopup.type == SearchPopup.Type.SearchQuery) {
              FeatureUsageTracker.getInstance().triggerFeatureUsed(key);
            }
          }
        };

        myMarketplaceSortByGroup = new DefaultActionGroup();

        for (SortBy option : SortBy.getEntries()) {
          myMarketplaceSortByGroup.addAction(new MarketplaceSortByAction(option));
        }

        myMarketplaceSortByAction = new LinkComponent() {
          @Override
          protected boolean isInClickableArea(Point pt) {
            return true;
          }

          @Override
          public AccessibleContext getAccessibleContext() {
            if (accessibleContext == null) {
              accessibleContext = new AccessibleLinkComponent();
            }
            return accessibleContext;
          }

          protected class AccessibleLinkComponent extends AccessibleLinkLabel {
            @Override
            public AccessibleRole getAccessibleRole() {
              return AccessibleRole.COMBO_BOX;
            }
          }
        };
        myMarketplaceSortByAction.setIcon(new Icon() {
          @Override
          public void paintIcon(Component c, Graphics g, int x, int y) {
            getIcon().paintIcon(c, g, x, y + 1);
          }

          @Override
          public int getIconWidth() {
            return getIcon().getIconWidth();
          }

          @Override
          public int getIconHeight() {
            return getIcon().getIconHeight();
          }

          private static @NotNull Icon getIcon() {
            return AllIcons.General.ButtonDropTriangle;
          }
        }); // TODO: icon
        myMarketplaceSortByAction.setPaintUnderline(false);
        myMarketplaceSortByAction.setIconTextGap(JBUIScale.scale(4));
        myMarketplaceSortByAction.setHorizontalTextPosition(SwingConstants.LEFT);
        myMarketplaceSortByAction.setForeground(PluginsGroupComponent.SECTION_HEADER_FOREGROUND);

        //noinspection unchecked
        myMarketplaceSortByAction.setListener(
          (component, __) -> showRightBottomPopup(component.getParent().getParent(), IdeBundle.message("plugins.configurable.sort.by"),
                                                  myMarketplaceSortByGroup), null);

        DumbAwareAction.create(event -> myMarketplaceSortByAction.doClick())
          .registerCustomShortcutSet(KeyEvent.VK_DOWN, 0, myMarketplaceSortByAction);

        myMarketplaceSortByCallback = updateAction -> {
          MarketplaceSortByAction removeAction = null;
          MarketplaceSortByAction addAction = null;

          if (updateAction.myState) {
            for (AnAction action : myMarketplaceSortByGroup.getChildren(ActionManager.getInstance())) {
              MarketplaceSortByAction sortByAction = (MarketplaceSortByAction)action;
              if (sortByAction != updateAction && sortByAction.myState) {
                sortByAction.myState = false;
                removeAction = sortByAction;
                break;
              }
            }
            addAction = updateAction;
          }
          else {
            if (updateAction.myOption == SortBy.RELEVANCE) {
              updateAction.myState = true;
              return;
            }

            for (AnAction action : myMarketplaceSortByGroup.getChildren(ActionManager.getInstance())) {
              MarketplaceSortByAction sortByAction = (MarketplaceSortByAction)action;
              if (sortByAction.myOption == SortBy.RELEVANCE) {
                sortByAction.myState = true;
                break;
              }
            }

            removeAction = updateAction;
          }

          List<String> queries = new ArrayList<>();
          new SearchQueryParser.Marketplace(mySearchTextField.getText()) { // FIXME: it's unused - why hasn't it been removed?
            @Override
            protected void addToSearchQuery(@NotNull String query) {
              queries.add(query);
            }

            @Override
            protected void handleAttribute(@NotNull String name, @NotNull String value) {
              queries.add(name + SearchQueryParser.wrapAttribute(value));
            }
          };
          if (removeAction != null) {
            String query = removeAction.getQuery();
            if (query != null) {
              queries.remove(query);
            }
          }
          if (addAction != null) {
            String query = addAction.getQuery();
            if (query != null) {
              queries.add(query);
            }
          }

          String query = StringUtil.join(queries, " ");
          mySearchTextField.setTextIgnoreEvents(query);
          if (query.isEmpty()) {
            myMarketplaceTab.hideSearchPanel();
          }
          else {
            myMarketplaceTab.showSearchPanel(query);
          }
        };

        MultiSelectionEventHandler eventHandler = new MultiSelectionEventHandler();
        marketplaceController.setSearchResultEventHandler(eventHandler);

        PluginsGroupComponentWithProgress panel = new PluginsGroupComponentWithProgress(eventHandler) {
          @Override
          protected @NotNull ListPluginComponent createListComponent(@NotNull IdeaPluginDescriptor descriptor,
                                                                     @NotNull PluginsGroup group) {
            return new ListPluginComponent(myPluginModel, descriptor, group, mySearchListener, true);
          }
        };

        panel.setSelectionListener(selectionListener);
        registerCopyProvider(panel);

        Project project = ProjectUtil.getActiveProject();

        myMarketplaceSearchPanel =
          new SearchResultPanel(marketplaceController, panel, true, 0, 0) {
            @Override
            protected void handleQuery(@NotNull String query, @NotNull PluginsGroup result) {
              int searchIndex = PluginManagerUsageCollector.updateAndGetSearchIndex();
              try {
                SearchQueryParser.Marketplace parser = new SearchQueryParser.Marketplace(query);

                Map<IdeaPluginDescriptor, Double> pluginToScore = null;

                if (parser.internal) {
                  PluginsViewCustomizer.PluginsGroupDescriptor groupDescriptor =
                    getPluginsViewCustomizer().getInternalPluginsGroupDescriptor();
                  if (groupDescriptor != null) {
                    if (parser.searchQuery == null) {
                      result.descriptors.addAll(groupDescriptor.getPlugins());
                    }
                    else {
                      for (IdeaPluginDescriptor pluginDescriptor : groupDescriptor.getPlugins()) {
                        if (StringUtil.containsIgnoreCase(pluginDescriptor.getName(), parser.searchQuery)) {
                          result.descriptors.add(pluginDescriptor);
                        }
                      }
                    }
                    ContainerUtil.removeDuplicates(result.descriptors);
                    result.sortByName();
                    return;
                  }
                }

                Map<String, List<PluginNode>> customRepositoriesMap =
                  CustomPluginRepositoryService.getInstance().getCustomRepositoryPluginMap();


                if (parser.suggested && project != null) {
                  result.descriptors.addAll(PluginsAdvertiserStartupActivityKt.findSuggestedPlugins(project, customRepositoriesMap));
                }
                else if (!parser.repositories.isEmpty()) {
                  for (String repository : parser.repositories) {
                    List<PluginNode> descriptors = customRepositoriesMap.get(repository);
                    if (descriptors == null) {
                      continue;
                    }
                    if (parser.searchQuery == null) {
                      result.descriptors.addAll(descriptors);
                    }
                    else {
                      for (PluginNode descriptor : descriptors) {
                        if (StringUtil.containsIgnoreCase(descriptor.getName(), parser.searchQuery)) {
                          result.descriptors.add(descriptor);
                        }
                      }
                    }
                  }
                  ContainerUtil.removeDuplicates(result.descriptors);
                  result.sortByName();
                }
                else {
                  List<PluginNode> pluginsFromMarketplace =
                    myMarketplaceRequests.searchPlugins(parser.getUrlQuery(), 10000, true);
                  // compare plugin versions between marketplace & custom repositories
                  List<PluginNode> customPlugins = ContainerUtil.flatten(customRepositoriesMap.values());
                  Collection<PluginNode> plugins = RepositoryHelper.mergePluginsFromRepositories(pluginsFromMarketplace,
                                                                                                 customPlugins,
                                                                                                 false);
                  result.descriptors.addAll(0, plugins);

                  if (parser.searchQuery != null) {
                    List<PluginNode> descriptors = ContainerUtil.filter(customPlugins,
                                                                        descriptor -> StringUtil.containsIgnoreCase(descriptor.getName(),
                                                                                                                    parser.searchQuery));
                    result.descriptors.addAll(0, descriptors);
                  }

                  ContainerUtil.removeDuplicates(result.descriptors);

                  final var localRanker = MarketplaceLocalRanker.getInstanceIfEnabled();
                  if (localRanker != null) {
                    pluginToScore = localRanker.rankPlugins(parser, result.descriptors);
                  }

                  if (!result.descriptors.isEmpty()) {
                    String title = IdeBundle.message("plugin.manager.action.label.sort.by.1");

                    for (AnAction action : myMarketplaceSortByGroup.getChildren(ActionManager.getInstance())) {
                      MarketplaceSortByAction sortByAction = (MarketplaceSortByAction)action;
                      sortByAction.setState(parser);
                      if (sortByAction.myState) {
                        title = IdeBundle.message("plugin.manager.action.label.sort.by",
                                                  sortByAction.myOption.getPresentableNameSupplier().get());
                      }
                    }

                    myMarketplaceSortByAction.setText(title);
                    result.addRightAction(myMarketplaceSortByAction);


                    Collection<IdeaPluginDescriptor> updates = PluginUpdatesService.getUpdates();
                    if (!ContainerUtil.isEmpty(updates)) {
                      myPostFillGroupCallback = () -> {
                        applyUpdates(myPanel, updates);
                        selectionListener.accept(myMarketplacePanel);
                        selectionListener.accept(myMarketplaceSearchPanel.getPanel());
                      };
                    }
                  }
                }

                PluginManagerUsageCollector.performMarketplaceSearch(
                  ProjectUtil.getActiveProject(), parser, result.descriptors, searchIndex, pluginToScore);
              }
              catch (IOException e) {
                LOG.info(e);
                ApplicationManager.getApplication().invokeLater(
                  () -> myPanel.getEmptyText()
                    .setText(IdeBundle.message("plugins.configurable.search.result.not.loaded"))
                    .appendSecondaryText(
                      IdeBundle.message("plugins.configurable.check.internet"), StatusText.DEFAULT_ATTRIBUTES, null), ModalityState.any()
                );
              }
            }
          };

        return myMarketplaceSearchPanel;
      }
@Override
      protected @NotNull SearchResultPanel createSearchPanel(@NotNull Consumer<? super PluginsGroupComponent> selectionListener)