From a521a78b9391645c1fe50df00b915b3132b0c005 Mon Sep 17 00:00:00 2001 From: nik Date: Thu, 31 Mar 2011 16:41:58 +0400 Subject: [PATCH 01/32] enabled libbreakgen library on Mac --- .../runners/ProcessProxyFactoryImpl.java | 11 +++++++- .../rt/execution/application/AppMain.java | 27 ++++++++++++------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java b/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java index e8764d29657d..6af48770e78d 100644 --- a/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java +++ b/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java @@ -54,7 +54,16 @@ public class ProcessProxyFactoryImpl extends ProcessProxyFactory { @Override public boolean isBreakGenLibraryAvailable() { - @NonNls final String libName = SystemInfo.isWindows ? "breakgen.dll" : "libbreakgen.so"; + @NonNls final String libName; + if (SystemInfo.isWindows) { + libName = "breakgen.dll"; + } + else if (SystemInfo.isMac) { + libName = "libbreakgen.jnilib"; + } + else { + libName = "libbreakgen.so"; + } return new File(PathManager.getBinPath() + File.separator + libName).exists(); } } \ No newline at end of file diff --git a/java/java-runtime/src/com/intellij/rt/execution/application/AppMain.java b/java/java-runtime/src/com/intellij/rt/execution/application/AppMain.java index 09e6dd5f12aa..1d723e246cae 100644 --- a/java/java-runtime/src/com/intellij/rt/execution/application/AppMain.java +++ b/java/java-runtime/src/com/intellij/rt/execution/application/AppMain.java @@ -38,20 +38,28 @@ public class AppMain { static { String binPath = System.getProperty(PROPERTY_BINPATH) + File.separator; final String osName = System.getProperty("os.name").toLowerCase(); + String arch = System.getProperty("os.arch").toLowerCase(); String libPath = null; if (osName.startsWith("windows")) { - if (System.getProperty("os.arch").equals("amd64")) { + if (arch.equals("amd64")) { libPath = binPath + "breakgen64.dll"; } else { libPath = binPath + "breakgen.dll"; } } else if (osName.startsWith("linux")) { - if (System.getProperty("os.arch").toLowerCase().equals("amd64")) { + if (arch.equals("amd64")) { libPath = binPath + "libbreakgen64.so"; } else { libPath = binPath + "libbreakgen.so"; } + } else if (osName.startsWith("mac")) { + if (arch.endsWith("64")) { + libPath = binPath + "libbreakgen64.jnilib"; + } else { + libPath = binPath + "libbreakgen.jnilib"; + } + } try { if (libPath != null) { @@ -59,7 +67,9 @@ public class AppMain { } } catch (UnsatisfiedLinkError e) { - //Do nothing, unknown os or some other error => no ctrl-break is available + if (new File(libPath).exists() && osName.startsWith("mac")) { + e.printStackTrace(); + } } } @@ -86,19 +96,16 @@ public class AppMain { System.exit(1); } } - } catch (IOException e) { - return; - } catch (IllegalArgumentException iae) { - return; - } catch (SecurityException se) { - return; + } catch (IOException ignored) { + } catch (IllegalArgumentException ignored) { + } catch (SecurityException ignored) { } } }, "Monitor Ctrl-Break"); try { t.setDaemon(true); t.start(); - } catch (Exception e) {} + } catch (Exception ignored) {} String mainClass = args[0]; String[] parms = new String[args.length - 1]; From 3135647879f2b7fdf889ce874d6e6e40e29219f1 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 31 Mar 2011 14:48:50 +0200 Subject: [PATCH 02/32] IDEA-33331 (Inspection String.equals("") on JDK 5 or up should use String.isEmpty in quickfix) --- .../siyeh/InspectionGadgetsBundle.properties | 1 + ...andomDoubleForRandomIntegerInspection.java | 12 +++- .../StringEqualsEmptyStringInspection.java | 63 +++++++++++++++---- 3 files changed, 61 insertions(+), 15 deletions(-) diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 381cf82b5185..a4c29893292e 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1291,6 +1291,7 @@ string.buffer.to.string.in.concatenation.remove.quickfix=Remove 'toString()' string.concatenation.in.loops.only.option=Only warn if string is repeatedly appended string.concatenation.inside.string.buffer.append.replace.quickfix=Replace with chained append() calls string.equals.empty.string.replace.quickfix=Replace with 'length()==0' +string.equals.empty.string.replace.quickfix2=Replace with 'isEmpty()' tail.recursion.replace.quickfix=Replace tail recursion with iteration if.statement.with.too.many.branches.max.option=Maximum number of branches: if.statement.with.too.many.branches.problem.descriptor='#ref' has too many branches ({0}) #loc diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/RandomDoubleForRandomIntegerInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/RandomDoubleForRandomIntegerInspection.java index 34722f22cc61..e6ae0cbbad7d 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/RandomDoubleForRandomIntegerInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/RandomDoubleForRandomIntegerInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,23 +32,27 @@ import org.jetbrains.annotations.Nullable; public class RandomDoubleForRandomIntegerInspection extends BaseInspection { + @Override @NotNull public String getID() { return "UsingRandomNextDoubleForRandomInteger"; } + @Override @NotNull public String getDisplayName() { return InspectionGadgetsBundle.message( "random.double.for.random.integer.display.name"); } + @Override @NotNull protected String buildErrorString(Object... infos) { return InspectionGadgetsBundle.message( "random.double.for.random.integer.problem.descriptor"); } + @Override public InspectionGadgetsFix buildFix(Object... infos) { return new RandomDoubleForRandomIntegerFix(); } @@ -62,6 +66,7 @@ public class RandomDoubleForRandomIntegerInspection "random.double.for.random.integer.replace.quickfix"); } + @Override public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { final PsiIdentifier name = @@ -103,11 +108,12 @@ public class RandomDoubleForRandomIntegerInspection } } + @Override public BaseInspectionVisitor buildVisitor() { - return new StringEqualsEmptyStringVisitor(); + return new RandomDoubleForRandomIntegerVisitor(); } - private static class StringEqualsEmptyStringVisitor + private static class RandomDoubleForRandomIntegerVisitor extends BaseInspectionVisitor { @Override public void visitMethodCallExpression( diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java index 54a922119ff4..20a4130181ee 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package com.siyeh.ig.performance; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.IncorrectOperationException; import com.siyeh.HardcodedMethodConstants; import com.siyeh.InspectionGadgetsBundle; @@ -48,16 +49,39 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { @Override public InspectionGadgetsFix buildFix(Object... infos) { - return new StringEqualsEmptyStringFix(); + return new StringEqualsEmptyStringFix((PsiMethodCallExpression)infos[0]); } private static class StringEqualsEmptyStringFix extends InspectionGadgetsFix { + private final boolean useIsEmpty; + + public StringEqualsEmptyStringFix(PsiMethodCallExpression call) { + final Project project = call.getProject(); + final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); + final GlobalSearchScope scope = call.getResolveScope(); + final PsiClass stringClass = + psiFacade.findClass(CommonClassNames.JAVA_LANG_STRING, + scope); + if (stringClass != null) { + final PsiMethod[] methods = + stringClass.findMethodsByName("isEmpty", false); + useIsEmpty = methods.length > 0; + } else { + useIsEmpty = false; + } + } + @NotNull public String getName() { - return InspectionGadgetsBundle.message( - "string.equals.empty.string.replace.quickfix"); + if (useIsEmpty) { + return InspectionGadgetsBundle.message( + "string.equals.empty.string.replace.quickfix2"); + } else { + return InspectionGadgetsBundle.message( + "string.equals.empty.string.replace.quickfix"); + } } @Override @@ -72,7 +96,8 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { } final PsiExpression call = (PsiExpression)expression.getParent(); final PsiExpression qualifier = expression.getQualifierExpression(); - final String qualifierText = getRemainingText(qualifier); + final String qualifierText = + getRemainingText(qualifier, useIsEmpty); if (call == null) { return; } @@ -80,19 +105,33 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { if (parent instanceof PsiExpression) { final PsiExpression parentExpression = (PsiExpression) parent; if(BoolUtils.isNegation(parentExpression)) { - replaceExpression(parentExpression, - qualifierText + ".length()!=0"); + if (useIsEmpty) { + replaceExpression(parentExpression, + '!' + qualifierText + ".isEmpty()"); + } else { + replaceExpression(parentExpression, + qualifierText + ".length()!=0"); + } + } else { + if (useIsEmpty) { + replaceExpression(call, qualifier + ".isEmpty()"); + } else { + replaceExpression(call, qualifierText + ".length()==0"); + } + } + } else { + if (useIsEmpty) { + replaceExpression(call, qualifierText + ".isEmpty()"); } else { replaceExpression(call, qualifierText + ".length()==0"); } - } else { - replaceExpression(call, qualifierText + ".length()==0"); } } - private static String getRemainingText(PsiExpression qualifier) { + private static String getRemainingText(PsiExpression qualifier, + boolean useIsEmpty) { final String qualifierText; - if (qualifier instanceof PsiMethodCallExpression) { + if (!useIsEmpty && qualifier instanceof PsiMethodCallExpression) { // to replace stringBuffer.toString().equals("") with // stringBuffer.length() == 0 final PsiMethodCallExpression callExpression = @@ -163,7 +202,7 @@ public class StringEqualsEmptyStringInspection extends BaseInspection { // produce uncompilable code (out of merely incorrect code). return; } - registerMethodCallError(call); + registerMethodCallError(call, call); } } } \ No newline at end of file From 469ac12475b5feba8b1cc88df67b5ac15c6acc7a Mon Sep 17 00:00:00 2001 From: andrey zaytsev Date: Thu, 31 Mar 2011 16:51:44 +0400 Subject: [PATCH 03/32] IDEA-67268: in-selection-only state was preserved when switching from replace to find. --- .../src/com/intellij/find/FindUtil.java | 28 +++++++++++++++ .../editorHeaderActions/SwitchToFind.java | 5 ++- .../editorHeaderActions/SwitchToReplace.java | 5 ++- .../editor/actions/IncrementalFindAction.java | 35 ++----------------- 4 files changed, 39 insertions(+), 34 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/find/FindUtil.java b/platform/lang-impl/src/com/intellij/find/FindUtil.java index 8d830f886b2b..15d2712b1db7 100644 --- a/platform/lang-impl/src/com/intellij/find/FindUtil.java +++ b/platform/lang-impl/src/com/intellij/find/FindUtil.java @@ -95,6 +95,34 @@ public class FindUtil { } } + public static void configureFindModel(boolean replace, Editor editor, FindModel model) { + String selectedText = editor.getSelectionModel().getSelectedText(); + model.setReplaceState(replace); + if (selectedText != null) { + if (replace) { + if (!StringUtil.isEmpty(selectedText)) { + if (selectedText.indexOf('\n') >= 0) { + model.setGlobal(false); + } + else { + model.setStringToFind(selectedText); + model.setGlobal(true); + } + } else { + model.setGlobal(true); + } + } else { + model.setStringToFind(selectedText); + model.setGlobal(true); + } + + if (model.isGlobal()) { + model.setStringToFind(selectedText); + } + } + model.setPromptOnReplace(false); + } + private enum Direction { UP, DOWN } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java index 211f6d81d56c..6ac05693cb50 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java @@ -1,6 +1,8 @@ package com.intellij.find.editorHeaderActions; import com.intellij.find.EditorSearchComponent; +import com.intellij.find.FindModel; +import com.intellij.find.FindUtil; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -24,6 +26,7 @@ public class SwitchToFind extends EditorHeaderAction { @Override public void actionPerformed(AnActionEvent e) { - getEditorSearchComponent().getFindModel().setReplaceState(false); + final FindModel findModel = getEditorSearchComponent().getFindModel(); + FindUtil.configureFindModel(false, getEditorSearchComponent().getEditor(), findModel); } } diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java index ce67a8ce799c..33272a0b0299 100644 --- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java +++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java @@ -1,6 +1,8 @@ package com.intellij.find.editorHeaderActions; import com.intellij.find.EditorSearchComponent; +import com.intellij.find.FindModel; +import com.intellij.find.FindUtil; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -23,6 +25,7 @@ public class SwitchToReplace extends EditorHeaderAction { @Override public void actionPerformed(AnActionEvent e) { - getEditorSearchComponent().getFindModel().setReplaceState(true); + final FindModel findModel = getEditorSearchComponent().getFindModel(); + FindUtil.configureFindModel(true, getEditorSearchComponent().getEditor(), findModel); } } diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java index 761d56877b36..760d88f95feb 100644 --- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java +++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/IncrementalFindAction.java @@ -19,6 +19,7 @@ package com.intellij.openapi.editor.actions; import com.intellij.find.EditorSearchComponent; import com.intellij.find.FindManager; import com.intellij.find.FindModel; +import com.intellij.find.FindUtil; import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; @@ -26,7 +27,6 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorAction; import com.intellij.openapi.editor.actionSystem.EditorActionHandler; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; import javax.swing.*; @@ -49,10 +49,7 @@ public class IncrementalFindAction extends EditorAction { if (!myReplace) { headerComponent.requestFocus(); } - if (myReplace != editorSearchComponent.getFindModel().isReplaceState()){ - editorSearchComponent.getFindModel().setReplaceState(myReplace); - } - configureFindModel(editor, editorSearchComponent.getFindModel()); + FindUtil.configureFindModel(myReplace, editor, editorSearchComponent.getFindModel()); } else { FindManager findManager = FindManager.getInstance(project); FindModel model; @@ -62,7 +59,7 @@ public class IncrementalFindAction extends EditorAction { model = new FindModel(); model.copyFrom(findManager.getFindInFileModel()); } - configureFindModel(editor, model); + FindUtil.configureFindModel(myReplace, editor, model); final EditorSearchComponent header = new EditorSearchComponent(editor, project, model); editor.setHeaderComponent(header); header.requestFocus(); @@ -70,32 +67,6 @@ public class IncrementalFindAction extends EditorAction { } } - private void configureFindModel(Editor editor, FindModel model) { - String selectedText = editor.getSelectionModel().getSelectedText(); - if (selectedText != null) { - if (myReplace) { - if (!StringUtil.isEmpty(selectedText)) { - if (selectedText.indexOf('\n') >= 0) { - model.setGlobal(false); - } - else { - model.setStringToFind(selectedText); - model.setGlobal(true); - } - } else { - model.setGlobal(true); - } - } else { - model.setStringToFind(selectedText); - } - - if (model.isGlobal()) { - model.setStringToFind(selectedText); - } - } - model.setPromptOnReplace(false); - } - public boolean isEnabled(Editor editor, DataContext dataContext) { Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(editor.getComponent())); return project != null && !editor.isOneLineMode(); From 4805a2d4ba22819e2454b5d702d3e66ef965f4bd Mon Sep 17 00:00:00 2001 From: Gregory Shrago Date: Thu, 31 Mar 2011 16:55:55 +0400 Subject: [PATCH 04/32] IDEA-67274 Console: scroll to the output end --- .../intellij/execution/console/LanguageConsoleImpl.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java index b8d9a8af9e27..7b1c7bd590f9 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java @@ -369,7 +369,6 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { public String addCurrentToHistory(final TextRange textRange, final boolean erase, final boolean preserveMarkup) { final Ref ref = Ref.create(""); - final boolean scrollToEnd = shouldScrollHistoryToEnd(); final Runnable action = new Runnable() { public void run() { ref.set(addTextRangeToHistory(textRange, myConsoleEditor, preserveMarkup)); @@ -384,10 +383,9 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { else { ApplicationManager.getApplication().runReadAction(action); } - if (scrollToEnd) { - scrollHistoryToEnd(); - } - queueUiUpdate(scrollToEnd); + // always scroll to end on user input + scrollHistoryToEnd(); + queueUiUpdate(true); return ref.get(); } From 90b98e50e5e56477d5e524e20ccfbdc9fd624825 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 31 Mar 2011 15:09:15 +0200 Subject: [PATCH 05/32] IDEA-67325 (Quickfix for "Manual array to collection copy" should use java.util.Collections.addAll instead of Collection.addAll(Arrays.asList())) --- .../siyeh/InspectionGadgetsBundle.properties | 2 +- ...ManualArrayToCollectionCopyInspection.java | 44 ++++++++++++------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index a4c29893292e..9b8042e92c18 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1282,7 +1282,7 @@ string.can.be.simplified.problem.descriptor=#ref can be simplified string.replace.quickfix=Replace with ''{0}'' instantiating.object.to.get.class.object.replace.quickfix=Replace with direct class object access manual.array.copy.replace.quickfix=Replace with 'System.arrayCopy()' -manual.array.to.collection.copy.replace.quickfix=Replace with 'Collection.addAll(Arrays.asList())' +manual.array.to.collection.copy.replace.quickfix=Replace with 'Collections.addAll(...,...)' method.may.be.static.only.option=Only check private or final methods method.may.be.static.empty.option=Ignore empty methods random.double.for.random.integer.replace.quickfix=Replace with 'nextInt()' diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ManualArrayToCollectionCopyInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ManualArrayToCollectionCopyInspection.java index 040d0ecfe925..b0823fec2333 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ManualArrayToCollectionCopyInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ManualArrayToCollectionCopyInspection.java @@ -120,11 +120,12 @@ public class ManualArrayToCollectionCopyInspection extends BaseInspection { return null; } final String arrayText = iteratedValue.getText(); - @NonNls final StringBuilder buffer = new StringBuilder(60); + @NonNls final StringBuilder buffer = + new StringBuilder("java.util.Collections.addAll("); buffer.append(collectionText); - buffer.append(".addAll(java.util.Arrays.asList("); + buffer.append(','); buffer.append(arrayText); - buffer.append("));"); + buffer.append(");"); return buffer.toString(); } @@ -189,24 +190,33 @@ public class ManualArrayToCollectionCopyInspection extends BaseInspection { if (toOffsetText == null) { return null; } - @NonNls final StringBuilder buffer = new StringBuilder(); - if (collectionText.length() > 0) { + if (fromOffsetText.equals("0") && + toOffsetText.equals(arrayText + ".length")) { + @NonNls final StringBuilder buffer = + new StringBuilder("java.util.Collections.addAll("); + buffer.append(collectionText); + buffer.append(','); + buffer.append(arrayText); + buffer.append(");"); + return buffer.toString(); + } else { + @NonNls final StringBuilder buffer = new StringBuilder(); buffer.append(collectionText); buffer.append('.'); - } - buffer.append("addAll(java.util.Arrays.asList("); - buffer.append(arrayText); - buffer.append(')'); - if (!fromOffsetText.equals("0") || - !toOffsetText.equals(arrayText + ".length")) { - buffer.append(".subList("); - buffer.append(fromOffsetText); - buffer.append(", "); - buffer.append(toOffsetText); + buffer.append("addAll(java.util.Arrays.asList("); + buffer.append(arrayText); buffer.append(')'); + if (!fromOffsetText.equals("0") || + !toOffsetText.equals(arrayText + ".length")) { + buffer.append(".subList("); + buffer.append(fromOffsetText); + buffer.append(", "); + buffer.append(toOffsetText); + buffer.append(')'); + } + buffer.append(");"); + return buffer.toString(); } - buffer.append(");"); - return buffer.toString(); } private static PsiArrayAccessExpression getArrayAccessExpression( From 388fea264af5b458c5252b3548702b047731ecbb Mon Sep 17 00:00:00 2001 From: Denis Zhdanov Date: Thu, 31 Mar 2011 17:12:13 +0400 Subject: [PATCH 06/32] IDEA-67327 Undo: Correct bulk undo processing at document end Corrected deferred changes processing during end -> start direction. --- .../intellij/openapi/editor/impl/TextChangesStorage.java | 2 +- .../openapi/editor/impl/TextChangesStorageTest.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/TextChangesStorage.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/TextChangesStorage.java index d2dd97bbdecd..88187b9632d1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/TextChangesStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/TextChangesStorage.java @@ -243,7 +243,7 @@ public class TextChangesStorage { if (newChangeStart <= storedClientStart && newChangeEnd >= storedClientEnd) { myChanges.remove(i); insertionIndex = i; - newChangeEnd -= changeEntry.change.getText().length(); + newChangeEnd -= changeEntry.change.getDiff(); i--; continue; } diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/TextChangesStorageTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/TextChangesStorageTest.java index fb4b164b0e4f..9829c64eff11 100644 --- a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/TextChangesStorageTest.java +++ b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/TextChangesStorageTest.java @@ -109,6 +109,13 @@ public class TextChangesStorageTest { checkChanges(c("", 2, 5)); } + @Test + public void adjacentDeletesFromEndToStart() { + delete(5, 6); + delete(4, 5); + checkChanges(c("", 4, 6)); + } + @Test public void singleReplace() { replace("abc", 3, 4); From b5bd47c636e9b8dc33ca757e9c5d9bea7e5839c7 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 31 Mar 2011 15:27:09 +0200 Subject: [PATCH 07/32] fix python test: if a prefix starts with an underscore, don't allow variants to start with more underscores --- .../com/intellij/psi/codeStyle/NameUtil.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java index c6b1218acdaf..5882dd07e66f 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java +++ b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java @@ -509,22 +509,26 @@ public class NameUtil { return handleAsterisk(patternIndex, words, wordIndex); } + if (patternIndex == 0 && myFirstLetterCaseMatters && word.charAt(0) != myPattern[0]) { + return false; + } + if (isWordSeparator(word.charAt(0))) { assert word.length() == 1 : "'" + word + "'"; - if (isWordSeparator(myPattern[patternIndex])) { + char p = myPattern[patternIndex]; + if (isWordSeparator(p)) { + if (myFirstLetterCaseMatters && + wordIndex == 0 && words.size() > 1 && patternIndex + 1 < myPattern.length && + isWordSeparator(words.get(1).charAt(0)) && !isWordSeparator(myPattern[patternIndex + 1])) { + return false; + } + return matches(patternIndex + 1, words, wordIndex + 1); } - if (patternIndex == 0 && myFirstLetterCaseMatters) { - return false; - } return matches(patternIndex, words, wordIndex + 1); } - if (patternIndex == 0 && myFirstLetterCaseMatters && word.charAt(0) != myPattern[0]) { - return false; - } - if (StringUtil.toLowerCase(word.charAt(0)) != StringUtil.toLowerCase(myPattern[patternIndex])) { return false; } From cdf2da14e1cf63ee6b3b3dc2769e53134cecc63c Mon Sep 17 00:00:00 2001 From: Alexey Pegov Date: Thu, 31 Mar 2011 18:00:32 +0400 Subject: [PATCH 08/32] libbreakgen.jnilib for mac (correct library) --- bin/mac/libbreakgen.jnilib | Bin 37840 -> 8972 bytes bin/mac/libbreakgen64.jnilib | Bin 18608 -> 9000 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/mac/libbreakgen.jnilib b/bin/mac/libbreakgen.jnilib index bfbdee970594f08ce78036e4178818434acb3da4..00c7ad5a7bae45b7fe636fbd5b3c180e3258836c 100644 GIT binary patch literal 8972 zcmeHN-)j_C6uwDTUE8fD1tF!SUF%xw`#=?t-aFG&L!Cu-wj%o6VTnnQ>-z zlL&$!rCoi=gHNUS*uS8KQuMM)R^Z7v=~$^fxQ8zhTY;aF`^>4lqo0FkK@J4V zRpo^$O6|cM*AZKVpK=)TU&?aOma^loyS^h`ejR{5|A*k40CWV`Mcr%kAbC} zotZz?Y|P|$p$aGW4_U#TVGP&i^a_;Y;Bj!@&v8f?oj5YQz&1U@b1gD{R;0|emh$V) zCM@x`5SJ&gnz{LiQAp;=>D{UjH5jvyXCS$E&VLP?_oA_1h+BBv%g{MbO3w+&UGSds z&OeLZLp*WZPOrnk=LF;5|8Z&P=vP0Uxaz!f?%X~;^GG(A;y8Q>R({t0DbH@kiE7uU zvm;_&lSV)zpb^jrXaqC@8Uc-fMnEI*A|tTW`}NB2gTxy6Mz(%%Mq3&Ijetf#BcKt`2xtT}0vZ90 zfJQ(gpb^jryyysw?Js})YW3<{;c&Pw99|G(ljy%X{l>Y4zBd}@3m3$exKJLOlr5En zu0yK=Yt8k%+S2^Y^7|7Lhv7uKQ+{N2O=$;hw96CadG2``B~ooDyOX$qFU>IYT-!|b zsW6-~U0)`V+iI!k!@y6Xz?)_pSezOWciv2Ux=sf00mximfW9&^B<_B3eU9Hk>KORl zV-I94)9Gh_nEx}NK93>S9XddtK<))I_6B7CC&V`e{kwwBo-x15fF{YgT@}VstfJV6 zLrTW4hydjxmGx6SbA&nu&^w!F4O0Zz!wNdW!$F nbza#?e8>-?Hv0GO;bTV!Rt4gD-GS$pC%d)V?&}lRT!?=FGCym( literal 37840 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 DmNa`D literal 18608 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 Date: Thu, 31 Mar 2011 14:08:39 +0200 Subject: [PATCH 09/32] check accessibility without access object (IDEA-67220) --- .../codeInsight/generation/GenerateConstructorHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateConstructorHandler.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateConstructorHandler.java index 0419d0b848c5..39e6d067c411 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateConstructorHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateConstructorHandler.java @@ -84,7 +84,7 @@ public class GenerateConstructorHandler extends GenerateMembersHandlerBase { if (baseClass != null){ ArrayList array = new ArrayList(); for (PsiMethod method : baseClass.getConstructors()) { - if (JavaPsiFacade.getInstance(method.getProject()).getResolveHelper().isAccessible(method, aClass, aClass)) { + if (JavaPsiFacade.getInstance(method.getProject()).getResolveHelper().isAccessible(method, aClass, null)) { array.add(method); } } From 6f8b67665c643f168fee086819c4f6436315f7f2 Mon Sep 17 00:00:00 2001 From: anna Date: Thu, 31 Mar 2011 15:56:35 +0200 Subject: [PATCH 10/32] unimplement interface in generics case: check by subst. signature (IDEA-67230 ) --- .../actions/UnimplementInterfaceAction.java | 43 ++++++++++++++++--- .../quickFix/unimplement/afterGenerics.java | 11 +++++ .../quickFix/unimplement/beforeGenerics.java | 12 ++++++ 3 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unimplement/afterGenerics.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unimplement/beforeGenerics.java diff --git a/java/java-impl/src/com/intellij/codeInspection/actions/UnimplementInterfaceAction.java b/java/java-impl/src/com/intellij/codeInspection/actions/UnimplementInterfaceAction.java index d0ac9310e4c4..9275c149ac0f 100644 --- a/java/java-impl/src/com/intellij/codeInspection/actions/UnimplementInterfaceAction.java +++ b/java/java-impl/src/com/intellij/codeInspection/actions/UnimplementInterfaceAction.java @@ -21,12 +21,18 @@ import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.MethodSignatureUtil; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Collections; import java.util.HashSet; +import java.util.Map; import java.util.Set; public class UnimplementInterfaceAction implements IntentionAction { @@ -55,7 +61,10 @@ public class UnimplementInterfaceAction implements IntentionAction { if (psiClass.getExtendsList() != referenceList && psiClass.getImplementsList() != referenceList) return false; - final PsiElement target = psiReference.resolve(); + PsiJavaCodeReferenceElement referenceElement = getTopLevelRef(psiReference, referenceList); + if (referenceElement == null) return false; + + final PsiElement target = referenceElement.resolve(); if (target == null || !(target instanceof PsiClass)) return false; PsiClass targetClass = (PsiClass)target; @@ -69,6 +78,18 @@ public class UnimplementInterfaceAction implements IntentionAction { return true; } + @Nullable + private static PsiJavaCodeReferenceElement getTopLevelRef(PsiReference psiReference, PsiReferenceList referenceList) { + PsiElement element = psiReference.getElement(); + while (element.getParent() != referenceList) { + element = element.getParent(); + if (element == null) return null; + } + + if (!(element instanceof PsiJavaCodeReferenceElement)) return null; + return (PsiJavaCodeReferenceElement)element; + } + public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { if (!CodeInsightUtilBase.preparePsiElementForWrite(file)) return; @@ -83,12 +104,22 @@ public class UnimplementInterfaceAction implements IntentionAction { if (psiClass.getExtendsList() != referenceList && psiClass.getImplementsList() != referenceList) return; - final PsiElement target = psiReference.resolve(); + PsiJavaCodeReferenceElement element = getTopLevelRef(psiReference, referenceList); + if (element == null) return; + + final PsiElement target = element.resolve(); if (target == null || !(target instanceof PsiClass)) return; PsiClass targetClass = (PsiClass)target; - psiReference.getElement().delete(); + final Map implementations = new HashMap(); + for (PsiMethod psiMethod : targetClass.getAllMethods()) { + final PsiMethod implementingMethod = MethodSignatureUtil.findMethodBySuperMethod(psiClass, psiMethod, false); + if (implementingMethod != null) { + implementations.put(psiMethod, implementingMethod); + } + } + element.delete(); final Set superMethods = new HashSet(); for (PsiClass aClass : psiClass.getSupers()) { @@ -97,10 +128,8 @@ public class UnimplementInterfaceAction implements IntentionAction { final PsiMethod[] psiMethods = targetClass.getAllMethods(); for (PsiMethod psiMethod : psiMethods) { if (superMethods.contains(psiMethod)) continue; - final PsiMethod[] implementingMethods = psiClass.findMethodsBySignature(psiMethod, false); - for (PsiMethod implementingMethod : implementingMethods) { - implementingMethod.delete(); - } + final PsiMethod impl = implementations.get(psiMethod); + if (impl != null) impl.delete(); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unimplement/afterGenerics.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unimplement/afterGenerics.java new file mode 100644 index 000000000000..e050a74b282b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unimplement/afterGenerics.java @@ -0,0 +1,11 @@ +// "Unimplement Interface" "true" +class A { + public String toString() { + return super.toString(); + } + +} + +interface II { + void foo(T ty); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unimplement/beforeGenerics.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unimplement/beforeGenerics.java new file mode 100644 index 000000000000..efeddf023d92 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/unimplement/beforeGenerics.java @@ -0,0 +1,12 @@ +// "Unimplement Interface" "true" +class A implements IItring> { + public String toString() { + return super.toString(); + } + + public void foo(String ty){} +} + +interface II { + void foo(T ty); +} \ No newline at end of file From a8559ea3b92d0a80b872a1c49233f9eaeac95c14 Mon Sep 17 00:00:00 2001 From: anna Date: Thu, 31 Mar 2011 16:23:15 +0200 Subject: [PATCH 11/32] enable dnd in favorites view (IDEA-67055 ) --- .../intellij/ide/favoritesTreeView/FavoritesProjectViewPane.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesProjectViewPane.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesProjectViewPane.java index cc1ad6ea1de3..e8784e009f83 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesProjectViewPane.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesProjectViewPane.java @@ -102,6 +102,7 @@ public class FavoritesProjectViewPane extends AbstractProjectViewPane { setTreeBuilder(myViewPanel.getBuilder()); myTreeStructure = myViewPanel.getFavoritesTreeStructure(); installComparator(); + enableDnD(); return myViewPanel; } From 2d007678590dd5342751cde480a2ad7383b4fb55 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Thu, 31 Mar 2011 18:32:32 +0400 Subject: [PATCH 12/32] if alarm is disposed -> NO startLoading [TBR=kirillk] --- .../src/com/intellij/openapi/ui/LoadingDecorator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java b/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java index a4012a2abedb..5b2c78eba050 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/LoadingDecorator.java @@ -75,7 +75,7 @@ public class LoadingDecorator { } public void startLoading(final boolean takeSnapshot) { - if (isLoading() || myStartRequest) return; + if (isLoading() || myStartRequest || myStartAlarm.isDisposed()) return; myStartRequest = true; if (myDelay > 0) { From 842a5b752b1e864e98b5fac565388bdfae97b130 Mon Sep 17 00:00:00 2001 From: Gregory Shrago Date: Thu, 31 Mar 2011 19:21:02 +0400 Subject: [PATCH 13/32] minor console fixes & IDEA-67273 --- .../console/ConsoleHistoryController.java | 15 ++++++++------- .../execution/console/LanguageConsoleImpl.java | 3 ++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java b/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java index 04abc29cb262..d66706965d60 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java +++ b/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java @@ -29,8 +29,8 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.editor.actions.ContentChooser; -import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectEx; import com.intellij.openapi.util.Disposer; @@ -120,9 +120,9 @@ public class ConsoleHistoryController { myHistoryNext.registerCustomShortcutSet(KeyEvent.VK_UP, 0, null); myHistoryPrev.registerCustomShortcutSet(KeyEvent.VK_DOWN, 0, null); } - myHistoryNext.registerCustomShortcutSet(myHistoryNext.getShortcutSet(), myConsole.getConsoleEditor().getComponent()); - myHistoryPrev.registerCustomShortcutSet(myHistoryPrev.getShortcutSet(), myConsole.getConsoleEditor().getComponent()); - myBrowseHistory.registerCustomShortcutSet(myBrowseHistory.getShortcutSet(), myConsole.getConsoleEditor().getComponent()); + myHistoryNext.registerCustomShortcutSet(myHistoryNext.getShortcutSet(), myConsole.getCurrentEditor().getComponent()); + myHistoryPrev.registerCustomShortcutSet(myHistoryPrev.getShortcutSet(), myConsole.getCurrentEditor().getComponent()); + myBrowseHistory.registerCustomShortcutSet(myBrowseHistory.getShortcutSet(), myConsole.getCurrentEditor().getComponent()); } private File getFile() { @@ -214,12 +214,13 @@ public class ConsoleHistoryController { } protected void actionTriggered(final String command) { - final Editor editor = myConsole.getConsoleEditor(); + final Editor editor = myConsole.getCurrentEditor(); final Document document = editor.getDocument(); new WriteCommandAction(myConsole.getProject(), myConsole.getFile()) { protected void run(final Result result) throws Throwable { document.setText(StringUtil.notNullize(command)); editor.getCaretModel().moveToOffset(document.getTextLength()); + editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } }.execute(); } @@ -247,7 +248,7 @@ public class ConsoleHistoryController { } private boolean canMoveInEditor(final boolean next) { - final EditorEx consoleEditor = myConsole.getConsoleEditor(); + final Editor consoleEditor = myConsole.getCurrentEditor(); final Document document = consoleEditor.getDocument(); final CaretModel caretModel = consoleEditor.getCaretModel(); @@ -283,7 +284,7 @@ public class ConsoleHistoryController { } private void saveHistory(final XmlSerializer out) throws IOException { - out.startDocument(null, null); + out.startDocument(System.getProperty("file.encoding"), null); out.startTag(null, "console-history"); out.attribute(null, "id", myId); for (String s : myModel.getHistory()) { diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java index 7b1c7bd590f9..84a174bd6ed7 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java @@ -293,7 +293,8 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { } public void setPrompt(String prompt) { - myPrompt = prompt; + // always add space to the prompt otherwise it may look ugly + myPrompt = prompt != null && !prompt.endsWith(" ")? prompt + " " : prompt; setPromptInner(myPrompt); } From 8056eb3d19745b668efec0d65ed09f0d312cbb8f Mon Sep 17 00:00:00 2001 From: irengrig Date: Tue, 29 Mar 2011 16:07:32 +0400 Subject: [PATCH 14/32] EA-25672 NPE in IgnoreUnversionedAction --- .../openapi/vcs/changes/actions/IgnoreUnversionedAction.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/IgnoreUnversionedAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/IgnoreUnversionedAction.java index d37f9d9400b1..b62bf35cba7d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/IgnoreUnversionedAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/IgnoreUnversionedAction.java @@ -59,7 +59,9 @@ public class IgnoreUnversionedAction extends AnAction { public void update(AnActionEvent e) { List files = e.getData(ChangesListView.UNVERSIONED_FILES_DATA_KEY); - removeNullFiles(files); + if (files != null) { + removeNullFiles(files); + } boolean enabled = files != null && !files.isEmpty(); e.getPresentation().setEnabled(enabled); e.getPresentation().setVisible(enabled); From 2036fd094f4dea71bbcd03aaca122b959525c53d Mon Sep 17 00:00:00 2001 From: irengrig Date: Tue, 29 Mar 2011 19:25:38 +0400 Subject: [PATCH 15/32] VCS: always show update results, ask to merge etc, also for canceled/failed update --- .../openapi/progress/ProgressManager.java | 13 ++++ .../src/messages/VcsBundle.properties | 2 + .../vcs/ex/ProjectLevelVcsManagerEx.java | 5 +- .../vcs/impl/ProjectLevelVcsManagerImpl.java | 9 +-- .../update/AbstractCommonUpdateAction.java | 59 ++++++++----------- .../openapi/vcs/update/RestoreUpdateTree.java | 3 +- .../src/git4idea/merge/GitMergeUtil.java | 2 +- .../integrate/SvnIntegrateChangesTask.java | 2 +- ...AbstractSvnUpdateIntegrateEnvironment.java | 4 +- 9 files changed, 56 insertions(+), 43 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/progress/ProgressManager.java b/platform/platform-api/src/com/intellij/openapi/progress/ProgressManager.java index 3f4bb6d27e4d..0962c9e473bd 100644 --- a/platform/platform-api/src/com/intellij/openapi/progress/ProgressManager.java +++ b/platform/platform-api/src/com/intellij/openapi/progress/ProgressManager.java @@ -48,6 +48,19 @@ public abstract class ProgressManager { } } + public static void progress(final String text) throws ProcessCanceledException { + progress(text, ""); + } + + public static void progress(final String text, @Nullable String text2) throws ProcessCanceledException { + final ProgressIndicator pi = getInstance().getProgressIndicator(); + if (pi != null) { + pi.checkCanceled(); + pi.setText(text); + pi.setText2(text2 == null ? "" : text2); + } + } + protected abstract void doCheckCanceled() throws ProcessCanceledException; @Deprecated diff --git a/platform/platform-resources-en/src/messages/VcsBundle.properties b/platform/platform-resources-en/src/messages/VcsBundle.properties index 32447cc2761c..a2b6931d54fd 100644 --- a/platform/platform-resources-en/src/messages/VcsBundle.properties +++ b/platform/platform-resources-en/src/messages/VcsBundle.properties @@ -197,8 +197,10 @@ message.text.file.is.up.to.date=File is up-to-date message.text.all.files.are.up.to.date=All files are up-to-date progress.text.synchronizing.files=Synchronizing files... progress.text.updating.done=Updating done +progress.text.updating.canceled=Update canceled message.title.vcs.update.errors={0} Errors toolwindow.title.update.action.info={0} Info +toolwindow.title.update.action.canceled.info={0} Info (Canceled) update.tree.node.size.statistics={0,choice, 0#no items|1#1 item|2#{0, number} items} toolwindow.title.update.project=Update Project ({0}) action.name.group.by.packages=Group by Packages diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ProjectLevelVcsManagerEx.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ProjectLevelVcsManagerEx.java index 345dd7a69631..c09dea89e31a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ProjectLevelVcsManagerEx.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ProjectLevelVcsManagerEx.java @@ -45,7 +45,10 @@ public abstract class ProjectLevelVcsManagerEx extends ProjectLevelVcsManager { public abstract void notifyDirectoryMappingChanged(); - public abstract UpdateInfoTree showUpdateProjectInfo(UpdatedFiles updatedFiles, String displayActionName, ActionInfo actionInfo); + public abstract UpdateInfoTree showUpdateProjectInfo(UpdatedFiles updatedFiles, + String displayActionName, + ActionInfo actionInfo, + boolean canceled); public abstract void fireDirectoryMappingsChanged(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java index 9b39feee1779..8468955a9c92 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/ProjectLevelVcsManagerImpl.java @@ -406,18 +406,19 @@ public void addMessageToConsoleWindow(final String message, final TextAttributes } public void showProjectOperationInfo(final UpdatedFiles updatedFiles, String displayActionName) { - showUpdateProjectInfo(updatedFiles, displayActionName, ActionInfo.STATUS); + showUpdateProjectInfo(updatedFiles, displayActionName, ActionInfo.STATUS, false); } - public UpdateInfoTree showUpdateProjectInfo(UpdatedFiles updatedFiles, String displayActionName, ActionInfo actionInfo) { + public UpdateInfoTree showUpdateProjectInfo(UpdatedFiles updatedFiles, String displayActionName, ActionInfo actionInfo, boolean canceled) { if (! myProject.isOpen() || myProject.isDisposed()) return null; ContentManager contentManager = getContentManager(); if (contentManager == null) { return null; // content manager is made null during dispose; flag is set later } final UpdateInfoTree updateInfoTree = new UpdateInfoTree(contentManager, myProject, updatedFiles, displayActionName, actionInfo); - Content content = ContentFactory.SERVICE.getInstance().createContent(updateInfoTree, VcsBundle.message( - "toolwindow.title.update.action.info", displayActionName), true); + Content content = ContentFactory.SERVICE.getInstance().createContent(updateInfoTree, canceled ? + VcsBundle.message("toolwindow.title.update.action.canceled.info", displayActionName) : + VcsBundle.message("toolwindow.title.update.action.info", displayActionName), true); Disposer.register(content, updateInfoTree); ContentsUtil.addContent(contentManager, content, true); ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.VCS).activate(null); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/update/AbstractCommonUpdateAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/update/AbstractCommonUpdateAction.java index 2efe09c3c0a2..5ff22d3535f2 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/update/AbstractCommonUpdateAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/update/AbstractCommonUpdateAction.java @@ -42,13 +42,12 @@ import com.intellij.openapi.vcs.changes.VcsDirtyScopeManagerImpl; import com.intellij.openapi.vcs.changes.committed.CommittedChangesAdapter; import com.intellij.openapi.vcs.changes.committed.CommittedChangesCache; import com.intellij.openapi.vcs.changes.committed.IntoSelfVirtualFileConvertor; -import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager; import com.intellij.openapi.vcs.ex.ProjectLevelVcsManagerEx; +import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; -import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.util.WaitForProgressToShow; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.ui.OptionsDialog; @@ -388,10 +387,7 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction { } } finally { try { - if (progressIndicator != null) { - progressIndicator.setText(VcsBundle.message("progress.text.synchronizing.files")); - progressIndicator.setText2(""); - } + ProgressManager.progress(VcsBundle.message("progress.text.synchronizing.files")); doVfsRefresh(); } finally { if (myProject.isOpen() && (! myProject.isDisposed())) { // not sure @@ -468,13 +464,13 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction { public void onSuccess() { try { - onSuccessImpl(); + onSuccessImpl(false); } finally { releaseIfNeeded(); } } - private void onSuccessImpl() { + private void onSuccessImpl(final boolean wasCanceled) { if ((! myProject.isOpen()) || myProject.isDisposed()) { ProjectManagerEx.getInstanceEx().unblockReloadingProjectOnExternalChanges(); return; @@ -485,11 +481,9 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction { } final boolean continueChainFinal = continueChain; - final boolean someSessionWasCancelled = someSessionWasCanceled(myUpdateSessions); - if (! someSessionWasCancelled) { - for (final UpdateSession updateSession : myUpdateSessions) { - updateSession.onRefreshFilesCompleted(); - } + final boolean someSessionWasCancelled = wasCanceled || someSessionWasCanceled(myUpdateSessions); + for (final UpdateSession updateSession : myUpdateSessions) { + updateSession.onRefreshFilesCompleted(); } if (myActionInfo.canChangeFileStatus()) { @@ -510,8 +504,7 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction { final boolean updateSuccess = (! someSessionWasCancelled) && (myGroupedExceptions.isEmpty()); - if (! someSessionWasCancelled) { - WaitForProgressToShow.runOrInvokeLaterAboveProgress(new Runnable() { + WaitForProgressToShow.runOrInvokeLaterAboveProgress(new Runnable() { public void run() { if (myProject.isDisposed()) { ProjectManagerEx.getInstanceEx().unblockReloadingProjectOnExternalChanges(); @@ -522,22 +515,23 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction { gatherContextInterruptedMessages(); } AbstractVcsHelper.getInstance(myProject).showErrors(myGroupedExceptions, VcsBundle.message("message.title.vcs.update.errors", - getTemplatePresentation().getText())); - } - else { - final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); - if (indicator != null) { - indicator.setText(VcsBundle.message("progress.text.updating.done")); - } + getTemplatePresentation().getText())); + } else if (someSessionWasCancelled) { + ProgressManager.progress(VcsBundle.message("progress.text.updating.canceled")); + } else { + ProgressManager.progress(VcsBundle.message("progress.text.updating.done")); } final boolean noMerged = myUpdatedFiles.getGroupById(FileGroup.MERGED_WITH_CONFLICT_ID).isEmpty(); if (myUpdatedFiles.isEmpty() && myGroupedExceptions.isEmpty()) { - ToolWindowManager.getInstance(myProject).notifyByBalloon( - ChangesViewContentManager.TOOLWINDOW_ID, MessageType.INFO, getAllFilesAreUpToDateMessage(myRoots)); + if (someSessionWasCancelled) { + VcsBalloonProblemNotifier.showOverChangesView(myProject, VcsBundle.message("progress.text.updating.canceled"), MessageType.WARNING); + } else { + VcsBalloonProblemNotifier.showOverChangesView(myProject, getAllFilesAreUpToDateMessage(myRoots), MessageType.INFO); + } } else if (! myUpdatedFiles.isEmpty()) { - showUpdateTree(continueChainFinal && updateSuccess && noMerged); + showUpdateTree(continueChainFinal && updateSuccess && noMerged, someSessionWasCancelled); final CommittedChangesCache cache = CommittedChangesCache.getInstance(myProject); cache.processUpdatedFiles(myUpdatedFiles); @@ -556,11 +550,6 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction { } } }, null, myProject); - } else if (continueChain) { - // since error - showContextInterruptedError(); - ProjectManagerEx.getInstanceEx().unblockReloadingProjectOnExternalChanges(); - } } private void showContextInterruptedError() { @@ -578,11 +567,11 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction { } } - private void showUpdateTree(final boolean willBeContinued) { + private void showUpdateTree(final boolean willBeContinued, final boolean wasCanceled) { RestoreUpdateTree restoreUpdateTree = RestoreUpdateTree.getInstance(myProject); restoreUpdateTree.registerUpdateInformation(myUpdatedFiles, myActionInfo); final String text = getTemplatePresentation().getText() + ((willBeContinued || (myUpdateNumber > 1)) ? ("#" + myUpdateNumber) : ""); - final UpdateInfoTree updateInfoTree = myProjectLevelVcsManager.showUpdateProjectInfo(myUpdatedFiles, text, myActionInfo); + final UpdateInfoTree updateInfoTree = myProjectLevelVcsManager.showUpdateProjectInfo(myUpdatedFiles, text, myActionInfo, wasCanceled); updateInfoTree.setBefore(myBefore); updateInfoTree.setAfter(myAfter); @@ -603,7 +592,11 @@ public abstract class AbstractCommonUpdateAction extends AbstractVcsAction { } public void onCancel() { - onSuccess(); + try { + onSuccessImpl(true); + } finally { + releaseIfNeeded(); + } } } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/update/RestoreUpdateTree.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/update/RestoreUpdateTree.java index 494855842cdd..b838bb97d25c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/update/RestoreUpdateTree.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/update/RestoreUpdateTree.java @@ -48,7 +48,8 @@ public class RestoreUpdateTree implements ProjectComponent, JDOMExternalizable { ActionInfo actionInfo = myUpdateInfo.getActionInfo(); if (actionInfo != null) { ProjectLevelVcsManagerEx.getInstanceEx(myProject).showUpdateProjectInfo(myUpdateInfo.getFileInformation(), - VcsBundle.message("action.display.name.update"), actionInfo); + VcsBundle.message("action.display.name.update"), actionInfo, + false); CommittedChangesCache.getInstance(myProject).refreshIncomingChangesAsync(); } myUpdateInfo = null; diff --git a/plugins/git4idea/src/git4idea/merge/GitMergeUtil.java b/plugins/git4idea/src/git4idea/merge/GitMergeUtil.java index a149f39ade98..41342adb7669 100644 --- a/plugins/git4idea/src/git4idea/merge/GitMergeUtil.java +++ b/plugins/git4idea/src/git4idea/merge/GitMergeUtil.java @@ -170,7 +170,7 @@ public class GitMergeUtil { action.delayTask(new TransactionRunnable() { public void run(List exceptionList) { ProjectLevelVcsManagerEx manager = (ProjectLevelVcsManagerEx)ProjectLevelVcsManager.getInstance(project); - UpdateInfoTree tree = manager.showUpdateProjectInfo(files, actionName, actionInfo); + UpdateInfoTree tree = manager.showUpdateProjectInfo(files, actionName, actionInfo, false); tree.setBefore(beforeLabel); tree.setAfter(LocalHistory.getInstance().putSystemLabel(project, "After update")); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesTask.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesTask.java index 156b9c59dcc7..2307146b8cca 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesTask.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesTask.java @@ -248,7 +248,7 @@ public class SvnIntegrateChangesTask extends Task.Backgroundable { RestoreUpdateTree restoreUpdateTree = RestoreUpdateTree.getInstance(myProject); // action info is actually NOT used restoreUpdateTree.registerUpdateInformation(myAccomulatedFiles.getUpdatedFiles(), ActionInfo.INTEGRATE); - myProjectLevelVcsManager.showUpdateProjectInfo(myAccomulatedFiles.getUpdatedFiles(), myTitle, ActionInfo.INTEGRATE); + myProjectLevelVcsManager.showUpdateProjectInfo(myAccomulatedFiles.getUpdatedFiles(), myTitle, ActionInfo.INTEGRATE, false); } private void doStatus(final Consumer afterStatus) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdateIntegrateEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdateIntegrateEnvironment.java index 40b60d6d147e..71d0735a70da 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdateIntegrateEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdateIntegrateEnvironment.java @@ -89,8 +89,8 @@ public abstract class AbstractSvnUpdateIntegrateEnvironment implements UpdateEnv } }); for (FilePath contentRoot : contentRoots) { - if (progressIndicator != null && progressIndicator.isCanceled()) { - throw new ProcessCanceledException(); + if (progressIndicator != null) { + progressIndicator.checkCanceled(); } final File ioRoot = contentRoot.getIOFile(); if (! ((SvnUpdateContext)context.get()).shouldRunFor(ioRoot)) continue; From b5f28e8d861c048715852ebdf8e8b9151ea9ea76 Mon Sep 17 00:00:00 2001 From: irengrig Date: Thu, 31 Mar 2011 17:12:18 +0400 Subject: [PATCH 16/32] git: restore change lists correctly. Use Continuation for control pass --- .../history/integration/PatchingTestCase.java | 3 +- .../progress/AsynchronousExecution.java | 31 +++ .../continuation/ContinuationContext.java | 42 +++++ .../util/continuation/TaskDescriptor.java | 22 +++ .../diff/impl/patch/formove/PatchApplier.java | 156 ++++++++++----- .../changes/shelf/ShelveChangesManager.java | 96 ++++++---- .../util/continuation/Continuation.java | 178 ++++++++++++++++-- .../checkin/GitPushActiveBranchesDialog.java | 112 +++++------ .../checkout/branches/GitCheckoutProcess.java | 123 ++++++------ .../src/git4idea/history/GitHistoryUtils.java | 11 +- .../src/git4idea/update/GitChangesSaver.java | 68 +++---- .../update/GitShelveChangesSaver.java | 11 +- .../git4idea/update/GitStashChangesSaver.java | 25 ++- .../src/git4idea/update/GitStashUtils.java | 133 ++++++++----- .../git4idea/update/GitUpdateEnvironment.java | 7 +- .../git4idea/update/GitUpdateLikeProcess.java | 82 ++++++++ .../src/git4idea/update/GitUpdateProcess.java | 66 +++---- 17 files changed, 810 insertions(+), 356 deletions(-) create mode 100644 platform/platform-api/src/com/intellij/openapi/progress/AsynchronousExecution.java create mode 100644 plugins/git4idea/src/git4idea/update/GitUpdateLikeProcess.java diff --git a/platform/lvcs-impl/testSrc/com/intellij/history/integration/PatchingTestCase.java b/platform/lvcs-impl/testSrc/com/intellij/history/integration/PatchingTestCase.java index 7056182b1b52..c1f03d8ca360 100644 --- a/platform/lvcs-impl/testSrc/com/intellij/history/integration/PatchingTestCase.java +++ b/platform/lvcs-impl/testSrc/com/intellij/history/integration/PatchingTestCase.java @@ -21,6 +21,7 @@ import com.intellij.openapi.diff.impl.patch.FilePatch; import com.intellij.openapi.diff.impl.patch.PatchReader; import com.intellij.openapi.diff.impl.patch.PatchVirtualFileReader; import com.intellij.openapi.diff.impl.patch.formove.PatchApplier; +import com.intellij.openapi.vcs.changes.LocalChangeList; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; @@ -55,6 +56,6 @@ public abstract class PatchingTestCase extends IntegrationTestCase { patches.add(p); } - new PatchApplier(myProject, myRoot, patches, null, null).execute(); + new PatchApplier(myProject, myRoot, patches, (LocalChangeList) null, null).execute(); } } diff --git a/platform/platform-api/src/com/intellij/openapi/progress/AsynchronousExecution.java b/platform/platform-api/src/com/intellij/openapi/progress/AsynchronousExecution.java new file mode 100644 index 000000000000..72df34aacee3 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/progress/AsynchronousExecution.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.progress; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author irengrig + * Date: 3/30/11 + * Time: 7:55 PM + */ +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.METHOD}) +public @interface AsynchronousExecution { +} diff --git a/platform/vcs-api/src/com/intellij/util/continuation/ContinuationContext.java b/platform/vcs-api/src/com/intellij/util/continuation/ContinuationContext.java index 2a3f66f68e36..017f841458eb 100644 --- a/platform/vcs-api/src/com/intellij/util/continuation/ContinuationContext.java +++ b/platform/vcs-api/src/com/intellij/util/continuation/ContinuationContext.java @@ -16,6 +16,8 @@ package com.intellij.util.continuation; import com.intellij.openapi.vcs.CalledInAny; +import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Arrays; @@ -30,9 +32,18 @@ public interface ContinuationContext { void last(TaskDescriptor... next); @CalledInAny void last(List next); + @CalledInAny + void after(@NotNull TaskDescriptor inQueue, TaskDescriptor... next); + @CalledInAny void cancelEverything(); + void addExceptionHandler(final Class clazz, final Consumer consumer); + boolean handleException(final Exception e); + + void keepExisting(final Object disaster, final Object cure); + void throwDisaster(final Object disaster, final Object cure); + void suspend(); void ping(); @@ -51,6 +62,23 @@ public interface ContinuationContext { public void cancelEverything() { } + @Override + public void addExceptionHandler(Class clazz, Consumer consumer) { + } + + @Override + public boolean handleException(Exception e) { + return false; + } + + @Override + public void throwDisaster(Object disaster, final Object cure) { + } + + @Override + public void keepExisting(Object disaster, Object cure) { + } + @Override public void next(TaskDescriptor... next) { myList.addAll(0, Arrays.asList(next)); @@ -71,6 +99,20 @@ public interface ContinuationContext { myList.addAll(next); } + @Override + public void after(@NotNull TaskDescriptor inQueue, TaskDescriptor... next) { + int idx = -1; + for (int i = 0; i < myList.size(); i++) { + final TaskDescriptor descriptor = myList.get(i); + if (inQueue == descriptor) { + idx = i; + break; + } + } + assert idx != -1; + myList.addAll(idx, Arrays.asList(next)); + } + @Override public void suspend() { } diff --git a/platform/vcs-api/src/com/intellij/util/continuation/TaskDescriptor.java b/platform/vcs-api/src/com/intellij/util/continuation/TaskDescriptor.java index e00ca9eada04..43cf5f149afd 100644 --- a/platform/vcs-api/src/com/intellij/util/continuation/TaskDescriptor.java +++ b/platform/vcs-api/src/com/intellij/util/continuation/TaskDescriptor.java @@ -18,19 +18,33 @@ package com.intellij.util.continuation; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.HashMap; +import java.util.Map; + public abstract class TaskDescriptor { + private boolean myHaveMagicCure; private final String myName; @NotNull private final Where myWhere; + private final Map mySurviveKit; public TaskDescriptor(final String name, @NotNull final Where where) { myName = name; myWhere = where; + mySurviveKit = new HashMap(); } @Nullable public abstract void run(final ContinuationContext context); + public final void addCure(final Object disaster, final Object cure) { + mySurviveKit.put(disaster, cure); + } + @Nullable + public final Object hasCure(final Object disaster) { + return mySurviveKit.get(disaster); + } + public String getName() { return myName; } @@ -39,4 +53,12 @@ public abstract class TaskDescriptor { public Where getWhere() { return myWhere; } + + public boolean isHaveMagicCure() { + return myHaveMagicCure; + } + + public void setHaveMagicCure(boolean haveMagicCure) { + myHaveMagicCure = haveMagicCure; + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java index 2ac0e41e047a..f39ba0bd1da1 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java +++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/patch/formove/PatchApplier.java @@ -26,6 +26,7 @@ import com.intellij.openapi.diff.impl.patch.apply.ApplyTextFilePatch; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.fileTypes.ex.FileTypeChooser; +import com.intellij.openapi.progress.AsynchronousExecution; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.Messages; @@ -46,6 +47,11 @@ import com.intellij.openapi.vfs.newvfs.RefreshSession; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.util.Consumer; import com.intellij.util.WaitForProgressToShow; +import com.intellij.util.continuation.Continuation; +import com.intellij.util.continuation.ContinuationContext; +import com.intellij.util.continuation.TaskDescriptor; +import com.intellij.util.continuation.Where; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; @@ -61,17 +67,16 @@ public class PatchApplier { private final VirtualFile myBaseDirectory; private final List myPatches; private final CustomBinaryPatchApplier myCustomForBinaries; - private final LocalChangeList myTargetChangeList; - + private final Consumer> myToTargetListsMover; private final List myRemainingPatches; private final PathsVerifier myVerifier; public PatchApplier(final Project project, final VirtualFile baseDirectory, final List patches, - final LocalChangeList targetChangeList, final CustomBinaryPatchApplier customForBinaries) { + @Nullable final Consumer> toTargetListsMover, final CustomBinaryPatchApplier customForBinaries) { myProject = project; myBaseDirectory = baseDirectory; myPatches = patches; - myTargetChangeList = targetChangeList; + myToTargetListsMover = toTargetListsMover; myCustomForBinaries = customForBinaries; myRemainingPatches = new ArrayList(); myVerifier = new PathsVerifier(myProject, myBaseDirectory, myPatches, new PathsVerifier.BaseMapper() { @@ -87,38 +92,89 @@ public class PatchApplier { }); } - public ApplyPatchStatus execute() { - return execute(true); + public PatchApplier(final Project project, final VirtualFile baseDirectory, final List patches, + final LocalChangeList targetChangeList, final CustomBinaryPatchApplier customForBinaries) { + this(project, baseDirectory, patches, createMover(project, targetChangeList), customForBinaries); } - public ApplyPatchStatus execute(boolean showSuccessNotification) { - myRemainingPatches.addAll(myPatches); + @Nullable + private static Consumer> createMover(final Project project, final LocalChangeList targetChangeList) { + final ChangeListManager clm = ChangeListManager.getInstance(project); + if (targetChangeList == null || clm.getDefaultListName().equals(targetChangeList.getName())) return null; + return new FilesMover(clm, targetChangeList); + } - final ApplyPatchStatus patchStatus = nonWriteActionPreCheck(); - if (ApplyPatchStatus.FAILURE.equals(patchStatus)) return patchStatus; + @AsynchronousExecution + public void execute() { + execute(true); + } - final ApplyPatchStatus applyStatus = ApplicationManager.getApplication().runReadAction(new Computable() { - public ApplyPatchStatus compute() { - final Ref refStatus = new Ref(ApplyPatchStatus.FAILURE); - CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { - public void run() { - refStatus.set(executeWritable()); - } - }, VcsBundle.message("patch.apply.command"), null); - return refStatus.get(); - } - }); - final ApplyPatchStatus status = ApplyPatchStatus.SUCCESS.equals(patchStatus) ? applyStatus : - ApplyPatchStatus.and(patchStatus, applyStatus); - // listeners finished, all 'legal' file additions/deletions with VCS are done - final TriggerAdditionOrDeletion trigger = new TriggerAdditionOrDeletion(myProject); - addSkippedItems(trigger); - trigger.process(); - if(showSuccessNotification || !ApplyPatchStatus.SUCCESS.equals(status)) { - showApplyStatus(myProject, status); + @AsynchronousExecution + public void execute(boolean showSuccessNotification) { + final Continuation continuation = new Continuation(myProject, true); + final ContinuationContext.GatheringContinuationContext initContext = + new ContinuationContext.GatheringContinuationContext(); + scheduleSelf(showSuccessNotification, initContext); + continuation.run(initContext.getList()); + } + + public class ApplyPatchTask extends TaskDescriptor { + private ApplyPatchStatus myStatus; + private final boolean myShowNotification; + + public ApplyPatchTask(final boolean showNotification) { + super("", Where.AWT); + myShowNotification = showNotification; } - refreshFiles(trigger.getAffected()); - return status; + + @Override + public void run(ContinuationContext context) { + myRemainingPatches.addAll(myPatches); + + final ApplyPatchStatus patchStatus = nonWriteActionPreCheck(); + if (ApplyPatchStatus.FAILURE.equals(patchStatus)) { + if (myShowNotification) { + showApplyStatus(myProject, patchStatus); + } + myStatus = patchStatus; + return; + } + + final ApplyPatchStatus applyStatus = ApplicationManager.getApplication().runReadAction(new Computable() { + public ApplyPatchStatus compute() { + final Ref refStatus = new Ref(ApplyPatchStatus.FAILURE); + CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { + public void run() { + refStatus.set(executeWritable()); + } + }, VcsBundle.message("patch.apply.command"), null); + return refStatus.get(); + } + }); + myStatus = ApplyPatchStatus.SUCCESS.equals(patchStatus) ? applyStatus : + ApplyPatchStatus.and(patchStatus, applyStatus); + // listeners finished, all 'legal' file additions/deletions with VCS are done + final TriggerAdditionOrDeletion trigger = new TriggerAdditionOrDeletion(myProject); + addSkippedItems(trigger); + trigger.process(); + if(myShowNotification || !ApplyPatchStatus.SUCCESS.equals(myStatus)) { + showApplyStatus(myProject, myStatus); + } + refreshFiles(trigger.getAffected(), context); + } + + public ApplyPatchStatus getStatus() { + return myStatus; + } + } + + public ApplyPatchTask createApplyPart(final boolean showSuccessNotification) { + return new ApplyPatchTask(showSuccessNotification); + } + + @AsynchronousExecution + public void scheduleSelf(boolean showSuccessNotification, @NotNull final ContinuationContext context) { + context.next(createApplyPart(showSuccessNotification)); } public static ApplyPatchStatus executePatchGroup(final Collection group) { @@ -151,7 +207,7 @@ public class PatchApplier { trigger.process(); for (PatchApplier applier : group) { - applier.refreshFiles(trigger.getAffected()); + applier.refreshFiles(trigger.getAffected(), null); } showApplyStatus(project, result); return result; @@ -223,19 +279,31 @@ public class PatchApplier { } } - protected void refreshFiles(final Collection additionalDirectly) { + protected void refreshFiles(final Collection additionalDirectly, @Nullable final ContinuationContext context) { final List directlyAffected = myVerifier.getDirectlyAffected(); final List indirectlyAffected = myVerifier.getAllAffected(); directlyAffected.addAll(additionalDirectly); + if (context != null) { + context.suspend(); + } final RefreshSession session = RefreshQueue.getInstance().createSession(false, true, new Runnable() { public void run() { if (myProject.isDisposed()) return; final ChangeListManager changeListManager = ChangeListManager.getInstance(myProject); - if ((myTargetChangeList != null) && (! directlyAffected.isEmpty()) && - (! myTargetChangeList.getName().equals(changeListManager.getDefaultListName()))) { - changeListManager.invokeAfterUpdate(new FilesMover(changeListManager, directlyAffected), InvokeAfterUpdateMode.BACKGROUND_CANCELLABLE, + if (! directlyAffected.isEmpty() && myToTargetListsMover != null) { + changeListManager.invokeAfterUpdate(new Runnable() { + @Override + public void run() { + if (myToTargetListsMover != null) { + myToTargetListsMover.consume(directlyAffected); + } + if (context != null) { + context.ping(); + } + } + }, InvokeAfterUpdateMode.BACKGROUND_CANCELLABLE, VcsBundle.message("change.lists.manager.move.changes.to.list"), new Consumer() { public void consume(final VcsDirtyScopeManager vcsDirtyScopeManager) { @@ -246,6 +314,9 @@ public class PatchApplier { final VcsDirtyScopeManager vcsDirtyScopeManager = VcsDirtyScopeManager.getInstance(myProject); // will schedule update vcsDirtyScopeManager.filePathsDirty(directlyAffected, null); + if (context != null) { + context.ping(); + } } } }); @@ -373,18 +444,19 @@ public class PatchApplier { }, null, project); } - private class FilesMover implements Runnable { + private static class FilesMover implements Consumer> { private final ChangeListManager myChangeListManager; - private final List myDirectlyAffected; + private final LocalChangeList myTargetChangeList; - public FilesMover(final ChangeListManager changeListManager, final List directlyAffected) { + public FilesMover(final ChangeListManager changeListManager, final LocalChangeList targetChangeList) { myChangeListManager = changeListManager; - myDirectlyAffected = directlyAffected; + myTargetChangeList = targetChangeList; } - public void run() { + @Override + public void consume(List directlyAffected) { List changes = new ArrayList(); - for(FilePath file: myDirectlyAffected) { + for(FilePath file: directlyAffected) { final Change change = myChangeListManager.getChange(file); if (change != null) { changes.add(change); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java index 1ec5a83c719f..645b96430f24 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelveChangesManager.java @@ -32,6 +32,7 @@ import com.intellij.openapi.diff.impl.patch.apply.ApplyFilePatchBase; import com.intellij.openapi.diff.impl.patch.formove.CustomBinaryPatchApplier; import com.intellij.openapi.diff.impl.patch.formove.PatchApplier; import com.intellij.openapi.options.StreamProvider; +import com.intellij.openapi.progress.AsynchronousExecution; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; @@ -47,6 +48,10 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; import com.intellij.util.PathUtil; import com.intellij.util.SmartList; +import com.intellij.util.continuation.Continuation; +import com.intellij.util.continuation.ContinuationContext; +import com.intellij.util.continuation.TaskDescriptor; +import com.intellij.util.continuation.Where; import com.intellij.util.messages.MessageBus; import com.intellij.util.messages.Topic; import com.intellij.util.text.CharArrayCharSequence; @@ -301,48 +306,75 @@ public class ShelveChangesManager implements ProjectComponent, JDOMExternalizabl unshelveChangeList(changeList, changes, binaryFiles, targetChangeList, true); } + @AsynchronousExecution public void unshelveChangeList(final ShelvedChangeList changeList, @Nullable final List changes, @Nullable final List binaryFiles, - final LocalChangeList targetChangeList, + @Nullable final LocalChangeList targetChangeList, boolean showSuccessNotification) { - List remainingPatches = new ArrayList(); + final Continuation continuation = new Continuation(myProject, true); + final ContinuationContext.GatheringContinuationContext initContext = new ContinuationContext.GatheringContinuationContext(); + scheduleUnshelveChangeList(changeList, changes, binaryFiles, targetChangeList, showSuccessNotification, initContext); + continuation.run(initContext.getList()); + } - final List textFilePatches; - try { - textFilePatches = loadTextPatches(changeList, changes, remainingPatches); - } - catch (IOException e) { - LOG.info(e); - PatchApplier.showError(myProject, "Cannot load patch(es): " + e.getMessage(), true); - return; - } - catch (PatchSyntaxException e) { - PatchApplier.showError(myProject, "Cannot load patch(es): " + e.getMessage(), true); - LOG.info(e); - return; - } + @AsynchronousExecution + public void scheduleUnshelveChangeList(final ShelvedChangeList changeList, + @Nullable final List changes, + @Nullable final List binaryFiles, + @Nullable final LocalChangeList targetChangeList, + final boolean showSuccessNotification, final ContinuationContext context) { + context.next(new TaskDescriptor("", Where.AWT) { + @Override + public void run(ContinuationContext context) { + final List remainingPatches = new ArrayList(); - final List patches = new ArrayList(textFilePatches); + final List textFilePatches; + try { + textFilePatches = loadTextPatches(changeList, changes, remainingPatches); + } + catch (IOException e) { + LOG.info(e); + PatchApplier.showError(myProject, "Cannot load patch(es): " + e.getMessage(), true); + return; + } + catch (PatchSyntaxException e) { + PatchApplier.showError(myProject, "Cannot load patch(es): " + e.getMessage(), true); + LOG.info(e); + return; + } - final List remainingBinaries = new ArrayList(); - final List binaryFilesToUnshelve = getBinaryFilesToUnshelve(changeList, binaryFiles, remainingBinaries); + final List patches = new ArrayList(textFilePatches); - for (final ShelvedBinaryFile shelvedBinaryFile : binaryFilesToUnshelve) { - patches.add(new ShelvedBinaryFilePatch(shelvedBinaryFile)); - } + final List remainingBinaries = new ArrayList(); + final List binaryFilesToUnshelve = getBinaryFilesToUnshelve(changeList, binaryFiles, remainingBinaries); - final BinaryPatchApplier binaryPatchApplier = new BinaryPatchApplier(binaryFilesToUnshelve.size()); - final PatchApplier patchApplier = new PatchApplier(myProject, myProject.getBaseDir(), patches, targetChangeList, binaryPatchApplier); - patchApplier.execute(showSuccessNotification); - remainingPatches.addAll(patchApplier.getRemainingPatches()); + for (final ShelvedBinaryFile shelvedBinaryFile : binaryFilesToUnshelve) { + patches.add(new ShelvedBinaryFilePatch(shelvedBinaryFile)); + } - if ((remainingPatches.size() == 0) && remainingBinaries.isEmpty()) { - recycleChangeList(changeList); - } - else { - saveRemainingPatches(changeList, remainingPatches, remainingBinaries); - } + final BinaryPatchApplier binaryPatchApplier = new BinaryPatchApplier(binaryFilesToUnshelve.size()); + final PatchApplier patchApplier = new PatchApplier(myProject, myProject.getBaseDir(), + patches, targetChangeList, binaryPatchApplier); + + // after patch applier part + context.next(new TaskDescriptor("", Where.AWT) { + @Override + public void run(ContinuationContext context) { + remainingPatches.addAll(patchApplier.getRemainingPatches()); + + if ((remainingPatches.size() == 0) && remainingBinaries.isEmpty()) { + recycleChangeList(changeList); + } + else { + saveRemainingPatches(changeList, remainingPatches, remainingBinaries); + } + } + }); + + patchApplier.scheduleSelf(showSuccessNotification, context); + } + }); } private static List loadTextPatches(final ShelvedChangeList changeList, final List changes, final List remainingPatches) diff --git a/platform/vcs-impl/src/com/intellij/util/continuation/Continuation.java b/platform/vcs-impl/src/com/intellij/util/continuation/Continuation.java index 733f7390fe14..94c309a4dd6d 100644 --- a/platform/vcs-impl/src/com/intellij/util/continuation/Continuation.java +++ b/platform/vcs-impl/src/com/intellij/util/continuation/Continuation.java @@ -16,6 +16,7 @@ package com.intellij.util.continuation; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; @@ -25,14 +26,14 @@ import com.intellij.openapi.vcs.CalledInAny; import com.intellij.openapi.vcs.CalledInAwt; import com.intellij.openapi.vcs.changes.BackgroundFromStartOption; import com.intellij.util.Consumer; +import com.intellij.util.Processor; import com.intellij.util.WaitForProgressToShow; +import com.intellij.util.concurrency.Semaphore; +import com.sun.tools.javac.code.Attribute; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; +import java.util.*; public class Continuation { private GeneralRunner myGeneralRunner; @@ -55,6 +56,27 @@ public class Continuation { pingRunnerInCorrectThread(); } + public void runAndWait(final TaskDescriptor... tasks) { + runAndWait(Arrays.asList(tasks)); + } + + public void runAndWait(final List tasks) { + final Semaphore semaphore = new Semaphore(); + semaphore.down(); + tasks.add(new TaskDescriptor("", Where.AWT) { + @Override + public void run(ContinuationContext context) { + semaphore.up(); + } + }); + run(tasks); + semaphore.waitFor(); + } + + public void addExceptionHandler(final Class clazz, final Consumer consumer) { + myGeneralRunner.addExceptionHandler(clazz, consumer); + } + public void runIndirect(final Consumer consumer) { consumer.consume(myGeneralRunner); if (myGeneralRunner.isEmpty()) return; @@ -90,6 +112,10 @@ public class Continuation { myGeneralRunner.next(list); } + public boolean isEmpty() { + return myGeneralRunner.isEmpty(); + } + private static class TaskWrapper extends Task.Backgroundable { private final TaskDescriptor myTaskDescriptor; private final GeneralRunner myGeneralRunner; @@ -119,22 +145,69 @@ public class Continuation { private final Project myProject; private final boolean myCancellable; private final List myQueue; - private boolean myTriggerSuspend; - private BackgroundableProcessIndicator myIndicator; + private final Object myQueueLock; + private volatile boolean myTriggerSuspend; + private ProgressIndicator myIndicator; + private final Map myDisasters; + private final Map, Consumer> myHandlersMap; private GeneralRunner(final Project project, boolean cancellable) { myProject = project; myCancellable = cancellable; - myQueue = Collections.synchronizedList(new LinkedList()); + myQueueLock = new Object(); + myQueue = new LinkedList(); + myDisasters = new HashMap(); + myHandlersMap = new HashMap, Consumer>(); + } + + public void addExceptionHandler(final Class clazz, final Consumer consumer) { + synchronized (myQueueLock) { + myHandlersMap.put(clazz, new Consumer() { + @Override + public void consume(Exception e) { + if (! clazz.isAssignableFrom(e.getClass())) { + throw new RuntimeException(e); + } + consumer.consume((T) e); + } + }); + } } public Project getProject() { return myProject; } + public void clearDisasters() { + synchronized (myQueueLock) { + myDisasters.clear(); + } + } + + @Override + public boolean handleException(Exception e) { + synchronized (myQueueLock) { + final Class aClass = e.getClass(); + Consumer consumer = myHandlersMap.get(e.getClass()); + if (consumer != null) { + consumer.consume(e); + return true; + } + for (Map.Entry, Consumer> entry : myHandlersMap.entrySet()) { + if (entry.getKey().isAssignableFrom(aClass)) { + entry.getValue().consume(e); + return true; + } + } + } + return false; + } + @CalledInAny public void cancelEverything() { - myQueue.clear(); + synchronized (myQueueLock) { + myQueue.clear(); + } } public void cancelCurrent() { @@ -147,27 +220,79 @@ public class Continuation { myTriggerSuspend = true; } + @Override + public void keepExisting(Object disaster, Object cure) { + synchronized (myQueueLock) { + for (TaskDescriptor taskDescriptor : myQueue) { + taskDescriptor.addCure(disaster, cure); + } + } + } + + @Override + public void throwDisaster(@NotNull Object disaster, @NotNull final Object cure) { + synchronized (myQueueLock) { + final Iterator iterator = myQueue.iterator(); + while (iterator.hasNext()) { + final TaskDescriptor taskDescriptor = iterator.next(); + if (taskDescriptor.isHaveMagicCure()) continue; + final Object taskCure = taskDescriptor.hasCure(disaster); + if (! cure.equals(taskCure)) { + iterator.remove(); + } + } + myDisasters.put(disaster, cure); + } + } + + @Override + public void after(@NotNull TaskDescriptor inQueue, TaskDescriptor... next) { + synchronized (myQueueLock) { + int idx = -1; + int i = 0; + for (TaskDescriptor descriptor : myQueue) { + if (descriptor == inQueue) { + idx = i; + break; + } + ++ i; + } + assert idx != -1; + myQueue.addAll(idx + 1, Arrays.asList(next)); + } + } + @CalledInAny public void next(TaskDescriptor... next) { - myQueue.addAll(0, Arrays.asList(next)); + synchronized (myQueueLock) { + myQueue.addAll(0, Arrays.asList(next)); + } } public void next(List next) { - myQueue.addAll(0, next); + synchronized (myQueueLock) { + myQueue.addAll(0, next); + } } @Override public void last(List next) { - myQueue.addAll(next); + synchronized (myQueueLock) { + myQueue.addAll(next); + } } @Override public void last(TaskDescriptor... next) { - myQueue.addAll(Arrays.asList(next)); + synchronized (myQueueLock) { + myQueue.addAll(Arrays.asList(next)); + } } public boolean isEmpty() { - return myQueue.isEmpty(); + synchronized (myQueueLock) { + return myQueue.isEmpty(); + } } @CalledInAwt @@ -177,19 +302,34 @@ public class Continuation { while (true) { // stop if project is being disposed if (! myProject.isOpen()) return; - if (myQueue.isEmpty()) return; - if (myTriggerSuspend) { - myTriggerSuspend = false; - return; + + TaskDescriptor current; + synchronized (myQueueLock) { + if (myQueue.isEmpty()) return; + if (myTriggerSuspend) { + myTriggerSuspend = false; + return; + } + current = myQueue.remove(0); + // check if some tasks were scheduled after disaster was thrown, anyway, they should also be checked for cure + if (! current.isHaveMagicCure()) { + for (Map.Entry entry : myDisasters.entrySet()) { + if (! entry.getValue().equals(current.hasCure(entry.getKey()))) { + current = null; + break; + } + } + } + if (current == null) continue; } - TaskDescriptor current = myQueue.remove(0); if (Where.AWT.equals(current.getWhere())) { myIndicator = null; current.run(this); } else { final TaskWrapper task = new TaskWrapper(myProject, current.getName(), myCancellable, current, this); - myIndicator = new BackgroundableProcessIndicator(task); + myIndicator = ApplicationManager.getApplication().isUnitTestMode() ? new EmptyProgressIndicator() : + new BackgroundableProcessIndicator(task); ProgressManagerImpl.runProcessWithProgressAsynchronously(task, myIndicator); return; } diff --git a/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java b/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java index bf0f717ee0e0..13bd919d27bf 100644 --- a/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java +++ b/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java @@ -37,6 +37,8 @@ import com.intellij.ui.CheckboxTree; import com.intellij.ui.CheckedTreeNode; import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; +import com.intellij.util.Consumer; +import com.intellij.util.continuation.ContinuationContext; import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; @@ -420,7 +422,7 @@ public class GitPushActiveBranchesDialog extends DialogWrapper { private boolean executeRebase(final List exceptions, RebaseInfo rebaseInfo) { // TODO this is a workaround to attach PushActiveBranched to the new update. // at first we update via rebase - boolean result = new GitUpdateProcess(myProject, new EmptyProgressIndicator(), rebaseInfo.roots, UpdatedFiles.create()).update(true); + boolean result = new GitUpdateProcess(myProject, new EmptyProgressIndicator(), rebaseInfo.roots, UpdatedFiles.create()).update(true, true); // then we reorder commits if (result) { @@ -436,7 +438,7 @@ public class GitPushActiveBranchesDialog extends DialogWrapper { } - private boolean reorderCommitsIfNeeded(@NotNull RebaseInfo rebaseInfo) { + private boolean reorderCommitsIfNeeded(@NotNull final RebaseInfo rebaseInfo) { if (rebaseInfo.reorderedCommits.isEmpty()) { return true; } @@ -446,75 +448,57 @@ public class GitPushActiveBranchesDialog extends DialogWrapper { progressIndicator = new EmptyProgressIndicator(); } String stashMessage = "Uncommitted changes before rebase operation at " + DateFormatUtil.formatDateTime(Clock.getTime()); - GitChangesSaver saver = rebaseInfo.policy == GitVcsSettings.UpdateChangesPolicy.SHELVE ? new GitShelveChangesSaver(myProject, progressIndicator, stashMessage) : new GitStashChangesSaver(myProject, progressIndicator, stashMessage); - - final boolean saveOnFrameDeactivation = myGeneralSettings.isSaveOnFrameDeactivation(); - final boolean syncOnFrameDeactivation = myGeneralSettings.isSyncOnFrameActivation(); - myProjectManager.blockReloadingProjectOnExternalChanges(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override public void run() { - FileDocumentManager.getInstance().saveAllDocuments(); - myGeneralSettings.setSaveOnFrameDeactivation(false); - myGeneralSettings.setSyncOnFrameActivation(false); - } - }); - } - }); - - try { - final Set rootsToReorder = rebaseInfo.reorderedCommits.keySet(); - saver.saveLocalChanges(rootsToReorder); + final GitChangesSaver saver = rebaseInfo.policy == GitVcsSettings.UpdateChangesPolicy.SHELVE ? new GitShelveChangesSaver(myProject, progressIndicator, stashMessage) : new GitStashChangesSaver(myProject, progressIndicator, stashMessage); + final Boolean[] result = new Boolean[1]; + result[0] = false; + new GitUpdateLikeProcess(myProject) { + @Override + protected void runImpl(ContinuationContext context) { try { - GitRebaser rebaser = new GitRebaser(myProject); - for (Map.Entry> rootToCommits: rebaseInfo.reorderedCommits.entrySet()) { - final VirtualFile root = rootToCommits.getKey(); - GitBranch b = GitBranch.current(myProject, root); - if (b == null) { - LOG.info("executeRebase: current branch is null"); - continue; - } - GitBranch t = b.tracked(myProject, root); - if (t == null) { - LOG.info("executeRebase: tracked branch is null"); - continue; - } + final Set rootsToReorder = rebaseInfo.reorderedCommits.keySet(); + saver.saveLocalChanges(rootsToReorder); - final GitRevisionNumber mergeBase = b.getMergeBase(myProject, root, t); - if (mergeBase == null) { - LOG.info("executeRebase: merge base is null for " + b + " and " + t); - continue; - } - - String parentCommit = mergeBase.getRev(); - return rebaser.reoderCommitsIfNeeded(root, parentCommit, rootToCommits.getValue()); - } - - } catch (VcsException e) { - notifyMessage(myProject, "Commits weren't pushed", "Failed to reorder commits", NotificationType.WARNING, true, - Collections.singleton(e)); - } finally { try { - saver.restoreLocalChanges(); + GitRebaser rebaser = new GitRebaser(myProject); + for (Map.Entry> rootToCommits: rebaseInfo.reorderedCommits.entrySet()) { + final VirtualFile root = rootToCommits.getKey(); + GitBranch b = GitBranch.current(myProject, root); + if (b == null) { + LOG.info("executeRebase: current branch is null"); + continue; + } + GitBranch t = b.tracked(myProject, root); + if (t == null) { + LOG.info("executeRebase: tracked branch is null"); + continue; + } + + final GitRevisionNumber mergeBase = b.getMergeBase(myProject, root, t); + if (mergeBase == null) { + LOG.info("executeRebase: merge base is null for " + b + " and " + t); + continue; + } + + String parentCommit = mergeBase.getRev(); + result[0] = rebaser.reoderCommitsIfNeeded(root, parentCommit, rootToCommits.getValue()); + } + } catch (VcsException e) { - LOG.info("Couldn't restore local changes after reordering commits", e); - notifyImportantError(myProject, "Couldn't restore local changes after update", - "Restoring changes saved before update failed with an error.
" + e.getLocalizedMessage()); + notifyMessage(myProject, "Commits weren't pushed", "Failed to reorder commits", NotificationType.WARNING, true, + Collections.singleton(e)); + } finally { + saver.restoreLocalChanges(context); } + } catch (VcsException e) { + LOG.info("Couldn't save local changes", e); + notifyError(myProject, "Couldn't save local changes", + "Tried to save uncommitted changes in " + saver.getSaverName() + " before update, but failed with an error.
" + + "Update was cancelled.", true, e); } - } catch (VcsException e) { - LOG.info("Couldn't save local changes", e); - notifyError(myProject, "Couldn't save local changes", - "Tried to save uncommitted changes in " + saver.getSaverName() + " before update, but failed with an error.
" + - "Update was cancelled.", true, e); - } finally { - myProjectManager.unblockReloadingProjectOnExternalChanges(); - myGeneralSettings.setSaveOnFrameDeactivation(saveOnFrameDeactivation); - myGeneralSettings.setSyncOnFrameActivation(syncOnFrameDeactivation); - } - return false; + } + }.execute(); + return result[0]; } private static class RebaseInfo { diff --git a/plugins/git4idea/src/git4idea/checkout/branches/GitCheckoutProcess.java b/plugins/git4idea/src/git4idea/checkout/branches/GitCheckoutProcess.java index 07e5419d1468..4c930c8f837b 100644 --- a/plugins/git4idea/src/git4idea/checkout/branches/GitCheckoutProcess.java +++ b/plugins/git4idea/src/git4idea/checkout/branches/GitCheckoutProcess.java @@ -22,23 +22,29 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectManagerEx; +import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.*; import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager; import com.intellij.openapi.vcs.changes.shelf.ShelvedChangeList; +import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.util.Consumer; +import com.intellij.util.continuation.Continuation; +import com.intellij.util.continuation.ContinuationContext; import com.intellij.util.ui.UIUtil; -import com.intellij.vcsUtil.VcsUtil; import git4idea.GitRevisionNumber; import git4idea.GitUtil; import git4idea.checkout.branches.GitBranchConfigurations.BranchChanges; import git4idea.checkout.branches.GitBranchConfigurations.ChangeInfo; import git4idea.checkout.branches.GitBranchConfigurations.ChangeListInfo; import git4idea.commands.*; +import git4idea.ui.GitUIUtil; import git4idea.update.GitStashUtils; import org.jetbrains.annotations.Nullable; @@ -553,77 +559,86 @@ public class GitCheckoutProcess { * @param changes the changes to restore, null means no changes to restore * @return true if changes has been restored successfully */ - private boolean restoreChanges(ProgressIndicator progress, - final BranchChanges changes) { + private void restoreChanges(ProgressIndicator progress, final BranchChanges changes) { if (changes == null) { - return true; + return; } ShelvedChangeList shelve = null; for (ShelvedChangeList changeList : myShelveManager.getShelvedChangeLists()) { if (changeList.PATH.equals(changes.SHELVE_PATH)) { + // todo - why hadn't it interrupted? shelve = changeList; } } if (shelve == null) { //noinspection ThrowableInstanceNeverThrown myExceptions.add(new VcsException("Failed to find shelve with path" + changes.SHELVE_PATH)); - return false; + return; } progress.setText("Refreshing files before restoring shelve: " + shelve.DESCRIPTION); - GitStashUtils.doSystemUnshelve(myProject, shelve, myShelveManager, myChangeManager, myExceptions); - // dirty files and parse changes - final HashMap, String> parsedChanges = new HashMap, String>(); - for (ChangeInfo changeInfo : changes.CHANGES) { - String before = changeInfo.BEFORE_PATH; - String after = changeInfo.AFTER_PATH; - parsedChanges.put(Pair.create(before, after), changeInfo.CHANGE_LIST_NAME); - if (after != null) { - myDirtyScopeManager.fileDirty(VcsUtil.getFilePath(after)); - } - if (before != null) { - myDirtyScopeManager.fileDirty(VcsUtil.getFilePath(before)); - } - } final ShelvedChangeList finalShelve = shelve; - try { - waitForChanges(); - HashMap lists = new HashMap(); - for (LocalChangeList localChangeList : myChangeManager.getChangeLists()) { - lists.put(localChangeList.getName(), localChangeList); + + final Continuation continuation = new Continuation(myProject, true); + final Consumer exceptionConsumer = new Consumer() { + @Override + public void consume(VcsException e) { + GitUIUtil.showTabErrors(myProject, "Failed to restore shelved lists", Collections.singletonList(e)); + ToolWindowManager.getInstance(myProject).notifyByBalloon(ChangesViewContentManager.TOOLWINDOW_ID, MessageType.ERROR, + "Failed to process restore shelved change list: " + + finalShelve.DESCRIPTION + + ". Please restore it manually."); } - LocalChangeList defaultList = myChangeManager.getDefaultChangeList(); - for (ChangeListInfo changeListInfo : changes.CHANGE_LISTS) { - LocalChangeList changeList = lists.get(changeListInfo.NAME); - if (changeList == null) { - changeList = myChangeManager.addChangeList(changeListInfo.NAME, changeListInfo.COMMENT); - lists.put(changeListInfo.NAME, changeList); + }; + continuation.addExceptionHandler(VcsException.class, exceptionConsumer); + final ContinuationContext.GatheringContinuationContext initContext = + new ContinuationContext.GatheringContinuationContext(); + GitStashUtils.doSystemUnshelve(myProject, shelve, myShelveManager, new Runnable() { + @Override + public void run() { + final HashMap, String> parsedChanges = new HashMap, String>(); + for (ChangeInfo changeInfo : changes.CHANGES) { + String before = changeInfo.BEFORE_PATH; + String after = changeInfo.AFTER_PATH; + parsedChanges.put(Pair.create(before, after), changeInfo.CHANGE_LIST_NAME); } - if (changeListInfo.IS_DEFAULT) { - myChangeManager.setDefaultChangeList(changeList); + try { + HashMap lists = new HashMap(); + final List existedChangeLists = myChangeManager.getChangeLists(); + for (LocalChangeList localChangeList : existedChangeLists) { + lists.put(localChangeList.getName(), localChangeList); + } + LocalChangeList defaultList = myChangeManager.getDefaultChangeList(); + for (ChangeListInfo changeListInfo : changes.CHANGE_LISTS) { + LocalChangeList changeList = lists.get(changeListInfo.NAME); + if (changeList == null) { + changeList = myChangeManager.addChangeList(changeListInfo.NAME, changeListInfo.COMMENT); + lists.put(changeListInfo.NAME, changeList); + } + if (changeListInfo.IS_DEFAULT) { + myChangeManager.setDefaultChangeList(changeList); + } + } + for (Change change : defaultList.getChanges()) { + ContentRevision beforeRevision = change.getBeforeRevision(); + String before = beforeRevision == null ? null : beforeRevision.getFile().getPath(); + ContentRevision afterRevision = change.getAfterRevision(); + String after = afterRevision == null ? null : afterRevision.getFile().getPath(); + Pair key = Pair.create(before, after); + String listName = parsedChanges.get(key); + assert listName != null : "List name should be found: " + key; + if (!listName.equals(defaultList.getName())) { + LocalChangeList changeList = lists.get(listName); + assert changeList != null : "Change List should be found: " + listName; + myChangeManager.moveChangesTo(changeList, new Change[]{change}); + } + } + } + catch (Throwable t) { + exceptionConsumer.consume(new VcsException(t)); } } - for (Change change : defaultList.getChanges()) { - ContentRevision beforeRevision = change.getBeforeRevision(); - String before = beforeRevision == null ? null : beforeRevision.getFile().getPath(); - ContentRevision afterRevision = change.getAfterRevision(); - String after = afterRevision == null ? null : afterRevision.getFile().getPath(); - Pair key = Pair.create(before, after); - String listName = parsedChanges.get(key); - assert listName != null : "List name should be found: " + key; - if (!listName.equals(defaultList.getName())) { - LocalChangeList changeList = lists.get(listName); - assert changeList != null : "Change List should be found: " + listName; - myChangeManager.moveChangesTo(changeList, new Change[]{change}); - } - } - return true; - } - catch (Throwable t) { - //noinspection ThrowableInstanceNeverThrown - myExceptions.add( - new VcsException("Failed to process restore shelved change list: " + finalShelve.DESCRIPTION + ". Please restore it manually.", t)); - return false; - } + }, initContext); + continuation.run(initContext.getList()); } /** diff --git a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java index 226eef9240fe..9b9ebca04d64 100644 --- a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java +++ b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java @@ -36,7 +36,10 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.AsynchConsumer; import com.intellij.util.Consumer; import com.intellij.util.concurrency.Semaphore; -import git4idea.*; +import git4idea.GitBranch; +import git4idea.GitFileRevision; +import git4idea.GitRevisionNumber; +import git4idea.GitUtil; import git4idea.commands.*; import git4idea.config.GitConfigUtil; import git4idea.history.browser.GitCommit; @@ -659,9 +662,9 @@ public class GitHistoryUtils { final ChangeListManager changeManager = ChangeListManager.getInstance(project); final Change change = changeManager.getChange(path); if (change != null && change.getType() == Change.Type.MOVED) { - GitContentRevision r = (GitContentRevision)change.getBeforeRevision(); - assert r != null : "Move change always have beforeRevision"; - path = r.getFile(); + // GitContentRevision r = (GitContentRevision)change.getBeforeRevision(); + assert change.getBeforeRevision() != null : "Move change always have beforeRevision"; + path = change.getBeforeRevision().getFile(); } return path; } diff --git a/plugins/git4idea/src/git4idea/update/GitChangesSaver.java b/plugins/git4idea/src/git4idea/update/GitChangesSaver.java index 4dc87f34edd1..6c65d9d7f714 100644 --- a/plugins/git4idea/src/git4idea/update/GitChangesSaver.java +++ b/plugins/git4idea/src/git4idea/update/GitChangesSaver.java @@ -17,20 +17,19 @@ package git4idea.update; import com.intellij.notification.Notification; import com.intellij.notification.NotificationListener; -import com.intellij.notification.NotificationType; -import com.intellij.notification.Notifications; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vcs.changes.*; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ChangeListManagerEx; +import com.intellij.openapi.vcs.changes.LocalChangeList; +import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.ui.UIUtil; -import git4idea.GitVcs; +import com.intellij.util.Consumer; +import com.intellij.util.continuation.ContinuationContext; import git4idea.config.GitVcsSettings; -import git4idea.i18n.GitBundle; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -100,22 +99,10 @@ public abstract class GitChangesSaver { /** * Loads local changes from stash or shelf, and sorts the changes back to the change lists they were before update. + * @param context */ - public void restoreLocalChanges() throws VcsException { - load(); - myDirtyScopeManager.filePathsDirty(getChangedFiles(), null); - restoreChangeLists(); - } - - public void notifyLocalChangesAreNotRestored() { - if (wereChangesSaved()) { - LOG.info("Update is incomplete, changes are not restored"); - Notifications.Bus.notify(new Notification(GitVcs.IMPORTANT_ERROR_NOTIFICATION, "Local changes were not restored", - "Before update your uncommitted changes were saved to " + getSaverName() + "
" + - "Update is not complete, you have unresolved merges in your working tree
" + - "Resolve conflicts, complete update and restore changes manually.", NotificationType.WARNING, - new ShowSavedChangesNotificationListener())); - } + public void restoreLocalChanges(ContinuationContext context) { + load(getRestoreListsRunnable(), context); } public List getChangeLists() { @@ -148,8 +135,10 @@ public abstract class GitChangesSaver { /** * Loads the changes - specific for chosen save strategy. + * @param restoreListsRunnable + * @param exceptionConsumer */ - protected abstract void load() throws VcsException; + protected abstract void load(@Nullable Runnable restoreListsRunnable, ContinuationContext exceptionConsumer); /** * @return true if there were local changes to save. @@ -166,28 +155,23 @@ public abstract class GitChangesSaver { */ protected abstract void showSavedChanges(); - // Move files back to theirs change lists - private void restoreChangeLists() { - UIUtil.invokeLaterIfNeeded(new Runnable() { + private Runnable getRestoreListsRunnable() { + return new Runnable() { public void run() { - myChangeManager.invokeAfterUpdate(new Runnable() { - public void run() { - if (myChangeLists == null) { - return; - } - LOG.info("restoreChangeLists " + myChangeLists); - for (LocalChangeList changeList : myChangeLists) { - final Collection changes = changeList.getChanges(); - LOG.debug( "restoreProjectChangesAfterUpdate.invokeAfterUpdate changeList: " + changeList.getName() + " changes: " + changes.size()); - if (!changes.isEmpty()) { - LOG.debug("After restoring files: moving " + changes.size() + " changes to '" + changeList.getName() + "'"); - myChangeManager.moveChangesTo(changeList, changes.toArray(new Change[changes.size()])); - } - } + if (myChangeLists == null) { + return; + } + LOG.info("restoreChangeLists " + myChangeLists); + for (LocalChangeList changeList : myChangeLists) { + final Collection changes = changeList.getChanges(); + LOG.debug( "restoreProjectChangesAfterUpdate.invokeAfterUpdate changeList: " + changeList.getName() + " changes: " + changes.size()); + if (!changes.isEmpty()) { + LOG.debug("After restoring files: moving " + changes.size() + " changes to '" + changeList.getName() + "'"); + myChangeManager.moveChangesTo(changeList, changes.toArray(new Change[changes.size()])); } - }, InvokeAfterUpdateMode.BACKGROUND_NOT_CANCELLABLE, GitBundle.getString("update.restoring.change.lists"), ModalityState.NON_MODAL); + } } - }); + }; } protected class ShowSavedChangesNotificationListener implements NotificationListener { diff --git a/plugins/git4idea/src/git4idea/update/GitShelveChangesSaver.java b/plugins/git4idea/src/git4idea/update/GitShelveChangesSaver.java index a47348d8900f..3691a7c68677 100644 --- a/plugins/git4idea/src/git4idea/update/GitShelveChangesSaver.java +++ b/plugins/git4idea/src/git4idea/update/GitShelveChangesSaver.java @@ -26,6 +26,8 @@ import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager; import com.intellij.openapi.vcs.changes.shelf.ShelvedChangeList; import com.intellij.openapi.vcs.changes.shelf.ShelvedChangesViewManager; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.continuation.Continuation; +import com.intellij.util.continuation.ContinuationContext; import git4idea.GitUtil; import git4idea.i18n.GitBundle; import org.jetbrains.annotations.NotNull; @@ -68,17 +70,12 @@ public class GitShelveChangesSaver extends GitChangesSaver { } } - protected void load() throws VcsException { + protected void load(Runnable restoreListsRunnable, ContinuationContext context) { if (myShelvedChangeList != null) { LOG.info("load "); myProgressIndicator.setText(GitBundle.getString("update.unshelving.changes")); if (myShelvedChangeList != null) { - List exceptions = new ArrayList(1); - GitStashUtils.doSystemUnshelve(myProject, myShelvedChangeList, myShelveManager, myChangeManager, exceptions); - if (!exceptions.isEmpty()) { - LOG.info("load " + exceptions, exceptions.get(0)); - throw exceptions.get(0); - } + GitStashUtils.doSystemUnshelve(myProject, myShelvedChangeList, myShelveManager, restoreListsRunnable, context); } } } diff --git a/plugins/git4idea/src/git4idea/update/GitStashChangesSaver.java b/plugins/git4idea/src/git4idea/update/GitStashChangesSaver.java index 9cf6e5bf1705..7045a8d615bc 100644 --- a/plugins/git4idea/src/git4idea/update/GitStashChangesSaver.java +++ b/plugins/git4idea/src/git4idea/update/GitStashChangesSaver.java @@ -19,6 +19,7 @@ import com.intellij.notification.Notification; import com.intellij.notification.NotificationListener; import com.intellij.notification.NotificationType; import com.intellij.notification.Notifications; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; @@ -27,20 +28,25 @@ import com.intellij.openapi.vcs.ObjectsConvertor; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ContentRevision; +import com.intellij.openapi.vcs.changes.InvokeAfterUpdateMode; import com.intellij.openapi.vcs.changes.LocalChangeList; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vcs.merge.MergeDialogCustomizer; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.continuation.ContinuationContext; +import com.intellij.util.ui.UIUtil; import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.commands.*; import git4idea.config.GitVcsSettings; import git4idea.convert.GitFileSeparatorConverter; +import git4idea.i18n.GitBundle; import git4idea.merge.GitMergeConflictResolver; import git4idea.ui.GitUIUtil; import git4idea.ui.GitUnstashDialog; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.event.HyperlinkEvent; import java.io.File; @@ -70,15 +76,28 @@ public class GitStashChangesSaver extends GitChangesSaver { } @Override - protected void load() throws VcsException { + protected void load(@Nullable final Runnable restoreListsRunnable, ContinuationContext context) { for (VirtualFile root : myStashedRoots) { - loadRoot(root); + try { + loadRoot(root); + } + catch (VcsException e) { + context.handleException(e); + } } final List files = ObjectsConvertor.fp2jiof(getChangedFiles()); LocalFileSystem.getInstance().refreshIoFiles(files); + if (restoreListsRunnable != null) { + UIUtil.invokeLaterIfNeeded(new Runnable() { + public void run() { + myChangeManager.invokeAfterUpdate(restoreListsRunnable, InvokeAfterUpdateMode.BACKGROUND_NOT_CANCELLABLE, + GitBundle.getString("update.restoring.change.lists"), ModalityState.NON_MODAL); + } + }); + } } - @Override + @Override protected boolean wereChangesSaved() { return !myStashedRoots.isEmpty(); } diff --git a/plugins/git4idea/src/git4idea/update/GitStashUtils.java b/plugins/git4idea/src/git4idea/update/GitStashUtils.java index db8af8d0406c..68fef5735da6 100644 --- a/plugins/git4idea/src/git4idea/update/GitStashUtils.java +++ b/plugins/git4idea/src/git4idea/update/GitStashUtils.java @@ -15,13 +15,18 @@ */ package git4idea.update; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.AsynchronousExecution; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.AbstractVcsHelper; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.FileStatus; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; -import com.intellij.openapi.vcs.changes.ChangeListManagerEx; +import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vcs.changes.InvokeAfterUpdateMode; +import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager; import com.intellij.openapi.vcs.changes.shelf.ShelvedBinaryFile; import com.intellij.openapi.vcs.changes.shelf.ShelvedChange; @@ -29,7 +34,9 @@ import com.intellij.openapi.vcs.changes.shelf.ShelvedChangeList; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; -import com.intellij.util.ui.UIUtil; +import com.intellij.util.continuation.ContinuationContext; +import com.intellij.util.continuation.TaskDescriptor; +import com.intellij.util.continuation.Where; import com.intellij.vcsUtil.VcsUtil; import git4idea.GitUtil; import git4idea.GitVcs; @@ -110,20 +117,87 @@ public class GitStashUtils { * @param project the project * @param shelvedChangeList the shelved change list * @param shelveManager the shelve manager - * @param changeManager the change manager - * @param exceptions the collected exceptions + * @param restoreListsRunnable */ + @AsynchronousExecution public static void doSystemUnshelve(final Project project, final ShelvedChangeList shelvedChangeList, final ShelveChangesManager shelveManager, - final ChangeListManagerEx changeManager, - List exceptions) { - LOG.info("doSystemUnshelve "); - // The changes are temporary copied to the first local change list, the next operation will restore them back + @NotNull final Runnable restoreListsRunnable, + final @NotNull ContinuationContext context) { VirtualFile baseDir = project.getBaseDir(); assert baseDir != null; - String projectPath = baseDir.getPath() + "/"; - // Refresh files that might be affected by unshelve + final String projectPath = baseDir.getPath() + "/"; + + context.next(new TaskDescriptor("Refreshing files before unshelve", Where.POOLED) { + @Override + public void run(ContinuationContext context) { + LOG.info("doSystemUnshelve "); + // The changes are temporary copied to the first local change list, the next operation will restore them back + // Refresh files that might be affected by unshelve + refreshFilesBeforeUnshelve(shelvedChangeList, projectPath); + + LOG.info("doSystemUnshelve files refreshed. unshelving in AWT thread."); + } + }, new TaskDescriptor("", Where.AWT) { + @Override + public void run(ContinuationContext context) { + GitVFSListener l = GitVcs.getInstance(project).getVFSListener(); + l.setEventsSuppressed(true); + + LOG.info("Unshelving in UI thread. shelvedChangeList: " + shelvedChangeList); + // we pass null as target change list for Patch Applier to do NOTHING with change lists + shelveManager.scheduleUnshelveChangeList(shelvedChangeList, shelvedChangeList.getChanges(), + shelvedChangeList.getBinaryFiles(), null, false, context); + } + }, new TaskDescriptor("", Where.AWT) { + @Override + public void run(ContinuationContext context) { + LOG.info("Deleting change list"); + shelveManager.deleteChangeList(shelvedChangeList); + GitVcs.getInstance(project).getVFSListener().setEventsSuppressed(false); + addFilesAfterUnshelve(project, shelvedChangeList, projectPath, context); + ChangeListManager.getInstance(project).invokeAfterUpdate(new Runnable() { + @Override + public void run() { + restoreListsRunnable.run(); + } + }, InvokeAfterUpdateMode.BACKGROUND_NOT_CANCELLABLE_NOT_AWT, "Restoring changelists", ModalityState.NON_MODAL); + } + }); + } + + private static void addFilesAfterUnshelve(Project project, + ShelvedChangeList shelvedChangeList, + String projectPath, ContinuationContext context) { + Collection paths = new ArrayList(); + for (ShelvedChange c : shelvedChangeList.getChanges()) { + if (c.getBeforePath() == null || !c.getBeforePath().equals(c.getAfterPath()) || c.getFileStatus() == FileStatus.ADDED) { + paths.add(VcsUtil.getFilePath(projectPath + c.getAfterPath())); + } + } + for (ShelvedBinaryFile f : shelvedChangeList.getBinaryFiles()) { + if (f.BEFORE_PATH == null || !f.BEFORE_PATH.equals(f.AFTER_PATH) || f.getFileStatus() == FileStatus.ADDED) { + paths.add(VcsUtil.getFilePath(projectPath + f.AFTER_PATH)); + } + } + final VcsDirtyScopeManager dsm = VcsDirtyScopeManager.getInstance(project); + Map> map = GitUtil.sortGitFilePathsByGitRoot(paths); + for (Map.Entry> e : map.entrySet()) { + try { + GitFileUtils.addPaths(project, e.getKey(), e.getValue()); + dsm.filePathsDirty(e.getValue(), null); + } + catch (VcsException e1) { + if (! context.handleException(e1)) { + AbstractVcsHelper.getInstance(project).showError(e1, "Can not add file to Git"); + LOG.error("Vcs Exception not handled"); + } + } + } + } + + private static void refreshFilesBeforeUnshelve(ShelvedChangeList shelvedChangeList, String projectPath) { HashSet filesToRefresh = new HashSet(); for (ShelvedChange c : shelvedChangeList.getChanges()) { if (c.getBeforePath() != null) { @@ -142,45 +216,6 @@ public class GitStashUtils { } } LocalFileSystem.getInstance().refreshIoFiles(filesToRefresh); - LOG.info("doSystemUnshelve files refreshed. unshelving in AWT thread."); - // Do unshevle - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - public void run() { - GitVFSListener l = GitVcs.getInstance(project).getVFSListener(); - l.setEventsSuppressed(true); - try { - LOG.info("Unshelving in UI thread. shelvedChangeList: " + shelvedChangeList); - shelveManager - .unshelveChangeList(shelvedChangeList, shelvedChangeList.getChanges(), shelvedChangeList.getBinaryFiles(), - changeManager.getDefaultChangeList(), false); - LOG.info("Deleting change list"); - shelveManager.deleteChangeList(shelvedChangeList); - } - finally { - l.setEventsSuppressed(false); - } - } - }); - Collection paths = new ArrayList(); - for (ShelvedChange c : shelvedChangeList.getChanges()) { - if (c.getBeforePath() == null || !c.getBeforePath().equals(c.getAfterPath()) || c.getFileStatus() == FileStatus.ADDED) { - paths.add(VcsUtil.getFilePath(projectPath + c.getAfterPath())); - } - } - for (ShelvedBinaryFile f : shelvedChangeList.getBinaryFiles()) { - if (f.BEFORE_PATH == null || !f.BEFORE_PATH.equals(f.AFTER_PATH) || f.getFileStatus() == FileStatus.ADDED) { - paths.add(VcsUtil.getFilePath(projectPath + f.AFTER_PATH)); - } - } - Map> map = GitUtil.sortGitFilePathsByGitRoot(paths); - for (Map.Entry> e : map.entrySet()) { - try { - GitFileUtils.addPaths(project, e.getKey(), e.getValue()); - } - catch (VcsException e1) { - exceptions.add(e1); - } - } } /** diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java b/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java index 63c8fe0240e5..886ce1fb35d9 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdateEnvironment.java @@ -27,6 +27,10 @@ import com.intellij.openapi.vcs.update.UpdateEnvironment; import com.intellij.openapi.vcs.update.UpdateSession; import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.continuation.Continuation; +import com.intellij.util.continuation.ContinuationContext; +import com.intellij.util.continuation.TaskDescriptor; +import com.intellij.util.continuation.Where; import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.config.GitVcsSettings; @@ -61,7 +65,8 @@ public class GitUpdateEnvironment implements UpdateEnvironment { @NotNull public UpdateSession updateDirectories(@NotNull FilePath[] filePaths, UpdatedFiles updatedFiles, ProgressIndicator progressIndicator, @NotNull Ref sequentialUpdatesContextRef) throws ProcessCanceledException { Set roots = GitUtil.gitRoots(Arrays.asList(filePaths)); - boolean result = new GitUpdateProcess(myProject, progressIndicator, roots, updatedFiles).update(); + final GitUpdateProcess gitUpdateProcess = new GitUpdateProcess(myProject, progressIndicator, roots, updatedFiles); + boolean result = gitUpdateProcess.update(false, false); return new GitUpdateSession(result); } diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateLikeProcess.java b/plugins/git4idea/src/git4idea/update/GitUpdateLikeProcess.java new file mode 100644 index 000000000000..91469e800a43 --- /dev/null +++ b/plugins/git4idea/src/git4idea/update/GitUpdateLikeProcess.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.update; + +import com.intellij.ide.GeneralSettings; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ex.ProjectManagerEx; +import com.intellij.util.continuation.Continuation; +import com.intellij.util.continuation.ContinuationContext; +import com.intellij.util.continuation.TaskDescriptor; +import com.intellij.util.continuation.Where; +import com.intellij.util.ui.UIUtil; + +/** + * @author irengrig + * Date: 3/31/11 + * Time: 2:59 PM + */ +public abstract class GitUpdateLikeProcess { + private final Project myProject; + private GeneralSettings myGeneralSettings; + private ProjectManagerEx myProjectManager; + + public GitUpdateLikeProcess(final Project project) { + myProject = project; + myGeneralSettings = GeneralSettings.getInstance(); + myProjectManager = ProjectManagerEx.getInstanceEx(); + } + + public void execute() { + final boolean saveOnFrameDeactivation = myGeneralSettings.isSaveOnFrameDeactivation(); + final boolean syncOnFrameDeactivation = myGeneralSettings.isSyncOnFrameActivation(); + myProjectManager.blockReloadingProjectOnExternalChanges(); + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + FileDocumentManager.getInstance().saveAllDocuments(); + myGeneralSettings.setSaveOnFrameDeactivation(false); + myGeneralSettings.setSyncOnFrameActivation(false); + } + }); + } + }); + + final Continuation continuation = new Continuation(myProject, true); + final ContinuationContext.GatheringContinuationContext initContext = new ContinuationContext.GatheringContinuationContext(); + initContext.next(new TaskDescriptor("Git: updating", Where.POOLED) { + @Override + public void run(final ContinuationContext context) { + runImpl(context); + } + }, new TaskDescriptor("", Where.AWT) { + @Override + public void run(ContinuationContext context) { + myProjectManager.unblockReloadingProjectOnExternalChanges(); + myGeneralSettings.setSaveOnFrameDeactivation(saveOnFrameDeactivation); + myGeneralSettings.setSyncOnFrameActivation(syncOnFrameDeactivation); + } + }); + continuation.runAndWait(initContext.getList()); + } + + protected abstract void runImpl(ContinuationContext context); +} diff --git a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java index 46cb33c88244..e647da504b36 100644 --- a/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java +++ b/plugins/git4idea/src/git4idea/update/GitUpdateProcess.java @@ -17,9 +17,7 @@ package git4idea.update; import com.intellij.ide.GeneralSettings; import com.intellij.notification.NotificationType; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectManagerEx; @@ -27,8 +25,9 @@ import com.intellij.openapi.util.Clock; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Consumer; +import com.intellij.util.continuation.ContinuationContext; import com.intellij.util.text.DateFormatUtil; -import com.intellij.util.ui.UIUtil; import git4idea.GitBranch; import git4idea.branch.GitBranchPair; import git4idea.merge.GitMergeConflictResolver; @@ -81,7 +80,7 @@ public class GitUpdateProcess { * In case of error shows notification and returns false. If update completes without errors, returns true. */ public boolean update() { - return update(false); + return update(false, true); } /** @@ -96,28 +95,25 @@ public class GitUpdateProcess { * @param forceRebase * @return */ - public boolean update(boolean forceRebase) { + public boolean update(final boolean forceRebase, final boolean restoreChangesRightNow) { LOG.info("update started|" + (forceRebase ? " force rebase" : "")); if (!fetchAndNotify()) { return false; } - final boolean saveOnFrameDeactivation = myGeneralSettings.isSaveOnFrameDeactivation(); - final boolean syncOnFrameDeactivation = myGeneralSettings.isSyncOnFrameActivation(); - myProjectManager.blockReloadingProjectOnExternalChanges(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override public void run() { - FileDocumentManager.getInstance().saveAllDocuments(); - myGeneralSettings.setSaveOnFrameDeactivation(false); - myGeneralSettings.setSyncOnFrameActivation(false); - } - }); + final Boolean[] result = new Boolean[1]; + result[0] = false; + new GitUpdateLikeProcess(myProject) { + @Override + protected void runImpl(ContinuationContext context) { + result[0] = updateImpl(forceRebase, context); } - }); + }.execute(); + return result[0]; + } + private boolean updateImpl(boolean forceRebase, ContinuationContext context) { try { // check if update is possible if (checkRebaseInProgress() || checkMergeInProgress() || checkUnmergedFiles()) { return false; } @@ -148,7 +144,6 @@ public class GitUpdateProcess { mySaver.saveLocalChanges(rootsToSave); // update each root - boolean incomplete = false; boolean success = true; VirtualFile currentlyUpdatedRoot = null; try { @@ -157,9 +152,6 @@ public class GitUpdateProcess { GitUpdater updater = entry.getValue(); GitUpdateResult res = updater.update(); LOG.info("updating root " + currentlyUpdatedRoot + " finished: " + res); - if (res == GitUpdateResult.INCOMPLETE) { - incomplete = true; - } success &= res.isSuccess(); } } catch (VcsException e) { @@ -168,17 +160,7 @@ public class GitUpdateProcess { notifyImportantError(myProject, "Error updating " + rootName, "Updating " + rootName + " failed with an error: " + e.getLocalizedMessage()); } finally { - try { - if (!incomplete) { - mySaver.restoreLocalChanges(); - } else { - mySaver.notifyLocalChangesAreNotRestored(); - } - } catch (VcsException e) { - LOG.info("Couldn't restore local changes after update", e); - notifyImportantError(myProject, "Couldn't restore local changes after update", - "Restoring changes saved before update failed with an error.
" + e.getLocalizedMessage()); - } + restoreLocalChanges(context); } return success; } catch (VcsException e) { @@ -186,12 +168,20 @@ public class GitUpdateProcess { notifyError(myProject, "Couldn't save local changes", "Tried to save uncommitted changes in " + mySaver.getSaverName() + " before update, but failed with an error.
" + "Update was cancelled.", true, e); - } finally { - myProjectManager.unblockReloadingProjectOnExternalChanges(); - myGeneralSettings.setSaveOnFrameDeactivation(saveOnFrameDeactivation); - myGeneralSettings.setSyncOnFrameActivation(syncOnFrameDeactivation); + return false; } - return false; + } + + public void restoreLocalChanges(ContinuationContext context) { + context.addExceptionHandler(VcsException.class, new Consumer() { + @Override + public void consume(VcsException e) { + LOG.info("Couldn't restore local changes after reordering commits", e); + notifyImportantError(myProject, "Couldn't restore local changes after update", + "Restoring changes saved before update failed with an error.
" + e.getLocalizedMessage()); + } + }); + mySaver.restoreLocalChanges(context); } // fetch all roots. If an error happens, return false and notify about errors. From 3967dda8b3bb3eb5650ba99e1177a0df79960216 Mon Sep 17 00:00:00 2001 From: irengrig Date: Thu, 31 Mar 2011 17:51:41 +0400 Subject: [PATCH 17/32] VCS: changes view cosmetics --- .../openapi/vcs/changes/ui/ChangesListView.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesListView.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesListView.java index a300b610f603..4082fb6b5412 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesListView.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesListView.java @@ -93,6 +93,7 @@ public class ChangesListView extends Tree implements TypeSafeDataProvider, Advan SmartExpander.installOn(this); myCopyProvider = new TreeCopyProvider(this); new TreeLinkMouseListener(new ChangesBrowserNodeRenderer(myProject, false, false)).install(this); + setCellRenderer(new ChangesBrowserNodeRenderer(myProject, isShowFlatten(), true)); } public DefaultTreeModel getModel() { @@ -142,16 +143,13 @@ public class ChangesListView extends Tree implements TypeSafeDataProvider, Advan @Nullable List ignoredFiles, final List lockedFolders, @Nullable final Map logicallyLockedFiles) { - storeState(); - TreeModelBuilder builder = new TreeModelBuilder(myProject, isShowFlatten()); - final DefaultTreeModel model = builder.buildModel(changeLists, unversionedFiles, locallyDeletedFiles, modifiedWithoutEditing, + final DefaultTreeModel model = builder.buildModel(changeLists, unversionedFiles, locallyDeletedFiles, modifiedWithoutEditing, switchedFiles, switchedRoots, ignoredFiles, lockedFolders, logicallyLockedFiles); + + storeState(); setModel(model); - setCellRenderer(new ChangesBrowserNodeRenderer(myProject, isShowFlatten(), true)); - expandPath(new TreePath(((ChangesBrowserNode)model.getRoot()).getPath())); - restoreState(); } From b1ffe6f8cdd689ede1d0398ba93acfb0809755db Mon Sep 17 00:00:00 2001 From: irengrig Date: Thu, 31 Mar 2011 18:39:52 +0400 Subject: [PATCH 18/32] IDEA-67244 CVS History window does not appear. --- .../openapi/vcs/history/FileHistoryPanelImpl.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java index 5a5b26b6b9f7..6c757de2e853 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java @@ -256,9 +256,11 @@ public class FileHistoryPanelImpl Date: Thu, 31 Mar 2011 19:41:33 +0400 Subject: [PATCH 19/32] Remove nasty and absolutely unnecessary hack, that trivially manifests in a WTF bug in any platform based IDE except for IDEA, RubyMine and PyCharm. --- .../options/colors/FontEditorPreview.java | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java b/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java index e862f5619662..ae8841587790 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/FontEditorPreview.java @@ -47,26 +47,13 @@ public class FontEditorPreview implements PreviewPanel{ } public static String getIDEDemoText() { - String name = ApplicationNamesInfo.getInstance().getFullProductName(); - String language = getLanguage(name); // HACK return - name + " is a full-featured " + language + " IDE\n" + + ApplicationNamesInfo.getInstance().getFullProductName() + + " is a full-featured IDE\n" + "with a high level of usability and outstanding\n" + "advanced code editing and refactoring support.\n"; } - private static String getLanguage(String name) { - if (name.contains("RubyMine")) { - return "Ruby"; - } - - if (name.contains("PyCharm")) { - return "Python"; - } - - return "Java"; - } - static void installTrafficLights(EditorEx editor) { ErrorStripeRenderer renderer = new TrafficLightRenderer(null,null,null,null){ protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(boolean fillErrorsCount, SeverityRegistrar severityRegistrar) { From 4291bdb268a438e6863e0ba675406dd8d807e182 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 31 Mar 2011 17:18:20 +0200 Subject: [PATCH 20/32] fragment highlighting back in speed search --- .../ide/util/FileStructureDialog.java | 2 +- .../ui/speedSearch/SpeedSearchSupply.java | 4 +- .../ui/speedSearch/SpeedSearchUtil.java | 21 ++----- .../src/com/intellij/ui/SpeedSearchBase.java | 61 +++++------------- .../testFramework/UsefulTestCase.java | 19 +++--- .../com/intellij/psi/codeStyle/NameUtil.java | 62 ++++++++++++------- 6 files changed, 72 insertions(+), 97 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructureDialog.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructureDialog.java index 24fd16bba1cb..b6a8ef2294ca 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructureDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructureDialog.java @@ -423,7 +423,7 @@ public class FileStructureDialog extends DialogWrapper { if (name == null) { continue; } - if (!speedSearchComparator.doCompare(enteredPrefix, name)) { + if (speedSearchComparator.matchingFragments(enteredPrefix, name) == null) { continue; } } diff --git a/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchSupply.java b/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchSupply.java index 773373031e77..af56a5e8dda0 100644 --- a/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchSupply.java +++ b/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchSupply.java @@ -16,11 +16,11 @@ package com.intellij.ui.speedSearch; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.TextRange; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.regex.Matcher; /** * User: spLeaner @@ -39,5 +39,5 @@ public abstract class SpeedSearchSupply { public abstract boolean isPopupActive(); @Nullable - public abstract Matcher compareAndGetMatcher(@NotNull final String text); + public abstract Iterable matchingFragments(@NotNull final String text); } diff --git a/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java b/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java index 637a4a8b0188..5d9c60abd393 100644 --- a/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java +++ b/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java @@ -16,6 +16,7 @@ package com.intellij.ui.speedSearch; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.TextRange; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.Processor; @@ -28,7 +29,6 @@ import javax.swing.*; import java.awt.*; import java.util.ArrayList; import java.util.List; -import java.util.regex.Matcher; /** * User: spLeaner @@ -43,23 +43,12 @@ public final class SpeedSearchUtil { @NotNull final SimpleColoredComponent simpleColoredComponent) { final SpeedSearchSupply speedSearch = SpeedSearchSupply.getSupply(speedSearchEnabledComponent); if (speedSearch != null) { - final Matcher matcher = speedSearch.compareAndGetMatcher(text); - if (matcher != null) { + final Iterable fragments = speedSearch.matchingFragments(text); + if (fragments != null) { final List> searchTerms = new ArrayList>(); - for (int i = 0; i < matcher.groupCount(); i++) { - final int start = matcher.start(i + 1); - if (searchTerms.size() > 0) { - final Pair recent = searchTerms.get(searchTerms.size() - 1); - if (start == recent.second + recent.first.length()) { - searchTerms.set(searchTerms.size() - 1, Pair.create(recent.first + matcher.group(i + 1), recent.second)); - continue; - } - } - - final String group = matcher.group(i + 1); - if (group != null) searchTerms.add(Pair.create(group, start)); + for (TextRange fragment : fragments) { + searchTerms.add(Pair.create(fragment.substring(text), fragment.getStartOffset())); } - appendFragmentsStrict(text, searchTerms, attributes.getStyle(), attributes.getFgColor(), selected ? UIUtil.getTreeSelectionBackground() : UIUtil.getTreeTextBackground(), simpleColoredComponent); } diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java index 4cbe9cdea526..802f2b75815c 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java @@ -21,13 +21,14 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter; import com.intellij.openapi.wm.ex.ToolWindowManagerEx; import com.intellij.openapi.wm.ex.ToolWindowManagerListener; import com.intellij.psi.codeStyle.NameUtil; import com.intellij.ui.speedSearch.SpeedSearchSupply; -import com.intellij.util.StringBuilderSpinAllocator; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -46,9 +47,6 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ListIterator; import java.util.NoSuchElementException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; public abstract class SpeedSearchBase extends SpeedSearchSupply { private static final Logger LOG = Logger.getInstance("#com.intellij.ui.SpeedSearchBase"); @@ -100,11 +98,11 @@ public abstract class SpeedSearchBase extends SpeedSear @Override - public Matcher compareAndGetMatcher(@NotNull String text) { + public Iterable matchingFragments(@NotNull String text) { if (!isPopupActive()) return null; final SpeedSearchComparator comparator = getComparator(); final String recentSearchText = comparator.getRecentSearchText(); - return recentSearchText != null && recentSearchText.length() > 0 && comparator.doCompare(recentSearchText, text) && !NameUtil.isUseMinusculeHumpMatcher() ? comparator.getRecentSearchMatcher() : null; + return StringUtil.isNotEmpty(recentSearchText) ? comparator.matchingFragments(recentSearchText, text) : null; } /** @@ -154,7 +152,7 @@ public abstract class SpeedSearchBase extends SpeedSear } protected boolean compare(String text, String pattern) { - return myComparator.doCompare(pattern, text); + return myComparator.matchingFragments(pattern, text) != null; } public SpeedSearchComparator getComparator() { @@ -167,7 +165,6 @@ public abstract class SpeedSearchBase extends SpeedSear public static class SpeedSearchComparator { private NameUtil.MinusculeMatcher myMinusculeMatcher; - private Matcher myRecentSearchMatcher; private String myRecentSearchText; private boolean myShouldMatchFromTheBeginning; @@ -179,45 +176,15 @@ public abstract class SpeedSearchBase extends SpeedSear myShouldMatchFromTheBeginning = shouldMatchFromTheBeginning; } - public boolean doCompare(String pattern, String text) { - if (myRecentSearchText != null && - myRecentSearchText.equals(pattern) - ) { - if (NameUtil.isUseMinusculeHumpMatcher()) { - return myMinusculeMatcher.matches(text); - } - - myRecentSearchMatcher.reset(text); - return myRecentSearchMatcher.find(); - } - else { + @Nullable + public Iterable matchingFragments(String pattern, String text) { + if (myRecentSearchText == null || !myRecentSearchText.equals(pattern)) { myRecentSearchText = pattern; - @NonNls final StringBuilder buf = StringBuilderSpinAllocator.alloc(); - - try { - translatePattern(buf, pattern); - - try { - boolean allLowercase = pattern.equals(pattern.toLowerCase()); - final Pattern recentSearchPattern = Pattern.compile(buf.toString(), allLowercase ? Pattern.CASE_INSENSITIVE : 0); - myRecentSearchMatcher = recentSearchPattern.matcher(text); - - if (NameUtil.isUseMinusculeHumpMatcher()) { - myMinusculeMatcher = new NameUtil.MinusculeMatcher(myShouldMatchFromTheBeginning ? pattern : "*" + pattern, false, false); - return myMinusculeMatcher.matches(text); - } - return myRecentSearchMatcher.find(); - } - catch (PatternSyntaxException ex) { - myRecentSearchText = null; - } - } - finally { - StringBuilderSpinAllocator.dispose(buf); - } - - return false; + @NonNls final StringBuilder buf = new StringBuilder(); + translatePattern(buf, pattern); + myMinusculeMatcher = new NameUtil.MinusculeMatcher(myShouldMatchFromTheBeginning ? pattern : "*" + pattern, false, false); } + return myMinusculeMatcher.matchingFragments(text); } public void translatePattern(final StringBuilder buf, final String pattern) { @@ -234,8 +201,8 @@ public abstract class SpeedSearchBase extends SpeedSear return myRecentSearchText; } - public Matcher getRecentSearchMatcher() { - return myRecentSearchMatcher; + public NameUtil.MinusculeMatcher getRecentSearchMatcher() { + return myMinusculeMatcher; } public void translateCharacter(final StringBuilder buf, final char ch) { diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index 7321b2b2631b..117c27e406ee 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -49,7 +49,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; -import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -255,8 +254,8 @@ public abstract class UsefulTestCase extends TestCase { } @NonNls - public static String toString(Collection collection) { - if (collection.isEmpty()) { + public static String toString(Iterable collection) { + if (!collection.iterator().hasNext()) { return ""; } @@ -277,24 +276,28 @@ public abstract class UsefulTestCase extends TestCase { assertOrderedEquals(Arrays.asList(actual), expected); } - public static void assertOrderedEquals(Collection actual, T... expected) { + public static void assertOrderedEquals(Iterable actual, T... expected) { assertOrderedEquals(null, actual, expected); } - public static void assertOrderedEquals(final String errorMsg, Collection actual, T... expected) { + public static void assertOrderedEquals(final String errorMsg, Iterable actual, T... expected) { Assert.assertNotNull(actual); Assert.assertNotNull(expected); assertOrderedEquals(errorMsg, actual, Arrays.asList(expected)); } - public static void assertOrderedEquals(final Collection actual, final Collection expected) { + public static void assertOrderedEquals(final Iterable actual, final Collection expected) { assertOrderedEquals(null, actual, expected); } public static void assertOrderedEquals(final String erroMsg, - final Collection actual, + final Iterable actual, final Collection expected) { - if (!new ArrayList(actual).equals(new ArrayList(expected))) { + ArrayList list = new ArrayList(); + for (T t : actual) { + list.add(t); + } + if (!list.equals(new ArrayList(expected))) { Assert.assertEquals(erroMsg, toString(expected), toString(actual)); Assert.fail(); } diff --git a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java index 5882dd07e66f..1d1b2d0963fb 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java +++ b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java @@ -16,11 +16,13 @@ package com.intellij.psi.codeStyle; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.FList; import com.intellij.util.text.StringTokenizer; import org.apache.oro.text.regex.MalformedPatternException; import org.apache.oro.text.regex.Pattern; @@ -28,10 +30,12 @@ import org.apache.oro.text.regex.Perl5Compiler; import org.apache.oro.text.regex.Perl5Matcher; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class NameUtil { @@ -495,42 +499,44 @@ public class NameUtil { myPattern = StringUtil.trimEnd(pattern, "* ").replaceAll(":", "\\*:").replaceAll("\\.", "\\*\\.").toCharArray(); } - private boolean matches(int patternIndex, List words, int wordIndex) { + @Nullable + private FList matchName(int patternIndex, List words, int wordIndex, int wordStart) { if (patternIndex == myPattern.length) { - return true; + return FList.emptyList(); } if (wordIndex == words.size()) { - return false; + return null; } String word = words.get(wordIndex); if ('*' == myPattern[patternIndex]) { - return handleAsterisk(patternIndex, words, wordIndex); + return handleAsterisk(patternIndex, words, wordIndex, wordStart); } if (patternIndex == 0 && myFirstLetterCaseMatters && word.charAt(0) != myPattern[0]) { - return false; + return null; } if (isWordSeparator(word.charAt(0))) { assert word.length() == 1 : "'" + word + "'"; char p = myPattern[patternIndex]; + int nextStart = wordStart + word.length(); if (isWordSeparator(p)) { if (myFirstLetterCaseMatters && wordIndex == 0 && words.size() > 1 && patternIndex + 1 < myPattern.length && isWordSeparator(words.get(1).charAt(0)) && !isWordSeparator(myPattern[patternIndex + 1])) { - return false; + return null; } - return matches(patternIndex + 1, words, wordIndex + 1); + return matchName(patternIndex + 1, words, wordIndex + 1, nextStart); } - return matches(patternIndex, words, wordIndex + 1); + return matchName(patternIndex, words, wordIndex + 1, nextStart); } if (StringUtil.toLowerCase(word.charAt(0)) != StringUtil.toLowerCase(myPattern[patternIndex])) { - return false; + return null; } boolean uppers = isWordStart(myPattern[patternIndex]); @@ -538,7 +544,7 @@ public class NameUtil { int i = 1; while (true) { if (patternIndex + i == myPattern.length) { - return true; + return FList.emptyList().prepend(TextRange.from(wordStart, i)); } if (i == word.length()) { break; @@ -561,26 +567,30 @@ public class NameUtil { } // there's more in the pattern, but no more words if (wordIndex == words.size() - 1) { - if (patternIndex + i == myPattern.length - 1 && ' ' == myPattern[patternIndex + i]) { - return i == word.length(); + if (patternIndex + i == myPattern.length - 1 && ' ' == myPattern[patternIndex + i] && i == word.length()) { + return FList.emptyList().prepend(TextRange.from(wordStart, i)); } - return false; + return null; } + + int nextWord = wordStart + word.length(); while (i > 0) { - if (matches(patternIndex + i, words, wordIndex + 1)) { - return true; + FList ranges = matchName(patternIndex + i, words, wordIndex + 1, nextWord); + if (ranges != null) { + return ranges.prepend(TextRange.from(wordStart, i)); } i--; } - return false; + return null; } - private boolean handleAsterisk(int patternIndex, List words, int wordIndex) { + @Nullable + private FList handleAsterisk(int patternIndex, List words, int wordIndex, int wordStart) { while ('*' == myPattern[patternIndex]) { patternIndex++; if (patternIndex == myPattern.length) { - return true; + return FList.emptyList(); } } @@ -597,13 +607,14 @@ public class NameUtil { List newWords = new ArrayList(); newWords.add(s.substring(next)); newWords.addAll(words.subList(i + 1, words.size())); - if (matches(patternIndex, newWords, 0)) { - return true; + FList ranges = matchName(patternIndex, newWords, 0, wordStart + next); + if (ranges != null) { + return ranges; } fromIndex = next + 1; } } - return false; + return null; } private static boolean isWordSeparator(char c) { @@ -612,6 +623,11 @@ public class NameUtil { @Override public boolean matches(String name) { + return matchingFragments(name) != null; + } + + @Nullable + public Iterable matchingFragments(String name) { StringTokenizer tokenizer = new StringTokenizer(name, " -_.:/", true); List words = new ArrayList(); while (tokenizer.hasMoreTokens()) { @@ -620,10 +636,10 @@ public class NameUtil { } if (words.isEmpty()) { - return myPattern.length == 0; + return myPattern.length == 0 ? Collections.emptyList() : null; } - return matches(0, words, 0); + return matchName(0, words, 0, 0); } } } From bf5668cad194faffa1b6d3868ebc62d8d6dadd59 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 31 Mar 2011 17:37:27 +0200 Subject: [PATCH 21/32] no need to translate pattern --- .../ide/util/FileStructureDialog.java | 22 +---------- .../src/com/intellij/ui/SpeedSearchBase.java | 37 ------------------- .../maven/wizards/MavenModuleWizardStep.java | 12 +----- 3 files changed, 2 insertions(+), 69 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructureDialog.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructureDialog.java index b6a8ef2294ca..b4da40061a95 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructureDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructureDialog.java @@ -342,7 +342,6 @@ public class FileStructureDialog extends DialogWrapper { myList.repaint(); // to update match highlighting } }); - myListSpeedSearch.setComparator(createSpeedSearchComparator()); } private boolean hasPrefixShortened(final PropertyChangeEvent evt) { @@ -413,7 +412,7 @@ public class FileStructureDialog extends DialogWrapper { } ArrayList filteredElements = new ArrayList(childElements.length); - SpeedSearchBase.SpeedSearchComparator speedSearchComparator = createSpeedSearchComparator(); + SpeedSearchBase.SpeedSearchComparator speedSearchComparator = new SpeedSearchBase.SpeedSearchComparator(); for (Object child : childElements) { if (child instanceof AbstractTreeNode) { @@ -439,25 +438,6 @@ public class FileStructureDialog extends DialogWrapper { } } - private static SpeedSearchBase.SpeedSearchComparator createSpeedSearchComparator() { - return new SpeedSearchBase.SpeedSearchComparator() { - public void translateCharacter(final StringBuilder buf, final char ch) { - if (ch == '*') { - if (buf.length() > 0 && "^*)(".indexOf(buf.charAt(buf.length() - 1)) == -1) buf.append(')'); - buf.append(".*"); // overrides '*' handling to skip (,) in parameter lists - } - else { - if (ch == ':') { - if (buf.length() > 0 && "^*)(".indexOf(buf.charAt(buf.length() - 1)) == -1) buf.append(')'); - buf.append(".*"); // get:int should match any getter returning int - buf.append('('); - } - super.translateCharacter(buf, ch); - } - } - }; - } - private class MyTreeActionsOwner implements TreeActionsOwner { private final Set myFilters = new HashSet(); diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java index 802f2b75815c..b6862b5f993d 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java @@ -180,52 +180,15 @@ public abstract class SpeedSearchBase extends SpeedSear public Iterable matchingFragments(String pattern, String text) { if (myRecentSearchText == null || !myRecentSearchText.equals(pattern)) { myRecentSearchText = pattern; - @NonNls final StringBuilder buf = new StringBuilder(); - translatePattern(buf, pattern); myMinusculeMatcher = new NameUtil.MinusculeMatcher(myShouldMatchFromTheBeginning ? pattern : "*" + pattern, false, false); } return myMinusculeMatcher.matchingFragments(text); } - public void translatePattern(final StringBuilder buf, final String pattern) { - if (myShouldMatchFromTheBeginning) buf.append('^'); // match from the line start - final int len = pattern.length(); - for (int i = 0; i < len; ++i) { - translateCharacter(buf, pattern.charAt(i)); - } - - if (buf.length() > 0 && "*^".indexOf(buf.charAt(buf.length() - 1)) == -1) buf.append(')'); - } public String getRecentSearchText() { return myRecentSearchText; } - - public NameUtil.MinusculeMatcher getRecentSearchMatcher() { - return myMinusculeMatcher; - } - - public void translateCharacter(final StringBuilder buf, final char ch) { - if (ch == '*' ) { - buf.append("(\\w|:)"); // ':' for xml tags - } - else if ("{}[].+^$()?".indexOf(ch) != -1) { - // do not bother with other metachars - buf.append('\\'); - } - - if (Character.isUpperCase(ch)) { - if (buf.length() > 0 && "*^".indexOf(buf.charAt(buf.length() - 1)) == -1) buf.append(')'); - // for camel humps - buf.append("[A-Za-z_]*"); - buf.append('('); - } else { - if (buf.length() > 0 && "*^".indexOf(buf.charAt(buf.length() - 1)) != -1) buf.append('('); - } - - if (buf.length() == 0 || buf.length() > 0 && "^".indexOf(buf.charAt(buf.length() - 1)) != -1) buf.append('('); - buf.append(ch); - } } @Nullable diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java index d761d5f3ba1d..2cc11707e3bc 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleWizardStep.java @@ -157,17 +157,7 @@ public class MavenModuleWizardStep extends ModuleWizardStep { MavenArchetype info = getArchetypeInfoFromPathComponent(path.getLastPathComponent()); return info.groupId + ":" + info.artifactId + ":" + info.version; } - }).setComparator(new SpeedSearchBase.SpeedSearchComparator(false) { - @Override - public void translateCharacter(StringBuilder buf, char ch) { - if (ch == '*') { - buf.append("(.)*"); - } - else { - super.translateCharacter(buf, ch); - } - } - }); + }).setComparator(new SpeedSearchBase.SpeedSearchComparator(false)); myArchetypeDescriptionField.setEditable(false); myArchetypeDescriptionField.setBackground(UIUtil.getPanelBackground()); From 311ebcebfd939306d0c8c9b7b9c6a41b2545e0e0 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 31 Mar 2011 17:37:54 +0200 Subject: [PATCH 22/32] more correct range calculation after * --- platform/util/src/com/intellij/psi/codeStyle/NameUtil.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java index 1d1b2d0963fb..698b48345cdf 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java +++ b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java @@ -613,6 +613,7 @@ public class NameUtil { } fromIndex = next + 1; } + wordStart += s.length(); } return null; } From 74dbaa6927ad516d778fe6bd7cf98c4944788a98 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 31 Mar 2011 17:57:15 +0200 Subject: [PATCH 23/32] color matching fragments in lookup --- .../lookup/impl/LookupCellRenderer.java | 22 +++++----- .../ui/speedSearch/SpeedSearchUtil.java | 44 +++++++++---------- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java index bbba75b5f69b..3dd0fee9794c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java @@ -24,10 +24,13 @@ import com.intellij.ide.ui.UISettings; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.colors.EditorFontType; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.codeStyle.NameUtil; import com.intellij.ui.LayeredIcon; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleTextAttributes; +import com.intellij.ui.speedSearch.SpeedSearchUtil; import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -236,26 +239,25 @@ public class LookupCellRenderer implements ListCellRenderer { return used; } - void renderItemName(LookupElement item, + private void renderItemName(LookupElement item, Color foreground, boolean selected, int style, String name, final SimpleColoredComponent nameComponent) { - final SimpleTextAttributes baseAttrs = new SimpleTextAttributes(style, foreground); + final SimpleTextAttributes base = new SimpleTextAttributes(style, foreground); final String prefix = myLookup.itemPrefix(item); - if (prefix.length() > 0){ - final int i = StringUtil.indexOfIgnoreCase(name, prefix, 0); - if (i >= 0 && !(item instanceof EmptyLookupItem)) { - nameComponent.append(name.substring(0, i), baseAttrs); - nameComponent.append(name.substring(i, i + prefix.length()), - new SimpleTextAttributes(style, selected ? SELECTED_PREFIX_FOREGROUND_COLOR : PREFIX_FOREGROUND_COLOR)); - nameComponent.append(name.substring(i + prefix.length()), baseAttrs); + if (prefix.length() > 0) { + Iterable ranges = new NameUtil.MinusculeMatcher("*" + prefix, false, false).matchingFragments(name); + if (ranges != null) { + SimpleTextAttributes highlighted = + new SimpleTextAttributes(style, selected ? SELECTED_PREFIX_FOREGROUND_COLOR : PREFIX_FOREGROUND_COLOR); + SpeedSearchUtil.appendColoredFragments(nameComponent, name, ranges, base, highlighted); return; } } - nameComponent.append(name, baseAttrs); + nameComponent.append(name, base); } private int setTypeTextLabel(LookupElement item, diff --git a/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java b/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java index 5d9c60abd393..b8185b42fb9f 100644 --- a/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java +++ b/platform/platform-api/src/com/intellij/ui/speedSearch/SpeedSearchUtil.java @@ -22,7 +22,6 @@ import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -45,46 +44,43 @@ public final class SpeedSearchUtil { if (speedSearch != null) { final Iterable fragments = speedSearch.matchingFragments(text); if (fragments != null) { - final List> searchTerms = new ArrayList>(); - for (TextRange fragment : fragments) { - searchTerms.add(Pair.create(fragment.substring(text), fragment.getStartOffset())); - } - appendFragmentsStrict(text, searchTerms, attributes.getStyle(), attributes.getFgColor(), - selected ? UIUtil.getTreeSelectionBackground() : UIUtil.getTreeTextBackground(), simpleColoredComponent); + final Color fg = attributes.getFgColor(); + final Color bg = selected ? UIUtil.getTreeSelectionBackground() : UIUtil.getTreeTextBackground(); + final int style = attributes.getStyle(); + final SimpleTextAttributes plain = new SimpleTextAttributes(style, fg); + final SimpleTextAttributes highlighted = new SimpleTextAttributes(bg, fg, null, style | SimpleTextAttributes.STYLE_SEARCH_MATCH); + appendColoredFragments(simpleColoredComponent, text, fragments, plain, highlighted); + return; } - else { - simpleColoredComponent.append(text, attributes); - } - } else { - simpleColoredComponent.append(text, attributes); } + simpleColoredComponent.append(text, attributes); } - public static void appendFragmentsStrict(@NonNls final String text, @NotNull final List> toHighlight, - final int style, final Color foreground, - final Color background, final SimpleColoredComponent c) { - if (text == null) return; - final SimpleTextAttributes plainAttributes = new SimpleTextAttributes(style, foreground); + public static void appendColoredFragments(final SimpleColoredComponent simpleColoredComponent, + final String text, + Iterable colored, + final SimpleTextAttributes plain, final SimpleTextAttributes highlighted) { + final List> searchTerms = new ArrayList>(); + for (TextRange fragment : colored) { + searchTerms.add(Pair.create(fragment.substring(text), fragment.getStartOffset())); + } final int[] lastOffset = {0}; - ContainerUtil.process(toHighlight, new Processor>() { + ContainerUtil.process(searchTerms, new Processor>() { @Override public boolean process(Pair pair) { if (pair.second > lastOffset[0]) { - c.append(text.substring(lastOffset[0], pair.second), new SimpleTextAttributes(style, foreground)); + simpleColoredComponent.append(text.substring(lastOffset[0], pair.second), plain); } - c.append(text.substring(pair.second, pair.second + pair.first.length()), new SimpleTextAttributes(background, - foreground, null, - style | - SimpleTextAttributes.STYLE_SEARCH_MATCH)); + simpleColoredComponent.append(text.substring(pair.second, pair.second + pair.first.length()), highlighted); lastOffset[0] = pair.second + pair.first.length(); return true; } }); if (lastOffset[0] < text.length()) { - c.append(text.substring(lastOffset[0]), plainAttributes); + simpleColoredComponent.append(text.substring(lastOffset[0]), plain); } } } From 1c6506393b4c7701024c03f7da585e401b89d2db Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 31 Mar 2011 18:46:29 +0200 Subject: [PATCH 24/32] cheaper asterisk handling --- .../com/intellij/psi/codeStyle/NameUtil.java | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java index 698b48345cdf..f0bfde762bd8 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java +++ b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java @@ -500,7 +500,7 @@ public class NameUtil { } @Nullable - private FList matchName(int patternIndex, List words, int wordIndex, int wordStart) { + private FList matchName(int patternIndex, List words, int wordIndex, int insideWord, int wordStart) { if (patternIndex == myPattern.length) { return FList.emptyList(); } @@ -511,14 +511,14 @@ public class NameUtil { String word = words.get(wordIndex); if ('*' == myPattern[patternIndex]) { - return handleAsterisk(patternIndex, words, wordIndex, wordStart); + return handleAsterisk(patternIndex, words, wordIndex, insideWord, wordStart); } - if (patternIndex == 0 && myFirstLetterCaseMatters && word.charAt(0) != myPattern[0]) { + if (patternIndex == 0 && myFirstLetterCaseMatters && word.charAt(insideWord) != myPattern[0]) { return null; } - if (isWordSeparator(word.charAt(0))) { + if (isWordSeparator(word.charAt(insideWord))) { assert word.length() == 1 : "'" + word + "'"; char p = myPattern[patternIndex]; int nextStart = wordStart + word.length(); @@ -529,13 +529,13 @@ public class NameUtil { return null; } - return matchName(patternIndex + 1, words, wordIndex + 1, nextStart); + return matchName(patternIndex + 1, words, wordIndex + 1, 0, nextStart); } - return matchName(patternIndex, words, wordIndex + 1, nextStart); + return matchName(patternIndex, words, wordIndex + 1, 0, nextStart); } - if (StringUtil.toLowerCase(word.charAt(0)) != StringUtil.toLowerCase(myPattern[patternIndex])) { + if (StringUtil.toLowerCase(word.charAt(insideWord)) != StringUtil.toLowerCase(myPattern[patternIndex])) { return null; } @@ -544,9 +544,9 @@ public class NameUtil { int i = 1; while (true) { if (patternIndex + i == myPattern.length) { - return FList.emptyList().prepend(TextRange.from(wordStart, i)); + return FList.emptyList().prepend(TextRange.from(wordStart + insideWord, i)); } - if (i == word.length()) { + if (i == word.length() - insideWord) { break; } char p = myPattern[patternIndex + i]; @@ -556,7 +556,7 @@ public class NameUtil { uppers = false; } - char w = word.charAt(i); + char w = word.charAt(insideWord + i); if (!myCaseMatters) { w = StringUtil.toLowerCase(w); } @@ -567,8 +567,8 @@ public class NameUtil { } // there's more in the pattern, but no more words if (wordIndex == words.size() - 1) { - if (patternIndex + i == myPattern.length - 1 && ' ' == myPattern[patternIndex + i] && i == word.length()) { - return FList.emptyList().prepend(TextRange.from(wordStart, i)); + if (patternIndex + i == myPattern.length - 1 && ' ' == myPattern[patternIndex + i] && i == word.length() - insideWord) { + return FList.emptyList().prepend(TextRange.from(wordStart + insideWord, i)); } return null; @@ -576,9 +576,9 @@ public class NameUtil { int nextWord = wordStart + word.length(); while (i > 0) { - FList ranges = matchName(patternIndex + i, words, wordIndex + 1, nextWord); + FList ranges = matchName(patternIndex + i, words, wordIndex + 1, 0, nextWord); if (ranges != null) { - return ranges.prepend(TextRange.from(wordStart, i)); + return ranges.prepend(TextRange.from(wordStart + insideWord, i)); } i--; } @@ -586,7 +586,7 @@ public class NameUtil { } @Nullable - private FList handleAsterisk(int patternIndex, List words, int wordIndex, int wordStart) { + private FList handleAsterisk(int patternIndex, List words, int wordIndex, int insideWord, int wordStart) { while ('*' == myPattern[patternIndex]) { patternIndex++; if (patternIndex == myPattern.length) { @@ -596,23 +596,21 @@ public class NameUtil { String nextChar = String.valueOf(myPattern[patternIndex]); + int fromIndex = insideWord; for (int i = wordIndex; i < words.size(); i++) { String s = words.get(i); - int fromIndex = 0; while (true) { int next = StringUtil.indexOfIgnoreCase(s, nextChar, fromIndex); if (next < 0) { break; } - List newWords = new ArrayList(); - newWords.add(s.substring(next)); - newWords.addAll(words.subList(i + 1, words.size())); - FList ranges = matchName(patternIndex, newWords, 0, wordStart + next); + FList ranges = matchName(patternIndex, words, i, next, wordStart); if (ranges != null) { return ranges; } fromIndex = next + 1; } + fromIndex = 0; wordStart += s.length(); } return null; @@ -640,7 +638,7 @@ public class NameUtil { return myPattern.length == 0 ? Collections.emptyList() : null; } - return matchName(0, words, 0, 0); + return matchName(0, words, 0, 0, 0); } } } From 6f23609dfafe6834f05dba3c9c9b60f412e8c645 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 31 Mar 2011 18:55:44 +0200 Subject: [PATCH 25/32] MatchingCaseSensitivity enum --- .../lookup/impl/LookupCellRenderer.java | 2 +- .../src/com/intellij/ui/SpeedSearchBase.java | 2 +- .../com/intellij/psi/codeStyle/NameUtil.java | 38 +++++++++---------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java index 3dd0fee9794c..d4d3fa967e6b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java @@ -249,7 +249,7 @@ public class LookupCellRenderer implements ListCellRenderer { final String prefix = myLookup.itemPrefix(item); if (prefix.length() > 0) { - Iterable ranges = new NameUtil.MinusculeMatcher("*" + prefix, false, false).matchingFragments(name); + Iterable ranges = new NameUtil.MinusculeMatcher("*" + prefix, NameUtil.MatchingCaseSensitivity.NONE).matchingFragments(name); if (ranges != null) { SimpleTextAttributes highlighted = new SimpleTextAttributes(style, selected ? SELECTED_PREFIX_FOREGROUND_COLOR : PREFIX_FOREGROUND_COLOR); diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java index b6862b5f993d..64b6801313ec 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java @@ -180,7 +180,7 @@ public abstract class SpeedSearchBase extends SpeedSear public Iterable matchingFragments(String pattern, String text) { if (myRecentSearchText == null || !myRecentSearchText.equals(pattern)) { myRecentSearchText = pattern; - myMinusculeMatcher = new NameUtil.MinusculeMatcher(myShouldMatchFromTheBeginning ? pattern : "*" + pattern, false, false); + myMinusculeMatcher = new NameUtil.MinusculeMatcher(myShouldMatchFromTheBeginning ? pattern : "*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); } return myMinusculeMatcher.matchingFragments(text); } diff --git a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java index f0bfde762bd8..9e9c4bc74145 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java +++ b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java @@ -15,7 +15,6 @@ */ package com.intellij.psi.codeStyle; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; @@ -39,7 +38,6 @@ import java.util.Collections; import java.util.List; public class NameUtil { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.codeStyle.NameUtil"); private static final Function LOWERCASE_MAPPING = new Function() { public String fun(final String s) { return s.toLowerCase(); @@ -389,23 +387,26 @@ public class NameUtil { } public static Matcher buildCompletionMatcher(String pattern, int exactPrefixLen, boolean allowToUpper, boolean allowToLower) { - return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower, false, true), exactPrefixLen > 0, !allowToLower && !allowToUpper); + MatchingCaseSensitivity options = !allowToLower && !allowToUpper ? MatchingCaseSensitivity.ALL : exactPrefixLen > 0 ? MatchingCaseSensitivity.FIRST_LETTER : MatchingCaseSensitivity.NONE; + return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower, false, true), options); } public static Matcher buildMatcher(String pattern, int exactPrefixLen, boolean allowToUpper, boolean allowToLower) { - return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower), exactPrefixLen > 0, !allowToLower && !allowToUpper); + MatchingCaseSensitivity options = !allowToLower && !allowToUpper ? MatchingCaseSensitivity.ALL : exactPrefixLen > 0 ? MatchingCaseSensitivity.FIRST_LETTER : MatchingCaseSensitivity.NONE; + return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower), options); } public static Matcher buildMatcher(String pattern, int exactPrefixLen, boolean allowToUpper, boolean allowToLower, boolean lowerCaseWords) { - return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower, lowerCaseWords, false), exactPrefixLen > 0, !allowToLower && !allowToUpper); + MatchingCaseSensitivity options = !allowToLower && !allowToUpper ? MatchingCaseSensitivity.ALL : exactPrefixLen > 0 ? MatchingCaseSensitivity.FIRST_LETTER : MatchingCaseSensitivity.NONE; + return buildMatcher(pattern, buildRegexp(pattern, exactPrefixLen, allowToUpper, allowToLower, lowerCaseWords, false), options); } public static boolean isUseMinusculeHumpMatcher() { return Registry.is("minuscule.humps.matching"); } - private static Matcher buildMatcher(final String pattern, String regexp, boolean firstLetterMatters, boolean caseMatters) { - return isUseMinusculeHumpMatcher() ? new MinusculeMatcher(pattern, firstLetterMatters, caseMatters) : new OptimizedMatcher(pattern, regexp); + private static Matcher buildMatcher(final String pattern, String regexp, MatchingCaseSensitivity options) { + return isUseMinusculeHumpMatcher() ? new MinusculeMatcher(pattern, options) : new OptimizedMatcher(pattern, regexp); } private static class OptimizedMatcher implements Matcher { @@ -485,17 +486,16 @@ public class NameUtil { } } + public enum MatchingCaseSensitivity { + NONE, FIRST_LETTER, ALL + } + public static class MinusculeMatcher implements Matcher { private final char[] myPattern; - private final boolean myFirstLetterCaseMatters; - private final boolean myCaseMatters; + private final MatchingCaseSensitivity myOptions; - public MinusculeMatcher(String pattern, boolean firstLetterCaseMatters, boolean caseMatters) { - myFirstLetterCaseMatters = firstLetterCaseMatters; - myCaseMatters = caseMatters; - if (caseMatters) { - LOG.assertTrue(firstLetterCaseMatters); - } + public MinusculeMatcher(String pattern, MatchingCaseSensitivity options) { + myOptions = options; myPattern = StringUtil.trimEnd(pattern, "* ").replaceAll(":", "\\*:").replaceAll("\\.", "\\*\\.").toCharArray(); } @@ -514,7 +514,7 @@ public class NameUtil { return handleAsterisk(patternIndex, words, wordIndex, insideWord, wordStart); } - if (patternIndex == 0 && myFirstLetterCaseMatters && word.charAt(insideWord) != myPattern[0]) { + if (patternIndex == 0 && myOptions != MatchingCaseSensitivity.NONE && word.charAt(insideWord) != myPattern[0]) { return null; } @@ -523,7 +523,7 @@ public class NameUtil { char p = myPattern[patternIndex]; int nextStart = wordStart + word.length(); if (isWordSeparator(p)) { - if (myFirstLetterCaseMatters && + if (myOptions != MatchingCaseSensitivity.NONE && wordIndex == 0 && words.size() > 1 && patternIndex + 1 < myPattern.length && isWordSeparator(words.get(1).charAt(0)) && !isWordSeparator(myPattern[patternIndex + 1])) { return null; @@ -550,14 +550,14 @@ public class NameUtil { break; } char p = myPattern[patternIndex + i]; - if (uppers && isWordStart(p) && !myCaseMatters) { + if (uppers && isWordStart(p) && myOptions != MatchingCaseSensitivity.ALL) { p = StringUtil.toLowerCase(p); } else { uppers = false; } char w = word.charAt(insideWord + i); - if (!myCaseMatters) { + if (myOptions != MatchingCaseSensitivity.ALL) { w = StringUtil.toLowerCase(w); } if (w != p) { From 898ed9bfcc067bc037f180178f2972bf57bfbadf Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Thu, 31 Mar 2011 21:33:26 +0400 Subject: [PATCH 26/32] [patch from Sascha.Weinreuter] IDEA-67266 Generate XML document from XSD fails with non-ASCII content --- ...erateInstanceDocumentFromSchemaAction.java | 40 ++++++++++--------- .../actions/xmlbeans/Xsd2InstanceUtils.java | 26 ++++++++++-- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/xml/impl/src/com/intellij/xml/actions/xmlbeans/GenerateInstanceDocumentFromSchemaAction.java b/xml/impl/src/com/intellij/xml/actions/xmlbeans/GenerateInstanceDocumentFromSchemaAction.java index 4299df21b83b..fbb4fd56d5d5 100644 --- a/xml/impl/src/com/intellij/xml/actions/xmlbeans/GenerateInstanceDocumentFromSchemaAction.java +++ b/xml/impl/src/com/intellij/xml/actions/xmlbeans/GenerateInstanceDocumentFromSchemaAction.java @@ -39,10 +39,10 @@ import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.io.StringBufferInputStream; import java.util.LinkedList; import java.util.List; @@ -57,7 +57,7 @@ public class GenerateInstanceDocumentFromSchemaAction extends AnAction { e.getPresentation().setEnabled(enabled); if (ActionPlaces.isPopupPlace(e.getPlace())) { e.getPresentation().setVisible(enabled); - } + } } public void actionPerformed(AnActionEvent e) { @@ -113,12 +113,12 @@ public class GenerateInstanceDocumentFromSchemaAction extends AnAction { (XmlFile) PsiManager.getInstance(project).findFile(relativeFile), new THashMap(), new Xsd2InstanceUtils.SchemaReferenceProcessor() { - public void processSchema(String schemaFileName, String schemaContent) { + public void processSchema(String schemaFileName, byte[] schemaContent) { try { final String fullFileName = tempDir.getPath() + File.separatorChar + schemaFileName; FileUtils.saveStreamContentAsFile( fullFileName, - new StringBufferInputStream(schemaContent) + new ByteArrayInputStream(schemaContent) ); } catch (IOException e) { throw new RuntimeException(e); @@ -147,26 +147,30 @@ public class GenerateInstanceDocumentFromSchemaAction extends AnAction { final VirtualFile baseDirForCreatedInstanceDocument1 = relativeFileDir; String xmlFileName = baseDirForCreatedInstanceDocument1.getPath() + File.separatorChar + dialog.getOutputFileName(); - FileOutputStream fileOutputStream = null; + FileOutputStream fileOutputStream; try { fileOutputStream = new FileOutputStream(xmlFileName); - fileOutputStream.write(xml.getBytes()); - fileOutputStream.close(); - fileOutputStream = null; + try { + // the generated XML doesn't have any XML declaration -> utf-8 + fileOutputStream.write(xml.getBytes("utf-8")); + } + finally { + fileOutputStream.close(); + } + + final File xmlFile = new File(xmlFileName); + VirtualFile virtualFile = ApplicationManager.getApplication().runWriteAction(new Computable() { + @Nullable + public VirtualFile compute() { + return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(xmlFile); + } + }); + FileEditorManager.getInstance(project).openFile(virtualFile, true); } catch (IOException e) { - e.printStackTrace(); + Messages.showErrorDialog(project, "Could not save generated XML document: " + StringUtil.getMessage(e), XmlBundle.message("error")); } - - final File xmlFile = new File(xmlFileName); - VirtualFile virtualFile = ApplicationManager.getApplication().runWriteAction(new Computable() { - @Nullable - public VirtualFile compute() { - return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(xmlFile); - } - }); - FileEditorManager.getInstance(project).openFile(virtualFile, true); } static boolean isAcceptableFileForGenerateSchemaFromInstanceDocument(VirtualFile virtualFile) { diff --git a/xml/impl/src/com/intellij/xml/actions/xmlbeans/Xsd2InstanceUtils.java b/xml/impl/src/com/intellij/xml/actions/xmlbeans/Xsd2InstanceUtils.java index 0bb9ba882db5..c6c358eda169 100644 --- a/xml/impl/src/com/intellij/xml/actions/xmlbeans/Xsd2InstanceUtils.java +++ b/xml/impl/src/com/intellij/xml/actions/xmlbeans/Xsd2InstanceUtils.java @@ -15,6 +15,7 @@ */ package com.intellij.xml.actions.xmlbeans; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.XmlRecursiveElementVisitor; @@ -28,12 +29,14 @@ import com.intellij.psi.xml.XmlTag; import com.intellij.xml.XmlElementDescriptor; import com.intellij.xml.XmlNSDescriptor; import com.intellij.xml.impl.schema.XmlNSDescriptorImpl; +import com.intellij.xml.util.XmlUtil; import org.apache.xmlbeans.*; import org.apache.xmlbeans.impl.tool.CommandLine; import org.apache.xmlbeans.impl.xsd2inst.SampleXmlUtil; import org.jetbrains.annotations.NotNull; import java.io.File; +import java.io.UnsupportedEncodingException; import java.util.*; @@ -85,7 +88,7 @@ public class Xsd2InstanceUtils { } catch (Exception e) { - throw new IllegalArgumentException("Can not load schema file: " + schemaFiles[i] + ": "); + throw new IllegalArgumentException("Can not load schema file: " + schemaFiles[i] + ": " + e.getLocalizedMessage()); } } @@ -145,7 +148,7 @@ public class Xsd2InstanceUtils { return null; } - + public static List addVariantsFromRootTag(XmlTag rootTag) { PsiMetaData metaData = rootTag.getMetaData(); if (metaData instanceof XmlNSDescriptorImpl) { @@ -217,11 +220,26 @@ public class Xsd2InstanceUtils { } }); - schemaReferenceProcessor.processSchema(fileName, result.toString()); + final VirtualFile virtualFile = file.getVirtualFile(); + final String content = result.toString(); + + byte[] bytes; + if (virtualFile != null) { + bytes = content.getBytes(virtualFile.getCharset()); + } else { + try { + final String charsetName = XmlUtil.extractXmlEncodingFromProlog(content.getBytes()); + bytes = charsetName != null ? content.getBytes(charsetName) : content.getBytes(); + } catch (UnsupportedEncodingException e) { + bytes = content.getBytes(); + } + } + + schemaReferenceProcessor.processSchema(fileName, bytes); return fileName; } public interface SchemaReferenceProcessor { - void processSchema(String schemaFileName, String schemaContent); + void processSchema(String schemaFileName, byte[] schemaContent); } } From 08c2174385c6a9bff4900cabc99115458a71310d Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 31 Mar 2011 16:23:26 +0400 Subject: [PATCH 27/32] Import completion in console now works identically like in normal python editor (PY-2408). --- .../lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index 9da2d00e02b7..d6685573880f 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -443,6 +443,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF return getContainingDirectory(); } + @Nullable public PsiDirectory getContainingDirectory() { final VirtualFile parentFile = getViewProvider().getVirtualFile().getParent(); if (parentFile == null) return null; From dfcbc87d60905ab11a163e53c0c7fe5ea2acad2c Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 31 Mar 2011 19:57:04 +0200 Subject: [PATCH 28/32] splitting into words without excessive object creation --- .../com/intellij/psi/codeStyle/NameUtil.java | 40 +++++-------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java index 9e9c4bc74145..74a3de79045a 100644 --- a/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java +++ b/platform/util/src/com/intellij/psi/codeStyle/NameUtil.java @@ -31,8 +31,6 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.text.CharacterIterator; -import java.text.StringCharacterIterator; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -325,61 +323,45 @@ public class NameUtil { return Character.isUpperCase(p) || Character.isDigit(p); } - private static void addAllWords(String word, List result) { - CharacterIterator it = new StringCharacterIterator(word); - StringBuffer b = new StringBuffer(); + private static void addAllWords(String text, List result) { + int start = 0; WordState state = WordState.NO_WORD; - char curPrevUC = '\0'; - for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) { + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); switch (state) { case NO_WORD: if (!isWordStart(c)) { - b.append(c); state = WordState.WORD; } else { state = WordState.PREV_UC; - curPrevUC = c; } break; case PREV_UC: if (!isWordStart(c)) { - b = startNewWord(result, b, curPrevUC); - b.append(c); + start = startNewWord(text, result, start, i - 1); state = WordState.WORD; } else { - b.append(curPrevUC); state = WordState.PREV_UC; - curPrevUC = c; } break; case WORD: if (isWordStart(c)) { - startNewWord(result, b, c); - b.setLength(0); + start = startNewWord(text, result, start, i); state = WordState.PREV_UC; - curPrevUC = c; - } - else { - b.append(c); } break; } } - if (state == WordState.PREV_UC) { - b.append(curPrevUC); - } - result.add(b.toString()); + startNewWord(text, result, start, text.length()); } - private static StringBuffer startNewWord(List result, StringBuffer b, char c) { - if (b.length() > 0) { - result.add(b.toString()); + private static int startNewWord(String word, List result, int start, int end) { + if (end > start) { + result.add(word.substring(start, end)); } - b = new StringBuffer(); - b.append(c); - return b; + return end; } public interface Matcher { From 0bf7fec31199e6bcdaecc33357d6b3c56e239a10 Mon Sep 17 00:00:00 2001 From: anna Date: Thu, 31 Mar 2011 18:21:04 +0200 Subject: [PATCH 29/32] correct relative path for one class --- .../src/com/intellij/refactoring/copy/CopyClassesHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java b/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java index 52b10badd94e..844837ab418c 100644 --- a/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java @@ -125,7 +125,7 @@ public class CopyClassesHandler implements CopyHandlerDelegate { CopyClassDialog dialog = new CopyClassDialog(classes.values().iterator().next()[0], defaultTargetDirectory, project, false){ @Override protected String getQualifiedName() { - if (commonPath != null) { + if (commonPath != null && !commonPath.isEmpty()) { return StringUtil.getQualifiedName(super.getQualifiedName(), commonPath.replaceAll("/", ".")); } return super.getQualifiedName(); From b866f1d9f2150b8d1bac20cb75559fbe729e506d Mon Sep 17 00:00:00 2001 From: anna Date: Thu, 31 Mar 2011 18:49:48 +0200 Subject: [PATCH 30/32] ask if files already exist in move (IDEA-64478 ) --- .../copy/CopyFilesOrDirectoriesHandler.java | 37 +++++++++++-------- .../MoveFilesOrDirectoriesUtil.java | 22 ++++++++++- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesHandler.java b/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesHandler.java index 8e89079f1fb4..7e7e7768fde5 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/copy/CopyFilesOrDirectoriesHandler.java @@ -243,22 +243,7 @@ public class CopyFilesOrDirectoriesHandler implements CopyHandlerDelegate { if (elementToCopy instanceof PsiFile) { PsiFile file = (PsiFile)elementToCopy; String name = newName == null ? file.getName() : newName; - final PsiFile existing = targetDirectory.findFile(name); - if (existing!=null) { - int selection = choice == null || choice[0] == -1 ? Messages.showDialog( - String.format("File '%s' already exists in directory '%s'", name, targetDirectory.getVirtualFile().getPath()), - "Copy", - choice == null ? new String[]{"Overwrite", "Skip"} - : new String[]{"Overwrite", "Skip", "Overwrite for all", "Skip for all"}, 0, Messages.getQuestionIcon()) - : choice[0]; - if (choice != null && selection > 1) { - choice[0] = selection % 2; - selection = choice[0]; - } - if (selection == 0 && file != existing) { - existing.delete(); - } else return null; - } + if (checkFileExist(targetDirectory, choice, file, name)) return null; return targetDirectory.copyFileFrom(name, file); } else if (elementToCopy instanceof PsiDirectory) { @@ -290,4 +275,24 @@ public class CopyFilesOrDirectoriesHandler implements CopyHandlerDelegate { throw new IllegalArgumentException("unexpected elementToCopy: " + elementToCopy); } } + + public static boolean checkFileExist(PsiDirectory targetDirectory, int[] choice, PsiFile file, String name) { + final PsiFile existing = targetDirectory.findFile(name); + if (existing!=null) { + int selection = choice == null || choice[0] == -1 ? Messages.showDialog( + String.format("File '%s' already exists in directory '%s'", name, targetDirectory.getVirtualFile().getPath()), + "Copy", + choice == null ? new String[]{"Overwrite", "Skip"} + : new String[]{"Overwrite", "Skip", "Overwrite for all", "Skip for all"}, 0, Messages.getQuestionIcon()) + : choice[0]; + if (choice != null && selection > 1) { + choice[0] = selection % 2; + selection = choice[0]; + } + if (selection == 0 && file != existing) { + existing.delete(); + } else return true; + } + return false; + } } diff --git a/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesUtil.java b/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesUtil.java index 1773a9de6cf3..d63c664005f7 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesUtil.java +++ b/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesUtil.java @@ -22,9 +22,11 @@ import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.Computable; import com.intellij.psi.*; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.RefactoringSettings; +import com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler; import com.intellij.refactoring.move.MoveCallback; import com.intellij.refactoring.move.MoveHandler; import com.intellij.refactoring.util.CommonRefactoringUtil; @@ -32,7 +34,9 @@ import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; public class MoveFilesOrDirectoriesUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil"); @@ -102,11 +106,25 @@ public class MoveFilesOrDirectoriesUtil { PsiManager manager = PsiManager.getInstance(project); try { - for (PsiElement psiElement : newElements) { + final int[] choice = elements.length > 1 ? new int[]{-1} : null; + final List els = new ArrayList(); + for (int i = 0, newElementsLength = newElements.length; i < newElementsLength; i++) { + final PsiElement psiElement = newElements[i]; + if (psiElement instanceof PsiFile) { + final PsiFile file = (PsiFile)psiElement; + final boolean fileExist = ApplicationManager.getApplication().runWriteAction(new Computable() { + @Override + public Boolean compute() { + return CopyFilesOrDirectoriesHandler.checkFileExist(targetDirectory, choice, file, file.getName()); + } + }); + if (fileExist) continue; + } manager.checkMove(psiElement, targetDirectory); + els.add(psiElement); } - new MoveFilesOrDirectoriesProcessor(project, newElements, targetDirectory, + new MoveFilesOrDirectoriesProcessor(project, els.toArray(new PsiElement[els.size()]), targetDirectory, RefactoringSettings.getInstance().MOVE_SEARCH_FOR_REFERENCES_FOR_FILE, false, false, moveCallback, new Runnable() { public void run() { From 0d21845e37b3d78d1a85212d7d33eababc305b57 Mon Sep 17 00:00:00 2001 From: anna Date: Thu, 31 Mar 2011 20:39:16 +0200 Subject: [PATCH 31/32] allow to move packages without java files out of source roots (IDEA-66580 ) --- .../MoveClassesOrPackagesHandlerBase.java | 27 ++++++++++++++++++- .../JavaMoveFilesOrDirectoriesHandler.java | 2 ++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesHandlerBase.java b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesHandlerBase.java index 7deacc03e155..ec86a76f7c96 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesHandlerBase.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveClassesOrPackagesHandlerBase.java @@ -34,6 +34,7 @@ import com.intellij.refactoring.JavaRefactoringSettings; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.move.MoveCallback; import com.intellij.refactoring.move.MoveHandlerDelegate; +import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.RadioUpDownListener; import com.intellij.refactoring.util.RefactoringUtil; @@ -131,8 +132,13 @@ public class MoveClassesOrPackagesHandlerBase extends MoveHandlerDelegate { processor.run(); } else { + final boolean containsJava = hasJavaFiles(directories[0]); + if (!containsJava) { + MoveFilesOrDirectoriesUtil.doMove(project, new PsiElement[] {directories[0]}, new PsiElement[]{targetContainer}, callback); + return; + } final MoveClassesOrPackagesToNewDirectoryDialog dlg = - new MoveClassesOrPackagesToNewDirectoryDialog(directories[0], new PsiElement[2], false, callback) { + new MoveClassesOrPackagesToNewDirectoryDialog(directories[0], new PsiElement[0], false, callback) { @Override protected void performRefactoring(Project project, final PsiDirectory targetDirectory, @@ -161,6 +167,25 @@ public class MoveClassesOrPackagesHandlerBase extends MoveHandlerDelegate { MoveClassesOrPackagesImpl.doMove(project, elements, targetContainer, callback); } + public static boolean hasJavaFiles(PsiDirectory directory) { + final boolean [] containsJava = new boolean[]{false}; + directory.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (containsJava[0]) return; + if (element instanceof PsiFile || element instanceof PsiDirectory) { + super.visitElement(element); + } + } + + @Override + public void visitJavaFile(PsiJavaFile file) { + containsJava[0] = true; + } + }); + return containsJava[0]; + } + @Override public PsiElement adjustTargetForMove(DataContext dataContext, PsiElement targetContainer) { if (targetContainer instanceof PsiPackage) { diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/JavaMoveFilesOrDirectoriesHandler.java b/java/java-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/JavaMoveFilesOrDirectoriesHandler.java index 91c1f33c0c21..0412ec0d99d7 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/JavaMoveFilesOrDirectoriesHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/JavaMoveFilesOrDirectoriesHandler.java @@ -24,6 +24,7 @@ import com.intellij.psi.impl.file.JavaDirectoryServiceImpl; import com.intellij.psi.util.PsiUtilBase; import com.intellij.refactoring.copy.JavaCopyFilesOrDirectoriesHandler; import com.intellij.refactoring.move.MoveCallback; +import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesHandlerBase; import com.intellij.util.ArrayUtil; import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; @@ -41,6 +42,7 @@ public class JavaMoveFilesOrDirectoriesHandler extends MoveFilesOrDirectoriesHan for (PsiElement element : srcElements) { if (element instanceof PsiDirectory) { allJava &= JavaCopyFilesOrDirectoriesHandler.hasPackages((PsiDirectory)element); + allJava &= MoveClassesOrPackagesHandlerBase.hasJavaFiles((PsiDirectory)element); } else if (element instanceof PsiFile) { allJava &= element instanceof PsiJavaFile && !JspPsiUtil.isInJspFile(element) && From faef4a2f62ceed1a492b8955528e38f3f62b2d08 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 31 Mar 2011 21:32:09 +0200 Subject: [PATCH 32/32] add *.py and *.rb to default file masks (PY-2963) --- .../lang-impl/src/com/intellij/find/impl/FindSettingsImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindSettingsImpl.java b/platform/lang-impl/src/com/intellij/find/impl/FindSettingsImpl.java index 186c2a15db11..d3683eebda79 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindSettingsImpl.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindSettingsImpl.java @@ -110,6 +110,8 @@ public class FindSettingsImpl extends FindSettings implements PersistentStateCom RECENT_FILE_MASKS.add("*.as"); RECENT_FILE_MASKS.add("*.css"); RECENT_FILE_MASKS.add("*.mxml"); + RECENT_FILE_MASKS.add("*.py"); + RECENT_FILE_MASKS.add("*.rb"); } }