mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
+20
-1
@@ -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)
|
||||
|
||||
|
||||
@@ -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"))}")
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-20
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+20
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -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) {
|
||||
|
||||
-12
@@ -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();
|
||||
}
|
||||
|
||||
+21
@@ -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;
|
||||
}
|
||||
|
||||
-54
@@ -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;
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
@@ -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) {
|
||||
|
||||
+3
-1
@@ -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;
|
||||
|
||||
+7
-12
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +159,14 @@
|
||||
<option name="HTML_TEXT" value="true"/>
|
||||
</context>
|
||||
</template>
|
||||
<template description="<link rel="import" href="">"
|
||||
name="link:import" toReformat="true" toShortenFQNames="true"
|
||||
value="<link rel="import" href="$HTML$.html"/>">
|
||||
<variable alwaysStopAt="true" defaultValue="""" expression="" name="HTML"/>
|
||||
<context>
|
||||
<option name="HTML_TEXT" value="true"/>
|
||||
</context>
|
||||
</template>
|
||||
<template description="<link rel="import" href="">"
|
||||
name="link:im" toReformat="true" toShortenFQNames="true"
|
||||
value="<link rel="import" href="$HTML$.html"/>">
|
||||
@@ -397,13 +405,13 @@
|
||||
<option name="HTML_TEXT" value="true"/>
|
||||
</context>
|
||||
</template>
|
||||
<template description="<input name="..." type="hidden"/>" name="input:hidden" toReformat="true" toShortenFQNames="true" value="<input name="$VAR0$" type="hidden"/>">
|
||||
<template description="<input type="hidden" name="..."/>" name="input:hidden" toReformat="true" toShortenFQNames="true" value="<input type="hidden" name="$VAR0$" />">
|
||||
<variable alwaysStopAt="true" defaultValue="""" expression="" name="VAR0"/>
|
||||
<context>
|
||||
<option name="HTML_TEXT" value="true"/>
|
||||
</context>
|
||||
</template>
|
||||
<template description="<input name="..." type="hidden"/>" name="input:h" toReformat="true" toShortenFQNames="true" value="<input name="$VAR0$" type="hidden"/>">
|
||||
<template description="<input type="hidden" name="..."/>" name="input:h" toReformat="true" toShortenFQNames="true" value="<input type="hidden" name="$VAR0$"/>">
|
||||
<variable alwaysStopAt="true" defaultValue="""" 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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user