private void suggestCompletion(final boolean selectReplacedText, final boolean isExplicitCall) {
    if (isExplicitCall) {
      myAutopopup = true;
    }

    if (!getField().isFocusOwner()) return;

    final CompletionResult result = new CompletionResult();
    if (myList != null && myCurrentCompletion != null) {
      int index = myList.getSelectedIndex();
      if (index >= 0 && index < myList.getModel().getSize()) {
        result.myPreselected = (LookupFile) myList.getSelectedValue();
      }
    }

    myUiUpdater.queue(
        new Update("textField.suggestCompletion") {
          public void run() {
            final String completionBase = getCompletionBase();
            if (completionBase != null) {
              final LookupFile file = myFinder.find(completionBase);
              if (file != null && !file.isDirectory()) {
                // we've entered a complete path already, no need to autopopup completion again
                // (IDEA-78996)
                return;
              }
            }
            result.myCompletionBase = completionBase;
            if (result.myCompletionBase == null) return;
            result.myFieldText = myPathTextField.getText();
            ApplicationManager.getApplication()
                .executeOnPooledThread(
                    new Runnable() {
                      public void run() {
                        processCompletion(result);
                        SwingUtilities.invokeLater(
                            new Runnable() {
                              public void run() {
                                if (!result.myCompletionBase.equals(getCompletionBase())) return;

                                int pos = selectCompletionRemoveText(result, selectReplacedText);

                                showCompletionPopup(result, pos, isExplicitCall);
                              }
                            });
                      }
                    });
          }
        });
  }
  private void addMacroPaths(final CompletionResult result, final String typedText) {
    result.myMacros = new ArrayList<LookupFile>();

    final Iterator<String> macros = myMacroMap.keySet().iterator();
    while (macros.hasNext()) {
      String eachMacro = macros.next();
      if (eachMacro.toUpperCase().startsWith(typedText.toUpperCase())) {
        final String eachPath = myMacroMap.get(eachMacro);
        if (eachPath != null) {
          final LookupFile macroFile = myFinder.find(eachPath);
          if (macroFile != null && macroFile.exists()) {
            result.myMacros.add(macroFile);
            result.myToComplete.add(macroFile);
            macroFile.setMacro(eachMacro);
          }
        }
      }
    }
  }
  public void processCompletion(final CompletionResult result) {
    result.myToComplete = new ArrayList<LookupFile>();
    result.mySiblings = new ArrayList<LookupFile>();
    result.myKidsAfterSeparator = new ArrayList<LookupFile>();
    String typed = result.myCompletionBase;

    if (typed == null || typed.length() == 0) return;

    addMacroPaths(result, typed);

    final String typedText = myFinder.normalize(typed);

    result.current = getClosestParent(typed);
    result.myClosestParent = result.current;

    if (result.current != null) {
      result.currentParentMatch =
          SystemInfo.isFileSystemCaseSensitive
              ? typedText.equals(result.current.getAbsolutePath())
              : typedText.equalsIgnoreCase(result.current.getAbsolutePath());

      result.closedPath =
          typed.endsWith(myFinder.getSeparator())
              && typedText.length() > myFinder.getSeparator().length();
      final String currentParentText = result.current.getAbsolutePath();

      if (!typedText.toUpperCase().startsWith(currentParentText.toUpperCase())) return;

      String prefix = typedText.substring(currentParentText.length());
      if (prefix.startsWith(myFinder.getSeparator())) {
        prefix = prefix.substring(myFinder.getSeparator().length());
      } else if (typed.endsWith(myFinder.getSeparator())) {
        prefix = "";
      }

      result.effectivePrefix = prefix.toUpperCase();

      result.currentGrandparent = result.current.getParent();
      if (result.currentGrandparent != null && result.currentParentMatch && !result.closedPath) {
        final String currentGrandparentText = result.currentGrandparent.getAbsolutePath();
        if (StringUtil.startsWithConcatenationOf(
            typedText, currentGrandparentText, myFinder.getSeparator())) {
          result.grandparentPrefix =
              currentParentText
                  .substring(currentGrandparentText.length() + myFinder.getSeparator().length())
                  .toUpperCase();
        }
      }
    } else {
      result.effectivePrefix = typedText.toUpperCase();
    }

    ApplicationManager.getApplication()
        .runReadAction(
            new Runnable() {
              public void run() {
                if (result.current != null) {
                  result.myToComplete.addAll(
                      result.current.getChildren(
                          new LookupFilter() {
                            public boolean isAccepted(final LookupFile file) {
                              return myFilter.isAccepted(file)
                                  && file.getName()
                                      .toUpperCase()
                                      .startsWith(result.effectivePrefix);
                            }
                          }));

                  if (result.currentParentMatch && !result.closedPath) {
                    result.myKidsAfterSeparator.addAll(result.myToComplete);
                  }

                  if (result.grandparentPrefix != null) {
                    final List<LookupFile> siblings =
                        result.currentGrandparent.getChildren(
                            new LookupFilter() {
                              public boolean isAccepted(final LookupFile file) {
                                return !file.equals(result.current)
                                    && myFilter.isAccepted(file)
                                    && file.getName()
                                        .toUpperCase()
                                        .startsWith(result.grandparentPrefix);
                              }
                            });
                    result.myToComplete.addAll(0, siblings);
                    result.mySiblings.addAll(siblings);
                  }
                }

                int currentDiff = Integer.MIN_VALUE;
                LookupFile toPreselect = result.myPreselected;

                if (toPreselect == null || !result.myToComplete.contains(toPreselect)) {
                  boolean toPreselectFixed = false;
                  if (result.effectivePrefix.length() > 0) {
                    for (LookupFile each : result.myToComplete) {
                      String eachName = each.getName().toUpperCase();
                      if (!eachName.startsWith(result.effectivePrefix)) continue;
                      int diff = result.effectivePrefix.compareTo(eachName);
                      currentDiff = Math.max(diff, currentDiff);
                      if (currentDiff == diff) {
                        toPreselect = each;
                        toPreselectFixed = true;
                        break;
                      }
                    }

                    if (!toPreselectFixed) {
                      toPreselect = null;
                    }
                  } else {
                    toPreselect = null;
                  }

                  if (toPreselect == null) {
                    if (result.myToComplete.size() == 1) {
                      toPreselect = result.myToComplete.get(0);
                    } else if (result.effectivePrefix.length() == 0) {
                      if (result.mySiblings.size() > 0) {
                        toPreselect = result.mySiblings.get(0);
                      }
                    }

                    if (toPreselect == null
                        && !result.myToComplete.contains(toPreselect)
                        && result.myToComplete.size() > 0) {
                      toPreselect = result.myToComplete.get(0);
                    }
                  }
                }

                if (result.currentParentMatch && result.mySiblings.size() > 0) {
                  toPreselect = null;
                }

                result.myPreselected = toPreselect;
              }
            });
  }