From c8c066b1887e50bafbcd83f572a2c9b7d071fecf Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 16 May 2011 18:55:05 +0400 Subject: [PATCH 01/31] fix row height on Win/Unix --- .../src/com/intellij/ui/table/JBTable.java | 14 ++---- .../diff/impl/dir/TestDirDiffAction.java | 45 +++++++++---------- 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ui/table/JBTable.java b/platform/platform-api/src/com/intellij/ui/table/JBTable.java index 973f64e51ce4..f6cdc98fdb10 100644 --- a/platform/platform-api/src/com/intellij/ui/table/JBTable.java +++ b/platform/platform-api/src/com/intellij/ui/table/JBTable.java @@ -17,7 +17,6 @@ package com.intellij.ui.table; import com.intellij.Patches; import com.intellij.ide.ui.UISettings; -import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.ui.ComponentWithExpandableItems; import com.intellij.ui.ExpandableItemsHandler; @@ -125,8 +124,7 @@ public class JBTable extends JTable implements ComponentWithEmptyText, Component @Override public int getRowHeight() { - if (myRowHeightIsComputing - || !SystemInfo.isMac) { //todo[kirillk]: looks weird on Win/Linux + if (myRowHeightIsComputing) { return super.getRowHeight(); } @@ -163,13 +161,8 @@ public class JBTable extends JTable implements ComponentWithEmptyText, Component @Override public void setRowHeight(int rowHeight) { - //todo[kirillk]: looks weird on Win/Linux - if (SystemInfo.isMac) { - myRowHeight = rowHeight; - myRowHeightIsExplicitlySet = true; - } else { - super.setRowHeight(rowHeight); - } + myRowHeight = rowHeight; + myRowHeightIsExplicitlySet = true; } private void repaintViewport() { @@ -319,6 +312,7 @@ public class JBTable extends JTable implements ComponentWithEmptyText, Component final TableCellEditor editor = getCellEditor(row, column); if (editor != null && editor.isCellEditable(e)) { editorComp = prepareEditor(editor, row, column); + ((JComponent)editorComp).setBorder(null); if (editorComp == null) { removeEditor(); return false; diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/TestDirDiffAction.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/TestDirDiffAction.java index 92112bc1043b..36312816ee16 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/TestDirDiffAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/TestDirDiffAction.java @@ -15,19 +15,16 @@ */ package com.intellij.openapi.diff.impl.dir; -import com.intellij.ide.diff.DiffElement; -import com.intellij.ide.diff.DirDiffSettings; -import com.intellij.ide.diff.VirtualFileDiffElement; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.diff.DirDiffManager; -import com.intellij.openapi.fileChooser.FileChooserDescriptor; -import com.intellij.openapi.fileChooser.FileChooserFactory; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.registry.Registry; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.ui.ScrollPaneFactory; +import com.intellij.ui.table.JBTable; + +import javax.swing.*; +import javax.swing.table.DefaultTableModel; +import java.awt.*; /** * @author Konstantin Bulenkov @@ -35,21 +32,19 @@ import com.intellij.openapi.vfs.VirtualFileManager; public class TestDirDiffAction extends AnAction { @Override public void actionPerformed(AnActionEvent e) { - final Project project = e.getData(PlatformDataKeys.PROJECT); - if (project != null) { - final VirtualFile src = VirtualFileManager.getInstance().findFileByUrl(Registry.stringValue("dir.diff.default.src.folder")); - final VirtualFile trg = VirtualFileManager.getInstance().findFileByUrl(Registry.stringValue("dir.diff.default.trg.folder")); - final FileChooserDescriptor descriptor = new FileChooserDescriptor(false, true, false, false, false, false); - final VirtualFile[] files1 = src != null ? new VirtualFile[]{src} : FileChooserFactory.getInstance().createFileChooser(descriptor, project).choose(null, project); - final VirtualFile[] files2 = trg != null ? new VirtualFile[]{trg} : FileChooserFactory.getInstance().createFileChooser(descriptor, project).choose(null, project); - if (files1.length == 1 && files2.length == 1) { - DiffElement elem1 = new VirtualFileDiffElement(files1[0]); - DiffElement elem2 = new VirtualFileDiffElement(files2[0]); - final DirDiffManager diffManager = DirDiffManager.getInstance(project); - if (diffManager.canShow(elem1, elem2)) { - diffManager.showDiff(elem1, elem2, new DirDiffSettings()); - } + new DialogWrapper(e.getData(PlatformDataKeys.PROJECT)) { + { + init(); } - } + + @Override + protected JComponent createCenterPanel() { + final JPanel panel = new JPanel(new BorderLayout()); + final JBTable table = new JBTable(); + table.setModel(new DefaultTableModel(new Object[][]{{"aaa", "bbb"}, {"ccc", "ddd"}}, new Object[]{"foo", "bar"})); + panel.add(ScrollPaneFactory.createScrollPane(table), BorderLayout.CENTER); + return panel; + } + }.show(); } } From 5992341698db3e146dd28607da48e379cd44729b Mon Sep 17 00:00:00 2001 From: Denis Zhdanov Date: Mon, 16 May 2011 19:07:56 +0400 Subject: [PATCH 02/31] WI-6048 Web IDE slows down tremendously up with big one-lined css file open Don't process fold regions which boundaries belong to the same logical line during gutter repainting --- .../impl/EditorGutterComponentImpl.java | 67 +++++++++++++------ .../util/src/com/intellij/util/Function.java | 4 +- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index c587297d2ada..fec825922b77 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -690,18 +690,21 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse return new VisualPosition(myEditor.offsetToVisualPosition(offset).line, 0); } - private void doPaintFoldingTree(Graphics2D g, Rectangle clip, int firstVisibleOffset, int lastVisibleOffset) { - int anchorX = getFoldingAreaOffset(); - int width = getFoldingAnchorWidth(); + private void doPaintFoldingTree(final Graphics2D g, final Rectangle clip, int firstVisibleOffset, int lastVisibleOffset) { + final int anchorX = getFoldingAreaOffset(); + final int width = getFoldingAnchorWidth(); - FoldRegion[] visibleFoldRegions = ((FoldingModelImpl)myEditor.getFoldingModel()).fetchVisible(); - - for (FoldRegion visibleFoldRegion : visibleFoldRegions) { - if (!visibleFoldRegion.isValid()) continue; - if (visibleFoldRegion.getStartOffset() > lastVisibleOffset) continue; - if (getEndOffset(visibleFoldRegion) < firstVisibleOffset) continue; - drawAnchor(visibleFoldRegion, width, clip, g, anchorX, false, false); - } + doForVisibleFoldRegions( + new Function() { + @Override + public Void fun(FoldRegion foldRegion) { + drawAnchor(foldRegion, width, clip, g, anchorX, false, false); + return null; + } + }, + firstVisibleOffset, + lastVisibleOffset + ); if (myActiveFoldRegion != null) { drawAnchor(myActiveFoldRegion, width, clip, g, anchorX, true, true); @@ -709,6 +712,23 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } } + private void doForVisibleFoldRegions(@NotNull Function action, int firstVisibleOffset, int lastVisibleOffset) { + FoldRegion[] visibleFoldRegions = ((FoldingModelImpl)myEditor.getFoldingModel()).fetchVisible(); + final Document document = myEditor.getDocument(); + for (FoldRegion visibleFoldRegion : visibleFoldRegions) { + if (!visibleFoldRegion.isValid()) continue; + final int startOffset = visibleFoldRegion.getStartOffset(); + if (startOffset > lastVisibleOffset) continue; + final int endOffset = getEndOffset(visibleFoldRegion); + if (endOffset < firstVisibleOffset) continue; + if (document.getLineNumber(startOffset) >= document.getLineNumber(endOffset)) { + //TODO den remove this check as soon as editor performance on dimension mapping is improved (IDEA-69317) + continue; + } + action.fun(visibleFoldRegion); + } + } + private void paintFoldingBackground(Graphics g, Rectangle clip, int firstVisibleOffset, int lastVisibleOffset) { int lineX = getWhitespaceSeparatorOffset(); paintBackground(g, clip, getFoldingAreaOffset(), getFoldingAreaWidth()); @@ -721,26 +741,29 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse doPaintFoldingBoxBackground((Graphics2D)g, clip, firstVisibleOffset, lastVisibleOffset); } - private void doPaintFoldingBoxBackground(Graphics2D g, Rectangle clip, int firstVisibleOffset, int lastVisibleOffset) { + private void doPaintFoldingBoxBackground(final Graphics2D g, final Rectangle clip, int firstVisibleOffset, int lastVisibleOffset) { if (!isFoldingOutlineShown()) return; UIUtil.drawVDottedLine(g, getWhitespaceSeparatorOffset(), clip.y, clip.y + clip.height, null, getOutlineColor(false)); - int anchorX = getFoldingAreaOffset(); - int width = getFoldingAnchorWidth(); - - FoldRegion[] visibleFoldRegions = ((FoldingModelImpl)myEditor.getFoldingModel()).fetchVisible(); + final int anchorX = getFoldingAreaOffset(); + final int width = getFoldingAnchorWidth(); if (myActiveFoldRegion != null) { drawFoldingLines(myActiveFoldRegion, clip, width, anchorX, g); } - for (FoldRegion visibleFoldRegion : visibleFoldRegions) { - if (!visibleFoldRegion.isValid()) continue; - if (visibleFoldRegion.getStartOffset() > lastVisibleOffset) continue; - if (getEndOffset(visibleFoldRegion) < firstVisibleOffset) continue; - drawAnchor(visibleFoldRegion, width, clip, g, anchorX, false, true); - } + doForVisibleFoldRegions( + new Function() { + @Override + public Void fun(FoldRegion foldRegion) { + drawAnchor(foldRegion, width, clip, g, anchorX, false, true); + return null; + } + }, + firstVisibleOffset, + lastVisibleOffset + ); } public int getWhitespaceSeparatorOffset() { diff --git a/platform/util/src/com/intellij/util/Function.java b/platform/util/src/com/intellij/util/Function.java index 9ef0996b76bd..90c1e76725ce 100644 --- a/platform/util/src/com/intellij/util/Function.java +++ b/platform/util/src/com/intellij/util/Function.java @@ -15,6 +15,8 @@ */ package com.intellij.util; +import org.jetbrains.annotations.Nullable; + import java.util.Collection; /** @@ -23,7 +25,7 @@ import java.util.Collection; */ @SuppressWarnings({"unchecked"}) public interface Function { - Result fun(Param param); + @Nullable Result fun(Param param); /** * @see FunctionUtil#id() From 70ea89f4d946a4e06194451a187f0aae53191b93 Mon Sep 17 00:00:00 2001 From: Sergey Evdokimov Date: Mon, 16 May 2011 18:46:43 +0400 Subject: [PATCH 03/31] IDEA-54181 GSP: "Expand empty tag" intention fails when applied to groovy tags with attributes, IDEA-69468 Inspection "Replace tag empty end with empty body" causes crash. --- .../xml/util/CheckEmptyTagInspection.java | 13 +------- .../src/com/intellij/xml/util/XmlUtil.java | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/xml/impl/src/com/intellij/xml/util/CheckEmptyTagInspection.java b/xml/impl/src/com/intellij/xml/util/CheckEmptyTagInspection.java index af0b0e57e1a9..ed169c7d2921 100644 --- a/xml/impl/src/com/intellij/xml/util/CheckEmptyTagInspection.java +++ b/xml/impl/src/com/intellij/xml/util/CheckEmptyTagInspection.java @@ -22,17 +22,13 @@ import com.intellij.lang.Language; import com.intellij.lang.html.HTMLLanguage; import com.intellij.lang.xml.XMLLanguage; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.ReadonlyStatusHandler; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiFileFactory; import com.intellij.psi.XmlElementVisitor; import com.intellij.psi.html.HtmlTag; import com.intellij.psi.xml.XmlChildRole; -import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.util.IncorrectOperationException; import com.intellij.xml.XmlBundle; @@ -119,15 +115,8 @@ public class CheckEmptyTagInspection extends XmlSuppressableInspectionTool { if (psiFile == null) return; ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(psiFile.getVirtualFile()); - final StringBuilder builder = new StringBuilder(tag.getText()); - builder.replace(builder.length() - 2, builder.length(), ">"); - try { - final FileType fileType = psiFile.getFileType(); - PsiFile file = PsiFileFactory.getInstance(tag.getProject()).createFileFromText( - "dummy." + (fileType == StdFileTypes.JSP || tag.getContainingFile().getLanguage() == HTMLLanguage.INSTANCE ? "html" : "xml"), builder.toString()); - - tag.replace(((XmlFile)file).getDocument().getRootTag()); + XmlUtil.expandTag(tag); } catch (IncorrectOperationException e) { LOG.error(e); diff --git a/xml/impl/src/com/intellij/xml/util/XmlUtil.java b/xml/impl/src/com/intellij/xml/util/XmlUtil.java index 1112b7799934..87426f71e159 100644 --- a/xml/impl/src/com/intellij/xml/util/XmlUtil.java +++ b/xml/impl/src/com/intellij/xml/util/XmlUtil.java @@ -53,6 +53,8 @@ import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.filters.XmlTagFilter; import com.intellij.psi.filters.position.FilterPattern; import com.intellij.psi.impl.source.html.HtmlDocumentImpl; +import com.intellij.psi.impl.source.tree.CompositeElement; +import com.intellij.psi.impl.source.tree.LeafElement; import com.intellij.psi.impl.source.xml.XmlEntityRefImpl; import com.intellij.psi.scope.processor.FilterElementProcessor; import com.intellij.psi.search.PsiElementProcessor; @@ -587,6 +589,37 @@ public class XmlUtil { return null; } + public static void expandTag(@NotNull XmlTag tag) { + XmlTag newTag = XmlElementFactory.getInstance(tag.getProject()).createTagFromText('<' + tag.getName() + ">'); + + ASTNode node = tag.getNode(); + if (!(node instanceof CompositeElement)) return; + CompositeElement compositeElement = (CompositeElement)node; + + final LeafElement emptyTagEnd = (LeafElement)XmlChildRole.EMPTY_TAG_END_FINDER.findChild(compositeElement); + if (emptyTagEnd == null) return; + + compositeElement.removeChild(emptyTagEnd); + PsiElement[] children = newTag.getChildren(); + + compositeElement.addChildren(children[2].getNode(), null, null); + } + // + //public static void expandTag(@NotNull XmlTag tag) { + // final LeafElement emptyTagEnd = (LeafElement)XmlChildRole.EMPTY_TAG_END_FINDER.findChild(tag.getNode()); + // if (emptyTagEnd == null) return; + // + // PsiFile file = tag.getContainingFile().getOriginalFile(); + // + // TextRange textRange = emptyTagEnd.getTextRange(); + // Document document = file.getViewProvider().getDocument(); + // if (document == null) return; + // + // PsiDocumentManager.getInstance(file.getProject()).commitDocument(document); + // document.replaceString(textRange.getStartOffset(), textRange.getEndOffset(), ">'); + // PsiDocumentManager.getInstance(file.getProject()).commitDocument(document); + //} + private static class XmlElementProcessor { private final PsiElementProcessor processor; private final PsiFile targetFile; From ef199042d824ef66caa791ff6c41be9d32e34010 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 16 May 2011 19:58:28 +0400 Subject: [PATCH 04/31] check if alarm already disposed --- .../com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java index b7538b09a38b..5758a5c0b985 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java @@ -392,6 +392,7 @@ public class FileHistoryPanelImpl Date: Mon, 16 May 2011 15:29:40 +0400 Subject: [PATCH 05/31] create from checkout sources: do not override explicitly set project directory (IDEA-69299) --- .../com/intellij/ide/util/projectWizard/WizardContext.java | 4 ++++ .../idea/eclipse/importWizard/EclipseWorkspaceRootStep.java | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/platform/lang-api/src/com/intellij/ide/util/projectWizard/WizardContext.java b/platform/lang-api/src/com/intellij/ide/util/projectWizard/WizardContext.java index e5daad1340c0..2a608531a170 100644 --- a/platform/lang-api/src/com/intellij/ide/util/projectWizard/WizardContext.java +++ b/platform/lang-api/src/com/intellij/ide/util/projectWizard/WizardContext.java @@ -80,6 +80,10 @@ public class WizardContext { "Projects"; } + public boolean isProjectFileDirectorySet() { + return myProjectFileDirectory != null; + } + public void setProjectFileDirectory(String projectFileDirectory) { myProjectFileDirectory = projectFileDirectory; } diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/importWizard/EclipseWorkspaceRootStep.java b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importWizard/EclipseWorkspaceRootStep.java index 5fd3df7449e6..9472c748c0cf 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/importWizard/EclipseWorkspaceRootStep.java +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importWizard/EclipseWorkspaceRootStep.java @@ -109,7 +109,11 @@ public class EclipseWorkspaceRootStep extends ProjectImportWizardStep { public void updateStep() { String path = getContext().getRootDirectory(); if (path == null) { - path = PropertiesComponent.getInstance().isValueSet(_ECLIPSE_PROJECT_DIR) ? PropertiesComponent.getInstance().getValue(_ECLIPSE_PROJECT_DIR) : getWizardContext().getProjectFileDirectory(); + if (getWizardContext().isProjectFileDirectorySet() || !PropertiesComponent.getInstance().isValueSet(_ECLIPSE_PROJECT_DIR)) { + path = getWizardContext().getProjectFileDirectory(); + } else { + path = PropertiesComponent.getInstance().getValue(_ECLIPSE_PROJECT_DIR); + } } myWorkspaceRootComponent.setText(path.replace('/', File.separatorChar)); myWorkspaceRootComponent.getTextField().selectAll(); From aeb56eb52bd6f24b50ab120a2f14ed4dbce09f0b Mon Sep 17 00:00:00 2001 From: anna Date: Mon, 16 May 2011 17:10:45 +0400 Subject: [PATCH 06/31] distinguish scopes per file (IDEA-68759) --- .../DependencyValidationManagerImpl.java | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/packageDependencies/DependencyValidationManagerImpl.java b/platform/lang-impl/src/com/intellij/packageDependencies/DependencyValidationManagerImpl.java index f0a73ef4a139..4a3156b6cbfc 100644 --- a/platform/lang-impl/src/com/intellij/packageDependencies/DependencyValidationManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/packageDependencies/DependencyValidationManagerImpl.java @@ -19,11 +19,14 @@ package com.intellij.packageDependencies; import com.intellij.ide.IdeBundle; import com.intellij.ide.impl.ContentManagerWatcher; import com.intellij.openapi.components.State; +import com.intellij.openapi.components.StateSplitter; import com.intellij.openapi.components.Storage; +import com.intellij.openapi.components.StorageScheme; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.*; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ToolWindowId; @@ -32,6 +35,8 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.search.scope.packageSet.*; import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentManager; +import com.intellij.util.text.UniqueNameGenerator; +import org.jdom.Attribute; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -46,7 +51,8 @@ import java.util.*; @Storage( id="other", file = "$PROJECT_FILE$" - )} + ), @Storage(id = "dir", file = "$PROJECT_CONFIG_DIR$/scopes/", scheme = StorageScheme.DIRECTORY_BASED, + stateSplitter = DependencyValidationManagerImpl.ScopesStateSplitter.class)} ) public class DependencyValidationManagerImpl extends DependencyValidationManager { private static final Logger LOG = Logger.getInstance("#com.intellij.packageDependencies.DependencyValidationManagerImpl"); @@ -303,4 +309,44 @@ public class DependencyValidationManagerImpl extends DependencyValidationManager if (fromNamedScope == null || toNamedScope == null) return null; return new DependencyRule(fromNamedScope, toNamedScope, Boolean.valueOf(denyRule).booleanValue()); } + + public static class ScopesStateSplitter implements StateSplitter { + public List> splitState(Element e) { + final UniqueNameGenerator generator = new UniqueNameGenerator(); + final List> result = new ArrayList>(); + + final Element[] elements = JDOMUtil.getElements(e); + for (Element element : elements) { + if (element.getName().equals("scope")) { + element.detach(); + String scopeName = element.getAttributeValue("name"); + assert scopeName != null; + final String name = generator.generateUniqueName(FileUtil.sanitizeFileName(scopeName)) + ".xml"; + result.add(new Pair(element, name)); + } + } + result.add(new Pair(e, generator.generateUniqueName("scope_settings") + ".xml")); + return result; + } + + public void mergeStatesInto(Element target, Element[] elements) { + for (Element element : elements) { + if (element.getName().equals("scope")) { + element.detach(); + target.addContent(element); + } + else { + final Element[] states = JDOMUtil.getElements(element); + for (Element state : states) { + state.detach(); + target.addContent(state); + } + for (Object attr : element.getAttributes()) { + target.setAttribute((Attribute)((Attribute)attr).clone()); + } + } + } + } + } + } From 72063660af38bd44cad94c182fb26f450407f1b8 Mon Sep 17 00:00:00 2001 From: anna Date: Mon, 16 May 2011 21:21:38 +0400 Subject: [PATCH 07/31] add one more case to process assertEquals --- .../src/com/intellij/junit4/JUnit4TestResultsSender.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java index 666f9850f69f..5d13df8249c6 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java @@ -101,6 +101,9 @@ public class JUnit4TestResultsSender extends RunListener { if (!matcher.matches()) { matcher = Pattern.compile("expected same:<(.*)> was not:<(.*)>", Pattern.DOTALL).matcher(message); } + if (!matcher.matches()) { + matcher = Pattern.compile("expected:<(.*)> but was:<(.*)>", Pattern.DOTALL).matcher(message); + } if (matcher.matches()) { return ComparisonDetailsExtractor .create(assertion, matcher.group(1).replaceAll("\\\\n", "\n"), matcher.group(2).replaceAll("\\\\n", "\n")); From af4873b8aa59b3195b75ff89905157b93dd46dd6 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 16 May 2011 19:37:27 +0200 Subject: [PATCH 08/31] IDEA-69645 (bad code is green: attribute value must be constant) --- .../daemon/impl/analysis/AnnotationsHighlightUtil.java | 10 ++++++---- .../annotations/nonConstantInitializer.java | 4 ++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java index 233825ad6688..35ce6e890f52 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java @@ -173,8 +173,9 @@ public class AnnotationsHighlightUtil { Set names = new HashSet(); PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); for (PsiNameValuePair attribute : attributes) { - if (attribute.getName() != null) { - names.add(attribute.getName()); + final String name = attribute.getName(); + if (name != null) { + names.add(name); } else { names.add(PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME); @@ -211,8 +212,9 @@ public class AnnotationsHighlightUtil { @Nullable public static HighlightInfo checkConstantExpression(PsiExpression expression) { - if (expression.getParent() instanceof PsiAnnotationMethod || expression.getParent() instanceof PsiNameValuePair) { - if (PsiType.NULL.equals(expression.getType()) || !PsiUtil.isConstantExpression(expression)) { + final PsiElement parent = expression.getParent(); + if (parent instanceof PsiAnnotationMethod || parent instanceof PsiNameValuePair || parent instanceof PsiArrayInitializerMemberValue) { + if (!PsiUtil.isConstantExpression(expression)) { return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, JavaErrorMessages.message("annotation.nonconstant.attribute.value")); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/nonConstantInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/nonConstantInitializer.java index 82a151b61755..c8998b249f25 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/nonConstantInitializer.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/annotations/nonConstantInitializer.java @@ -1,10 +1,14 @@ @interface Ann { int i (); + + String[] j(); } class D { int field; @Ann(i=field) void foo () {} + + @Ann(j={null}) void bar() {} } @interface ManistaDouble From a6a7270b12136d0911172431eaee69e58dfc818e Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 16 May 2011 14:37:33 +0400 Subject: [PATCH 09/31] fix app test --- .../com/intellij/openapi/project/impl/ProjectManagerImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java index 23de8bec50d7..6d7b5dbe8368 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java @@ -242,7 +242,8 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt return message; } - private ProjectImpl createAndInitProject(String projectName, String filePath, boolean isDefault, boolean isOptimiseTestLoadSpeed, + private ProjectImpl + createAndInitProject(String projectName, String filePath, boolean isDefault, boolean isOptimiseTestLoadSpeed, @Nullable Project template) throws IOException { final ProjectImpl project = isDefault ? new DefaultProject(this, filePath, isOptimiseTestLoadSpeed, projectName) : new ProjectImpl(this, filePath, isOptimiseTestLoadSpeed, projectName); From 3c6b2c71f3e6b2f3d735f1c38d527402cb4ad0c1 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 16 May 2011 21:11:09 +0200 Subject: [PATCH 10/31] when we resolve method with partial signature, the last argument is currently being edited or evaluated for the expected type => 1) its generics will contribute nothing to the resolve process 2) the inference of the generics may cause endless recursion => use raw type for this argument matching --- .../plugins/groovy/lang/psi/util/PsiUtil.java | 7 ++++++ .../groovy/lang/GroovyStressTest.groovy | 22 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index 12ccc64c8c3b..3d9a8e109485 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -31,6 +31,7 @@ import com.intellij.psi.search.SearchScope; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.ContainerUtil; @@ -232,6 +233,9 @@ public class PsiUtil { if (type == null) { result.add(nullAsBottom ? PsiType.NULL : TypesUtil.getJavaLangObject(expression)); } else { + if (stopAt == expression) { + type = TypeConversionUtil.erasure(type); + } result.add(type); } if (stopAt == expression) { @@ -242,6 +246,9 @@ public class PsiUtil { for (GrClosableBlock closure : closures) { PsiType closureType = closure.getType(); if (closureType != null) { + if (stopAt == closure) { + closureType = TypeConversionUtil.erasure(closureType); + } result.add(closureType); } if (stopAt == closure) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStressTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStressTest.groovy index f196b1fadd62..c8649250cdca 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStressTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyStressTest.groovy @@ -106,4 +106,26 @@ class GroovyStressTest extends LightCodeInsightFixtureTestCase { IdeaTestUtil.assertTiming "slow", 10000, { myFixture.doHighlighting() } } + public void testDeeplyNestedClosuresInGenericCalls() { + String text = "println it" + for (i in 1..10) { + text = "foo(it) { $text }" + } + myFixture.configureByText("a.groovy", "def foo(T t, Closure cl) {}\n" + text) + myFixture.enableInspections(new MissingReturnInspection()) + IdeaTestUtil.assertTiming "slow", 10000, { myFixture.doHighlighting() } + + } + + public void testDeeplyNestedClosuresInGenericCalls2() { + String text = "println it" + for (i in 1..10) { + text = "foo(it) { $text }" + } + myFixture.configureByText("a.groovy", "def foo(T t, Closure cl) {}\n" + text) + myFixture.enableInspections(new MissingReturnInspection()) + IdeaTestUtil.assertTiming "slow", 10000, { myFixture.doHighlighting() } + + } + } From 5642f53c10030eefff268f9683a50071d306b67b Mon Sep 17 00:00:00 2001 From: Gregory Shrago Date: Mon, 16 May 2011 23:37:59 +0400 Subject: [PATCH 11/31] lazy pattern compiler & IDEA-18165 shareable intelliLang settings --- .../com/intellij/util/FileContentUtil.java | 8 + .../compiler/PatternCompilerFactoryImpl.java | 6 +- .../compiler/PatternCompilerImpl.java | 178 ++++++- .../intelliLang/AdvancedSettingsUI.java | 4 +- .../config/MethodParameterInjection.java | 9 +- .../inject/java/ConcatenationInjector.java | 8 +- .../java/JavaLanguageInjectionSupport.java | 31 +- .../java/LanguageReferenceProvider.java | 13 +- .../validation/InjectionNotApplicable.java | 2 +- .../java/validation/LanguageMismatch.java | 2 +- .../java/validation/UnknownLanguageID.java | 2 +- .../PatternAnnotationNotApplicable.java | 2 +- ...PatternOverriddenByNonAnnotatedMethod.java | 2 +- .../intelliLang/pattern/PatternValidator.java | 10 +- .../impl/PatternValidationCompiler.java | 7 +- ...SubstitutedExpressionEvaluationHelper.java | 4 +- plugins/IntelliLang/src/META-INF/plugin.xml | 15 +- .../plugins/intelliLang/Configuration.java | 479 +++++++++++------- .../intelliLang/InjectionsSettingsUI.java | 459 ++++++++++++----- .../plugins/intelliLang/Settings.java | 33 +- .../AbstractLanguageInjectionSupport.java | 2 - .../inject/EditInjectionSettingsAction.java | 2 +- .../inject/InjectLanguageAction.java | 2 +- .../inject/UnInjectLanguageAction.java | 2 +- .../inject/config/BaseInjection.java | 68 +-- .../inject/config/InjectionPlace.java | 20 +- .../config/ui/AbstractInjectionPanel.java | 2 +- .../inject/config/ui/BaseInjectionPanel.java | 10 +- .../inject/config/XmlAttributeInjection.java | 6 +- .../inject/config/XmlTagInjection.java | 5 +- .../xml/XmlLanguageInjectionSupport.java | 30 +- 31 files changed, 910 insertions(+), 513 deletions(-) diff --git a/platform/lang-api/src/com/intellij/util/FileContentUtil.java b/platform/lang-api/src/com/intellij/util/FileContentUtil.java index d627f9c15300..4a29dce33a44 100644 --- a/platform/lang-api/src/com/intellij/util/FileContentUtil.java +++ b/platform/lang-api/src/com/intellij/util/FileContentUtil.java @@ -20,6 +20,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -37,6 +38,7 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Set; /** @@ -102,4 +104,10 @@ public class FileContentUtil { } events.add(new VFilePropertyChangeEvent(FORCE_RELOAD_REQUESTOR, virtualFile, VirtualFile.PROP_NAME, virtualFile.getName(), virtualFile.getName(), false)); } + + public static void reparseOpenedFiles() { + for (Project project : ProjectManager.getInstance().getOpenProjects()) { + reparseFiles(project, Collections.emptyList(), true); + } + } } diff --git a/platform/lang-impl/src/com/intellij/patterns/compiler/PatternCompilerFactoryImpl.java b/platform/lang-impl/src/com/intellij/patterns/compiler/PatternCompilerFactoryImpl.java index 9d7e9acebadd..42a4e516f01d 100644 --- a/platform/lang-impl/src/com/intellij/patterns/compiler/PatternCompilerFactoryImpl.java +++ b/platform/lang-impl/src/com/intellij/patterns/compiler/PatternCompilerFactoryImpl.java @@ -44,9 +44,9 @@ public class PatternCompilerFactoryImpl extends PatternCompilerFactory { return result.isEmpty()? ArrayUtil.EMPTY_CLASS_ARRAY : result.toArray(new Class[result.size()]); } }; - private final Map myCompilers = new ConcurrentFactoryMap() { + private final Map, PatternCompiler> myCompilers = new ConcurrentFactoryMap, PatternCompiler>() { @Override - protected PatternCompiler create(Class[] key) { + protected PatternCompiler create(List key) { return new PatternCompilerImpl(key); } }; @@ -60,6 +60,6 @@ public class PatternCompilerFactoryImpl extends PatternCompilerFactory { @NotNull @Override public PatternCompiler getPatternCompiler(@NotNull Class[] patternClasses) { - return myCompilers.get(patternClasses); + return myCompilers.get(Arrays.asList(patternClasses)); } } diff --git a/platform/platform-impl/src/com/intellij/patterns/compiler/PatternCompilerImpl.java b/platform/platform-impl/src/com/intellij/patterns/compiler/PatternCompilerImpl.java index d0a28328b6f2..fb82f5b64368 100644 --- a/platform/platform-impl/src/com/intellij/patterns/compiler/PatternCompilerImpl.java +++ b/platform/platform-impl/src/com/intellij/patterns/compiler/PatternCompilerImpl.java @@ -19,12 +19,17 @@ package com.intellij.patterns.compiler; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.text.StringHash; import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.ElementPatternCondition; +import com.intellij.patterns.InitialPatternCondition; import com.intellij.util.Function; +import com.intellij.util.ProcessingContext; import com.intellij.util.ReflectionCache; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Stack; +import com.intellij.util.containers.StringInterner; import gnu.trove.THashMap; import gnu.trove.THashSet; import org.jetbrains.annotations.Nullable; @@ -39,15 +44,13 @@ public class PatternCompilerImpl implements PatternCompiler { private static final Logger LOG = Logger.getInstance(PatternCompilerImpl.class.getName()); - private Set myStaticMethods; + private final Set myStaticMethods; + private final StringInterner myStringInterner = new StringInterner(); - public PatternCompilerImpl(final Class[] patternClasses) { + public PatternCompilerImpl(final List patternClasses) { myStaticMethods = getStaticMethods(patternClasses); } - protected void preInvoke(Object target, String methodName, Object[] arguments) { - } - @Override @Nullable public ElementPattern createElementPattern(final String text, final String displayName) { @@ -61,23 +64,42 @@ public class PatternCompilerImpl implements PatternCompiler { } } + //@Override + //public ElementPattern compileElementPattern(final String text) { + // return processElementPatternText(text, new Function() { + // public Object fun(final Frame frame) { + // try { + // final Object[] args = frame.params.toArray(); + // preInvoke(frame.target, frame.methodName, args); + // return invokeMethod(frame.target, frame.methodName, args, myStaticMethods); + // } + // catch (Throwable throwable) { + // throw new IllegalArgumentException(text, throwable); + // } + // } + // }); + //} + @Override public ElementPattern compileElementPattern(final String text) { - return processElementPatternText(text, new Function() { - public Object fun(final Frame frame) { + final Node node = processElementPatternText(text, new Function() { + public Node fun(final Frame frame) { try { final Object[] args = frame.params.toArray(); - preInvoke(frame.target, frame.methodName, args); - return invokeMethod(frame.target, frame.methodName, args, myStaticMethods); + for (int i = 0, argsLength = args.length; i < argsLength; i++) { + args[i] = args[i] instanceof String ? myStringInterner.intern((String)args[i]) : args[i]; + } + return new Node((Node)frame.target, myStringInterner.intern(frame.methodName), args); } catch (Throwable throwable) { throw new IllegalArgumentException(text, throwable); } } }); + return new LazyPresentablePattern(node); } - private static Set getStaticMethods(Class[] patternClasses) { + private static Set getStaticMethods(List patternClasses) { return new THashSet(ContainerUtil.concat(patternClasses, new Function>() { public Collection fun(final Class aClass) { return ContainerUtil.findAll(ReflectionCache.getMethods(aClass), new Condition() { @@ -500,4 +522,140 @@ public class PatternCompilerImpl implements PatternCompiler { // } // return null; //} + + private static final ElementPattern ALWAYS_FALSE = new FalsePattern(); + + private static class Node { + final Node target; + final String method; + final Object[] args; + + private Node(final Node target, final String method, final Object[] args) { + this.target = target; + this.method = method; + this.args = args; + } + } + + private static class FalsePattern extends InitialPatternCondition implements ElementPattern { + private final ElementPatternCondition myCondition = new ElementPatternCondition(this); + + protected FalsePattern() { + super(Object.class); + } + + @Override + public boolean accepts(@Nullable final Object o) { + return false; + } + + @Override + public boolean accepts(@Nullable final Object o, final ProcessingContext context) { + return false; + } + + @Override + public ElementPatternCondition getCondition() { + return myCondition; + } + } + + + public class LazyPresentablePattern implements ElementPattern { + + private ElementPattern myCompiledPattern; + private final Node myNode; + private final long myHashCode; + + public LazyPresentablePattern(final Node node) { + myNode = node; + myHashCode = StringHash.calc(toString()); + } + + @Override + public boolean accepts(@Nullable final Object o) { + return getCompiledPattern().accepts(o, new ProcessingContext()); + } + + @Override + public boolean accepts(@Nullable final Object o, final ProcessingContext context) { + return getCompiledPattern().accepts(o, context); + } + + @Override + public ElementPatternCondition getCondition() { + return getCompiledPattern().getCondition(); + } + + public ElementPattern getCompiledPattern() { + if (myCompiledPattern == null) { + Object result; + try { + result = execute(myNode); + } + catch (Throwable throwable) { + LOG.error(toString(), throwable); + result = ALWAYS_FALSE; + } + myCompiledPattern = (ElementPattern)result; + } + return myCompiledPattern; + } + + @Override + public String toString() { + return toString(myNode, new StringBuilder()).toString(); + } + + private StringBuilder toString(final Node node, final StringBuilder sb) { + if (node.target != null) { + toString(node.target, sb); + sb.append('.'); + } + sb.append(node.method).append('('); + boolean first = true; + for (Object arg : node.args) { + if (first) first = false; + else sb.append(',').append(' '); + if (arg instanceof Node) { + toString((Node)arg, sb); + } + else if (arg instanceof String) { + sb.append('\"').append(StringUtil.escapeStringCharacters((String)arg)).append('\"'); + } + else if (arg instanceof Number) { + sb.append(arg); + } + } + sb.append(')'); + return sb; + } + + private Object execute(final Node node) throws Throwable { + final Object target = node.target != null? execute(node.target) : null; + final String methodName = node.method; + final Object[] args; + if (node.args.length == 0) { + args = node.args; + } + else { + args = new Object[node.args.length]; + for (int i = 0, len = node.args.length; i < len; i++) { + args[i] = node.args[i] instanceof Node? execute((Node)node.args[i]) : node.args[i]; + } + } + return invokeMethod(target, methodName, args, myStaticMethods); + } + + @Override + public int hashCode() { + return (int)myHashCode; + } + + @Override + public boolean equals(final Object obj) { + return obj instanceof LazyPresentablePattern && + ((LazyPresentablePattern)obj).myHashCode == myHashCode; + } + } } diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/AdvancedSettingsUI.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/AdvancedSettingsUI.java index e2a86f70b5d6..c23e2146268d 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/AdvancedSettingsUI.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/AdvancedSettingsUI.java @@ -43,7 +43,7 @@ import java.util.Arrays; * @author Gregory.Shrago */ public class AdvancedSettingsUI implements Configurable { - private final Configuration myConfiguration; + private final Configuration.AdvancedConfiguration myConfiguration; @SuppressWarnings({"UnusedDeclaration", "FieldCanBeLocal"}) private JPanel myRoot; @@ -65,7 +65,7 @@ public class AdvancedSettingsUI implements Configurable { private final ReferenceEditorWithBrowseButton mySubstField; public AdvancedSettingsUI(@NotNull final Project project, Configuration configuration) { - myConfiguration = configuration; + myConfiguration = configuration.getAdvancedConfiguration(); myAnnotationField = new ReferenceEditorWithBrowseButton(null, project, new Function() { public Document fun(String s) { diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/MethodParameterInjection.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/MethodParameterInjection.java index 69e89b3f8ae8..f4e44709d88d 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/MethodParameterInjection.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/config/MethodParameterInjection.java @@ -21,6 +21,7 @@ import com.intellij.openapi.util.JDOMExternalizableStringList; import com.intellij.openapi.util.JDOMExternalizer; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.patterns.compiler.PatternCompiler; import com.intellij.psi.*; import com.intellij.psi.util.PsiFormatUtil; import com.intellij.util.IncorrectOperationException; @@ -118,8 +119,12 @@ public class MethodParameterInjection extends BaseInjection { } @Override - protected List generatePlaces() { - return getPatternString(this); + public void generatePlaces() { + getInjectionPlaces().clear(); + final PatternCompiler compiler = getCompiler(); + for (String text : getPatternString(this)) { + getInjectionPlaces().add(new InjectionPlace(compiler.createElementPattern(text, getDisplayName()), true)); + } } @SuppressWarnings({"RedundantIfStatement"}) diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/ConcatenationInjector.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/ConcatenationInjector.java index aa922edfc897..49e9c43bc595 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/ConcatenationInjector.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/ConcatenationInjector.java @@ -80,7 +80,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector { }, false); myAnnoIndex = CachedValuesManager.getManager(myProject).createCachedValue(new CachedValueProvider>() { public Result> compute() { - final String annotationClass = myConfiguration.getLanguageAnnotationClass(); + final String annotationClass = myConfiguration.getAdvancedConfiguration().getLanguageAnnotationClass(); final Collection result = new THashSet(); final ArrayList annoClasses = new ArrayList(3); annoClasses.add(StringUtil.getShortName(annotationClass)); @@ -211,7 +211,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector { } public boolean visitVariable(PsiVariable variable) { - if (myConfiguration.getDfaOption() != Configuration.DfaOption.OFF && visitedVars.add(variable)) { + if (myConfiguration.getAdvancedConfiguration().getDfaOption() != Configuration.DfaOption.OFF && visitedVars.add(variable)) { ReferencesSearch.search(variable, searchScope).forEach(new Processor() { @Override public boolean process(PsiReference psiReference) { @@ -247,7 +247,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector { } public boolean visitReference(PsiReferenceExpression expression) { - if (myConfiguration.getDfaOption() == Configuration.DfaOption.OFF) return true; + if (myConfiguration.getAdvancedConfiguration().getDfaOption() == Configuration.DfaOption.OFF) return true; final PsiElement e = expression.resolve(); if (e instanceof PsiVariable) { if (e instanceof PsiParameter) { @@ -300,7 +300,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector { else checkName = null; if (checkName == null || !areThereInjectionsWithName(checkName, true)) return true; final PsiAnnotation[] annotations = - AnnotationUtilEx.getAnnotationFrom(annoElement, myConfiguration.getLanguageAnnotationPair(), true); + AnnotationUtilEx.getAnnotationFrom(annoElement, myConfiguration.getAdvancedConfiguration().getLanguageAnnotationPair(), true); if (annotations.length > 0) { final String id = AnnotationUtilEx.calcAnnotationValue(annotations, "value"); final String prefix = AnnotationUtilEx.calcAnnotationValue(annotations, "prefix"); diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/JavaLanguageInjectionSupport.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/JavaLanguageInjectionSupport.java index dbb1063450fe..c96e264d324c 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/JavaLanguageInjectionSupport.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/JavaLanguageInjectionSupport.java @@ -32,6 +32,7 @@ import com.intellij.openapi.util.Factory; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.PsiJavaPatterns; +import com.intellij.patterns.compiler.PatternCompiler; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.GlobalSearchScope; @@ -102,11 +103,11 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo public boolean removeInjectionInPlace(final PsiLanguageInjectionHost psiElement) { if (!isMine(psiElement)) return false; - final Configuration configuration = Configuration.getInstance(); final HashMap> injectionsMap = new HashMap>(); final ArrayList annotations = new ArrayList(); final PsiLiteralExpression host = (PsiLiteralExpression)psiElement; final Project project = host.getProject(); + final Configuration configuration = Configuration.getProjectInstance(project); collectInjections(host, configuration, injectionsMap, annotations); if (injectionsMap.isEmpty() && annotations.isEmpty()) return false; @@ -120,17 +121,17 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo return newInjection; } }); - Configuration.getInstance().replaceInjectionsWithUndo(project, newInjections, originalInjections, annotations); + configuration.replaceInjectionsWithUndo(project, newInjections, originalInjections, annotations); return true; } public boolean editInjectionInPlace(final PsiLanguageInjectionHost psiElement) { if (!isMine(psiElement)) return false; - final Configuration configuration = Configuration.getInstance(); final HashMap> injectionsMap = new HashMap>(); final ArrayList annotations = new ArrayList(); final PsiLiteralExpression host = (PsiLiteralExpression)psiElement; final Project project = host.getProject(); + final Configuration configuration = Configuration.getProjectInstance(project); collectInjections(host, configuration, injectionsMap, annotations); if (injectionsMap.isEmpty() || !annotations.isEmpty()) return false; @@ -139,10 +140,9 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo final MethodParameterInjection copy = methodParameterInjection.copy(); final BaseInjection newInjection = showInjectionUI(project, methodParameterInjection); if (newInjection != null) { - copy.initializePlaces(false); newInjection.mergeOriginalPlacesFrom(copy, false); newInjection.mergeOriginalPlacesFrom(originalInjection, true); - Configuration.getInstance().replaceInjectionsWithUndo( + configuration.replaceInjectionsWithUndo( project, Collections.singletonList(newInjection), Collections.singletonList(originalInjection), Collections.emptyList()); } return true; @@ -165,7 +165,6 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo } }); if (builder.show() == DialogWrapper.OK_EXIT_CODE) { - methodParameterInjection.initializePlaces(false); return new BaseInjection(methodParameterInjection.getSupportId()).copyFrom(methodParameterInjection); } return null; @@ -256,6 +255,7 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo info.getParamFlags()[parameterIndex] = true; } injection.setMethodInfos(Collections.singletonList(info)); + injection.generatePlaces(); doEditInjection(project, injection, psiMethod); return true; } @@ -307,11 +307,9 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo } private static void doEditInjection(final Project project, final MethodParameterInjection template, final PsiMethod contextMethod) { - final Configuration configuration = Configuration.getInstance(); - template.initializePlaces(false); + final Configuration configuration = Configuration.getProjectInstance(project); final BaseInjection baseTemplate = new BaseInjection(template.getSupportId()).copyFrom(template); final MethodParameterInjection allMethodParameterInjection = createFrom(project, baseTemplate, contextMethod, true); - allMethodParameterInjection.initializePlaces(false); // find existing injection for this class. final BaseInjection originalInjection = configuration.findExistingInjection(allMethodParameterInjection); final MethodParameterInjection methodParameterInjection; @@ -326,12 +324,11 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo methodParameterInjection = createFrom(project, originalCopy, contextMethod, false); } if (InjectLanguageAction.doEditConfigurable(project, new MethodParameterInjectionConfigurable(methodParameterInjection, null, project))) { - methodParameterInjection.initializePlaces(false); final BaseInjection newInjection = new BaseInjection(methodParameterInjection.getSupportId()).copyFrom(methodParameterInjection); if (originalInjection != null) { newInjection.mergeOriginalPlacesFrom(originalInjection, true); } - Configuration.getInstance().replaceInjectionsWithUndo( + configuration.replaceInjectionsWithUndo( project, Collections.singletonList(newInjection), ContainerUtil.createMaybeSingletonList(originalInjection), Collections.emptyList()); @@ -344,7 +341,7 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo new ConcatenationInjector.InjectionProcessor(configuration, host) { @Override protected boolean processAnnotationInjections(PsiModifierListOwner annoElement) { - ContainerUtil.addAll(annotations, AnnotationUtilEx.getAnnotationFrom(annoElement, configuration.getLanguageAnnotationPair(), true)); + ContainerUtil.addAll(annotations, AnnotationUtilEx.getAnnotationFrom(annoElement, configuration.getAdvancedConfiguration().getLanguageAnnotationPair(), true)); return true; } @@ -395,6 +392,7 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo final ArrayList infos = new ArrayList(); if (classes.length > 0) { final THashSet visitedSignatures = new THashSet(); + final PatternCompiler compiler = injection.getCompiler(); for (PsiClass psiClass : classes) { for (PsiMethod method : psiClass.getMethods()) { final PsiModifierList modifiers = method.getModifierList(); @@ -404,7 +402,8 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo if (!visitedSignatures.add(methodInfo.getMethodSignature())) continue; if (isInjectable(method.getReturnType(), method.getProject())) { final int parameterIndex = -1; - final InjectionPlace place = injection.findPlaceByText(getPatternStringForJavaPlace(method, parameterIndex)); + final InjectionPlace place = ContainerUtil.find( + injection.getInjectionPlaces(), new InjectionPlace(compiler.compileElementPattern(getPatternStringForJavaPlace(method, parameterIndex)), true)); methodInfo.setReturnFlag(place != null && place.isEnabled() || includeAllPlaces); add = true; } @@ -412,7 +411,9 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo for (int i = 0; i < parameters.length; i++) { final PsiParameter p = parameters[i]; if (isInjectable(p.getType(), p.getProject())) { - final InjectionPlace place = injection.findPlaceByText(getPatternStringForJavaPlace(method, i)); + final InjectionPlace place = ContainerUtil.find( + injection.getInjectionPlaces(), + new InjectionPlace(compiler.compileElementPattern(getPatternStringForJavaPlace(method, i)), true)); methodInfo.getParamFlags()[i] = place != null && place.isEnabled() || includeAllPlaces; add = true; } @@ -433,6 +434,7 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo //} } result.setMethodInfos(infos); + result.generatePlaces(); return result; } @@ -470,7 +472,6 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo if (newInjection != null) { newInjection.mergeOriginalPlacesFrom(originalInjection, mergeEnabled); originalInjection.copyFrom(newInjection); - originalInjection.initializePlaces(true); } } else { diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/LanguageReferenceProvider.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/LanguageReferenceProvider.java index e8f36cab82d6..e8510b3b2974 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/LanguageReferenceProvider.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/LanguageReferenceProvider.java @@ -16,7 +16,6 @@ package org.intellij.plugins.intelliLang.inject.java; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Computable; import com.intellij.patterns.PatternCondition; import com.intellij.patterns.StandardPatterns; import com.intellij.psi.*; @@ -32,20 +31,14 @@ import static com.intellij.patterns.PsiJavaPatterns.literalExpression; * Provides references to Language-IDs and RegExp enums for completion. */ public final class LanguageReferenceProvider extends PsiReferenceContributor { - private final Configuration myConfig = Configuration.getInstance(); - - private final Computable ANNOTATION_NAME = new Computable() { - public String compute() { - return myConfig.getLanguageAnnotationClass(); - } - }; public void registerReferenceProviders(PsiReferenceRegistrar registrar) { + final Configuration configuration = Configuration.getInstance(); registrar.registerReferenceProvider( literalExpression().annotationParam(StandardPatterns.string().with(new PatternCondition("isLanguageAnnotation") { @Override public boolean accepts(@NotNull final String s, final ProcessingContext context) { - return Comparing.equal(ANNOTATION_NAME.compute(), s); + return Comparing.equal(configuration.getAdvancedConfiguration().getLanguageAnnotationClass(), s); } }), "value").and(literalExpression().with(new PatternCondition("isStringLiteral") { @Override @@ -72,7 +65,7 @@ public final class LanguageReferenceProvider extends PsiReferenceContributor { final PsiModifierListOwner owner = AnnotationUtilEx.getAnnotatedElementFor(expression, AnnotationUtilEx.LookupType.PREFER_DECLARATION); if (owner != null && PsiUtilEx.isLanguageAnnotationTarget(owner)) { - final PsiAnnotation[] annotations = AnnotationUtilEx.getAnnotationFrom(owner, myConfig.getPatternAnnotationPair(), true); + final PsiAnnotation[] annotations = AnnotationUtilEx.getAnnotationFrom(owner, configuration.getAdvancedConfiguration().getPatternAnnotationPair(), true); if (annotations.length > 0) { final String pattern = AnnotationUtilEx.calcAnnotationValue(annotations, "value"); if (pattern != null) { diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/validation/InjectionNotApplicable.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/validation/InjectionNotApplicable.java index bc9d66c82fcd..a910d025b33b 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/validation/InjectionNotApplicable.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/validation/InjectionNotApplicable.java @@ -51,7 +51,7 @@ public class InjectionNotApplicable extends LocalInspectionTool { @NotNull public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { return new JavaElementVisitor() { - final String annotationName = Configuration.getInstance().getLanguageAnnotationClass(); + final String annotationName = Configuration.getProjectInstance(holder.getProject()).getAdvancedConfiguration().getLanguageAnnotationClass(); public void visitReferenceExpression(PsiReferenceExpression expression) { } diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/validation/LanguageMismatch.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/validation/LanguageMismatch.java index 0d2f8414a253..7f79f9c67913 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/validation/LanguageMismatch.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/validation/LanguageMismatch.java @@ -76,7 +76,7 @@ public class LanguageMismatch extends LocalInspectionTool { @NotNull public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { return new JavaElementVisitor() { - final Pair> annotationName = Configuration.getInstance().getLanguageAnnotationPair(); + final Pair> annotationName = Configuration.getProjectInstance(holder.getProject()).getAdvancedConfiguration().getLanguageAnnotationPair(); public void visitExpression(PsiExpression expression) { checkExpression(expression, holder, annotationName); diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/validation/UnknownLanguageID.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/validation/UnknownLanguageID.java index fc987720250a..f323cb4f84c3 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/validation/UnknownLanguageID.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/inject/java/validation/UnknownLanguageID.java @@ -51,7 +51,7 @@ public class UnknownLanguageID extends LocalInspectionTool { @NotNull public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { return new JavaElementVisitor() { - final String annotationName = Configuration.getInstance().getLanguageAnnotationClass(); + final String annotationName = Configuration.getProjectInstance(holder.getProject()).getAdvancedConfiguration().getLanguageAnnotationClass(); public void visitReferenceExpression(PsiReferenceExpression expression) { } diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/PatternAnnotationNotApplicable.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/PatternAnnotationNotApplicable.java index 0d7979edba2c..3003379fc491 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/PatternAnnotationNotApplicable.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/PatternAnnotationNotApplicable.java @@ -51,7 +51,7 @@ public class PatternAnnotationNotApplicable extends LocalInspectionTool { @NotNull public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { return new JavaElementVisitor() { - final String annotationName = Configuration.getInstance().getPatternAnnotationClass(); + final String annotationName = Configuration.getProjectInstance(holder.getProject()).getAdvancedConfiguration().getPatternAnnotationClass(); public void visitReferenceExpression(PsiReferenceExpression expression) { } diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/PatternOverriddenByNonAnnotatedMethod.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/PatternOverriddenByNonAnnotatedMethod.java index c6600e3f652a..5f418ab5a078 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/PatternOverriddenByNonAnnotatedMethod.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/PatternOverriddenByNonAnnotatedMethod.java @@ -53,7 +53,7 @@ public class PatternOverriddenByNonAnnotatedMethod extends LocalInspectionTool { @NotNull public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { return new JavaElementVisitor() { - final Pair> annotationName = Configuration.getInstance().getPatternAnnotationPair(); + final Pair> annotationName = Configuration.getProjectInstance(holder.getProject()).getAdvancedConfiguration().getPatternAnnotationPair(); public void visitReferenceExpression(PsiReferenceExpression expression) { } diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/PatternValidator.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/PatternValidator.java index b5506442e449..43854a802f45 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/PatternValidator.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/PatternValidator.java @@ -173,7 +173,7 @@ public class PatternValidator extends LocalInspectionTool { final PsiModifierListOwner element; if (isAnnotationValue) { final PsiAnnotation psiAnnotation = PsiTreeUtil.getParentOfType(expression, PsiAnnotation.class); - if (psiAnnotation != null && myConfiguration.getSubstAnnotationClass().equals(psiAnnotation.getQualifiedName())) { + if (psiAnnotation != null && myConfiguration.getAdvancedConfiguration().getSubstAnnotationClass().equals(psiAnnotation.getQualifiedName())) { element = PsiTreeUtil.getParentOfType(expression, PsiModifierListOwner.class); } else { @@ -184,7 +184,7 @@ public class PatternValidator extends LocalInspectionTool { element = AnnotationUtilEx.getAnnotatedElementFor(expression, AnnotationUtilEx.LookupType.PREFER_CONTEXT); } if (element != null && PsiUtilEx.isLanguageAnnotationTarget(element)) { - PsiAnnotation[] annotations = AnnotationUtilEx.getAnnotationFrom(element, myConfiguration.getPatternAnnotationPair(), true); + PsiAnnotation[] annotations = AnnotationUtilEx.getAnnotationFrom(element, myConfiguration.getAdvancedConfiguration().getPatternAnnotationPair(), true); checkExpression(expression, annotations, holder); } } @@ -224,7 +224,7 @@ public class PatternValidator extends LocalInspectionTool { List nonConstantElements = new SmartList(); final Object result = new SubstitutedExpressionEvaluationHelper(expression.getProject()).computeExpression( - expression, myConfiguration.getDfaOption(), false, nonConstantElements); + expression, myConfiguration.getAdvancedConfiguration().getDfaOption(), false, nonConstantElements); final String o = result == null ? null : String.valueOf(result); if (o != null) { if (!pattern.matcher(o).matches()) { @@ -258,13 +258,13 @@ public class PatternValidator extends LocalInspectionTool { final PsiModifierListOwner owner = e instanceof PsiModifierListOwner? (PsiModifierListOwner)e : null; LocalQuickFix quickFix; if (owner != null && PsiUtilEx.isLanguageAnnotationTarget(owner)) { - PsiAnnotation[] resolvedAnnos = AnnotationUtilEx.getAnnotationFrom(owner, myConfiguration.getPatternAnnotationPair(), true); + PsiAnnotation[] resolvedAnnos = AnnotationUtilEx.getAnnotationFrom(owner, myConfiguration.getAdvancedConfiguration().getPatternAnnotationPair(), true); if (resolvedAnnos.length == 2 && annotations.length == 2 && Comparing.strEqual(resolvedAnnos[1].getQualifiedName(), annotations[1].getQualifiedName())) { // both target and source annotated indirectly with the same anno return; } - final String classname = Configuration.getInstance().getSubstAnnotationPair().first; + final String classname = myConfiguration.getAdvancedConfiguration().getSubstAnnotationPair().first; final AnnotateFix fix = new AnnotateFix((PsiModifierListOwner)e, classname); quickFix = fix.canApply() ? fix : new IntroduceVariableFix(expr); } diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/compiler/impl/PatternValidationCompiler.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/compiler/impl/PatternValidationCompiler.java index d2f9f66459be..293f29f1d0ec 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/compiler/impl/PatternValidationCompiler.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/pattern/compiler/impl/PatternValidationCompiler.java @@ -45,7 +45,8 @@ public class PatternValidationCompiler extends AnnotationBasedInstrumentingCompi protected String[] getAnnotationNames(Project project) { synchronized (myAnnotations) { myAnnotations.clear(); - final Pair> patternAnnotation = Configuration.getInstance().getPatternAnnotationPair(); + final Pair> patternAnnotation = + Configuration.getProjectInstance(project).getAdvancedConfiguration().getPatternAnnotationPair(); final GlobalSearchScope scope = GlobalSearchScope.allScope(project); final PsiClass psiClass = JavaPsiFacade.getInstance(project).findClass(patternAnnotation.first, scope); @@ -83,14 +84,14 @@ public class PatternValidationCompiler extends AnnotationBasedInstrumentingCompi } protected boolean isEnabled() { - final Configuration.InstrumentationType option = Configuration.getInstance().getInstrumentation(); + final Configuration.InstrumentationType option = Configuration.getInstance().getAdvancedConfiguration().getInstrumentation(); return option == Configuration.InstrumentationType.ASSERT || option == Configuration.InstrumentationType.EXCEPTION; } @NotNull protected Instrumenter createInstrumenter(ClassWriter classwriter) { synchronized (myAnnotations) { - final Configuration.InstrumentationType instrumentation = Configuration.getInstance().getInstrumentation(); + final Configuration.InstrumentationType instrumentation = Configuration.getInstance().getAdvancedConfiguration().getInstrumentation(); return new PatternValidationInstrumenter(new HashMap(myAnnotations), classwriter, instrumentation); } } diff --git a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java index 6a4ab0358575..edde2ccfd863 100644 --- a/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java +++ b/plugins/IntelliLang/java-support/org/intellij/plugins/intelliLang/util/SubstitutedExpressionEvaluationHelper.java @@ -45,7 +45,7 @@ public class SubstitutedExpressionEvaluationHelper { } public Object computeExpression(final PsiExpression e, final List uncomputables) { - return computeExpression(e, myConfiguration.getDfaOption(), myConfiguration.isIncludeUncomputablesAsLiterals(), uncomputables); + return computeExpression(e, myConfiguration.getAdvancedConfiguration().getDfaOption(), myConfiguration.getAdvancedConfiguration().isIncludeUncomputablesAsLiterals(), uncomputables); } public Object computeExpression(final PsiExpression e, final Configuration.DfaOption dfaOption, final boolean includeUncomputablesAsLiterals, final List uncomputables) { @@ -127,7 +127,7 @@ public class SubstitutedExpressionEvaluationHelper { @Nullable private Object calcSubstituted(final PsiModifierListOwner owner) { - final PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, myConfiguration.getSubstAnnotationPair().second); + final PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, myConfiguration.getAdvancedConfiguration().getSubstAnnotationPair().second); if (annotation != null) { return AnnotationUtilEx.calcAnnotationValue(annotation, "value"); } diff --git a/plugins/IntelliLang/src/META-INF/plugin.xml b/plugins/IntelliLang/src/META-INF/plugin.xml index 95faa6fef94a..72297bfd4f4a 100644 --- a/plugins/IntelliLang/src/META-INF/plugin.xml +++ b/plugins/IntelliLang/src/META-INF/plugin.xml @@ -39,20 +39,17 @@ - + - + + - - - - org.intellij.plugins.intelliLang.Configuration - - + diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java index 2376047017b6..bb86fb7ee918 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java @@ -19,22 +19,16 @@ import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.IdeaPluginDescriptorImpl; import com.intellij.ide.plugins.PluginManager; import com.intellij.ide.plugins.cl.PluginClassLoader; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.UndoConfirmationPolicy; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.command.undo.GlobalUndoableAction; import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.command.undo.UndoableAction; -import com.intellij.openapi.components.PersistentStateComponent; -import com.intellij.openapi.components.State; -import com.intellij.openapi.components.Storage; -import com.intellij.openapi.components.StorageScheme; +import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.util.*; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiCompiledElement; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -46,6 +40,7 @@ import com.intellij.util.NullableFunction; import com.intellij.util.PairProcessor; import com.intellij.util.containers.ConcurrentFactoryMap; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Convertor; import gnu.trove.THashMap; import gnu.trove.THashSet; import org.intellij.plugins.intelliLang.inject.InjectorUtils; @@ -72,12 +67,88 @@ import java.util.*; * Making it a service may result in FileContentUtil.reparseFiles at a random loading moment which may cause * mysterious PSI validity losses */ -@State( - name = Configuration.COMPONENT_NAME, - storages = {@Storage(id = "dir", file = "$APP_CONFIG$/IntelliLang.xml", scheme = StorageScheme.DIRECTORY_BASED)}) -public final class Configuration implements PersistentStateComponent, ModificationTracker { +public class Configuration implements PersistentStateComponent, ModificationTracker { + static final Logger LOG = Logger.getInstance(Configuration.class.getName()); + @State( + name = Configuration.COMPONENT_NAME, + storages = {@Storage(id = "dir", file = "$APP_CONFIG$/IntelliLang.xml", scheme = StorageScheme.DIRECTORY_BASED)}) + public static class App extends Configuration { + + private final List myDefaultInjections; + private final AdvancedConfiguration myAdvancedConfiguration; + + App() { + myDefaultInjections = loadDefaultInjections(); + myAdvancedConfiguration = new AdvancedConfiguration(); + } + + @Override + public List getDefaultInjections() { + return myDefaultInjections; + } + + @Override + public AdvancedConfiguration getAdvancedConfiguration() { + return myAdvancedConfiguration; + } + + @Override + public void loadState(final Element element) { + myAdvancedConfiguration.loadState(element); + super.loadState(element); + } + + @Override + public Element getState() { + final Element element = new Element(COMPONENT_NAME); + myAdvancedConfiguration.writeState(element); + return getState(element); + } + } + @State( + name = Configuration.COMPONENT_NAME, + storages = {@Storage(id = "default", file = "$PROJECT_FILE$"), + @Storage(id = "dir", file = "$PROJECT_CONFIG_DIR$/IntelliLang.xml", scheme = StorageScheme.DIRECTORY_BASED)}) + public static class Prj extends Configuration { + + private final Configuration myParentConfiguration; + + Prj(final Configuration configuration) { + myParentConfiguration = configuration; + } + + @Override + public AdvancedConfiguration getAdvancedConfiguration() { + return myParentConfiguration.getAdvancedConfiguration(); + } + + @Override + public List getDefaultInjections() { + return myParentConfiguration.getDefaultInjections(); + } + + @NotNull + @Override + public List getInjections(final String injectorId) { + return ContainerUtil.concat(myParentConfiguration.getInjections(injectorId), getOwnInjections(injectorId)); + } + + public Configuration getParentConfiguration() { + return myParentConfiguration; + } + + public List getOwnInjections(final String injectorId) { + return super.getInjections(injectorId); + } + + @Override + public long getModificationCount() { + return super.getModificationCount() + myParentConfiguration.getModificationCount(); + } + } + public enum InstrumentationType { NONE, ASSERT, EXCEPTION } @@ -108,37 +179,17 @@ public final class Configuration implements PersistentStateComponent, M return ContainerUtil.createEmptyCOWList(); } }; - private ArrayList myDefaultInjections; - // runtime pattern validation instrumentation - @NotNull private InstrumentationType myInstrumentationType = InstrumentationType.ASSERT; - - // annotation class names - @NotNull private String myLanguageAnnotation; - @NotNull private String myPatternAnnotation; - @NotNull private String mySubstAnnotation; - - private boolean myIncludeUncomputablesAsLiterals; - private DfaOption myDfaOption = DfaOption.RESOLVE; - - // cached annotation name pairs - private Pair> myLanguageAnnotationPair; - private Pair> myPatternAnnotationPair; - - private Pair> mySubstAnnotationPair; private volatile long myModificationCount; public Configuration() { - setLanguageAnnotation("org.intellij.lang.annotations.Language"); - setPatternAnnotation("org.intellij.lang.annotations.Pattern"); - setSubstAnnotation("org.intellij.lang.annotations.Subst"); + } + + public AdvancedConfiguration getAdvancedConfiguration() { + throw new UnsupportedOperationException("getAdvancedConfiguration should not be called"); } public void loadState(final Element element) { - loadState(element, true); - } - - public void loadState(final Element element, final boolean mergeWithOriginalAndCompile) { final THashMap supports = new THashMap(); for (LanguageInjectionSupport support : Extensions.getExtensions(LanguageInjectionSupport.EP_NAME)) { supports.put(support.getId(), support); @@ -151,30 +202,7 @@ public final class Configuration implements PersistentStateComponent, M injection.loadState(child); myInjections.get(key).add(injection); } - setInstrumentationType(JDOMExternalizerUtil.readField(element, INSTRUMENTATION_TYPE_NAME)); - setLanguageAnnotation(JDOMExternalizerUtil.readField(element, LANGUAGE_ANNOTATION_NAME)); - setPatternAnnotation(JDOMExternalizerUtil.readField(element, PATTERN_ANNOTATION_NAME)); - setSubstAnnotation(JDOMExternalizerUtil.readField(element, SUBST_ANNOTATION_NAME)); - if (readBoolean(element, RESOLVE_REFERENCES, true)) { - setDfaOption(DfaOption.RESOLVE); - } - if (readBoolean(element, LOOK_FOR_VAR_ASSIGNMENTS, false)) { - setDfaOption(DfaOption.ASSIGNMENTS); - } - if (readBoolean(element, USE_DFA_IF_AVAILABLE, false)) { - setDfaOption(DfaOption.DFA); - } - setIncludeUncomputablesAsLiterals(readBoolean(element, INCLUDE_UNCOMPUTABLES_AS_LITERALS, false)); - - if (mergeWithOriginalAndCompile) { - mergeWithDefaultConfiguration(); - - for (String supportId : InjectorUtils.getActiveInjectionSupportIds()) { - for (BaseInjection injection : getInjections(supportId)) { - injection.initializePlaces(true); - } - } - } + importPlaces(getDefaultInjections()); } private void loadStateOld(Element element, final LanguageInjectionSupport xmlSupport, final LanguageInjectionSupport javaSupport) { @@ -208,7 +236,7 @@ public final class Configuration implements PersistentStateComponent, M return Boolean.parseBoolean(value); } - private void mergeWithDefaultConfiguration() { + private static List loadDefaultInjections() { final ArrayList cfgList = new ArrayList(); for (LanguageInjectionSupport support : InjectorUtils.getActiveInjectionSupports()) { final String config = support.getDefaultConfigUrl(); @@ -247,47 +275,26 @@ public final class Configuration implements PersistentStateComponent, M } } - final ArrayList originalInjections = new ArrayList(); - final ArrayList newInjections = new ArrayList(); - myDefaultInjections = new ArrayList(); + final ArrayList defaultInjections = new ArrayList(); for (String supportId : InjectorUtils.getActiveInjectionSupportIds()) { for (Configuration cfg : cfgList) { final List imported = cfg.getInjections(supportId); - myDefaultInjections.addAll(imported); - importInjections(getInjections(supportId), imported, originalInjections, newInjections); + defaultInjections.addAll(imported); } } - replaceInjections(newInjections, originalInjections); + return defaultInjections; } public Element getState() { - final Element element = new Element(COMPONENT_NAME); - - JDOMExternalizerUtil.writeField(element, INSTRUMENTATION_TYPE_NAME, myInstrumentationType.toString()); - JDOMExternalizerUtil.writeField(element, LANGUAGE_ANNOTATION_NAME, myLanguageAnnotation); - JDOMExternalizerUtil.writeField(element, PATTERN_ANNOTATION_NAME, myPatternAnnotation); - JDOMExternalizerUtil.writeField(element, SUBST_ANNOTATION_NAME, mySubstAnnotation); - switch (myDfaOption) { - case OFF: - break; - case RESOLVE: - JDOMExternalizerUtil.writeField(element, RESOLVE_REFERENCES, Boolean.TRUE.toString()); - break; - case ASSIGNMENTS: - JDOMExternalizerUtil.writeField(element, LOOK_FOR_VAR_ASSIGNMENTS, Boolean.TRUE.toString()); - break; - case DFA: - JDOMExternalizerUtil.writeField(element, USE_DFA_IF_AVAILABLE, Boolean.TRUE.toString()); - break; - } + return getState(new Element(COMPONENT_NAME)); + } + protected Element getState(final Element element) { final List injectorIds = new ArrayList(myInjections.keySet()); Collections.sort(injectorIds); for (String key : injectorIds) { final List injections = new ArrayList(myInjections.get(key)); - if (myDefaultInjections != null) { - injections.removeAll(myDefaultInjections); - } + injections.removeAll(getDefaultInjections()); Collections.sort(injections, new Comparator() { public int compare(final BaseInjection o1, final BaseInjection o2) { return Comparing.compare(o1.getDisplayName(), o2.getDisplayName()); @@ -315,59 +322,15 @@ public final class Configuration implements PersistentStateComponent, M } public static Configuration getInstance() { - return ApplicationManager.getApplication().getComponent(Configuration.class); + return ServiceManager.getService(Configuration.class); } - public String getLanguageAnnotationClass() { - return myLanguageAnnotation; + public static Configuration getProjectInstance(Project project) { + return ServiceManager.getService(project, Configuration.class); } - public String getPatternAnnotationClass() { - return myPatternAnnotation; - } - - public String getSubstAnnotationClass() { - return mySubstAnnotation; - } - - public void setInstrumentationType(@Nullable String type) { - if (type != null) { - setInstrumentationType(InstrumentationType.valueOf(type)); - } - } - - public void setInstrumentationType(@NotNull InstrumentationType type) { - myInstrumentationType = type; - } - - public void setLanguageAnnotation(@Nullable String languageAnnotation) { - if (languageAnnotation == null) return; - myLanguageAnnotation = languageAnnotation; - myLanguageAnnotationPair = Pair.create(languageAnnotation, Collections.singleton(languageAnnotation)); - } - - public Pair> getLanguageAnnotationPair() { - return myLanguageAnnotationPair; - } - - public void setPatternAnnotation(@Nullable String patternAnnotation) { - if (patternAnnotation == null) return; - myPatternAnnotation = patternAnnotation; - myPatternAnnotationPair = Pair.create(patternAnnotation, Collections.singleton(patternAnnotation)); - } - - public Pair> getPatternAnnotationPair() { - return myPatternAnnotationPair; - } - - public void setSubstAnnotation(@Nullable String substAnnotation) { - if (substAnnotation == null) return; - mySubstAnnotation = substAnnotation; - mySubstAnnotationPair = Pair.create(substAnnotation, Collections.singleton(substAnnotation)); - } - - public Pair> getSubstAnnotationPair() { - return mySubstAnnotationPair; + public List getDefaultInjections() { + return Collections.emptyList(); } @Nullable @@ -375,16 +338,23 @@ public final class Configuration implements PersistentStateComponent, M try { final Document document = JDOMUtil.loadDocument(is); final ArrayList elements = new ArrayList(); - elements.add(document.getRootElement()); - elements.addAll(document.getRootElement().getChildren("component")); - final Element element = ContainerUtil.find(elements, new Condition() { - public boolean value(final Element element) { - return "component".equals(element.getName()) && COMPONENT_NAME.equals(element.getAttributeValue("name")); - } - }); - if (element != null) { + final Element rootElement = document.getRootElement(); + final Element state; + if (rootElement.getName().equals(COMPONENT_NAME)) { + state = rootElement; + } + else { + elements.add(rootElement); + elements.addAll(rootElement.getChildren("component")); + state = ContainerUtil.find(elements, new Condition() { + public boolean value(final Element element) { + return "component".equals(element.getName()) && COMPONENT_NAME.equals(element.getAttributeValue("name")); + } + }); + } + if (state != null) { final Configuration cfg = new Configuration(); - cfg.loadState(element, false); + cfg.loadState(state); return cfg; } return null; @@ -394,16 +364,19 @@ public final class Configuration implements PersistentStateComponent, M } } - /** - * Import from another configuration (e.g. imported file). Returns the number of imported items. - * @param cfg configuration to import from - * @return added injections count - */ - public int importFrom(final Configuration cfg) { + private int importPlaces(final List injections) { + final Map> map = ContainerUtil.classify(injections.iterator(), new Convertor() { + @Override + public String convert(final BaseInjection o) { + return o.getSupportId(); + } + }); final ArrayList originalInjections = new ArrayList(); final ArrayList newInjections = new ArrayList(); for (String supportId : InjectorUtils.getActiveInjectionSupportIds()) { - importInjections(getInjections(supportId), cfg.getInjections(supportId), originalInjections, newInjections); + final Set importingInjections = map.get(supportId); + if (importingInjections == null) continue; + importInjections(getInjections(supportId), importingInjections, originalInjections, newInjections); } if (!newInjections.isEmpty()) configurationModified(); replaceInjections(newInjections, originalInjections); @@ -412,11 +385,16 @@ public final class Configuration implements PersistentStateComponent, M static void importInjections(final Collection existingInjections, final Collection importingInjections, final Collection originalInjections, final Collection newInjections) { - final MultiValuesMap existingMap = createInjectionMap(existingInjections); + final MultiValuesMap placeMap = new MultiValuesMap(); + for (BaseInjection exising : existingInjections) { + for (InjectionPlace place : exising.getInjectionPlaces()) { + placeMap.put(place, exising); + } + } main: for (BaseInjection other : importingInjections) { final List matchingInjections = ContainerUtil.concat(other.getInjectionPlaces(), new Function>() { public Collection fun(final InjectionPlace o) { - final Collection collection = existingMap.get(o.getText()); + final Collection collection = placeMap.get(o); return collection == null? Collections.emptyList() : collection; } }); @@ -442,16 +420,6 @@ public final class Configuration implements PersistentStateComponent, M } } - private static MultiValuesMap createInjectionMap(final Collection injections) { - final MultiValuesMap existingMap = new MultiValuesMap(); - for (BaseInjection injection : injections) { - for (InjectionPlace place : injection.getInjectionPlaces()) { - existingMap.put(place.getText(), injection); - } - } - return existingMap; - } - public void configurationModified() { myModificationCount ++; } @@ -460,23 +428,6 @@ public final class Configuration implements PersistentStateComponent, M return myModificationCount; } - public boolean isIncludeUncomputablesAsLiterals() { - return myIncludeUncomputablesAsLiterals; - } - - public void setIncludeUncomputablesAsLiterals(boolean flag) { - myIncludeUncomputablesAsLiterals = flag; - } - - @NotNull - public DfaOption getDfaOption() { - return myDfaOption; - } - - public void setDfaOption(@NotNull final DfaOption dfaOption) { - myDfaOption = dfaOption; - } - @Nullable public BaseInjection findExistingInjection(@NotNull final BaseInjection injection) { final List list = getInjections(injection.getSupportId()); @@ -497,7 +448,7 @@ public final class Configuration implements PersistentStateComponent, M for (InjectionPlace place : injection.getInjectionPlaces()) { if (place.isEnabled() != enabled && place.getElementPattern() != null && (place.getElementPattern().accepts(host) || place.getElementPattern().accepts(host.getParent()))) { - newPlaces.add(new InjectionPlace(place.getText(), place.getElementPattern(), enabled)); + newPlaces.add(place.enabled(enabled)); replace = true; } else newPlaces.add(place); @@ -518,8 +469,10 @@ public final class Configuration implements PersistentStateComponent, M return false; } - public InstrumentationType getInstrumentation() { - return myInstrumentationType; + protected void setInjections(Collection injections) { + for (BaseInjection injection : injections) { + myInjections.get(injection.getSupportId()).add(injection); + } } @NotNull @@ -536,12 +489,18 @@ public final class Configuration implements PersistentStateComponent, M final List originalInjections, final List psiElementsToRemove) { replaceInjectionsWithUndo(project, newInjections, originalInjections, psiElementsToRemove, - new PairProcessor, List>() { - public boolean process(final List add, final List remove) { - replaceInjections(add, remove); - return true; - } - }); + new PairProcessor, List>() { + public boolean process(final List add, + final List remove) { + replaceInjectionsWithUndoInner(add, remove); + FileContentUtil.reparseOpenedFiles(); + return true; + } + }); + } + + protected void replaceInjectionsWithUndoInner(final List add, final List remove) { + replaceInjections(add, remove); } public static void replaceInjectionsWithUndo(final Project project, final T add, final T remove, @@ -582,14 +541,144 @@ public final class Configuration implements PersistentStateComponent, M myInjections.get(injection.getSupportId()).remove(injection); } for (BaseInjection injection : newInjections) { - injection.initializePlaces(true); myInjections.get(injection.getSupportId()).add(injection); } configurationModified(); - for (Project project : ProjectManager.getInstance().getOpenProjects()) { - FileContentUtil.reparseFiles(project, Collections.emptyList(), true); - } } + public static class AdvancedConfiguration { + // runtime pattern validation instrumentation + @NotNull private InstrumentationType myInstrumentationType = InstrumentationType.ASSERT; + // annotation class names + @NotNull private String myLanguageAnnotation; + @NotNull private String myPatternAnnotation; + @NotNull private String mySubstAnnotation; + + private boolean myIncludeUncomputablesAsLiterals; + private DfaOption myDfaOption = DfaOption.RESOLVE; + + // cached annotation name pairs + private Pair> myLanguageAnnotationPair; + private Pair> myPatternAnnotationPair; + + private Pair> mySubstAnnotationPair; + + public AdvancedConfiguration() { + setLanguageAnnotation("org.intellij.lang.annotations.Language"); + setPatternAnnotation("org.intellij.lang.annotations.Pattern"); + setSubstAnnotation("org.intellij.lang.annotations.Subst"); + } + + public String getLanguageAnnotationClass() { + return myLanguageAnnotation; + } + + public String getPatternAnnotationClass() { + return myPatternAnnotation; + } + + public String getSubstAnnotationClass() { + return mySubstAnnotation; + } + + public void setInstrumentationType(@Nullable String type) { + if (type != null) { + setInstrumentationType(InstrumentationType.valueOf(type)); + } + } + + public void setInstrumentationType(@NotNull InstrumentationType type) { + myInstrumentationType = type; + } + + public void setLanguageAnnotation(@Nullable String languageAnnotation) { + if (languageAnnotation == null) return; + myLanguageAnnotation = languageAnnotation; + myLanguageAnnotationPair = Pair.create(languageAnnotation, Collections.singleton(languageAnnotation)); + } + + public Pair> getLanguageAnnotationPair() { + return myLanguageAnnotationPair; + } + + public void setPatternAnnotation(@Nullable String patternAnnotation) { + if (patternAnnotation == null) return; + myPatternAnnotation = patternAnnotation; + myPatternAnnotationPair = Pair.create(patternAnnotation, Collections.singleton(patternAnnotation)); + } + + public Pair> getPatternAnnotationPair() { + return myPatternAnnotationPair; + } + + public void setSubstAnnotation(@Nullable String substAnnotation) { + if (substAnnotation == null) return; + mySubstAnnotation = substAnnotation; + mySubstAnnotationPair = Pair.create(substAnnotation, Collections.singleton(substAnnotation)); + } + + public Pair> getSubstAnnotationPair() { + return mySubstAnnotationPair; + } + + public boolean isIncludeUncomputablesAsLiterals() { + return myIncludeUncomputablesAsLiterals; + } + + public void setIncludeUncomputablesAsLiterals(boolean flag) { + myIncludeUncomputablesAsLiterals = flag; + } + + @NotNull + public DfaOption getDfaOption() { + return myDfaOption; + } + + public void setDfaOption(@NotNull final DfaOption dfaOption) { + myDfaOption = dfaOption; + } + + + public InstrumentationType getInstrumentation() { + return myInstrumentationType; + } + + private void writeState(final Element element) { + JDOMExternalizerUtil.writeField(element, INSTRUMENTATION_TYPE_NAME, myInstrumentationType.toString()); + JDOMExternalizerUtil.writeField(element, LANGUAGE_ANNOTATION_NAME, myLanguageAnnotation); + JDOMExternalizerUtil.writeField(element, PATTERN_ANNOTATION_NAME, myPatternAnnotation); + JDOMExternalizerUtil.writeField(element, SUBST_ANNOTATION_NAME, mySubstAnnotation); + switch (myDfaOption) { + case OFF: + break; + case RESOLVE: + JDOMExternalizerUtil.writeField(element, RESOLVE_REFERENCES, Boolean.TRUE.toString()); + break; + case ASSIGNMENTS: + JDOMExternalizerUtil.writeField(element, LOOK_FOR_VAR_ASSIGNMENTS, Boolean.TRUE.toString()); + break; + case DFA: + JDOMExternalizerUtil.writeField(element, USE_DFA_IF_AVAILABLE, Boolean.TRUE.toString()); + break; + } + } + + private void loadState(final Element element) { + setInstrumentationType(JDOMExternalizerUtil.readField(element, INSTRUMENTATION_TYPE_NAME)); + setLanguageAnnotation(JDOMExternalizerUtil.readField(element, LANGUAGE_ANNOTATION_NAME)); + setPatternAnnotation(JDOMExternalizerUtil.readField(element, PATTERN_ANNOTATION_NAME)); + setSubstAnnotation(JDOMExternalizerUtil.readField(element, SUBST_ANNOTATION_NAME)); + if (readBoolean(element, RESOLVE_REFERENCES, true)) { + setDfaOption(DfaOption.RESOLVE); + } + if (readBoolean(element, LOOK_FOR_VAR_ASSIGNMENTS, false)) { + setDfaOption(DfaOption.ASSIGNMENTS); + } + if (readBoolean(element, USE_DFA_IF_AVAILABLE, false)) { + setDfaOption(DfaOption.DFA); + } + setIncludeUncomputablesAsLiterals(readBoolean(element, INCLUDE_UNCOMPUTABLES_AS_LITERALS, false)); + } + } } diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java index e290b15b81e9..ec37f7957c9a 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java @@ -23,6 +23,7 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDialog; import com.intellij.openapi.fileChooser.FileChooserFactory; +import com.intellij.openapi.fileChooser.FileSaverDescriptor; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.options.Configurable; @@ -33,32 +34,35 @@ import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileWrapper; import com.intellij.ui.*; import com.intellij.ui.table.TableView; -import com.intellij.util.Consumer; -import com.intellij.util.Function; -import com.intellij.util.Icons; -import com.intellij.util.Processor; +import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Convertor; import com.intellij.util.ui.ColumnInfo; import com.intellij.util.ui.ListTableModel; import gnu.trove.THashMap; +import gnu.trove.THashSet; +import gnu.trove.TObjectHashingStrategy; import org.intellij.plugins.intelliLang.inject.AbstractLanguageInjectionSupport; import org.intellij.plugins.intelliLang.inject.InjectedLanguage; import org.intellij.plugins.intelliLang.inject.InjectorUtils; import org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport; import org.intellij.plugins.intelliLang.inject.config.BaseInjection; import org.intellij.plugins.intelliLang.inject.config.InjectionPlace; +import org.jdom.Document; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.table.TableCellRenderer; import java.awt.*; +import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.io.IOException; import java.util.*; import java.util.List; @@ -68,10 +72,7 @@ import java.util.List; public class InjectionsSettingsUI implements Configurable { private final Project myProject; - private final Configuration myConfiguration; - private final List myInjections; - private final List myOriginalInjections; - + private final CfgInfo[] myInfos; private final JPanel myRoot; private final InjectionsTable myInjectionsTable; @@ -83,27 +84,13 @@ public class InjectionsSettingsUI implements Configurable { public InjectionsSettingsUI(final Project project, final Configuration configuration) { myProject = project; - myConfiguration = configuration; - myOriginalInjections = ContainerUtil - .concat(InjectorUtils.getActiveInjectionSupportIds(), new Function>() { - public Collection fun(final String s) { - return ContainerUtil.findAll(myConfiguration.getInjections(s), new Condition() { - public boolean value(final BaseInjection injection) { - return InjectedLanguage.findLanguageById(injection.getInjectedLanguageId()) != null; - } - }); - } - }); - sortInjections(myOriginalInjections); - myInjections = new ArrayList(); - for (BaseInjection injection : myOriginalInjections) { - myInjections.add(injection.copy()); - } + myInfos = configuration instanceof Configuration.Prj? new CfgInfo[] {new CfgInfo(((Configuration.Prj)configuration).getParentConfiguration()), new CfgInfo(configuration)} + : new CfgInfo[] {new CfgInfo(configuration)}; myRoot = new JPanel(new BorderLayout()); - myInjectionsTable = new InjectionsTable(myInjections); + myInjectionsTable = new InjectionsTable(getInjInfoList(myInfos)); myInjectionsTable.getEmptyText().setText("No injections configured"); final JPanel tablePanel = new JPanel(new BorderLayout()); @@ -130,7 +117,8 @@ public class InjectionsSettingsUI implements Configurable { }; final Factory producer = new NullableFactory() { public BaseInjection create() { - return getSelectedInjection(); + final InjInfo info = getSelectedInjection(); + return info == null? null : info.injection; } }; for (LanguageInjectionSupport support : InjectorUtils.getActiveInjectionSupports()) { @@ -161,7 +149,14 @@ public class InjectionsSettingsUI implements Configurable { final AnAction removeAction = new AnAction("Remove", "Remove", Icons.DELETE_ICON) { @Override public void update(final AnActionEvent e) { - e.getPresentation().setEnabled(!getSelectedInjections().isEmpty()); + boolean enabled = false; + for (InjInfo info : getSelectedInjections()) { + if (!info.isBundled()) { + enabled = true; + break; + } + } + e.getPresentation().setEnabled(enabled); } @Override @@ -193,9 +188,9 @@ public class InjectionsSettingsUI implements Configurable { @Override public void actionPerformed(final AnActionEvent e) { - final BaseInjection injection = getSelectedInjection(); + final InjInfo injection = getSelectedInjection(); if (injection != null) { - addInjection(injection.copy()); + addInjection(injection.injection.copy()); //performEditAction(e); } } @@ -209,13 +204,6 @@ public class InjectionsSettingsUI implements Configurable { removeAction.registerCustomShortcutSet(CommonShortcuts.DELETE, myInjectionsTable); editAction.registerCustomShortcutSet(CommonShortcuts.ENTER, myInjectionsTable); - group.add(new AnAction("Import", "Import", IconLoader.getIcon("/actions/install.png")) { - @Override - public void actionPerformed(final AnActionEvent e) { - doImportAction(e.getDataContext()); - updateCountLabel(); - } - }); group.addSeparator(); group.add(new AnAction("Enable Selected Injections", "Enable Selected Injections", Icons.SELECT_ALL_ICON) { @Override @@ -236,15 +224,97 @@ public class InjectionsSettingsUI implements Configurable { performToggleAction(); } }.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0)), myInjectionsTable); + + if (myInfos.length > 1) { + group.addSeparator(); + final AnAction shareAction = new AnAction("Make Global", null, IconLoader.getIcon("/actions/import.png")) { + @Override + public void actionPerformed(final AnActionEvent e) { + final List injections = getSelectedInjections(); + final CfgInfo cfg = getTargetCfgInfo(injections); + if (cfg == null) return; + for (InjInfo info : injections) { + if (info.cfgInfo == cfg) continue; + if (info.isBundled()) continue; + info.cfgInfo.injectionInfos.remove(info); + cfg.addInjection(info.injection); + } + final int[] selectedRows = myInjectionsTable.getSelectedRows(); + myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos)); + TableUtil.selectRows(myInjectionsTable, selectedRows); + } + + @Override + public void update(final AnActionEvent e) { + final CfgInfo cfg = getTargetCfgInfo(getSelectedInjections()); + e.getPresentation().setEnabled(cfg != null); + e.getPresentation().setText(cfg == getDefaultCfgInfo() ? "Make Global" : "Move to Project"); + super.update(e); + } + + @Nullable + private CfgInfo getTargetCfgInfo(final List injections) { + CfgInfo cfg = null; + for (InjInfo info : injections) { + if (info.isBundled()) { + continue; + } + if (cfg == null) cfg = info.cfgInfo; + else if (cfg != info.cfgInfo) return info.cfgInfo; + } + if (cfg == null) return cfg; + for (CfgInfo info : myInfos) { + if (info != cfg) return info; + } + throw new AssertionError(); + } + }; + shareAction.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.SHIFT_DOWN_MASK)), myInjectionsTable); + group.add(shareAction); + } + group.addSeparator(); + group.add(new AnAction("Import", "Import", IconLoader.getIcon("/actions/install.png")) { + @Override + public void actionPerformed(final AnActionEvent e) { + doImportAction(e.getDataContext()); + updateCountLabel(); + } + }); + group.add(new AnAction("Export", "Export", IconLoader.getIcon("/actions/export.png")) { + @Override + public void actionPerformed(final AnActionEvent e) { + final List injections = getInjectionList(getSelectedInjections()); + final VirtualFileWrapper wrapper = FileChooserFactory.getInstance().createSaveFileDialog( + new FileSaverDescriptor("Export Selected Injections to File...", "", "xml"), myProject).save(null, null); + if (wrapper == null) return; + final Configuration configuration = new Configuration(); + configuration.setInjections(injections); + final Document document = new Document(configuration.getState()); + try { + JDOMUtil.writeDocument(document, wrapper.getFile(), "\n"); + } + catch (IOException ex) { + final String msg = ex.getLocalizedMessage(); + Messages.showErrorDialog(myProject, msg != null && msg.length() > 0 ? msg : ex.toString(), "Export failed"); + } + } + + @Override + public void update(final AnActionEvent e) { + e.getPresentation().setEnabled(!getSelectedInjections().isEmpty()); + } + }); + return group; } + private void performEditAction(AnActionEvent e) { final AnAction action = getEditAction(); if (action != null) { final int row = myInjectionsTable.getSelectedRow(); action.actionPerformed(e); - ((ListTableModel)myInjectionsTable.getModel()).fireTableDataChanged(); + myInjectionsTable.getListTableModel().fireTableDataChanged(); myInjectionsTable.getSelectionModel().setSelectionInterval(row, row); updateCountLabel(); } @@ -253,15 +323,16 @@ public class InjectionsSettingsUI implements Configurable { private void updateCountLabel() { int placesCount = 0; int enablePlacesCount = 0; - for (BaseInjection injection : myInjections) { - for (InjectionPlace place : injection.getInjectionPlaces()) { - placesCount++; - if (place.isEnabled()) enablePlacesCount++; + final List items = myInjectionsTable.getListTableModel().getItems(); + if (!items.isEmpty()) { + for (InjInfo injection : items) { + for (InjectionPlace place : injection.injection.getInjectionPlaces()) { + placesCount++; + if (place.isEnabled()) enablePlacesCount++; + } } - } - if (!myInjections.isEmpty()) { final StringBuilder sb = new StringBuilder(); - sb.append(myInjections.size()).append(" injection").append(myInjections.size() > 1 ? "s" : "").append(" (").append(enablePlacesCount) + sb.append(items.size()).append(" injection").append(items.size() > 1 ? "s" : "").append(" (").append(enablePlacesCount) .append(" of ").append(placesCount).append(" place").append(placesCount > 1 ? "s" : "").append(" enabled) "); myCountLabel.setText(sb.toString()); } @@ -272,20 +343,23 @@ public class InjectionsSettingsUI implements Configurable { @Nullable private AnAction getEditAction() { - final BaseInjection injection = getSelectedInjection(); - final String supportId = injection == null? null : injection.getSupportId(); + final InjInfo info = getSelectedInjection(); + final String supportId = info == null? null : info.injection.getSupportId(); return supportId == null? null : myEditActions.get(supportId); } private void addInjection(final BaseInjection injection) { - injection.initializePlaces(true); - myInjections.add(injection); - myInjectionsTable.getListTableModel().setItems(myInjections); - final int index = myInjections.indexOf(injection); + final InjInfo info = getDefaultCfgInfo().addInjection(injection); + myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos)); + final int index = myInjectionsTable.convertRowIndexToView(myInjectionsTable.getListTableModel().getItems().indexOf(info)); myInjectionsTable.getSelectionModel().setSelectionInterval(index, index); TableUtil.scrollSelectionToVisible(myInjectionsTable); } + private CfgInfo getDefaultCfgInfo() { + return myInfos[0]; + } + private static void sortInjections(final List injections) { Collections.sort(injections, new Comparator() { public int compare(final BaseInjection o1, final BaseInjection o2) { @@ -302,12 +376,11 @@ public class InjectionsSettingsUI implements Configurable { return myRoot; } - public void reset() { - myInjections.clear(); - for (BaseInjection injection : myOriginalInjections) { - myInjections.add(injection.copy()); + public void reset() { + for (CfgInfo info : myInfos) { + info.reset(); } - myInjectionsTable.getListTableModel().setItems(myInjections); + myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos)); updateCountLabel(); } @@ -315,33 +388,33 @@ public class InjectionsSettingsUI implements Configurable { } public void apply() { - myConfiguration.replaceInjections(myInjections, myOriginalInjections); - myOriginalInjections.clear(); - myOriginalInjections.addAll(myInjections); - sortInjections(myOriginalInjections); + for (CfgInfo info : myInfos) { + info.apply(); + } reset(); } public boolean isModified() { - final List copy = new ArrayList(myInjections); - sortInjections(copy); - return !myOriginalInjections.equals(copy); + for (CfgInfo info : myInfos) { + if (info.isModified()) return true; + } + return false; } private void performSelectedInjectionsEnabled(final boolean enabled) { - for (BaseInjection injection : getSelectedInjections()) { - injection.setPlaceEnabled(null, enabled); + for (InjInfo info : getSelectedInjections()) { + info.injection.setPlaceEnabled(null, enabled); } myInjectionsTable.updateUI(); updateCountLabel(); } private void performToggleAction() { - final List selectedInjections = getSelectedInjections(); + final List selectedInjections = getSelectedInjections(); boolean enabledExists = false; boolean disabledExists = false; - for (BaseInjection injection : selectedInjections) { - if (injection.isEnabled()) enabledExists = true; + for (InjInfo info : selectedInjections) { + if (info.injection.isEnabled()) enabledExists = true; else disabledExists = true; if (enabledExists && disabledExists) break; } @@ -352,25 +425,20 @@ public class InjectionsSettingsUI implements Configurable { private void performRemove() { final int selectedRow = myInjectionsTable.getSelectedRow(); if (selectedRow < 0) return; - final List selected = getSelectedInjections(); - main: for (Iterator it = myInjections.iterator(); it.hasNext(); ) { - final BaseInjection injection = it.next(); - for (BaseInjection selectedInjection : selected) { - if (injection == selectedInjection) { - it.remove(); - continue main; - } - } + final List selected = getSelectedInjections(); + for (InjInfo info : selected) { + if (info.isBundled()) continue; + info.cfgInfo.injectionInfos.remove(info); } - ((ListTableModel)myInjectionsTable.getModel()).fireTableDataChanged(); - final int index = Math.min(myInjections.size() - 1, selectedRow); + myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos)); + final int index = Math.min(myInjectionsTable.getListTableModel().getRowCount() - 1, selectedRow); myInjectionsTable.getSelectionModel().setSelectionInterval(index, index); TableUtil.scrollSelectionToVisible(myInjectionsTable); updateCountLabel(); } - private List getSelectedInjections() { - final ArrayList toRemove = new ArrayList(); + private List getSelectedInjections() { + final ArrayList toRemove = new ArrayList(); for (int row : myInjectionsTable.getSelectedRows()) { toRemove.add(myInjectionsTable.getItems().get(myInjectionsTable.convertRowIndexToModel(row))); } @@ -378,7 +446,7 @@ public class InjectionsSettingsUI implements Configurable { } @Nullable - private BaseInjection getSelectedInjection() { + private InjInfo getSelectedInjection() { final int row = myInjectionsTable.getSelectedRow(); return row < 0? null : myInjectionsTable.getItems().get(myInjectionsTable.convertRowIndexToModel(row)); } @@ -409,9 +477,9 @@ public class InjectionsSettingsUI implements Configurable { return "reference.settings.injection.language.injection.settings"; } - private class InjectionsTable extends TableView { - private InjectionsTable(final List injections) { - super(new ListTableModel(createInjectionColumnInfos(), injections, 1)); + private class InjectionsTable extends TableView { + private InjectionsTable(final List injections) { + super(new ListTableModel(createInjectionColumnInfos(), injections, 1)); setAutoResizeMode(AUTO_RESIZE_LAST_COLUMN); getColumnModel().getColumn(2).setCellRenderer(createLanguageCellRenderer()); getColumnModel().getColumn(1).setCellRenderer(createDisplayNameCellRenderer()); @@ -421,9 +489,9 @@ public class InjectionsSettingsUI implements Configurable { setGridColor(getForeground()); getColumnModel().getColumn(0).setMaxWidth(new JCheckBox().getPreferredSize().width); final int[] preffered = new int[] {0} ; - ContainerUtil.process(myInjections, new Processor() { - public boolean process(final BaseInjection injection) { - final String languageId = injection.getInjectedLanguageId(); + ContainerUtil.process(injections, new Processor() { + public boolean process(final InjInfo injection) { + final String languageId = injection.injection.getInjectedLanguageId(); if (preffered[0] < languageId.length()) preffered[0] = languageId.length(); return true; } @@ -456,7 +524,7 @@ public class InjectionsSettingsUI implements Configurable { @Override protected String getElementText(final Object element) { - final BaseInjection injection = (BaseInjection)element; + final BaseInjection injection = ((InjInfo)element).injection; return injection.getSupportId() + " " + injection.getInjectedLanguageId() + " " + injection.getDisplayName(); } }; @@ -468,71 +536,71 @@ public class InjectionsSettingsUI implements Configurable { final TableCellRenderer booleanCellRenderer = createBooleanCellRenderer(); final TableCellRenderer displayNameCellRenderer = createDisplayNameCellRenderer(); final TableCellRenderer languageCellRenderer = createLanguageCellRenderer(); - final Comparator languageComparator = new Comparator() { - public int compare(final BaseInjection o1, final BaseInjection o2) { - return Comparing.compare(o1.getInjectedLanguageId(), o2.getInjectedLanguageId()); + final Comparator languageComparator = new Comparator() { + public int compare(final InjInfo o1, final InjInfo o2) { + return Comparing.compare(o1.injection.getInjectedLanguageId(), o2.injection.getInjectedLanguageId()); } }; - final Comparator displayNameComparator = new Comparator() { - public int compare(final BaseInjection o1, final BaseInjection o2) { - final int support = Comparing.compare(o1.getSupportId(), o2.getSupportId()); + final Comparator displayNameComparator = new Comparator() { + public int compare(final InjInfo o1, final InjInfo o2) { + final int support = Comparing.compare(o1.injection.getSupportId(), o2.injection.getSupportId()); if (support != 0) return support; - return Comparing.compare(o1.getDisplayName(), o2.getDisplayName()); + return Comparing.compare(o1.injection.getDisplayName(), o2.injection.getDisplayName()); } }; - return new ColumnInfo[]{new ColumnInfo(" ") { + return new ColumnInfo[]{new ColumnInfo(" ") { @Override public Class getColumnClass() { return Boolean.class; } @Override - public Boolean valueOf(final BaseInjection o) { - return o.isEnabled(); + public Boolean valueOf(final InjInfo o) { + return o.injection.isEnabled(); } @Override - public boolean isCellEditable(final BaseInjection injection) { + public boolean isCellEditable(final InjInfo injection) { return true; } @Override - public void setValue(final BaseInjection injection, final Boolean value) { - injection.setPlaceEnabled(null, value.booleanValue()); + public void setValue(final InjInfo injection, final Boolean value) { + injection.injection.setPlaceEnabled(null, value.booleanValue()); } @Override - public TableCellRenderer getRenderer(final BaseInjection injection) { + public TableCellRenderer getRenderer(final InjInfo injection) { return booleanCellRenderer; } - }, new ColumnInfo("Display Name") { + }, new ColumnInfo("Display Name") { @Override - public BaseInjection valueOf(final BaseInjection injection) { - return injection; + public InjInfo valueOf(final InjInfo info) { + return info; } @Override - public Comparator getComparator() { + public Comparator getComparator() { return displayNameComparator; } @Override - public TableCellRenderer getRenderer(final BaseInjection injection) { + public TableCellRenderer getRenderer(final InjInfo injection) { return displayNameCellRenderer; } - }, new ColumnInfo("Language") { + }, new ColumnInfo("Language") { @Override - public BaseInjection valueOf(final BaseInjection injection) { - return injection; + public InjInfo valueOf(final InjInfo info) { + return info; } @Override - public Comparator getComparator() { + public Comparator getComparator() { return languageComparator; } @Override - public TableCellRenderer getRenderer(final BaseInjection injection) { + public TableCellRenderer getRenderer(final InjInfo info) { return languageCellRenderer; } }}; @@ -559,13 +627,14 @@ public class InjectionsSettingsUI implements Configurable { public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) { - final BaseInjection injection = (BaseInjection)value; + final InjInfo injection = (InjInfo)value; // fix for a marvellous Swing peculiarity: AccessibleJTable likes to pass null here if (injection == null) return myLabel; - final Language language = InjectedLanguage.findLanguageById(injection.getInjectedLanguageId()); + final String languageId = injection.injection.getInjectedLanguageId(); + final Language language = InjectedLanguage.findLanguageById(languageId); final FileType fileType = language == null ? null : language.getAssociatedFileType(); myLabel.setIcon(fileType == null ? null : fileType.getIcon()); - myLabel.setText(language == null ? injection.getInjectedLanguageId() : language.getDisplayName()); + myLabel.setText(language == null ? languageId : language.getDisplayName()); setLabelColors(myLabel, table, isSelected, row); return myLabel; } @@ -581,12 +650,20 @@ public class InjectionsSettingsUI implements Configurable { final int row, final int column) { myLabel.clear(); - final BaseInjection injection = (BaseInjection)value; + final InjInfo info = (InjInfo)value; // fix for a marvellous Swing peculiarity: AccessibleJTable likes to pass null here - if (injection == null) return myLabel; + if (info == null) return myLabel; + final boolean projectLevel = myInfos.length > 1 && info.cfgInfo != myInfos[0]; final SimpleTextAttributes grayAttrs = isSelected ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES; - myText.append(injection.getSupportId() + ": ", grayAttrs); - mySupports.get(injection.getSupportId()).setupPresentation(injection, myText, isSelected); + final String supportId = info.injection.getSupportId(); + myText.append(supportId + ": ", grayAttrs); + mySupports.get(supportId).setupPresentation(info.injection, myText, isSelected); + if (projectLevel) { + for (ListIterator it = myText.getAttributes().listIterator(); it.hasNext(); ) { + final SimpleTextAttributes attributes = it.next(); + it.set(attributes.derive(SimpleTextAttributes.STYLE_BOLD, null, null, null)); + } + } myText.appendToComponent(myLabel); myText.clear(); setLabelColors(myLabel, table, isSelected, row); @@ -635,10 +712,11 @@ public class InjectionsSettingsUI implements Configurable { Messages.showWarningDialog(myProject, "The selected file does not contain any importable configuration.", "Nothing to Import"); return; } - final Map> currentMap = - ContainerUtil.classify(myInjections.iterator(), new Convertor() { - public String convert(final BaseInjection o) { - return o.getSupportId(); + final CfgInfo info = getDefaultCfgInfo(); + final Map> currentMap = + ContainerUtil.classify(info.injectionInfos.iterator(), new Convertor() { + public String convert(final InjInfo o) { + return o.injection.getSupportId(); } }); final List originalInjections = new ArrayList(); @@ -655,7 +733,7 @@ public class InjectionsSettingsUI implements Configurable { //myInjections.addAll(newInjections); for (String supportId : InjectorUtils.getActiveInjectionSupportIds()) { - final Set currentInjections = currentMap.get(supportId); + final List currentInjections = getInjectionList(new ArrayList(currentMap.get(supportId))); final List importingInjections = cfg.getInjections(supportId); if (currentInjections == null) { newInjections.addAll(importingInjections); @@ -664,12 +742,8 @@ public class InjectionsSettingsUI implements Configurable { Configuration.importInjections(currentInjections, importingInjections, originalInjections, newInjections); } } - myInjections.removeAll(originalInjections); - myInjections.addAll(newInjections); - for (BaseInjection injection : newInjections) { - injection.initializePlaces(true); - } - myInjectionsTable.getListTableModel().setItems(myInjections); + info.replace(originalInjections, newInjections); + myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos)); final int n = newInjections.size(); if (n > 1) { Messages.showInfoMessage(myProject, n + " entries have been successfully imported", "Import Successful"); @@ -681,11 +755,128 @@ public class InjectionsSettingsUI implements Configurable { Messages.showInfoMessage(myProject, "No new entries have been imported", "Import"); } } - catch (Exception e1) { - Configuration.LOG.error("Unable to load Settings", e1); + catch (Exception ex) { + Configuration.LOG.error(ex); - final String msg = e1.getLocalizedMessage(); - Messages.showErrorDialog(myProject, msg != null && msg.length() > 0 ? msg : e1.toString(), "Could not load Settings"); + final String msg = ex.getLocalizedMessage(); + Messages.showErrorDialog(myProject, msg != null && msg.length() > 0 ? msg : ex.toString(), "Import failed"); } } + + private static class CfgInfo { + final Configuration cfg; + final List originalInjections; + final List injectionInfos = new ArrayList(); + final THashSet bundledInjections = new THashSet(new SameParamsAndPlacesStrategy()); + + public CfgInfo(Configuration cfg) { + this.cfg = cfg; + bundledInjections.addAll(cfg.getDefaultInjections()); + originalInjections = ContainerUtil + .concat(InjectorUtils.getActiveInjectionSupportIds(), new Function>() { + public Collection fun(final String s) { + return ContainerUtil.findAll( + CfgInfo.this.cfg instanceof Configuration.Prj ? ((Configuration.Prj)CfgInfo.this.cfg).getOwnInjections(s) : CfgInfo.this.cfg + .getInjections(s), + new Condition() { + public boolean value(final BaseInjection injection) { + return InjectedLanguage.findLanguageById(injection.getInjectedLanguageId()) != null; + } + }); + } + }); + sortInjections(originalInjections); + reset(); + } + + public void apply() { + final List injectionList = getInjectionList(injectionInfos); + cfg.replaceInjections(injectionList, originalInjections); + originalInjections.clear(); + originalInjections.addAll(injectionList); + sortInjections(originalInjections); + FileContentUtil.reparseOpenedFiles(); + } + + public void reset() { + injectionInfos.clear(); + for (BaseInjection injection : originalInjections) { + injectionInfos.add(new InjInfo(injection.copy(), this)); + } + } + + public InjInfo addInjection(final BaseInjection injection) { + final InjInfo info = new InjInfo(injection, this); + injectionInfos.add(info); + return info; + } + + public boolean isModified() { + final List copy = new ArrayList(getInjectionList(injectionInfos)); + sortInjections(copy); + return !originalInjections.equals(copy); + } + + public void replace(final List originalInjections, final List newInjections) { + for (Iterator it = injectionInfos.iterator(); it.hasNext(); ) { + final InjInfo info = it.next(); + if (originalInjections.contains(info.injection)) it.remove(); + } + for (BaseInjection newInjection : newInjections) { + injectionInfos.add(new InjInfo(newInjection, this)); + } + } + + } + + private static class SameParamsAndPlacesStrategy implements TObjectHashingStrategy { + @Override + public int computeHashCode(final BaseInjection object) { + return object.hashCode(); + } + + @Override + public boolean equals(final BaseInjection o1, final BaseInjection o2) { + if (!o1.sameLanguageParameters(o2)) return false; + if (!o1.getInjectionPlaces().equals(o2.getInjectionPlaces())) return false; + return true; + } + } + + private static class InjInfo { + final BaseInjection injection; + final CfgInfo cfgInfo; + + private InjInfo(final BaseInjection injection, final CfgInfo cfgInfo) { + this.injection = injection; + this.cfgInfo = cfgInfo; + } + + boolean isBundled() { + return cfgInfo.bundledInjections.contains(injection); + } + } + + private static List getInjInfoList(final CfgInfo[] infos) { + return ContainerUtil.concat(infos, new Function>() { + @Override + public Collection fun(final CfgInfo cfgInfo) { + return cfgInfo.injectionInfos; + } + }); + } + + private static List getInjectionList(final List list) { + return new AbstractList() { + @Override + public BaseInjection get(final int index) { + return list.get(index).injection; + } + + @Override + public int size() { + return list.size(); + } + }; + } } diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Settings.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Settings.java index b72b6ae63448..6d81d3c82691 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Settings.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Settings.java @@ -43,10 +43,10 @@ import java.awt.*; */ public class Settings implements SearchableConfigurable { - private final Configuration myConfiguration; + private final Project myProject; - Settings(Configuration configuration) { - myConfiguration = configuration; + Settings(final Project project) { + myProject = project; } private SettingsUI mySettingsUI; @@ -69,32 +69,7 @@ public class Settings implements SearchableConfigurable { } public JComponent createComponent() { - final ProjectManager projectManager = ProjectManager.getInstance(); - final Project[] projects = projectManager.getOpenProjects(); - - Project project = null; - if (projects.length == 0) { - project = projectManager.getDefaultProject(); - } - else { - final WindowManagerEx windowManager = WindowManagerEx.getInstanceEx(); - final Window focusedWindow = windowManager.getMostRecentFocusedWindow(); - if (focusedWindow != null) { - for (Project p : projects) { - final Window w = windowManager.suggestParentWindow(p); - if (w == focusedWindow || w.isAncestorOf(focusedWindow) || focusedWindow.isAncestorOf(w)) { - project = p; - break; - } - } - } - if (project == null) { - project = projectManager.getDefaultProject(); - } - } - - mySettingsUI = new SettingsUI(project, myConfiguration); - + mySettingsUI = new SettingsUI(myProject, Configuration.getProjectInstance(myProject)); return mySettingsUI.createComponent(); } diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/AbstractLanguageInjectionSupport.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/AbstractLanguageInjectionSupport.java index a511b60a3cf7..ab51e99bca8d 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/AbstractLanguageInjectionSupport.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/AbstractLanguageInjectionSupport.java @@ -87,7 +87,6 @@ public abstract class AbstractLanguageInjectionSupport extends LanguageInjection final BaseInjection newInjection = showDefaultInjectionUI(project, originalInjection.copy()); if (newInjection != null) { originalInjection.copyFrom(newInjection); - originalInjection.initializePlaces(true); } } }; @@ -134,7 +133,6 @@ public abstract class AbstractLanguageInjectionSupport extends LanguageInjection } }); if (builder.show() == DialogWrapper.OK_EXIT_CODE) { - injection.initializePlaces(false); return injection; } return null; diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/EditInjectionSettingsAction.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/EditInjectionSettingsAction.java index 931620e9c4ba..cc97dfd8c000 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/EditInjectionSettingsAction.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/EditInjectionSettingsAction.java @@ -76,7 +76,7 @@ public class EditInjectionSettingsAction implements IntentionAction, LowPriority if (support == null) return; try { if (!support.editInjectionInPlace(host)) { - ShowSettingsUtil.getInstance().editConfigurable(project, new InjectionsSettingsUI(project, Configuration.getInstance())); + ShowSettingsUtil.getInstance().editConfigurable(project, new InjectionsSettingsUI(project, Configuration.getProjectInstance(project))); } } finally { diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectLanguageAction.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectLanguageAction.java index 448f70b5d99d..dc43d6a35c2d 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectLanguageAction.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectLanguageAction.java @@ -115,7 +115,7 @@ public class InjectLanguageAction implements IntentionAction { } private static boolean defaultFunctionalityWorked(final PsiLanguageInjectionHost host, final String languageId) { - return Configuration.getInstance().setHostInjectionEnabled(host, Collections.singleton(languageId), true); + return Configuration.getProjectInstance(host.getProject()).setHostInjectionEnabled(host, Collections.singleton(languageId), true); } private static boolean doChooseLanguageToInject(Editor editor, final Processor onChosen) { diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/UnInjectLanguageAction.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/UnInjectLanguageAction.java index a826ff343b4f..83a6b160497a 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/UnInjectLanguageAction.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/UnInjectLanguageAction.java @@ -97,7 +97,7 @@ public class UnInjectLanguageAction implements IntentionAction, LowPriorityActio } // todo there is a problem: host i.e. literal expression is confused with "target" i.e. parameter // todo therefore this part doesn't work for java - return Configuration.getInstance().setHostInjectionEnabled(host, languages, false); + return Configuration.getProjectInstance(host.getProject()).setHostInjectionEnabled(host, languages, false); } public boolean startInWriteAction() { diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/BaseInjection.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/BaseInjection.java index 75236bfa391f..8ccf142fd548 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/BaseInjection.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/BaseInjection.java @@ -161,7 +161,7 @@ public class BaseInjection implements Injection, PersistentStateComponent helper = getCompiler(); final Element e = element.getChild(getClass().getSimpleName()); if (e != null) { myInjectedLanguageId = JDOMExternalizer.readString(e, "LANGUAGE"); @@ -235,7 +235,6 @@ public class BaseInjection implements Injection, PersistentStateComponent)element.getChildren("place")) { final boolean enabled = !Boolean.parseBoolean(placeElement.getAttributeValue("disabled")); final String text = placeElement.getText(); - myPlaces.add(new InjectionPlace(text, null, enabled)); + myPlaces.add(new InjectionPlace(helper.createElementPattern(text, getDisplayName()), enabled)); } - myPlaces.trimToSize(); } - } - - public void initializePlaces(final boolean compile) { - final PatternCompiler helper = - PatternCompilerFactory.getFactory().getPatternCompiler(InjectorUtils.findInjectionSupport(getSupportId()).getPatternClasses()); if (myPlaces.isEmpty()) { - for (String text : generatePlaces()) { - myPlaces.add(new InjectionPlace(text, compile? helper.createElementPattern(text, getDisplayName()) : null, true)); - } - } - else if (compile) { - boolean replace = false; - final ArrayList newPlaces = new ArrayList(); - for (InjectionPlace place : myPlaces) { - if (StringUtil.isNotEmpty(place.getText()) && place.getElementPattern() == null) { - replace = true; - newPlaces.add(new InjectionPlace(place.getText(), helper.createElementPattern(place.getText(), getDisplayName()), place.isEnabled())); - } - else { - newPlaces.add(place); - } - } - if (replace) { - myPlaces.clear(); - myPlaces.addAll(newPlaces); - } + generatePlaces(); } + myPlaces.trimToSize(); } - protected List generatePlaces() { - return Collections.emptyList(); + + public PatternCompiler getCompiler() { + return PatternCompilerFactory.getFactory().getPatternCompiler(InjectorUtils.findInjectionSupport(getSupportId()).getPatternClasses()); + } + + public void generatePlaces() { } protected void readExternalImpl(Element e) {} @@ -387,13 +366,8 @@ public class BaseInjection implements Injection, PersistentStateComponent myElementPattern; private final boolean myEnabled; - public InjectionPlace(final String myText, final ElementPattern myElementPattern, final boolean enabled) { - this.myText = myText; + public InjectionPlace(final ElementPattern myElementPattern, final boolean enabled) { this.myElementPattern = myElementPattern; myEnabled = enabled; } + public InjectionPlace enabled(final boolean enabled) { + return new InjectionPlace(myElementPattern, enabled); + } + public String getText() { - return myText; + return myElementPattern.toString(); } public ElementPattern getElementPattern() { @@ -52,16 +55,13 @@ public class InjectionPlace { final InjectionPlace place = (InjectionPlace)o; - if (myEnabled != place.myEnabled) return false; - if (myText != null ? !myText.equals(place.myText) : place.myText != null) return false; + if (!myElementPattern.equals(place.myElementPattern)) return false; return true; } @Override public int hashCode() { - int result = myText != null ? myText.hashCode() : 0; - result = 31 * result + (myEnabled ? 1 : 0); - return result; + return myElementPattern.hashCode(); } } diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/AbstractInjectionPanel.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/AbstractInjectionPanel.java index 4b100f823993..2626d4f433ed 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/AbstractInjectionPanel.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/AbstractInjectionPanel.java @@ -94,7 +94,7 @@ public abstract class AbstractInjectionPanel implements for (Field panel : myOtherPanels) { getField(panel).apply(); } - + myOrigInjection.generatePlaces(); myEditCopy.copyFrom(myOrigInjection); } diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/BaseInjectionPanel.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/BaseInjectionPanel.java index 6ec111eb42d2..e79f88bf8946 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/BaseInjectionPanel.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/config/ui/BaseInjectionPanel.java @@ -93,12 +93,13 @@ public class BaseInjectionPanel extends AbstractInjectionPanel { final StringBuilder sb = new StringBuilder(); final ArrayList places = new ArrayList(); for (String s : myTextArea.getText().split("\\s*\n\\s*")) { + final boolean nextEnabled; if (s.startsWith("+")) { - enabled = true; + nextEnabled = true; s = s.substring(1).trim(); } else if (s.startsWith("-")) { - enabled = false; + nextEnabled = false; s = s.substring(1).trim(); } else { @@ -107,14 +108,15 @@ public class BaseInjectionPanel extends AbstractInjectionPanel { } if (sb.length() > 0) { final String text = sb.toString(); - places.add(new InjectionPlace(text, myHelper.compileElementPattern(text), enabled)); + places.add(new InjectionPlace(myHelper.compileElementPattern(text), enabled)); sb.setLength(0); } sb.append(s); + enabled = nextEnabled; } if (sb.length() > 0) { final String text = sb.toString(); - places.add(new InjectionPlace(text, myHelper.compileElementPattern(text), enabled)); + places.add(new InjectionPlace(myHelper.compileElementPattern(text), enabled)); } other.getInjectionPlaces().clear(); other.getInjectionPlaces().addAll(places); diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlAttributeInjection.java b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlAttributeInjection.java index 87b73448c419..3f402ce68ee5 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlAttributeInjection.java +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlAttributeInjection.java @@ -17,6 +17,7 @@ package org.intellij.plugins.intelliLang.inject.config; import com.intellij.openapi.util.JDOMExternalizer; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.patterns.compiler.PatternCompiler; import com.intellij.psi.PsiElement; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlAttributeValue; @@ -76,8 +77,9 @@ public class XmlAttributeInjection extends AbstractTagInjection { } @Override - protected List generatePlaces() { - return Collections.singletonList(getPatternString(this)); + public void generatePlaces() { + getInjectionPlaces().clear(); + getInjectionPlaces().add(new InjectionPlace(getCompiler().createElementPattern(getPatternString(this), getDisplayName()), true)); } private boolean matches(@NotNull XmlAttribute attr) { diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlTagInjection.java b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlTagInjection.java index 8e6fc8c5691d..e77a9d40b145 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlTagInjection.java +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/config/XmlTagInjection.java @@ -51,8 +51,9 @@ public class XmlTagInjection extends AbstractTagInjection { } @Override - protected List generatePlaces() { - return Collections.singletonList(getPatternString(this)); + public void generatePlaces() { + getInjectionPlaces().clear(); + getInjectionPlaces().add(new InjectionPlace(getCompiler().createElementPattern(getPatternString(this), getDisplayName()), true)); } public static String getPatternString(final AbstractTagInjection injection) { diff --git a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/xml/XmlLanguageInjectionSupport.java b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/xml/XmlLanguageInjectionSupport.java index 5f4cae94e1a5..e24f47941dca 100644 --- a/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/xml/XmlLanguageInjectionSupport.java +++ b/plugins/IntelliLang/xml-support/org/intellij/plugins/intelliLang/inject/xml/XmlLanguageInjectionSupport.java @@ -101,7 +101,8 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor public boolean removeInjectionInPlace(final PsiLanguageInjectionHost host) { if (!isMine(host)) return false; - final Configuration configuration = Configuration.getInstance(); + final Project project = host.getProject(); + final Configuration configuration = Configuration.getProjectInstance(project); final ArrayList injections = collectInjections(host, configuration); if (injections.isEmpty()) return false; final ArrayList newInjections = new ArrayList(); @@ -109,23 +110,23 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor final BaseInjection newInjection = injection.copy(); newInjection.setPlaceEnabled(null, false); } - Configuration.getInstance().replaceInjectionsWithUndo( - host.getProject(), newInjections, injections, Collections.emptyList()); + configuration.replaceInjectionsWithUndo( + project, newInjections, injections, Collections.emptyList()); return true; } public boolean editInjectionInPlace(final PsiLanguageInjectionHost host) { if (!isMine(host)) return false; - final Configuration configuration = Configuration.getInstance(); + final Project project = host.getProject(); + final Configuration configuration = Configuration.getProjectInstance(project); final ArrayList injections = collectInjections(host, configuration); if (injections.isEmpty()) return false; - final Project project = host.getProject(); final BaseInjection originalInjection = injections.get(0); final BaseInjection xmlInjection = createFrom(originalInjection, host); final BaseInjection newInjection = xmlInjection == null? showDefaultInjectionUI(project, originalInjection.copy()) : showInjectionUI(project, xmlInjection); if (newInjection != null) { - Configuration.getInstance().replaceInjectionsWithUndo( + configuration.replaceInjectionsWithUndo( project, Collections.singletonList(newInjection), Collections.singletonList(originalInjection), Collections.emptyList()); @@ -158,7 +159,6 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor } }); if (builder.show() == DialogWrapper.OK_EXIT_CODE) { - xmlInjection.initializePlaces(false); return new AbstractTagInjection().copyFrom(xmlInjection); } return null; @@ -166,7 +166,7 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor @Nullable private static BaseInjection createFrom(final BaseInjection injection, final PsiLanguageInjectionHost host) { - if (injection.getInjectionPlaces().size() > 1) return null; + if (injection.getInjectionPlaces().isEmpty() || injection.getInjectionPlaces().size() > 1) return null; AbstractTagInjection result; final InjectionPlace place = injection.getInjectionPlaces().get(0); @@ -218,6 +218,7 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor } else return null; } + result.generatePlaces(); return result; } @@ -265,6 +266,7 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor injection.setInjectedLanguageId(languageId); injection.setTagName(tag.getLocalName()); injection.setTagNamespace(tag.getNamespace()); + injection.generatePlaces(); doEditInjection(host.getProject(), injection); return true; } @@ -272,11 +274,12 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor } private static void doEditInjection(final Project project, final XmlTagInjection template) { - final AbstractTagInjection originalInjection = (AbstractTagInjection)Configuration.getInstance().findExistingInjection(template); + final Configuration configuration = Configuration.getProjectInstance(project); + final AbstractTagInjection originalInjection = (AbstractTagInjection)configuration.findExistingInjection(template); final XmlTagInjection newInjection = originalInjection == null? template : new XmlTagInjection().copyFrom(originalInjection); if (InjectLanguageAction.doEditConfigurable(project, new XmlTagInjectionConfigurable(newInjection, null, project))) { - Configuration.getInstance().replaceInjectionsWithUndo( + configuration.replaceInjectionsWithUndo( project, Collections.singletonList(newInjection), ContainerUtil.createMaybeSingletonList(originalInjection), Collections.emptyList()); @@ -293,6 +296,7 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor injection.setAttributeNamespace(attribute.getNamespace()); injection.setTagName(tag.getLocalName()); injection.setTagNamespace(tag.getNamespace()); + injection.generatePlaces(); doEditInjection(host.getProject(), injection); return true; } @@ -300,12 +304,11 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor } private static void doEditInjection(final Project project, final XmlAttributeInjection template) { - final Configuration configuration = Configuration.getInstance(); - template.initializePlaces(false); + final Configuration configuration = Configuration.getProjectInstance(project); final BaseInjection originalInjection = configuration.findExistingInjection(template); final BaseInjection newInjection = originalInjection == null ? template : originalInjection.copy(); if (InjectLanguageAction.doEditConfigurable(project, new XmlAttributeInjectionConfigurable((XmlAttributeInjection)newInjection, null, project))) { - Configuration.getInstance().replaceInjectionsWithUndo( + configuration.replaceInjectionsWithUndo( project, Collections.singletonList(newInjection), ContainerUtil.createMaybeSingletonList(originalInjection), Collections.emptyList()); @@ -356,7 +359,6 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor final BaseInjection newInjection = showInjectionUI(project, injection); if (newInjection != null) { originalInjection.copyFrom(newInjection); - originalInjection.initializePlaces(true); } } else { From 93ccb6479d987602afd7795c79d018887509ce41 Mon Sep 17 00:00:00 2001 From: andrey zaytsev Date: Tue, 17 May 2011 02:33:05 +0400 Subject: [PATCH 12/31] IDEA-69490 Ctrl+F (Find) opens with old search value: very dirty urgent hack to fix it. --- platform/lang-impl/src/com/intellij/find/FindUtil.java | 9 ++++++--- .../intellij/find/editorHeaderActions/SwitchToFind.java | 2 +- .../find/editorHeaderActions/SwitchToReplace.java | 2 +- .../openapi/editor/actions/IncrementalFindAction.java | 4 ++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/find/FindUtil.java b/platform/lang-impl/src/com/intellij/find/FindUtil.java index b3f246d80b70..c0984fa3d47c 100644 --- a/platform/lang-impl/src/com/intellij/find/FindUtil.java +++ b/platform/lang-impl/src/com/intellij/find/FindUtil.java @@ -95,7 +95,7 @@ public class FindUtil { } } - public static void configureFindModel(boolean replace, @Nullable String selectedText, FindModel model) { + public static void configureFindModel(boolean replace, @Nullable String selectedText, FindModel model, boolean firstSearch) { boolean isGlobal = true; String stringToFind = null; if (!StringUtil.isEmpty(selectedText)) { @@ -109,9 +109,12 @@ public class FindUtil { stringToFind = selectedText; } } else { - stringToFind = model.getStringToFind(); + if (firstSearch) { + stringToFind = ""; + } else { + stringToFind = model.getStringToFind(); + } } - model.setReplaceState(replace); model.setStringToFind(stringToFind); model.setGlobal(isGlobal); diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java index f4b093548e30..bcc7b5088bd9 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java @@ -37,6 +37,6 @@ public class SwitchToFind extends EditorHeaderAction { } final FindModel findModel = getEditorSearchComponent().getFindModel(); - FindUtil.configureFindModel(false, null, findModel); + FindUtil.configureFindModel(false, null, findModel, false); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java index ce413663bfbd..b6a1da84237c 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java @@ -26,6 +26,6 @@ public class SwitchToReplace extends EditorHeaderAction { @Override public void actionPerformed(AnActionEvent e) { final FindModel findModel = getEditorSearchComponent().getFindModel(); - FindUtil.configureFindModel(true, null, findModel); + FindUtil.configureFindModel(true, null, findModel, false); } } diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java index 9ca379769825..29bf9088e651 100644 --- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java @@ -47,7 +47,7 @@ public class IncrementalFindAction extends EditorAction { if (headerComponent instanceof EditorSearchComponent) { EditorSearchComponent editorSearchComponent = (EditorSearchComponent)headerComponent; headerComponent.requestFocus(); - FindUtil.configureFindModel(myReplace, editor.getSelectionModel().getSelectedText(), editorSearchComponent.getFindModel()); + FindUtil.configureFindModel(myReplace, editor.getSelectionModel().getSelectedText(), editorSearchComponent.getFindModel(), false); } else { FindManager findManager = FindManager.getInstance(project); FindModel model; @@ -57,7 +57,7 @@ public class IncrementalFindAction extends EditorAction { model = new FindModel(); model.copyFrom(findManager.getFindInFileModel()); } - FindUtil.configureFindModel(myReplace, editor.getSelectionModel().getSelectedText(), model); + FindUtil.configureFindModel(myReplace, editor.getSelectionModel().getSelectedText(), model, true); final EditorSearchComponent header = new EditorSearchComponent(editor, project, model); editor.setHeaderComponent(header); header.requestFocus(); From 96400bfc55a2753d89be7e66ab3fba0defd875ce Mon Sep 17 00:00:00 2001 From: andrey zaytsev Date: Tue, 17 May 2011 04:01:55 +0400 Subject: [PATCH 13/31] IDEA-68974 Replace with Preserve Case does not preserve case on first attempt. --- platform/lang-api/src/com/intellij/find/FindModel.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/lang-api/src/com/intellij/find/FindModel.java b/platform/lang-api/src/com/intellij/find/FindModel.java index 5f4cbc12dd68..616e1b2211dc 100644 --- a/platform/lang-api/src/com/intellij/find/FindModel.java +++ b/platform/lang-api/src/com/intellij/find/FindModel.java @@ -98,7 +98,11 @@ public class FindModel extends UserDataHolderBase implements Cloneable { * @param preserveCase the value of the Preserve Case flag. */ public void setPreserveCase(boolean preserveCase) { + boolean changed = isPreserveCase != preserveCase; isPreserveCase = preserveCase; + if (changed) { + notifyObservers(); + } } private boolean isPreserveCase = false; From c93e69a157fb699c21f92d8efedfcb2da7bf6773 Mon Sep 17 00:00:00 2001 From: Gregory Shrago Date: Tue, 17 May 2011 04:39:53 +0400 Subject: [PATCH 14/31] separate column for type. correct error handling. empty string handling & escaping fixes. --- .../compiler/PatternCompilerImpl.java | 12 ++- .../intelliLang/InjectionsSettingsUI.java | 81 ++++++++++++++----- 2 files changed, 70 insertions(+), 23 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/patterns/compiler/PatternCompilerImpl.java b/platform/platform-impl/src/com/intellij/patterns/compiler/PatternCompilerImpl.java index fb82f5b64368..a9d8d045722d 100644 --- a/platform/platform-impl/src/com/intellij/patterns/compiler/PatternCompilerImpl.java +++ b/platform/platform-impl/src/com/intellij/patterns/compiler/PatternCompilerImpl.java @@ -51,8 +51,8 @@ public class PatternCompilerImpl implements PatternCompiler { myStaticMethods = getStaticMethods(patternClasses); } + private static final Node ERROR_NODE = new Node(null, null, null); @Override - @Nullable public ElementPattern createElementPattern(final String text, final String displayName) { try { return compileElementPattern(text); @@ -60,7 +60,7 @@ public class PatternCompilerImpl implements PatternCompiler { catch (Exception ex) { final Throwable cause = ex.getCause() != null ? ex.getCause() : ex; LOG.warn("error processing place: " + displayName + " [" + text + "]", cause); - return null; + return new LazyPresentablePattern(new Node(ERROR_NODE, text, null)); } } @@ -271,7 +271,7 @@ public class PatternCompilerImpl implements PatternCompiler { } private static Object makeParam(final String s) { - if (s.length() > 2 && s.startsWith("\"") && s.endsWith("\"")) return s.substring(1, s.length()-1); + if (s.length() >= 2 && s.startsWith("\"") && s.endsWith("\"")) return s.substring(1, s.length()-1); try { return Integer.valueOf(s); } @@ -608,6 +608,9 @@ public class PatternCompilerImpl implements PatternCompiler { } private StringBuilder toString(final Node node, final StringBuilder sb) { + if (node.target == ERROR_NODE) { + return sb.append(node.method); + } if (node.target != null) { toString(node.target, sb); sb.append('.'); @@ -621,7 +624,8 @@ public class PatternCompilerImpl implements PatternCompiler { toString((Node)arg, sb); } else if (arg instanceof String) { - sb.append('\"').append(StringUtil.escapeStringCharacters((String)arg)).append('\"'); + // todo no escaping! + sb.append('\"').append(arg).append('\"'); } else if (arg instanceof Number) { sb.append(arg); diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java index ec37f7957c9a..8a6ce50ba09c 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/InjectionsSettingsUI.java @@ -85,8 +85,10 @@ public class InjectionsSettingsUI implements Configurable { public InjectionsSettingsUI(final Project project, final Configuration configuration) { myProject = project; - myInfos = configuration instanceof Configuration.Prj? new CfgInfo[] {new CfgInfo(((Configuration.Prj)configuration).getParentConfiguration()), new CfgInfo(configuration)} - : new CfgInfo[] {new CfgInfo(configuration)}; + final CfgInfo currentInfo = new CfgInfo(configuration, "project"); + myInfos = configuration instanceof Configuration.Prj ? + new CfgInfo[]{new CfgInfo(((Configuration.Prj)configuration).getParentConfiguration(), "global"), currentInfo} + : new CfgInfo[]{currentInfo}; myRoot = new JPanel(new BorderLayout()); @@ -151,7 +153,7 @@ public class InjectionsSettingsUI implements Configurable { public void update(final AnActionEvent e) { boolean enabled = false; for (InjInfo info : getSelectedInjections()) { - if (!info.isBundled()) { + if (!info.bundled) { enabled = true; break; } @@ -235,7 +237,7 @@ public class InjectionsSettingsUI implements Configurable { if (cfg == null) return; for (InjInfo info : injections) { if (info.cfgInfo == cfg) continue; - if (info.isBundled()) continue; + if (info.bundled) continue; info.cfgInfo.injectionInfos.remove(info); cfg.addInjection(info.injection); } @@ -256,7 +258,7 @@ public class InjectionsSettingsUI implements Configurable { private CfgInfo getTargetCfgInfo(final List injections) { CfgInfo cfg = null; for (InjInfo info : injections) { - if (info.isBundled()) { + if (info.bundled) { continue; } if (cfg == null) cfg = info.cfgInfo; @@ -427,7 +429,7 @@ public class InjectionsSettingsUI implements Configurable { if (selectedRow < 0) return; final List selected = getSelectedInjections(); for (InjInfo info : selected) { - if (info.isBundled()) continue; + if (info.bundled) continue; info.cfgInfo.injectionInfos.remove(info); } myInjectionsTable.getListTableModel().setItems(getInjInfoList(myInfos)); @@ -548,7 +550,7 @@ public class InjectionsSettingsUI implements Configurable { return Comparing.compare(o1.injection.getDisplayName(), o2.injection.getDisplayName()); } }; - return new ColumnInfo[]{new ColumnInfo(" ") { + final ColumnInfo[] columnInfos = {new ColumnInfo(" ") { @Override public Class getColumnClass() { return Boolean.class; @@ -604,6 +606,36 @@ public class InjectionsSettingsUI implements Configurable { return languageCellRenderer; } }}; + if (myInfos.length > 1) { + final TableCellRenderer typeRenderer = createTypeRenderer(); + return ArrayUtil.append(columnInfos, new ColumnInfo("Type") { + @Override + public String valueOf(final InjInfo info) { + return info.bundled ? "bundled" : info.cfgInfo.title; + } + + @Override + public TableCellRenderer getRenderer(final InjInfo injInfo) { + return typeRenderer; + } + + @Override + public int getWidth(final JTable table) { + return table.getFontMetrics(table.getFont()).stringWidth(StringUtil.repeatSymbol('m', 6)); + } + + @Override + public Comparator getComparator() { + return new Comparator() { + @Override + public int compare(final InjInfo o1, final InjInfo o2) { + return Comparing.compare(valueOf(o1), valueOf(o2)); + } + }; + } + }); + } + return columnInfos; } private static BooleanTableCellRenderer createBooleanCellRenderer() { @@ -653,17 +685,10 @@ public class InjectionsSettingsUI implements Configurable { final InjInfo info = (InjInfo)value; // fix for a marvellous Swing peculiarity: AccessibleJTable likes to pass null here if (info == null) return myLabel; - final boolean projectLevel = myInfos.length > 1 && info.cfgInfo != myInfos[0]; final SimpleTextAttributes grayAttrs = isSelected ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES; final String supportId = info.injection.getSupportId(); myText.append(supportId + ": ", grayAttrs); mySupports.get(supportId).setupPresentation(info.injection, myText, isSelected); - if (projectLevel) { - for (ListIterator it = myText.getAttributes().listIterator(); it.hasNext(); ) { - final SimpleTextAttributes attributes = it.next(); - it.set(attributes.derive(SimpleTextAttributes.STYLE_BOLD, null, null, null)); - } - } myText.appendToComponent(myLabel); myText.clear(); setLabelColors(myLabel, table, isSelected, row); @@ -672,6 +697,24 @@ public class InjectionsSettingsUI implements Configurable { }; } + private static TableCellRenderer createTypeRenderer() { + return new TableCellRenderer() { + final SimpleColoredComponent myLabel = new SimpleColoredComponent(); + + public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, + final int row, + final int column) { + myLabel.clear(); + final String info = (String)value; + if (info == null) return myLabel; + final SimpleTextAttributes grayAttrs = isSelected ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES; + myLabel.append(info, grayAttrs); + setLabelColors(myLabel, table, isSelected, row); + return myLabel; + } + }; + } + private static Component setLabelColors(final Component label, final JTable table, final boolean isSelected, final int row) { if (label instanceof JComponent) { ((JComponent)label).setOpaque(true); @@ -768,9 +811,11 @@ public class InjectionsSettingsUI implements Configurable { final List originalInjections; final List injectionInfos = new ArrayList(); final THashSet bundledInjections = new THashSet(new SameParamsAndPlacesStrategy()); + final String title; - public CfgInfo(Configuration cfg) { + public CfgInfo(Configuration cfg, final String title) { this.cfg = cfg; + this.title = title; bundledInjections.addAll(cfg.getDefaultInjections()); originalInjections = ContainerUtil .concat(InjectorUtils.getActiveInjectionSupportIds(), new Function>() { @@ -846,14 +891,12 @@ public class InjectionsSettingsUI implements Configurable { private static class InjInfo { final BaseInjection injection; final CfgInfo cfgInfo; + final boolean bundled; private InjInfo(final BaseInjection injection, final CfgInfo cfgInfo) { this.injection = injection; this.cfgInfo = cfgInfo; - } - - boolean isBundled() { - return cfgInfo.bundledInjections.contains(injection); + bundled = cfgInfo.bundledInjections.contains(injection); } } From ca9f9542f4b99f5a866c45c9ea9129ff0275ab61 Mon Sep 17 00:00:00 2001 From: Gregory Shrago Date: Tue, 17 May 2011 05:14:45 +0400 Subject: [PATCH 15/31] do not log error message twice --- .../src/com/intellij/patterns/compiler/PatternCompilerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/patterns/compiler/PatternCompilerImpl.java b/platform/platform-impl/src/com/intellij/patterns/compiler/PatternCompilerImpl.java index a9d8d045722d..179f575b146d 100644 --- a/platform/platform-impl/src/com/intellij/patterns/compiler/PatternCompilerImpl.java +++ b/platform/platform-impl/src/com/intellij/patterns/compiler/PatternCompilerImpl.java @@ -591,7 +591,7 @@ public class PatternCompilerImpl implements PatternCompiler { if (myCompiledPattern == null) { Object result; try { - result = execute(myNode); + result = myNode.target == ERROR_NODE? ALWAYS_FALSE : execute(myNode); } catch (Throwable throwable) { LOG.error(toString(), throwable); From 215a3b0e65e7a6f552c5d3cbcf63f285095500e3 Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Mon, 16 May 2011 14:06:46 +0200 Subject: [PATCH 16/31] AppCode: Formatter: separate options for method and functions alignment and braces (OC-878) --- .../intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java index d0138253edfa..5f070bdfe924 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java @@ -16,6 +16,7 @@ package com.intellij.psi.codeStyle; import com.intellij.openapi.application.ApplicationBundle; +import org.jetbrains.annotations.Nullable; public interface CodeStyleSettingsCustomizable { String SPACES_AROUND_OPERATORS = ApplicationBundle.message("group.spaces.around.operators"); @@ -107,7 +108,7 @@ public interface CodeStyleSettingsCustomizable { void showCustomOption(Class settingsClass, String fieldName, String title, - String groupName, + @Nullable String groupName, Object... options); void renameStandardOption(String fieldName, String newTitle); From 107ba1616c339579510d304384e88153d81398af Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Tue, 17 May 2011 09:50:54 +0200 Subject: [PATCH 17/31] Platform: Code Style Settings: ability to rearrange settings AppCode: Formatter: separate options for method and functions alignment and braces (OC-878), UI --- .../CodeStyleSettingsCustomizable.java | 10 ++ .../codeStyle/CodeStyleBlankLinesPanel.java | 12 ++ .../MultilanguageCodeStyleAbstractPanel.java | 115 ++++++++++++++--- .../OptionTableWithPreviewPanel.java | 41 ++++-- .../codeStyle/OptionTreeWithPreviewPanel.java | 117 +++++++++++++----- 5 files changed, 230 insertions(+), 65 deletions(-) diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java index 5f070bdfe924..9f16a2ab6e12 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java @@ -19,6 +19,8 @@ import com.intellij.openapi.application.ApplicationBundle; import org.jetbrains.annotations.Nullable; public interface CodeStyleSettingsCustomizable { + enum OptionAnchor {NONE, BEFORE, AFTER} + String SPACES_AROUND_OPERATORS = ApplicationBundle.message("group.spaces.around.operators"); String SPACES_BEFORE_PARENTHESES = ApplicationBundle.message("group.spaces.before.parentheses"); String SPACES_BEFORE_LEFT_BRACE = ApplicationBundle.message("group.spaces.before.left.brace"); @@ -111,5 +113,13 @@ public interface CodeStyleSettingsCustomizable { @Nullable String groupName, Object... options); + void showCustomOption(Class settingsClass, + String fieldName, + String title, + @Nullable String groupName, + @Nullable OptionAnchor anchor, + @Nullable String anchorFieldName, + Object... options); + void renameStandardOption(String fieldName, String newTitle); } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleBlankLinesPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleBlankLinesPanel.java index a7c0f9e930d4..e2227c87ba00 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleBlankLinesPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/CodeStyleBlankLinesPanel.java @@ -27,6 +27,7 @@ import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider; import com.intellij.ui.OptionGroup; import com.intellij.util.containers.MultiMap; import gnu.trove.THashMap; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -185,10 +186,21 @@ public class CodeStyleBlankLinesPanel extends MultilanguageCodeStyleAbstractPane } } + @Override public void showCustomOption(Class settingsClass, String fieldName, String title, String groupName, Object... options) { + showCustomOption(settingsClass, fieldName, title, groupName, null, null, options); + } + + public void showCustomOption(Class settingsClass, + String fieldName, + String title, + String groupName, + @Nullable OptionAnchor anchor, + @Nullable String anchorFieldName, + Object... options) { if (myIsFirstUpdate) { myCustomOptions.putValue(groupName, (Trinity)Trinity.create(settingsClass, fieldName, title)); } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/MultilanguageCodeStyleAbstractPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/MultilanguageCodeStyleAbstractPanel.java index 0a1a7a84a64a..c334789c2ff7 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/MultilanguageCodeStyleAbstractPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/MultilanguageCodeStyleAbstractPanel.java @@ -35,7 +35,11 @@ import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable; import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider; import com.intellij.ui.IdeBorderFactory; +import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; +import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -45,6 +49,10 @@ import javax.swing.event.AncestorListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; /** * Base class for code style settings panels supporting multiple programming languages. @@ -63,15 +71,15 @@ public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstr } protected void init() { - for(LanguageCodeStyleSettingsProvider provider: Extensions.getExtensions(LanguageCodeStyleSettingsProvider.EP_NAME)) { + for (LanguageCodeStyleSettingsProvider provider : Extensions.getExtensions(LanguageCodeStyleSettingsProvider.EP_NAME)) { provider.customizeSettings(this, getSettingsType()); } } - public boolean setPanelLanguage(Language language) { + public boolean setPanelLanguage(Language language) { boolean languageProviderFound = false; - for(LanguageCodeStyleSettingsProvider provider: Extensions.getExtensions(LanguageCodeStyleSettingsProvider.EP_NAME)) { + for (LanguageCodeStyleSettingsProvider provider : Extensions.getExtensions(LanguageCodeStyleSettingsProvider.EP_NAME)) { if (provider.getLanguage().is(language)) { provider.customizeSettings(this, getSettingsType()); languageProviderFound = true; @@ -79,7 +87,7 @@ public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstr } } if (!languageProviderFound) return false; - + myLanguage = language; setSkipPreviewHighlighting(true); @@ -162,21 +170,21 @@ public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstr final PsiDocumentManager manager = PsiDocumentManager.getInstance(project); final Document doc = manager.getDocument(psiFile); CommandProcessor.getInstance().executeCommand(project, new Runnable() { - public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - doc.replaceString(0, doc.getTextLength(), text); - manager.commitDocument(doc); - try { - CodeStyleManager.getInstance(project).reformat(psiFile); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - }); - } - }, "", ""); + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + doc.replaceString(0, doc.getTextLength(), text); + manager.commitDocument(doc); + try { + CodeStyleManager.getInstance(project).reformat(psiFile); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + }); + } + }, "", ""); if (doc != null) { manager.commitDocument(doc); } @@ -237,7 +245,7 @@ public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstr } private void selectCurrentLanguageTab() { - for(int i = 0; i < tabbedPane.getTabCount(); i ++) { + for (int i = 0; i < tabbedPane.getTabCount(); i++) { if (getTabName(myLanguage).equals(tabbedPane.getTitleAt(i))) { tabbedPane.setSelectedIndex(i); return; @@ -272,4 +280,71 @@ public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstr public Language getDefaultLanguage() { return getSelectedLanguage(); } + + protected List sortOptions(Collection options) { + Set names = new THashSet(ContainerUtil.map(options, new Function() { + @Override + public String fun(OrderedOption option) { + return option.getOptionName(); + } + })); + + List order = new ArrayList(options.size()); + MultiMap afters = new MultiMap(); + MultiMap befores = new MultiMap(); + + for (T each : options) { + String anchorOptionName = each.getAnchorOptionName(); + if (anchorOptionName != null && names.contains(anchorOptionName)) { + if (each.getAnchor() == OptionAnchor.AFTER) { + afters.putValue(anchorOptionName, each); + continue; + } + else if (each.getAnchor() == OptionAnchor.BEFORE) { + befores.putValue(anchorOptionName, each); + continue; + } + } + order.add(each); + } + + List result = new ArrayList(options.size()); + for (T each : order) { + result.addAll(befores.get(each.getOptionName())); + result.add(each); + result.addAll(afters.get(each.getOptionName())); + } + + assert result.size() == options.size(); + return result; + } + + protected abstract static class OrderedOption { + @NotNull private final String optionName; + @Nullable private final OptionAnchor anchor; + @Nullable private final String anchorOptionName; + + protected OrderedOption(@NotNull String optionName, + OptionAnchor anchor, + String anchorOptionName) { + this.optionName = optionName; + this.anchor = anchor; + this.anchorOptionName = anchorOptionName; + } + + @NotNull + public String getOptionName() { + return optionName; + } + + @Nullable + public OptionAnchor getAnchor() { + return anchor; + } + + @Nullable + public String getAnchorOptionName() { + return anchorOptionName; + } + } } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java index c4be46101146..74bf7b190f71 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java @@ -125,19 +125,31 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle } } + @Override + public void showCustomOption(Class settingsClass, + String fieldName, + String title, + String groupName, Object... options) { + showCustomOption(settingsClass, fieldName, title, groupName, null, null, options); + } + + @Override public void showCustomOption(Class settingsClass, String fieldName, String title, String groupName, + @Nullable OptionAnchor anchor, + @Nullable String anchorFieldName, Object... options) { if (isFirstUpdate) { Option option; if (options.length == 2) { - option = new SelectionOption(settingsClass, fieldName, title, groupName, (String[])options[0], (int[])options[1]); + option = + new SelectionOption(settingsClass, fieldName, title, groupName, anchor, anchorFieldName, (String[])options[0], (int[])options[1]); } else { - option = new BooleanOption(settingsClass, fieldName, title, groupName); + option = new BooleanOption(settingsClass, fieldName, title, groupName, anchor, anchorFieldName); } myCustomOptions.add(option); option.setEnabled(true); @@ -162,7 +174,8 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(); Map groupsMap = new THashMap(); - for (Option each : ContainerUtil.concat(myOptions, myCustomOptions)) { + List