Merge remote-tracking branch 'origin/master'

This commit is contained in:
Anna Kozlova
2015-01-07 17:14:27 +01:00
30 changed files with 469 additions and 288 deletions
+20 -1
View File
@@ -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.
@@ -29,6 +29,8 @@ class Paths {
final artifacts
final artifacts_core
final artifacts_jps
final ideaSystem
final ideaConfig
def Paths(String out) {
sandbox = out
@@ -39,6 +41,8 @@ class Paths {
artifacts = "$sandbox/artifacts"
artifacts_core = "$artifacts/core"
artifacts_jps = "$artifacts/jps"
ideaSystem = "$sandbox/system"
ideaConfig = "$sandbox/config"
}
}
@@ -75,6 +79,8 @@ target('default': 'The default target') {
zipSources(home, paths.artifacts)
indexSearchableOptions()
layoutAll([buildNumber: "IC-$snapshot",
system_selector: "IdeaIC${p("component.version.major")}",
tools_jar: true],
@@ -83,15 +89,28 @@ target('default': 'The default target') {
target('build-dist-jars' : 'Target to build jars from locally compiled classes') {
loadProject()
// load ApplicationInfo.xml properties
ant.xmlproperty(file: appInfoFile(), collapseAttributes: "true")
indexSearchableOptions()
layoutAll([buildNumber: "IC-$snapshot",
system_selector: "IdeaIC${p("component.version.major")}",
tools_jar: true],
home, null, paths)
}
private void indexSearchableOptions() {
buildSearchableOptions("${projectBuilder.moduleOutput(findModule("resources-en"))}/search", [], {
ant.pathelement(location: "$jdkHome/lib/tools.jar")
ant.pathelement(location: "$home/lib/junit.jar")
projectBuilder.moduleRuntimeClasspath(findModule("community-main"), false).each {
ant.pathelement(location: it)
}
})
}
def layoutAll(Map args, String home, String out, Paths _paths = null, buildJps = false) {
Paths paths = _paths != null ? _paths : new Paths(out)
+9 -5
View File
@@ -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.
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import org.jetbrains.jps.gant.JpsGantTool
import org.jetbrains.jps.gant.TeamCityBuildInfoPrinter
import org.jetbrains.jps.model.java.JavaSourceRootType
@@ -929,13 +928,18 @@ binding.setVariable("buildSearchableOptions", { String target, List licenses, Cl
ant.replace(file: classpathFile, token: File.pathSeparator, value: "\n")
ant.java(classname: "com.intellij.rt.execution.CommandLineWrapper", fork: true, failonerror: true) {
jvmarg(line: "-Xbootclasspath/a:${projectBuilder.moduleOutput(findModule("boot"))} -ea -Xmx500m -XX:MaxPermSize=200m")
jvmarg(line: "-Didea.home.path=$home -Didea.system.path=${paths.ideaSystem} -Didea.config.path=${paths.ideaConfig}")
jvmarg(line: "-ea -Xmx500m -XX:MaxPermSize=200m")
jvmarg(value: "-Xbootclasspath/a:${projectBuilder.moduleOutput(findModule("boot"))}")
jvmarg(value: "-Didea.home.path=${home}")
jvmarg(value: "-Didea.system.path=${paths.ideaSystem}")
jvmarg(value: "-Didea.config.path=${paths.ideaConfig}")
if (jvmArgs != null) {
jvmarg(line: jvmArgs)
}
arg(line: "${classpathFile} com.intellij.idea.Main traverseUI ${target}/searchableOptions.xml")
arg(value: "${classpathFile}")
arg(line: "com.intellij.idea.Main traverseUI")
arg(value: "${target}/searchableOptions.xml")
classpath() {
pathelement(location: "${projectBuilder.moduleOutput(findModule("java-runtime"))}")
@@ -90,7 +90,7 @@ class ContractInferenceInterpreter {
if (notNull && contract.returnValue == NOT_NULL_VALUE) {
return false;
}
return ContractInspection.isReturnTypeCompatible(returnType, contract.returnValue);
return InferenceFromSourceUtil.isReturnTypeCompatible(returnType, contract.returnValue);
}
});
}
@@ -92,29 +92,10 @@ public class ContractInspection extends BaseJavaBatchLocalInspectionTool {
return "Method takes " + paramCount + " parameters, while contract clause number " + (i + 1) + " expects " + contract.arguments.length;
}
PsiType returnType = method.getReturnType();
if (returnType != null && !isReturnTypeCompatible(returnType, contract.returnValue)) {
if (returnType != null && !InferenceFromSourceUtil.isReturnTypeCompatible(returnType, contract.returnValue)) {
return "Method returns " + returnType.getPresentableText() + " but the contract specifies " + contract.returnValue;
}
}
return null;
}
static boolean isReturnTypeCompatible(@Nullable PsiType returnType, @NotNull MethodContract.ValueConstraint returnValue) {
if (returnValue == MethodContract.ValueConstraint.ANY_VALUE || returnValue == MethodContract.ValueConstraint.THROW_EXCEPTION) {
return true;
}
if (PsiType.VOID.equals(returnType)) return false;
if (PsiType.BOOLEAN.equals(returnType)) {
return returnValue == MethodContract.ValueConstraint.TRUE_VALUE ||
returnValue == MethodContract.ValueConstraint.FALSE_VALUE;
}
if (returnType instanceof PsiClassType) {
return returnValue == MethodContract.ValueConstraint.NULL_VALUE ||
returnValue == MethodContract.ValueConstraint.NOT_NULL_VALUE;
}
return true;
}
}
@@ -23,6 +23,7 @@ import com.intellij.psi.search.searches.MethodReferencesSearch;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author peter
@@ -52,4 +53,23 @@ public class InferenceFromSourceUtil {
VirtualFile virtualFile = PsiUtilCore.getVirtualFile(method);
return virtualFile != null && FileIndexFacade.getInstance(method.getProject()).isInLibrarySource(virtualFile);
}
static boolean isReturnTypeCompatible(@Nullable PsiType returnType, @NotNull MethodContract.ValueConstraint returnValue) {
if (returnValue == MethodContract.ValueConstraint.ANY_VALUE || returnValue == MethodContract.ValueConstraint.THROW_EXCEPTION) {
return true;
}
if (PsiType.VOID.equals(returnType)) return false;
if (PsiType.BOOLEAN.equals(returnType)) {
return returnValue == MethodContract.ValueConstraint.TRUE_VALUE ||
returnValue == MethodContract.ValueConstraint.FALSE_VALUE;
}
if (returnType instanceof PsiClassType) {
return returnValue == MethodContract.ValueConstraint.NULL_VALUE ||
returnValue == MethodContract.ValueConstraint.NOT_NULL_VALUE;
}
return false;
}
}
@@ -291,6 +291,15 @@ class ContractInferenceFromSourceTest extends LightCodeInsightFixtureTestCase {
assert c == []
}
public void "test double constant auto-unboxing"() {
def c = inferContracts("""
static double method() {
return 1;
}
""")
assert c == []
}
public void "test non-returning delegation"() {
def c = inferContracts("""
static void test2(Object o) {
@@ -433,6 +442,15 @@ class ContractInferenceFromSourceTest extends LightCodeInsightFixtureTestCase {
assert c == ['null -> !null']
}
public void "test primitive return type"() {
def c = inferContracts("""
String s(String s) {
return s != "a" ? "b" : null;
}
""")
assert c == ['null -> !null']
}
public void "test return after if without else"() {
def c = inferContracts("""
public static boolean isBlank(String s) {
@@ -589,18 +589,6 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor {
}
private MatchingStrategy findStrategy(PsiElement el) {
// identify matching strategy
final MatchingHandler handler = myCompilingVisitor.getContext().getPattern().getHandler(el);
//if (handler instanceof SubstitutionHandler) {
// final SubstitutionHandler shandler = (SubstitutionHandler) handler;
if (handler.getFilter() instanceof SymbolNodeFilter ||
handler.getFilter() instanceof TypedSymbolNodeFilter
) {
return SymbolMatchingStrategy.getInstance();
}
//}
if (el instanceof PsiDocComment) {
return JavaDocMatchingStrategy.getInstance();
}
@@ -7,6 +7,27 @@ import com.intellij.psi.*;
*/
public class ExprMatchingStrategy extends MatchingStrategyBase {
@Override
public void visitTypeElement(PsiTypeElement type) {
result = true;
}
@Override public void visitReferenceParameterList(PsiReferenceParameterList psiReferenceParameterList) {
result = true;
}
@Override public void visitReferenceElement(PsiJavaCodeReferenceElement psiJavaCodeReferenceElement) {
result = true;
}
@Override public void visitTypeParameterList(PsiTypeParameterList psiTypeParameterList) {
result = true;
}
@Override public void visitReferenceList(final PsiReferenceList list) {
result = true;
}
@Override public void visitAnnotation(final PsiAnnotation annotation) {
result = true;
}
@@ -1,54 +0,0 @@
package com.intellij.structuralsearch.impl.matcher.strategies;
import com.intellij.psi.*;
/**
* CommonStrategy to match symbols
*/
public class SymbolMatchingStrategy extends ExprMatchingStrategy {
@Override public void visitReferenceList(final PsiReferenceList list) {
result = true;
}
@Override public void visitAnnotation(final PsiAnnotation annotation) {
result = true;
}
@Override public void visitAnnotationParameterList(final PsiAnnotationParameterList list) {
result = true;
}
@Override public void visitModifierList(final PsiModifierList list) {
result = true;
}
@Override public void visitNameValuePair(final PsiNameValuePair pair) {
result = true;
}
@Override public void visitTypeParameterList(PsiTypeParameterList psiTypeParameterList) {
result = true;
}
@Override public void visitTypeElement(PsiTypeElement psiTypeElement) {
result = true;
}
@Override public void visitReferenceElement(PsiJavaCodeReferenceElement psiJavaCodeReferenceElement) {
result = true;
}
@Override public void visitReferenceParameterList(PsiReferenceParameterList psiReferenceParameterList) {
result = true;
}
private SymbolMatchingStrategy() {}
private static class SymbolMatchingStrategyHolder {
private static final SymbolMatchingStrategy instance = new SymbolMatchingStrategy();
}
public static MatchingStrategy getInstance() {
return SymbolMatchingStrategyHolder.instance;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 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.
@@ -264,6 +264,10 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
public void showJavaDocInfo(@NotNull final PsiElement element,
final PsiElement original,
@Nullable Runnable closeCallback) {
if (!element.isValid()) {
return;
}
PopupUpdateProcessor updateProcessor = new PopupUpdateProcessor(element.getProject()) {
@Override
public void updatePopup(Object lookupItemObject) {
@@ -44,6 +44,8 @@ import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
import com.intellij.openapi.progress.util.ReadTask;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.*;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
@@ -55,6 +57,7 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.search.SearchScope;
import com.intellij.ui.*;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.table.JBTable;
import com.intellij.usageView.UsageInfo;
@@ -119,9 +122,9 @@ public class FindDialog extends DialogWrapper {
protected JLabel myReplacePrompt;
private HideableTitledPanel myScopePanel;
private static boolean myPreviousResultsExpandedState;
private static boolean myPreviousPreviewResultsState = true;
private HideableTitledPanel myResultsPreviewPanel;
private JBTable myResultsPreviewTable;
private JBPopup myResultsPopup;
private volatile ProgressIndicatorBase myResultsPreviewSearchProgress;
public FindDialog(@NotNull Project project, @NotNull FindModel model, @NotNull Consumer<FindModel> myOkHandler){
@@ -137,7 +140,7 @@ public class FindDialog extends DialogWrapper {
initByModel();
updateReplaceVisibility();
if (myResultsPreviewTable != null) {
if (haveResultsPreview()) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
@@ -169,13 +172,12 @@ public class FindDialog extends DialogWrapper {
@Override
protected void dispose() {
if (myResultsPreviewSearchProgress != null) myResultsPreviewSearchProgress.cancel();
finishPreviousPreviewSearch();
for(Map.Entry<EditorTextField, DocumentAdapter> e: myComboBoxListeners.entrySet()) {
e.getKey().removeDocumentListener(e.getValue());
}
myComboBoxListeners.clear();
if (myScopePanel != null) myPreviousResultsExpandedState = myScopePanel.isExpanded();
if (myResultsPreviewTable != null) myPreviousPreviewResultsState = myResultsPreviewPanel.isExpanded();
super.dispose();
}
@@ -312,18 +314,19 @@ public class FindDialog extends DialogWrapper {
}
private void findSettingsChanged() {
if (myModel.isMultipleFiles() && myResultsPreviewTable != null) {
if (haveResultsPreview()) {
final ModalityState state = ModalityState.current();
if (state == ModalityState.NON_MODAL) return; // skip initial changes
if (myResultsPreviewSearchProgress != null && !myResultsPreviewSearchProgress.isCanceled()) {
myResultsPreviewSearchProgress.cancel();
}
final DefaultTableModel model = new DefaultTableModel();
model.addColumn("Usages");
finishPreviousPreviewSearch();
final DefaultTableModel model = new DefaultTableModel() {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
myResultsPreviewTable.setModel(model);
myResultsPreviewTable.getColumnModel().getColumn(0).setCellRenderer(new MyTableCellRenderer());
model.addColumn("Usages");
final FindModel modelClone = myModel.clone();
applyTo(modelClone, false);
@@ -335,8 +338,16 @@ public class FindDialog extends DialogWrapper {
final ProgressIndicatorBase progressIndicatorWhenSearchStarted = new ProgressIndicatorBase();
myResultsPreviewSearchProgress = progressIndicatorWhenSearchStarted;
myResultsPreviewTable.setModel(model);
myResultsPreviewTable.getColumnModel().getColumn(0).setCellRenderer(new UsageTableCellRenderer());
myResultsPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(new JBScrollPane(myResultsPreviewTable),
myResultsPreviewTable)
.setRequestFocus(false).createPopup();
myResultsPreviewTable.getEmptyText().setText("Searching...");
myResultsPopup.show(new RelativePoint(myInputComboBox, new Point(0, myInputComboBox.getHeight())));
final AtomicInteger resultsCount = new AtomicInteger();
ProgressIndicatorUtils.scheduleWithWriteActionPriority(myResultsPreviewSearchProgress, new ReadTask() {
@@ -383,7 +394,13 @@ public class FindDialog extends DialogWrapper {
}
});
}
}
private void finishPreviousPreviewSearch() {
if (myResultsPreviewSearchProgress != null && !myResultsPreviewSearchProgress.isCanceled()) {
myResultsPreviewSearchProgress.cancel();
if (myResultsPopup != null) myResultsPopup.cancel();
}
}
@NotNull
@@ -468,30 +485,16 @@ public class FindDialog extends DialogWrapper {
myCbToSkipResultsWhenOneUsage.setVisible(!myModel.isReplaceState());
if (ApplicationManager.getApplication().isInternal() && myModel.isMultipleFiles()) {
gbConstraints.weightx = 1;
gbConstraints.weighty = 2;
gbConstraints.fill = GridBagConstraints.BOTH;
JBScrollPane scrollPane = new JBScrollPane(myResultsPreviewTable = new JBTable(), JBScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JBScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
optionsPanel.add(
myResultsPreviewPanel = new HideableTitledPanel("Results preview", scrollPane, myPreviousPreviewResultsState),
gbConstraints
);
myResultsPreviewTable.setShowColumns(false);
new DoubleClickListener() {
if (haveResultsPreview()) {
final JBTable table = new JBTable() {
@Override
protected boolean onDoubleClick(MouseEvent event) {
int row = myResultsPreviewTable.getSelectedRow();
Object valueAt = myResultsPreviewTable.getModel().getValueAt(row, 0);
if (valueAt instanceof Usage) {
doCancelAction();
((Usage)valueAt).navigate(true);
}
return true;
public Dimension getPreferredSize() {
return new Dimension(myInputComboBox.getWidth(), super.getPreferredSize().height);
}
}.installOn(myResultsPreviewTable);
};
table.setShowColumns(false);
new NavigateToSourceListener().installOn(table);
myResultsPreviewTable = table;
}
}
else {
@@ -517,6 +520,10 @@ public class FindDialog extends DialogWrapper {
return optionsPanel;
}
private boolean haveResultsPreview() {
return ApplicationManager.getApplication().isInternal() && myModel.isMultipleFiles();
}
private JPanel createResultsOptionPanel(JPanel optionsPanel, GridBagConstraints gbConstraints) {
JPanel resultsOptionPanel = new JPanel();
resultsOptionPanel.setLayout(new BoxLayout(resultsOptionPanel, BoxLayout.Y_AXIS));
@@ -1375,24 +1382,54 @@ public class FindDialog extends DialogWrapper {
updateControls();
}
private static class MyTableCellRenderer extends SimpleColoredComponent implements TableCellRenderer {
private static class UsageTableCellRenderer extends JPanel implements TableCellRenderer {
private SimpleColoredComponent myUsageRenderer = new SimpleColoredComponent();
private SimpleColoredComponent myFileAndLineNumber = new SimpleColoredComponent();
UsageTableCellRenderer() {
setLayout(new BorderLayout());
add(myUsageRenderer, BorderLayout.WEST);
add(myFileAndLineNumber, BorderLayout.EAST);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
clear();
myUsageRenderer.clear();
myFileAndLineNumber.clear();
if (value instanceof UsageInfo2UsageAdapter) {
UsageInfo2UsageAdapter usageAdapter = (UsageInfo2UsageAdapter)value;
UsagePresentation presentation = usageAdapter.getPresentation();
TextChunk[] text = presentation.getText();
append(usageAdapter.getFile().getName() + " ", SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES);
for (TextChunk textChunk : text) {
// put line number / file info at the right
for (int i = 1; i < text.length; ++i) {
TextChunk textChunk = text[i];
SimpleTextAttributes simples = textChunk.getSimpleAttributesIgnoreBackground();
append(textChunk.getText(), simples);
myUsageRenderer.append(textChunk.getText(), simples);
}
myFileAndLineNumber.append(usageAdapter.getFile().getName() + " " + text[0].getText(),
SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES);
}
return this;
}
}
private class NavigateToSourceListener extends DoubleClickListener {
@Override
protected boolean onDoubleClick(MouseEvent event) {
Object source = event.getSource();
if (!(source instanceof JBTable)) return false;
int row = ((JBTable)source).getSelectedRow();
Object valueAt = ((JBTable)source).getModel().getValueAt(row, 0);
if (valueAt instanceof Usage) {
doCancelAction(); //?
((Usage)valueAt).navigate(true);
}
return true;
}
}
}
@@ -116,6 +116,17 @@ public class SymlinkHandlingTest extends SymlinkTestCase {
link2.getPath() + "/" + link1Home.getName() + "/" + link1.getName());
}
public void testSameTargetShouldBeVisitedSeveralTimesFromSeveralNonRecursiveLinks() throws Exception {
File target = createTestDir(myTempDir, "target");
File child = createTestDir(myTempDir, "child");
File link1 = createSymLink(target.getPath(), myTempDir.getPath() + "/link1");
File link2 = createSymLink(target.getPath(), myTempDir.getPath() + "/link2");
assertVisitedPaths(myTempDir,
target.getPath(), child.getPath(),
link1.getPath(), link1.getPath() + "/child",
link2.getPath(), link2.getPath() + "/child");
}
public void testTargetIsWritable() throws Exception {
File targetFile = createTestFile(myTempDir, "target.txt");
File linkFile = createSymLink(targetFile.getPath(), myTempDir + "/link");
@@ -34,6 +34,7 @@ import org.jdom.Element;
import org.jdom.JDOMException;
import org.jetbrains.annotations.NotNull;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
@@ -55,9 +56,13 @@ public class CoreProjectLoader {
private static void loadDirectoryProject(MockProject project, VirtualFile projectDir) throws IOException, JDOMException,
InvalidDataException {
VirtualFile dotIdea = projectDir.findChild(Project.DIRECTORY_STORE_FOLDER);
assert dotIdea != null;
if (dotIdea == null)
throw new FileNotFoundException("Missing '" + Project.DIRECTORY_STORE_FOLDER + "' in " + projectDir.getPath());
VirtualFile modulesXml = dotIdea.findChild("modules.xml");
assert modulesXml != null;
if (modulesXml == null)
throw new FileNotFoundException("Missing 'modules.xml' in " + dotIdea.getPath());
StorageData storageData = loadStorageFile(project, modulesXml);
final Element moduleManagerState = storageData.getState("ProjectModuleManager");
if (moduleManagerState == null) {
@@ -67,7 +72,8 @@ public class CoreProjectLoader {
moduleManager.loadState(moduleManagerState);
VirtualFile miscXml = dotIdea.findChild("misc.xml");
assert miscXml != null;
if (miscXml == null)
throw new FileNotFoundException("Missing 'misc.xml' in " + dotIdea.getPath());
storageData = loadStorageFile(project, miscXml);
final Element projectRootManagerState = storageData.getState("ProjectRootManager");
if (projectRootManagerState == null) {
@@ -2445,12 +2445,14 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
"}\n";
assertEquals("Find all annotations", 4, findMatchesCount(source2, "@'_Annotation"));
String source3 = "class A {\n" +
String source3 = "class A<@HH T> extends @HH Object {\n" +
" @HH final String s = (@HH String) new @HH Object();\n" +
" final String t = (String) new Object();\n" +
" Map<@HH String, @HH List<@HH String>> map;\n" +
"}\n";
assertEquals("Find annotated casts", 1, findMatchesCount(source3, "(@'_A 'Cast) '_Expression"));
assertEquals("Find annotated new expressions", 1, findMatchesCount(source3, "new @'_A 'Type()"));
assertEquals("Find all annotations 2", 8, findMatchesCount(source3, "@'_Annotation"));
// package-info.java
final String source4 = "/**\n" +
@@ -26,6 +26,7 @@ import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
@@ -362,15 +363,15 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
if (myProject.isDisposed()) return;
TreeUtil.expandAll(myTree);
int listSelection = 0;
int scrollRow = -1;
int selectedListRow = 0;
int selectedTreeRow = -1;
if (myShowCheckboxes) {
if (myIncludedChanges.size() > 0) {
for (int i = 0; i < sortedChanges.size(); i++) {
T t = sortedChanges.get(i);
if (myIncludedChanges.contains(t)) {
listSelection = i;
selectedListRow = i;
break;
}
}
@@ -393,46 +394,32 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
@SuppressWarnings("unchecked")
final CheckboxTree.NodeState state = getNodeStatus(node);
if (state == CheckboxTree.NodeState.FULL && node.isLeaf()) {
scrollRow = myTree.getRowForPath(new TreePath(node.getPath()));
selectedTreeRow = myTree.getRowForPath(new TreePath(node.getPath()));
break;
}
}
}
} else {
if (toSelect != null) {
ChangesBrowserNode root = (ChangesBrowserNode)model.getRoot();
final int[] rowToSelect = new int[] {-1};
TreeUtil.traverse(root, new TreeUtil.Traverse() {
@Override
public boolean accept(Object node) {
if (node instanceof DefaultMutableTreeNode) {
Object userObject = ((DefaultMutableTreeNode)node).getUserObject();
if (userObject instanceof Change) {
Change change = (Change)userObject;
VirtualFile virtualFile = change.getVirtualFile();
if ((virtualFile != null && virtualFile.equals(toSelect)) || seemsToBeMoved(change, toSelect)) {
TreeNode[] path = ((DefaultMutableTreeNode)node).getPath();
rowToSelect[0] = myTree.getRowForPath(new TreePath(path));
}
}
}
return rowToSelect[0] == -1;
}
});
scrollRow = rowToSelect[0] == -1 ? scrollRow : rowToSelect[0];
int rowInTree = findRowContainingFile((TreeNode)model.getRoot(), toSelect);
if (rowInTree > -1) {
selectedTreeRow = rowInTree;
}
int rowInList = findRowContainingFile(myList.getModel(), toSelect);
if (rowInList > -1) {
selectedListRow = rowInList;
}
}
}
if (changes.size() > 0) {
myList.setSelectedIndex(listSelection);
myList.ensureIndexIsVisible(listSelection);
myList.setSelectedIndex(selectedListRow);
myList.ensureIndexIsVisible(selectedListRow);
if (scrollRow >= 0) {
myTree.setSelectionRow(scrollRow);
if (selectedTreeRow >= 0) {
myTree.setSelectionRow(selectedTreeRow);
}
TreeUtil.showRowCentered(myTree, scrollRow, false);
TreeUtil.showRowCentered(myTree, selectedTreeRow, false);
}
}
};
@@ -443,6 +430,50 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
}
}
private static int findRowContainingFile(@NotNull ListModel listModel, @Nullable final VirtualFile toSelect) {
if (toSelect == null) {
return -1;
}
for (int i = 0; i < listModel.getSize(); i++) {
Object item = listModel.getElementAt(i);
if (item instanceof Change && matches((Change)item, toSelect)) {
return i;
}
}
return -1;
}
private int findRowContainingFile(@NotNull TreeNode root, @Nullable final VirtualFile toSelect) {
if (toSelect == null) {
return -1;
}
final Ref<Integer> row = Ref.create(-1);
TreeUtil.traverse(root, new TreeUtil.Traverse() {
@Override
public boolean accept(Object node) {
if (node instanceof DefaultMutableTreeNode) {
Object userObject = ((DefaultMutableTreeNode)node).getUserObject();
if (userObject instanceof Change) {
if (matches((Change)userObject, toSelect)) {
TreeNode[] path = ((DefaultMutableTreeNode)node).getPath();
row.set(myTree.getRowForPath(new TreePath(path)));
}
}
}
return row.get() == -1;
}
});
return row.get();
}
private static boolean matches(@NotNull Change change, @NotNull VirtualFile file) {
VirtualFile virtualFile = change.getVirtualFile();
return virtualFile != null && virtualFile.equals(file) || seemsToBeMoved(change, file);
}
private static boolean seemsToBeMoved(Change change, VirtualFile toSelect) {
ContentRevision afterRevision = change.getAfterRevision();
if (afterRevision == null) return false;
@@ -20,11 +20,12 @@ import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Set;
public class ExpectedTypeUtils {
@@ -56,13 +57,13 @@ public class ExpectedTypeUtils {
/**
* @noinspection StaticCollection
*/
private static final Set<IElementType> arithmeticOps = new HashSet<IElementType>(5);
private static final Set<IElementType> arithmeticOps = new THashSet<IElementType>(5);
private static final Set<IElementType> booleanOps = new HashSet<IElementType>(5);
private static final Set<IElementType> booleanOps = new THashSet<IElementType>(5);
private static final Set<IElementType> shiftOps = new HashSet<IElementType>(3);
private static final Set<IElementType> shiftOps = new THashSet<IElementType>(3);
private static final Set<IElementType> operatorAssignmentOps = new HashSet<IElementType>(11);
private static final Set<IElementType> operatorAssignmentOps = new THashSet<IElementType>(11);
static {
arithmeticOps.add(JavaTokenType.PLUS);
@@ -611,13 +612,7 @@ public class ExpectedTypeUtils {
}
private static int getParameterPosition(@NotNull PsiExpressionList expressionList, PsiExpression expression) {
final PsiExpression[] expressions = expressionList.getExpressions();
for (int i = 0; i < expressions.length; i++) {
if (expressions[i].equals(expression)) {
return i;
}
}
return -1;
return ArrayUtil.indexOf(expressionList.getExpressions(), expression);
}
@Nullable
+1 -1
View File
@@ -155,7 +155,7 @@ public class GitVcs extends AbstractVcs<CommittedChangeList> {
myRollbackEnvironment = gitRollbackEnvironment;
myRevSelector = new GitRevisionSelector();
myConfigurable = new GitVcsConfigurable(myProject, gitProjectSettings, sharedSettings);
myUpdateEnvironment = new GitUpdateEnvironment(myProject, this, gitProjectSettings);
myUpdateEnvironment = new GitUpdateEnvironment(myProject, gitProjectSettings);
myCommittedChangeListProvider = new GitCommittedChangeListProvider(myProject);
myOutgoingChangesProvider = new GitOutgoingChangesProvider(myProject);
myTreeDiffProvider = new GitTreeDiffProvider(myProject);
@@ -52,6 +52,7 @@ import git4idea.repo.GitRepositoryManager;
import git4idea.update.GitRebaseOverMergeProblem;
import git4idea.update.GitUpdateProcess;
import git4idea.update.GitUpdateResult;
import git4idea.update.GitUpdater;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -383,7 +384,8 @@ public class GitPushOperation {
private void savePushUpdateSettings(@NotNull PushUpdateSettings settings, boolean rebaseOverMergeDetected) {
UpdateMethod updateMethod = settings.getUpdateMethod();
mySettings.setUpdateAllRootsIfPushRejected(settings.shouldUpdateAllRoots());
if (!rebaseOverMergeDetected) { // don't overwrite explicit "rebase" with temporary "merge" caused by merge commits
if (!rebaseOverMergeDetected // don't overwrite explicit "rebase" with temporary "merge" caused by merge commits
&& mySettings.getUpdateType() != updateMethod && mySettings.getUpdateType() != UpdateMethod.BRANCH_DEFAULT) { // don't overwrite "branch default" setting
mySettings.setUpdateType(updateMethod);
}
}
@@ -392,6 +394,10 @@ public class GitPushOperation {
private PushUpdateSettings readPushUpdateSettings() {
boolean updateAllRoots = mySettings.shouldUpdateAllRootsIfPushRejected();
UpdateMethod updateMethod = mySettings.getUpdateType();
if (updateMethod == UpdateMethod.BRANCH_DEFAULT) {
// deliberate limitation: we have only 2 buttons => choose method from the 1st repo if different
updateMethod = GitUpdater.resolveUpdateMethod(myProject, myPushSpecs.keySet().iterator().next().getRoot());
}
return new PushUpdateSettings(updateAllRoots, updateMethod);
}
@@ -429,12 +435,9 @@ public class GitPushOperation {
protected GitUpdateResult update(@NotNull Collection<GitRepository> rootsToUpdate,
@NotNull UpdateMethod updateMethod,
boolean checkForRebaseOverMergeProblem) {
GitUpdateProcess.UpdateMethod um = updateMethod == UpdateMethod.MERGE ?
GitUpdateProcess.UpdateMethod.MERGE :
GitUpdateProcess.UpdateMethod.REBASE;
GitUpdateResult updateResult = new GitUpdateProcess(myProject, myPlatformFacade, myProgressIndicator,
new HashSet<GitRepository>(rootsToUpdate), UpdatedFiles.create(),
checkForRebaseOverMergeProblem).update(um);
checkForRebaseOverMergeProblem).update(updateMethod);
for (GitRepository repository : rootsToUpdate) {
repository.getRoot().refresh(true, true);
repository.update();
@@ -220,6 +220,12 @@ class GitRejectedPushUpdateDialog extends DialogWrapper {
return myRebaseOverMergeProblemDetected;
}
@TestOnly
@NotNull
Action getDefaultAction() {
return Boolean.TRUE.equals(myMergeAction.getValue(DEFAULT_ACTION)) ? myMergeAction : myRebaseAction;
}
private class MergeAction extends AbstractAction {
MergeAction() {
super("&Merge");
@@ -16,7 +16,6 @@
package git4idea.update;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
@@ -29,7 +28,6 @@ import com.intellij.openapi.vcs.update.UpdateSession;
import com.intellij.openapi.vcs.update.UpdatedFiles;
import com.intellij.openapi.vfs.VirtualFile;
import git4idea.GitPlatformFacade;
import git4idea.GitVcs;
import git4idea.config.GitVcsSettings;
import git4idea.repo.GitRepositoryManager;
import org.jetbrains.annotations.NotNull;
@@ -41,21 +39,12 @@ import java.util.Set;
import static git4idea.GitUtil.*;
/**
* Git update environment implementation. The environment does
* {@code git pull -v} for each vcs root. Rebase variant is detected
* and processed as well.
*/
public class GitUpdateEnvironment implements UpdateEnvironment {
private final GitVcs myVcs;
private final Project myProject;
private final GitVcsSettings mySettings;
@NotNull private final GitPlatformFacade myPlatformFacade;
private static final Logger LOG = Logger.getInstance(GitUpdateEnvironment.class);
public GitUpdateEnvironment(@NotNull Project project, @NotNull GitVcs vcs, GitVcsSettings settings) {
myVcs = vcs;
public GitUpdateEnvironment(@NotNull Project project, @NotNull GitVcsSettings settings) {
myProject = project;
mySettings = settings;
myPlatformFacade = ServiceManager.getService(project, GitPlatformFacade.class);
@@ -72,7 +61,7 @@ public class GitUpdateEnvironment implements UpdateEnvironment {
final GitUpdateProcess gitUpdateProcess = new GitUpdateProcess(myProject, myPlatformFacade,
progressIndicator, getRepositoriesFromRoots(repositoryManager, roots),
updatedFiles, true);
boolean result = gitUpdateProcess.update(GitUpdateProcess.UpdateMethod.READ_FROM_SETTINGS).isSuccess();
boolean result = gitUpdateProcess.update(mySettings.getUpdateType()).isSuccess();
return new GitUpdateSession(result);
}
@@ -45,6 +45,7 @@ import git4idea.GitUtil;
import git4idea.branch.GitBranchPair;
import git4idea.branch.GitBranchUtil;
import git4idea.commands.Git;
import git4idea.config.UpdateMethod;
import git4idea.merge.GitConflictResolver;
import git4idea.merge.GitMergeCommittingConflictResolver;
import git4idea.merge.GitMerger;
@@ -83,12 +84,6 @@ public class GitUpdateProcess {
private GitUpdateResult myResult;
private final Collection<VirtualFile> myRootsToSave;
public enum UpdateMethod {
MERGE,
REBASE,
READ_FROM_SETTINGS
}
public GitUpdateProcess(@NotNull Project project,
@NotNull GitPlatformFacade platformFacade,
@Nullable ProgressIndicator progressIndicator,
@@ -298,15 +293,8 @@ public class GitUpdateProcess {
LOG.info("updateImpl: defining updaters...");
for (GitRepository repository : myRepositories) {
VirtualFile root = repository.getRoot();
final GitUpdater updater;
if (updateMethod == UpdateMethod.MERGE) {
updater = new GitMergeUpdater(myProject, myGit, root, myTrackedBranches, myProgressIndicator, myUpdatedFiles);
} else if (updateMethod == UpdateMethod.REBASE) {
updater = new GitRebaseUpdater(myProject, myGit, root, myTrackedBranches, myProgressIndicator, myUpdatedFiles);
} else {
updater = GitUpdater.getUpdater(myProject, myGit, myTrackedBranches, root, myProgressIndicator, myUpdatedFiles);
}
GitUpdater updater = GitUpdater.getUpdater(myProject, myGit, myTrackedBranches, root, myProgressIndicator, myUpdatedFiles,
updateMethod);
if (updater.isUpdateNeeded()) {
updaters.put(root, updater);
}
@@ -29,7 +29,7 @@ import git4idea.commands.Git;
import git4idea.commands.GitCommand;
import git4idea.commands.GitSimpleHandler;
import git4idea.config.GitConfigUtil;
import git4idea.config.GitVcsSettings;
import git4idea.config.UpdateMethod;
import git4idea.merge.MergeChangeCollector;
import git4idea.repo.GitRepositoryManager;
import org.jetbrains.annotations.NotNull;
@@ -76,43 +76,35 @@ public abstract class GitUpdater {
* @return {@link GitMergeUpdater} or {@link GitRebaseUpdater}.
*/
@NotNull
public static GitUpdater getUpdater(@NotNull Project project, @NotNull Git git, @NotNull Map<VirtualFile, GitBranchPair> trackedBranches,
@NotNull VirtualFile root, @NotNull ProgressIndicator progressIndicator,
@NotNull UpdatedFiles updatedFiles) {
final GitVcsSettings settings = GitVcsSettings.getInstance(project);
if (settings == null) {
return getDefaultUpdaterForBranch(project, git, root, trackedBranches, progressIndicator, updatedFiles);
public static GitUpdater getUpdater(@NotNull Project project,
@NotNull Git git,
@NotNull Map<VirtualFile, GitBranchPair> trackedBranches,
@NotNull VirtualFile root,
@NotNull ProgressIndicator progressIndicator,
@NotNull UpdatedFiles updatedFiles,
@NotNull UpdateMethod updateMethod) {
if (updateMethod == UpdateMethod.BRANCH_DEFAULT) {
updateMethod = resolveUpdateMethod(project, root);
}
switch (settings.getUpdateType()) {
case REBASE:
return new GitRebaseUpdater(project, git, root, trackedBranches, progressIndicator, updatedFiles);
case MERGE:
return new GitMergeUpdater(project, git, root, trackedBranches, progressIndicator, updatedFiles);
case BRANCH_DEFAULT:
// use default for the branch
return getDefaultUpdaterForBranch(project, git, root, trackedBranches, progressIndicator, updatedFiles);
}
return getDefaultUpdaterForBranch(project, git, root, trackedBranches, progressIndicator, updatedFiles);
return updateMethod == UpdateMethod.REBASE ?
new GitRebaseUpdater(project, git, root, trackedBranches, progressIndicator, updatedFiles):
new GitMergeUpdater(project, git, root, trackedBranches, progressIndicator, updatedFiles);
}
@NotNull
private static GitUpdater getDefaultUpdaterForBranch(@NotNull Project project, @NotNull Git git, @NotNull VirtualFile root,
@NotNull Map<VirtualFile, GitBranchPair> trackedBranches,
@NotNull ProgressIndicator progressIndicator, @NotNull UpdatedFiles updatedFiles) {
try {
GitLocalBranch branch = GitBranchUtil.getCurrentBranch(project, root);
boolean rebase = false;
if (branch != null) {
public static UpdateMethod resolveUpdateMethod(@NotNull Project project, @NotNull VirtualFile root) {
GitLocalBranch branch = GitBranchUtil.getCurrentBranch(project, root);
boolean rebase = false;
if (branch != null) {
try {
String rebaseValue = GitConfigUtil.getValue(project, root, "branch." + branch.getName() + ".rebase");
rebase = rebaseValue != null && rebaseValue.equalsIgnoreCase("true");
}
if (rebase) {
return new GitRebaseUpdater(project, git, root, trackedBranches, progressIndicator, updatedFiles);
catch (VcsException e) {
LOG.warn("Couldn't get git config branch." + branch.getName() + ".rebase", e);
}
} catch (VcsException e) {
LOG.info("getDefaultUpdaterForBranch branch", e);
}
return new GitMergeUpdater(project, git, root, trackedBranches, progressIndicator, updatedFiles);
return rebase ? UpdateMethod.REBASE : UpdateMethod.MERGE;
}
@NotNull
@@ -18,7 +18,6 @@ package git4idea.push;
import com.intellij.dvcs.push.PushSpec;
import com.intellij.dvcs.push.PushSupport;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Trinity;
import com.intellij.openapi.vcs.AbstractVcsHelper;
@@ -148,9 +147,9 @@ abstract class GitPushOperationBaseTest extends GitPlatformTest {
}
protected void agreeToUpdate(final int exitCode) {
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler() {
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler<GitRejectedPushUpdateDialog>() {
@Override
public int handleDialog(DialogWrapper dialog) {
public int handleDialog(GitRejectedPushUpdateDialog dialog) {
return exitCode;
}
});
@@ -18,6 +18,7 @@ package git4idea.push;
import com.intellij.dvcs.push.PushSpec;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.Trinity;
import com.intellij.openapi.util.io.FileUtil;
@@ -36,6 +37,7 @@ import git4idea.update.GitUpdateResult;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
@@ -47,6 +49,7 @@ import static git4idea.test.GitExecutor.*;
import static git4idea.test.GitTestUtil.makeCommit;
import static java.util.Collections.singletonMap;
@SuppressWarnings("StringToUpperCaseOrToLowerCaseWithoutLocale")
public class GitPushOperationSingleRepoTest extends GitPushOperationBaseTest {
protected GitRepository myRepository;
@@ -121,9 +124,9 @@ public class GitPushOperationSingleRepoTest extends GitPushOperationBaseTest {
pushCommitFromBro();
final Ref<Boolean> dialogShown = Ref.create(false);
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler() {
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler<GitRejectedPushUpdateDialog>() {
@Override
public int handleDialog(DialogWrapper dialog) {
public int handleDialog(GitRejectedPushUpdateDialog dialog) {
dialogShown.set(true);
return DialogWrapper.CANCEL_EXIT_CODE;
}
@@ -141,9 +144,9 @@ public class GitPushOperationSingleRepoTest extends GitPushOperationBaseTest {
git("checkout -b feature");
final Ref<Boolean> dialogShown = Ref.create(false);
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler() {
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler<GitRejectedPushUpdateDialog>() {
@Override
public int handleDialog(DialogWrapper dialog) {
public int handleDialog(GitRejectedPushUpdateDialog dialog) {
dialogShown.set(true);
return DialogWrapper.CANCEL_EXIT_CODE;
}
@@ -188,6 +191,50 @@ public class GitPushOperationSingleRepoTest extends GitPushOperationBaseTest {
assertFalse("The commit shouldn't be pushed", history.contains(hash));
}
public void test_use_selected_update_method_for_all_consecutive_updates() throws IOException {
pushCommitFromBro();
cd(myRepository);
makeCommit("afile.txt");
agreeToUpdate(GitRejectedPushUpdateDialog.REBASE_EXIT_CODE);
refresh();
PushSpec<GitPushSource, GitPushTarget> pushSpec = makePushSpec(myRepository, "master", "origin/master");
GitPushResult result = new GitPushOperation(myProject, myPushSupport, singletonMap(myRepository, pushSpec), null, false) {
boolean updateHappened;
@NotNull
@Override
protected GitUpdateResult update(@NotNull Collection<GitRepository> rootsToUpdate,
@NotNull UpdateMethod updateMethod,
boolean checkForRebaseOverMergeProblem) {
GitUpdateResult updateResult = super.update(rootsToUpdate, updateMethod, checkForRebaseOverMergeProblem);
try {
if (!updateHappened) {
updateHappened = true;
pushCommitFromBro();
}
}
catch (IOException e) {
throw new RuntimeException(e);
}
return updateResult;
}
}.execute();
assertResult(SUCCESS, 1, "master", "origin/master", GitUpdateResult.SUCCESS, result.getResults().get(myRepository));
cd(myRepository);
String[] commitMessages = StringUtil.splitByLines(log("--pretty=%s"));
boolean mergeCommitsInTheLog = ContainerUtil.exists(commitMessages, new Condition<String>() {
@Override
public boolean value(String s) {
return s.toLowerCase().contains("merge");
}
});
assertFalse("Unexpected merge commits when rebase method is selected", mergeCommitsInTheLog);
}
public void test_force_push() throws IOException {
String lostHash = pushCommitFromBro();
cd(myRepository);
@@ -305,6 +352,64 @@ public class GitPushOperationSingleRepoTest extends GitPushOperationBaseTest {
UpdateMethod.REBASE, myGitSettings.getUpdateType());
}
public void test_respect_branch_default_setting_for_rejected_push_dialog() throws IOException {
generateUpdateNeeded();
myGitSettings.setUpdateType(UpdateMethod.BRANCH_DEFAULT);
git("config branch.master.rebase true");
final Ref<String> defaultActionName = Ref.create();
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler<GitRejectedPushUpdateDialog>() {
@Override
public int handleDialog(@NotNull GitRejectedPushUpdateDialog dialog) {
defaultActionName.set((String)dialog.getDefaultAction().getValue(Action.NAME));
return DialogWrapper.CANCEL_EXIT_CODE;
}
});
push("master", "origin/master");
assertTrue("Default action in rejected-push dialog is incorrect: " + defaultActionName.get(),
defaultActionName.get().toLowerCase().contains("rebase"));
git("config branch.master.rebase false");
push("master", "origin/master");
assertTrue("Default action in rejected-push dialog is incorrect: " + defaultActionName.get(),
defaultActionName.get().toLowerCase().contains("merge"));
}
public void test_respect_branch_default_setting_for_silent_update_when_rejected_push() throws IOException {
generateUpdateNeeded();
myGitSettings.setUpdateType(UpdateMethod.BRANCH_DEFAULT);
git("config branch.master.rebase true");
myGitSettings.setAutoUpdateIfPushRejected(true);
push("master", "origin/master");
assertFalse("Unexpected merge commit: rebase should have happened", log("-1 --pretty=%s").toLowerCase().startsWith("merge"));
}
// there is no "branch default" choice in the rejected push dialog
// => simply don't rewrite the setting if the same value is chosen, as was default value initially
public void test_dont_overwrite_branch_default_setting_when_agree_in_rejected_push_dialog() throws IOException {
generateUpdateNeeded();
myGitSettings.setUpdateType(UpdateMethod.BRANCH_DEFAULT);
git("config branch.master.rebase true");
myDialogManager.registerDialogHandler(GitRejectedPushUpdateDialog.class, new TestDialogHandler<GitRejectedPushUpdateDialog>() {
@Override
public int handleDialog(@NotNull GitRejectedPushUpdateDialog dialog) {
return GitRejectedPushUpdateDialog.REBASE_EXIT_CODE;
}
});
push("master", "origin/master");
assertEquals(UpdateMethod.BRANCH_DEFAULT, myGitSettings.getUpdateType());
}
private void generateUpdateNeeded() throws IOException {
pushCommitFromBro();
cd(myRepository);
makeCommit("file.txt");
}
private void generateUnpushedMergedCommitProblem() throws IOException {
pushCommitFromBro();
cd(myRepository);
@@ -48,8 +48,15 @@ public class TestDialogManager extends DialogManager {
@Override
protected void showDialog(@NotNull DialogWrapper dialog) {
TestDialogHandler handler = myHandlers.get(dialog.getClass());
int exitCode = handler != null ? handler.handleDialog(dialog) : DialogWrapper.OK_EXIT_CODE;
dialog.close(exitCode, exitCode == DialogWrapper.OK_EXIT_CODE);
int exitCode = DialogWrapper.OK_EXIT_CODE;
try {
if (handler != null) {
exitCode = handler.handleDialog(dialog);
}
}
finally {
dialog.close(exitCode, exitCode == DialogWrapper.OK_EXIT_CODE);
}
}
@Override
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.actions;
import com.google.common.collect.Lists;
import com.intellij.execution.ExecutionHelper;
import com.intellij.execution.console.LanguageConsoleView;
import com.intellij.execution.process.ProcessHandler;
@@ -28,6 +29,7 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Consumer;
import com.intellij.util.NotNullFunction;
import com.jetbrains.python.console.PyCodeExecutor;
@@ -191,7 +193,8 @@ public class PyExecuteSelectionAction extends AnAction {
PythonConsoleToolWindow toolWindow = PythonConsoleToolWindow.getInstance(project);
if (toolWindow != null && toolWindow.getToolWindow().isVisible()) {
return toolWindow.getConsoleContentDescriptors();
RunContentDescriptor selectedContentDescriptor = toolWindow.getSelectedContentDescriptor();
return selectedContentDescriptor != null ? Lists.newArrayList(selectedContentDescriptor) : Lists.<RunContentDescriptor>newArrayList();
}
Collection<RunContentDescriptor> descriptors =
@@ -45,6 +45,14 @@ import java.util.List;
public class PythonConsoleToolWindow {
public static final Key<RunContentDescriptor> CONTENT_DESCRIPTOR = Key.create("CONTENT_DESCRIPTOR");
public static final Function<Content, RunContentDescriptor>
CONTENT_TO_DESCRIPTOR_FUNCTION = new Function<Content, RunContentDescriptor>() {
@Override
public RunContentDescriptor apply(@Nullable Content input) {
return input != null ? input.getUserData(CONTENT_DESCRIPTOR) : null;
}
};
private final Project myProject;
private boolean myInitialized = false;
@@ -61,12 +69,7 @@ public class PythonConsoleToolWindow {
public List<RunContentDescriptor> getConsoleContentDescriptors() {
return FluentIterable.from(Lists.newArrayList(getToolWindow().getContentManager().getContents()))
.transform(new Function<Content, RunContentDescriptor>() {
@Override
public RunContentDescriptor apply(@Nullable Content input) {
return input != null ? input.getUserData(CONTENT_DESCRIPTOR) : null;
}
}).filter(
.transform(CONTENT_TO_DESCRIPTOR_FUNCTION).filter(
Predicates.notNull()).toList();
}
@@ -172,4 +175,9 @@ public class PythonConsoleToolWindow {
myActivation.doWhenDone(runnable);
getToolWindow().activate(null);
}
@Nullable
public RunContentDescriptor getSelectedContentDescriptor() {
return CONTENT_TO_DESCRIPTOR_FUNCTION.apply(getToolWindow().getContentManager().getSelectedContent());
}
}
+10 -2
View File
@@ -159,6 +159,14 @@
<option name="HTML_TEXT" value="true"/>
</context>
</template>
<template description="&lt;link rel=&quot;import&quot; href=&quot;&quot;&gt;"
name="link:import" toReformat="true" toShortenFQNames="true"
value="&lt;link rel=&quot;import&quot; href=&quot;$HTML$.html&quot;/&gt;">
<variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="HTML"/>
<context>
<option name="HTML_TEXT" value="true"/>
</context>
</template>
<template description="&lt;link rel=&quot;import&quot; href=&quot;&quot;&gt;"
name="link:im" toReformat="true" toShortenFQNames="true"
value="&lt;link rel=&quot;import&quot; href=&quot;$HTML$.html&quot;/&gt;">
@@ -397,13 +405,13 @@
<option name="HTML_TEXT" value="true"/>
</context>
</template>
<template description="&lt;input name=&quot;...&quot; type=&quot;hidden&quot;/&gt;" name="input:hidden" toReformat="true" toShortenFQNames="true" value="&lt;input name=&quot;$VAR0$&quot; type=&quot;hidden&quot;/&gt;">
<template description="&lt;input type=&quot;hidden&quot; name=&quot;...&quot;/&gt;" name="input:hidden" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;hidden&quot; name=&quot;$VAR0$&quot; /&gt;">
<variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
<context>
<option name="HTML_TEXT" value="true"/>
</context>
</template>
<template description="&lt;input name=&quot;...&quot; type=&quot;hidden&quot;/&gt;" name="input:h" toReformat="true" toShortenFQNames="true" value="&lt;input name=&quot;$VAR0$&quot; type=&quot;hidden&quot;/&gt;">
<template description="&lt;input type=&quot;hidden&quot; name=&quot;...&quot;/&gt;" name="input:h" toReformat="true" toShortenFQNames="true" value="&lt;input type=&quot;hidden&quot; name=&quot;$VAR0$&quot;/&gt;">
<variable alwaysStopAt="true" defaultValue="&quot;&quot;" expression="" name="VAR0"/>
<context>
<option name="HTML_TEXT" value="true"/>
@@ -22,13 +22,9 @@ import com.intellij.openapi.command.undo.UndoConstants;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.XmlElementFactory;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ArrayUtil;
import com.intellij.util.LocalTimeCounter;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -100,7 +96,7 @@ public class TemplateToken extends ZenCodingToken {
String templateString = template.getString();
final PsiFileFactory psiFileFactory = PsiFileFactory.getInstance(callback.getProject());
if (!containsAttrsVar(template)) {
XmlFile dummyFile = (XmlFile)psiFileFactory.createFileFromText("dummy.xml", StdFileTypes.XML, templateString);
XmlFile dummyFile = (XmlFile)psiFileFactory.createFileFromText("dummy.xml", StdFileTypes.HTML, templateString);
dummyRootTag = dummyFile.getRootTag();
if (dummyRootTag != null) {
addMissingAttributes(dummyRootTag, attributes);
@@ -119,30 +115,14 @@ public class TemplateToken extends ZenCodingToken {
private static void addMissingAttributes(@NotNull XmlTag tag, @NotNull Map<String, String> attributes) {
Map<String, String> missingAttributes = ContainerUtil.newLinkedHashMap();
for (Map.Entry<String, String> attribute : attributes.entrySet()) {
if (!XmlEmmetParser.DEFAULT_ATTRIBUTE_NAME.equals(attribute.getKey()) && tag.getAttribute(attribute.getKey()) == null) {
missingAttributes.put(attribute.getKey(), attribute.getValue());
}
}
addAttributesBefore(tag, missingAttributes);
}
private static void addAttributesBefore(@NotNull XmlTag tag, @NotNull Map<String, String> attributes) {
XmlAttribute firstAttribute = ArrayUtil.getFirstElement(tag.getAttributes());
XmlElementFactory factory = XmlElementFactory.getInstance(tag.getProject());
for (String name : attributes.keySet()) {
XmlAttribute xmlAttribute = factory.createXmlAttribute(name, "");
if (firstAttribute != null) {
tag.addBefore(xmlAttribute, firstAttribute);
}
else {
tag.add(xmlAttribute);
tag.setAttribute(attribute.getKey(), "");
}
}
}
@Nullable
public TemplateImpl getTemplate() {
return myTemplate;
@@ -21,6 +21,7 @@ import com.intellij.lang.dtd.DTDLanguage;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.util.SimpleFieldCache;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.filters.ClassFilter;
import com.intellij.psi.scope.processor.FilterElementProcessor;
import com.intellij.psi.search.PsiElementProcessor;
@@ -32,6 +33,7 @@ import com.intellij.xml.XmlElementDescriptor;
import com.intellij.xml.XmlNSDescriptorEx;
import com.intellij.xml.impl.ExternalDocumentValidator;
import com.intellij.xml.util.XmlUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -95,8 +97,8 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
}
public XmlElementDescriptor[] getElements() {
final Collection<XmlElementDescriptor> delcarations = buildDeclarationMap().values();
return delcarations.toArray(new XmlElementDescriptor[delcarations.size()]);
final Collection<XmlElementDescriptor> declarations = buildDeclarationMap().values();
return declarations.toArray(new XmlElementDescriptor[declarations.size()]);
}
private Map<String,XmlElementDescriptor> buildDeclarationMap() {
@@ -111,16 +113,24 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
final List<XmlElementDecl> result = new ArrayList<XmlElementDecl>();
myElement.processElements(new FilterElementProcessor(new ClassFilter(XmlElementDecl.class), result), getDeclaration());
final Map<String, XmlElementDescriptor> ret = new LinkedHashMap<String, XmlElementDescriptor>((int)(result.size() * 1.5));
Set<PsiFile> dependencies = new THashSet<PsiFile>(1);
dependencies.add(myDescriptorFile);
for (final XmlElementDecl xmlElementDecl : result) {
final String name = xmlElementDecl.getName();
if (name != null) {
if (!ret.containsKey(name)) {
ret.put(name, new XmlElementDescriptorImpl(xmlElementDecl));
// if element descriptor was produced from entity reference use proper dependency
PsiElement dependingElement = xmlElementDecl.getUserData(XmlElement.DEPENDING_ELEMENT);
if (dependingElement != null) {
PsiFile dependingElementContainingFile = dependingElement.getContainingFile();
if (dependingElementContainingFile != null) dependencies.add(dependingElementContainingFile);
}
}
}
}
return new Result<Map<String, XmlElementDescriptor>>(ret, myDescriptorFile);
return new Result<Map<String, XmlElementDescriptor>>(ret, dependencies.toArray());
}
}, false);
}