Merge remote-tracking branch 'origin/master' into develar/is

This commit is contained in:
Vladimir Krivosheev
2016-06-24 11:31:06 +02:00
167 changed files with 1346 additions and 1563 deletions
@@ -15,24 +15,62 @@
*/
package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.generation.ClassMember;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.intention.LowPriorityAction;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.codeInsight.intention.impl.ParameterClassMember;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateBuilderImpl;
import com.intellij.codeInsight.template.impl.TextExpression;
import com.intellij.icons.AllIcons;
import com.intellij.ide.util.MemberChooser;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
/**
* User: anna
* Date: 8/2/12
*/
public class DefineParamsDefaultValueAction extends DelegateWithDefaultParamValueIntentionAction {
public class DefineParamsDefaultValueAction extends PsiElementBaseIntentionAction implements Iconable, LowPriorityAction {
private static final Logger LOG = Logger.getInstance(DefineParamsDefaultValueAction.class);
@Override
public boolean startInWriteAction() {
return false;
}
@NotNull
@Override
public String getFamilyName() {
return "Generate overloaded method with default parameter values";
}
@Override
public Icon getIcon(int flags) {
return AllIcons.Actions.RefactoringBulb;
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
@@ -56,20 +94,106 @@ public class DefineParamsDefaultValueAction extends DelegateWithDefaultParamValu
return true;
}
@Nullable
@Override
public void invoke(@NotNull final Project project, final Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
final PsiParameter[] parameters = getParams(element);
if (parameters == null || parameters.length == 0) return;
final PsiMethod method = (PsiMethod)parameters[0].getDeclarationScope();
final PsiMethod methodPrototype = generateMethodPrototype(method, parameters);
final PsiClass containingClass = method.getContainingClass();
if (containingClass == null) return;
final PsiMethod existingMethod = containingClass.findMethodBySignature(methodPrototype, false);
if (existingMethod != null) {
editor.getCaretModel().moveToOffset(existingMethod.getTextOffset());
HintManager.getInstance().showErrorHint(editor, (existingMethod.isConstructor() ? "Constructor" : "Method") +
" with the chosen signature already exists");
return;
}
if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return;
Runnable runnable = () -> {
final PsiMethod prototype = (PsiMethod)containingClass.addBefore(methodPrototype, method);
RefactoringUtil.fixJavadocsForParams(prototype, new HashSet<PsiParameter>(Arrays.asList(prototype.getParameterList().getParameters())));
TemplateBuilderImpl builder = new TemplateBuilderImpl(prototype);
PsiCodeBlock body = prototype.getBody();
final String callArgs =
"(" + StringUtil.join(method.getParameterList().getParameters(), psiParameter -> {
if (ArrayUtil.find(parameters, psiParameter) > -1) return "IntelliJIDEARulezzz";
return psiParameter.getName();
}, ",") + ");";
final String methodCall;
if (method.getReturnType() == null) {
methodCall = "this";
} else if (!PsiType.VOID.equals(method.getReturnType())) {
methodCall = "return " + method.getName();
} else {
methodCall = method.getName();
}
LOG.assertTrue(body != null);
body.add(JavaPsiFacade.getElementFactory(project).createStatementFromText(methodCall + callArgs, method));
body = (PsiCodeBlock)CodeStyleManager.getInstance(project).reformat(body);
final PsiStatement stmt = body.getStatements()[0];
PsiExpression expr = null;
if (stmt instanceof PsiReturnStatement) {
expr = ((PsiReturnStatement)stmt).getReturnValue();
} else if (stmt instanceof PsiExpressionStatement) {
expr = ((PsiExpressionStatement)stmt).getExpression();
}
if (expr instanceof PsiMethodCallExpression) {
PsiMethodCallExpression methodCallExp = (PsiMethodCallExpression)expr;
RangeMarker rangeMarker = editor.getDocument().createRangeMarker(prototype.getTextRange());
for (PsiParameter parameter : parameters) {
final PsiExpression exprToBeDefault =
methodCallExp.getArgumentList().getExpressions()[method.getParameterList().getParameterIndex(parameter)];
builder.replaceElement(exprToBeDefault, new TextExpression(""));
}
Template template = builder.buildTemplate();
editor.getCaretModel().moveToOffset(rangeMarker.getStartOffset());
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument());
editor.getDocument().deleteString(rangeMarker.getStartOffset(), rangeMarker.getEndOffset());
rangeMarker.dispose();
CreateFromUsageBaseFix.startTemplate(editor, template, project);
}
};
if (startInWriteAction()) {
runnable.run();
} else {
ApplicationManager.getApplication().runWriteAction(runnable);
}
}
@Nullable
protected PsiParameter[] getParams(PsiElement element) {
final PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class);
assert method != null;
final PsiParameter[] parameters = method.getParameterList().getParameters();
if (parameters.length == 1) {
return parameters;
}
final ParameterClassMember[] members = new ParameterClassMember[parameters.length];
for (int i = 0; i < members.length; i++) {
members[i] = new ParameterClassMember(parameters[i]);
}
final PsiParameter selectedParam = PsiTreeUtil.getParentOfType(element, PsiParameter.class);
final int idx = selectedParam != null ? ArrayUtil.find(parameters, selectedParam) : -1;
if (ApplicationManager.getApplication().isUnitTestMode()) {
return idx >= 0 ? new PsiParameter[] {selectedParam} : null;
}
final MemberChooser<ParameterClassMember> chooser =
new MemberChooser<ParameterClassMember>(members, false, true, element.getProject());
chooser.selectElements(members);
if (idx >= 0) {
chooser.selectElements(new ClassMember[] {members[idx]});
}
else {
chooser.selectElements(members);
}
chooser.setTitle("Choose Default Value Parameters");
chooser.setCopyJavadocVisible(false);
if (chooser.showAndGet()) {
final List<ParameterClassMember> elements = chooser.getSelectedElements();
if (elements != null) {
@@ -83,14 +207,34 @@ public class DefineParamsDefaultValueAction extends DelegateWithDefaultParamValu
return null;
}
@Override
public boolean startInWriteAction() {
return false;
}
private static PsiMethod generateMethodPrototype(PsiMethod method, PsiParameter... params) {
final PsiMethod prototype = (PsiMethod)method.copy();
final PsiCodeBlock body = prototype.getBody();
final PsiCodeBlock emptyBody = JavaPsiFacade.getElementFactory(method.getProject()).createMethodFromText("void foo(){}", prototype).getBody();
assert emptyBody != null;
if (body != null) {
body.replace(emptyBody);
} else {
prototype.getModifierList().setModifierProperty(PsiModifier.ABSTRACT, false);
prototype.addBefore(emptyBody, null);
}
@NotNull
@Override
public String getFamilyName() {
return "Generate overloaded method with default parameter values";
final PsiClass aClass = method.getContainingClass();
if (aClass != null && aClass.isInterface() && !method.hasModifierProperty(PsiModifier.STATIC)) {
prototype.getModifierList().setModifierProperty(PsiModifier.DEFAULT, true);
}
final PsiParameterList parameterList = method.getParameterList();
Arrays.sort(params, (p1, p2) -> {
final int parameterIndex1 = parameterList.getParameterIndex(p1);
final int parameterIndex2 = parameterList.getParameterIndex(p2);
return parameterIndex1 > parameterIndex2 ? -1 : 1;
});
for (PsiParameter param : params) {
final int parameterIndex = parameterList.getParameterIndex(param);
prototype.getParameterList().getParameters()[parameterIndex].delete();
}
return prototype;
}
}
@@ -1,191 +0,0 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.intention.LowPriorityAction;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateBuilderImpl;
import com.intellij.codeInsight.template.impl.TextExpression;
import com.intellij.icons.AllIcons;
import com.intellij.lang.StdLanguages;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
/**
* User: anna
*/
public class DelegateWithDefaultParamValueIntentionAction extends PsiElementBaseIntentionAction implements Iconable, LowPriorityAction {
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
final PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class);
if (parameter != null) {
if (!parameter.getLanguage().isKindOf(StdLanguages.JAVA)) return false;
final PsiElement declarationScope = parameter.getDeclarationScope();
if (declarationScope instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)declarationScope;
final PsiClass containingClass = method.getContainingClass();
if (containingClass != null && (!containingClass.isInterface() || PsiUtil.isLanguageLevel8OrHigher(method))) {
if (containingClass.findMethodBySignature(generateMethodPrototype(method, parameter), false) != null) {
return false;
}
setText("Generate overloaded " + (method.isConstructor() ? "constructor" : "method") + " with default parameter value");
return true;
}
}
}
return false;
}
@Override
public Icon getIcon(int flags) {
return AllIcons.Actions.RefactoringBulb;
}
private static PsiMethod generateMethodPrototype(PsiMethod method, PsiParameter... params) {
final PsiMethod prototype = (PsiMethod)method.copy();
final PsiCodeBlock body = prototype.getBody();
final PsiCodeBlock emptyBody = JavaPsiFacade.getElementFactory(method.getProject()).createMethodFromText("void foo(){}", prototype).getBody();
assert emptyBody != null;
if (body != null) {
body.replace(emptyBody);
} else {
prototype.getModifierList().setModifierProperty(PsiModifier.ABSTRACT, false);
prototype.addBefore(emptyBody, null);
}
final PsiClass aClass = method.getContainingClass();
if (aClass != null && aClass.isInterface() && !method.hasModifierProperty(PsiModifier.STATIC)) {
prototype.getModifierList().setModifierProperty(PsiModifier.DEFAULT, true);
}
final PsiParameterList parameterList = method.getParameterList();
Arrays.sort(params, (p1, p2) -> {
final int parameterIndex1 = parameterList.getParameterIndex(p1);
final int parameterIndex2 = parameterList.getParameterIndex(p2);
return parameterIndex1 > parameterIndex2 ? -1 : 1;
});
for (PsiParameter param : params) {
final int parameterIndex = parameterList.getParameterIndex(param);
prototype.getParameterList().getParameters()[parameterIndex].delete();
}
return prototype;
}
@Override
public void invoke(@NotNull final Project project, final Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
final PsiParameter[] parameters = getParams(element);
if (parameters == null || parameters.length == 0) return;
final PsiMethod method = (PsiMethod)parameters[0].getDeclarationScope();
final PsiMethod methodPrototype = generateMethodPrototype(method, parameters);
final PsiMethod existingMethod = method.getContainingClass().findMethodBySignature(methodPrototype, false);
if (existingMethod != null) {
editor.getCaretModel().moveToOffset(existingMethod.getTextOffset());
HintManager.getInstance().showErrorHint(editor, (existingMethod.isConstructor() ? "Constructor" : "Method") +
" with the chosen signature already exists");
return;
}
if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return;
Runnable runnable = () -> {
final PsiMethod prototype = (PsiMethod)method.getContainingClass().addBefore(methodPrototype, method);
RefactoringUtil.fixJavadocsForParams(prototype, new HashSet<PsiParameter>(Arrays.asList(prototype.getParameterList().getParameters())));
TemplateBuilderImpl builder = new TemplateBuilderImpl(prototype);
PsiCodeBlock body = prototype.getBody();
final String callArgs =
"(" + StringUtil.join(method.getParameterList().getParameters(), psiParameter -> {
if (ArrayUtil.find(parameters, psiParameter) > -1) return "IntelliJIDEARulezzz";
return psiParameter.getName();
}, ",") + ");";
final String methodCall;
if (method.getReturnType() == null) {
methodCall = "this";
} else if (!PsiType.VOID.equals(method.getReturnType())) {
methodCall = "return " + method.getName();
} else {
methodCall = method.getName();
}
body.add(JavaPsiFacade.getElementFactory(project).createStatementFromText(methodCall + callArgs, method));
body = (PsiCodeBlock)CodeStyleManager.getInstance(project).reformat(body);
final PsiStatement stmt = body.getStatements()[0];
PsiExpression expr = null;
if (stmt instanceof PsiReturnStatement) {
expr = ((PsiReturnStatement)stmt).getReturnValue();
} else if (stmt instanceof PsiExpressionStatement) {
expr = ((PsiExpressionStatement)stmt).getExpression();
}
if (expr instanceof PsiMethodCallExpression) {
PsiMethodCallExpression methodCallExp = (PsiMethodCallExpression)expr;
RangeMarker rangeMarker = editor.getDocument().createRangeMarker(prototype.getTextRange());
for (PsiParameter parameter : parameters) {
final PsiExpression exprToBeDefault =
methodCallExp.getArgumentList().getExpressions()[method.getParameterList().getParameterIndex(parameter)];
builder.replaceElement(exprToBeDefault, new TextExpression(""));
}
Template template = builder.buildTemplate();
editor.getCaretModel().moveToOffset(rangeMarker.getStartOffset());
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument());
editor.getDocument().deleteString(rangeMarker.getStartOffset(), rangeMarker.getEndOffset());
rangeMarker.dispose();
CreateFromUsageBaseFix.startTemplate(editor, template, project);
}
};
if (startInWriteAction()) {
runnable.run();
} else {
ApplicationManager.getApplication().runWriteAction(runnable);
}
}
@Nullable
protected PsiParameter[] getParams(PsiElement element) {
return new PsiParameter[]{PsiTreeUtil.getParentOfType(element, PsiParameter.class)};
}
@NotNull
@Override
public String getFamilyName() {
return "Generate overloaded method with default parameter value";
}
}
@@ -63,7 +63,7 @@ public class ExtractClassHandler implements ElementsHandler {
if (cannotRefactorMessage != null) {
CommonRefactoringUtil.showErrorHint(project, editor,
RefactorJBundle.message("cannot.perform.the.refactoring") + cannotRefactorMessage,
null, getHelpID());
ExtractClassProcessor.REFACTORING_NAME, getHelpID());
return;
}
new ExtractClassDialog(containingClass, selectedMember).show();
@@ -66,6 +66,7 @@ import java.util.*;
public class ExtractClassProcessor extends FixableUsagesRefactoringProcessor {
private static final Logger logger = Logger.getInstance("com.siyeh.rpp.extractclass.ExtractClassProcessor");
@NonNls public static final String REFACTORING_NAME = "Extract Delegate";
private final PsiClass sourceClass;
private final List<PsiField> fields;
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
class Test {
void foo() {
foo(<caret>);
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
abstract class Test {
int foo(boolean... args) {
return foo(<caret>, args);
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
class Test {
int foo() {
return foo();
@@ -1,4 +1,4 @@
// "Generate overloaded constructor with default parameter value" "true"
// "Generate overloaded constructor with default parameter values" "true"
class Test {
Test() {
this(<caret>);
@@ -0,0 +1,6 @@
// "Generate overloaded method with default parameter values" "true"
class Test {
void foo(){}
void foo(int ii){
}
}
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
interface Test {
default void foo() {
foo();
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
class Test {
/**
*/
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
class Test {
int foo() {
return foo(<caret>);
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
interface Test {
static void foo() {
foo();
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
class Test {
<T> int foo(boolean... args) {
return foo(<caret>, args);
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
class Test {
int foo(boolean... args) {
return foo(<caret>, args);
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
class Test {
void foo(int i<caret>i){
}
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
abstract class Test {
abstract int foo(int i<caret>i, boolean... args);
}
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
class Test {
int foo(int i<caret>i){
//comment1
@@ -1,4 +1,4 @@
// "Generate overloaded constructor with default parameter value" "true"
// "Generate overloaded constructor with default parameter values" "true"
class Test {
Test(int i<caret>i){}
}
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "false"
// "Generate overloaded method with default parameter values" "true"
class Test {
void foo(){}
void foo(int i<caret>i){
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
interface Test {
void foo(int i<caret>i);
}
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
class Test {
/**
* @param i
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
class Test {
int foo(int i<caret>i){
return 1;
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
interface Test {
static void foo(int i<caret>i) {}
}
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
class Test {
<T> int foo(T i<caret>i, boolean... args){
return 1;
@@ -1,4 +1,4 @@
// "Generate overloaded method with default parameter value" "true"
// "Generate overloaded method with default parameter values" "true"
class Test {
int foo(int i<caret>i, boolean... args){
return 1;
@@ -30,8 +30,9 @@ public class DelegateWithDefaultParamValueTest extends LightQuickFixParameterize
if (actionShouldBeAvailable) {
TemplateState state = TemplateManagerImpl.getTemplateState(getEditor());
assert state != null;
state.gotoEnd(false);
if (state != null) {
state.gotoEnd(false);
}
}
}
@@ -17,6 +17,7 @@ package com.intellij.diff.comparison;
import com.intellij.diff.fragments.DiffFragment;
import com.intellij.diff.fragments.LineFragment;
import com.intellij.diff.fragments.MergeLineFragment;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.progress.ProgressIndicator;
import org.jetbrains.annotations.NotNull;
@@ -61,6 +62,16 @@ public abstract class ComparisonManager {
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) throws DiffTooBigException;
/**
* Compare three texts by-line (LEFT - BASE - RIGHT)
*/
@NotNull
public abstract List<MergeLineFragment> compareLines(@NotNull CharSequence text1,
@NotNull CharSequence text2,
@NotNull CharSequence text3,
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) throws DiffTooBigException;
/**
* Compare two texts by-word
*/
@@ -15,13 +15,8 @@
*/
package com.intellij.diff.comparison;
import com.intellij.diff.comparison.iterables.DiffIterableUtil.*;
import com.intellij.diff.comparison.iterables.DiffIterableUtil.ExpandChangeBuilder;
import com.intellij.diff.comparison.iterables.FairDiffIterable;
import com.intellij.diff.fragments.LineFragment;
import com.intellij.diff.fragments.LineFragmentImpl;
import com.intellij.diff.fragments.MergeLineFragment;
import com.intellij.diff.fragments.MergeLineFragmentImpl;
import com.intellij.diff.util.IntPair;
import com.intellij.diff.util.MergeRange;
import com.intellij.diff.util.Range;
import com.intellij.openapi.progress.ProgressIndicator;
@@ -29,68 +24,77 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.Equality;
import gnu.trove.TIntArrayList;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import static com.intellij.diff.comparison.ComparisonPolicy.IGNORE_WHITESPACES;
import static com.intellij.diff.comparison.TrimUtil.trimEnd;
import static com.intellij.diff.comparison.TrimUtil.trimStart;
import static com.intellij.diff.comparison.iterables.DiffIterableUtil.*;
import static com.intellij.diff.comparison.iterables.DiffIterableUtil.diff;
import static com.intellij.diff.comparison.iterables.DiffIterableUtil.fair;
import static com.intellij.openapi.util.text.StringUtil.isWhiteSpace;
public class ByLine {
@NotNull
public static List<LineFragment> compare(@NotNull CharSequence text1,
@NotNull CharSequence text2,
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) {
public static FairDiffIterable compare(@NotNull List<? extends CharSequence> lines1,
@NotNull List<? extends CharSequence> lines2,
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) {
indicator.checkCanceled();
List<Line> lines1 = getLines(text1, policy);
List<Line> lines2 = getLines(text2, policy);
FairDiffIterable changes = compareSmart(lines1, lines2, indicator);
changes = optimizeLineChunks(lines1, lines2, changes, indicator);
changes = expandRanges(lines1, lines2, changes, indicator);
return convertIntoFragments(lines1, lines2, changes);
return doCompare(getLines(lines1, policy), getLines(lines2, policy), policy, indicator);
}
@NotNull
public static List<LineFragment> compareTwoStep(@NotNull CharSequence text1,
@NotNull CharSequence text2,
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) {
public static List<MergeRange> compare(@NotNull List<? extends CharSequence> lines1,
@NotNull List<? extends CharSequence> lines2,
@NotNull List<? extends CharSequence> lines3,
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) {
indicator.checkCanceled();
return doCompare(getLines(lines1, policy), getLines(lines2, policy), getLines(lines3, policy), policy, indicator);
}
//
// Impl
//
@NotNull
static FairDiffIterable doCompare(@NotNull List<Line> lines1,
@NotNull List<Line> lines2,
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) {
indicator.checkCanceled();
List<Line> lines1 = getLines(text1, policy);
List<Line> lines2 = getLines(text2, policy);
if (policy == IGNORE_WHITESPACES) {
FairDiffIterable changes = compareSmart(lines1, lines2, indicator);
changes = optimizeLineChunks(lines1, lines2, changes, indicator);
return correctChangesSecondStepIW(lines1, lines2, changes);
}
else {
List<Line> iwLines1 = convertMode(lines1, IGNORE_WHITESPACES);
List<Line> iwLines2 = convertMode(lines2, IGNORE_WHITESPACES);
List<Line> iwLines1 = convertToIgnoreWhitespace(lines1);
List<Line> iwLines2 = convertToIgnoreWhitespace(lines2);
FairDiffIterable iwChanges = compareSmart(iwLines1, iwLines2, indicator);
iwChanges = optimizeLineChunks(lines1, lines2, iwChanges, indicator);
FairDiffIterable changes = correctChangesSecondStep(lines1, lines2, iwChanges);
return convertIntoFragments(lines1, lines2, changes);
FairDiffIterable iwChanges = compareSmart(iwLines1, iwLines2, indicator);
iwChanges = optimizeLineChunks(lines1, lines2, iwChanges, indicator);
return correctChangesSecondStep(lines1, lines2, iwChanges);
}
}
@NotNull
public static List<MergeLineFragment> compareTwoStep(@NotNull CharSequence text1,
@NotNull CharSequence text2,
@NotNull CharSequence text3,
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) {
static List<MergeRange> doCompare(@NotNull List<Line> lines1,
@NotNull List<Line> lines2,
@NotNull List<Line> lines3,
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) {
indicator.checkCanceled();
List<Line> lines1 = getLines(text1, policy);
List<Line> lines2 = getLines(text2, policy);
List<Line> lines3 = getLines(text3, policy);
List<Line> iwLines1 = convertToIgnoreWhitespace(lines1);
List<Line> iwLines2 = convertToIgnoreWhitespace(lines2);
List<Line> iwLines3 = convertToIgnoreWhitespace(lines3);
List<Line> iwLines1 = convertMode(lines1, IGNORE_WHITESPACES);
List<Line> iwLines2 = convertMode(lines2, IGNORE_WHITESPACES);
List<Line> iwLines3 = convertMode(lines3, IGNORE_WHITESPACES);
FairDiffIterable iwChanges1 = compareSmart(iwLines2, iwLines1, indicator);
iwChanges1 = optimizeLineChunks(lines2, lines1, iwChanges1, indicator);
@@ -100,18 +104,30 @@ public class ByLine {
iwChanges2 = optimizeLineChunks(lines2, lines3, iwChanges2, indicator);
FairDiffIterable iterable2 = correctChangesSecondStep(lines2, lines3, iwChanges2);
List<MergeRange> conflicts = ComparisonMergeUtil.buildFair(iterable1, iterable2, indicator);
return convertIntoFragments(conflicts);
return ComparisonMergeUtil.buildFair(iterable1, iterable2, indicator);
}
//
// Impl
//
@NotNull
private static FairDiffIterable correctChangesSecondStep(@NotNull final List<Line> lines1,
@NotNull final List<Line> lines2,
@NotNull final FairDiffIterable changes) {
return doCorrectChangesSecondStep(lines1, lines2, changes,
Equality.CANONICAL);
}
@NotNull
private static FairDiffIterable correctChangesSecondStepIW(@NotNull final List<Line> lines1,
@NotNull final List<Line> lines2,
@NotNull final FairDiffIterable changes) {
return doCorrectChangesSecondStep(lines1, lines2, changes,
(l1, l2) -> StringUtil.equals(l1.getContent(), l2.getContent()));
}
@NotNull
private static FairDiffIterable doCorrectChangesSecondStep(@NotNull final List<Line> lines1,
@NotNull final List<Line> lines2,
@NotNull final FairDiffIterable changes,
@NotNull final Equality<Line> maximisingEquality) {
/*
* We want to fix invalid matching here:
*
@@ -156,7 +172,7 @@ public class ByLine {
Line line2 = lines2.get(index2);
if (!StringUtil.equalsIgnoreWhitespaces(sample, line1.getContent())) {
if (line1.equals(line2)) {
if (maximisingEquality.equals(line1, line2)) {
flush(index1, index2);
builder.markEqual(index1, index2);
}
@@ -197,13 +213,24 @@ public class ByLine {
}
private void alignExactMatching(TIntArrayList subLines1, TIntArrayList subLines2) {
if (subLines1.size() == subLines2.size()) return;
int n = Math.max(subLines1.size(), subLines2.size());
if (n > 10) return; // we use brute-force algorithm (C_n_k). This will limit search space by ~250 cases.
boolean skipAligning = n > 10 || // we use brute-force algorithm (C_n_k). This will limit search space by ~250 cases.
subLines1.size() == subLines2.size(); // nothing to do
if (skipAligning) {
int count = Math.min(subLines1.size(), subLines2.size());
for (int i = 0; i < count; i++) {
int index1 = subLines1.get(i);
int index2 = subLines2.get(i);
if (lines1.get(index1).equals(lines2.get(index2))) {
builder.markEqual(index1, index2);
}
}
return;
}
if (subLines1.size() < subLines2.size()) {
int[] matching = getBestMatchingAlignment(subLines1, subLines2, lines1, lines2);
int[] matching = getBestMatchingAlignment(subLines1, subLines2, lines1, lines2, maximisingEquality);
for (int i = 0; i < subLines1.size(); i++) {
int index1 = subLines1.get(i);
int index2 = subLines2.get(matching[i]);
@@ -213,7 +240,7 @@ public class ByLine {
}
}
else {
int[] matching = getBestMatchingAlignment(subLines2, subLines1, lines2, lines1);
int[] matching = getBestMatchingAlignment(subLines2, subLines1, lines2, lines1, maximisingEquality);
for (int i = 0; i < subLines2.size(); i++) {
int index1 = subLines1.get(matching[i]);
int index2 = subLines2.get(i);
@@ -232,7 +259,8 @@ public class ByLine {
private static int[] getBestMatchingAlignment(@NotNull final TIntArrayList subLines1,
@NotNull final TIntArrayList subLines2,
@NotNull final List<Line> lines1,
@NotNull final List<Line> lines2) {
@NotNull final List<Line> lines2,
@NotNull final Equality<Line> maximisingEquality) {
assert subLines1.size() < subLines2.size();
final int size = subLines1.size();
@@ -267,7 +295,7 @@ public class ByLine {
for (int i = 0; i < size; i++) {
int index1 = subLines1.get(i);
int index2 = subLines2.get(comb[i]);
if (lines1.get(index1).equals(lines2.get(index2))) weight++;
if (maximisingEquality.equals(lines1.get(index1), lines2.get(index2))) weight++;
}
if (weight > bestWeight) {
@@ -288,45 +316,6 @@ public class ByLine {
return new ChunkOptimizer.LineChunkOptimizer(lines1, lines2, iterable, indicator).build();
}
@NotNull
private static List<LineFragment> convertIntoFragments(@NotNull List<Line> lines1,
@NotNull List<Line> lines2,
@NotNull FairDiffIterable changes) {
List<LineFragment> fragments = new ArrayList<>();
for (Range ch : changes.iterateChanges()) {
IntPair offsets1 = getOffsets(lines1, ch.start1, ch.end1);
IntPair offsets2 = getOffsets(lines2, ch.start2, ch.end2);
fragments.add(new LineFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2,
offsets1.val1, offsets1.val2, offsets2.val1, offsets2.val2));
}
return fragments;
}
@NotNull
private static List<MergeLineFragment> convertIntoFragments(@NotNull List<MergeRange> conflicts) {
return ContainerUtil.map(conflicts, ch -> new MergeLineFragmentImpl(ch));
}
@NotNull
private static IntPair getOffsets(@NotNull List<Line> lines, int startIndex, int endIndex) {
if (startIndex == endIndex) {
int offset;
if (startIndex < lines.size()) {
offset = lines.get(startIndex).getOffset1();
}
else {
offset = lines.get(lines.size() - 1).getOffset2();
}
return new IntPair(offset, offset);
}
else {
int offset1 = lines.get(startIndex).getOffset1();
int offset2 = lines.get(endIndex - 1).getOffset2();
return new IntPair(offset1, offset2);
}
}
/*
* Compare lines in two steps:
* - compare ignoring "unimportant" lines
@@ -361,90 +350,44 @@ public class ByLine {
return Pair.create(bigLines, indexes);
}
@NotNull
private static FairDiffIterable expandRanges(@NotNull List<Line> lines1,
@NotNull List<Line> lines2,
@NotNull FairDiffIterable iterable,
@NotNull ProgressIndicator indicator) {
List<Range> changes = new ArrayList<>();
for (Range ch : iterable.iterateChanges()) {
Range expanded = TrimUtil.expand(lines1, lines2, ch.start1, ch.start2, ch.end1, ch.end2);
if (!expanded.isEmpty()) changes.add(expanded);
}
return fair(create(changes, lines1.size(), lines2.size()));
}
//
// Lines
//
@NotNull
private static List<Line> getLines(@NotNull CharSequence text, @NotNull ComparisonPolicy policy) {
List<Line> lines = new ArrayList<>();
int offset = 0;
while (true) {
Line line = createLine(text, offset, policy);
lines.add(line);
offset = line.getOffset2();
if (!line.hasNewline()) break;
}
return lines;
private static List<Line> getLines(@NotNull List<? extends CharSequence> text, @NotNull ComparisonPolicy policy) {
return ContainerUtil.map(text, (line) -> new Line(line, policy));
}
@NotNull
private static Line createLine(@NotNull CharSequence text, int offset, @NotNull ComparisonPolicy policy) {
switch (policy) {
case DEFAULT:
return Line.createDefault(text, offset);
case IGNORE_WHITESPACES:
return Line.createIgnore(text, offset);
case TRIM_WHITESPACES:
return Line.createTrim(text, offset);
default:
throw new IllegalArgumentException(policy.name());
}
}
@NotNull
private static List<Line> convertToIgnoreWhitespace(@NotNull List<Line> original) {
private static List<Line> convertMode(@NotNull List<Line> original, @NotNull ComparisonPolicy policy) {
List<Line> result = new ArrayList<>(original.size());
for (Line line : original) {
result.add(Line.createIgnore(line.getOriginalText(), line.getOffset1()));
result.add(new Line(line.getContent(), policy));
}
return result;
}
static class Line extends TextChunk {
enum Mode {DEFAULT, TRIM, IGNORE}
@NotNull private final Mode myMode;
static class Line {
@NotNull private final CharSequence myText;
@NotNull private final ComparisonPolicy myPolicy;
private final int myHash;
private final int myNonSpaceChars;
private final boolean myNewline;
public Line(@NotNull CharSequence text, int offset1, int offset2,
@NotNull Mode mode, int hash, int nonSpaceChars, boolean newline) {
super(text, offset1, offset2);
myMode = mode;
myHash = hash;
myNonSpaceChars = nonSpaceChars;
myNewline = newline;
}
public boolean hasNewline() {
return myNewline;
public Line(@NotNull CharSequence text, @NotNull ComparisonPolicy policy) {
myText = text;
myPolicy = policy;
myHash = hashCode(text, policy);
myNonSpaceChars = countNonSpaceChars(text);
}
@NotNull
@Override
public CharSequence getContent() {
return getOriginalText().subSequence(getOffset1(), getOffset2() - (myNewline ? 1 : 0));
return myText;
}
public int getNonSpaceChars() {
return myNonSpaceChars;
}
@Override
@@ -453,20 +396,11 @@ public class ByLine {
if (o == null || getClass() != o.getClass()) return false;
Line line = (Line)o;
assert myMode == line.myMode;
assert myPolicy == line.myPolicy;
if (hashCode() != line.hashCode()) return false;
switch (myMode) {
case DEFAULT:
return StringUtil.equals(getContent(), line.getContent());
case TRIM:
return StringUtil.equalsTrimWhitespaces(getContent(), line.getContent());
case IGNORE:
return StringUtil.equalsIgnoreWhitespaces(getContent(), line.getContent());
default:
throw new IllegalArgumentException(myMode.toString());
}
return equals(getContent(), line.getContent(), myPolicy);
}
@Override
@@ -474,87 +408,47 @@ public class ByLine {
return myHash;
}
public int getNonSpaceChars() {
return myNonSpaceChars;
}
public static Line createDefault(@NotNull CharSequence text, int startOffset) {
int len = text.length();
int h = 0;
private static int countNonSpaceChars(@NotNull CharSequence text) {
int nonSpace = 0;
boolean newline = false;
int offset = startOffset;
int len = text.length();
int offset = 0;
while (offset < len) {
char c = text.charAt(offset);
if (c == '\n') {
offset++;
newline = true;
break;
}
if (!isWhiteSpace(c)) nonSpace++;
h = 31 * h + c;
offset++;
}
return new Line(text, startOffset, offset, Mode.DEFAULT, h, nonSpace, newline);
}
public static Line createIgnore(@NotNull CharSequence text, int startOffset) {
int len = text.length();
int h = 0;
int nonSpace = 0;
boolean newline = false;
int offset = startOffset;
while (offset < len) {
char c = text.charAt(offset);
if (c == '\n') {
offset++;
newline = true;
break;
}
if (!isWhiteSpace(c)) {
nonSpace++;
h = 31 * h + c;
}
offset++;
}
return new Line(text, startOffset, offset, Mode.IGNORE, h, nonSpace, newline);
}
public static Line createTrim(@NotNull CharSequence text, int startOffset) {
int len = text.length();
int nonSpace = 0;
boolean newline = false;
int offset = startOffset;
while (offset < len) {
char c = text.charAt(offset);
if (c == '\n') {
offset++;
newline = true;
break;
}
if (!isWhiteSpace(c)) nonSpace++;
offset++;
}
int h = calcTrimHash(text, startOffset, offset);
return new Line(text, startOffset, offset, Mode.TRIM, h, nonSpace, newline);
return nonSpace;
}
private static boolean equals(@NotNull CharSequence text1, @NotNull CharSequence text2, @NotNull ComparisonPolicy policy) {
switch (policy) {
case DEFAULT:
return StringUtil.equals(text1, text2);
case TRIM_WHITESPACES:
return StringUtil.equalsTrimWhitespaces(text1, text2);
case IGNORE_WHITESPACES:
return StringUtil.equalsIgnoreWhitespaces(text1, text2);
default:
throw new IllegalArgumentException(policy.toString());
}
}
private static int calcTrimHash(@NotNull CharSequence text, int offset1, int offset2) {
offset1 = trimStart(text, offset1, offset2);
offset2 = trimEnd(text, offset1, offset2);
return StringUtil.stringHashCode(text, offset1, offset2);
private static int hashCode(@NotNull CharSequence text, @NotNull ComparisonPolicy policy) {
switch (policy) {
case DEFAULT:
return StringUtil.stringHashCode(text);
case TRIM_WHITESPACES:
int offset1 = trimStart(text, 0, text.length());
int offset2 = trimEnd(text, offset1, text.length());
return StringUtil.stringHashCode(text, offset1, offset2);
case IGNORE_WHITESPACES:
return StringUtil.stringHashCodeIgnoreWhitespaces(text);
default:
throw new IllegalArgumentException(policy.name());
}
}
}
}
@@ -17,24 +17,23 @@ package com.intellij.diff.comparison;
import com.intellij.diff.comparison.LineFragmentSplitter.WordBlock;
import com.intellij.diff.comparison.iterables.DiffIterable;
import com.intellij.diff.comparison.iterables.DiffIterableUtil;
import com.intellij.diff.comparison.iterables.DiffIterableUtil.*;
import com.intellij.diff.comparison.iterables.FairDiffIterable;
import com.intellij.diff.fragments.DiffFragment;
import com.intellij.diff.fragments.MergeWordFragment;
import com.intellij.diff.fragments.MergeWordFragmentImpl;
import com.intellij.diff.util.MergeRange;
import com.intellij.diff.util.Range;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.MergingCharSequence;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import static com.intellij.diff.comparison.ComparisonManagerImpl.convertIntoDiffFragments;
import static com.intellij.diff.comparison.ComparisonManagerImpl.convertIntoMergeWordFragments;
import static com.intellij.diff.comparison.TrimUtil.*;
import static com.intellij.diff.comparison.TrimUtil.trim;
import static com.intellij.diff.comparison.iterables.DiffIterableUtil.*;
@@ -66,7 +65,7 @@ public class ByWord {
FairDiffIterable delimitersIterable = matchAdjustmentDelimiters(text1, text2, words1, words2, wordChanges, indicator);
DiffIterable iterable = matchAdjustmentWhitespaces(text1, text2, delimitersIterable, policy, indicator);
return convertIntoFragments(iterable);
return convertIntoDiffFragments(iterable);
}
@NotNull
@@ -92,7 +91,7 @@ public class ByWord {
List<MergeRange> wordConflicts = ComparisonMergeUtil.buildFair(iterable1, iterable2, indicator);
List<MergeRange> result = matchAdjustmentWhitespaces(text1, text2, text3, wordConflicts, policy, indicator);
return convertIntoFragments(result);
return convertIntoMergeWordFragments(result);
}
@NotNull
@@ -144,7 +143,7 @@ public class ByWord {
offsets.start1, offsets.start2, indicator);
DiffIterable iterable = matchAdjustmentWhitespaces(subtext1, subtext2, delimitersIterable, policy, indicator);
List<DiffFragment> fragments = convertIntoFragments(iterable);
List<DiffFragment> fragments = convertIntoDiffFragments(iterable);
int newlines1 = countNewlines(subwords1);
int newlines2 = countNewlines(subwords2);
@@ -159,16 +158,6 @@ public class ByWord {
// Impl
//
@NotNull
private static List<MergeWordFragment> convertIntoFragments(@NotNull List<MergeRange> conflicts) {
return ContainerUtil.map(conflicts, ch -> new MergeWordFragmentImpl(ch));
}
@NotNull
private static List<DiffFragment> convertIntoFragments(@NotNull DiffIterable iterable) {
return DiffIterableUtil.convertIntoFragments(iterable);
}
@NotNull
private static FairDiffIterable optimizeWordChunks(@NotNull CharSequence text1,
@NotNull CharSequence text2,
@@ -863,14 +852,32 @@ public class ByWord {
int getOffset2();
}
static class WordChunk extends TextChunk implements InlineChunk {
static class WordChunk implements InlineChunk {
@NotNull private final CharSequence myText;
private final int myOffset1;
private final int myOffset2;
private final int myHash;
public WordChunk(@NotNull CharSequence text, int offset1, int offset2, int hash) {
super(text, offset1, offset2);
myText = text;
myOffset1 = offset1;
myOffset2 = offset2;
myHash = hash;
}
@NotNull
public CharSequence getContent() {
return myText.subSequence(myOffset1, myOffset2);
}
public int getOffset1() {
return myOffset1;
}
public int getOffset2() {
return myOffset2;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -15,10 +15,11 @@
*/
package com.intellij.diff.comparison;
import com.intellij.diff.fragments.DiffFragment;
import com.intellij.diff.fragments.DiffFragmentImpl;
import com.intellij.diff.fragments.LineFragment;
import com.intellij.diff.fragments.LineFragmentImpl;
import com.intellij.diff.comparison.iterables.DiffIterable;
import com.intellij.diff.comparison.iterables.FairDiffIterable;
import com.intellij.diff.fragments.*;
import com.intellij.diff.util.IntPair;
import com.intellij.diff.util.MergeRange;
import com.intellij.diff.util.Range;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
@@ -33,8 +34,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.intellij.diff.comparison.iterables.DiffIterableUtil.convertIntoFragments;
public class ComparisonManagerImpl extends ComparisonManager {
public static final Logger LOG = Logger.getInstance(ComparisonManagerImpl.class);
@@ -44,12 +43,24 @@ public class ComparisonManagerImpl extends ComparisonManager {
@NotNull CharSequence text2,
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) throws DiffTooBigException {
if (policy == ComparisonPolicy.IGNORE_WHITESPACES) {
return ByLine.compare(text1, text2, policy, indicator);
}
else {
return ByLine.compareTwoStep(text1, text2, policy, indicator);
}
List<Line> lines1 = getLines(text1);
List<Line> lines2 = getLines(text2);
FairDiffIterable iterable = ByLine.compare(lines1, lines2, policy, indicator);
return convertIntoLineFragments(lines1, lines2, iterable);
}
@NotNull
@Override
public List<MergeLineFragment> compareLines(@NotNull CharSequence text1,
@NotNull CharSequence text2,
@NotNull CharSequence text3,
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) throws DiffTooBigException {
List<Line> lines1 = getLines(text1);
List<Line> lines2 = getLines(text2);
List<Line> lines3 = getLines(text3);
List<MergeRange> ranges = ByLine.compare(lines1, lines2, lines3, policy, indicator);
return convertIntoMergeLineFragments(ranges);
}
@NotNull
@@ -145,13 +156,13 @@ public class ComparisonManagerImpl extends ComparisonManager {
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) throws DiffTooBigException {
if (policy == ComparisonPolicy.IGNORE_WHITESPACES) {
return convertIntoFragments(ByChar.compareIgnoreWhitespaces(text1, text2, indicator));
return convertIntoDiffFragments(ByChar.compareIgnoreWhitespaces(text1, text2, indicator));
}
if (policy == ComparisonPolicy.DEFAULT) {
return convertIntoFragments(ByChar.compareTwoStep(text1, text2, indicator));
return convertIntoDiffFragments(ByChar.compareTwoStep(text1, text2, indicator));
}
LOG.warn(policy.toString() + " is not supported by ByChar comparison");
return convertIntoFragments(ByChar.compareTwoStep(text1, text2, indicator));
return convertIntoDiffFragments(ByChar.compareTwoStep(text1, text2, indicator));
}
@Override
@@ -159,6 +170,63 @@ public class ComparisonManagerImpl extends ComparisonManager {
return ComparisonUtil.isEquals(text1, text2, policy);
}
//
// Fragments
//
@NotNull
public static List<DiffFragment> convertIntoDiffFragments(@NotNull DiffIterable changes) {
final List<DiffFragment> fragments = new ArrayList<>();
for (Range ch : changes.iterateChanges()) {
fragments.add(new DiffFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2));
}
return fragments;
}
@NotNull
public static List<LineFragment> convertIntoLineFragments(@NotNull List<Line> lines1,
@NotNull List<Line> lines2,
@NotNull FairDiffIterable changes) {
List<LineFragment> fragments = new ArrayList<>();
for (Range ch : changes.iterateChanges()) {
IntPair offsets1 = getOffsets(lines1, ch.start1, ch.end1);
IntPair offsets2 = getOffsets(lines2, ch.start2, ch.end2);
fragments.add(new LineFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2,
offsets1.val1, offsets1.val2, offsets2.val1, offsets2.val2));
}
return fragments;
}
@NotNull
private static IntPair getOffsets(@NotNull List<Line> lines, int startIndex, int endIndex) {
if (startIndex == endIndex) {
int offset;
if (startIndex < lines.size()) {
offset = lines.get(startIndex).getOffset1();
}
else {
offset = lines.get(lines.size() - 1).getOffset2();
}
return new IntPair(offset, offset);
}
else {
int offset1 = lines.get(startIndex).getOffset1();
int offset2 = lines.get(endIndex - 1).getOffset2();
return new IntPair(offset1, offset2);
}
}
@NotNull
public static List<MergeLineFragment> convertIntoMergeLineFragments(@NotNull List<MergeRange> conflicts) {
return ContainerUtil.map(conflicts, ch -> new MergeLineFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2, ch.start3, ch.end3));
}
@NotNull
public static List<MergeWordFragment> convertIntoMergeWordFragments(@NotNull List<MergeRange> conflicts) {
return ContainerUtil.map(conflicts, ch -> new MergeWordFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2, ch.start3, ch.end3));
}
//
// Post process line fragments
//
@@ -304,4 +372,45 @@ public class ComparisonManagerImpl extends ComparisonManager {
int length2 = lineFragment.getEndOffset2() - lineFragment.getStartOffset2();
return Collections.singletonList(new DiffFragmentImpl(0, length1, 0, length2));
}
@NotNull
private static List<Line> getLines(@NotNull CharSequence text) {
List<Line> lines = new ArrayList<>();
int offset = 0;
while (true) {
int lineEnd = StringUtil.indexOf(text, '\n', offset);
if (lineEnd != -1) {
lines.add(new Line(text, offset, lineEnd, true));
offset = lineEnd + 1;
}
else {
lines.add(new Line(text, offset, text.length(), false));
break;
}
}
return lines;
}
private static class Line extends CharSequenceSubSequence {
private final int myOffset1;
private final int myOffset2;
private final boolean myNewline;
public Line(@NotNull CharSequence chars, int offset1, int offset2, boolean newline) {
super(chars, offset1, offset2);
myOffset1 = offset1;
myOffset2 = offset2;
myNewline = newline;
}
public int getOffset1() {
return myOffset1;
}
public int getOffset2() {
return myOffset2 + (myNewline ? 1 : 0);
}
}
}
@@ -1,59 +0,0 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.diff.comparison;
import org.jetbrains.annotations.NotNull;
abstract class TextChunk {
@NotNull private final CharSequence myText;
private final int myOffset1;
private final int myOffset2;
public TextChunk(@NotNull CharSequence text, int offset1, int offset2) {
myText = text;
myOffset1 = offset1;
myOffset2 = offset2;
}
@Override
public abstract int hashCode();
@Override
public abstract boolean equals(Object obj);
@NotNull
public CharSequence getContent() {
return myText.subSequence(myOffset1, myOffset2);
}
@NotNull
public CharSequence getOriginalText() {
return myText;
}
public int getOffset1() {
return myOffset1;
}
public int getOffset2() {
return myOffset2;
}
@Override
public String toString() {
return getContent().toString();
}
}
@@ -18,7 +18,6 @@ package com.intellij.diff.comparison.iterables;
import com.intellij.diff.comparison.DiffTooBigException;
import com.intellij.diff.comparison.TrimUtil;
import com.intellij.diff.fragments.DiffFragment;
import com.intellij.diff.fragments.DiffFragmentImpl;
import com.intellij.diff.util.Range;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.util.Comparing;
@@ -88,20 +87,6 @@ public class DiffIterableUtil {
return diff(data1, data2, indicator);
}
/*
* Compare two arrays, basing on equals() and hashCode() of it's elements
*
* If the input arrays are too big, "everything is changed" can be returned.
*/
@NotNull
public static <T> FairDiffIterable diffSomehow(@NotNull T[] data1, @NotNull T[] data2, @NotNull ProgressIndicator indicator) {
indicator.checkCanceled();
// TODO: use ProgressIndicator inside
Diff.Change change = Diff.buildChangesSomehow(data1, data2);
return fair(create(change, data1.length, data2.length));
}
//
// Iterable
//
@@ -158,15 +143,6 @@ public class DiffIterableUtil {
// Misc
//
@NotNull
public static List<DiffFragment> convertIntoFragments(@NotNull DiffIterable changes) {
final List<DiffFragment> fragments = new ArrayList<>();
for (Range ch : changes.iterateChanges()) {
fragments.add(new DiffFragmentImpl(ch.start1, ch.end1, ch.start2, ch.end2));
}
return fragments;
}
@NotNull
public static Iterable<Pair<Range, Boolean>> iterateAll(@NotNull final DiffIterable iterable) {
return () -> new Iterator<Pair<Range, Boolean>>() {
@@ -15,7 +15,6 @@
*/
package com.intellij.diff.fragments;
import com.intellij.diff.util.MergeRange;
import com.intellij.diff.util.ThreeSide;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -57,14 +56,6 @@ public class MergeLineFragmentImpl implements MergeLineFragment {
myInnerFragments = innerFragments;
}
public MergeLineFragmentImpl(@NotNull MergeRange range) {
this(range, null);
}
public MergeLineFragmentImpl(@NotNull MergeRange range, @Nullable List<MergeWordFragment> innerFragments) {
this(range.start1, range.end1, range.start2, range.end2, range.start3, range.end3, innerFragments);
}
public MergeLineFragmentImpl(@NotNull MergeLineFragment fragment, @Nullable List<MergeWordFragment> fragments) {
this(fragment.getStartLine(ThreeSide.LEFT), fragment.getEndLine(ThreeSide.LEFT),
fragment.getStartLine(ThreeSide.BASE), fragment.getEndLine(ThreeSide.BASE),
@@ -41,10 +41,6 @@ public class MergeWordFragmentImpl implements MergeWordFragment {
myEndOffset3 = endOffset3;
}
public MergeWordFragmentImpl(@NotNull MergeRange range) {
this(range.start1, range.end1, range.start2, range.end2, range.start3, range.end3);
}
@Override
public int getStartOffset(@NotNull ThreeSide side) {
return side.select(myStartOffset1, myStartOffset2, myStartOffset3);
@@ -18,7 +18,7 @@ package com.intellij.diff.merge;
import com.intellij.diff.DiffContext;
import com.intellij.diff.FrameDiffTool;
import com.intellij.diff.actions.ProxyUndoRedoAction;
import com.intellij.diff.comparison.ByLine;
import com.intellij.diff.comparison.ComparisonManager;
import com.intellij.diff.comparison.ComparisonMergeUtil;
import com.intellij.diff.comparison.ComparisonPolicy;
import com.intellij.diff.comparison.DiffTooBigException;
@@ -363,8 +363,9 @@ public class TextMergeViewer implements MergeTool.MergeViewer {
return ContainerUtil.map(documents, Document::getImmutableCharSequence);
});
List<MergeLineFragment> lineFragments = ByLine.compareTwoStep(sequences.get(0), sequences.get(1), sequences.get(2),
ComparisonPolicy.DEFAULT, indicator);
ComparisonManager manager = ComparisonManager.getInstance();
List<MergeLineFragment> lineFragments = manager.compareLines(sequences.get(0), sequences.get(1), sequences.get(2),
ComparisonPolicy.DEFAULT, indicator);
List<MergeConflictType> conflictTypes = ReadAction.compute(() -> {
indicator.checkCanceled();
@@ -16,7 +16,7 @@
package com.intellij.diff.tools.simple;
import com.intellij.diff.DiffContext;
import com.intellij.diff.comparison.ByLine;
import com.intellij.diff.comparison.ComparisonManager;
import com.intellij.diff.comparison.ComparisonPolicy;
import com.intellij.diff.comparison.DiffTooBigException;
import com.intellij.diff.contents.DiffContent;
@@ -125,8 +125,10 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewerEx {
});
final ComparisonPolicy comparisonPolicy = getIgnorePolicy().getComparisonPolicy();
List<MergeLineFragment> lineFragments = ByLine.compareTwoStep(sequences.get(0), sequences.get(1), sequences.get(2),
comparisonPolicy, indicator);
ComparisonManager manager = ComparisonManager.getInstance();
List<MergeLineFragment> lineFragments = manager.compareLines(sequences.get(0), sequences.get(1), sequences.get(2),
comparisonPolicy, indicator);
List<MergeConflictType> conflictTypes = ReadAction.compute(() -> {
indicator.checkCanceled();
@@ -134,7 +134,7 @@ class ComparisonUtilAutoTest : DiffTestCase() {
val sequence2 = text2.charsSequence
val sequence3 = text3.charsSequence
val fragments = ByLine.compareTwoStep(sequence1, sequence2, sequence3, policy, INDICATOR)
val fragments = MANAGER.compareLines(sequence1, sequence2, sequence3, policy, INDICATOR)
val fineFragments = fragments.map { f ->
val chunk1 = DiffUtil.getLinesContent(text1, f.startLine1, f.endLine1)
@@ -401,6 +401,7 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
// TODO (" _-------_ _ _ " - " _ _ _ ").trim()
(" _-------_ _ _ " - " _ _ _ ").default()
(" _ _--_-_------" - " _--_-_ ").trim()
(" _-------_ _ _ " - " _ _ _ ").ignore()
testAll()
}
@@ -416,7 +417,6 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
lines() {
("====}_==== }_Y_====}" - "====}_Y_====}")
(" _------_ _ " - " _ _ ").default() // result after second step correction
(" _ _-_-----" - " _-_ ").ignore() // result looks strange because of 'diff.unimportant.line.char.count'
testAll()
}
}
@@ -428,4 +428,59 @@ class LineComparisonUtilTest : ComparisonUtilTestBase() {
testDefault()
}
}
fun `test ignore whitespace policy applies two-step correction`() {
lines() {
("1_ _ 1" - " 1")
("-_-_ " - " ").default()
(" _-_---" - " ").trim()
("-_-_ " - " ").ignore()
testAll()
}
lines() {
(" 1_ _1" - " 1")
(" _-_-" - " ").default()
testAll()
}
lines() {
("X_ Y_X" - "Y ")
("-_--_-" - "--").default()
("-_ _-" - " ").trim()
testAll()
}
}
fun `test regression - second step correction should be performed if there are no ambigous matchings`() {
lines {
("}_ }" - " }_}")
("-_--" - "--_-").default()
(" _ " - " _ ").trim()
testAll()
}
lines {
(" }_}_ }" - "}_}_}")
("--_ _--" - "-_ _-").default()
(" _ _ " - " _ _ ").trim()
testAll()
}
lines() {
("X_X __Y" - "X__Z")
(" _--__-" - " __-").default()
("-_ __-" - " __-").trim()
testAll()
}
}
fun `test regression - second step with too many possible matchings`() {
lines {
(" X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_ X" - "X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X_X ")
("--_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _-_-_-_-_-_--" - "-_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _--").default()
(" _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _-_-_-_-_--" - " _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ").trim()
testAll()
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 B

After

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

@@ -16,6 +16,7 @@
package com.intellij.codeInspection;
import com.intellij.analysis.AnalysisScope;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInspection.ex.*;
import com.intellij.conversion.ConversionListener;
import com.intellij.conversion.ConversionService;
@@ -255,7 +256,8 @@ public class InspectionApplication {
});
final String descriptionsFile = resultsDataPath + File.separatorChar + DESCRIPTIONS + XML_EXTENSION;
describeInspections(descriptionsFile,
myRunWithEditorSettings ? null : inspectionProfile.getName());
myRunWithEditorSettings ? null : inspectionProfile.getName(),
(InspectionProfile)inspectionProfile);
inspectionsResults.add(new File(descriptionsFile));
// convert report
if (reportConverter != null) {
@@ -446,8 +448,8 @@ public class InspectionApplication {
}
}
private static void describeInspections(@NonNls String myOutputPath, final String name) throws IOException {
final InspectionToolWrapper[] toolWrappers = InspectionProfileImpl.getDefaultProfile().getInspectionTools(null);
private static void describeInspections(@NonNls String myOutputPath, final String name, final InspectionProfile profile) throws IOException {
final InspectionToolWrapper[] toolWrappers = profile.getInspectionTools(null);
final Map<String, Set<InspectionToolWrapper>> map = new HashMap<String, Set<InspectionToolWrapper>>();
for (InspectionToolWrapper toolWrapper : toolWrappers) {
final String groupName = toolWrapper.getGroupDisplayName();
@@ -472,14 +474,17 @@ public class InspectionApplication {
final Set<InspectionToolWrapper> entries = map.get(groupName);
for (InspectionToolWrapper toolWrapper : entries) {
xmlWriter.startNode("inspection");
xmlWriter.addAttribute("shortName", toolWrapper.getShortName());
final String shortName = toolWrapper.getShortName();
xmlWriter.addAttribute("shortName", shortName);
xmlWriter.addAttribute("displayName", toolWrapper.getDisplayName());
final boolean toolEnabled = profile.isToolEnabled(HighlightDisplayKey.find(shortName));
xmlWriter.addAttribute("enabled", Boolean.toString(toolEnabled));
final String description = toolWrapper.loadDescription();
if (description != null) {
xmlWriter.setValue(description);
}
else {
LOG.error(toolWrapper.getShortName() + " descriptionUrl==" + toolWrapper);
LOG.error(shortName + " descriptionUrl==" + toolWrapper);
}
xmlWriter.endNode();
}
@@ -51,7 +51,8 @@ public class ScopePaneSelectInTarget extends ProjectViewSelectInTarget {
}
@Nullable
private NamedScope getContainingScope(PsiFile file) {
private NamedScope getContainingScope(@Nullable PsiFile file) {
if (file == null) return null;
NamedScopesHolder scopesHolder = DependencyValidationManager.getInstance(myProject);
for (NamedScope scope : ScopeViewPane.getShownScopes(myProject)) {
PackageSet packageSet = scope.getValue();
@@ -127,7 +127,9 @@ class ChangeTrackingValueContainer<Value> extends UpdatableValueContainer<Value>
newMerged = ((ChangeTrackingValueContainer<Value>)fromDisk).getMergedData().copy();
}
if ((myAdded != null || myInvalidated != null) && newMerged.size() > ValueContainerImpl.NUMBER_OF_VALUES_THRESHOLD) {
if ((myAdded != null || myInvalidated != null) &&
(newMerged.size() > ValueContainerImpl.NUMBER_OF_VALUES_THRESHOLD ||
(myAdded != null && myAdded.size() > ValueContainerImpl.NUMBER_OF_VALUES_THRESHOLD))) {
// Calculate file ids that have Value mapped to avoid O(NumberOfValuesInMerged) during removal
fileId2ValueMapping = new FileId2ValueMapping<Value>(newMerged);
}
@@ -9,7 +9,7 @@ InternalFrameUI=com.intellij.ide.ui.laf.darcula.ui.DarculaInternalFrameUI
InternalFrame.border=com.intellij.ide.ui.laf.darcula.ui.DarculaInternalBorder
RootPaneUI=com.intellij.ide.ui.laf.darcula.ui.DarculaRootPaneUI
InternalFrame.closeIcon=AllIcons.Windows.Close
InternalFrame.iconifyIcon=AllIcons.Windows.Iconify
InternalFrame.maximizeIcon=AllIcons.Windows.Maximize
InternalFrame.minimizeIcon=AllIcons.Windows.Minimize
InternalFrame.closeIcon=AllIcons.Windows.CloseInactive
InternalFrame.iconifyIcon=AllIcons.Windows.MinimizeInactive
InternalFrame.maximizeIcon=AllIcons.Windows.MaximizeInactive
InternalFrame.minimizeIcon=AllIcons.Windows.RestoreInactive
@@ -15,14 +15,18 @@
*/
package com.intellij.ide.ui.laf.darcula.ui;
import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
import com.intellij.openapi.ui.GraphicsConfig;
import com.intellij.openapi.wm.impl.IdeMenuBar;
import com.intellij.openapi.wm.impl.IdeRootPane;
import com.intellij.ui.Gray;
import com.intellij.ui.JBColor;
import com.intellij.util.ui.*;
import com.intellij.util.IconUtil;
import com.intellij.util.ui.ImageUtil;
import com.intellij.util.ui.JBDimension;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import org.imgscalr.Scalr;
import sun.swing.SwingUtilities2;
@@ -293,7 +297,7 @@ public class DarculaTitlePane extends JComponent {
menu.add(myCloseAction);
}
private static JButton createButton(String accessibleName, Icon icon, Action action) {
private static JButton createButton(String accessibleName, Icon icon, Icon hoverIcon, Action action, Color hoverBg) {
JButton button = new JButton() {
boolean mouseOverButton = false;
{
@@ -314,11 +318,11 @@ public class DarculaTitlePane extends JComponent {
}
@Override
protected void paintComponent(Graphics g) {
final Window window = SwingUtilities.windowForComponent(this);
float alpha = window.isActive() && mouseOverButton ? 1f : 0.5f;
final GraphicsConfig config = GraphicsUtil.paintWithAlpha(g, alpha);
getIcon().paintIcon(this, g, 0, 0);
config.restore();
if (mouseOverButton) {
g.setColor(hoverBg);
g.fillRect(0, 0, getWidth(), getHeight());
}
IconUtil.paintInCenterOf(this, g, mouseOverButton ? hoverIcon : icon);
}
};
button.setFocusPainted(false);
@@ -334,14 +338,14 @@ public class DarculaTitlePane extends JComponent {
}
private void createButtons() {
myCloseButton = createButton("Close", UIManager.getIcon("InternalFrame.closeIcon"), myCloseAction);
myCloseButton = createButton("Close", AllIcons.Windows.CloseActive, AllIcons.Windows.CloseHover, myCloseAction, Color.red);
if (getWindowDecorationStyle() == JRootPane.FRAME) {
myMaximizeIcon = UIManager.getIcon("InternalFrame.maximizeIcon");
myMinimizeIcon = UIManager.getIcon("InternalFrame.minimizeIcon");
myIconifyButton = createButton("Iconify", UIManager.getIcon("InternalFrame.iconifyIcon"), myIconifyAction);
myToggleButton = createButton("Maximize", myMaximizeIcon, myRestoreAction);
myIconifyButton = createButton("Iconify", AllIcons.Windows.MinimizeInactive, AllIcons.Windows.Minimize, myIconifyAction, new Color(0x55585A));
myToggleButton = createButton("Maximize", AllIcons.Windows.MaximizeInactive, AllIcons.Windows.MaximizeInactive, myRestoreAction, new Color(0x55585A));
}
}
@@ -541,14 +545,14 @@ public class DarculaTitlePane extends JComponent {
}
int w = width;
int h = height;
h--;
//int w = width;
//int h = height;
//h--;
g.setColor(UIManager.getColor("MenuBar.darcula.borderColor"));
g.drawLine(0, h, w, h);
h--;
g.setColor(UIManager.getColor("MenuBar.darcula.borderShadowColor"));
g.drawLine(0, h, w, h);
//g.drawLine(0, h, w, h);
//h--;
//g.setColor(UIManager.getColor("MenuBar.darcula.borderShadowColor"));
g.drawLine(0, getHeight()-1, getWidth(), getHeight()-1);
}
private class CloseAction extends AbstractAction {
@@ -604,7 +608,8 @@ public class DarculaTitlePane extends JComponent {
}
if (mySystemIcon != null) {
g.drawImage(mySystemIcon, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
final int offset = (getHeight() - mySystemIcon.getHeight(null)) / 2;
g.drawImage(mySystemIcon, offset, offset, null);
}
else {
Icon icon = UIManager.getIcon("InternalFrame.icon");
@@ -653,7 +658,7 @@ public class DarculaTitlePane extends JComponent {
iconHeight = IMAGE_HEIGHT;
}
return Math.max(Math.max(fontHeight, iconHeight), JBUI.scale(myIdeMenu == null ? 28 : 36));
return Math.max(Math.max(fontHeight, iconHeight), JBUI.scale(31));
}
public void layoutContainer(Container c) {
@@ -661,17 +666,17 @@ public class DarculaTitlePane extends JComponent {
int h = getHeight();
int x;
int spacing;
int buttonHeight;
int buttonWidth;
int buttonHeight = JBUI.scale(29);
int buttonWidth = JBUI.scale(45);
if (myCloseButton != null && myCloseButton.getIcon() != null) {
buttonHeight = myCloseButton.getIcon().getIconHeight();
buttonWidth = myCloseButton.getIcon().getIconWidth();
}
else {
buttonHeight = IMAGE_HEIGHT;
buttonWidth = IMAGE_WIDTH;
}
//if (myCloseButton != null && myCloseButton.getIcon() != null) {
// buttonHeight = myCloseButton.getIcon().getIconHeight();
// buttonWidth = myCloseButton.getIcon().getIconWidth();
//}
//else {
// buttonHeight = IMAGE_HEIGHT;
// buttonWidth = IMAGE_WIDTH;
//}
spacing = 5;
x = spacing;
@@ -679,33 +684,33 @@ public class DarculaTitlePane extends JComponent {
myMenuBar.setBounds(x, (h - buttonHeight) / 2, buttonWidth, buttonHeight);
}
int systemIconSize = mySystemIcon == null ? JBUI.scale(16) : mySystemIcon.getWidth(null);
x = buttonHeight - systemIconSize + systemIconSize + systemIconSize/2; // offset + width + offset, where offset is (H - iconHeight) / 2
if (myIdeMenu != null) {
final Dimension size = myIdeMenu.getPreferredSize();
x += spacing + (myMenuBar != null ? buttonWidth : 0);
myIdeMenu.setBounds(x, (h - size.height) / 2, size.width, size.height);
}
x = w;
spacing = 8;
x += -spacing - buttonWidth;
spacing = 0;
x -= spacing + buttonWidth;
if (myCloseButton != null) {
myCloseButton.setBounds(x, (h - buttonHeight) / 2, buttonWidth, buttonHeight);
}
if (getWindowDecorationStyle() == JRootPane.FRAME) {
if (Toolkit.getDefaultToolkit().isFrameStateSupported(
Frame.MAXIMIZED_BOTH)) {
if (myToggleButton.getParent() != null) {
//spacing = 10;
x += -spacing - buttonWidth;
x -= spacing + buttonWidth;
myToggleButton.setBounds(x, (h - buttonHeight) / 2, buttonWidth, buttonHeight);
}
}
if (myIconifyButton != null && myIconifyButton.getParent() != null) {
x += -spacing - buttonWidth;
x -= spacing + buttonWidth;
myIconifyButton.setBounds(x, (h - buttonHeight) / 2, buttonWidth, buttonHeight);
}
}
@@ -757,7 +762,7 @@ public class DarculaTitlePane extends JComponent {
} else if (icons.size() == 1) {
mySystemIcon = icons.get(0);
} else {
final JBDimension size = JBUI.size(32);
final JBDimension size = JBUI.size(16);
final Image image = icons.get(0);
mySystemIcon = Scalr.resize(ImageUtil.toBufferedImage(image), Scalr.Method.ULTRA_QUALITY, size.width, size.height);
}
@@ -314,6 +314,13 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
}
}
for (Project p : myOpenProjects) {
if (ProjectUtil.isSameProject(project.getBasePath(), p)) {
ProjectUtil.focusProjectWindow(p, false);
return false;
}
}
if (!addToOpened(project)) {
return false;
}
@@ -1267,10 +1267,14 @@ public class AllIcons {
}
public static class Windows {
public static final Icon Close = IconLoader.getIcon("/windows/close.png"); // 16x16
public static final Icon Iconify = IconLoader.getIcon("/windows/iconify.png"); // 16x16
public static final Icon Maximize = IconLoader.getIcon("/windows/maximize.png"); // 16x16
public static final Icon CloseActive = IconLoader.getIcon("/windows/closeActive.png"); // 16x16
public static final Icon CloseHover = IconLoader.getIcon("/windows/closeHover.png"); // 16x16
public static final Icon CloseInactive = IconLoader.getIcon("/windows/closeInactive.png"); // 16x16
public static final Icon MaximizeInactive = IconLoader.getIcon("/windows/maximizeInactive.png"); // 16x16
public static final Icon Minimize = IconLoader.getIcon("/windows/minimize.png"); // 16x16
public static final Icon MinimizeInactive = IconLoader.getIcon("/windows/minimizeInactive.png"); // 16x16
public static final Icon Restore = IconLoader.getIcon("/windows/restore.png"); // 16x16
public static final Icon RestoreInactive = IconLoader.getIcon("/windows/restoreInactive.png"); // 16x16
public static class Shadow {
public static final Icon Bottom = IconLoader.getIcon("/windows/shadow/bottom.png"); // 1x8
@@ -35,22 +35,6 @@ import java.util.BitSet;
public class Diff {
private static final Logger LOG = Logger.getInstance("#com.intellij.util.diff.Diff");
@Nullable
public static <T> Change buildChangesSomehow(@NotNull T[] objects1, @NotNull T[] objects2) {
try {
return buildChanges(objects1, objects2);
}
catch (FilesTooBigForDiffException e) {
final int startShift = getStartShift(objects1, objects2);
final int endCut = getEndCut(objects1, objects2, startShift);
int trimmedLength1 = objects1.length - startShift - endCut;
int trimmedLength2 = objects2.length - startShift - endCut;
return new Change(startShift, startShift, trimmedLength1, trimmedLength2, null);
}
}
@Nullable
public static Change buildChanges(@NotNull CharSequence before, @NotNull CharSequence after) throws FilesTooBigForDiffException {
final String[] strings1 = LineTokenizer.tokenize(before, false);
@@ -15,6 +15,9 @@
*/
package com.intellij.diff;
import com.intellij.diff.comparison.ByLine;
import com.intellij.diff.comparison.ComparisonPolicy;
import com.intellij.diff.comparison.DiffTooBigException;
import com.intellij.diff.comparison.iterables.DiffIterableUtil;
import com.intellij.diff.comparison.iterables.FairDiffIterable;
import com.intellij.diff.util.Range;
@@ -64,39 +67,50 @@ public class Block {
int end = -1;
int shift = 0;
FairDiffIterable iterable = DiffIterableUtil.diffSomehow(prevContent, mySource, DumbProgressIndicator.INSTANCE);
for (Pair<Range, Boolean> pair : DiffIterableUtil.iterateAll(iterable)) {
Boolean equals = pair.second;
Range range = pair.first;
if (!equals) {
if (Math.max(myStart, range.start2) < Math.min(myEnd, range.end2)) {
// ranges intersect
if (range.start2 <= myStart) start = range.start1;
if (range.end2 > myEnd) end = range.end1;
}
if (range.start2 > myStart) {
if (start == -1) start = myStart - shift;
if (end == -1 && range.start2 >= myEnd) end = myEnd - shift;
}
try {
FairDiffIterable iterable = ByLine.compare(Arrays.asList(prevContent), Arrays.asList(mySource),
ComparisonPolicy.IGNORE_WHITESPACES, DumbProgressIndicator.INSTANCE);
shift += (range.end2 - range.start2) - (range.end1 - range.start1);
}
else {
// intern strings, reducing memory usage
int count = range.end1 - range.start1;
for (int i = 0; i < count; i++) {
prevContent[range.start1 + i] = mySource[range.start2 + i];
for (Pair<Range, Boolean> pair : DiffIterableUtil.iterateAll(iterable)) {
Boolean equals = pair.second;
Range range = pair.first;
if (!equals) {
if (Math.max(myStart, range.start2) < Math.min(myEnd, range.end2)) {
// ranges intersect
if (range.start2 <= myStart) start = range.start1;
if (range.end2 > myEnd) end = range.end1;
}
if (range.start2 > myStart) {
if (start == -1) start = myStart - shift;
if (end == -1 && range.start2 >= myEnd) end = myEnd - shift;
}
shift += (range.end2 - range.start2) - (range.end1 - range.start1);
}
else {
// intern strings, reducing memory usage
int count = range.end1 - range.start1;
for (int i = 0; i < count; i++) {
int prevIndex = range.start1 + i;
int sourceIndex = range.start2 + i;
if (prevContent[prevIndex].equals(mySource[sourceIndex])) {
prevContent[prevIndex] = mySource[sourceIndex];
}
}
}
}
}
if (start == -1) start = myStart - shift;
if (end == -1) end = myEnd - shift;
if (start == -1) start = myStart - shift;
if (end == -1) end = myEnd - shift;
if (start < 0 || end > prevContent.length || end < start) {
LOG.error("Invalid block range: [" + start + ", " + end + "); length - " + prevContent.length);
}
if (start < 0 || end > prevContent.length || end < start) {
LOG.error("Invalid block range: [" + start + ", " + end + "); length - " + prevContent.length);
}
return new Block(prevContent, start, end);
return new Block(prevContent, start, end);
}
catch (DiffTooBigException e) {
return new Block(prevContent, 0, 0);
}
}
@NotNull
@@ -15,17 +15,22 @@
*/
package com.intellij.openapi.vcs.ex;
import com.intellij.diff.comparison.ByLine;
import com.intellij.diff.comparison.ComparisonPolicy;
import com.intellij.diff.comparison.TrimUtil;
import com.intellij.diff.comparison.iterables.DiffIterableUtil;
import com.intellij.diff.comparison.iterables.FairDiffIterable;
import com.intellij.diff.util.DiffUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.diff.Diff;
import com.intellij.openapi.progress.DumbProgressIndicator;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.ex.Range.InnerRange;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.diff.FilesTooBigForDiffException;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class RangesBuilder {
@@ -45,131 +50,166 @@ public class RangesBuilder {
@NotNull
public static List<Range> createRanges(@NotNull List<String> current,
@NotNull List<String> vcs,
int shift,
int currentShift,
int vcsShift,
boolean innerWhitespaceChanges) throws FilesTooBigForDiffException {
Diff.Change ch = Diff.buildChanges(ArrayUtil.toStringArray(vcs), ArrayUtil.toStringArray(current));
if (innerWhitespaceChanges) {
return createRangesSmart(current, vcs, currentShift, vcsShift);
}
else {
return createRangesSimple(current, vcs, currentShift, vcsShift);
}
}
@NotNull
private static List<Range> createRangesSimple(@NotNull List<String> current,
@NotNull List<String> vcs,
int currentShift,
int vcsShift) throws FilesTooBigForDiffException {
FairDiffIterable iterable = ByLine.compare(vcs, current, ComparisonPolicy.DEFAULT, DumbProgressIndicator.INSTANCE);
List<Range> result = new ArrayList<Range>();
while (ch != null) {
if (innerWhitespaceChanges) {
result.add(createOnSmart(ch, shift, vcsShift, current, vcs));
}
else {
result.add(createOn(ch, shift, vcsShift));
}
ch = ch.link;
for (com.intellij.diff.util.Range range : iterable.iterateChanges()) {
int vcsLine1 = vcsShift + range.start1;
int vcsLine2 = vcsShift + range.end1;
int currentLine1 = currentShift + range.start2;
int currentLine2 = currentShift + range.end2;
result.add(new Range(currentLine1, currentLine2, vcsLine1, vcsLine2));
}
return result;
}
private static Range createOn(@NotNull Diff.Change change, int shift, int vcsShift) {
int offset1 = shift + change.line1;
int offset2 = offset1 + change.inserted;
@NotNull
private static List<Range> createRangesSmart(@NotNull List<String> current,
@NotNull List<String> vcs,
int shift,
int vcsShift) throws FilesTooBigForDiffException {
FairDiffIterable iwIterable = ByLine.compare(vcs, current, ComparisonPolicy.IGNORE_WHITESPACES, DumbProgressIndicator.INSTANCE);
int uOffset1 = vcsShift + change.line0;
int uOffset2 = uOffset1 + change.deleted;
RangeBuilder rangeBuilder = new RangeBuilder(current, vcs, shift, vcsShift);
return new Range(offset1, offset2, uOffset1, uOffset2);
}
for (Pair<com.intellij.diff.util.Range, Boolean> pair : DiffIterableUtil.iterateAll(iwIterable)) {
com.intellij.diff.util.Range range = pair.first;
Boolean equals = pair.second;
private static Range createOnSmart(@NotNull Diff.Change change,
int shift,
int vcsShift,
@NotNull List<String> current,
@NotNull List<String> vcs) throws FilesTooBigForDiffException {
byte type = getChangeType(change);
if (equals) {
int count = range.end1 - range.start1;
for (int i = 0; i < count; i++) {
int vcsIndex = range.start1 + i;
int currentIndex = range.start2 + i;
String vcsLine = vcs.get(vcsIndex);
String currentLine = current.get(currentIndex);
int offset1 = shift + change.line1;
int offset2 = offset1 + change.inserted;
int uOffset1 = vcsShift + change.line0;
int uOffset2 = uOffset1 + change.deleted;
if (type != Range.MODIFIED) {
return new Range(offset1, offset2, uOffset1, uOffset2, Collections.singletonList(new Range.InnerRange(offset1, offset2, type)));
}
LineWrapper[] lines1 = new LineWrapper[change.deleted];
LineWrapper[] lines2 = new LineWrapper[change.inserted];
for (int i = 0; i < change.deleted; i++) {
lines1[i] = new LineWrapper(vcs.get(i + change.line0));
}
for (int i = 0; i < change.inserted; i++) {
lines2[i] = new LineWrapper(current.get(i + change.line1));
}
Diff.Change ch = Diff.buildChanges(lines1, lines2);
List<Range.InnerRange> inner = new ArrayList<Range.InnerRange>();
int last0 = 0;
int last1 = 0;
while (ch != null) {
if (ch.line0 != last0 && ch.line1 != last1) {
byte innerType = Range.EQUAL;
int innerStart = shift + change.line1 + last1;
int innerEnd = shift + change.line1 + ch.line1;
inner.add(new Range.InnerRange(innerStart, innerEnd, innerType));
if (vcsLine.equals(currentLine)) {
rangeBuilder.flushChange();
}
else {
rangeBuilder.markChangedWhitespaces(vcsIndex, currentIndex);
}
}
}
else {
rangeBuilder.markChanged(range.start1, range.end1, range.start2, range.end2);
}
byte innerType = getChangeType(ch);
int innerStart = shift + change.line1 + ch.line1;
int innerEnd = innerStart + ch.inserted;
inner.add(new Range.InnerRange(innerStart, innerEnd, innerType));
last0 = ch.line0 + ch.deleted;
last1 = ch.line1 + ch.inserted;
ch = ch.link;
}
if (change.deleted != last0 && change.inserted != last1) {
byte innerType = Range.EQUAL;
int innerStart = shift + change.line1 + last1;
int innerEnd = shift + change.line1 + change.inserted;
inner.add(new Range.InnerRange(innerStart, innerEnd, innerType));
}
return new Range(offset1, offset2, uOffset1, uOffset2, inner);
return rangeBuilder.finish();
}
private static byte getChangeType(@NotNull Diff.Change change) {
if ((change.deleted > 0) && (change.inserted > 0)) return Range.MODIFIED;
if ((change.deleted > 0)) return Range.DELETED;
if ((change.inserted > 0)) return Range.INSERTED;
LOG.error("Unknown change type");
return Range.EQUAL;
}
private static class RangeBuilder {
@NotNull private final List<String> myCurrent;
@NotNull private final List<String> myVcs;
private final int myCurrentShift;
private final int myVcsShift;
private static class LineWrapper {
@NotNull private final String myLine;
private final int myHash;
@NotNull private final List<Range> myRanges = new ArrayList<>();
public LineWrapper(@NotNull String line) {
myLine = line;
myHash = StringUtil.stringHashCodeIgnoreWhitespaces(line);
private com.intellij.diff.util.Range change;
private ArrayList<InnerRange> innerRanges;
public RangeBuilder(@NotNull List<String> current,
@NotNull List<String> vcs,
int currentShift,
int vcsShift) {
myCurrent = current;
myVcs = vcs;
myCurrentShift = currentShift;
myVcsShift = vcsShift;
}
public void flushChange() {
if (change == null) return;
for (InnerRange range : innerRanges) {
range.shift(myCurrentShift);
}
innerRanges.trimToSize();
change = TrimUtil.expand(myVcs, myCurrent, change.start1, change.start2, change.end1, change.end2);
int currentLine1 = myCurrentShift + change.start2;
int currentLine2 = myCurrentShift + change.end2;
int vcsLine1 = myVcsShift + change.start1;
int vcsLine2 = myVcsShift + change.end1;
myRanges.add(new Range(currentLine1, currentLine2, vcsLine1, vcsLine2, innerRanges));
change = null;
innerRanges = null;
}
public void markChangedWhitespaces(int vcsIndex, int currentIndex) {
appendChangedLine(vcsIndex, vcsIndex + 1, currentIndex, currentIndex + 1);
appendInnerEquals(vcsIndex, vcsIndex + 1, currentIndex, currentIndex + 1);
}
public void markChanged(int vcsStart, int vcsEnd, int currentStart, int currentEnd) {
appendChangedLine(vcsStart, vcsEnd, currentStart, currentEnd);
appendInnerChange(vcsStart, vcsEnd, currentStart, currentEnd);
}
@NotNull
public String getLine() {
return myLine;
public List<Range> finish() {
flushChange();
return myRanges;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LineWrapper wrapper = (LineWrapper)o;
if (myHash != wrapper.myHash) return false;
return StringUtil.equalsIgnoreWhitespaces(myLine, wrapper.myLine);
private void appendChangedLine(int vcsStart, int vcsEnd, int currentStart, int currentEnd) {
if (change == null) {
change = new com.intellij.diff.util.Range(vcsStart, vcsEnd, currentStart, currentEnd);
innerRanges = new ArrayList<>();
}
else {
assert vcsStart == change.end1;
assert currentStart == change.end2;
change = new com.intellij.diff.util.Range(change.start1, vcsEnd, change.start2, currentEnd);
}
}
@Override
public int hashCode() {
return myHash;
private void appendInnerChange(int vcsStart, int vcsEnd, int currentStart, int currentEnd) {
byte type = getChangeType(vcsStart, vcsEnd, currentStart, currentEnd);
innerRanges.add(new InnerRange(currentStart, currentEnd, type));
}
private void appendInnerEquals(int vcsStart, int vcsEnd, int currentStart, int currentEnd) {
InnerRange last = ContainerUtil.getLastItem(innerRanges);
if (last == null || last.getType() != Range.EQUAL) {
innerRanges.add(new InnerRange(currentStart, currentEnd, Range.EQUAL));
}
else {
assert currentStart == last.getLine2();
innerRanges.set(innerRanges.size() - 1, new InnerRange(last.getLine1(), currentEnd, Range.EQUAL));
}
}
}
private static byte getChangeType(int vcsStart, int vcsEnd, int currentStart, int currentEnd) {
int deleted = vcsEnd - vcsStart;
int inserted = currentEnd - currentStart;
if (deleted > 0 && inserted > 0) return Range.MODIFIED;
if (deleted > 0) return Range.DELETED;
if (inserted > 0) return Range.INSERTED;
LOG.error("Unknown change type");
return Range.EQUAL;
}
}
@@ -228,7 +228,8 @@ public class VcsSelectionHistoryDialog extends FrameWrapper implements DataProvi
@Override
protected void notifyError(@NotNull VcsException e) {
SwingUtilities.invokeLater(() -> {
if (!VcsSelectionHistoryDialog.this.getFrame().isShowing()) return;
VcsSelectionHistoryDialog dialog = VcsSelectionHistoryDialog.this;
if (dialog.isDisposed() || !dialog.getFrame().isShowing()) return;
PopupUtil.showBalloonForComponent(mySplitter, canNoLoadMessage(e), MessageType.ERROR, true, myProject);
});
}
@@ -59,7 +59,7 @@ public class VcsLogRepoSizeCollector extends AbstractApplicationUsagesCollector
asList(0, 1, 100, 1000, 10 * 1000, 100 * 1000, 500 * 1000)));
for (VcsKey vcs : groupedRoots.keySet()) {
usages.add(StatisticsUtilKt.getCountingUsage("data." + vcs.getName().toLowerCase() + ".root.count", groupedRoots.get(vcs).size(),
asList(0, 1, 2, 5, 8, 15, 30, 50, 100)));
asList(0, 1, 2, 5, 8, 15, 30, 50, 100, 500, 1000)));
}
return usages;
}
@@ -25,6 +25,7 @@ public class GrTraitMethod extends LightMethod implements PsiMirrorElement {
@NotNull PsiMethod method,
@NotNull PsiSubstitutor substitutor) {
super(containingClass, method, substitutor);
setNavigationElement(method);
}
@Override
@@ -19,6 +19,7 @@ import com.intellij.codeInspection.InspectionProfileEntry
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor
import org.jetbrains.plugins.groovy.codeInspection.GroovyUnusedDeclarationInspection
import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection
import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection
@@ -460,4 +461,16 @@ class C implements T {
'''
myFixture.testHighlighting false, false, false
}
void 'test trait method usages'() {
testHighlighting '''\
trait T {
def getFoo() {}
}
class A implements T {}
new A().foo
''', GroovyUnusedDeclarationInspection
}
}
@@ -18,7 +18,6 @@ import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.psi.PsiDirectory;
import com.intellij.util.DocumentUtil;
import com.intellij.util.Function;
@@ -31,7 +30,10 @@ import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
public class CCUtils {
public static final String ANSWER_EXTENSION_DOTTED = ".answer.";
@@ -144,11 +146,8 @@ public class CCUtils {
return generatedRoot.get();
}
/**
* @param requestor {@link VirtualFileEvent#getRequestor}
*/
@Nullable
public static VirtualFile generateFolder(@NotNull Project project, @NotNull Module module, @Nullable Object requestor, String name) {
public static VirtualFile generateFolder(@NotNull Project project, @NotNull Module module, String name) {
VirtualFile generatedRoot = getGeneratedFilesFolder(project, module);
if (generatedRoot == null) {
return null;
@@ -159,9 +158,9 @@ public class CCUtils {
ApplicationManager.getApplication().runWriteAction(() -> {
try {
if (folder.get() != null) {
folder.get().delete(requestor);
folder.get().delete(null);
}
folder.set(generatedRoot.createChildDirectory(requestor, name));
folder.set(generatedRoot.createChildDirectory(null, name));
}
catch (IOException e) {
LOG.info("Failed to generate folder " + name, e);
@@ -26,7 +26,7 @@ import java.util.List;
public class CCAddAnswerPlaceholder extends CCAnswerPlaceholderAction {
public CCAddAnswerPlaceholder() {
super("Add/Delete Answer Placeholder", "Add/Delete answer placeholder", null);
super("Add/Delete Answer Placeholder", "Add/Delete answer placeholder");
}
@@ -14,12 +14,10 @@ import com.jetbrains.edu.learning.courseFormat.TaskFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
abstract public class CCAnswerPlaceholderAction extends DumbAwareAction {
protected CCAnswerPlaceholderAction(@Nullable String text, @Nullable String description, @Nullable Icon icon) {
super(text, description, icon);
protected CCAnswerPlaceholderAction(@Nullable String text, @Nullable String description) {
super(text, description, null);
}
@Nullable
@@ -77,7 +77,7 @@ public class CCCreateCourseArchive extends DumbAwareAction {
final Course course = StudyTaskManager.getInstance(project).getCourse();
if (course == null) return;
final VirtualFile baseDir = project.getBaseDir();
VirtualFile archiveFolder = CCUtils.generateFolder(project, module, null, zipName);
VirtualFile archiveFolder = CCUtils.generateFolder(project, module, zipName);
if (archiveFolder == null) {
return;
}
@@ -107,7 +107,7 @@ public class CCDeleteAllAnswerPlaceholdersAction extends DumbAwareAction {
private static class ClearPlaceholders implements UndoableAction {
private final List<AnswerPlaceholder> myPlaceholders;
private final Editor myEditor;
TaskFile myTaskFile;
private final TaskFile myTaskFile;
public ClearPlaceholders(TaskFile taskFile, List<AnswerPlaceholder> placeholders, Editor editor) {
myTaskFile = taskFile;
@@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
public class CCEditAnswerPlaceholder extends CCAnswerPlaceholderAction {
public CCEditAnswerPlaceholder() {
super("Edit Answer Placeholder", "Edit answer placeholder", null);
super("Edit Answer Placeholder", "Edit answer placeholder");
}
@Override
@@ -21,7 +21,6 @@ import com.intellij.util.Function;
import com.jetbrains.edu.coursecreator.CCUtils;
import com.jetbrains.edu.coursecreator.ui.CCMoveStudyItemDialog;
import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.coursecreator.CCUtils;
import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.core.EduUtils;
import com.jetbrains.edu.learning.courseFormat.Course;
@@ -17,7 +17,6 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.refactoring.move.MoveCallback;
import com.intellij.refactoring.move.MoveHandlerDelegate;
import com.intellij.util.Function;
import com.jetbrains.edu.coursecreator.CCUtils;
import com.jetbrains.edu.coursecreator.ui.CCMoveStudyItemDialog;
import com.jetbrains.edu.learning.StudyTaskManager;
@@ -25,7 +24,6 @@ import com.jetbrains.edu.learning.core.EduNames;
import com.jetbrains.edu.learning.core.EduUtils;
import com.jetbrains.edu.learning.courseFormat.Course;
import com.jetbrains.edu.learning.courseFormat.Lesson;
import com.jetbrains.edu.learning.courseFormat.StudyItem;
import com.jetbrains.edu.learning.courseFormat.Task;
import org.jetbrains.annotations.Nullable;
@@ -91,6 +89,9 @@ public class CCTaskMoveHandlerDelegate extends MoveHandlerDelegate {
final Course course = StudyTaskManager.getInstance(project).getCourse();
final PsiDirectory sourceDirectory = (PsiDirectory)elements[0];
if (course == null) {
return;
}
final Task taskToMove = EduUtils.getTask(sourceDirectory, course);
if (taskToMove == null) {
return;

Some files were not shown because too many files have changed in this diff Show More