CompletionResult (@NotNull String typed, @NotNull Finder finder, @NotNull FileLookup.LookupFilter filter, @NotNull Map<String, String> macroMap, @Nullable FileLookup.LookupFile preselected) { List<FileLookup.LookupFile> macros = new ArrayList<>(); List<FileLookup.LookupFile> variants = new ArrayList<>(); MinusculeMatcher matcher = createMatcher(typed); for (String eachMacro : macroMap.keySet()) { if (matcher.matches(eachMacro)) { String eachPath = macroMap.get(eachMacro); if (eachPath != null) { FileLookup.LookupFile macroFile = finder.find(eachPath); if (macroFile != null && macroFile.exists()) { macros.add(macroFile); variants.add(macroFile); macroFile.setMacro(eachMacro); } } } } String typedText = finder.normalize(typed); FileLookup.LookupFile current = getClosestParent(typed, finder); boolean currentParentMatch; boolean closedPath; String effectivePrefix; FileLookup.LookupFile currentGrandparent; String grandparentPrefix; if (current != null) { currentParentMatch = SystemInfo.isFileSystemCaseSensitive ? typedText.equals(current.getAbsolutePath()) : typedText.equalsIgnoreCase(current.getAbsolutePath()); closedPath = typed.endsWith(finder.getSeparator()) && typedText.length() > finder.getSeparator().length(); String currentParentText = current.getAbsolutePath(); if (!StringUtil.startsWithIgnoreCase(typedText, currentParentText)) { return new CompletionResult(variants, macros, List.of(), List.of(), null); } String prefix = typedText.substring(currentParentText.length()); if (prefix.startsWith(finder.getSeparator())) { prefix = prefix.substring(finder.getSeparator().length()); } else if (typed.endsWith(finder.getSeparator())) { prefix = ""; } effectivePrefix = prefix; currentGrandparent = current.getParent(); String gpPrefix = null; if (currentGrandparent != null && currentParentMatch && !closedPath) { String currentGrandparentText = currentGrandparent.getAbsolutePath(); if (StringUtil.startsWithConcatenation(typedText, currentGrandparentText, finder.getSeparator())) { gpPrefix = currentParentText.substring(currentGrandparentText.length() + finder.getSeparator().length()); } } grandparentPrefix = gpPrefix; } else { currentParentMatch = false; closedPath = false; effectivePrefix = typedText; currentGrandparent = null; grandparentPrefix = null; } return ReadAction.compute(new ThrowableComputable<>() { @Override public CompletionResult compute() throws RuntimeException { List<FileLookup.LookupFile> siblings = new ArrayList<>(); List<FileLookup.LookupFile> kidsAfterSeparator = new ArrayList<>(); if (current != null) { variants.addAll(getMatchingChildren(effectivePrefix, current)); if (currentParentMatch && !closedPath && !typed.isEmpty()) { kidsAfterSeparator.addAll(variants); } if (grandparentPrefix != null) { List<FileLookup.LookupFile> children = getMatchingChildren(grandparentPrefix, currentGrandparent); variants.addAll(0, children); siblings.addAll(children); } } FileLookup.LookupFile toPreselect = preselected; if (toPreselect == null || !variants.contains(toPreselect)) { boolean toPreselectFixed = false; if (effectivePrefix.length() > 0) { for (FileLookup.LookupFile each : variants) { String eachName = StringUtil.toUpperCase(each.getName()); if (!eachName.startsWith(effectivePrefix)) continue; toPreselect = each; toPreselectFixed = true; break; } if (!toPreselectFixed) { toPreselect = null; } } else { toPreselect = null; } if (toPreselect == null) { if (variants.size() == 1) { toPreselect = variants.get(0); } else if (effectivePrefix.length() == 0) { if (siblings.size() > 0) { toPreselect = siblings.get(0); } } if (toPreselect == null && !variants.contains(null) && variants.size() > 0) { toPreselect = variants.get(0); } } } if (currentParentMatch && siblings.size() > 0) { toPreselect = null; } return new CompletionResult(variants, macros, siblings, kidsAfterSeparator, toPreselect); } private List<FileLookup.LookupFile> getMatchingChildren(String prefix, FileLookup.LookupFile parent) { MinusculeMatcher matcher = createMatcher(prefix); return parent.getChildren(file -> !file.equals(current) && filter.isAccepted(file) && matcher.matches(file.getName())); } }); }