From 5005b535359c9c52f98bd560185ebfc2a26090b4 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Thu, 30 Apr 2015 21:05:37 +0300 Subject: [PATCH 01/28] PY-14962 Initial version of extended options for dict literal formatting in Python --- .../jetbrains/python/formatter/PyBlock.java | 47 ++++++++++++- .../formatter/PyCodeStyleMainPanel.java | 5 ++ .../python/formatter/PyCodeStylePanel.form | 62 ++++++++++++++++- .../python/formatter/PyCodeStylePanel.java | 67 +++++++++++++++---- .../python/formatter/PyCodeStyleSettings.java | 25 +++++++ ...TrailingBlankLinesPostFormatProcessor.java | 1 + 6 files changed, 190 insertions(+), 17 deletions(-) diff --git a/python/src/com/jetbrains/python/formatter/PyBlock.java b/python/src/com/jetbrains/python/formatter/PyBlock.java index 1b03c9f26b2c..c05e4dc3ea96 100644 --- a/python/src/com/jetbrains/python/formatter/PyBlock.java +++ b/python/src/com/jetbrains/python/formatter/PyBlock.java @@ -21,6 +21,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.impl.source.tree.TreeUtil; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; @@ -29,6 +30,7 @@ import com.intellij.util.ArrayUtil; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.PythonDialectsTokenSetProvider; +import com.jetbrains.python.formatter.PyCodeStyleSettings.DictAlignment; import com.jetbrains.python.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -83,6 +85,7 @@ public class PyBlock implements ASTBlock { private final PyBlockContext myContext; private List mySubBlocks = null; private Alignment myChildAlignment; + private final Alignment myDictAlignment; private final boolean myEmptySequence; public PyBlock(final PyBlock parent, @@ -98,6 +101,8 @@ public class PyBlock implements ASTBlock { myWrap = wrap; myContext = context; myEmptySequence = isEmptySequence(node); + + myDictAlignment = node.getElementType() == PyElementTypes.DICT_LITERAL_EXPRESSION ? Alignment.createAlignment(true) : null; } @NotNull @@ -147,7 +152,10 @@ public class PyBlock implements ASTBlock { private PyBlock buildSubBlock(ASTNode child) { final IElementType parentType = myNode.getElementType(); - final IElementType grandparentType = myNode.getTreeParent() == null ? null : myNode.getTreeParent().getElementType(); + + final ASTNode grandParentNode = myNode.getTreeParent(); + final IElementType grandparentType = grandParentNode == null ? null : grandParentNode.getElementType(); + final IElementType childType = child.getElementType(); Wrap wrap = null; Indent childIndent = Indent.getNoneIndent(); @@ -216,6 +224,7 @@ public class PyBlock implements ASTBlock { } } + PyCodeStyleSettings settings = CodeStyleSettingsManager.getSettings(child.getPsi().getProject()).getCustomSettings(PyCodeStyleSettings.class); if (parentType == PyElementTypes.LIST_LITERAL_EXPRESSION || parentType == PyElementTypes.LIST_COMP_EXPRESSION) { if (childType == PyTokenTypes.RBRACKET || childType == PyTokenTypes.LBRACKET) { childIndent = Indent.getNoneIndent(); @@ -241,7 +250,7 @@ public class PyBlock implements ASTBlock { else if (parentType == PyElementTypes.FROM_IMPORT_STATEMENT) { if (myNode.findChildByType(PyTokenTypes.LPAR) != null) { if (childType == PyElementTypes.IMPORT_ELEMENT) { - if (myContext.getPySettings().ALIGN_MULTILINE_IMPORTS) { + if (settings.ALIGN_MULTILINE_IMPORTS) { childAlignment = getAlignmentForChildren(); } else { @@ -330,12 +339,27 @@ public class PyBlock implements ASTBlock { } } } - if (isAfterStatementList(child) && !hasLineBreaksBefore(child, 2) && child.getElementType() != PyTokenTypes.END_OF_LINE_COMMENT) { // maybe enter was pressed and cut us from a previous (nested) statement list childIndent = Indent.getNormalIndent(); } + if (settings.DICT_ALIGNMENT == DictAlignment.ON_VALUE.ordinal()) { + if (isDictLiteralPropertyValue(child) && !ourListElementTypes.contains(childType)) { + childAlignment = myParent.myDictAlignment; + } + else if (isDictLiteralPropertyValue(myNode) && + ourListElementTypes.contains(parentType) && + PyTokenTypes.OPEN_BRACES.contains(childType)) { + childAlignment = myParent.myParent.myDictAlignment; + } + } + else if (myContext.getPySettings().DICT_ALIGNMENT == DictAlignment.ON_COLON.ordinal()) { + if (isInsideDictLiteralKeyValue(child) && childType == PyTokenTypes.COLON) { + childAlignment = myParent.myDictAlignment; + } + } + ASTNode prev = child.getTreePrev(); while (prev != null && prev.getElementType() == TokenType.WHITE_SPACE) { if (prev.textContains('\\') && @@ -350,6 +374,23 @@ public class PyBlock implements ASTBlock { return new PyBlock(this, child, childAlignment, childIndent, wrap, myContext); } + private static boolean isDictLiteralPropertyValue(@NotNull ASTNode node) { + return isInsideDictLiteralKeyValue(node) && node.getTreeParent().getPsi(PyKeyValueExpression.class).getValue() == node.getPsi(); + } + + private static boolean isInsideDictLiteralKeyValue(@NotNull ASTNode node) { + final ASTNode nodeParent = node.getTreeParent(); + if (nodeParent == null) { + return false; + } + final ASTNode nodeGrandParent = nodeParent.getTreeParent(); + if (nodeGrandParent == null) { + return false; + } + return nodeParent.getElementType() == PyElementTypes.KEY_VALUE_EXPRESSION && + nodeGrandParent.getElementType() == PyElementTypes.DICT_LITERAL_EXPRESSION; + } + private static boolean isEmptySequence(@NotNull ASTNode node) { return node.getPsi() instanceof PySequenceExpression && ((PySequenceExpression)node.getPsi()).isEmpty(); } diff --git a/python/src/com/jetbrains/python/formatter/PyCodeStyleMainPanel.java b/python/src/com/jetbrains/python/formatter/PyCodeStyleMainPanel.java index 479074df2826..b48315f9004f 100644 --- a/python/src/com/jetbrains/python/formatter/PyCodeStyleMainPanel.java +++ b/python/src/com/jetbrains/python/formatter/PyCodeStyleMainPanel.java @@ -27,4 +27,9 @@ public class PyCodeStyleMainPanel extends TabbedLanguageCodeStylePanel { super(PythonLanguage.getInstance(), currentSettings, settings); } + @Override + protected void initTabs(CodeStyleSettings settings) { + super.initTabs(settings); + addTab(new PyCodeStylePanel(settings)); + } } diff --git a/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.form b/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.form index d776fac9f890..8fc0b4ba3d12 100644 --- a/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.form +++ b/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.form @@ -1,12 +1,70 @@
- + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.java b/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.java index 66315fe0d46b..b1f8f345fdfd 100644 --- a/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.java +++ b/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.java @@ -16,32 +16,57 @@ package com.jetbrains.python.formatter; import com.intellij.application.options.CodeStyleAbstractPanel; -import com.intellij.ide.highlighter.HighlighterFactory; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.highlighter.EditorHighlighter; +import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory; import com.intellij.openapi.fileTypes.FileType; -import com.intellij.psi.PsiFile; +import com.intellij.openapi.ui.ComboBox; import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.jetbrains.python.highlighting.PyHighlighter; +import com.intellij.testFramework.LightVirtualFile; +import com.intellij.ui.components.JBCheckBox; import com.jetbrains.python.PythonFileType; -import com.jetbrains.python.psi.LanguageLevel; +import com.jetbrains.python.PythonLanguage; +import com.jetbrains.python.formatter.PyCodeStyleSettings.DictAlignment; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; /** * @author yole */ public class PyCodeStylePanel extends CodeStyleAbstractPanel { + private JPanel myPanel; + private JBCheckBox myAddTrailingLineFeedCheckbox; + private ComboBox myDictAlignmentCombo; + private JPanel myPreviewPanel; protected PyCodeStylePanel(CodeStyleSettings settings) { - super(settings); + super(PythonLanguage.getInstance(), null, settings); + addPanelToWatch(myPanel); + installPreviewPanel(myPreviewPanel); + + for (DictAlignment alignment : DictAlignment.values()) { + //noinspection unchecked + myDictAlignmentCombo.addItem(alignment); + } + + myDictAlignmentCombo.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + somethingChanged(); + } + } + }); } @Override protected EditorHighlighter createHighlighter(EditorColorsScheme scheme) { - return HighlighterFactory.createHighlighter(new PyHighlighter(LanguageLevel.PYTHON26), scheme); + return EditorHighlighterFactory.getInstance().createEditorHighlighter(new LightVirtualFile("a.py"), scheme, null); + //return HighlighterFactory.createHighlighter(new PyHighlighter(LanguageLevel.PYTHON26), scheme); } @Override @@ -49,10 +74,6 @@ public class PyCodeStylePanel extends CodeStyleAbstractPanel { return 80; } - @Override - protected void prepareForReformat(PsiFile psiFile) { - } - @NotNull @Override protected FileType getFileType() { @@ -61,24 +82,46 @@ public class PyCodeStylePanel extends CodeStyleAbstractPanel { @Override protected String getPreviewText() { - return ""; + return PREVIEW; } @Override protected void resetImpl(CodeStyleSettings settings) { + for (DictAlignment alignment : DictAlignment.values()) { + if (getCustomSettings(settings).DICT_ALIGNMENT == alignment.ordinal()) { + myDictAlignmentCombo.setSelectedItem(alignment); + break; + } + } } @Override public void apply(CodeStyleSettings settings) { + getCustomSettings(settings).DICT_ALIGNMENT = getSelectedDictAlignment().ordinal(); } @Override public boolean isModified(CodeStyleSettings settings) { - return false; + return getCustomSettings(settings).DICT_ALIGNMENT != getSelectedDictAlignment().ordinal(); } @Override public JComponent getPanel() { return myPanel; } + + @NotNull + private static PyCodeStyleSettings getCustomSettings(@NotNull CodeStyleSettings settings) { + return settings.getCustomSettings(PyCodeStyleSettings.class); + } + + @NotNull + private DictAlignment getSelectedDictAlignment() { + return (DictAlignment)myDictAlignmentCombo.getSelectedItem(); + } + + public static final String PREVIEW = "{\n" + + " \"green\": 42,\n" + + " \"eggs and ham\": -0.0e0\n" + + "}"; } diff --git a/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java b/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java index c060b782d1ad..c691ec8a5c5d 100644 --- a/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java +++ b/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java @@ -22,6 +22,29 @@ import com.intellij.psi.codeStyle.CustomCodeStyleSettings; * @author yole */ public class PyCodeStyleSettings extends CustomCodeStyleSettings { + + public enum DictAlignment { + NONE("Do not align"), + ON_VALUE("Align on value"), + ON_COLON("Align on colon"); + + String description; + + DictAlignment(String description) { + this.description = description; + } + + @Override + public String toString() { + return description; + } + } + + // Unfortunately, the old serializer for code style settings can't handle enums + public static final int KEY_VALUE_DO_NOT_ALIGN = DictAlignment.NONE.ordinal(); + public static final int KEY_VALUE_ALIGN_ON_VALUE = DictAlignment.ON_VALUE.ordinal(); + public static final int KEY_VALUE_ALIGN_ON_COLON = DictAlignment.ON_COLON.ordinal(); + public boolean SPACE_WITHIN_BRACES = false; public boolean SPACE_BEFORE_PY_COLON = false; public boolean SPACE_AFTER_PY_COLON = true; @@ -43,6 +66,8 @@ public class PyCodeStyleSettings extends CustomCodeStyleSettings { public boolean SPACE_AFTER_NUMBER_SIGN = true; public boolean SPACE_BEFORE_NUMBER_SIGN = true; + public int DICT_ALIGNMENT = KEY_VALUE_DO_NOT_ALIGN; + public PyCodeStyleSettings(CodeStyleSettings container) { super("Python", container); } diff --git a/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java b/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java index 489000630a5c..2ad73539acae 100644 --- a/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java +++ b/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java @@ -117,6 +117,7 @@ public class PyTrailingBlankLinesPostFormatProcessor implements PostFormatProces if (numLineFeeds <= 0 && EditorSettingsExternalizable.getInstance().isEnsureNewLineAtEOF()) { numLineFeeds = 1; } + // TODO: figure out why this line causes all changes made because of dict alignment to be reverted documentManager.doPostponedOperationsAndUnblockDocument(document); try { final String text = StringUtil.repeat("\n", numLineFeeds); From 841c98065daeb56ab551ebdf3d8aa23f48294dcf Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 13 May 2015 16:47:54 +0300 Subject: [PATCH 02/28] PY-12360 Use dedicated checkbox in code style settings to enforce trailing blank line This checkbox is in the "Other" tab together with new dict alignment options. It's much better place than previously used "Blank Lines" panel because you can put only integer-values options there and because of this limitation user had to specify *number* of trailing blank lines, and that was awkward. --- .../jetbrains/python/formatter/PyBlock.java | 8 ++-- .../python/formatter/PyCodeStylePanel.form | 2 +- .../python/formatter/PyCodeStylePanel.java | 39 +++++++++++++------ .../python/formatter/PyCodeStyleSettings.java | 14 ++++--- .../PyLanguageCodeStyleSettingsProvider.java | 1 - ...TrailingBlankLinesPostFormatProcessor.java | 16 ++++---- 6 files changed, 50 insertions(+), 30 deletions(-) diff --git a/python/src/com/jetbrains/python/formatter/PyBlock.java b/python/src/com/jetbrains/python/formatter/PyBlock.java index c05e4dc3ea96..1a87f49963e7 100644 --- a/python/src/com/jetbrains/python/formatter/PyBlock.java +++ b/python/src/com/jetbrains/python/formatter/PyBlock.java @@ -30,7 +30,6 @@ import com.intellij.util.ArrayUtil; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.PythonDialectsTokenSetProvider; -import com.jetbrains.python.formatter.PyCodeStyleSettings.DictAlignment; import com.jetbrains.python.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,6 +39,9 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import static com.jetbrains.python.formatter.PyCodeStyleSettings.DICT_ALIGNMENT_ON_COLON; +import static com.jetbrains.python.formatter.PyCodeStyleSettings.DICT_ALIGNMENT_ON_VALUE; + /** * @author yole */ @@ -344,7 +346,7 @@ public class PyBlock implements ASTBlock { childIndent = Indent.getNormalIndent(); } - if (settings.DICT_ALIGNMENT == DictAlignment.ON_VALUE.ordinal()) { + if (settings.DICT_ALIGNMENT == DICT_ALIGNMENT_ON_VALUE) { if (isDictLiteralPropertyValue(child) && !ourListElementTypes.contains(childType)) { childAlignment = myParent.myDictAlignment; } @@ -354,7 +356,7 @@ public class PyBlock implements ASTBlock { childAlignment = myParent.myParent.myDictAlignment; } } - else if (myContext.getPySettings().DICT_ALIGNMENT == DictAlignment.ON_COLON.ordinal()) { + else if (myContext.getPySettings().DICT_ALIGNMENT == DICT_ALIGNMENT_ON_COLON) { if (isInsideDictLiteralKeyValue(child) && childType == PyTokenTypes.COLON) { childAlignment = myParent.myDictAlignment; } diff --git a/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.form b/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.form index 8fc0b4ba3d12..9884e8a9fee5 100644 --- a/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.form +++ b/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.form @@ -45,7 +45,7 @@ - + diff --git a/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.java b/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.java index b1f8f345fdfd..00334078dc9b 100644 --- a/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.java +++ b/python/src/com/jetbrains/python/formatter/PyCodeStylePanel.java @@ -16,20 +16,23 @@ package com.jetbrains.python.formatter; import com.intellij.application.options.CodeStyleAbstractPanel; +import com.intellij.ide.highlighter.HighlighterFactory; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.highlighter.EditorHighlighter; -import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.ui.ComboBox; import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.testFramework.LightVirtualFile; import com.intellij.ui.components.JBCheckBox; import com.jetbrains.python.PythonFileType; import com.jetbrains.python.PythonLanguage; import com.jetbrains.python.formatter.PyCodeStyleSettings.DictAlignment; +import com.jetbrains.python.highlighting.PyHighlighter; +import com.jetbrains.python.psi.LanguageLevel; import org.jetbrains.annotations.NotNull; import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; @@ -39,7 +42,7 @@ import java.awt.event.ItemListener; public class PyCodeStylePanel extends CodeStyleAbstractPanel { private JPanel myPanel; - private JBCheckBox myAddTrailingLineFeedCheckbox; + private JBCheckBox myAddTrailingBlankLineCheckbox; private ComboBox myDictAlignmentCombo; private JPanel myPreviewPanel; @@ -61,12 +64,18 @@ public class PyCodeStylePanel extends CodeStyleAbstractPanel { } } }); + + myAddTrailingBlankLineCheckbox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + somethingChanged(); + } + }); } @Override protected EditorHighlighter createHighlighter(EditorColorsScheme scheme) { - return EditorHighlighterFactory.getInstance().createEditorHighlighter(new LightVirtualFile("a.py"), scheme, null); - //return HighlighterFactory.createHighlighter(new PyHighlighter(LanguageLevel.PYTHON26), scheme); + return HighlighterFactory.createHighlighter(new PyHighlighter(LanguageLevel.PYTHON26), scheme); } @Override @@ -88,21 +97,26 @@ public class PyCodeStylePanel extends CodeStyleAbstractPanel { @Override protected void resetImpl(CodeStyleSettings settings) { for (DictAlignment alignment : DictAlignment.values()) { - if (getCustomSettings(settings).DICT_ALIGNMENT == alignment.ordinal()) { + if (getCustomSettings(settings).DICT_ALIGNMENT == alignment.asInt()) { myDictAlignmentCombo.setSelectedItem(alignment); break; } } + myAddTrailingBlankLineCheckbox.setSelected(getCustomSettings(settings).BLANK_LINE_AT_FILE_END); } @Override public void apply(CodeStyleSettings settings) { - getCustomSettings(settings).DICT_ALIGNMENT = getSelectedDictAlignment().ordinal(); + final PyCodeStyleSettings customSettings = getCustomSettings(settings); + customSettings.DICT_ALIGNMENT = getDictAlignmentAsInt(); + customSettings.BLANK_LINE_AT_FILE_END = ensureTrailingBlankLine(); } @Override public boolean isModified(CodeStyleSettings settings) { - return getCustomSettings(settings).DICT_ALIGNMENT != getSelectedDictAlignment().ordinal(); + final PyCodeStyleSettings customSettings = getCustomSettings(settings); + return customSettings.DICT_ALIGNMENT != getDictAlignmentAsInt() || + customSettings.BLANK_LINE_AT_FILE_END != ensureTrailingBlankLine(); } @Override @@ -115,9 +129,12 @@ public class PyCodeStylePanel extends CodeStyleAbstractPanel { return settings.getCustomSettings(PyCodeStyleSettings.class); } - @NotNull - private DictAlignment getSelectedDictAlignment() { - return (DictAlignment)myDictAlignmentCombo.getSelectedItem(); + private int getDictAlignmentAsInt() { + return ((DictAlignment)myDictAlignmentCombo.getSelectedItem()).asInt(); + } + + private boolean ensureTrailingBlankLine() { + return myAddTrailingBlankLineCheckbox.isSelected(); } public static final String PREVIEW = "{\n" + diff --git a/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java b/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java index c691ec8a5c5d..795b8c42e987 100644 --- a/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java +++ b/python/src/com/jetbrains/python/formatter/PyCodeStyleSettings.java @@ -34,6 +34,10 @@ public class PyCodeStyleSettings extends CustomCodeStyleSettings { this.description = description; } + public int asInt() { + return ordinal(); + } + @Override public String toString() { return description; @@ -41,9 +45,9 @@ public class PyCodeStyleSettings extends CustomCodeStyleSettings { } // Unfortunately, the old serializer for code style settings can't handle enums - public static final int KEY_VALUE_DO_NOT_ALIGN = DictAlignment.NONE.ordinal(); - public static final int KEY_VALUE_ALIGN_ON_VALUE = DictAlignment.ON_VALUE.ordinal(); - public static final int KEY_VALUE_ALIGN_ON_COLON = DictAlignment.ON_COLON.ordinal(); + public static final int DICT_ALIGNMENT_NONE = DictAlignment.NONE.asInt(); + public static final int DICT_ALIGNMENT_ON_VALUE = DictAlignment.ON_VALUE.asInt(); + public static final int DICT_ALIGNMENT_ON_COLON = DictAlignment.ON_COLON.asInt(); public boolean SPACE_WITHIN_BRACES = false; public boolean SPACE_BEFORE_PY_COLON = false; @@ -55,7 +59,7 @@ public class PyCodeStyleSettings extends CustomCodeStyleSettings { public int BLANK_LINES_AROUND_TOP_LEVEL_CLASSES_FUNCTIONS = 2; // TODO make boolean (it needs special editor in BlankLinesPanel) - public int BLANKS_LINES_AT_FILE_END = 1; + public boolean BLANK_LINE_AT_FILE_END = true; public boolean ALIGN_COLLECTIONS_AND_COMPREHENSIONS = true; public boolean ALIGN_MULTILINE_IMPORTS = true; @@ -66,7 +70,7 @@ public class PyCodeStyleSettings extends CustomCodeStyleSettings { public boolean SPACE_AFTER_NUMBER_SIGN = true; public boolean SPACE_BEFORE_NUMBER_SIGN = true; - public int DICT_ALIGNMENT = KEY_VALUE_DO_NOT_ALIGN; + public int DICT_ALIGNMENT = DICT_ALIGNMENT_NONE; public PyCodeStyleSettings(CodeStyleSettings container) { super("Python", container); diff --git a/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java b/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java index ed213eaf36a9..a74c457d9efb 100644 --- a/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java +++ b/python/src/com/jetbrains/python/formatter/PyLanguageCodeStyleSettingsProvider.java @@ -88,7 +88,6 @@ public class PyLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettin consumer.showCustomOption(PyCodeStyleSettings.class, "BLANK_LINES_AROUND_TOP_LEVEL_CLASSES_FUNCTIONS", "Around top-level classes and functions:", BLANK_LINES); - consumer.showCustomOption(PyCodeStyleSettings.class, "BLANKS_LINES_AT_FILE_END", "Blank lines at the end of file", BLANK_LINES); } else if (settingsType == SettingsType.WRAPPING_AND_BRACES_SETTINGS) { consumer.showStandardOptions("RIGHT_MARGIN", diff --git a/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java b/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java index 2ad73539acae..efc3dfbff996 100644 --- a/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java +++ b/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java @@ -20,7 +20,6 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -34,11 +33,11 @@ import org.jetbrains.annotations.NotNull; * Handles extra blank lines at the end of the file if corresponding whitespace elements belong to formatted range/element. * These trailing whitespaces are replaced by line feeds if either: *
    - *
  • Option {@link PyCodeStyleSettings#BLANKS_LINES_AT_FILE_END} has positive value. In this case that number of line feeds will be - * inserted at the end of file.
  • + *
  • Option {@link PyCodeStyleSettings#BLANK_LINE_AT_FILE_END} is enabled.
  • *
  • Setting {@link EditorSettingsExternalizable#isEnsureNewLineAtEOF()} is enabled. Otherwise extra new line added on the next * "Save" action will be removed after reformatting.
  • *
+ * and file is not empty. * If none of these conditions holds, blank lines are removed completely. * * @author Mikhail Golubev @@ -113,15 +112,14 @@ public class PyTrailingBlankLinesPostFormatProcessor implements PostFormatProces final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); final Document document = documentManager.getDocument(pyFile); if (document != null) { - int numLineFeeds = CodeStyleSettingsManager.getSettings(project).getCustomSettings(PyCodeStyleSettings.class).BLANKS_LINES_AT_FILE_END; - if (numLineFeeds <= 0 && EditorSettingsExternalizable.getInstance().isEnsureNewLineAtEOF()) { - numLineFeeds = 1; - } + final PyCodeStyleSettings customSettings = CodeStyleSettingsManager.getSettings(project).getCustomSettings(PyCodeStyleSettings.class); + final boolean addLineFeed = customSettings.BLANK_LINE_AT_FILE_END || EditorSettingsExternalizable.getInstance().isEnsureNewLineAtEOF(); // TODO: figure out why this line causes all changes made because of dict alignment to be reverted documentManager.doPostponedOperationsAndUnblockDocument(document); try { - final String text = StringUtil.repeat("\n", numLineFeeds); - if (numLineFeeds > 0 && whitespaceRange.getStartOffset() != 0) { + final String text = addLineFeed ? "\n" : ""; + // Do not add extra blank line in empty file + if (!text.isEmpty() && whitespaceRange.getStartOffset() != 0) { if (!whitespaceRange.isEmpty()) { document.replaceString(whitespaceRange.getStartOffset(), whitespaceRange.getEndOffset(), text); } From 33ab0e9b251a15d25b4b9b12f69d783afc05dd2e Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 13 May 2015 17:54:58 +0300 Subject: [PATCH 03/28] PY-12360 EA-68345 First apply pending formatting and only then search for trailing blank lines --- .../PyTrailingBlankLinesPostFormatProcessor.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java b/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java index efc3dfbff996..db9ed9544658 100644 --- a/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java +++ b/python/src/com/jetbrains/python/formatter/PyTrailingBlankLinesPostFormatProcessor.java @@ -55,6 +55,7 @@ public class PyTrailingBlankLinesPostFormatProcessor implements PostFormatProces public PsiElement processElement(@NotNull PsiElement source, @NotNull CodeStyleSettings settings) { final PsiFile psiFile = source.getContainingFile(); if (isApplicableTo(psiFile)) { + applyPendingChangesToPsi(source); final TextRange whitespaceRange = findTrailingWhitespacesRange(psiFile); if (source.getTextRange().intersects(whitespaceRange)) { replaceOrDeleteTrailingWhitespaces(psiFile, whitespaceRange); @@ -68,6 +69,7 @@ public class PyTrailingBlankLinesPostFormatProcessor implements PostFormatProces if (!isApplicableTo(source)) { return rangeToReformat; } + applyPendingChangesToPsi(source); final TextRange oldWhitespaceRange = findTrailingWhitespacesRange(source); if (rangeToReformat.intersects(oldWhitespaceRange)) { final TextRange newWhitespaceRange = replaceOrDeleteTrailingWhitespaces(source, oldWhitespaceRange); @@ -91,6 +93,14 @@ public class PyTrailingBlankLinesPostFormatProcessor implements PostFormatProces return rangeToReformat; } + private static void applyPendingChangesToPsi(@NotNull PsiElement source) { + final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(source.getContainingFile().getProject()); + final Document document = documentManager.getDocument(source.getContainingFile()); + if (document != null) { + documentManager.doPostponedOperationsAndUnblockDocument(document); + } + } + @NotNull private static TextRange findTrailingWhitespacesRange(@NotNull PsiFile file) { final CharSequence contents = file.getViewProvider().getContents(); @@ -114,8 +124,6 @@ public class PyTrailingBlankLinesPostFormatProcessor implements PostFormatProces if (document != null) { final PyCodeStyleSettings customSettings = CodeStyleSettingsManager.getSettings(project).getCustomSettings(PyCodeStyleSettings.class); final boolean addLineFeed = customSettings.BLANK_LINE_AT_FILE_END || EditorSettingsExternalizable.getInstance().isEnsureNewLineAtEOF(); - // TODO: figure out why this line causes all changes made because of dict alignment to be reverted - documentManager.doPostponedOperationsAndUnblockDocument(document); try { final String text = addLineFeed ? "\n" : ""; // Do not add extra blank line in empty file From 3a2c670972845bd33bf220fed579669d8eb2cdc5 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 13 May 2015 18:38:37 +0300 Subject: [PATCH 04/28] PY-14962 Add tests for new dict formatting options --- python/testData/formatter/alignDictLiteralOnColon.py | 7 +++++++ .../formatter/alignDictLiteralOnColon_after.py | 7 +++++++ python/testData/formatter/alignDictLiteralOnValue.py | 7 +++++++ .../formatter/alignDictLiteralOnValue_after.py | 7 +++++++ .../com/jetbrains/python/PyFormatterTest.java | 12 ++++++++++++ 5 files changed, 40 insertions(+) create mode 100644 python/testData/formatter/alignDictLiteralOnColon.py create mode 100644 python/testData/formatter/alignDictLiteralOnColon_after.py create mode 100644 python/testData/formatter/alignDictLiteralOnValue.py create mode 100644 python/testData/formatter/alignDictLiteralOnValue_after.py diff --git a/python/testData/formatter/alignDictLiteralOnColon.py b/python/testData/formatter/alignDictLiteralOnColon.py new file mode 100644 index 000000000000..ec4809b888d3 --- /dev/null +++ b/python/testData/formatter/alignDictLiteralOnColon.py @@ -0,0 +1,7 @@ +{ + "a": 1, + "bbb": [ + 2 + ], + "bbbbb": 3 +} \ No newline at end of file diff --git a/python/testData/formatter/alignDictLiteralOnColon_after.py b/python/testData/formatter/alignDictLiteralOnColon_after.py new file mode 100644 index 000000000000..663d95a84b7c --- /dev/null +++ b/python/testData/formatter/alignDictLiteralOnColon_after.py @@ -0,0 +1,7 @@ +{ + "a" : 1, + "bbb" : [ + 2 + ], + "bbbbb": 3 +} diff --git a/python/testData/formatter/alignDictLiteralOnValue.py b/python/testData/formatter/alignDictLiteralOnValue.py new file mode 100644 index 000000000000..afe69120050c --- /dev/null +++ b/python/testData/formatter/alignDictLiteralOnValue.py @@ -0,0 +1,7 @@ +{ + "a": 1, + "bbb": [ + 2 + ], + "bbbbb": 3 +} diff --git a/python/testData/formatter/alignDictLiteralOnValue_after.py b/python/testData/formatter/alignDictLiteralOnValue_after.py new file mode 100644 index 000000000000..c333ffcc903f --- /dev/null +++ b/python/testData/formatter/alignDictLiteralOnValue_after.py @@ -0,0 +1,7 @@ +{ + "a": 1, + "bbb": [ + 2 + ], + "bbbbb": 3 +} diff --git a/python/testSrc/com/jetbrains/python/PyFormatterTest.java b/python/testSrc/com/jetbrains/python/PyFormatterTest.java index 02c62a2113c2..35a3283e6c80 100644 --- a/python/testSrc/com/jetbrains/python/PyFormatterTest.java +++ b/python/testSrc/com/jetbrains/python/PyFormatterTest.java @@ -567,6 +567,18 @@ public class PyFormatterTest extends PyTestCase { doTest(); } + // PY-14962 + public void testAlignDictLiteralOnValue() { + getCustomSettings().DICT_ALIGNMENT = PyCodeStyleSettings.DICT_ALIGNMENT_ON_VALUE; + doTest(); + } + + // PY-14962 + public void testAlignDictLiteralOnColon() { + getCustomSettings().DICT_ALIGNMENT = PyCodeStyleSettings.DICT_ALIGNMENT_ON_COLON; + doTest(); + } + // PY-15530 public void testAlignmentInArgumentListWhereFirstArgumentIsEmptyCall() { doTest(); From dd6a6e28ef70cfac169895d091ba04d5a89a70e2 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Thu, 14 May 2015 13:08:55 +0300 Subject: [PATCH 05/28] IDEA-140202 Code folding popup does not hide on scroll --- .../hint/DocumentFragmentTooltipRenderer.java | 2 +- .../hint/EditorFragmentComponent.java | 19 +++---------------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/DocumentFragmentTooltipRenderer.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/DocumentFragmentTooltipRenderer.java index e630db6d7f17..3e490d6e0dc3 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/DocumentFragmentTooltipRenderer.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/DocumentFragmentTooltipRenderer.java @@ -77,7 +77,7 @@ public class DocumentFragmentTooltipRenderer implements TooltipRenderer { FoldingModelEx foldingModel = (FoldingModelEx)editor.getFoldingModel(); foldingModel.setFoldingEnabled(false); TextRange textRange = new TextRange(startOffset, endOffset); - hint = EditorFragmentComponent.showEditorFragmentHintAt(editor, textRange, p.y, false, false, true); + hint = EditorFragmentComponent.showEditorFragmentHintAt(editor, textRange, p.y, false, false, true, true, true); foldingModel.setFoldingEnabled(true); return hint; } diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/EditorFragmentComponent.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/EditorFragmentComponent.java index 2d8be80bc861..aa1c18f4c71f 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/EditorFragmentComponent.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/EditorFragmentComponent.java @@ -150,21 +150,6 @@ public class EditorFragmentComponent extends JPanel { /** * @param y y coordinate in layered pane coordinate system. - * @param hideByAnyKey - */ - @Nullable - public static LightweightHint showEditorFragmentHintAt(Editor editor, - TextRange range, - int y, - boolean showUpward, - boolean showFolding, - boolean hideByAnyKey) { - return showEditorFragmentHintAt(editor, range, y, showUpward, showFolding, hideByAnyKey, true); - } - - /** - * @param y y coordinate in layered pane coordinate system. - * @param hideByAnyKey */ @Nullable public static LightweightHint showEditorFragmentHintAt(Editor editor, @@ -173,6 +158,7 @@ public class EditorFragmentComponent extends JPanel { boolean showUpward, boolean showFolding, boolean hideByAnyKey, + boolean hideByScrolling, boolean useCaretRowBackground) { if (ApplicationManager.getApplication().isUnitTestMode()) return null; Document document = editor.getDocument(); @@ -215,6 +201,7 @@ public class EditorFragmentComponent extends JPanel { Point p = new Point(x, y); LightweightHint hint = new MyComponentHint(fragmentComponent); HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, p, (hideByAnyKey ? HintManager.HIDE_BY_ANY_KEY : 0) | + (hideByScrolling ? HintManager.HIDE_BY_SCROLLING : 0) | HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_MOUSEOVER, 0, false, new HintHint(editor, p)); return hint; @@ -252,7 +239,7 @@ public class EditorFragmentComponent extends JPanel { if (rootPane == null) return null; JLayeredPane layeredPane = rootPane.getLayeredPane(); Point point = SwingUtilities.convertPoint(editorComponent, -2, 0, layeredPane); - return showEditorFragmentHintAt(editor, range, point.y, true, showFolding, hideByAnyKey, false); + return showEditorFragmentHintAt(editor, range, point.y, true, showFolding, hideByAnyKey, true, false); } public static Color getBackgroundColor(Editor editor){ From 875d9ffae19bec1e05c0ddc0c568ce94c1ea5443 Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Thu, 14 May 2015 13:50:31 +0300 Subject: [PATCH 06/28] add copy to multi map --- .../util/src/com/intellij/util/containers/MultiMap.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/util/src/com/intellij/util/containers/MultiMap.java b/platform/util/src/com/intellij/util/containers/MultiMap.java index f8af63cc7ba8..4bc55fd5cd5e 100644 --- a/platform/util/src/com/intellij/util/containers/MultiMap.java +++ b/platform/util/src/com/intellij/util/containers/MultiMap.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,6 +47,11 @@ public class MultiMap implements Serializable { putAllValues(toCopy); } + @NotNull + public MultiMap copy() { + return new MultiMap(this); + } + public MultiMap(int i, float v) { myMap = createMap(i, v); } From de931e1d0b05aac2c683e565a4b1dfbeea28f668 Mon Sep 17 00:00:00 2001 From: nik Date: Thu, 14 May 2015 13:57:10 +0300 Subject: [PATCH 07/28] IdeEventQueue fixed: KeyboardSettingsExternalizable application service may be not initialized yet --- platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java index bfd8fecc4441..f6a0b2d9e7fb 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java @@ -410,7 +410,8 @@ public class IdeEventQueue extends EventQueue { //private static boolean altGrIsPressed = false; private static AWTEvent fixNonEnglishKeyboardLayouts(AWTEvent e) { - if (!KeyboardSettingsExternalizable.getInstance().isNonEnglishKeyboardSupportEnabled()) return e; + KeyboardSettingsExternalizable externalizable = KeyboardSettingsExternalizable.getInstance(); + if (externalizable == null || !externalizable.isNonEnglishKeyboardSupportEnabled()) return e; if (e instanceof KeyEvent) { KeyEvent ke = (KeyEvent)e; From a33bdfdec7257a4c7101f9a713802749d6bc81ad Mon Sep 17 00:00:00 2001 From: nik Date: Thu, 14 May 2015 14:06:33 +0300 Subject: [PATCH 08/28] gradle tests: added JDK home to allowed roots --- .../importing/GradleImportingTestCase.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java index 6fe520e18ba4..9f4e34cf2eb7 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java @@ -82,20 +82,24 @@ public abstract class GradleImportingTestCase extends ExternalSystemImportingTes @org.junit.runners.Parameterized.Parameter(0) public String gradleVersion; private GradleProjectSettings myProjectSettings; + private String myJdkHome; @Override public void setUp() throws Exception { + myJdkHome = IdeaTestUtil.requireRealJdkHome(); super.setUp(); assumeThat(gradleVersion, versionMatcherRule.getMatcher()); - final String jdkHome = IdeaTestUtil.requireRealJdkHome(); - assertNull("JDK " + GRADLE_JDK_NAME + " already exists", ProjectJdkTable.getInstance().findJdk(GRADLE_JDK_NAME)); new WriteAction() { @Override protected void run(@NotNull Result result) throws Throwable { - VirtualFile jdkHomeDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(jdkHome)); + Sdk oldJdk = ProjectJdkTable.getInstance().findJdk(GRADLE_JDK_NAME); + if (oldJdk != null) { + ProjectJdkTable.getInstance().removeJdk(oldJdk); + } + VirtualFile jdkHomeDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(myJdkHome)); Sdk jdk = SdkConfigurationUtil.setupSdk(new Sdk[0], jdkHomeDir, JavaSdk.getInstance(), true, null, GRADLE_JDK_NAME); - assertNotNull("Cannot create JDK for " + jdkHome, jdk); - SdkConfigurationUtil.addSdk(jdk); + assertNotNull("Cannot create JDK for " + myJdkHome, jdk); + ProjectJdkTable.getInstance().addJdk(jdk); } }.execute(); myProjectSettings = new GradleProjectSettings(); @@ -126,11 +130,7 @@ public abstract class GradleImportingTestCase extends ExternalSystemImportingTes @Override protected void collectAllowedRoots(List roots) throws IOException { - final String javaHome = System.getenv("JAVA_HOME"); - if (javaHome != null) { - roots.add(javaHome); - } - + roots.add(myJdkHome); roots.add(PathManager.getOptionsPath()); } From 8374d6a5407e4b8fc6ab0b3dcb9987c99fc2e993 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 14 May 2015 14:17:14 +0300 Subject: [PATCH 09/28] clarify javadoc --- .../src/com/intellij/vcs/log/data/SingleTaskController.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java index 7d535982cfd0..8d3e0d3fd9bf 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java @@ -23,10 +23,10 @@ import org.jetbrains.annotations.Nullable; import java.util.List; /** - * Collects incoming requests into a list, and provides them to an underlying background task via {@link #popRequests()}.
+ * Collects incoming requests into a list, and provides them to the underlying background task via {@link #popRequests()}.
* Such task is started immediately after the first request arrives, if no other task is currently running.
- * A task indicates its completion by calling {@link #taskCompleted(Object)} and providing a result which is immediately passed to the - * result handler. + * A task reports its completion by calling {@link #taskCompleted(Object)} and providing a result which is immediately passed to the + * result handler (unless it is null in which case the task is stopped but the result is not passed to the handler). *

* The purpose of this class is to provide a single thread, which processes incoming requests in the background and continues to process * new ones if they arrive while the previous ones were processed. An alternative would be a long living thread which always checks some From 1bcff41926215d879226a9813ea458c3431d907a Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Thu, 14 May 2015 15:13:52 +0300 Subject: [PATCH 10/28] [PsiBasedFormattingModel] Perform whitespace modification with disabled automatic formatting of changed psi elements. Changed whitespace would not be formatted twice, which will prevent from reformatting whitespaces of aligned blocks and producing inconsistent result --- .../formatter/PsiBasedFormattingModel.java | 27 ++++++++++++++----- .../alignDictLiteralOnValue_after.py | 4 +-- ...tDestroyAlignment_OnPostponedFormatting.py | 4 +++ ...oyAlignment_OnPostponedFormatting_after.py | 4 +++ .../com/jetbrains/python/PyFormatterTest.java | 5 ++++ 5 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 python/testData/formatter/doNotDestroyAlignment_OnPostponedFormatting.py create mode 100644 python/testData/formatter/doNotDestroyAlignment_OnPostponedFormatting_after.py diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/PsiBasedFormattingModel.java b/platform/lang-impl/src/com/intellij/psi/formatter/PsiBasedFormattingModel.java index 3712158a6b4c..e2a0958c4e2a 100644 --- a/platform/lang-impl/src/com/intellij/psi/formatter/PsiBasedFormattingModel.java +++ b/platform/lang-impl/src/com/intellij/psi/formatter/PsiBasedFormattingModel.java @@ -27,6 +27,7 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.TokenType; +import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import org.jetbrains.annotations.NotNull; @@ -36,18 +37,19 @@ public class PsiBasedFormattingModel implements FormattingModelEx { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.formatter.PsiBasedFormattingModel"); + private final Project myProject; private final ASTNode myASTNode; private final FormattingDocumentModelImpl myDocumentModel; @NotNull private final Block myRootBlock; protected boolean myCanModifyAllWhiteSpaces = false; - + public PsiBasedFormattingModel(final PsiFile file, @NotNull final Block rootBlock, final FormattingDocumentModelImpl documentModel) { myASTNode = SourceTreeToPsiMap.psiElementToTree(file); myDocumentModel = documentModel; myRootBlock = rootBlock; - + myProject = file.getProject(); } @@ -81,7 +83,7 @@ public class PsiBasedFormattingModel implements FormattingModelEx { @Nullable - private String replaceWithPSI(final TextRange textRange, String whiteSpace) { + private String replaceWithPSI(final TextRange textRange, final String whiteSpace) { final int offset = textRange.getEndOffset(); ASTNode leafElement = findElementAt(offset); @@ -101,7 +103,14 @@ public class PsiBasedFormattingModel implements FormattingModelEx { return replaceWithPsiInLeaf(textRange, whiteSpace, leafElement); } } else if (textRange.getEndOffset() == myASTNode.getTextLength()){ - FormatterUtil.replaceLastWhiteSpace(myASTNode, whiteSpace, textRange); + + CodeStyleManager.getInstance(myProject).performActionWithFormatterDisabled(new Runnable() { + @Override + public void run() { + FormatterUtil.replaceLastWhiteSpace(myASTNode, whiteSpace, textRange); + } + }); + return whiteSpace; } else { return null; @@ -109,12 +118,18 @@ public class PsiBasedFormattingModel implements FormattingModelEx { } @Nullable - protected String replaceWithPsiInLeaf(final TextRange textRange, String whiteSpace, ASTNode leafElement) { + protected String replaceWithPsiInLeaf(final TextRange textRange, final String whiteSpace, final ASTNode leafElement) { if (!myCanModifyAllWhiteSpaces) { if (leafElement.getElementType() == TokenType.WHITE_SPACE) return null; } - FormatterUtil.replaceWhiteSpace(whiteSpace, leafElement, TokenType.WHITE_SPACE, textRange); + CodeStyleManager.getInstance(myProject).performActionWithFormatterDisabled(new Runnable() { + @Override + public void run() { + FormatterUtil.replaceWhiteSpace(whiteSpace, leafElement, TokenType.WHITE_SPACE, textRange); + } + }); + return whiteSpace; } diff --git a/python/testData/formatter/alignDictLiteralOnValue_after.py b/python/testData/formatter/alignDictLiteralOnValue_after.py index c333ffcc903f..13881b918e21 100644 --- a/python/testData/formatter/alignDictLiteralOnValue_after.py +++ b/python/testData/formatter/alignDictLiteralOnValue_after.py @@ -1,6 +1,6 @@ { - "a": 1, - "bbb": [ + "a": 1, + "bbb": [ 2 ], "bbbbb": 3 diff --git a/python/testData/formatter/doNotDestroyAlignment_OnPostponedFormatting.py b/python/testData/formatter/doNotDestroyAlignment_OnPostponedFormatting.py new file mode 100644 index 000000000000..a0486c9a8d5e --- /dev/null +++ b/python/testData/formatter/doNotDestroyAlignment_OnPostponedFormatting.py @@ -0,0 +1,4 @@ +{ + "aaaaa": 1, + "bbb aaaaaaa": 2 +} \ No newline at end of file diff --git a/python/testData/formatter/doNotDestroyAlignment_OnPostponedFormatting_after.py b/python/testData/formatter/doNotDestroyAlignment_OnPostponedFormatting_after.py new file mode 100644 index 000000000000..e04ac0be0bc5 --- /dev/null +++ b/python/testData/formatter/doNotDestroyAlignment_OnPostponedFormatting_after.py @@ -0,0 +1,4 @@ +{ + "aaaaa" : 1, + "bbb aaaaaaa": 2 +} diff --git a/python/testSrc/com/jetbrains/python/PyFormatterTest.java b/python/testSrc/com/jetbrains/python/PyFormatterTest.java index 35a3283e6c80..605a8b5f83da 100644 --- a/python/testSrc/com/jetbrains/python/PyFormatterTest.java +++ b/python/testSrc/com/jetbrains/python/PyFormatterTest.java @@ -601,6 +601,11 @@ public class PyFormatterTest extends PyTestCase { doTest(); } + public void testDoNotDestroyAlignment_OnPostponedFormatting() throws Exception { + getCustomSettings().DICT_ALIGNMENT = PyCodeStyleSettings.DICT_ALIGNMENT_ON_COLON; + doTest(); + } + public void testAlignmentOfEmptyCollectionLiterals() { doTest(); } From ba3384da68458d6f7047a089e79213c36e73a256 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Thu, 14 May 2015 14:11:38 +0200 Subject: [PATCH 11/28] make keymap generator add action description --- .../com/intellij/help/impl/KeymapGenerator.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/help/impl/KeymapGenerator.java b/platform/platform-impl/src/com/intellij/help/impl/KeymapGenerator.java index f38ef84a2b93..6f2bfccea08f 100644 --- a/platform/platform-impl/src/com/intellij/help/impl/KeymapGenerator.java +++ b/platform/platform-impl/src/com/intellij/help/impl/KeymapGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ */ package com.intellij.help.impl; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.Shortcut; import com.intellij.openapi.application.ApplicationStarter; import com.intellij.openapi.application.PathManager; @@ -45,15 +47,17 @@ public class KeymapGenerator implements ApplicationStarter { @Override public void main(String[] args) { + ActionManager actionManager = ActionManager.getInstance(); StringBuilder xml = new StringBuilder(); xml.append("\n"); for (Keymap keymap : KeymapManagerEx.getInstanceEx().getAllKeymaps()) { - + xml.append(" \n"); for (String id : keymap.getActionIds()) { String shortcuts = KeymapUtil.getShortcutsText(keymap.getShortcuts(id)); if (!StringUtil.isEmpty(shortcuts)) { + AnAction action = actionManager.getAction(id); xml.append(" \n"); Set addedShortcuts = new THashSet(); for (Shortcut shortcut : keymap.getShortcuts(id)) { @@ -64,6 +68,12 @@ public class KeymapGenerator implements ApplicationStarter { xml.append(" ").append(shortcutText).append("\n"); } } + if (action != null) { + String text = action.getTemplatePresentation().getText(); + if (text != null) { + xml.append(" ").append(StringUtil.escapeXml(text)).append("\n"); + } + } xml.append(" \n"); } } From b82e47cf54592f81de8478b948ed655e92dd9ac4 Mon Sep 17 00:00:00 2001 From: Denis Fokin Date: Thu, 14 May 2015 16:34:15 +0400 Subject: [PATCH 12/28] Warning cleanup --- .../com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java index 19dfd08e3c57..b1da26956ac4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutTextField.java @@ -26,13 +26,14 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.KeyStrokeAdapter; import javax.swing.*; +import java.awt.*; import java.awt.event.KeyEvent; public class ShortcutTextField extends JTextField { private KeyStroke myKeyStroke; public ShortcutTextField() { - enableEvents(KeyEvent.KEY_EVENT_MASK); + enableEvents(AWTEvent.KEY_EVENT_MASK); setFocusTraversalKeysEnabled(false); } From 9d0dd23b8cd098f959577ba303cb319f654af384 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Thu, 14 May 2015 13:55:46 +0300 Subject: [PATCH 13/28] weaken visibility and notnull --- .../editor/impl/PersistentRangeMarker.java | 4 ++- .../openapi/editor/impl/RangeMarkerTree.java | 27 ++++++++++--------- .../openapi/editor/impl/RedBlackTree.java | 11 ++++---- .../openapi/util/UserDataHolderBase.java | 9 ++++--- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java index 59c124698166..915bd1723883 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarker.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ package com.intellij.openapi.editor.impl; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.editor.impl.event.DocumentEventImpl; @@ -43,6 +44,7 @@ class PersistentRangeMarker extends RangeMarkerImpl { private void storeLinesAndCols(DocumentEvent e) { // document might have been changed already int startOffset = getStartOffset(); + Document myDocument = getDocument(); if (startOffset <= myDocument.getTextLength()) { myStartLine = myDocument.getLineNumber(startOffset); myStartColumn = startOffset - myDocument.getLineStartOffset(myStartLine); diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java index 5df198263512..d27218eefbcf 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerTree.java @@ -29,6 +29,7 @@ import com.intellij.openapi.util.Segment; import com.intellij.util.Processor; import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; @@ -88,16 +89,16 @@ public class RangeMarkerTree extends IntervalTreeImpl addInterval(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { - RangeMarkerImpl marker = (RangeMarkerImpl)interval; - marker.setValid(true); - RMNode node = (RMNode)super.addInterval(interval, start, end, greedyToLeft, greedyToRight, layer); + interval.setValid(true); + RMNode node = (RMNode)super.addInterval(interval, start, end, greedyToLeft, greedyToRight, layer); if (DEBUG && !ApplicationInfoImpl.isInPerformanceTest() && node.intervals.size() > DUPLICATE_LIMIT) { l.readLock().lock(); @@ -136,18 +137,20 @@ public class RangeMarkerTree extends IntervalTreeImpl lookupNode(@NotNull T key) { + //noinspection unchecked return (RMNode)((RangeMarkerImpl)key).myNode; } @Override protected void setNode(@NotNull T key, IntervalNode intervalNode) { + //noinspection unchecked ((RangeMarkerImpl)key).myNode = (RMNode)intervalNode; } @@ -166,11 +169,11 @@ public class RangeMarkerTree extends IntervalTreeImpl extends IntervalTreeImpl root, + private boolean collectAffectedMarkersAndShiftSubtrees(@Nullable IntervalNode root, @NotNull DocumentEvent e, @NotNull List> affected) { if (root == null) return true; @@ -303,7 +306,7 @@ public class RangeMarkerTree extends IntervalTreeImpl sweepProcessor) { + public boolean sweep(final int start, final int end, @NotNull SweepProcessor sweepProcessor) { return sweep(new Generator() { @Override public boolean generateInStartOffsetOrder(@NotNull Processor processor) { @@ -319,7 +322,7 @@ public class RangeMarkerTree extends IntervalTreeImpl boolean sweep(@NotNull Generator generator, @NotNull final SweepProcessor sweepProcessor) { final Queue ends = new PriorityQueue(5, new Comparator() { @Override - public int compare(T o1, T o2) { + public int compare(@NotNull T o1, @NotNull T o2) { return o1.getEndOffset() - o2.getEndOffset(); } }); @@ -391,7 +394,7 @@ public class RangeMarkerTree extends IntervalTreeImpl root, + private void collectNodesToRetarget(@Nullable IntervalNode root, int start, int end, @NotNull List> affected) { if (root == null) return; diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/RedBlackTree.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/RedBlackTree.java index 41197feb5e74..6e1ab7fe6a15 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/RedBlackTree.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/RedBlackTree.java @@ -36,7 +36,7 @@ public abstract class RedBlackTree { verifyProperties(); } - protected void rotateLeft(Node n) { + protected void rotateLeft(@NotNull Node n) { Node r = n.getRight(); replaceNode(n, r); n.setRight(r.getLeft()); @@ -47,7 +47,7 @@ public abstract class RedBlackTree { n.setParent(r); } - protected void rotateRight(Node n) { + protected void rotateRight(@NotNull Node n) { Node l = n.getLeft(); replaceNode(n, l); n.setLeft(l.getRight()); @@ -177,10 +177,11 @@ public abstract class RedBlackTree { verifyProperties(); } - protected abstract Node swapWithMaxPred(Node nowAscendant, Node nowDescendant); + @NotNull + protected abstract Node swapWithMaxPred(@NotNull Node nowAscendant, @NotNull Node nowDescendant); - protected Node maximumNode(Node n) { - assert n != null; + @NotNull + protected Node maximumNode(@NotNull Node n) { while (n.getRight() != null) { n = n.getRight(); } diff --git a/platform/util/src/com/intellij/openapi/util/UserDataHolderBase.java b/platform/util/src/com/intellij/openapi/util/UserDataHolderBase.java index c365be8b33aa..983c8012e4dd 100644 --- a/platform/util/src/com/intellij/openapi/util/UserDataHolderBase.java +++ b/platform/util/src/com/intellij/openapi/util/UserDataHolderBase.java @@ -23,12 +23,13 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; public class UserDataHolderBase implements UserDataHolderEx, Cloneable { - public static final Key COPYABLE_USER_MAP_KEY = Key.create("COPYABLE_USER_MAP_KEY"); + private static final Key COPYABLE_USER_MAP_KEY = Key.create("COPYABLE_USER_MAP_KEY"); /** * Concurrent writes to this field are via CASes only, using the {@link #updater} */ - @NotNull private volatile KeyFMap myUserMap = KeyFMap.EMPTY_MAP; + @NotNull + private volatile KeyFMap myUserMap = KeyFMap.EMPTY_MAP; @Override protected Object clone() { @@ -47,10 +48,10 @@ public class UserDataHolderBase implements UserDataHolderEx, Cloneable { public String getUserDataString() { final KeyFMap userMap = getUserMap(); final KeyFMap copyableMap = getUserData(COPYABLE_USER_MAP_KEY); - return userMap.toString() + (copyableMap == null ? "" : copyableMap.toString()); + return userMap + (copyableMap == null ? "" : copyableMap.toString()); } - public void copyUserDataTo(UserDataHolderBase other) { + public void copyUserDataTo(@NotNull UserDataHolderBase other) { other.setUserMap(getUserMap()); } From 5b472944bf6aeb3dcba86e4bffd72a46ee6f495f Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Thu, 14 May 2015 13:56:18 +0300 Subject: [PATCH 14/28] assertion for creating range markers from within beforeRemoved --- .../openapi/editor/impl/IntervalTreeImpl.java | 139 +++++++++++------- .../openapi/editor/impl/RangeMarkerImpl.java | 10 +- .../editor/impl/RangeHighlighterTree.java | 6 +- 3 files changed, 92 insertions(+), 63 deletions(-) diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java index ed1c71dd095f..d48d6f6be400 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java @@ -25,6 +25,7 @@ import com.intellij.util.concurrency.AtomicFieldUpdater; import gnu.trove.TLongHashSet; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; @@ -42,7 +43,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; */ abstract class IntervalTreeImpl extends RedBlackTree implements IntervalTree { private int keySize; // number of all intervals, counting all duplicates, some of them maybe gced - protected final ReadWriteLock l = new ReentrantReadWriteLock(); + final ReadWriteLock l = new ReentrantReadWriteLock(); protected abstract int compareEqualStartIntervals(@NotNull IntervalNode i1, @NotNull IntervalNode i2); private final ReferenceQueue myReferenceQueue = new ReferenceQueue(); @@ -52,9 +53,9 @@ abstract class IntervalTreeImpl extends RedBlackTree< private volatile int myStart; private volatile int myEnd; private static final byte ATTACHED_TO_TREE_FLAG = COLOR_MASK <<1; // true if the node is inserted to the tree - protected final List> intervals; + final List> intervals; int maxEnd; // max of all intervalEnd()s among all children. - protected int delta; // delta of startOffset. getStartOffset() = myStartOffset + Sum of deltas up to root + int delta; // delta of startOffset. getStartOffset() = myStartOffset + Sum of deltas up to root private volatile long cachedDeltaUpToRoot; // field (packed to long for atomicity) containing deltaUpToRoot, node modCount and allDeltasUpAreNull flag // fields are packed as following @@ -62,6 +63,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< // private int deltaUpToRoot; // sum of all deltas up to the root (including this node' delta). Has valid value only if modCount == IntervalTreeImpl.this.modCount // private boolean allDeltasUpAreNull; // true if all deltas up the tree (including this node) are 0. Has valid value only if modCount == IntervalTreeImpl.this.modCount + @NotNull private final IntervalTreeImpl myIntervalTree; public IntervalNode(@NotNull IntervalTreeImpl intervalTree, @NotNull E key, int start, int end) { @@ -170,7 +172,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } private static class WeakReferencedGetter extends WeakReference implements Getter { - private WeakReferencedGetter(T referent, ReferenceQueue q) { + private WeakReferencedGetter(@NotNull T referent, @NotNull ReferenceQueue q) { super(referent, q); } @@ -290,6 +292,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return myEnd; } + @NotNull public IntervalTreeImpl getTree() { return myIntervalTree; } @@ -373,12 +376,12 @@ abstract class IntervalTreeImpl extends RedBlackTree< private void assertUnderWriteLock() { assert isAcquired(l.writeLock()) : l.writeLock(); } - private static boolean isAcquired(Lock l) { + private static boolean isAcquired(@NotNull Lock l) { String s = l.toString(); return s.contains("Locked by thread"); } - private void pushDeltaFromRoot(IntervalNode node) { + private void pushDeltaFromRoot(@Nullable IntervalNode node) { if (node != null) { long packedOffsets = node.cachedDeltaUpToRoot; if (IntervalNode.allDeltasUpAreNull(packedOffsets) && node.isValid() && IntervalNode.modCount(packedOffsets) == modCount) return; @@ -390,7 +393,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< @NotNull protected abstract IntervalNode createNewNode(@NotNull T key, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer); protected abstract IntervalNode lookupNode(@NotNull T key); - protected abstract void setNode(@NotNull T key, IntervalNode node); + protected abstract void setNode(@NotNull T key, @Nullable IntervalNode node); private int compareNodes(@NotNull IntervalNode i1, int delta1, @NotNull IntervalNode i2, int delta2, @NotNull List> invalid) { if (!i2.hasAliveKey(false)) { @@ -411,14 +414,16 @@ abstract class IntervalTreeImpl extends RedBlackTree< try { l.readLock().lock(); checkMax(true); - return process(getRoot(), processor, modCount); + return process(getRoot(), modCount, processor); } finally { l.readLock().unlock(); } } - private boolean process(final IntervalNode root, final Processor processor, final int modCountBefore) { + private boolean process(@Nullable IntervalNode root, + final int modCountBefore, + @NotNull final Processor processor) { if (root == null) return true; WalkingState.TreeGuide> guide = getGuide(); @@ -437,19 +442,19 @@ abstract class IntervalTreeImpl extends RedBlackTree< try { l.readLock().lock(); checkMax(true); - return processOverlappingWith(getRoot(), start, end, processor, modCount, 0); + return processOverlappingWith(getRoot(), start, end, modCount, 0, processor); } finally { l.readLock().unlock(); } } - private boolean processOverlappingWith(IntervalNode root, + private boolean processOverlappingWith(@Nullable IntervalNode root, int start, int end, - Processor processor, int modCountBefore, - int deltaUpToRootExclusive) { + int deltaUpToRootExclusive, + @NotNull Processor processor) { if (root == null) { return true; } @@ -460,7 +465,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return true; // right of the rightmost interval in the subtree } - if (!processOverlappingWith(root.getLeft(), start, end, processor, modCountBefore, delta)) return false; + if (!processOverlappingWith(root.getLeft(), start, end, modCountBefore, delta, processor)) return false; int myStartOffset = root.intervalStart() + delta; int myEndOffset = root.intervalEnd() + delta; boolean overlaps = Math.max(myStartOffset, start) <= Math.min(myEndOffset, end); @@ -473,25 +478,25 @@ abstract class IntervalTreeImpl extends RedBlackTree< return true; // left of the root, cant be in the right subtree } - return processOverlappingWith(root.getRight(), start, end, processor, modCountBefore, delta); + return processOverlappingWith(root.getRight(), start, end, modCountBefore, delta, processor); } boolean processOverlappingWithOutside(int start, int end, @NotNull Processor processor) { try { l.readLock().lock(); checkMax(true); - return processOverlappingWithOutside(getRoot(), start, end, processor, modCount, 0); + return processOverlappingWithOutside(getRoot(), start, end, modCount, 0, processor); } finally { l.readLock().unlock(); } } - private boolean processOverlappingWithOutside(IntervalNode root, + private boolean processOverlappingWithOutside(@Nullable IntervalNode root, int start, int end, - @NotNull Processor processor, int modCountBefore, - int deltaUpToRootExclusive) { + int deltaUpToRootExclusive, + @NotNull Processor processor) { if (root == null) { return true; } @@ -502,7 +507,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< int rootStartOffset = root.intervalStart() + delta; int rootEndOffset = root.intervalEnd() + delta; - if (!processOverlappingWithOutside(root.getLeft(), start, end, processor, modCountBefore, delta)) return false; + if (!processOverlappingWithOutside(root.getLeft(), start, end, modCountBefore, delta, processor)) return false; boolean toProcess = rootStartOffset < start || rootEndOffset > end; if (toProcess) { @@ -512,7 +517,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< if (rootStartOffset >= start && rootMaxEnd <= end) return true; // cant intersect outside - return processOverlappingWithOutside(root.getRight(), start, end, processor, modCountBefore, delta); + return processOverlappingWithOutside(root.getRight(), start, end, modCountBefore, delta, processor); } @@ -521,17 +526,17 @@ abstract class IntervalTreeImpl extends RedBlackTree< try { l.readLock().lock(); checkMax(true); - return processContaining(getRoot(), offset, processor, modCount, 0); + return processContaining(getRoot(), offset, modCount, 0, processor); } finally { l.readLock().unlock(); } } - private boolean processContaining(IntervalNode root, + private boolean processContaining(@Nullable IntervalNode root, int offset, - Processor processor, int modCountBefore, - int deltaUpToRootExclusive) { + int deltaUpToRootExclusive, + @NotNull Processor processor) { if (root == null) { return true; } @@ -541,7 +546,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return true; // right of the rightmost interval in the subtree } - if (!processContaining(root.getLeft(), offset, processor, modCountBefore, delta)) return false; + if (!processContaining(root.getLeft(), offset, modCountBefore, delta, processor)) return false; int myStartOffset = root.intervalStart() + delta; int myEndOffset = root.intervalEnd() + delta; boolean overlaps = myStartOffset <= offset && offset < myEndOffset; @@ -555,7 +560,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return true; // left of the root, cant be in the right subtree } - return processContaining(root.getRight(), offset, processor, modCountBefore, delta); + return processContaining(root.getRight(), offset, modCountBefore, delta, processor); } interface PeekableIterator extends DisposableIterator { @@ -608,7 +613,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return new PeekableIterator() { private IntervalNode currentNode = firstOverlap; private int deltaUpToRootExclusive = firstOverlapDelta-firstOverlap.delta; - private int indexInCurrentList = 0; + private int indexInCurrentList; private T current; @Override @@ -717,7 +722,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } } - private boolean overlaps(IntervalNode root, @NotNull TextRangeInterval rangeInterval, int deltaUpToRootExclusive) { + private boolean overlaps(@Nullable IntervalNode root, @NotNull TextRangeInterval rangeInterval, int deltaUpToRootExclusive) { if (root == null) return false; int delta = root.delta + deltaUpToRootExclusive; int start = root.intervalStart() + delta; @@ -725,6 +730,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return rangeInterval.intersects(start, end); } + @NotNull IntervalNode findOrInsert(@NotNull IntervalNode node) { assertUnderWriteLock(); node.setRed(); @@ -789,7 +795,11 @@ abstract class IntervalTreeImpl extends RedBlackTree< } } + @NotNull public IntervalTreeImpl.IntervalNode addInterval(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { + if (firingBeforeRemove) { + throw new IncorrectOperationException("Must not add rangemarker from within beforeRemoved listener"); + } try { l.writeLock().lock(); checkMax(true); @@ -852,13 +862,13 @@ abstract class IntervalTreeImpl extends RedBlackTree< } // returns real (minStart, maxStart, maxEnd) - private IntTrinity checkMax(IntervalNode root, + private IntTrinity checkMax(@Nullable IntervalNode root, int deltaUpToRootExclusive, boolean assertInvalid, - AtomicBoolean allValid, - int[] keyCounter, - int[] nodeCounter, - TLongHashSet ids, + @NotNull AtomicBoolean allValid, + @NotNull int[] keyCounter, + @NotNull int[] nodeCounter, + @NotNull TLongHashSet ids, boolean allDeltasUpAreNull) { if (root == null) return new IntTrinity(Integer.MAX_VALUE,Integer.MIN_VALUE,Integer.MIN_VALUE); long packedOffsets = root.cachedDeltaUpToRoot; @@ -914,8 +924,9 @@ abstract class IntervalTreeImpl extends RedBlackTree< return new IntTrinity(minStart, maxStart, root.maxEnd + delta); } + @NotNull @Override - protected Node maximumNode(Node n) { + protected Node maximumNode(@NotNull Node n) { IntervalNode root = (IntervalNode)n; pushDelta(root.getParent()); pushDelta(root); @@ -926,7 +937,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return root; } - protected void checkBelongsToTheTree(T interval, boolean assertInvalid) { + protected void checkBelongsToTheTree(@NotNull T interval, boolean assertInvalid) { IntervalNode root = lookupNode(interval); if (root == null) return; assert root.getTree() == this : root.getTree() +"; this: "+this; @@ -966,7 +977,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< IntervalNode node = lookupNode(interval); if (node == null) return false; - reportInvalidation(interval, "Explicit Dispose"); + beforeRemove(interval, "Explicit Dispose"); node.removeInterval(interval); setNode(interval, null); @@ -1005,7 +1016,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } // returns true if all deltas involved are still 0 - boolean pushDelta(IntervalNode root) { + boolean pushDelta(@Nullable IntervalNode root) { if (root == null || !root.isValid()) return true; IntervalNode parent = root.getParent(); assertAllDeltasAreNull(parent); @@ -1026,7 +1037,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } // returns true if all deltas involved are still 0 - private boolean incDelta(IntervalNode root, int delta) { + private boolean incDelta(@Nullable IntervalNode root, int delta) { if (root == null) return true; if (root.isValid()) { int newDelta = root.changeDelta(delta); @@ -1041,7 +1052,8 @@ abstract class IntervalTreeImpl extends RedBlackTree< } @Override - protected IntervalNode swapWithMaxPred(Node root, Node maxPred) { + @NotNull + protected IntervalNode swapWithMaxPred(@NotNull Node root, @NotNull Node maxPred) { checkMax(false); IntervalNode a = (IntervalNode)root; IntervalNode d = (IntervalNode)maxPred; @@ -1068,7 +1080,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< assert d.delta == 0 : d.delta; return a; } - private void swapNodes(IntervalNode n1, IntervalNode n2) { + private void swapNodes(@NotNull IntervalNode n1, @NotNull IntervalNode n2) { IntervalNode l1 = n1.getLeft(); IntervalNode r1 = n1.getRight(); IntervalNode p1 = n1.getParent(); @@ -1102,7 +1114,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } // returns real max endOffset of all intervals below - private int maxEndOf(IntervalNode node, int deltaUpToRootExclusive) { + private int maxEndOf(@Nullable IntervalNode node, int deltaUpToRootExclusive) { if (node == null) { return 0; } @@ -1121,7 +1133,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< node.maxEnd = realMax - deltaUpToRoot; } - private void correctMaxUp(IntervalNode node) { + private void correctMaxUp(@Nullable IntervalNode node) { int delta = node == null ? 0 : node.computeDeltaUpToRoot(); assert delta == 0 : delta; while (node != null) { @@ -1136,7 +1148,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } @Override - protected void rotateRight(Node n) { + protected void rotateRight(@NotNull Node n) { checkMax(false); IntervalNode node1 = (IntervalNode)n; IntervalNode node2 = node1.getLeft(); @@ -1162,7 +1174,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } @Override - protected void rotateLeft(Node n) { + protected void rotateLeft(@NotNull Node n) { checkMax(false); IntervalNode node1 = (IntervalNode)n; IntervalNode node2 = node1.getLeft(); @@ -1201,7 +1213,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } } - private void assertAllDeltasAreNull(IntervalNode node) { + private void assertAllDeltasAreNull(@Nullable IntervalNode node) { if (node == null) return; if (!node.isValid()) return; assert node.delta == 0; @@ -1209,7 +1221,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< assert IntervalNode.modCount(packedOffsets) != modCount || IntervalNode.allDeltasUpAreNull(packedOffsets); } - private IntervalNode findMinOverlappingWith(IntervalNode root, Interval interval, int modCountBefore, int deltaUpToRootExclusive) { + private IntervalNode findMinOverlappingWith(@Nullable IntervalNode root, @NotNull Interval interval, int modCountBefore, int deltaUpToRootExclusive) { if (root == null) { return null; } @@ -1235,7 +1247,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return findMinOverlappingWith(root.getRight(), interval, modCountBefore, delta); } - void changeData(T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { + void changeData(@NotNull T interval, int start, int end, boolean greedyToLeft, boolean greedyToRight, int layer) { try { l.writeLock().lock(); @@ -1284,14 +1296,14 @@ abstract class IntervalTreeImpl extends RedBlackTree< @Override public void clear() { + l.writeLock().lock(); process(new Processor() { @Override public boolean process(T t) { - reportInvalidation(t, "Clear all"); + beforeRemove(t, "Clear all"); return true; } }); - l.writeLock().lock(); try { super.clear(); keySize = 0; @@ -1301,23 +1313,39 @@ abstract class IntervalTreeImpl extends RedBlackTree< } } - private void collectGced(IntervalNode root, List> gced) { + private void collectGced(@Nullable IntervalNode root, @NotNull List> gced) { if (root == null) return; - if (!root.hasAliveKey(true)) gced.add(root); + if (!root.hasAliveKey(true)) { + gced.add(root); + } collectGced(root.getLeft(), gced); collectGced(root.getRight(), gced); } private void printSorted() { printSorted(getRoot());} - private void printSorted(IntervalNode root) { + private void printSorted(@Nullable IntervalNode root) { if (root == null) return; printSorted(root.getLeft()); System.out.println(root); printSorted(root.getRight()); } - void reportInvalidation(T markerEx, @NonNls Object reason) { + void fireBeforeRemoved(@NotNull T markerEx, @NotNull @NonNls Object reason) { + } + + private boolean firingBeforeRemove; // accessed under l.writeLock() only + void beforeRemove(@NotNull T markerEx, @NonNls @NotNull Object reason) { + if (firingBeforeRemove) { + throw new IllegalStateException(); + } + firingBeforeRemove = true; + try { + fireBeforeRemoved(markerEx, reason); + } + finally { + firingBeforeRemove = false; + } } private static class IntervalTreeGuide implements WalkingState.TreeGuide> { @@ -1348,6 +1376,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< } private static final IntervalTreeGuide INTERVAL_TREE_GUIDE_INSTANCE = new IntervalTreeGuide(); + @NotNull private static WalkingState.TreeGuide> getGuide() { //noinspection unchecked return (WalkingState.TreeGuide)INTERVAL_TREE_GUIDE_INSTANCE; @@ -1358,7 +1387,7 @@ abstract class IntervalTreeImpl extends RedBlackTree< return maxHeight(root); } - private int maxHeight(Node root) { + private int maxHeight(@Nullable Node root) { return root == null ? 0 : 1 + Math.max(maxHeight(root.left), maxHeight(root.right)); } diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java index 8e3cdcdd8567..e4d4199b3de8 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/RangeMarkerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,8 +27,8 @@ import org.jetbrains.annotations.NotNull; public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx, MutableInterval { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.RangeMarkerImpl"); - protected final DocumentEx myDocument; - protected RangeMarkerTree.RMNode myNode; + private final DocumentEx myDocument; + RangeMarkerTree.RMNode myNode; private final long myId; private static final StripedIDGenerator counter = new StripedIDGenerator(); @@ -89,7 +89,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx return intervalEnd() + (node == null ? 0 : node.computeDeltaUpToRoot()); } - public void invalidate(@NotNull final Object reason) { + void invalidate(@NotNull final Object reason) { setValid(false); RangeMarkerTree.RMNode node = myNode; @@ -97,7 +97,7 @@ public class RangeMarkerImpl extends UserDataHolderBase implements RangeMarkerEx node.processAliveKeys(new Processor() { @Override public boolean process(RangeMarkerEx markerEx) { - myNode.getTree().reportInvalidation(markerEx, reason); + myNode.getTree().beforeRemove(markerEx, reason); return true; } }); diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/RangeHighlighterTree.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/RangeHighlighterTree.java index 3b9dd10ff0ba..c9659764e2c8 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/RangeHighlighterTree.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/RangeHighlighterTree.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -66,13 +66,13 @@ public class RangeHighlighterTree extends RangeMarkerTree { //range highlighters are strongly referenced @Override protected Getter createGetter(@NotNull RangeHighlighterEx interval) { + //noinspection unchecked return (Getter)interval; } } @Override - void reportInvalidation(RangeHighlighterEx markerEx, Object reason) { - super.reportInvalidation(markerEx, reason); + void fireBeforeRemoved(@NotNull RangeHighlighterEx markerEx, @NotNull Object reason) { myMarkupModel.fireBeforeRemoved(markerEx); } } From 81420c5869f6263c64769f4f8091664720c2cf3c Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Thu, 14 May 2015 14:09:36 +0300 Subject: [PATCH 15/28] notnull --- platform/util/src/com/intellij/util/ArrayUtil.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/util/src/com/intellij/util/ArrayUtil.java b/platform/util/src/com/intellij/util/ArrayUtil.java index 462f90c86447..2550a1d41d41 100644 --- a/platform/util/src/com/intellij/util/ArrayUtil.java +++ b/platform/util/src/com/intellij/util/ArrayUtil.java @@ -414,6 +414,7 @@ public class ArrayUtil extends ArrayUtilRt { return result; } + @NotNull @Contract(pure=true) public static T[] append(@NotNull final T[] src, final T element, @NotNull ArrayFactory factory) { int length = src.length; From fe1bba7752ba2fccda4223ae937365aec205b5f1 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 14 May 2015 16:28:30 +0300 Subject: [PATCH 16/28] IDEA-139945 When putting a watch on a breakpoint, Java debugger produces a boxed Integer instead of primitive int --- .../engine/evaluation/expression/MethodEvaluator.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java index bb36ecf04672..7a2aa5b3634b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java @@ -30,6 +30,7 @@ import com.intellij.debugger.impl.ClassLoadingUtils; import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.jdi.VirtualMachineProxyImpl; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.SystemInfo; import com.intellij.rt.debugger.DefaultMethodInvoker; import com.sun.jdi.*; @@ -47,6 +48,9 @@ public class MethodEvaluator implements Evaluator { private final boolean myCheckDefaultInterfaceMethod; private final boolean myMustBeVararg; + // see IDEA-139945, corresponding jdk bug was fixed in 8u45 + private static boolean ourUseDefaultInvoker = !SystemInfo.isJavaVersionAtLeast("1.8.0_45"); + public MethodEvaluator(Evaluator objectEvaluator, JVMName className, String methodName, @@ -180,7 +184,7 @@ public class MethodEvaluator implements Evaluator { return debugProcess.invokeInstanceMethod(context, objRef, jdiMethod, args, ObjectReference.INVOKE_NONVIRTUAL); } // fix for default methods in interfaces, see IDEA-124066 - if (myCheckDefaultInterfaceMethod && jdiMethod.declaringType() instanceof InterfaceType) { + if (ourUseDefaultInvoker && myCheckDefaultInterfaceMethod && jdiMethod.declaringType() instanceof InterfaceType) { try { return invokeDefaultMethod(debugProcess, context, objRef, myMethodName); } catch (EvaluateException e) { From ed36943182f5bee1ed04571fafc674351d5ce533 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 14 May 2015 16:44:20 +0300 Subject: [PATCH 17/28] IDEA-139945 When putting a watch on a breakpoint, Java debugger produces a boxed Integer instead of primitive int - correct fix --- .../debugger/engine/evaluation/expression/MethodEvaluator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java index 7a2aa5b3634b..283611380209 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java @@ -49,7 +49,7 @@ public class MethodEvaluator implements Evaluator { private final boolean myMustBeVararg; // see IDEA-139945, corresponding jdk bug was fixed in 8u45 - private static boolean ourUseDefaultInvoker = !SystemInfo.isJavaVersionAtLeast("1.8.0_45"); + private static boolean ourUseDefaultInvoker = !SystemInfo.isJavaVersionAtLeast("1.8.0_40"); public MethodEvaluator(Evaluator objectEvaluator, JVMName className, From 547b3ab02a55941fc4359cd2d44eba250d4334dd Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 14 May 2015 16:59:50 +0300 Subject: [PATCH 18/28] IDEA-132852 Debugger: values in editor are still shown after disconnect --- .../src/com/intellij/xdebugger/impl/frame/XVariablesView.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java index 16a1ce54d933..b75002919dce 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesView.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -73,6 +73,7 @@ public class XVariablesView extends XVariablesViewBase { tree.getProject().putUserData(DEBUG_VARIABLES, null); tree.getProject().putUserData(DEBUG_VARIABLES_TIMESTAMPS, null); tree.setSourcePosition(null); + tree.updateEditor(); XDebuggerTreeNode node; XDebugSession session = getSession(getPanel()); From d9be1f18f9cadb46ed949f20c2e94ccb78e385cf Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 14 May 2015 17:12:19 +0300 Subject: [PATCH 19/28] IDEA-139945 - fixes after review --- .../engine/evaluation/expression/MethodEvaluator.java | 7 ++----- platform/util/src/com/intellij/Patches.java | 8 +++++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java index 283611380209..7387c7ffb0b2 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java @@ -20,6 +20,7 @@ */ package com.intellij.debugger.engine.evaluation.expression; +import com.intellij.Patches; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.engine.DebugProcess; import com.intellij.debugger.engine.DebugProcessImpl; @@ -30,7 +31,6 @@ import com.intellij.debugger.impl.ClassLoadingUtils; import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.jdi.VirtualMachineProxyImpl; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.SystemInfo; import com.intellij.rt.debugger.DefaultMethodInvoker; import com.sun.jdi.*; @@ -48,9 +48,6 @@ public class MethodEvaluator implements Evaluator { private final boolean myCheckDefaultInterfaceMethod; private final boolean myMustBeVararg; - // see IDEA-139945, corresponding jdk bug was fixed in 8u45 - private static boolean ourUseDefaultInvoker = !SystemInfo.isJavaVersionAtLeast("1.8.0_40"); - public MethodEvaluator(Evaluator objectEvaluator, JVMName className, String methodName, @@ -184,7 +181,7 @@ public class MethodEvaluator implements Evaluator { return debugProcess.invokeInstanceMethod(context, objRef, jdiMethod, args, ObjectReference.INVOKE_NONVIRTUAL); } // fix for default methods in interfaces, see IDEA-124066 - if (ourUseDefaultInvoker && myCheckDefaultInterfaceMethod && jdiMethod.declaringType() instanceof InterfaceType) { + if (Patches.JDK_BUG_ID_8042123 && myCheckDefaultInterfaceMethod && jdiMethod.declaringType() instanceof InterfaceType) { try { return invokeDefaultMethod(debugProcess, context, objRef, myMethodName); } catch (EvaluateException e) { diff --git a/platform/util/src/com/intellij/Patches.java b/platform/util/src/com/intellij/Patches.java index cb1c9c07347d..daea52abff4e 100644 --- a/platform/util/src/com/intellij/Patches.java +++ b/platform/util/src/com/intellij/Patches.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -108,4 +108,10 @@ public class Patches { * fixed in JDK8 */ public static final boolean JDK_BUG_ID_7103570 = true; + + /** + * Support default methods in JDI + * See JDK-8042123 + */ + public static final boolean JDK_BUG_ID_8042123 = !SystemInfo.isJavaVersionAtLeast("1.8.0_40"); } From d8b18795a848331018a2525d88c621d1ba44e44b Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 14 May 2015 17:56:09 +0300 Subject: [PATCH 20/28] IDEA-140152 In the debug window gear menu, the current state of the watching method return values and auto variables mode selections is unclear --- .../debugger/engine/JavaDebugProcess.java | 20 ++++--------------- .../src/messages/DebuggerBundle.properties | 2 ++ 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java index 5dd4279b3cd1..36aff625f280 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java @@ -329,18 +329,10 @@ public class JavaDebugProcess extends XDebugProcess { private volatile boolean myAutoModeEnabled; public AutoVarsSwitchAction() { - super("", "", AllIcons.Debugger.AutoVariablesMode); + super(DebuggerBundle.message("action.auto.variables.mode"), DebuggerBundle.message("action.auto.variables.mode.description"), null); myAutoModeEnabled = DebuggerSettings.getInstance().AUTO_VARIABLES_MODE; } - @Override - public void update(@NotNull final AnActionEvent e) { - super.update(e); - final Presentation presentation = e.getPresentation(); - final boolean autoModeEnabled = Boolean.TRUE.equals(presentation.getClientProperty(SELECTED_PROPERTY)); - presentation.setText(autoModeEnabled ? "All-Variables Mode" : "Auto-Variables Mode"); - } - @Override public boolean isSelected(AnActionEvent e) { return myAutoModeEnabled; @@ -356,15 +348,13 @@ public class JavaDebugProcess extends XDebugProcess { private static class WatchLastMethodReturnValueAction extends ToggleAction { private volatile boolean myWatchesReturnValues; - private final String myTextEnable; + private final String myText; private final String myTextUnavailable; - private final String myMyTextDisable; public WatchLastMethodReturnValueAction() { super("", DebuggerBundle.message("action.watch.method.return.value.description"), null); myWatchesReturnValues = DebuggerSettings.getInstance().WATCH_RETURN_VALUES; - myTextEnable = DebuggerBundle.message("action.watches.method.return.value.enable"); - myMyTextDisable = DebuggerBundle.message("action.watches.method.return.value.disable"); + myText = DebuggerBundle.message("action.watches.method.return.value.enable"); myTextUnavailable = DebuggerBundle.message("action.watches.method.return.value.unavailable.reason"); } @@ -372,12 +362,10 @@ public class JavaDebugProcess extends XDebugProcess { public void update(@NotNull final AnActionEvent e) { super.update(e); final Presentation presentation = e.getPresentation(); - final boolean watchValues = Boolean.TRUE.equals(presentation.getClientProperty(SELECTED_PROPERTY)); DebugProcessImpl process = getCurrentDebugProcess(e.getProject()); - final String actionText = watchValues ? myMyTextDisable : myTextEnable; if (process == null || process.canGetMethodReturnValue()) { presentation.setEnabled(true); - presentation.setText(actionText); + presentation.setText(myText); } else { presentation.setEnabled(false); diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties index 55687bf4d04d..929447158cd4 100644 --- a/resources-en/src/messages/DebuggerBundle.properties +++ b/resources-en/src/messages/DebuggerBundle.properties @@ -444,6 +444,8 @@ action.watch.method.return.value.description=Enables watching last executed meth action.watches.method.return.value.enable=Watch method return values action.watches.method.return.value.disable=Stop watching method return values action.watches.method.return.value.unavailable.reason=Feature is not supported by the target VM +action.auto.variables.mode=Auto-Variables Mode +action.auto.variables.mode.description=Show only variables used near the execution point action.maximizeContent.text breakpoint.properties.panel.option.depends.disable.again=Disable again breakpoint.properties.panel.option.depends.leave.enabled=Leave enabled From c489a086c11bc5f18996aa81eaeddd626f77a668 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Thu, 14 May 2015 18:44:49 +0300 Subject: [PATCH 21/28] IDEA-89484 Macros that rely on active editor don't work when invoked from Find Action popup --- .../src/com/intellij/ide/macro/EditorMacro.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/macro/EditorMacro.java b/platform/lang-impl/src/com/intellij/ide/macro/EditorMacro.java index 5092eff72e94..474ec528e7cf 100644 --- a/platform/lang-impl/src/com/intellij/ide/macro/EditorMacro.java +++ b/platform/lang-impl/src/com/intellij/ide/macro/EditorMacro.java @@ -20,8 +20,6 @@ import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.editor.ex.util.EditorUtil; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.wm.ToolWindowManager; import org.jetbrains.annotations.Nullable; /** @@ -48,13 +46,9 @@ public abstract class EditorMacro extends Macro { @Override public final String expand(DataContext dataContext) throws ExecutionCancelledException { - Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project == null) return null; - if (ToolWindowManager.getInstance(project).isEditorComponentActive()) { - Editor editor = CommonDataKeys.EDITOR.getData(dataContext); - if (editor != null){ - return expand(editor); - } + Editor editor = CommonDataKeys.EDITOR.getData(dataContext); + if (editor != null){ + return expand(editor); } return null; } From 9a66103a88868ed4751f7fc72c4a7ed161cfbf25 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 14 May 2015 19:18:02 +0300 Subject: [PATCH 22/28] moved renderers to the corresponding package --- .../impl/src/com/intellij/debugger/engine/JavaValue.java | 2 +- .../{settings => ui/tree/render}/ColorObjectRenderer.java | 4 ++-- .../tree/render}/GraphicsObjectRenderer.java | 3 ++- .../{settings => ui/tree/render}/IconObjectRenderer.java | 4 ++-- .../{settings => ui/tree/render}/ImageObjectRenderer.java | 4 +++- .../tree/render}/ToStringBasedRenderer.java | 3 ++- resources/src/META-INF/IdeaPlugin.xml | 8 ++++---- 7 files changed, 16 insertions(+), 12 deletions(-) rename java/debugger/impl/src/com/intellij/debugger/{settings => ui/tree/render}/ColorObjectRenderer.java (95%) rename java/debugger/impl/src/com/intellij/debugger/{settings => ui/tree/render}/GraphicsObjectRenderer.java (96%) rename java/debugger/impl/src/com/intellij/debugger/{settings => ui/tree/render}/IconObjectRenderer.java (95%) rename java/debugger/impl/src/com/intellij/debugger/{settings => ui/tree/render}/ImageObjectRenderer.java (96%) rename java/debugger/impl/src/com/intellij/debugger/{settings => ui/tree/render}/ToStringBasedRenderer.java (95%) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java index dcc54be00a2c..acdf8687dea2 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java @@ -27,7 +27,7 @@ import com.intellij.debugger.engine.events.DebuggerCommandImpl; import com.intellij.debugger.engine.events.SuspendContextCommandImpl; import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.impl.DebuggerUtilsEx; -import com.intellij.debugger.settings.ToStringBasedRenderer; +import com.intellij.debugger.ui.tree.render.ToStringBasedRenderer; import com.intellij.debugger.ui.impl.DebuggerTreeRenderer; import com.intellij.debugger.ui.impl.watch.*; import com.intellij.debugger.ui.tree.*; diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ColorObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ColorObjectRenderer.java similarity index 95% rename from java/debugger/impl/src/com/intellij/debugger/settings/ColorObjectRenderer.java rename to java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ColorObjectRenderer.java index 420638ed0c5e..31bf6f0981d7 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/ColorObjectRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ColorObjectRenderer.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.debugger.settings; +package com.intellij.debugger.ui.tree.render; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; +import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; import com.intellij.util.ui.ColorIcon; import com.sun.jdi.*; diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/GraphicsObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/GraphicsObjectRenderer.java similarity index 96% rename from java/debugger/impl/src/com/intellij/debugger/settings/GraphicsObjectRenderer.java rename to java/debugger/impl/src/com/intellij/debugger/ui/tree/render/GraphicsObjectRenderer.java index 614430311377..eccc01d16e03 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/GraphicsObjectRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/GraphicsObjectRenderer.java @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.debugger.settings; +package com.intellij.debugger.ui.tree.render; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.engine.DebuggerUtils; import com.intellij.debugger.engine.FullValueEvaluatorProvider; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; +import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; import com.intellij.xdebugger.frame.XFullValueEvaluator; import com.sun.jdi.*; diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/IconObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/IconObjectRenderer.java similarity index 95% rename from java/debugger/impl/src/com/intellij/debugger/settings/IconObjectRenderer.java rename to java/debugger/impl/src/com/intellij/debugger/ui/tree/render/IconObjectRenderer.java index 2850a85c2f6e..c9b5d635fffb 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/IconObjectRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/IconObjectRenderer.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.debugger.settings; +package com.intellij.debugger.ui.tree.render; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.engine.FullValueEvaluatorProvider; @@ -21,9 +21,9 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.impl.DebuggerUtilsImpl; +import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; import com.intellij.debugger.ui.tree.ValueDescriptor; -import com.intellij.debugger.ui.tree.render.DescriptorLabelListener; import com.intellij.icons.AllIcons; import com.intellij.xdebugger.frame.XFullValueEvaluator; import org.jetbrains.annotations.Nullable; diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ImageObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ImageObjectRenderer.java similarity index 96% rename from java/debugger/impl/src/com/intellij/debugger/settings/ImageObjectRenderer.java rename to java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ImageObjectRenderer.java index b6cb26dcdba3..e511a6aca5a8 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/ImageObjectRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ImageObjectRenderer.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.debugger.settings; +package com.intellij.debugger.ui.tree.render; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.engine.DebugProcess; @@ -22,6 +22,8 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.impl.ClassLoadingUtils; +import com.intellij.debugger.settings.CustomPopupFullValueEvaluator; +import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.rt.debugger.ImageSerializer; diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/ToStringBasedRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringBasedRenderer.java similarity index 95% rename from java/debugger/impl/src/com/intellij/debugger/settings/ToStringBasedRenderer.java rename to java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringBasedRenderer.java index 9db4db739fb9..3fc5070ec15b 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/ToStringBasedRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringBasedRenderer.java @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.debugger.settings; +package com.intellij.debugger.ui.tree.render; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContext; +import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.debugger.ui.tree.ValueDescriptor; import com.intellij.debugger.ui.tree.render.*; diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index b8b47df466cf..0f416c38d822 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1521,10 +1521,10 @@ - - - - + + + + From a84ee3044f6c0e02ac0f5d5ef0009c8c1cf226e0 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 14 May 2015 19:34:52 +0300 Subject: [PATCH 23/28] IDEA-139800 Show file tree under java.io.File instances in debugger views --- .../settings/NodeRendererSettings.java | 5 ++-- .../ui/tree/render/FileObjectRenderer.java | 29 +++++++++++++++++++ resources/src/META-INF/IdeaPlugin.xml | 1 + 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 java/debugger/impl/src/com/intellij/debugger/ui/tree/render/FileObjectRenderer.java diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java index 5874f8b33b86..5e4308884471 100644 --- a/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java +++ b/java/debugger/impl/src/com/intellij/debugger/settings/NodeRendererSettings.java @@ -361,7 +361,8 @@ public class NodeRendererSettings implements PersistentStateComponent { return renderer; } - private ExpressionChildrenRenderer createExpressionChildrenRenderer(@NonNls String expressionText, @NonNls String childrenExpandableText) { + public static ExpressionChildrenRenderer createExpressionChildrenRenderer(@NonNls String expressionText, + @NonNls String childrenExpandableText) { final ExpressionChildrenRenderer childrenRenderer = new ExpressionChildrenRenderer(); childrenRenderer.setChildrenExpression(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, expressionText, "", StdFileTypes.JAVA)); if (childrenExpandableText != null) { @@ -370,7 +371,7 @@ public class NodeRendererSettings implements PersistentStateComponent { return childrenRenderer; } - private EnumerationChildrenRenderer createEnumerationChildrenRenderer(@NonNls String[][] expressions) { + private static EnumerationChildrenRenderer createEnumerationChildrenRenderer(@NonNls String[][] expressions) { final EnumerationChildrenRenderer childrenRenderer = new EnumerationChildrenRenderer(); if (expressions != null && expressions.length > 0) { final ArrayList> childrenList = new ArrayList>(expressions.length); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/FileObjectRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/FileObjectRenderer.java new file mode 100644 index 000000000000..9a03f6b0af57 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/FileObjectRenderer.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.debugger.ui.tree.render; + +import com.intellij.debugger.settings.NodeRendererSettings; + +/** + * @author egor + */ +public class FileObjectRenderer extends ToStringBasedRenderer { + public FileObjectRenderer(final NodeRendererSettings rendererSettings) { + super(rendererSettings, "File", null, NodeRendererSettings.createExpressionChildrenRenderer("listFiles()", null)); + setClassName("java.io.File"); + setEnabled(true); + } +} diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 0f416c38d822..a518d3a5e771 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1527,6 +1527,7 @@ + From 0186b10ece82d05abdce891afdf095a351875c04 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 14 May 2015 19:40:28 +0300 Subject: [PATCH 24/28] cleanup --- .../ui/tree/render/ExpressionChildrenRenderer.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ExpressionChildrenRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ExpressionChildrenRenderer.java index 68608c82c67b..1af0b6acb5da 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ExpressionChildrenRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ExpressionChildrenRenderer.java @@ -33,6 +33,7 @@ import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiExpression; import com.sun.jdi.BooleanValue; import com.sun.jdi.Value; @@ -148,7 +149,7 @@ public class ExpressionChildrenRenderer extends ReferenceRenderer implements Chi expressionValue, context); } - private NodeRenderer getChildrenRenderer(Value childrenValue, ValueDescriptor parentDescriptor) { + private static NodeRenderer getChildrenRenderer(Value childrenValue, ValueDescriptor parentDescriptor) { NodeRenderer renderer = getLastChildrenRenderer(parentDescriptor); if (renderer == null || childrenValue == null || !renderer.isApplicable(childrenValue.type())) { renderer = DebugProcessImpl.getDefaultRenderer(childrenValue != null ? childrenValue.type() : null); @@ -160,7 +161,7 @@ public class ExpressionChildrenRenderer extends ReferenceRenderer implements Chi public boolean isExpandable(Value value, final EvaluationContext context, NodeDescriptor parentDescriptor) { final EvaluationContext evaluationContext = context.createEvaluationContext(value); - if(!"".equals(myChildrenExpandable.getReferenceExpression().getText())) { + if(!StringUtil.isEmpty(myChildrenExpandable.getReferenceExpression().getText())) { try { Value expanded = myChildrenExpandable.getEvaluator(evaluationContext.getProject()).evaluate(evaluationContext); if(expanded instanceof BooleanValue) { @@ -174,9 +175,7 @@ public class ExpressionChildrenRenderer extends ReferenceRenderer implements Chi try { Value children = evaluateChildren(evaluationContext, parentDescriptor); - - ChildrenRenderer defaultChildrenRenderer = ((DebugProcessImpl)evaluationContext.getDebugProcess()).getDefaultRenderer(value.type()); - + ChildrenRenderer defaultChildrenRenderer = DebugProcessImpl.getDefaultRenderer(value.type()); return defaultChildrenRenderer.isExpandable(children, evaluationContext, parentDescriptor); } catch (EvaluateException e) { From ddface9ec75b1bb120491ade50ce48775cbb2dfa Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 14 May 2015 20:17:09 +0300 Subject: [PATCH 25/28] removed unused logger --- .../debugger/ui/impl/watch/ArrayElementDescriptorImpl.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArrayElementDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArrayElementDescriptorImpl.java index 584b09bca900..bf6bc9c9bd1c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArrayElementDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArrayElementDescriptorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,6 @@ import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.ui.tree.ArrayElementDescriptor; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiElementFactory; @@ -31,8 +30,6 @@ import com.sun.jdi.ObjectCollectedException; import com.sun.jdi.Value; public class ArrayElementDescriptorImpl extends ValueDescriptorImpl implements ArrayElementDescriptor{ - private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.ui.impl.watch.ArrayElementDescriptorImpl"); - private final int myIndex; private final ArrayReference myArray; From 76d43e32e7b14e9dbaa3f7780ab9bc973285bfdc Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 14 May 2015 20:30:47 +0300 Subject: [PATCH 26/28] cleanup --- .../evaluation/expression/ArrayAccessEvaluator.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java index 4413c8384da5..633e3f5cf7bf 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ArrayAccessEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,13 +20,13 @@ */ package com.intellij.debugger.engine.evaluation.expression; +import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.engine.DebuggerUtils; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; -import com.intellij.debugger.impl.DebuggerUtilsEx; -import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl; import com.intellij.debugger.ui.impl.watch.ArrayElementDescriptorImpl; -import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl; import com.intellij.openapi.project.Project; import com.sun.jdi.*; @@ -50,7 +50,7 @@ class ArrayAccessEvaluator implements Evaluator { throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.array.reference.expected")); } myEvaluatedArrayReference = (ArrayReference)arrayValue; - if (!DebuggerUtilsEx.isInteger(indexValue)) { + if (!DebuggerUtils.isInteger(indexValue)) { throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.index.expression")); } myEvaluatedIndex = ((PrimitiveValue)indexValue).intValue(); From d66ea438cd0a87ff28a0e845f187deaa7cd1a31e Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Thu, 14 May 2015 21:43:41 +0300 Subject: [PATCH 27/28] Added test for manage.py --- .../com/jetbrains/python/fixtures/PyTestCase.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java b/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java index 0e6c77e4f6f2..e311f362be58 100644 --- a/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java +++ b/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java @@ -49,10 +49,7 @@ import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.TestDataPath; import com.intellij.testFramework.UsefulTestCase; -import com.intellij.testFramework.fixtures.CodeInsightTestFixture; -import com.intellij.testFramework.fixtures.IdeaProjectTestFixture; -import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory; -import com.intellij.testFramework.fixtures.TestFixtureBuilder; +import com.intellij.testFramework.fixtures.*; import com.intellij.testFramework.fixtures.impl.LightTempDirTestFixtureImpl; import com.intellij.usageView.UsageInfo; import com.intellij.usages.Usage; @@ -124,12 +121,20 @@ public abstract class PyTestCase extends UsefulTestCase { TestFixtureBuilder fixtureBuilder = factory.createLightFixtureBuilder(getProjectDescriptor()); final IdeaProjectTestFixture fixture = fixtureBuilder.getFixture(); myFixture = IdeaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(fixture, - new LightTempDirTestFixtureImpl(true)); + createTempDirFixture()); myFixture.setUp(); myFixture.setTestDataPath(getTestDataPath()); } + /** + * @return fixture to be used as temporary dir. + */ + @NotNull + protected TempDirTestFixture createTempDirFixture() { + return new LightTempDirTestFixtureImpl(true); // "tmp://" dir by default + } + protected String getTestDataPath() { return PythonTestUtil.getTestDataPath(); } From 67073228c402793d3cd206b0937bd9e66f0a61c2 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Thu, 14 May 2015 23:05:20 +0300 Subject: [PATCH 28/28] introduce StringUtil.escapeMnemonics() --- .../src/com/intellij/openapi/util/text/StringUtil.java | 9 +++++++++ .../ide/actions/SynchronizeCurrentFileAction.java | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index 7835e488d617..97b40512dff8 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -2086,6 +2086,15 @@ public class StringUtil extends StringUtilRt { return replace(text, REPLACES_DISP, REPLACES_REFS); } + @NonNls private static final String[] MN_QUOTED = {"&&", "__"}; + @NonNls private static final String[] MN_CHARS = {"&", "_"}; + + @Contract(value = "null -> null; !null -> !null", pure = true) + public static String escapeMnemonics(@Nullable String text) { + if (text == null) return null; + return replace(text, MN_CHARS, MN_QUOTED); + } + @NotNull @Contract(pure = true) public static String htmlEmphasize(@NotNull String text) { diff --git a/platform/vcs-impl/src/com/intellij/ide/actions/SynchronizeCurrentFileAction.java b/platform/vcs-impl/src/com/intellij/ide/actions/SynchronizeCurrentFileAction.java index 9bcd04a41e61..cde64d3dc698 100644 --- a/platform/vcs-impl/src/com/intellij/ide/actions/SynchronizeCurrentFileAction.java +++ b/platform/vcs-impl/src/com/intellij/ide/actions/SynchronizeCurrentFileAction.java @@ -22,6 +22,7 @@ import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; @@ -42,7 +43,7 @@ public class SynchronizeCurrentFileAction extends AnAction implements DumbAware String message = getMessage(files); e.getPresentation().setEnabledAndVisible(true); - e.getPresentation().setText(message.replace("_", "__").replace("&", "&&")); + e.getPresentation().setText(StringUtil.escapeMnemonics(message)); } private static String getMessage(VirtualFile[] files) {