public void setupFieldInitializationDependencies(@NotNull List<ArrangementEntryDependencyInfo> fieldDependencyRoots, @NotNull ArrangementSettings settings, @NotNull JavaArrangementParseInfo parseInfo) { Collection<JavaElementArrangementEntry> fields = parseInfo.getFields(); List<JavaElementArrangementEntry> arrangedFields = ArrangementEngine.arrange(fields, settings.getSections(), settings.getRulesSortedByPriority(), null); for (ArrangementEntryDependencyInfo root : fieldDependencyRoots) { JavaElementArrangementEntry anchorField = root.getAnchorEntry(); final int anchorEntryIndex = arrangedFields.indexOf(anchorField); for (ArrangementEntryDependencyInfo fieldInInitializerInfo : root.getDependentEntriesInfos()) { JavaElementArrangementEntry fieldInInitializer = fieldInInitializerInfo.getAnchorEntry(); if (arrangedFields.indexOf(fieldInInitializer) > anchorEntryIndex) { anchorField.addDependency(fieldInInitializer); } } } }
@NotNull private Runnable prepareRearrangeCommand(@NotNull final PsiFile file, @NotNull final Collection<TextRange> ranges) { final ArrangementEngine engine = ServiceManager.getService(myProject, ArrangementEngine.class); return new Runnable() { @Override public void run() { engine.arrange(file, ranges); if (getInfoCollector() != null) { String info = engine.getUserNotificationInfo(); getInfoCollector().setRearrangeCodeNotification(info); } } }; }
private void doTestArrangement(String dst) { final VirtualFile f = myFixture.copyFileToProject(BASE_PATH + getTestName(true) + ".xml", dst); myFixture.configureFromExistingVirtualFile(f); final ArrangementEngine engine = ServiceManager.getService(getProject(), ArrangementEngine.class); WriteCommandAction.runWriteCommandAction(null, new Runnable() { @Override public void run() { engine.arrange(myFixture.getEditor(), myFixture.getFile(), Arrays.asList(new TextRange(0, myFixture.getFile().getTextLength()))); } }); myFixture.checkResultByFile(BASE_PATH + getTestName(true) + "_after.xml"); }
@NotNull // com.intellij.codeInsight.actions.RearrangeCodeProcessor#prepareRearrangeCommand private Runnable prepareRearrangeCommand(@NotNull PsiFile file, @NotNull Collection<TextRange> ranges) { ArrangementEngine engine = ServiceManager.getService(myProject, ArrangementEngine.class); return () -> { engine.arrange(file, ranges); if (getInfoCollector() != null) { String info = engine.getUserNotificationInfo(); getInfoCollector().setRearrangeCodeNotification(info); } }; }
@Nonnull private Runnable prepareRearrangeCommand(@Nonnull final PsiFile file, @Nonnull final Collection<TextRange> ranges) { final ArrangementEngine engine = ServiceManager.getService(myProject, ArrangementEngine.class); return new Runnable() { @Override public void run() { engine.arrange(file, ranges); if (getInfoCollector() != null) { String info = engine.getUserNotificationInfo(); getInfoCollector().setRearrangeCodeNotification(info); } } }; }
protected void doTest(@NotNull Map<String, ?> args) { String text = (String)args.get("initial"); String expected = (String)args.get("expected"); @SuppressWarnings("unchecked") List<TextRange> ranges = (List<TextRange>)args.get("ranges"); Info info = parse(text); if (!isEmpty(ranges) && !isEmpty(info.ranges)) { fail("Duplicate ranges set: explicit: " + ranges + ", " + "derived: " + info.ranges + ", text:\n" + text); } if (isEmpty(info.ranges)) { info.ranges = !isEmpty(ranges) ? ranges : Arrays.asList(TextRange.from(0, text.length())); } myFixture.configureByText(fileType, info.text); final FoldingModel foldingModel = myFixture.getEditor().getFoldingModel(); for (final FoldingInfo foldingInfo : info.foldings) { foldingModel.runBatchFoldingOperation(new Runnable() { @Override public void run() { FoldRegion region = foldingModel.addFoldRegion(foldingInfo.start, foldingInfo.end, foldingInfo.placeholder); if (region != null) region.setExpanded(false); } }); } @SuppressWarnings("unchecked") List<ArrangementGroupingRule> groupingRules = (List<ArrangementGroupingRule>)args.get("groups"); if (groupingRules == null) groupingRules = Collections.emptyList(); List<?> rules = (List<?>)args.get("rules"); List<ArrangementSectionRule> sectionRules = getSectionRules(rules); @SuppressWarnings("unchecked") List<StdArrangementRuleAliasToken> aliases = (List<StdArrangementRuleAliasToken>)args.get("aliases"); CommonCodeStyleSettings settings = CodeStyleSettingsManager.getInstance(myFixture.getProject()).getCurrentSettings().getCommonSettings(language); final StdArrangementSettings arrangementSettings = aliases == null ? new StdArrangementSettings(groupingRules, sectionRules) : new StdArrangementExtendableSettings(groupingRules, sectionRules, aliases); settings.setArrangementSettings(arrangementSettings); ArrangementEngine engine = ServiceManager.getService(myFixture.getProject(), ArrangementEngine.class); engine.arrange(myFixture.getEditor(), myFixture.getFile(), info.ranges); // Check expectation. info = parse(expected); assertEquals(info.text, myFixture.getEditor().getDocument().getText()); for (FoldingInfo it : info.foldings) { FoldRegion foldRegion = foldingModel.getCollapsedRegionAtOffset(it.start); assertNotNull("Expected to find fold region at offset " + it.start, foldRegion); assertEquals(it.end, foldRegion.getEndOffset()); } }
/** * Tries to find an element at the given context which should be the previous sibling for the given 'member'element according to the * {@link CommonCodeStyleSettings#getArrangementSettings() user-defined arrangement rules}. * <p/> * E.g. the IDE might generate given 'member' element and wants to know element after which it should be inserted * * @param member target member which anchor should be calculated * @param settings code style settings to use * @param context given member's context * @return given member's anchor if the one can be computed; * given 'context' element if given member should be the first child * <code>null</code> otherwise */ @SuppressWarnings("MethodMayBeStatic") @Nullable public PsiElement getAnchor(@NotNull PsiElement member, @NotNull CommonCodeStyleSettings settings, @NotNull PsiElement context) { Language language = context.getLanguage(); Rearranger<?> rearranger = Rearranger.EXTENSION.forLanguage(language); if (rearranger == null) { return null; } ArrangementSettings arrangementSettings = settings.getArrangementSettings(); if (arrangementSettings == null && rearranger instanceof ArrangementStandardSettingsAware) { arrangementSettings = ((ArrangementStandardSettingsAware)rearranger).getDefaultSettings(); } if (arrangementSettings == null) { return null; } Pair<? extends ArrangementEntry,? extends List<? extends ArrangementEntry>> pair = rearranger.parseWithNew(context, null, Collections.singleton(context.getTextRange()), member, arrangementSettings); if (pair == null || pair.second.isEmpty()) { return null; } ArrangementEntry memberEntry = pair.first; List<? extends ArrangementEntry> entries = pair.second; ArrangementEntry parentEntry = entries.get(0); List<? extends ArrangementEntry> nonArranged = parentEntry.getChildren(); List<ArrangementEntry> entriesWithNew = new ArrayList<ArrangementEntry>(nonArranged); entriesWithNew.add(memberEntry); //TODO: check insert new element final List<? extends ArrangementMatchRule> rulesByPriority = arrangementSettings.getRulesSortedByPriority(); final List<ArrangementSectionRule> extendedSectionRules = ArrangementUtil.getExtendedSectionRules(arrangementSettings); List<ArrangementEntry> arranged = ArrangementEngine.arrange(entriesWithNew, extendedSectionRules, rulesByPriority, null); int i = arranged.indexOf(memberEntry); if (i <= 0) { return context; } ArrangementEntry anchorEntry = null; if (i >= arranged.size() - 1) { anchorEntry = nonArranged.get(nonArranged.size() - 1); } else { Set<ArrangementEntry> entriesBelow = new HashSet<ArrangementEntry>(); entriesBelow.addAll(arranged.subList(i + 1, arranged.size())); for (ArrangementEntry entry : nonArranged) { if (entriesBelow.contains(entry)) { break; } anchorEntry = entry; } } if (anchorEntry == null) { return context; } int offset = anchorEntry.getEndOffset() - 1 - context.getTextRange().getStartOffset(); PsiElement element = context.findElementAt(offset); for (PsiElement e = element; e != null && e.getTextRange().getStartOffset() >= anchorEntry.getStartOffset(); e = e.getParent()) { element = e; } return element; }
@Override public void actionPerformed(AnActionEvent e) { final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext()); if (project == null) { return; } final Editor editor = PlatformDataKeys.EDITOR.getData(e.getDataContext()); if (editor == null) { return; } PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); Document document = editor.getDocument(); documentManager.commitDocument(document); final PsiFile file = documentManager.getPsiFile(document); if (file == null) { return; } final List<TextRange> ranges = new ArrayList<TextRange>(); SelectionModel selectionModel = editor.getSelectionModel(); if (selectionModel.hasSelection()) { ranges.add(TextRange.create(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd())); } else if (selectionModel.hasBlockSelection()) { int[] starts = selectionModel.getBlockSelectionStarts(); int[] ends = selectionModel.getBlockSelectionEnds(); for (int i = 0; i < starts.length; i++) { ranges.add(TextRange.create(starts[i], ends[i])); } } else { ranges.add(TextRange.create(0, document.getTextLength())); } final ArrangementEngine engine = ServiceManager.getService(project, ArrangementEngine.class); try { CommandProcessor.getInstance().executeCommand(project, new Runnable() { @Override public void run() { engine.arrange(editor, file, ranges); } }, getTemplatePresentation().getText(), null); } finally { documentManager.commitDocument(document); } }
/** * Tries to find an element at the given context which should be the previous sibling for the given 'member'element according to the * {@link CommonCodeStyleSettings#getArrangementSettings() user-defined arrangement rules}. * <p/> * E.g. the IDE might generate given 'member' element and wants to know element after which it should be inserted * * @param member target member which anchor should be calculated * @param settings code style settings to use * @param context given member's context * @return given member's anchor if the one can be computed; * given 'context' element if given member should be the first child * <code>null</code> otherwise */ @SuppressWarnings("MethodMayBeStatic") @Nullable public PsiElement getAnchor(@NotNull PsiElement member, @NotNull CommonCodeStyleSettings settings, @NotNull PsiElement context) { Language language = context.getLanguage(); Rearranger<?> rearranger = Rearranger.EXTENSION.forLanguage(language); if (rearranger == null) { return null; } ArrangementSettings arrangementSettings = settings.getArrangementSettings(); if (arrangementSettings == null && rearranger instanceof ArrangementStandardSettingsAware) { arrangementSettings = ((ArrangementStandardSettingsAware)rearranger).getDefaultSettings(); } if (arrangementSettings == null) { return null; } Pair<? extends ArrangementEntry,? extends List<? extends ArrangementEntry>> pair = rearranger.parseWithNew(context, null, Collections.singleton(context.getTextRange()), member, arrangementSettings); if (pair == null || pair.second.isEmpty()) { return null; } ArrangementEntry memberEntry = pair.first; List<? extends ArrangementEntry> entries = pair.second; ArrangementEntry parentEntry = entries.get(0); List<? extends ArrangementEntry> nonArranged = parentEntry.getChildren(); List<ArrangementEntry> entriesWithNew = new ArrayList<ArrangementEntry>(nonArranged); entriesWithNew.add(memberEntry); final List<? extends ArrangementMatchRule> rulesByPriority = ArrangementUtil.getRulesSortedByPriority(arrangementSettings); List<ArrangementEntry> arranged = ArrangementEngine.arrange(entriesWithNew, arrangementSettings.getRules(), rulesByPriority); int i = arranged.indexOf(memberEntry); if (i <= 0) { return context; } ArrangementEntry anchorEntry = null; if (i >= arranged.size() - 1) { anchorEntry = nonArranged.get(nonArranged.size() - 1); } else { Set<ArrangementEntry> entriesBelow = new HashSet<ArrangementEntry>(); entriesBelow.addAll(arranged.subList(i + 1, arranged.size())); for (ArrangementEntry entry : nonArranged) { if (entriesBelow.contains(entry)) { break; } anchorEntry = entry; } } if (anchorEntry == null) { return context; } int offset = anchorEntry.getEndOffset() - 1 - context.getTextRange().getStartOffset(); PsiElement element = context.findElementAt(offset); for (PsiElement e = element; e != null && e.getTextRange().getStartOffset() >= anchorEntry.getStartOffset(); e = e.getParent()) { element = e; } return element; }
/** * Tries to find an element at the given context which should be the previous sibling for the given 'member'element according to the * {@link CommonCodeStyleSettings#getArrangementSettings() user-defined arrangement rules}. * <p/> * E.g. the IDE might generate given 'member' element and wants to know element after which it should be inserted * * @param member target member which anchor should be calculated * @param settings code style settings to use * @param context given member's context * @return given member's anchor if the one can be computed; * given 'context' element if given member should be the first child * <code>null</code> otherwise */ @SuppressWarnings("MethodMayBeStatic") @Nullable public PsiElement getAnchor(@Nonnull PsiElement member, @Nonnull CommonCodeStyleSettings settings, @Nonnull PsiElement context) { Language language = context.getLanguage(); Rearranger<?> rearranger = Rearranger.EXTENSION.forLanguage(language); if (rearranger == null) { return null; } ArrangementSettings arrangementSettings = settings.getArrangementSettings(); if (arrangementSettings == null && rearranger instanceof ArrangementStandardSettingsAware) { arrangementSettings = ((ArrangementStandardSettingsAware)rearranger).getDefaultSettings(); } if (arrangementSettings == null) { return null; } Pair<? extends ArrangementEntry,? extends List<? extends ArrangementEntry>> pair = rearranger.parseWithNew(context, null, Collections.singleton(context.getTextRange()), member, arrangementSettings); if (pair == null || pair.second.isEmpty()) { return null; } ArrangementEntry memberEntry = pair.first; List<? extends ArrangementEntry> entries = pair.second; ArrangementEntry parentEntry = entries.get(0); List<? extends ArrangementEntry> nonArranged = parentEntry.getChildren(); List<ArrangementEntry> entriesWithNew = new ArrayList<ArrangementEntry>(nonArranged); entriesWithNew.add(memberEntry); //TODO: check insert new element final List<? extends ArrangementMatchRule> rulesByPriority = arrangementSettings.getRulesSortedByPriority(); final List<ArrangementSectionRule> extendedSectionRules = ArrangementUtil.getExtendedSectionRules(arrangementSettings); List<ArrangementEntry> arranged = ArrangementEngine.arrange(entriesWithNew, extendedSectionRules, rulesByPriority, null); int i = arranged.indexOf(memberEntry); if (i <= 0) { return context; } ArrangementEntry anchorEntry = null; if (i >= arranged.size() - 1) { anchorEntry = nonArranged.get(nonArranged.size() - 1); } else { Set<ArrangementEntry> entriesBelow = new HashSet<ArrangementEntry>(); entriesBelow.addAll(arranged.subList(i + 1, arranged.size())); for (ArrangementEntry entry : nonArranged) { if (entriesBelow.contains(entry)) { break; } anchorEntry = entry; } } if (anchorEntry == null) { return context; } int offset = anchorEntry.getEndOffset() - 1 - context.getTextRange().getStartOffset(); PsiElement element = context.findElementAt(offset); for (PsiElement e = element; e != null && e.getTextRange().getStartOffset() >= anchorEntry.getStartOffset(); e = e.getParent()) { element = e; } return element; }