@Override
  public @NotNull ConfigurableHit getConfigurables(@NotNull List<? extends ConfigurableGroup> groups,
                                                   DocumentEvent.EventType type,
                                                   @Nullable Set<? extends Configurable> previouslyFiltered,
                                                   @NotNull String option,
                                                   @Nullable Project project) {
    if (previouslyFiltered == null || previouslyFiltered.isEmpty()) {
      previouslyFiltered = null;
    }

    String optionToCheck = Strings.toLowerCase(option.trim());

    ConfigurableHit foundByPath = findGroupsByPath(groups, optionToCheck);
    if (foundByPath != null) {
      return foundByPath;
    }

    Set<Configurable> effectiveConfigurables = new LinkedHashSet<>();
    if (previouslyFiltered == null) {
      for (ConfigurableGroup group : groups) {
        SearchUtilKt.processExpandedGroups(group, effectiveConfigurables);
      }
    }
    else {
      effectiveConfigurables.addAll(previouslyFiltered);
    }

    Set<Configurable> nameHits = new LinkedHashSet<>();
    Set<Configurable> nameFullHits = new LinkedHashSet<>();

    Set<String> options = getProcessedWordsWithoutStemming(optionToCheck);
    if (options.isEmpty()) {
      for (Configurable each : effectiveConfigurables) {
        if (each.getDisplayName() != null) {
          nameHits.add(each);
          nameFullHits.add(each);
        }
      }
    }
    else {
      for (Configurable each : effectiveConfigurables) {
        if (each.getDisplayName() == null) {
          continue;
        }
        final String displayName = Strings.toLowerCase(each.getDisplayName());
        if (displayName.contains(optionToCheck)) {
          nameFullHits.add(each);
          nameHits.add(each);
        }
      }
    }

    // operate with substring
    Set<String> descriptionOptions = new HashSet<>();
    if (options.isEmpty()) {
      String[] components = WORD_SEPARATOR_CHARS.split(optionToCheck);
      if (components.length > 0) {
        Collections.addAll(descriptionOptions, components);
      }
      else {
        descriptionOptions.add(option);
      }
    }
    else {
      descriptionOptions.addAll(options);
    }

    Set<String> foundIds = findConfigurablesByDescriptions(descriptionOptions);
    if (foundIds == null) {
      return new ConfigurableHit(nameHits, nameFullHits, Collections.emptySet(), option);
    }

    List<Configurable> contentHits = filterById(effectiveConfigurables, foundIds);

    if (type == DocumentEvent.EventType.CHANGE && previouslyFiltered != null && effectiveConfigurables.size() == contentHits.size()) {
      return getConfigurables(groups, DocumentEvent.EventType.CHANGE, null, option, project);
    }
    return new ConfigurableHit(nameHits, nameFullHits, new LinkedHashSet<>(contentHits), option);
  }
@Override
  public @NotNull ConfigurableHit getConfigurables(@NotNull List<? extends ConfigurableGroup> groups,
                                                   DocumentEvent.EventType type,
                                                   @Nullable Set<? extends Configurable> previouslyFiltered,
                                                   @NotNull String option,
                                                   @Nullable Project project)