Merge remote-tracking branch 'origin/master' into develar/is
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 257 B |
|
After Width: | Height: | Size: 132 B |
|
After Width: | Height: | Size: 202 B |
|
After Width: | Height: | Size: 245 B |
|
After Width: | Height: | Size: 154 B |
|
After Width: | Height: | Size: 154 B |
|
After Width: | Height: | Size: 239 B |
|
After Width: | Height: | Size: 148 B |
|
After Width: | Height: | Size: 216 B |
|
After Width: | Height: | Size: 245 B |
|
After Width: | Height: | Size: 154 B |
|
Before Width: | Height: | Size: 96 B |
|
Before Width: | Height: | Size: 161 B |
|
After Width: | Height: | Size: 109 B |
|
After Width: | Height: | Size: 111 B |
|
After Width: | Height: | Size: 91 B |
|
After Width: | Height: | Size: 111 B |
|
After Width: | Height: | Size: 110 B |
|
After Width: | Height: | Size: 90 B |
|
After Width: | Height: | Size: 91 B |
|
Before Width: | Height: | Size: 196 B After Width: | Height: | Size: 78 B |
|
After Width: | Height: | Size: 94 B |
|
After Width: | Height: | Size: 97 B |
|
After Width: | Height: | Size: 83 B |
|
After Width: | Height: | Size: 97 B |
|
After Width: | Height: | Size: 96 B |
|
After Width: | Height: | Size: 82 B |
|
After Width: | Height: | Size: 83 B |
|
After Width: | Height: | Size: 109 B |
|
After Width: | Height: | Size: 129 B |
|
After Width: | Height: | Size: 129 B |
|
After Width: | Height: | Size: 108 B |
|
After Width: | Height: | Size: 133 B |
|
After Width: | Height: | Size: 128 B |
|
After Width: | Height: | Size: 107 B |
|
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;
|
||||
|
||||