Collection<Group> (@NotNull AbstractTreeNode<?> parent, @NotNull Collection<TreeElement> children) { List<Key> keys = new ArrayList<>(); String parentPrefix; int parentPrefixLength; if (parent.getValue() instanceof PropertiesPrefixGroup) { parentPrefix = ((PropertiesPrefixGroup)parent.getValue()).getPrefix(); parentPrefixLength = StringUtil.split(parentPrefix, mySeparator).size(); } else { parentPrefix = ""; parentPrefixLength = 0; } for (TreeElement element : children) { final String text = getPropertyUnescapedKey(element); if (text == null) continue; boolean expected = text.startsWith(parentPrefix) || text.startsWith(mySeparator); if (!expected) LOG.error("unexpected text: " + text + "; parentPrefix=" + parentPrefix + "; mySeparator=" + mySeparator); List<String> words = StringUtil.split(text, mySeparator); keys.add(new Key(words, element)); } if (keys.isEmpty()) return ContainerUtil.emptyList(); keys.sort((k1, k2) -> { List<String> o1 = k1.words; List<String> o2 = k2.words; for (int i = 0; i < Math.max(o1.size(), o2.size()); i++) { if (i == o1.size()) return 1; if (i == o2.size()) return -1; String s1 = o1.get(i); String s2 = o2.get(i); int res = s1.compareTo(s2); if (res != 0) return res; } return 0; }); List<Group> groups = new ArrayList<>(); int groupStart = 0; for (int i = 0; i <= keys.size(); i++) { if (!isEndOfGroup(i, keys, parentPrefixLength)) { continue; } // find longest group prefix List<String> firstKey = groupStart == keys.size() ? Collections.emptyList() : keys.get(groupStart).words; List<TreeElement> groupChildren = new SmartList<>(); groupChildren.add(keys.get(groupStart).node); int prefixLen = firstKey.size(); for (int j = groupStart+1; j < i; j++) { List<String> prevKey = keys.get(j-1).words; List<String> nextKey = keys.get(j).words; for (int k = parentPrefixLength; k < prefixLen; k++) { String word = k < nextKey.size() ? nextKey.get(k) : null; String wordInPrevKey = k < prevKey.size() ? prevKey.get(k) : null; if (!Comparing.strEqual(word, wordInPrevKey)) { prefixLen = k; break; } } groupChildren.add(keys.get(j).node); } String[] strings = firstKey.subList(0,prefixLen).toArray(new String[prefixLen]); String prefix = StringUtil.join(strings, mySeparator); String presentableName = prefix.substring(parentPrefix.length()); presentableName = StringUtil.trimStart(presentableName, mySeparator); if (i - groupStart > 1) { groups.add(new PropertiesPrefixGroup(groupChildren, prefix, presentableName, mySeparator)); } else if (groupStart != keys.size()) { TreeElement node = keys.get(groupStart).node; ((PropertyStructureViewElement)node).setPresentableName(presentableName); } groupStart = i; } return groups; }