mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -245,7 +245,7 @@ public class BreakpointManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nullable
|
||||
public ExceptionBreakpoint addExceptionBreakpoint(@NotNull final String exceptionClassName, final String packageName) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
final JavaExceptionBreakpointType type = XDebuggerUtil.getInstance().findBreakpointType(JavaExceptionBreakpointType.class);
|
||||
|
||||
@@ -47,7 +47,6 @@ import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.JDOMExternalizerUtil;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.StringBuilderSpinAllocator;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -150,14 +149,17 @@ public class MethodBreakpoint extends BreakpointWithHighlighter<JavaMethodBreakp
|
||||
}
|
||||
|
||||
AtomicReference<ProgressIndicator> indicatorRef = new AtomicReference<>();
|
||||
ApplicationManager.getApplication().invokeAndWait(() -> indicatorRef.set(new ProgressWindowWithNotification(true, myProject)));
|
||||
ApplicationManager.getApplication()
|
||||
.invokeAndWait(() -> indicatorRef.set(new ProgressWindowWithNotification(true, false, myProject, "Cancel emulation")));
|
||||
ProgressIndicator indicator = indicatorRef.get();
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(
|
||||
() -> processPreparedSubTypes(baseType, subType -> createRequestForPreparedClassEmulated(debugProcess, subType, false), indicator),
|
||||
indicator);
|
||||
if (indicator.isCanceled()) {
|
||||
ApplicationManager.getApplication().invokeLater(
|
||||
() -> DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().removeBreakpoint(this));
|
||||
ApplicationManager.getApplication().invokeLater(() -> {
|
||||
getProperties().EMULATED = false;
|
||||
fireBreakpointChanged();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,7 +495,7 @@ public class MethodBreakpoint extends BreakpointWithHighlighter<JavaMethodBreakp
|
||||
}
|
||||
|
||||
public boolean isEmulated() {
|
||||
return getProperties().EMULATED && Registry.is("debugger.emulate.method.breakpoints");
|
||||
return getProperties().EMULATED;
|
||||
}
|
||||
|
||||
private boolean isWatchEntry() {
|
||||
|
||||
+1
-3
@@ -17,7 +17,6 @@
|
||||
package com.intellij.debugger.ui.breakpoints;
|
||||
|
||||
import com.intellij.debugger.DebuggerBundle;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.util.ui.DialogUtil;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
@@ -98,8 +97,7 @@ public class MethodBreakpointPropertiesPanel extends XBreakpointCustomProperties
|
||||
|
||||
@Override
|
||||
public void loadFrom(@NotNull XBreakpoint<JavaMethodBreakpointProperties> breakpoint) {
|
||||
myEmulatedCheckBox.setVisible(
|
||||
Registry.is("debugger.emulate.method.breakpoints") && breakpoint.getType() instanceof JavaMethodBreakpointType);
|
||||
myEmulatedCheckBox.setVisible(breakpoint.getType() instanceof JavaMethodBreakpointType);
|
||||
myEmulatedCheckBox.setSelected(breakpoint.getProperties().EMULATED);
|
||||
|
||||
myWatchEntryCheckBox.setSelected(breakpoint.getProperties().WATCH_ENTRY);
|
||||
|
||||
+17
-33
@@ -65,7 +65,7 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool {
|
||||
public boolean ADD_APPLET_TO_ENTRIES = true;
|
||||
public boolean ADD_SERVLET_TO_ENTRIES = true;
|
||||
public boolean ADD_NONJAVA_TO_ENTRIES = true;
|
||||
protected boolean TEST_ENTRY_POINTS = true;
|
||||
private boolean TEST_ENTRY_POINTS = true;
|
||||
|
||||
public static final String DISPLAY_NAME = InspectionsBundle.message("inspection.dead.code.display.name");
|
||||
public static final String SHORT_NAME = HighlightInfoType.UNUSED_SYMBOL_SHORT_NAME;
|
||||
@@ -290,7 +290,6 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool {
|
||||
if (isSuppressed || !scope.contains(file)) {
|
||||
getEntryPointsManager(globalContext).addEntryPoint(refElement, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -323,12 +322,9 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool {
|
||||
String qualifiedName = psiClass != null ? psiClass.getQualifiedName() : null;
|
||||
if (qualifiedName != null) {
|
||||
final GlobalSearchScope projectScope = GlobalSearchScope.projectScope(globalContext.getProject());
|
||||
final PsiNonJavaFileReferenceProcessor processor = new PsiNonJavaFileReferenceProcessor() {
|
||||
@Override
|
||||
public boolean process(PsiFile file, int startOffset, int endOffset) {
|
||||
getEntryPointsManager(globalContext).addEntryPoint(refElement, false);
|
||||
return false;
|
||||
}
|
||||
final PsiNonJavaFileReferenceProcessor processor = (file, startOffset, endOffset) -> {
|
||||
getEntryPointsManager(globalContext).addEntryPoint(refElement, false);
|
||||
return false;
|
||||
};
|
||||
final DelegatingGlobalSearchScope globalSearchScope = new DelegatingGlobalSearchScope(projectScope) {
|
||||
@Override
|
||||
@@ -450,9 +446,9 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool {
|
||||
checkForReachableRefs(globalContext);
|
||||
final RefFilter filter = myPhase == 1 ? new StrictUnreferencedFilter(this, globalContext) :
|
||||
new RefUnreachableFilter(this, globalContext);
|
||||
final boolean[] requestAdded = {false};
|
||||
LOG.assertTrue(myProcessedSuspicious != null, "phase: " + myPhase);
|
||||
|
||||
final boolean[] requestAdded = {false};
|
||||
globalContext.getRefManager().iterate(new RefJavaVisitor() {
|
||||
@Override
|
||||
public void visitElement(@NotNull RefEntity refEntity) {
|
||||
@@ -469,12 +465,9 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool {
|
||||
getEntryPointsManager(globalContext).addEntryPoint(refField, false);
|
||||
}
|
||||
else {
|
||||
globalContext.getExtension(GlobalJavaInspectionContext.CONTEXT).enqueueFieldUsagesProcessor(refField, new GlobalJavaInspectionContext.UsagesProcessor() {
|
||||
@Override
|
||||
public boolean process(PsiReference psiReference) {
|
||||
getEntryPointsManager(globalContext).addEntryPoint(refField, false);
|
||||
return false;
|
||||
}
|
||||
globalContext.getExtension(GlobalJavaInspectionContext.CONTEXT).enqueueFieldUsagesProcessor(refField, psiReference -> {
|
||||
getEntryPointsManager(globalContext).addEntryPoint(refField, false);
|
||||
return false;
|
||||
});
|
||||
requestAdded[0] = true;
|
||||
}
|
||||
@@ -506,20 +499,14 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool {
|
||||
public void visitClass(@NotNull final RefClass refClass) {
|
||||
myProcessedSuspicious.add(refClass);
|
||||
if (!refClass.isAnonymous()) {
|
||||
globalContext.getExtension(GlobalJavaInspectionContext.CONTEXT).enqueueDerivedClassesProcessor(refClass, new GlobalJavaInspectionContext.DerivedClassesProcessor() {
|
||||
@Override
|
||||
public boolean process(PsiClass inheritor) {
|
||||
getEntryPointsManager(globalContext).addEntryPoint(refClass, false);
|
||||
return false;
|
||||
}
|
||||
globalContext.getExtension(GlobalJavaInspectionContext.CONTEXT).enqueueDerivedClassesProcessor(refClass, inheritor -> {
|
||||
getEntryPointsManager(globalContext).addEntryPoint(refClass, false);
|
||||
return false;
|
||||
});
|
||||
|
||||
globalContext.getExtension(GlobalJavaInspectionContext.CONTEXT).enqueueClassUsagesProcessor(refClass, new GlobalJavaInspectionContext.UsagesProcessor() {
|
||||
@Override
|
||||
public boolean process(PsiReference psiReference) {
|
||||
getEntryPointsManager(globalContext).addEntryPoint(refClass, false);
|
||||
return false;
|
||||
}
|
||||
globalContext.getExtension(GlobalJavaInspectionContext.CONTEXT).enqueueClassUsagesProcessor(refClass, psiReference -> {
|
||||
getEntryPointsManager(globalContext).addEntryPoint(refClass, false);
|
||||
return false;
|
||||
});
|
||||
requestAdded[0] = true;
|
||||
}
|
||||
@@ -549,12 +536,9 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool {
|
||||
|
||||
private static void enqueueMethodUsages(GlobalInspectionContext globalContext, final RefMethod refMethod) {
|
||||
if (refMethod.getSuperMethods().isEmpty()) {
|
||||
globalContext.getExtension(GlobalJavaInspectionContext.CONTEXT).enqueueMethodUsagesProcessor(refMethod, new GlobalJavaInspectionContext.UsagesProcessor() {
|
||||
@Override
|
||||
public boolean process(PsiReference psiReference) {
|
||||
getEntryPointsManager(globalContext).addEntryPoint(refMethod, false);
|
||||
return false;
|
||||
}
|
||||
globalContext.getExtension(GlobalJavaInspectionContext.CONTEXT).enqueueMethodUsagesProcessor(refMethod, psiReference -> {
|
||||
getEntryPointsManager(globalContext).addEntryPoint(refMethod, false);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
||||
+12
-43
@@ -25,7 +25,6 @@ import com.intellij.codeInspection.reference.*;
|
||||
import com.intellij.codeInspection.ui.InspectionToolPresentation;
|
||||
import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection;
|
||||
import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspectionBase;
|
||||
import com.intellij.openapi.ui.VerticalFlowLayout;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.controlFlow.DefUseUtil;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
@@ -34,7 +33,6 @@ import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.ui.components.JBRadioButton;
|
||||
import com.intellij.ui.components.JBTabbedPane;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.ui.JBInsets;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -43,10 +41,11 @@ import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase {
|
||||
private final UnusedParametersInspection myUnusedParameters = new UnusedParametersInspection();
|
||||
@@ -155,12 +154,7 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase
|
||||
final ButtonGroup group = new ButtonGroup();
|
||||
group.add(asEntryPoint);
|
||||
group.add(asUnused);
|
||||
final ActionListener listener = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
setTestEntryPoints(asEntryPoint.isSelected());
|
||||
}
|
||||
};
|
||||
final ActionListener listener = e -> setTestEntryPoints(asEntryPoint.isSelected());
|
||||
asEntryPoint.addActionListener(listener);
|
||||
asUnused.addActionListener(listener);
|
||||
|
||||
@@ -187,12 +181,7 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase
|
||||
|
||||
myMainsCheckbox = new JCheckBox(InspectionsBundle.message("inspection.dead.code.option.main"));
|
||||
myMainsCheckbox.setSelected(ADD_MAINS_TO_ENTRIES);
|
||||
myMainsCheckbox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
ADD_MAINS_TO_ENTRIES = myMainsCheckbox.isSelected();
|
||||
}
|
||||
});
|
||||
myMainsCheckbox.addActionListener(e -> ADD_MAINS_TO_ENTRIES = myMainsCheckbox.isSelected());
|
||||
|
||||
|
||||
add(myMainsCheckbox, gc);
|
||||
@@ -200,23 +189,13 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase
|
||||
|
||||
myAppletToEntries = new JCheckBox(InspectionsBundle.message("inspection.dead.code.option.applet"));
|
||||
myAppletToEntries.setSelected(ADD_APPLET_TO_ENTRIES);
|
||||
myAppletToEntries.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
ADD_APPLET_TO_ENTRIES = myAppletToEntries.isSelected();
|
||||
}
|
||||
});
|
||||
myAppletToEntries.addActionListener(e -> ADD_APPLET_TO_ENTRIES = myAppletToEntries.isSelected());
|
||||
add(myAppletToEntries, gc);
|
||||
gc.gridy++;
|
||||
|
||||
myServletToEntries = new JCheckBox(InspectionsBundle.message("inspection.dead.code.option.servlet"));
|
||||
myServletToEntries.setSelected(ADD_SERVLET_TO_ENTRIES);
|
||||
myServletToEntries.addActionListener(new ActionListener(){
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
ADD_SERVLET_TO_ENTRIES = myServletToEntries.isSelected();
|
||||
}
|
||||
});
|
||||
myServletToEntries.addActionListener(e -> ADD_SERVLET_TO_ENTRIES = myServletToEntries.isSelected());
|
||||
add(myServletToEntries, gc);
|
||||
gc.gridy++;
|
||||
|
||||
@@ -224,12 +203,7 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase
|
||||
if (extension.showUI()) {
|
||||
final JCheckBox extCheckbox = new JCheckBox(extension.getDisplayName());
|
||||
extCheckbox.setSelected(extension.isSelected());
|
||||
extCheckbox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
extension.setSelected(extCheckbox.isSelected());
|
||||
}
|
||||
});
|
||||
extCheckbox.addActionListener(e -> extension.setSelected(extCheckbox.isSelected()));
|
||||
add(extCheckbox, gc);
|
||||
gc.gridy++;
|
||||
}
|
||||
@@ -238,12 +212,7 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase
|
||||
myNonJavaCheckbox =
|
||||
new JCheckBox(InspectionsBundle.message("inspection.dead.code.option.external"));
|
||||
myNonJavaCheckbox.setSelected(ADD_NONJAVA_TO_ENTRIES);
|
||||
myNonJavaCheckbox.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
ADD_NONJAVA_TO_ENTRIES = myNonJavaCheckbox.isSelected();
|
||||
}
|
||||
});
|
||||
myNonJavaCheckbox.addActionListener(e -> ADD_NONJAVA_TO_ENTRIES = myNonJavaCheckbox.isSelected());
|
||||
|
||||
gc.weighty = 1;
|
||||
add(myNonJavaCheckbox, gc);
|
||||
@@ -267,10 +236,10 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase
|
||||
|
||||
private class UnusedVariablesGraphAnnotator extends RefGraphAnnotator {
|
||||
private final InspectionManager myInspectionManager;
|
||||
private GlobalInspectionContextImpl myContext;
|
||||
private Map<String, Tools> myTools;
|
||||
private final GlobalInspectionContextImpl myContext;
|
||||
private final Map<String, Tools> myTools;
|
||||
|
||||
public UnusedVariablesGraphAnnotator(InspectionManager inspectionManager, RefManager refManager) {
|
||||
UnusedVariablesGraphAnnotator(InspectionManager inspectionManager, RefManager refManager) {
|
||||
myInspectionManager = inspectionManager;
|
||||
myContext = (GlobalInspectionContextImpl)((RefManagerImpl)refManager).getContext();
|
||||
myTools = myContext.getTools();
|
||||
|
||||
@@ -158,7 +158,7 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private MostlySingularMultiMap<String, AnnotationData> getDataFromFile(@NotNull PsiFile file) {
|
||||
MostlySingularMultiMap<String, AnnotationData> getDataFromFile(@NotNull PsiFile file) {
|
||||
Pair<MostlySingularMultiMap<String, AnnotationData>, Long> cached = myAnnotationFileToDataAndModStampCache.get(file);
|
||||
long fileModificationStamp = file.getModificationStamp();
|
||||
if (cached != null && cached.getSecond() == fileModificationStamp) {
|
||||
@@ -336,16 +336,16 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected void cacheExternalAnnotations(@SuppressWarnings("UnusedParameters") @NotNull String packageName,
|
||||
@NotNull PsiFile fromFile,
|
||||
@NotNull List<PsiFile> annotationFiles) {
|
||||
void cacheExternalAnnotations(@SuppressWarnings("UnusedParameters") @NotNull String packageName,
|
||||
@NotNull PsiFile fromFile,
|
||||
@NotNull List<PsiFile> annotationFiles) {
|
||||
VirtualFile virtualFile = fromFile.getVirtualFile();
|
||||
if (virtualFile != null) {
|
||||
myExternalAnnotationsCache.put(virtualFile, annotationFiles);
|
||||
}
|
||||
}
|
||||
|
||||
private static class AnnotationData {
|
||||
static class AnnotationData {
|
||||
private final String annotationClassFqName;
|
||||
private final String annotationParameters;
|
||||
|
||||
@@ -357,7 +357,7 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PsiAnnotation getAnnotation(@NotNull BaseExternalAnnotationsManager context) {
|
||||
PsiAnnotation getAnnotation(@NotNull BaseExternalAnnotationsManager context) {
|
||||
PsiAnnotation a = myAnnotation;
|
||||
if (a == null) {
|
||||
String text = "@" + annotationClassFqName + (annotationParameters.isEmpty() ? "" : "(" + annotationParameters + ")");
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.application.ex.PathManagerEx;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiFormatUtil;
|
||||
import com.intellij.testFramework.IdeaTestCase;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MostlySingularMultiMap;
|
||||
import com.intellij.xml.util.XmlUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ExternalAnnotationsManagerTest extends IdeaTestCase {
|
||||
@Override
|
||||
protected Sdk getTestProjectJdk() {
|
||||
Sdk jdk = JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();
|
||||
Sdk sdk = PsiTestUtil.addJdkAnnotations(jdk);
|
||||
String home = jdk.getHomeDirectory().getParent().getPath();
|
||||
String toolsPath = home + "/lib/tools.jar!/";
|
||||
VfsRootAccess.allowRootAccess(getTestRootDisposable(), home);
|
||||
VirtualFile toolsJar = JarFileSystem.getInstance().findFileByPath(toolsPath);
|
||||
|
||||
Sdk plusTools = PsiTestUtil.addRootsToJdk(sdk, OrderRootType.CLASSES, toolsJar);
|
||||
|
||||
Collection<String> utilClassPath = PathManager.getUtilClassPath();
|
||||
VirtualFile[] files = utilClassPath.stream()
|
||||
.map(path -> path.endsWith(".jar") ?
|
||||
JarFileSystem.getInstance() .findFileByPath(FileUtil.toSystemIndependentName(path) + "!/") :
|
||||
LocalFileSystem.getInstance() .findFileByPath(FileUtil.toSystemIndependentName(path)))
|
||||
.toArray(VirtualFile[]::new);
|
||||
|
||||
Sdk result = PsiTestUtil.addRootsToJdk(plusTools, OrderRootType.CLASSES, files);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void testBundledAnnotationXmls() {
|
||||
String root = PathManagerEx.getCommunityHomePath() + "/java/jdkAnnotations";
|
||||
findAnnotationsXmlAndCheck(root);
|
||||
}
|
||||
|
||||
private void findAnnotationsXmlAndCheck(String root) {
|
||||
VirtualFile jdkAnnoRoot = LocalFileSystem.getInstance().findFileByPath(root);
|
||||
VfsUtilCore.visitChildrenRecursively(jdkAnnoRoot, new VirtualFileVisitor() {
|
||||
@Override
|
||||
public boolean visitFile(@NotNull VirtualFile file) {
|
||||
if (file.getName().equals("annotations.xml")) {
|
||||
check(file);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// some android classes are missing in IDEA, e.g. android.support.annotation.NonNull
|
||||
public void _testAndroidAnnotationsXml() {
|
||||
VirtualFile lib = LocalFileSystem.getInstance().findFileByPath(PathManagerEx.getCommunityHomePath() + "/android/android/lib");
|
||||
VirtualFile[] androidJars = Arrays.stream(lib.getChildren())
|
||||
.map(file -> file.getName().endsWith(".jar") ?
|
||||
JarFileSystem.getInstance().getJarRootForLocalFile(file) :
|
||||
file)
|
||||
.toArray(VirtualFile[]::new);
|
||||
|
||||
ApplicationManager.getApplication().runWriteAction(() -> ProjectRootManager.getInstance(getProject())
|
||||
.setProjectSdk(PsiTestUtil.addRootsToJdk(getTestProjectJdk(), OrderRootType.CLASSES, androidJars)));
|
||||
|
||||
String root = PathManagerEx.getCommunityHomePath() + "/android/android/annotations";
|
||||
findAnnotationsXmlAndCheck(root);
|
||||
}
|
||||
|
||||
private void check(VirtualFile file) {
|
||||
//System.out.println("file = " + file);
|
||||
ExternalAnnotationsManagerImpl manager = (ExternalAnnotationsManagerImpl)ExternalAnnotationsManager.getInstance(getProject());
|
||||
PsiFile psiFile = getPsiManager().findFile(file);
|
||||
MostlySingularMultiMap<String, BaseExternalAnnotationsManager.AnnotationData> map = manager.getDataFromFile(psiFile);
|
||||
for (String externalName : map.keySet()) {
|
||||
checkExternalName(psiFile, externalName);
|
||||
|
||||
// 'annotation name="org.jetbrains.annotations.NotNull"' should have FQN
|
||||
for (BaseExternalAnnotationsManager.AnnotationData annotationData : map.get(externalName)) {
|
||||
PsiAnnotation annotation = annotationData.getAnnotation(manager);
|
||||
String nameText = annotation.getNameReferenceElement().getText();
|
||||
assertClassFqn(nameText, psiFile, externalName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PsiClass assertClassFqn(String text, PsiFile psiFile, String externalName) {
|
||||
if (!PsiNameHelper.getInstance(getProject()).isQualifiedName(text) || !text.contains(".")) {
|
||||
fail("'" + text + "' doesn't seem like a FQN", psiFile, externalName);
|
||||
}
|
||||
|
||||
PsiClass aClass = JavaPsiFacade.getInstance(getProject()).findClass(text, GlobalSearchScope.allScope(getProject()));
|
||||
if (aClass == null) {
|
||||
fail("'" + text + "' doesn't resolve to a class", psiFile, externalName);
|
||||
}
|
||||
return aClass;
|
||||
}
|
||||
|
||||
private static void fail(String error, PsiFile psiFile, String externalName) {
|
||||
int offset = psiFile.getText().indexOf(XmlUtil.escape(externalName));
|
||||
int line = PsiDocumentManager.getInstance(psiFile.getProject()).getDocument(psiFile).getLineNumber(offset);
|
||||
fail(error + "\nFile: " + psiFile.getVirtualFile().getPath() + ":" + (line+1) + " (offset: "+offset+")");
|
||||
}
|
||||
|
||||
private void checkExternalName(PsiFile psiFile, String externalName) {
|
||||
// 'item name="java.lang.ClassLoader java.net.URL getResource(java.lang.String) 0"' should have all FQNs
|
||||
String unescaped = StringUtil.unescapeXml(externalName);
|
||||
List<String> words = StringUtil.split(unescaped, " ");
|
||||
String className = words.get(0);
|
||||
PsiClass aClass = assertClassFqn(className, psiFile, externalName);
|
||||
if (words.size() == 1) return;
|
||||
|
||||
String rest = unescaped.substring(className.length() + " ".length());
|
||||
|
||||
if (rest.indexOf('(') == -1) {
|
||||
// field
|
||||
String field = StringUtil.trim(rest);
|
||||
PsiField psiField = aClass.findFieldByName(field, false);
|
||||
if (psiField == null) {
|
||||
fail("Field '"+field+"' not found in class '"+aClass.getQualifiedName()+"'", psiFile, externalName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
String methodName = ContainerUtil.getLastItem(StringUtil.getWordsIn(rest.substring(0, rest.indexOf('('))));
|
||||
|
||||
String methodSignature = rest.substring(0, rest.indexOf(')') + 1);
|
||||
String methodExternalName = className + " " + methodSignature;
|
||||
|
||||
List<PsiMethod> methods = Arrays.stream(aClass.getMethods())
|
||||
.filter(method -> methodExternalName.equals(PsiFormatUtil.getExternalName(method, false, Integer.MAX_VALUE)))
|
||||
.collect(Collectors.toList());
|
||||
boolean found = !methods.isEmpty();
|
||||
if (!found) {
|
||||
List<String> candidates = Arrays.stream(aClass.findMethodsByName(methodName, false))
|
||||
.map(method -> XmlUtil.escape(PsiFormatUtil.getExternalName(method, false, Integer.MAX_VALUE)))
|
||||
.collect(Collectors.toList());
|
||||
String additionalMsg = candidates.isEmpty() ? "" : "\nMaybe you have meant one of these methods instead:\n"+StringUtil.join(candidates, "\n")+"\n";
|
||||
fail("This method was not found in class '"+aClass.getQualifiedName()+"':\n"+"'"+methodSignature+"'"+additionalMsg, psiFile, externalName);
|
||||
}
|
||||
|
||||
String parameterNumberText = StringUtil.trim(rest.substring(rest.indexOf(')') + 1));
|
||||
if (parameterNumberText.isEmpty()) return;
|
||||
|
||||
try {
|
||||
int paramNumber = Integer.parseInt(parameterNumberText);
|
||||
PsiMethod method = methods.get(0);
|
||||
if (method.getParameterList().getParametersCount() <= paramNumber) {
|
||||
fail("Parameter number '"+paramNumber+"' is too big for a method '"+methodSignature+"'", psiFile, externalName);
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
fail("Parameter number is not an integer: '"+parameterNumberText+"'", psiFile, externalName);
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
-3
@@ -20,7 +20,9 @@ import com.intellij.codeInsight.hints.settings.ParameterNameHintsSettings
|
||||
import com.intellij.openapi.editor.Inlay
|
||||
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.impl.DebugUtil
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
import com.intellij.util.DocumentUtil
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
@@ -88,7 +90,13 @@ class InlayAssert(private val file: PsiFile, val inlays: List<Inlay>) {
|
||||
val hintOffsets = hints.map { it.first }
|
||||
val hintNames = hints.map { it.second }
|
||||
|
||||
assertThat(hints.size).isEqualTo(expectedInlays.size)
|
||||
val elements = hintOffsets.mapNotNull { file.findElementAt(it) }
|
||||
assertThat(hints.size)
|
||||
.withFailMessage("Expected ${expectedInlays.size} elements with hints, Actual elements count ${hints.size}" +
|
||||
": ${elements.joinToString(", ")}, file text: \n\n ${file.text} \n\n isCommitted ${isCommitted(file)} \n\n" +
|
||||
"Psi: \n ${DebugUtil.psiToString(file, true)}")
|
||||
|
||||
.isEqualTo(expectedInlays.size)
|
||||
|
||||
val expect = expectedInlays.map { it.substringBefore("->") to it.substringAfter("->") }
|
||||
val expectedHintNames = expect.map { it.first }
|
||||
@@ -96,9 +104,16 @@ class InlayAssert(private val file: PsiFile, val inlays: List<Inlay>) {
|
||||
|
||||
assertThat(hintNames).isEqualTo(expectedHintNames)
|
||||
|
||||
val wordsAfter = hintOffsets.mapNotNull { file.findElementAt(it) }.map { it.text }
|
||||
|
||||
val wordsAfter = elements.map { it.text }
|
||||
assertThat(wordsAfter).isEqualTo(expectedWordsAfter)
|
||||
}
|
||||
|
||||
private fun isCommitted(file: PsiFile): Boolean {
|
||||
val manager = PsiDocumentManager.getInstance(file.project)
|
||||
val document = manager.getDocument(file)
|
||||
|
||||
assertThat(document).isNotNull()
|
||||
return manager.isCommitted(document!!)
|
||||
}
|
||||
|
||||
}
|
||||
+4
-1
@@ -708,13 +708,16 @@ class Key {
|
||||
setup("""
|
||||
class Test {
|
||||
void test() {
|
||||
xxx(100);
|
||||
check(1 + 1);
|
||||
int i=1; check(1 + 1 + 1);
|
||||
}
|
||||
void check(int isShow) {}
|
||||
void xxx(int followTheSum) {}
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
onLineStartingWith("xxx").assertInlays("followTheSum->100")
|
||||
onLineStartingWith("check").assertInlays("isShow->1")
|
||||
onLineStartingWith("int").assertInlays("isShow->1")
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ import com.intellij.openapi.util.Ref
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.*
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFilePropertyChangeEvent
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry
|
||||
@@ -64,6 +66,7 @@ import com.intellij.util.FileContentUtil
|
||||
import com.intellij.util.Processor
|
||||
import com.intellij.util.indexing.*
|
||||
import com.intellij.util.io.*
|
||||
import groovy.transform.CompileStatic
|
||||
import org.jetbrains.annotations.NotNull
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
@@ -566,14 +569,14 @@ class IndexTest extends JavaCodeInsightFixtureTestCase {
|
||||
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
|
||||
@Override
|
||||
boolean visitFile(@NotNull VirtualFile visitedFile) {
|
||||
iterator.processFile(visitedFile);
|
||||
return true;
|
||||
iterator.processFile(visitedFile)
|
||||
return true
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
protected void doInvalidateIndicesForFile(VirtualFile file, boolean contentChange) {
|
||||
vfsEventMerger.recordBeforeFileEvent(((VirtualFileWithId)file).id, file, contentChange);
|
||||
vfsEventMerger.recordBeforeFileEvent(((VirtualFileWithId)file).id, file, contentChange)
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -586,12 +589,12 @@ class IndexTest extends JavaCodeInsightFixtureTestCase {
|
||||
vfsEventMerger.processChanges(new VfsEventsMerger.VfsEventProcessor() {
|
||||
@Override
|
||||
boolean process(VfsEventsMerger.ChangeInfo info) {
|
||||
operation.set(info.toString());
|
||||
operation.set(info.toString())
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
StringUtil.replace(operation.get(), file.getPath(), file.getName());
|
||||
StringUtil.replace(operation.get(), file.getPath(), file.getName())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,7 +604,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase {
|
||||
ApplicationManager.getApplication().getMessageBus().connect(getTestRootDisposable()).subscribe(
|
||||
VirtualFileManager.VFS_CHANGES,
|
||||
listener
|
||||
);
|
||||
)
|
||||
|
||||
def fileName = "test.txt"
|
||||
final VirtualFile testFile = myFixture.addFileToProject(fileName, "test").getVirtualFile()
|
||||
@@ -614,17 +617,17 @@ class IndexTest extends JavaCodeInsightFixtureTestCase {
|
||||
assertEquals("file: $fileName\n" +
|
||||
"operation: REMOVE ADD", listener.indexingOperation(testFile))
|
||||
|
||||
VfsUtil.saveText(testFile, "foo");
|
||||
VfsUtil.saveText(testFile, "bar");
|
||||
VfsUtil.saveText(testFile, "foo")
|
||||
VfsUtil.saveText(testFile, "bar")
|
||||
|
||||
assertEquals("file: $fileName\n" +
|
||||
"operation: UPDATE-REMOVE UPDATE", listener.indexingOperation(testFile));
|
||||
"operation: UPDATE-REMOVE UPDATE", listener.indexingOperation(testFile))
|
||||
|
||||
VfsUtil.saveText(testFile, "baz")
|
||||
testFile.delete(null)
|
||||
|
||||
assertEquals("file: $fileName\n" +
|
||||
"operation: REMOVE", listener.indexingOperation(testFile));
|
||||
"operation: REMOVE", listener.indexingOperation(testFile))
|
||||
}
|
||||
|
||||
void "test files inside copied directory are indexed"() {
|
||||
@@ -643,35 +646,35 @@ class IndexTest extends JavaCodeInsightFixtureTestCase {
|
||||
assert JavaFileElementType.isInSourceContent(myFixture.tempDirFixture.getFile('another/doo/A.java'))
|
||||
}
|
||||
|
||||
|
||||
@CompileStatic
|
||||
void "test Vfs Events Processing Performance"() {
|
||||
def filename = 'A.java'
|
||||
myFixture.addFileToProject('foo/bar/' + filename, 'class A {}')
|
||||
|
||||
PlatformTestUtil.startPerformanceTest("Vfs Event Processing By Index", 1000, {
|
||||
def files = FilenameIndex.getFilesByName(project, filename, GlobalSearchScope.moduleScope(myModule))
|
||||
assert files != null
|
||||
assert files.length == 1
|
||||
assert files?.length == 1
|
||||
|
||||
VirtualFile file = files[0].virtualFile
|
||||
|
||||
def filename2 = 'B.java'
|
||||
def max = 100000
|
||||
List<VFileEvent> eventList = new ArrayList<>(max);
|
||||
def len = max / 2;
|
||||
List<VFileEvent> eventList = new ArrayList<>(max)
|
||||
def len = max / 2
|
||||
|
||||
for(int i = 0; i < len; ++i) {
|
||||
eventList.add(new VFilePropertyChangeEvent(null, file, VirtualFile.PROP_NAME, filename, filename2, true)) ;
|
||||
eventList.add(new VFilePropertyChangeEvent(null, file, VirtualFile.PROP_NAME, filename2, filename, true)) ;
|
||||
eventList.add(new VFilePropertyChangeEvent(null, file, VirtualFile.PROP_NAME, filename, filename2, true))
|
||||
eventList.add(new VFilePropertyChangeEvent(null, file, VirtualFile.PROP_NAME, filename2, filename, true))
|
||||
eventList.add(new VFileDeleteEvent(null, file, true))
|
||||
eventList.add(new VFileCreateEvent(null, file.parent, filename, false, true))
|
||||
}
|
||||
|
||||
IndexedFilesListener indexedFilesListener = ((FileBasedIndexImpl)FileBasedIndex.instance).changedFilesCollector
|
||||
indexedFilesListener.before(eventList);
|
||||
indexedFilesListener.after(eventList);
|
||||
indexedFilesListener.before(eventList)
|
||||
indexedFilesListener.after(eventList)
|
||||
|
||||
files = FilenameIndex.getFilesByName(project, filename, GlobalSearchScope.moduleScope(myModule))
|
||||
assert files != null
|
||||
assert files.length == 1
|
||||
}).cpuBound().ioBound().assertTiming();
|
||||
assert files?.length == 1
|
||||
}).cpuBound().ioBound().assertTiming()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,9 +65,6 @@
|
||||
<val name="intValues" val="{java.awt.BasicStroke.JOIN_BEVEL, java.awt.BasicStroke.JOIN_MITER, java.awt.BasicStroke.JOIN_ROUND}" />
|
||||
</annotation>
|
||||
</item>
|
||||
<item name="java.awt.CardLayout void show(Container parent, java.lang.String) 1">
|
||||
<annotation name="org.jetbrains.annotations.NonNls" />
|
||||
</item>
|
||||
<item name="java.awt.CardLayout void show(java.awt.Container, java.lang.String) 1">
|
||||
<annotation name="org.jetbrains.annotations.NonNls" />
|
||||
</item>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<item name='java.awt.datatransfer.DataFlavor DataFlavor(java.lang.String) 0'>
|
||||
<annotation name='org.jetbrains.annotations.NonNls'/>
|
||||
</item>
|
||||
<item name='java.awt.datatransfer.DataFlavor DataFlavor(java.lang.String, java.lang.String,java.lang.ClassLoader) 0'>
|
||||
<item name='java.awt.datatransfer.DataFlavor DataFlavor(java.lang.String, java.lang.String, java.lang.ClassLoader) 0'>
|
||||
<annotation name='org.jetbrains.annotations.NonNls'/>
|
||||
</item>
|
||||
</root>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<val name="flags" val="{java.awt.event.HierarchyEvent.PARENT_CHANGED,java.awt.event.HierarchyEvent.DISPLAYABILITY_CHANGED,java.awt.event.HierarchyEvent.SHOWING_CHANGED}" />
|
||||
</annotation>
|
||||
</item>
|
||||
<item name="java.awt.event.HierarchyEvent int getChangeFlags()">
|
||||
<item name="java.awt.event.HierarchyEvent long getChangeFlags()">
|
||||
<annotation name="org.intellij.lang.annotations.MagicConstant">
|
||||
<val name="flags" val="{java.awt.event.HierarchyEvent.PARENT_CHANGED,java.awt.event.HierarchyEvent.DISPLAYABILITY_CHANGED,java.awt.event.HierarchyEvent.SHOWING_CHANGED}" />
|
||||
</annotation>
|
||||
|
||||
@@ -37,12 +37,6 @@
|
||||
<item name="java.lang.Class java.lang.reflect.Method getMethod(java.lang.String, java.lang.Class<?>...) 0">
|
||||
<annotation name="org.jetbrains.annotations.NonNls" />
|
||||
</item>
|
||||
<item name="java.lang.Class java.lang.reflect.Method getMethod(java.lang.String, java.lang.Class...) 0">
|
||||
<annotation name="org.jetbrains.annotations.NonNls" />
|
||||
</item>
|
||||
<item name="java.lang.ClassLoader InputStream getResourceAsStream(java.lang.String) 0">
|
||||
<annotation name="org.jetbrains.annotations.NonNls" />
|
||||
</item>
|
||||
<item name="java.lang.ClassLoader java.io.InputStream getResourceAsStream(java.lang.String) 0">
|
||||
<annotation name="org.jetbrains.annotations.NonNls" />
|
||||
</item>
|
||||
@@ -70,9 +64,6 @@
|
||||
<item name="java.lang.Readable int read(java.nio.CharBuffer) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="java.lang.Runtime Process exec(java.lang.String[]) 0">
|
||||
<annotation name="org.jetbrains.annotations.NonNls" />
|
||||
</item>
|
||||
<item name="java.lang.Runtime java.lang.Process exec(java.lang.String[]) 0">
|
||||
<annotation name="org.jetbrains.annotations.NonNls" />
|
||||
</item>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<root>
|
||||
<item name='java.security.MessageDigest MessageDigest java.security.getInstance(java.lang.String) 0'>
|
||||
<item name='java.security.MessageDigest java.security.MessageDigest getInstance(java.lang.String) 0'>
|
||||
<annotation name='org.jetbrains.annotations.NonNls'/>
|
||||
</item>
|
||||
</root>
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
<val name="intValues" val="{java.sql.Statement.RETURN_GENERATED_KEYS, java.sql.Statement.NO_GENERATED_KEYS}" />
|
||||
</annotation>
|
||||
</item>
|
||||
<item name="java.sql.Statement int execute(java.lang.String, int) 1">
|
||||
<item name="java.sql.Statement boolean execute(java.lang.String, int) 1">
|
||||
<annotation name="org.intellij.lang.annotations.MagicConstant">
|
||||
<val name="intValues" val="{java.sql.Statement.RETURN_GENERATED_KEYS, java.sql.Statement.NO_GENERATED_KEYS}" />
|
||||
</annotation>
|
||||
|
||||
@@ -612,21 +612,12 @@
|
||||
<val name="targetIsContainer" val="true"/>
|
||||
</annotation>
|
||||
</item>
|
||||
<item name="java.util.Collection boolean containsAll(java.util.Collection<?> c) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="java.util.Collection boolean containsAll(java.util.Collection<?>) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="java.util.Collection boolean removeAll(java.util.Collection<?> c) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="java.util.Collection boolean removeAll(java.util.Collection<?>) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="java.util.Collection boolean retainAll(java.util.Collection<?> c) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="java.util.Collection boolean retainAll(java.util.Collection<?>) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
@@ -981,12 +972,6 @@
|
||||
<val name="targetIsContainer" val="true"/>
|
||||
</annotation>
|
||||
</item>
|
||||
<item name="java.util.List List<E> subList(int fromIndex, int toIndex)">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="java.util.List ListIterator<E> listIterator()">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="java.util.List T[] toArray(T[])">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
|
||||
@@ -322,6 +322,16 @@
|
||||
<val name="intValues" val="{javax.swing.JTabbedPane.WRAP_TAB_LAYOUT, javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT}" />
|
||||
</annotation>
|
||||
</item>
|
||||
<item name="javax.swing.JTabbedPane int getTabLayoutPolicy()">
|
||||
<annotation name="org.intellij.lang.annotations.MagicConstant">
|
||||
<val name="intValues" val="{javax.swing.JTabbedPane.WRAP_TAB_LAYOUT, javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT}" />
|
||||
</annotation>
|
||||
</item>
|
||||
<item name="javax.swing.JTabbedPane int getTabPlacement()">
|
||||
<annotation name="org.intellij.lang.annotations.MagicConstant">
|
||||
<val name="intValues" val="{javax.swing.SwingConstants.TOP, javax.swing.SwingConstants.BOTTOM, javax.swing.SwingConstants.LEFT, javax.swing.SwingConstants.RIGHT}" />
|
||||
</annotation>
|
||||
</item>
|
||||
<item name="javax.swing.JTable JTable(java.lang.Object[][], java.lang.Object[]) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
@@ -331,16 +341,6 @@
|
||||
<item name="javax.swing.JTable int columnAtPoint(java.awt.Point) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="javax.swing.JTable int getTabLayoutPolicy()">
|
||||
<annotation name="org.intellij.lang.annotations.MagicConstant">
|
||||
<val name="intValues" val="{javax.swing.JTabbedPane.WRAP_TAB_LAYOUT, javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT}" />
|
||||
</annotation>
|
||||
</item>
|
||||
<item name="javax.swing.JTable int getTabPlacement()">
|
||||
<annotation name="org.intellij.lang.annotations.MagicConstant">
|
||||
<val name="intValues" val="{javax.swing.SwingConstants.TOP, javax.swing.SwingConstants.BOTTOM, javax.swing.SwingConstants.LEFT, javax.swing.SwingConstants.RIGHT}" />
|
||||
</annotation>
|
||||
</item>
|
||||
<item name="javax.swing.JTable int rowAtPoint(java.awt.Point) 0">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<val name="intValues" val="{javax.swing.SwingConstants.NORTH,javax.swing.SwingConstants.SOUTH,javax.swing.SwingConstants.EAST,javax.swing.SwingConstants.WEST}" />
|
||||
</annotation>
|
||||
</item>
|
||||
<item name="javax.swing.plaf.basic.BasicArrowButton void getDirection()">
|
||||
<item name="javax.swing.plaf.basic.BasicArrowButton int getDirection()">
|
||||
<annotation name="org.intellij.lang.annotations.MagicConstant">
|
||||
<val name="intValues" val="{javax.swing.SwingConstants.NORTH,javax.swing.SwingConstants.SOUTH,javax.swing.SwingConstants.EAST,javax.swing.SwingConstants.WEST}" />
|
||||
</annotation>
|
||||
|
||||
@@ -36,13 +36,13 @@
|
||||
<item name="org.jdom.Element Element(java.lang.String) 0">
|
||||
<annotation name="org.jetbrains.annotations.NonNls" />
|
||||
</item>
|
||||
<item name="org.jdom.Element java.util.List getChildren()">
|
||||
<item name="org.jdom.Element java.util.List<org.jdom.Element> getChildren()">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="org.jdom.Element java.util.List getChildren(java.lang.String)">
|
||||
<item name="org.jdom.Element java.util.List<org.jdom.Element> getChildren(java.lang.String)">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name="org.jdom.Element java.util.List getChildren(java.lang.String, org.jdom.Namespace)">
|
||||
<item name="org.jdom.Element java.util.List<org.jdom.Element> getChildren(java.lang.String, org.jdom.Namespace)">
|
||||
<annotation name="org.jetbrains.annotations.NotNull" />
|
||||
</item>
|
||||
<item name='org.jdom.Element java.util.List<org.jdom.Content> getContent()'>
|
||||
|
||||
+21
-9
@@ -21,7 +21,6 @@ import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
|
||||
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
|
||||
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
|
||||
import com.intellij.debugger.impl.DebuggerManagerImpl;
|
||||
import com.intellij.debugger.impl.PositionUtil;
|
||||
import com.intellij.debugger.impl.PrioritizedTask;
|
||||
import com.intellij.debugger.impl.SynchronizationBasedSemaphore;
|
||||
@@ -47,9 +46,9 @@ import com.intellij.util.SmartList;
|
||||
import com.intellij.util.TimeoutUtil;
|
||||
import com.intellij.util.lang.CompoundRuntimeException;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.xdebugger.breakpoints.XBreakpoint;
|
||||
import com.sun.jdi.Method;
|
||||
import com.sun.jdi.ThreadReference;
|
||||
import org.jetbrains.java.debugger.breakpoints.properties.JavaMethodBreakpointProperties;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
@@ -379,33 +378,41 @@ public abstract class ExecutionWithDebuggerToolsTestCase extends ExecutionTestCa
|
||||
|
||||
public void createBreakpoints(final PsiFile file) {
|
||||
Runnable runnable = () -> {
|
||||
BreakpointManager breakpointManager = DebuggerManagerImpl.getInstanceEx(myProject).getBreakpointManager();
|
||||
BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
|
||||
Document document = PsiDocumentManager.getInstance(myProject).getDocument(file);
|
||||
String text = document.getText();
|
||||
int offset = -1;
|
||||
for (; ;) {
|
||||
offset = document.getText().indexOf("Breakpoint!", offset + 1);
|
||||
while (true) {
|
||||
offset = text.indexOf("Breakpoint!", offset + 1);
|
||||
if (offset == -1) break;
|
||||
|
||||
int commentLine = document.getLineNumber(offset);
|
||||
|
||||
String comment = document.getText().substring(document.getLineStartOffset(commentLine), document.getLineEndOffset(commentLine));
|
||||
String comment = text.substring(document.getLineStartOffset(commentLine), document.getLineEndOffset(commentLine));
|
||||
|
||||
Breakpoint breakpoint;
|
||||
|
||||
if (comment.indexOf("Method") != -1) {
|
||||
if (comment.contains("Method")) {
|
||||
breakpoint = breakpointManager.addMethodBreakpoint(document, commentLine + 1);
|
||||
if (breakpoint != null) {
|
||||
println("MethodBreakpoint created at " + file.getVirtualFile().getName() + ":" + (commentLine + 2),
|
||||
ProcessOutputTypes.SYSTEM);
|
||||
|
||||
String emulated = readValue(comment, "Emulated");
|
||||
if (emulated != null) {
|
||||
((JavaMethodBreakpointProperties)breakpoint.getXBreakpoint().getProperties()).EMULATED = Boolean.valueOf(emulated);
|
||||
println("Emulated = " + emulated, ProcessOutputTypes.SYSTEM);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (comment.indexOf("Field") != -1) {
|
||||
else if (comment.contains("Field")) {
|
||||
breakpoint = breakpointManager.addFieldBreakpoint(document, commentLine + 1, readValue(comment, "Field"));
|
||||
if (breakpoint != null) {
|
||||
println("FieldBreakpoint created at " + file.getVirtualFile().getName() + ":" + (commentLine + 2), ProcessOutputTypes.SYSTEM);
|
||||
}
|
||||
}
|
||||
else if (comment.indexOf("Exception") != -1) {
|
||||
else if (comment.contains("Exception")) {
|
||||
breakpoint = breakpointManager.addExceptionBreakpoint(readValue(comment, "Exception"), "");
|
||||
if (breakpoint != null) {
|
||||
println("ExceptionBreakpoint created at " + file.getVirtualFile().getName() + ":" + (commentLine + 2),
|
||||
@@ -419,6 +426,11 @@ public abstract class ExecutionWithDebuggerToolsTestCase extends ExecutionTestCa
|
||||
}
|
||||
}
|
||||
|
||||
if (breakpoint == null) {
|
||||
LOG.error("Unable to set a breakpoint at line " + (commentLine + 1));
|
||||
continue;
|
||||
}
|
||||
|
||||
String suspendPolicy = readValue(comment, "suspendPolicy");
|
||||
if (suspendPolicy != null) {
|
||||
//breakpoint.setSuspend(!DebuggerSettings.SUSPEND_NONE.equals(suspendPolicy));
|
||||
|
||||
@@ -18,16 +18,16 @@ package com.jetbrains.jsonSchema;
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
|
||||
import com.intellij.json.JsonFileType;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.ZipperUpdater;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.openapi.vfs.impl.BulkVirtualFileListenerAdapter;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.search.FileTypeIndex;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaServiceImpl;
|
||||
@@ -53,23 +53,29 @@ public class JsonSchemaVfsListener extends BulkVirtualFileListenerAdapter {
|
||||
if (scope.isEmpty()) return;
|
||||
|
||||
final DaemonCodeAnalyzer analyzer = DaemonCodeAnalyzer.getInstance(project);
|
||||
ApplicationManager.getApplication().runReadAction(() -> {
|
||||
FileTypeIndex.processFiles(JsonFileType.INSTANCE, jsonFile -> {
|
||||
final Collection<Pair<VirtualFile, String>> collection = myService.getSchemaFilesByFile(jsonFile);
|
||||
if (collection != null && !collection.isEmpty()) {
|
||||
for (Pair<VirtualFile, String> pair : collection) {
|
||||
if (scope.contains(pair.getFirst())) {
|
||||
final PsiFile psiFile = PsiManager.getInstance(project).findFile(jsonFile);
|
||||
if (psiFile != null) {
|
||||
analyzer.restart(psiFile);
|
||||
final PsiManager psiManager = PsiManager.getInstance(project);
|
||||
final Editor[] editors = EditorFactory.getInstance().getAllEditors();
|
||||
for (Editor editor : editors) {
|
||||
if (editor instanceof EditorEx) {
|
||||
final VirtualFile file = ((EditorEx)editor).getVirtualFile();
|
||||
if (JsonFileType.INSTANCE.equals(file.getFileType())) {
|
||||
final Collection<Pair<VirtualFile, String>> collection = myService.getSchemaFilesByFile(file);
|
||||
if (collection != null && !collection.isEmpty()) {
|
||||
for (Pair<VirtualFile, String> pair : collection) {
|
||||
if (scope.contains(pair.getFirst())) {
|
||||
ApplicationManager.getApplication().runReadAction(() -> {
|
||||
final PsiFile psiFile = psiManager.findFile(file);
|
||||
if (psiFile != null) {
|
||||
analyzer.restart(psiFile);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, GlobalSearchScope.projectScope(project));
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
@@ -105,10 +111,8 @@ public class JsonSchemaVfsListener extends BulkVirtualFileListenerAdapter {
|
||||
private void onFileChange(@NotNull final VirtualFile schemaFile) {
|
||||
if (myMappingsProjectConfiguration.isRegisteredSchemaFile(schemaFile)) {
|
||||
myService.dropProviderFromCache(schemaFile);
|
||||
if (Registry.is("json.schema.fast.annotation.update")) {
|
||||
myDirtySchemas.add(schemaFile);
|
||||
myUpdater.queue(myRunnable);
|
||||
}
|
||||
myDirtySchemas.add(schemaFile);
|
||||
myUpdater.queue(myRunnable);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package com.jetbrains.jsonSchema.impl;
|
||||
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.SLRUMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -16,7 +19,7 @@ public class JsonSchemaObject {
|
||||
private Map<String, JsonSchemaObject> myDefinitions;
|
||||
private Map<String, JsonSchemaObject> myProperties;
|
||||
private Map<String, JsonSchemaObject> myPatternProperties;
|
||||
private final SLRUMap<String, String> myCachedPatternProperties = new SLRUMap<>(100, 100);
|
||||
private final PatternCalculator myPatternCalculator = new PatternCalculator();
|
||||
|
||||
private String myId;
|
||||
private String mySchema;
|
||||
@@ -80,7 +83,7 @@ public class JsonSchemaObject {
|
||||
myProperties = other.myProperties;
|
||||
myDefinitions = other.myDefinitions;
|
||||
myPatternProperties = other.myPatternProperties;
|
||||
myCachedPatternProperties.clear();
|
||||
myPatternCalculator.clear();
|
||||
|
||||
myType = other.myType;
|
||||
myDefault = other.myDefault;
|
||||
@@ -123,7 +126,7 @@ public class JsonSchemaObject {
|
||||
myProperties.putAll(other.myProperties);
|
||||
myDefinitions = copyMap(myDefinitions, other.myDefinitions);
|
||||
myPatternProperties = copyMap(myPatternProperties, other.myPatternProperties);
|
||||
myCachedPatternProperties.clear();
|
||||
myPatternCalculator.clear();
|
||||
if (!StringUtil.isEmptyOrSpaces(other.myDescription)) {
|
||||
myDescription = other.myDescription;
|
||||
}
|
||||
@@ -198,7 +201,7 @@ public class JsonSchemaObject {
|
||||
|
||||
public void setPatternProperties(Map<String, JsonSchemaObject> patternProperties) {
|
||||
myPatternProperties = patternProperties;
|
||||
myCachedPatternProperties.clear();
|
||||
myPatternCalculator.clear();
|
||||
}
|
||||
|
||||
public JsonSchemaType getType() {
|
||||
@@ -503,20 +506,7 @@ public class JsonSchemaObject {
|
||||
|
||||
@Nullable
|
||||
public JsonSchemaObject getMatchingPatternPropertySchema(@NotNull String name) {
|
||||
if (myPatternProperties == null || myPatternProperties.isEmpty()) return null;
|
||||
final String s = myCachedPatternProperties.get(name);
|
||||
if (s != null) return myPatternProperties.get(s);
|
||||
final List<String> strings = new ArrayList<>(myPatternProperties.keySet());
|
||||
Collections.sort(strings);
|
||||
for (final String pattern : strings) {
|
||||
final boolean matches = Pattern.compile(adaptSchemaPattern(pattern)).matcher(StringUtil.newBombedCharSequence(name, 1000)).matches();
|
||||
if (matches) {
|
||||
myCachedPatternProperties.put(name, pattern);
|
||||
return myPatternProperties.get(pattern);
|
||||
}
|
||||
}
|
||||
myCachedPatternProperties.put(name, "");
|
||||
return null;
|
||||
return myPatternCalculator.getMatchingPatternPropertySchema(myPatternProperties, name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -525,4 +515,84 @@ public class JsonSchemaObject {
|
||||
pattern = pattern.endsWith("+") || pattern.endsWith("*") ? pattern : (pattern + ".*");
|
||||
return pattern;
|
||||
}
|
||||
|
||||
private static class PatternCalculator {
|
||||
private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
|
||||
private Map<String, Pattern> myCachedPatterns;
|
||||
private SLRUMap<String, String> myCachedPatternProperties;
|
||||
|
||||
@Nullable
|
||||
public JsonSchemaObject getMatchingPatternPropertySchema(@Nullable final Map<String, JsonSchemaObject> patternProperties,
|
||||
@NotNull final String name) {
|
||||
if (patternProperties == null || patternProperties.isEmpty()) return null;
|
||||
myLock.readLock().lock();
|
||||
try {
|
||||
if (myCachedPatterns == null) {
|
||||
initPatternCache(patternProperties);
|
||||
}
|
||||
assert myCachedPatternProperties != null;
|
||||
final String s = myCachedPatternProperties.get(name);
|
||||
if (s != null) return patternProperties.get(s);
|
||||
return matchPatternsToString(name, patternProperties);
|
||||
} finally {
|
||||
myLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
myLock.writeLock().lock();
|
||||
try {
|
||||
myCachedPatterns = null;
|
||||
myCachedPatternProperties = null;
|
||||
} finally {
|
||||
myLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private JsonSchemaObject matchPatternsToString(@NotNull final String name, @NotNull final Map<String, JsonSchemaObject> patternProperties) {
|
||||
final List<String> strings = new ArrayList<>(patternProperties.keySet());
|
||||
Collections.sort(strings);
|
||||
|
||||
return underWrite(() -> {
|
||||
for (final String pattern : strings) {
|
||||
try {
|
||||
final Pattern compiledPattern = myCachedPatterns.get(pattern);
|
||||
assert compiledPattern != null;
|
||||
final boolean matches = compiledPattern.matcher(StringUtil.newBombedCharSequence(name, 300)).matches();
|
||||
if (matches) {
|
||||
myCachedPatternProperties.put(name, pattern);
|
||||
return patternProperties.get(pattern);
|
||||
}
|
||||
} catch (ProcessCanceledException e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
myCachedPatternProperties.put(name, "");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private <T> T underWrite(@NotNull final Computable<T> computable) {
|
||||
myLock.readLock().unlock();
|
||||
myLock.writeLock().lock();
|
||||
try {
|
||||
final T t = computable.compute();
|
||||
myLock.readLock().lock();
|
||||
return t;
|
||||
} finally {
|
||||
myLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void initPatternCache(@NotNull final Map<String, JsonSchemaObject> patternProperties) {
|
||||
underWrite(() -> {
|
||||
myCachedPatterns = new HashMap<>(patternProperties.size(), 1.0f);
|
||||
myCachedPatternProperties = new SLRUMap<>(100, 100);
|
||||
for (String pattern : patternProperties.keySet()) {
|
||||
myCachedPatterns.put(pattern, Pattern.compile(adaptSchemaPattern(pattern)));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ public abstract class GlobalInspectionTool extends InspectionProfileEntry {
|
||||
* usages of the same classes and methods, usage searches are not performed directly, but
|
||||
* instead are queued for batch processing through
|
||||
* {@link GlobalJavaInspectionContext#enqueueClassUsagesProcessor} and similar methods. The method
|
||||
* can add new problems to <code>problemDescriptionsProcessor</code> or remove some of the problems
|
||||
* can add new problems to {@code problemDescriptionsProcessor} or remove some of the problems
|
||||
* collected by {@link #runInspection(AnalysisScope, InspectionManager, GlobalInspectionContext, ProblemDescriptionsProcessor)}
|
||||
* by calling {@link ProblemDescriptionsProcessor#ignoreElement(RefEntity)}.
|
||||
*
|
||||
@@ -207,7 +207,6 @@ public abstract class GlobalInspectionTool extends InspectionProfileEntry {
|
||||
* @return JobDescriptors array to show inspection progress correctly. TotalAmount should be set (e.g. in
|
||||
* {@link #runInspection(AnalysisScope, InspectionManager, GlobalInspectionContext, ProblemDescriptionsProcessor)})
|
||||
* ProgressIndicator should progress with {@link GlobalInspectionContext#incrementJobDoneAmount(JobDescriptor, String)}
|
||||
* @param context
|
||||
*/
|
||||
@Nullable
|
||||
public JobDescriptor[] getAdditionalJobs(GlobalInspectionContext context) {
|
||||
|
||||
@@ -311,8 +311,8 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool {
|
||||
|
||||
/**
|
||||
* Read in settings from XML config.
|
||||
* Default implementation uses XmlSerializer so you may use public fields (like <code>int TOOL_OPTION</code>)
|
||||
* and bean-style getters/setters (like <code>int getToolOption(), void setToolOption(int)</code>) to store your options.
|
||||
* Default implementation uses XmlSerializer so you may use public fields (like {@code int TOOL_OPTION})
|
||||
* and bean-style getters/setters (like {@code int getToolOption(), void setToolOption(int)}) to store your options.
|
||||
*
|
||||
* @param node to read settings from.
|
||||
* @throws InvalidDataException if the loaded data was not valid.
|
||||
@@ -334,8 +334,8 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool {
|
||||
|
||||
/**
|
||||
* Store current settings in XML config.
|
||||
* Default implementation uses XmlSerializer so you may use public fields (like <code>int TOOL_OPTION</code>)
|
||||
* and bean-style getters/setters (like <code>int getToolOption(), void setToolOption(int)</code>) to store your options.
|
||||
* Default implementation uses XmlSerializer so you may use public fields (like {@code int TOOL_OPTION})
|
||||
* and bean-style getters/setters (like {@code int getToolOption(), void setToolOption(int)}) to store your options.
|
||||
*
|
||||
* @param node to store settings to.
|
||||
* @throws WriteExternalException if no data should be saved for this component.
|
||||
@@ -366,17 +366,11 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
|
||||
try {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (!line.isEmpty()) ourBlackList.add(line);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
reader.close();
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (!line.isEmpty()) ourBlackList.add(line);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
||||
@@ -600,7 +600,8 @@ public class ByWord {
|
||||
Range expanded = expandW(myText1, myText2, range);
|
||||
Range trimmed = trim(myText1, myText2, expanded);
|
||||
|
||||
if (!trimmed.isEmpty()) {
|
||||
if (!trimmed.isEmpty() &&
|
||||
!isEqualsIW(myText1, myText2, trimmed)) {
|
||||
myChanges.add(trimmed);
|
||||
}
|
||||
}
|
||||
@@ -638,7 +639,8 @@ public class ByWord {
|
||||
MergeRange expanded = expandW(myText1, myText2, myText3, range);
|
||||
MergeRange trimmed = trim(myText1, myText2, myText3, expanded);
|
||||
|
||||
if (!trimmed.isEmpty()) {
|
||||
if (!trimmed.isEmpty() &&
|
||||
!isEqualsIW(myText1, myText2, myText3, trimmed)) {
|
||||
myChanges.add(trimmed);
|
||||
}
|
||||
}
|
||||
@@ -690,7 +692,8 @@ public class ByWord {
|
||||
|
||||
Range trimmed = new Range(start1, end1, start2, end2);
|
||||
|
||||
if (!trimmed.isEmpty()) {
|
||||
if (!trimmed.isEmpty() &&
|
||||
!isEquals(myText1, myText2, trimmed)) {
|
||||
myChanges.add(trimmed);
|
||||
}
|
||||
}
|
||||
@@ -753,7 +756,8 @@ public class ByWord {
|
||||
|
||||
MergeRange trimmed = new MergeRange(start1, end1, start2, end2, start3, end3);
|
||||
|
||||
if (!trimmed.isEmpty()) {
|
||||
if (!trimmed.isEmpty() &&
|
||||
!isEquals(myText1, myText2, myText3, trimmed)) {
|
||||
myChanges.add(trimmed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,4 +384,40 @@ public class TrimUtil {
|
||||
public static Range expandIW(@NotNull CharSequence text1, @NotNull CharSequence text2) {
|
||||
return expandIW(text1, text2, 0, 0, text1.length(), text2.length());
|
||||
}
|
||||
|
||||
//
|
||||
// Equality
|
||||
//
|
||||
|
||||
public static boolean isEquals(@NotNull CharSequence text1, @NotNull CharSequence text2,
|
||||
@NotNull Range range) {
|
||||
CharSequence sequence1 = text1.subSequence(range.start1, range.end1);
|
||||
CharSequence sequence2 = text2.subSequence(range.start2, range.end2);
|
||||
return ComparisonUtil.isEquals(sequence1, sequence2, ComparisonPolicy.DEFAULT);
|
||||
}
|
||||
|
||||
public static boolean isEqualsIW(@NotNull CharSequence text1, @NotNull CharSequence text2,
|
||||
@NotNull Range range) {
|
||||
CharSequence sequence1 = text1.subSequence(range.start1, range.end1);
|
||||
CharSequence sequence2 = text2.subSequence(range.start2, range.end2);
|
||||
return ComparisonUtil.isEquals(sequence1, sequence2, ComparisonPolicy.IGNORE_WHITESPACES);
|
||||
}
|
||||
|
||||
public static boolean isEquals(@NotNull CharSequence text1, @NotNull CharSequence text2, @NotNull CharSequence text3,
|
||||
@NotNull MergeRange range) {
|
||||
CharSequence sequence1 = text1.subSequence(range.start1, range.end1);
|
||||
CharSequence sequence2 = text2.subSequence(range.start2, range.end2);
|
||||
CharSequence sequence3 = text3.subSequence(range.start3, range.end3);
|
||||
return ComparisonUtil.isEquals(sequence2, sequence1, ComparisonPolicy.DEFAULT) &&
|
||||
ComparisonUtil.isEquals(sequence2, sequence3, ComparisonPolicy.DEFAULT);
|
||||
}
|
||||
|
||||
public static boolean isEqualsIW(@NotNull CharSequence text1, @NotNull CharSequence text2, @NotNull CharSequence text3,
|
||||
@NotNull MergeRange range) {
|
||||
CharSequence sequence1 = text1.subSequence(range.start1, range.end1);
|
||||
CharSequence sequence2 = text2.subSequence(range.start2, range.end2);
|
||||
CharSequence sequence3 = text3.subSequence(range.start3, range.end3);
|
||||
return ComparisonUtil.isEquals(sequence2, sequence1, ComparisonPolicy.IGNORE_WHITESPACES) &&
|
||||
ComparisonUtil.isEquals(sequence2, sequence3, ComparisonPolicy.IGNORE_WHITESPACES);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.intellij.diff.util.ThreeSide
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.progress.DumbProgressIndicator
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.util.Couple
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.testFramework.UsefulTestCase
|
||||
@@ -66,6 +65,10 @@ abstract class DiffTestCase : UsefulTestCase() {
|
||||
assertTrue(message, actual)
|
||||
}
|
||||
|
||||
fun assertFalse(actual: Boolean, message: String = "") {
|
||||
assertFalse(message, actual)
|
||||
}
|
||||
|
||||
fun assertEquals(expected: Any?, actual: Any?, message: String = "") {
|
||||
assertEquals(message, expected, actual)
|
||||
}
|
||||
@@ -75,17 +78,33 @@ abstract class DiffTestCase : UsefulTestCase() {
|
||||
}
|
||||
|
||||
fun assertEqualsCharSequences(chunk1: CharSequence, chunk2: CharSequence, ignoreSpaces: Boolean, skipLastNewline: Boolean) {
|
||||
if (skipLastNewline && !ignoreSpaces) {
|
||||
assertTrue(StringUtil.equals(chunk1, chunk2) ||
|
||||
StringUtil.equals(stripNewline(chunk1), chunk2) ||
|
||||
StringUtil.equals(chunk1, stripNewline(chunk2)))
|
||||
}
|
||||
else {
|
||||
assertTrue(isEqualsCharSequences(chunk1, chunk2, ignoreSpaces))
|
||||
}
|
||||
}
|
||||
|
||||
fun assertNotEqualsCharSequences(chunk1: CharSequence, chunk2: CharSequence, ignoreSpaces: Boolean, skipLastNewline: Boolean) {
|
||||
if (skipLastNewline && !ignoreSpaces) {
|
||||
assertTrue(!StringUtil.equals(chunk1, chunk2) ||
|
||||
!StringUtil.equals(stripNewline(chunk1), chunk2) ||
|
||||
!StringUtil.equals(chunk1, stripNewline(chunk2)))
|
||||
}
|
||||
else {
|
||||
assertFalse(isEqualsCharSequences(chunk1, chunk2, ignoreSpaces))
|
||||
}
|
||||
}
|
||||
|
||||
fun isEqualsCharSequences(chunk1: CharSequence, chunk2: CharSequence, ignoreSpaces: Boolean): Boolean {
|
||||
if (ignoreSpaces) {
|
||||
assertTrue(StringUtil.equalsIgnoreWhitespaces(chunk1, chunk2))
|
||||
} else {
|
||||
if (skipLastNewline) {
|
||||
if (StringUtil.equals(chunk1, chunk2)) return
|
||||
if (StringUtil.equals(stripNewline(chunk1), chunk2)) return
|
||||
if (StringUtil.equals(chunk1, stripNewline(chunk2))) return
|
||||
assertTrue(false)
|
||||
} else {
|
||||
assertTrue(StringUtil.equals(chunk1, chunk2))
|
||||
}
|
||||
return StringUtil.equalsIgnoreWhitespaces(chunk1, chunk2)
|
||||
}
|
||||
else {
|
||||
return StringUtil.equals(chunk1, chunk2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,14 +221,14 @@ abstract class DiffTestCase : UsefulTestCase() {
|
||||
// Helpers
|
||||
//
|
||||
|
||||
open class Trio<T : Any>(val data1: T, val data2: T, val data3: T) {
|
||||
open class Trio<out T>(val data1: T, val data2: T, val data3: T) {
|
||||
companion object {
|
||||
fun <V : Any> from(f: (ThreeSide) -> V): Trio<V> = Trio(f(ThreeSide.LEFT), f(ThreeSide.BASE), f(ThreeSide.RIGHT))
|
||||
fun <V> from(f: (ThreeSide) -> V): Trio<V> = Trio(f(ThreeSide.LEFT), f(ThreeSide.BASE), f(ThreeSide.RIGHT))
|
||||
}
|
||||
|
||||
fun <V : Any> map(f: (T) -> V): Trio<V> = Trio(f(data1), f(data2), f(data3))
|
||||
fun <V> map(f: (T) -> V): Trio<V> = Trio(f(data1), f(data2), f(data3))
|
||||
|
||||
fun <V : Any> map(f: (T, ThreeSide) -> V): Trio<V> = Trio(f(data1, ThreeSide.LEFT), f(data2, ThreeSide.BASE), f(data3, ThreeSide.RIGHT))
|
||||
fun <V> map(f: (T, ThreeSide) -> V): Trio<V> = Trio(f(data1, ThreeSide.LEFT), f(data2, ThreeSide.BASE), f(data3, ThreeSide.RIGHT))
|
||||
|
||||
fun forEach(f: (T, ThreeSide) -> Unit): Unit {
|
||||
f(data1, ThreeSide.LEFT)
|
||||
@@ -228,7 +247,11 @@ abstract class DiffTestCase : UsefulTestCase() {
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return data1.hashCode() * 37 * 37 + data2.hashCode() * 37 + data3.hashCode()
|
||||
var h = 0
|
||||
if (data1 != null) h = h * 31 + data1.hashCode()
|
||||
if (data2 != null) h = h * 31 + data2.hashCode()
|
||||
if (data3 != null) h = h * 31 + data3.hashCode()
|
||||
return h
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,28 +26,31 @@ import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
|
||||
class ComparisonUtilAutoTest : DiffTestCase() {
|
||||
val RUNS = 30
|
||||
val MAX_LENGTH = 300
|
||||
|
||||
fun testChar() {
|
||||
doTestChar(System.currentTimeMillis(), 30, 30)
|
||||
doTestChar(System.currentTimeMillis(), RUNS, MAX_LENGTH)
|
||||
}
|
||||
|
||||
fun testWord() {
|
||||
doTestWord(System.currentTimeMillis(), 30, 300)
|
||||
doTestWord(System.currentTimeMillis(), RUNS, MAX_LENGTH)
|
||||
}
|
||||
|
||||
fun testLine() {
|
||||
doTestLine(System.currentTimeMillis(), 30, 300)
|
||||
doTestLine(System.currentTimeMillis(), RUNS, MAX_LENGTH)
|
||||
}
|
||||
|
||||
fun testLineSquashed() {
|
||||
doTestLineSquashed(System.currentTimeMillis(), 30, 300)
|
||||
doTestLineSquashed(System.currentTimeMillis(), RUNS, MAX_LENGTH)
|
||||
}
|
||||
|
||||
fun testLineTrimSquashed() {
|
||||
doTestLineTrimSquashed(System.currentTimeMillis(), 30, 300)
|
||||
doTestLineTrimSquashed(System.currentTimeMillis(), RUNS, MAX_LENGTH)
|
||||
}
|
||||
|
||||
fun testMerge() {
|
||||
doTestMerge(System.currentTimeMillis(), 30, 300)
|
||||
doTestMerge(System.currentTimeMillis(), RUNS, MAX_LENGTH)
|
||||
}
|
||||
|
||||
private fun doTestLine(seed: Long, runs: Int, maxLength: Int) {
|
||||
@@ -141,8 +144,8 @@ class ComparisonUtilAutoTest : DiffTestCase() {
|
||||
val chunk2 = DiffUtil.getLinesContent(text2, f.startLine2, f.endLine2)
|
||||
val chunk3 = DiffUtil.getLinesContent(text3, f.startLine3, f.endLine3)
|
||||
|
||||
val wordFragments = ByWord.compare(chunk1, chunk2, chunk3, policy, INDICATOR);
|
||||
MergeLineFragmentImpl(f, wordFragments);
|
||||
val wordFragments = ByWord.compare(chunk1, chunk2, chunk3, policy, INDICATOR)
|
||||
MergeLineFragmentImpl(f, wordFragments)
|
||||
}
|
||||
debugData.put("Fragments", fineFragments)
|
||||
|
||||
@@ -200,18 +203,18 @@ class ComparisonUtilAutoTest : DiffTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
checkUnchanged(text1.charsSequence, text2.charsSequence, fragments, policy, true)
|
||||
checkValidRanges(text1.charsSequence, text2.charsSequence, fragments, policy, true)
|
||||
checkCantTrimLines(text1, text2, fragments, policy, allowNonSquashed)
|
||||
}
|
||||
|
||||
private fun checkResultWord(text1: CharSequence, text2: CharSequence, fragments: List<DiffFragment>, policy: ComparisonPolicy) {
|
||||
checkDiffConsistency(fragments)
|
||||
checkUnchanged(text1, text2, fragments, policy, false)
|
||||
checkValidRanges(text1, text2, fragments, policy, false)
|
||||
}
|
||||
|
||||
private fun checkResultChar(text1: CharSequence, text2: CharSequence, fragments: List<DiffFragment>, policy: ComparisonPolicy) {
|
||||
checkDiffConsistency(fragments)
|
||||
checkUnchanged(text1, text2, fragments, policy, false)
|
||||
checkValidRanges(text1, text2, fragments, policy, false)
|
||||
}
|
||||
|
||||
private fun checkResultMerge(text1: Document, text2: Document, text3: Document, fragments: List<MergeLineFragment>, policy: ComparisonPolicy) {
|
||||
@@ -223,10 +226,10 @@ class ComparisonUtilAutoTest : DiffTestCase() {
|
||||
val chunk3 = DiffUtil.getLinesContent(text3, f.startLine3, f.endLine3)
|
||||
|
||||
checkDiffConsistency3(f.innerFragments!!)
|
||||
checkUnchanged3(chunk1, chunk2, chunk3, f.innerFragments!!, policy)
|
||||
checkValidRanges3(chunk1, chunk2, chunk3, f.innerFragments!!, policy)
|
||||
}
|
||||
|
||||
checkUnchanged3(text1, text2, text3, fragments, policy)
|
||||
checkValidRanges3(text1, text2, text3, fragments, policy)
|
||||
checkCantTrimLines3(text1, text2, text3, fragments, policy)
|
||||
}
|
||||
|
||||
@@ -374,28 +377,39 @@ class ComparisonUtilAutoTest : DiffTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkUnchanged(text1: CharSequence, text2: CharSequence, fragments: List<DiffFragment>, policy: ComparisonPolicy, skipNewline: Boolean) {
|
||||
private fun checkValidRanges(text1: CharSequence, text2: CharSequence, fragments: List<DiffFragment>, policy: ComparisonPolicy, skipNewline: Boolean) {
|
||||
// TODO: better check for Trim spaces case ?
|
||||
val ignoreSpaces = policy !== ComparisonPolicy.DEFAULT
|
||||
val ignoreSpacesUnchanged = policy != ComparisonPolicy.DEFAULT
|
||||
val ignoreSpacesChanged = policy == ComparisonPolicy.IGNORE_WHITESPACES
|
||||
|
||||
var last1 = 0
|
||||
var last2 = 0
|
||||
for (fragment in fragments) {
|
||||
val chunk1 = text1.subSequence(last1, fragment.startOffset1)
|
||||
val chunk2 = text2.subSequence(last2, fragment.startOffset2)
|
||||
val start1 = fragment.startOffset1
|
||||
val start2 = fragment.startOffset2
|
||||
val end1 = fragment.endOffset1
|
||||
val end2 = fragment.endOffset2
|
||||
|
||||
assertEqualsCharSequences(chunk1, chunk2, ignoreSpaces, skipNewline)
|
||||
val chunk1 = text1.subSequence(last1, start1)
|
||||
val chunk2 = text2.subSequence(last2, start2)
|
||||
assertEqualsCharSequences(chunk1, chunk2, ignoreSpacesUnchanged, skipNewline)
|
||||
|
||||
val chunkContent1 = text1.subSequence(start1, end1)
|
||||
val chunkContent2 = text2.subSequence(start2, end2)
|
||||
if (!skipNewline) {
|
||||
assertNotEqualsCharSequences(chunkContent1, chunkContent2, ignoreSpacesChanged, skipNewline)
|
||||
}
|
||||
|
||||
last1 = fragment.endOffset1
|
||||
last2 = fragment.endOffset2
|
||||
}
|
||||
val chunk1 = text1.subSequence(last1, text1.length)
|
||||
val chunk2 = text2.subSequence(last2, text2.length)
|
||||
assertEqualsCharSequences(chunk1, chunk2, ignoreSpaces, skipNewline)
|
||||
assertEqualsCharSequences(chunk1, chunk2, ignoreSpacesUnchanged, skipNewline)
|
||||
}
|
||||
|
||||
private fun checkUnchanged3(text1: Document, text2: Document, text3: Document, fragments: List<MergeLineFragment>, policy: ComparisonPolicy) {
|
||||
val ignoreSpaces = policy !== ComparisonPolicy.DEFAULT
|
||||
private fun checkValidRanges3(text1: Document, text2: Document, text3: Document, fragments: List<MergeLineFragment>, policy: ComparisonPolicy) {
|
||||
val ignoreSpaces = policy != ComparisonPolicy.DEFAULT
|
||||
|
||||
var last1 = 0
|
||||
var last2 = 0
|
||||
@@ -425,8 +439,9 @@ class ComparisonUtilAutoTest : DiffTestCase() {
|
||||
assertEqualsCharSequences(content2, content3, ignoreSpaces, false)
|
||||
}
|
||||
|
||||
private fun checkUnchanged3(text1: CharSequence, text2: CharSequence, text3: CharSequence, fragments: List<MergeWordFragment>, policy: ComparisonPolicy) {
|
||||
val ignoreSpaces = policy !== ComparisonPolicy.DEFAULT
|
||||
private fun checkValidRanges3(text1: CharSequence, text2: CharSequence, text3: CharSequence, fragments: List<MergeWordFragment>, policy: ComparisonPolicy) {
|
||||
val ignoreSpacesUnchanged = policy != ComparisonPolicy.DEFAULT
|
||||
val ignoreSpacesChanged = policy == ComparisonPolicy.IGNORE_WHITESPACES
|
||||
|
||||
var last1 = 0
|
||||
var last2 = 0
|
||||
@@ -435,13 +450,21 @@ class ComparisonUtilAutoTest : DiffTestCase() {
|
||||
val start1 = fragment.startOffset1
|
||||
val start2 = fragment.startOffset2
|
||||
val start3 = fragment.startOffset3
|
||||
val end1 = fragment.endOffset1
|
||||
val end2 = fragment.endOffset2
|
||||
val end3 = fragment.endOffset3
|
||||
|
||||
val content1 = text1.subSequence(last1, start1)
|
||||
val content2 = text2.subSequence(last2, start2)
|
||||
val content3 = text3.subSequence(last3, start3)
|
||||
assertEqualsCharSequences(content2, content1, ignoreSpacesUnchanged, false)
|
||||
assertEqualsCharSequences(content2, content3, ignoreSpacesUnchanged, false)
|
||||
|
||||
assertEqualsCharSequences(content2, content1, ignoreSpaces, false)
|
||||
assertEqualsCharSequences(content2, content3, ignoreSpaces, false)
|
||||
val chunkContent1 = text1.subSequence(start1, end1)
|
||||
val chunkContent2 = text2.subSequence(start2, end2)
|
||||
val chunkContent3 = text3.subSequence(start3, end3)
|
||||
assertFalse(isEqualsCharSequences(chunkContent2, chunkContent1, ignoreSpacesChanged) &&
|
||||
isEqualsCharSequences(chunkContent2, chunkContent3, ignoreSpacesChanged))
|
||||
|
||||
last1 = fragment.endOffset1
|
||||
last2 = fragment.endOffset2
|
||||
@@ -452,8 +475,8 @@ class ComparisonUtilAutoTest : DiffTestCase() {
|
||||
val content2 = text2.subSequence(last2, text2.length)
|
||||
val content3 = text3.subSequence(last3, text3.length)
|
||||
|
||||
assertEqualsCharSequences(content2, content1, ignoreSpaces, false)
|
||||
assertEqualsCharSequences(content2, content3, ignoreSpaces, false)
|
||||
assertEqualsCharSequences(content2, content1, ignoreSpacesUnchanged, false)
|
||||
assertEqualsCharSequences(content2, content3, ignoreSpacesUnchanged, false)
|
||||
}
|
||||
|
||||
private fun checkCantTrimLines(text1: Document, text2: Document, fragments: List<LineFragment>, policy: ComparisonPolicy, allowNonSquashed: Boolean) {
|
||||
@@ -491,11 +514,7 @@ class ComparisonUtilAutoTest : DiffTestCase() {
|
||||
}
|
||||
|
||||
private fun countNonWhitespaceCharacters(line: CharSequence): Int {
|
||||
var count = 0
|
||||
for (i in 0 until line.length) {
|
||||
if (!StringUtil.isWhiteSpace(line[i])) count++
|
||||
}
|
||||
return count
|
||||
return (0 until line.length).count { !StringUtil.isWhiteSpace(line[it]) }
|
||||
}
|
||||
|
||||
private fun getFirstLastLines(text: Document, start: Int, end: Int): Couple<CharSequence>? {
|
||||
|
||||
@@ -18,6 +18,9 @@ package com.intellij.diff.comparison
|
||||
import com.intellij.diff.DiffTestCase
|
||||
import com.intellij.diff.fragments.DiffFragment
|
||||
import com.intellij.diff.fragments.LineFragment
|
||||
import com.intellij.diff.fragments.MergeWordFragment
|
||||
import com.intellij.diff.util.IntPair
|
||||
import com.intellij.diff.util.ThreeSide
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.editor.impl.DocumentImpl
|
||||
import com.intellij.openapi.util.Couple
|
||||
@@ -25,31 +28,64 @@ import com.intellij.util.containers.ContainerUtil
|
||||
import java.util.*
|
||||
|
||||
abstract class ComparisonUtilTestBase : DiffTestCase() {
|
||||
private fun doLineTest(before: Document, after: Document, matchings: Couple<BitSet>?, expected: List<Change>?, policy: ComparisonPolicy) {
|
||||
private fun doLineTest(text: Couple<Document>, matchings: Couple<BitSet>?, expected: List<Couple<IntPair>>?, policy: ComparisonPolicy) {
|
||||
val before = text.first
|
||||
val after = text.second
|
||||
val fragments = MANAGER.compareLines(before.charsSequence, after.charsSequence, policy, INDICATOR)
|
||||
checkConsistency(fragments, before, after)
|
||||
if (matchings != null) checkLineMatching(fragments, matchings)
|
||||
if (expected != null) checkLineChanges(fragments, expected)
|
||||
}
|
||||
|
||||
private fun doWordTest(before: Document, after: Document, matchings: Couple<BitSet>?, expected: List<Change>?, policy: ComparisonPolicy) {
|
||||
private fun doLineInnerTest(text: Couple<Document>, matchings: Couple<BitSet>?, expected: List<Couple<IntPair>>?, policy: ComparisonPolicy) {
|
||||
val before = text.first
|
||||
val after = text.second
|
||||
val rawFragments = MANAGER.compareLinesInner(before.charsSequence, after.charsSequence, policy, INDICATOR)
|
||||
val fragments = MANAGER.squash(rawFragments)
|
||||
checkConsistencyWord(fragments, before, after)
|
||||
checkConsistencyLineInner(fragments, before, after)
|
||||
|
||||
val diffFragments = fragments[0].innerFragments!!
|
||||
if (matchings != null) checkDiffMatching(diffFragments, matchings)
|
||||
if (expected != null) checkDiffChanges(diffFragments, expected)
|
||||
}
|
||||
|
||||
private fun doCharTest(before: Document, after: Document, matchings: Couple<BitSet>?, expected: List<Change>?, policy: ComparisonPolicy) {
|
||||
private fun doWordTest(text: Couple<Document>, matchings: Couple<BitSet>?, expected: List<Couple<IntPair>>?, policy: ComparisonPolicy) {
|
||||
val before = text.first
|
||||
val after = text.second
|
||||
val fragments = MANAGER.compareWords(before.charsSequence, after.charsSequence, policy, INDICATOR)
|
||||
checkConsistency(fragments, before, after)
|
||||
|
||||
if (matchings != null) checkDiffMatching(fragments, matchings)
|
||||
if (expected != null) checkDiffChanges(fragments, expected)
|
||||
}
|
||||
|
||||
private fun doWordTest(text: Trio<Document>, matchings: Trio<BitSet>?, expected: List<Trio<IntPair>>?, policy: ComparisonPolicy) {
|
||||
val before = text.data1
|
||||
val base = text.data2
|
||||
val after = text.data3
|
||||
val fragments = ByWord.compare(before.charsSequence, base.charsSequence, after.charsSequence, policy, INDICATOR)
|
||||
checkConsistency(fragments)
|
||||
|
||||
if (matchings != null) checkMergeMatching(fragments, matchings)
|
||||
if (expected != null) checkMergeChanges(fragments, expected)
|
||||
}
|
||||
|
||||
private fun doCharTest(text: Couple<Document>, matchings: Couple<BitSet>?, expected: List<Couple<IntPair>>?, policy: ComparisonPolicy) {
|
||||
val before = text.first
|
||||
val after = text.second
|
||||
val fragments = MANAGER.compareChars(before.charsSequence, after.charsSequence, policy, INDICATOR)
|
||||
checkConsistency(fragments, before, after)
|
||||
if (matchings != null) checkDiffMatching(fragments, matchings)
|
||||
if (expected != null) checkDiffChanges(fragments, expected)
|
||||
}
|
||||
|
||||
private fun doSplitterTest(before: Document, after: Document, squash: Boolean, trim: Boolean, expected: List<Change>?, policy: ComparisonPolicy) {
|
||||
private fun doSplitterTest(text: Couple<Document>,
|
||||
squash: Boolean,
|
||||
trim: Boolean,
|
||||
expected: List<Couple<IntPair>>?,
|
||||
policy: ComparisonPolicy) {
|
||||
val before = text.first
|
||||
val after = text.second
|
||||
val text1 = before.charsSequence
|
||||
val text2 = after.charsSequence
|
||||
|
||||
@@ -62,7 +98,7 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
|
||||
if (expected != null) checkLineChanges(fragments, expected)
|
||||
}
|
||||
|
||||
private fun checkConsistencyWord(fragments: List<LineFragment>, before: Document, after: Document) {
|
||||
private fun checkConsistencyLineInner(fragments: List<LineFragment>, before: Document, after: Document) {
|
||||
assertTrue(fragments.size == 1)
|
||||
val fragment = fragments[0]
|
||||
|
||||
@@ -102,16 +138,33 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkLineChanges(fragments: List<LineFragment>, expected: List<Change>) {
|
||||
private fun checkConsistency(fragments: List<MergeWordFragment>) {
|
||||
for (fragment in fragments) {
|
||||
assertTrue(fragment.getStartOffset(ThreeSide.LEFT) <= fragment.getEndOffset(ThreeSide.LEFT))
|
||||
assertTrue(fragment.getStartOffset(ThreeSide.BASE) <= fragment.getEndOffset(ThreeSide.BASE))
|
||||
assertTrue(fragment.getStartOffset(ThreeSide.RIGHT) <= fragment.getEndOffset(ThreeSide.RIGHT))
|
||||
|
||||
assertTrue(fragment.getStartOffset(ThreeSide.LEFT) != fragment.getEndOffset(ThreeSide.LEFT) ||
|
||||
fragment.getStartOffset(ThreeSide.BASE) != fragment.getEndOffset(ThreeSide.BASE) ||
|
||||
fragment.getStartOffset(ThreeSide.RIGHT) != fragment.getEndOffset(ThreeSide.RIGHT))
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkLineChanges(fragments: List<LineFragment>, expected: List<Couple<IntPair>>) {
|
||||
val changes = convertLineFragments(fragments)
|
||||
assertOrderedEquals(changes, expected)
|
||||
}
|
||||
|
||||
private fun checkDiffChanges(fragments: List<DiffFragment>, expected: List<Change>) {
|
||||
private fun checkDiffChanges(fragments: List<DiffFragment>, expected: List<Couple<IntPair>>) {
|
||||
val changes = convertDiffFragments(fragments)
|
||||
assertOrderedEquals(changes, expected)
|
||||
}
|
||||
|
||||
private fun checkMergeChanges(fragments: List<MergeWordFragment>, expected: List<Trio<IntPair>>) {
|
||||
val changes = convertMergeFragments(fragments)
|
||||
assertOrderedEquals(changes, expected)
|
||||
}
|
||||
|
||||
private fun checkLineMatching(fragments: List<LineFragment>, matchings: Couple<BitSet>) {
|
||||
val set1 = BitSet()
|
||||
val set2 = BitSet()
|
||||
@@ -120,8 +173,8 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
|
||||
set2.set(fragment.startLine2, fragment.endLine2)
|
||||
}
|
||||
|
||||
assertEquals(matchings.first, set1)
|
||||
assertEquals(matchings.second, set2)
|
||||
assertEquals(matchings.first, set1, "Before")
|
||||
assertEquals(matchings.second, set2, "After")
|
||||
}
|
||||
|
||||
private fun checkDiffMatching(fragments: List<DiffFragment>, matchings: Couple<BitSet>) {
|
||||
@@ -132,16 +185,39 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
|
||||
set2.set(fragment.startOffset2, fragment.endOffset2)
|
||||
}
|
||||
|
||||
assertEquals(matchings.first, set1)
|
||||
assertEquals(matchings.second, set2)
|
||||
assertEquals(matchings.first, set1, "Before")
|
||||
assertEquals(matchings.second, set2, "After")
|
||||
}
|
||||
|
||||
private fun convertDiffFragments(fragments: List<DiffFragment>): List<Change> {
|
||||
return fragments.map { Change(it.startOffset1, it.endOffset1, it.startOffset2, it.endOffset2) }
|
||||
private fun checkMergeMatching(fragments: List<MergeWordFragment>, matchings: Trio<BitSet>) {
|
||||
val set1 = BitSet()
|
||||
val set2 = BitSet()
|
||||
val set3 = BitSet()
|
||||
for (fragment in fragments) {
|
||||
set1.set(fragment.getStartOffset(ThreeSide.LEFT), fragment.getEndOffset(ThreeSide.LEFT))
|
||||
set2.set(fragment.getStartOffset(ThreeSide.BASE), fragment.getEndOffset(ThreeSide.BASE))
|
||||
set3.set(fragment.getStartOffset(ThreeSide.RIGHT), fragment.getEndOffset(ThreeSide.RIGHT))
|
||||
}
|
||||
|
||||
assertEquals(matchings.data1, set1, "Before")
|
||||
assertEquals(matchings.data2, set2, "Base")
|
||||
assertEquals(matchings.data3, set3, "After")
|
||||
}
|
||||
|
||||
private fun convertLineFragments(fragments: List<LineFragment>): List<Change> {
|
||||
return fragments.map { Change(it.startLine1, it.endLine1, it.startLine2, it.endLine2) }
|
||||
private fun convertDiffFragments(fragments: List<DiffFragment>): List<Couple<IntPair>> {
|
||||
return fragments.map { Couple(IntPair(it.startOffset1, it.endOffset1), IntPair(it.startOffset2, it.endOffset2)) }
|
||||
}
|
||||
|
||||
private fun convertLineFragments(fragments: List<LineFragment>): List<Couple<IntPair>> {
|
||||
return fragments.map { Couple(IntPair(it.startLine1, it.endLine1), IntPair(it.startLine2, it.endLine2)) }
|
||||
}
|
||||
|
||||
private fun convertMergeFragments(fragments: List<MergeWordFragment>): List<Trio<IntPair>> {
|
||||
return fragments.map {
|
||||
Trio(IntPair(it.getStartOffset(ThreeSide.LEFT), it.getEndOffset(ThreeSide.LEFT)),
|
||||
IntPair(it.getStartOffset(ThreeSide.BASE), it.getEndOffset(ThreeSide.BASE)),
|
||||
IntPair(it.getStartOffset(ThreeSide.RIGHT), it.getEndOffset(ThreeSide.RIGHT)))
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkLineOffsets(fragment: LineFragment, before: Document, after: Document) {
|
||||
@@ -168,39 +244,51 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
|
||||
// Test Builder
|
||||
//
|
||||
|
||||
private fun parseLineMatching(matching: String, document: Document): BitSet {
|
||||
assertEquals(matching.length, document.textLength)
|
||||
|
||||
val lines1 = matching.split('_', '*')
|
||||
val lines2 = document.charsSequence.split('\n')
|
||||
assertEquals(lines1.size, lines2.size)
|
||||
for (i in 0..lines1.size - 1) {
|
||||
assertEquals(lines1[i].length, lines2[i].length, "line $i")
|
||||
}
|
||||
|
||||
|
||||
val set = BitSet()
|
||||
|
||||
var index = 0
|
||||
var lineNumber = 0
|
||||
while (index < matching.length) {
|
||||
var end = matching.indexOfAny(listOf("_", "*"), index) + 1
|
||||
if (end == 0) end = matching.length
|
||||
|
||||
val line = matching.subSequence(index, end)
|
||||
if (line.find { it != ' ' && it != '_' } != null) {
|
||||
assert(!line.contains(' '))
|
||||
set.set(lineNumber)
|
||||
}
|
||||
lineNumber++
|
||||
index = end
|
||||
}
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
internal enum class TestType {
|
||||
LINE, WORD, CHAR, SPLITTER
|
||||
LINE, LINE_INNER, WORD, CHAR, SPLITTER
|
||||
}
|
||||
|
||||
internal inner class TestBuilder(private val type: TestType) {
|
||||
private var isExecuted: Boolean = false
|
||||
|
||||
private var before: Document? = null
|
||||
private var after: Document? = null
|
||||
|
||||
private var defaultChanges: List<Change>? = null
|
||||
private var trimChanges: List<Change>? = null
|
||||
private var ignoreChanges: List<Change>? = null
|
||||
|
||||
private var defaultMatching: Couple<BitSet>? = null
|
||||
private var trimMatching: Couple<BitSet>? = null
|
||||
private var ignoreMatching: Couple<BitSet>? = null
|
||||
private var text: Data<Document> = Data()
|
||||
private var changes: PolicyData<List<Data<IntPair>>> = PolicyData()
|
||||
private var matchings: PolicyData<Data<BitSet>> = PolicyData()
|
||||
|
||||
private var shouldSquash: Boolean = false
|
||||
private var shouldTrim: Boolean = false
|
||||
|
||||
private fun changes(policy: ComparisonPolicy): List<Change>? = when (policy) {
|
||||
ComparisonPolicy.IGNORE_WHITESPACES -> ignoreChanges ?: trimChanges ?: defaultChanges
|
||||
ComparisonPolicy.TRIM_WHITESPACES -> trimChanges ?: defaultChanges
|
||||
ComparisonPolicy.DEFAULT -> defaultChanges
|
||||
}
|
||||
|
||||
private fun matchings(policy: ComparisonPolicy): Couple<BitSet>? = when (policy) {
|
||||
ComparisonPolicy.IGNORE_WHITESPACES -> ignoreMatching ?: trimMatching ?: defaultMatching
|
||||
ComparisonPolicy.TRIM_WHITESPACES -> trimMatching ?: defaultMatching
|
||||
ComparisonPolicy.DEFAULT -> defaultMatching
|
||||
}
|
||||
|
||||
fun assertExecuted() {
|
||||
assertTrue(isExecuted)
|
||||
}
|
||||
@@ -209,17 +297,36 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
|
||||
try {
|
||||
isExecuted = true
|
||||
|
||||
val change = changes(policy)
|
||||
val matchings = matchings(policy)
|
||||
assertTrue(change != null || matchings != null)
|
||||
if (text.isTwoSide()) {
|
||||
val text = text.asCouple()
|
||||
val changes = changes.get(policy)?.map { it.asCouple() }
|
||||
val matchings = matchings.get(policy)?.asCouple()
|
||||
assertTrue(changes != null || matchings != null)
|
||||
|
||||
when (type) {
|
||||
TestType.LINE -> doLineTest(before!!, after!!, matchings, change, policy)
|
||||
TestType.WORD -> doWordTest(before!!, after!!, matchings, change, policy)
|
||||
TestType.CHAR -> doCharTest(before!!, after!!, matchings, change, policy)
|
||||
TestType.SPLITTER -> {
|
||||
assertNull(matchings)
|
||||
doSplitterTest(before!!, after!!, shouldSquash, shouldTrim, change, policy)
|
||||
when (type) {
|
||||
TestType.LINE -> doLineTest(text, matchings, changes, policy)
|
||||
TestType.LINE_INNER -> {
|
||||
doLineInnerTest(text, matchings, changes, policy)
|
||||
doWordTest(text, matchings, changes, policy)
|
||||
}
|
||||
TestType.WORD -> doWordTest(text, matchings, changes, policy)
|
||||
TestType.CHAR -> doCharTest(text, matchings, changes, policy)
|
||||
TestType.SPLITTER -> {
|
||||
assertNull(matchings)
|
||||
doSplitterTest(text, shouldSquash, shouldTrim, changes, policy)
|
||||
}
|
||||
else -> assert(false)
|
||||
}
|
||||
}
|
||||
else {
|
||||
val text = text.asTrio()
|
||||
val changes = changes.get(policy)?.map { it.asTrio() }
|
||||
val matchings = matchings.get(policy)?.asTrio()
|
||||
assertTrue(changes != null || matchings != null)
|
||||
|
||||
when (type) {
|
||||
TestType.WORD -> doWordTest(text, matchings, changes, policy)
|
||||
else -> assert(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,102 +361,84 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
|
||||
return Helper(this, v)
|
||||
}
|
||||
|
||||
inner class Helper(val before: String, val after: String) {
|
||||
operator fun Helper.minus(v: String): Helper {
|
||||
return Helper(before, v, after)
|
||||
}
|
||||
|
||||
inner class Helper(val before: String, val after: String, val base: String? = null) {
|
||||
init {
|
||||
val builder = this@TestBuilder
|
||||
if (builder.before == null && builder.after == null) {
|
||||
builder.before = DocumentImpl(parseSource(before))
|
||||
builder.after = DocumentImpl(parseSource(after))
|
||||
if (builder.text.before == null && builder.text.after == null ||
|
||||
base != null && builder.text.base == null) {
|
||||
builder.text.before = DocumentImpl(parseSource(before))
|
||||
builder.text.after = DocumentImpl(parseSource(after))
|
||||
if (base != null) builder.text.base = DocumentImpl(parseSource(base))
|
||||
}
|
||||
}
|
||||
|
||||
fun plainSource() {
|
||||
val builder = this@TestBuilder
|
||||
builder.before = DocumentImpl(before)
|
||||
builder.after = DocumentImpl(after)
|
||||
builder.text.before = DocumentImpl(before)
|
||||
builder.text.after = DocumentImpl(after)
|
||||
if (base != null) {
|
||||
builder.text.base = DocumentImpl(base)
|
||||
}
|
||||
}
|
||||
|
||||
fun default() {
|
||||
defaultMatching = parseMatching(before, after)
|
||||
matchings.default = parseMatching(before, after, base)
|
||||
}
|
||||
|
||||
fun trim() {
|
||||
trimMatching = parseMatching(before, after)
|
||||
matchings.trim = parseMatching(before, after, base)
|
||||
}
|
||||
|
||||
fun ignore() {
|
||||
ignoreMatching = parseMatching(before, after)
|
||||
matchings.ignore = parseMatching(before, after, base)
|
||||
}
|
||||
|
||||
private fun parseMatching(before: String, after: String): Couple<BitSet> {
|
||||
private fun parseMatching(before: String, after: String, base: String?): Data<BitSet> {
|
||||
if (type == TestType.LINE) {
|
||||
val builder = this@TestBuilder
|
||||
return Couple.of(parseLineMatching(before, builder.before!!), parseLineMatching(after, builder.after!!))
|
||||
return Data(parseLineMatching(before, builder.text.before!!),
|
||||
if (base != null) parseLineMatching(base, builder.text.base!!) else null,
|
||||
parseLineMatching(after, builder.text.after!!))
|
||||
}
|
||||
else {
|
||||
return Couple.of(parseMatching(before), parseMatching(after))
|
||||
return Data(parseMatching(before),
|
||||
if (base != null) parseMatching(base) else null,
|
||||
parseMatching(after))
|
||||
}
|
||||
}
|
||||
|
||||
fun parseLineMatching(matching: String, document: Document): BitSet {
|
||||
assertEquals(matching.length, document.textLength)
|
||||
|
||||
val lines1 = matching.split('_', '*')
|
||||
val lines2 = document.charsSequence.split('\n')
|
||||
assertEquals(lines1.size, lines2.size)
|
||||
for (i in 0..lines1.size - 1) {
|
||||
assertEquals(lines1[i].length, lines2[i].length, "line $i")
|
||||
}
|
||||
|
||||
|
||||
val set = BitSet()
|
||||
|
||||
var index = 0
|
||||
var lineNumber = 0
|
||||
while (index < matching.length) {
|
||||
var end = matching.indexOfAny(listOf("_", "*"), index) + 1
|
||||
if (end == 0) end = matching.length
|
||||
|
||||
val line = matching.subSequence(index, end)
|
||||
if (line.find { it != ' ' && it != '_' } != null) {
|
||||
assert(!line.contains(' '))
|
||||
set.set(lineNumber)
|
||||
}
|
||||
lineNumber++
|
||||
index = end
|
||||
}
|
||||
|
||||
return set
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun default(vararg expected: Change): Unit {
|
||||
defaultChanges = ContainerUtil.list(*expected)
|
||||
fun default(vararg expected: Couple<IntPair>): Unit {
|
||||
changes.default = ContainerUtil.list(*expected).map { Data(it.first, it.second) }
|
||||
}
|
||||
|
||||
fun trim(vararg expected: Change): Unit {
|
||||
trimChanges = ContainerUtil.list(*expected)
|
||||
fun trim(vararg expected: Couple<IntPair>): Unit {
|
||||
changes.trim = ContainerUtil.list(*expected).map { Data(it.first, it.second) }
|
||||
}
|
||||
|
||||
fun ignore(vararg expected: Change): Unit {
|
||||
ignoreChanges = ContainerUtil.list(*expected)
|
||||
fun ignore(vararg expected: Couple<IntPair>): Unit {
|
||||
changes.ignore = ContainerUtil.list(*expected).map { Data(it.first, it.second) }
|
||||
}
|
||||
|
||||
fun mod(line1: Int, line2: Int, count1: Int, count2: Int): Change {
|
||||
fun mod(line1: Int, line2: Int, count1: Int, count2: Int): Couple<IntPair> {
|
||||
assert(count1 != 0)
|
||||
assert(count2 != 0)
|
||||
return Change(line1, line1 + count1, line2, line2 + count2)
|
||||
return Couple(IntPair(line1, line1 + count1), IntPair(line2, line2 + count2))
|
||||
}
|
||||
|
||||
fun del(line1: Int, line2: Int, count1: Int): Change {
|
||||
fun del(line1: Int, line2: Int, count1: Int): Couple<IntPair> {
|
||||
assert(count1 != 0)
|
||||
return Change(line1, line1 + count1, line2, line2)
|
||||
return Couple(IntPair(line1, line1 + count1), IntPair(line2, line2))
|
||||
}
|
||||
|
||||
fun ins(line1: Int, line2: Int, count2: Int): Change {
|
||||
fun ins(line1: Int, line2: Int, count2: Int): Couple<IntPair> {
|
||||
assert(count2 != 0)
|
||||
return Change(line1, line1, line2, line2 + count2)
|
||||
return Couple(IntPair(line1, line1), IntPair(line2, line2 + count2))
|
||||
}
|
||||
|
||||
|
||||
@@ -361,6 +450,8 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
|
||||
|
||||
internal fun lines(f: TestBuilder.() -> Unit): Unit = doTest(TestType.LINE, f)
|
||||
|
||||
internal fun lines_inner(f: TestBuilder.() -> Unit): Unit = doTest(TestType.LINE_INNER, f)
|
||||
|
||||
internal fun words(f: TestBuilder.() -> Unit): Unit = doTest(TestType.WORD, f)
|
||||
|
||||
internal fun chars(f: TestBuilder.() -> Unit): Unit = doTest(TestType.CHAR, f)
|
||||
@@ -382,9 +473,28 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
|
||||
// Helpers
|
||||
//
|
||||
|
||||
data class Change(val start1: Int, val end1: Int, val start2: Int, val end2: Int) {
|
||||
override fun toString(): String {
|
||||
return "($start1, $end1) - ($start2, $end2)"
|
||||
private data class Data<T>(var before: T?, var base: T?, var after: T?) {
|
||||
constructor() : this(null, null, null)
|
||||
constructor(before: T?, after : T?) : this(before, null, after)
|
||||
fun isTwoSide(): Boolean = before != null && after != null && base == null
|
||||
fun isThreeSide(): Boolean = before != null && after != null && base != null
|
||||
fun asCouple(): Couple<T> {
|
||||
assert(isTwoSide())
|
||||
return Couple(before!!, after!!)
|
||||
}
|
||||
|
||||
fun asTrio(): Trio<T> {
|
||||
assert(isThreeSide())
|
||||
return Trio(before!!, base!!, after!!)
|
||||
}
|
||||
}
|
||||
|
||||
private data class PolicyData<T>(var default: T? = null, var trim: T? = null, var ignore: T? = null) {
|
||||
fun get(policy: ComparisonPolicy): T? =
|
||||
when (policy) {
|
||||
ComparisonPolicy.IGNORE_WHITESPACES -> ignore ?: trim ?: default
|
||||
ComparisonPolicy.TRIM_WHITESPACES -> trim ?: default
|
||||
ComparisonPolicy.DEFAULT -> default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,25 +187,31 @@ class MergeResolveUtilTest : DiffTestCase() {
|
||||
)
|
||||
}
|
||||
|
||||
fun testRegressions() {
|
||||
test(
|
||||
"i\n",
|
||||
"i",
|
||||
"\ni",
|
||||
"i\n",
|
||||
"i"
|
||||
)
|
||||
}
|
||||
|
||||
private fun testGreedy(base: String, left: String, right: String, expected: String?) {
|
||||
test(base, left, right, expected, true);
|
||||
test(base, left, right, expected, true)
|
||||
}
|
||||
|
||||
private fun test(base: String, left: String, right: String, expected: String?, isGreedy: Boolean = false) {
|
||||
val simpleResult = MergeResolveUtil.tryResolve(left, base, right)
|
||||
val magicResult = MergeResolveUtil.tryGreedyResolve(left, base, right);
|
||||
val expectedSimple = if (isGreedy) null else expected
|
||||
val expectedGreedy = expected
|
||||
test(base, left, right, expectedSimple, expectedGreedy)
|
||||
}
|
||||
|
||||
if (expected == null) {
|
||||
assertNull(simpleResult)
|
||||
assertNull(magicResult)
|
||||
}
|
||||
else if (isGreedy) {
|
||||
assertNull(simpleResult)
|
||||
assertEquals(expected, magicResult)
|
||||
}
|
||||
else {
|
||||
assertEquals(expected, simpleResult)
|
||||
assertEquals(expected, magicResult)
|
||||
}
|
||||
private fun test(base: String, left: String, right: String, expectedSimple: String?, expectedGreedy: String?) {
|
||||
val simpleResult = MergeResolveUtil.tryResolve(left, base, right)
|
||||
val greedyResult = MergeResolveUtil.tryGreedyResolve(left, base, right)
|
||||
|
||||
assertEquals(expectedSimple, simpleResult, "Simple")
|
||||
assertEquals(expectedGreedy, greedyResult, "Greedy")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,72 +17,72 @@ package com.intellij.diff.comparison
|
||||
|
||||
class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
fun testSimpleCases() {
|
||||
words {
|
||||
lines_inner {
|
||||
("x z" - "y z")
|
||||
("- " - "- ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x z" - "y z")
|
||||
("- " - "- ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
(" x z" - "y z")
|
||||
("-- " - "- ").default()
|
||||
(" - " - "- ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x z " - "y z")
|
||||
("- -" - "- ").default()
|
||||
("- " - "- ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x z " - "y z")
|
||||
("- -" - "- ").default()
|
||||
("- " - "- ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x z" - " y z ")
|
||||
("- " - "-- -").default()
|
||||
("- " - " - ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x y" - "x z ")
|
||||
(" -" - " --").default()
|
||||
(" -" - " - ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x,y" - "x")
|
||||
(" --" - " ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x,y" - "y")
|
||||
("-- " - " ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
(".x=" - ".!=")
|
||||
(" - " - " - ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("X xyz1 Z" - "X xyz2 Z")
|
||||
(" ---- " - " ---- ").default()
|
||||
testAll()
|
||||
@@ -90,52 +90,52 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
}
|
||||
|
||||
fun testPunctuation() {
|
||||
words {
|
||||
lines_inner {
|
||||
(" x.z.x " - "x..x")
|
||||
("- - -" - " ").default()
|
||||
(" - " - " ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x..x" - " x.z.x ")
|
||||
(" " - "- - -").default()
|
||||
(" " - " - ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x ... z" - "y ... z")
|
||||
("- " - "- ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x ... z" - "x ... y")
|
||||
(" -" - " -").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x ,... z" - "x ... y")
|
||||
(" - -" - " -").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x . , .. z" - "x ... y")
|
||||
(" --- -" - " -").default()
|
||||
(" - -" - " -").ignore()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x==y==z" - "x====z")
|
||||
(" - " - " ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x====z" - "x==t==z")
|
||||
(" " - " - ").default()
|
||||
testAll()
|
||||
@@ -143,13 +143,13 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
}
|
||||
|
||||
fun testOldDiffBug() {
|
||||
words {
|
||||
lines_inner {
|
||||
("x'y'>" - "x'>")
|
||||
(" -- " - " ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x'>" - "x'y'>")
|
||||
(" " - " -- ").default()
|
||||
testAll()
|
||||
@@ -157,14 +157,14 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
}
|
||||
|
||||
fun testWhitespaceOnlyChanges() {
|
||||
words {
|
||||
lines_inner {
|
||||
("x =z" - "x= z")
|
||||
(" -- " - " -- ").default()
|
||||
testDefault()
|
||||
testTrim()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x =" - "x= z")
|
||||
(" -- " - " ---").default()
|
||||
(" " - " -").ignore()
|
||||
@@ -173,7 +173,7 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
}
|
||||
|
||||
fun testNewlines() {
|
||||
words {
|
||||
lines_inner {
|
||||
(" x _ y _ z " - "x z")
|
||||
("- ------ -" - " ").default()
|
||||
(" - " - " ").trim()
|
||||
@@ -181,17 +181,48 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x z" - " x _ y _ z ")
|
||||
(" " - "- ------ -").default()
|
||||
(" " - " - ").trim()
|
||||
(" " - " - ").ignore()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
("_i" - "i_")
|
||||
("- " - " -").default()
|
||||
(" " - " ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
("i_" - "_i")
|
||||
("- " - " -").default() // TODO
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
("x_y" - "xy")
|
||||
(" " - " ").ignore()
|
||||
testIgnore()
|
||||
}
|
||||
|
||||
words {
|
||||
("A x_y B" - "a xy b")
|
||||
("-------" - "------").ignore()
|
||||
testIgnore()
|
||||
}
|
||||
|
||||
words {
|
||||
("A xy B" - "a xy b")
|
||||
("- -" - "- -").ignore()
|
||||
testIgnore()
|
||||
}
|
||||
}
|
||||
|
||||
fun testFixedBugs() {
|
||||
words {
|
||||
lines_inner {
|
||||
(".! " - ". y!")
|
||||
(" -" - " --- ").default()
|
||||
(" " - " --- ").trim()
|
||||
@@ -199,7 +230,7 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
(" x n" - " y_ x m")
|
||||
(" -" - "---- -").default()
|
||||
(" -" - " - -").trim()
|
||||
@@ -207,7 +238,7 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x_" - "x! ")
|
||||
(" -" - " ---").default()
|
||||
(" " - " - ").trim()
|
||||
@@ -217,35 +248,35 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
}
|
||||
|
||||
fun testInnerWhitespaces() {
|
||||
words {
|
||||
lines_inner {
|
||||
("<< x >>" - "<.<>.>")
|
||||
(" --- " - " - - ").default()
|
||||
(" - " - " - - ").ignore()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("<< x >>" - "y<<x>>y")
|
||||
(" - - " - "- -").default()
|
||||
(" " - "- -").ignore()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x .. z" - "x y .. z")
|
||||
(" " - " -- ").default() // TODO: looks wrong
|
||||
(" " - " -- ").default()
|
||||
(" " - " - ").ignore()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
(" x..z" - "x..y ")
|
||||
("-- -" - " ---").default()
|
||||
(" -" - " - ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
(" x y x _ x z x " - "x x_x x")
|
||||
("- -- - - -- -" - " ").default()
|
||||
(" -- -- " - " ").trim()
|
||||
@@ -256,28 +287,28 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
|
||||
fun testAlgorithmSpecific() {
|
||||
// prefer words over punctuation
|
||||
words {
|
||||
lines_inner {
|
||||
("...x" - "x...")
|
||||
("--- " - " ---").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
// prefer longer words sequences
|
||||
words {
|
||||
lines_inner {
|
||||
("x x y" - "x y")
|
||||
("-- " - " ").default()
|
||||
("- " - " ").ignore()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("y x x" - "y x")
|
||||
(" --" - " ").default()
|
||||
(" -" - " ").ignore()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("A X A B" - "A B")
|
||||
("---- " - " ").default()
|
||||
("--- " - " ").ignore()
|
||||
@@ -285,14 +316,14 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
}
|
||||
|
||||
// prefer less modified 'sentences'
|
||||
words {
|
||||
lines_inner {
|
||||
("A.X A.Z" - "A.X A.Y A.Z")
|
||||
(" " - " ---- ").default()
|
||||
(" " - " --- ").ignore()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("X.A Z.A" - "X.A Y.A Z.A")
|
||||
(" " - " ---- ").default()
|
||||
(" " - " --- ").ignore()
|
||||
@@ -300,7 +331,7 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
}
|
||||
|
||||
// prefer punctuation over whitespaces
|
||||
words {
|
||||
lines_inner {
|
||||
(". " - " .")
|
||||
(" ---" - "--- ").default()
|
||||
testDefault()
|
||||
@@ -308,26 +339,26 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
}
|
||||
|
||||
fun `test legacy cases from ByWordTest`() {
|
||||
words {
|
||||
lines_inner {
|
||||
("abc def, 123" - "ab def, 12")
|
||||
("--- ---" - "-- --").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
(" a[xy]+1" - ",a[]+1")
|
||||
("- -- " - "- ").default()
|
||||
(" -- " - "- ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("0987_ a.g();_" - "yyyy_")
|
||||
("------------- " - "---- ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
(" abc_2222_" - " x = abc_zzzz_")
|
||||
//(" ---- " - "-- ---- ---- ").legacy()
|
||||
(" ---- " - " ------ ---- ").default()
|
||||
@@ -335,7 +366,7 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
testAll()
|
||||
}
|
||||
|
||||
words { // Idea58505
|
||||
lines_inner { // Idea58505
|
||||
(" if (eventMerger!=null && !dataSelection.getValueIsAdjusting()) {" -
|
||||
" if (eventMerger!=null && (dataSelection==null || !dataSelection.getValueIsAdjusting())) {")
|
||||
//(" - " -
|
||||
@@ -347,7 +378,7 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
testAll()
|
||||
}
|
||||
|
||||
words { // Idea56428
|
||||
lines_inner { // Idea56428
|
||||
("messageInsertStatement = connection.prepareStatement(\"INSERT INTO AUDIT (AUDIT_TYPE_ID, STATUS, SERVER_ID, INSTANCE_ID, REQUEST_ID) VALUES (?, ?, ?, ?, ?)\");" -
|
||||
"messageInsertStatement = connection.prepareStatement(\"INSERT INTO AUDIT (AUDIT_TYPE_ID, CREATION_TIMESTAMP, STATUS, SERVER_ID, INSTANCE_ID, REQUEST_ID) VALUES (?, ?, ?, ?, ?, ?)\");").plainSource()
|
||||
//(" . . " -
|
||||
@@ -359,14 +390,14 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("f(a, b);" - "f(a,_ b);")
|
||||
(" " - " -- ").default()
|
||||
(" " - " ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
(" o.f(a)" - "o. f( b)")
|
||||
("- - " - " - -- ").default()
|
||||
(" - " - " - -- ").trim()
|
||||
@@ -374,7 +405,7 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
(" 123 " - "xyz")
|
||||
(" --- " - "---").trim()
|
||||
testTrim()
|
||||
@@ -382,14 +413,14 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
}
|
||||
|
||||
fun testEmptyRangePositions() {
|
||||
words {
|
||||
lines_inner {
|
||||
("x? y" - "x y")
|
||||
(" - " - " ").default()
|
||||
default(del(1, 1, 1))
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
lines_inner {
|
||||
("x ?y" - "x y")
|
||||
(" - " - " ").default()
|
||||
default(del(2, 2, 1))
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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
|
||||
|
||||
class WordMergeComparisonUtilTest : ComparisonUtilTestBase() {
|
||||
fun testSimple() {
|
||||
words {
|
||||
("" - "" - "")
|
||||
("" - "" - "").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
("" - "X" - "")
|
||||
("" - "-" - "").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
("X" - "" - "")
|
||||
("-" - "" - "").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
("a b" - "a b" - "a b")
|
||||
(" " - " " - " ").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
("A b c" - "a b c" - "a b C")
|
||||
("- -" - "- -" - "- -").default()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
("a c" - "a c" - "a X c")
|
||||
(" " - " " - " -- ").default()
|
||||
(" " - " " - " - ").ignore()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
("a X c" - "a X c" - "a c")
|
||||
(" -- " - " -- " - " ").default()
|
||||
(" - " - " - " - " ").ignore()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
("a X c" - "a c" - "a Y c")
|
||||
(" -- " - " " - " -- ").default()
|
||||
(" - " - " " - " - ").ignore()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
("a c" - "a X c" - "a Y c")
|
||||
(" " - " -- " - " -- ").default()
|
||||
(" " - " - " - " - ").ignore()
|
||||
testAll()
|
||||
}
|
||||
}
|
||||
|
||||
fun testNewlines() {
|
||||
words {
|
||||
("i" - "i_" - "_i")
|
||||
("-" - "--" - "--").default() // TODO
|
||||
(" " - " " - " ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
("_i" - "i_" - "i")
|
||||
("--" - "--" - "-").default()
|
||||
(" " - " " - " ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
("i" - "_i" - "i_")
|
||||
(" " - "- " - " -").default()
|
||||
(" " - " " - " ").trim()
|
||||
testAll()
|
||||
}
|
||||
|
||||
words {
|
||||
("_i" - "i" - "i_")
|
||||
("- " - " " - " -").default()
|
||||
(" " - " " - " ").trim()
|
||||
testAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ class MergeAutoTest : MergeTestBase() {
|
||||
private fun doUndoTest(seed: Long, runs: Int, maxLength: Int) {
|
||||
doTest(seed, runs, maxLength) { text1, text2, text3, debugData ->
|
||||
testN(text1, text2, text3) {
|
||||
if (changes.size == 0) {
|
||||
if (changes.isEmpty()) {
|
||||
assertEquals(text1, text2)
|
||||
assertEquals(text1, text3)
|
||||
assertEquals(text2, text3)
|
||||
|
||||
@@ -99,7 +99,7 @@ abstract class MergeTestBase : DiffTestCase() {
|
||||
val editor: EditorEx = viewer.editor
|
||||
val document: Document = editor.document
|
||||
|
||||
private val textEditor = TextEditorProvider.getInstance().getTextEditor(editor);
|
||||
private val textEditor = TextEditorProvider.getInstance().getTextEditor(editor)
|
||||
private val undoManager = UndoManager.getInstance(project!!)
|
||||
|
||||
fun change(num: Int): TextMergeChange {
|
||||
@@ -114,7 +114,7 @@ abstract class MergeTestBase : DiffTestCase() {
|
||||
//
|
||||
|
||||
fun runActionByTitle(name: String): Boolean {
|
||||
val action = actions.filter { name.equals(it.templatePresentation.text) }
|
||||
val action = actions.filter { name == it.templatePresentation.text }
|
||||
assertTrue(action.size == 1, action.toString())
|
||||
return runAction(action[0])
|
||||
}
|
||||
@@ -396,7 +396,7 @@ abstract class MergeTestBase : DiffTestCase() {
|
||||
if (other !is ViewerState) return false
|
||||
|
||||
if (!StringUtil.equals(content, other.content)) return false
|
||||
if (!changes.equals(other.changes)) return false
|
||||
if (changes != other.changes) return false
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -411,9 +411,9 @@ abstract class MergeTestBase : DiffTestCase() {
|
||||
if (other !is ChangeState) return false
|
||||
|
||||
if (!StringUtil.equals(content, other.content)) return false
|
||||
if (!starts.equals(other.starts)) return false
|
||||
if (!ends.equals(other.ends)) return false
|
||||
if (!resolved.equals(other.resolved)) return false
|
||||
if (starts != other.starts) return false
|
||||
if (ends != other.ends) return false
|
||||
if (resolved != other.resolved) return false
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -175,6 +175,7 @@ class LineNumberConvertorCorrectorTest : UsefulTestCase() {
|
||||
assertEquals(minimumMatched2, counter2)
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun printMatchings() {
|
||||
for (i in 0..length * 2 - 1) {
|
||||
val value = convertor.convert1(i)
|
||||
|
||||
+2
-2
@@ -34,8 +34,8 @@ class UnifiedFragmentBuilderAutoTest : DiffTestCase() {
|
||||
doAutoTest(seed, runs) { debugData ->
|
||||
debugData.put("MaxLength", maxLength)
|
||||
|
||||
var text1 = DocumentImpl(generateText(maxLength))
|
||||
var text2 = DocumentImpl(generateText(maxLength))
|
||||
val text1 = DocumentImpl(generateText(maxLength))
|
||||
val text2 = DocumentImpl(generateText(maxLength))
|
||||
|
||||
debugData.put("Text1", textToReadableFormat(text1.charsSequence))
|
||||
debugData.put("Text2", textToReadableFormat(text2.charsSequence))
|
||||
|
||||
+25
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 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.
|
||||
@@ -95,6 +95,30 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority
|
||||
@NotNull String presentationText,
|
||||
@NotNull List<ProblemDescriptor> descriptions,
|
||||
@Nullable Class quickfixClass) {
|
||||
sortDescriptions(descriptions);
|
||||
return applyFixesNoSort(project, presentationText, descriptions, quickfixClass);
|
||||
}
|
||||
|
||||
public static AbstractPerformFixesTask applyFixesNoSort(@NotNull Project project,
|
||||
@NotNull String presentationText,
|
||||
@NotNull List<ProblemDescriptor> descriptions,
|
||||
@Nullable Class quickfixClass) {
|
||||
final SequentialModalProgressTask progressTask =
|
||||
new SequentialModalProgressTask(project, presentationText, true);
|
||||
final boolean isBatch = quickfixClass != null && BatchQuickFix.class.isAssignableFrom(quickfixClass);
|
||||
final AbstractPerformFixesTask fixesTask = isBatch ?
|
||||
new PerformBatchFixesTask(project, descriptions.toArray(ProblemDescriptor.EMPTY_ARRAY), progressTask, quickfixClass) :
|
||||
new PerformFixesTask(project, descriptions.toArray(ProblemDescriptor.EMPTY_ARRAY), progressTask, quickfixClass);
|
||||
CommandProcessor.getInstance().executeCommand(project, () -> {
|
||||
CommandProcessor.getInstance().markCurrentCommandAsGlobal(project);
|
||||
progressTask.setMinIterationTime(200);
|
||||
progressTask.setTask(fixesTask);
|
||||
ProgressManager.getInstance().run(progressTask);
|
||||
}, presentationText, null);
|
||||
return fixesTask;
|
||||
}
|
||||
|
||||
public static void sortDescriptions(@NotNull List<ProblemDescriptor> descriptions) {
|
||||
Collections.sort(descriptions, (o1, o2) -> {
|
||||
final ProblemDescriptorBase d1 = (ProblemDescriptorBase)o1;
|
||||
final ProblemDescriptorBase d2 = (ProblemDescriptorBase)o2;
|
||||
@@ -104,20 +128,6 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority
|
||||
}
|
||||
return -elementsDiff;
|
||||
});
|
||||
|
||||
final SequentialModalProgressTask progressTask =
|
||||
new SequentialModalProgressTask(project, presentationText, true);
|
||||
final boolean isBatch = quickfixClass != null && BatchQuickFix.class.isAssignableFrom(quickfixClass);
|
||||
final AbstractPerformFixesTask fixesTask = isBatch ?
|
||||
new PerformBatchFixesTask(project, descriptions.toArray(ProblemDescriptor.EMPTY_ARRAY), progressTask, quickfixClass) :
|
||||
new PerformFixesTask(project, descriptions.toArray(ProblemDescriptor.EMPTY_ARRAY), progressTask, quickfixClass);
|
||||
CommandProcessor.getInstance().executeCommand(project, () -> {
|
||||
CommandProcessor.getInstance().markCurrentCommandAsGlobal(project);
|
||||
progressTask.setMinIterationTime(200);
|
||||
progressTask.setTask(fixesTask);
|
||||
ProgressManager.getInstance().run(progressTask);
|
||||
}, presentationText, null);
|
||||
return fixesTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-1
@@ -938,6 +938,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
}
|
||||
}
|
||||
if (!localDescriptors.isEmpty()) {
|
||||
CleanupInspectionIntention.sortDescriptions(localDescriptors);
|
||||
descriptors.addAll(localDescriptors);
|
||||
files.add(file);
|
||||
}
|
||||
@@ -962,7 +963,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
|
||||
}
|
||||
Runnable runnable = () -> {
|
||||
if (!FileModificationService.getInstance().preparePsiElementsForWrite(files)) return;
|
||||
CleanupInspectionIntention.applyFixes(getProject(), "Code Cleanup", descriptors, null);
|
||||
CleanupInspectionIntention.applyFixesNoSort(getProject(), "Code Cleanup", descriptors, null);
|
||||
};
|
||||
TransactionGuard.submitTransaction(getProject(), runnable);
|
||||
}
|
||||
|
||||
@@ -326,6 +326,12 @@ public final class LanguageConsoleBuilder {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scrollToEnd() {
|
||||
getComponent().validate();
|
||||
super.scrollToEnd();
|
||||
}
|
||||
|
||||
private final class GutterUpdateScheduler extends DocumentAdapter implements DocumentBulkUpdateListener {
|
||||
private final ConsoleGutterComponent lineStartGutter;
|
||||
private final ConsoleGutterComponent lineEndGutter;
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import static com.intellij.formatting.Indent.Type.CONTINUATION;
|
||||
import static com.intellij.formatting.Indent.Type.NORMAL;
|
||||
|
||||
class IndentCalculator {
|
||||
public class IndentCalculator {
|
||||
|
||||
private @NotNull final Project myProject;
|
||||
private @NotNull final Editor myEditor;
|
||||
|
||||
@@ -39,7 +39,6 @@ import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
|
||||
import com.intellij.openapi.project.*;
|
||||
import com.intellij.openapi.roots.*;
|
||||
import com.intellij.openapi.roots.impl.PushedFilePropertiesUpdaterImpl;
|
||||
@@ -2003,11 +2002,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
private void processFilesInReadActionWithYieldingToWriteAction() {
|
||||
try {
|
||||
while (myVfsEventsMerger.hasChanges()) {
|
||||
boolean result = ProgressIndicatorUtils
|
||||
.runInReadActionWithWriteActionPriority(this::processFilesInReadAction, null);
|
||||
if (!result) {
|
||||
ProgressIndicatorUtils.yieldToPendingWriteActions();
|
||||
}
|
||||
ProgressManager.getInstance().runInReadActionWithWriteActionPriority(this::processFilesInReadAction);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
||||
@@ -23,7 +23,7 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Created by Maxim.Mossienko on 11/10/2016.
|
||||
* @author Maxim.Mossienko on 11/10/2016.
|
||||
*/
|
||||
public class VfsEventsMerger {
|
||||
public void recordFileEvent(int fileId, VirtualFile file, boolean contentChange) {
|
||||
@@ -35,19 +35,10 @@ public class VfsEventsMerger {
|
||||
}
|
||||
|
||||
private void updateChange(int fileId, VirtualFile file, short mask) {
|
||||
ChangeInfo newChangeInfo = new ChangeInfo(file, mask, null);
|
||||
ChangeInfo existingChangeInfo = myChangeInfos.cacheOrGet(fileId, newChangeInfo);
|
||||
|
||||
if (existingChangeInfo != newChangeInfo) {
|
||||
while (true) {
|
||||
newChangeInfo = new ChangeInfo(file, mask, existingChangeInfo);
|
||||
if (existingChangeInfo == null) {
|
||||
existingChangeInfo = myChangeInfos.cacheOrGet(fileId, newChangeInfo);
|
||||
} else {
|
||||
if (myChangeInfos.replace(fileId, existingChangeInfo, newChangeInfo)) break;
|
||||
existingChangeInfo = myChangeInfos.get(fileId);
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
ChangeInfo existingChangeInfo = myChangeInfos.get(fileId);
|
||||
ChangeInfo newChangeInfo = new ChangeInfo(file, mask, existingChangeInfo);
|
||||
if(myChangeInfos.put(fileId, newChangeInfo) == existingChangeInfo) break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +50,7 @@ public class VfsEventsMerger {
|
||||
// 2. Method processes snapshot of available events at the time of the invokation, it does mean that if events are produced concurrently
|
||||
// with the processing then set of events will be not empty
|
||||
// 3. Method regularly checks for cancellations (thus can finish with PCEs) but event processor should process the change info atomically
|
||||
// (without PCE)
|
||||
public boolean processChanges(VfsEventProcessor eventProcessor) {
|
||||
if (!myChangeInfos.isEmpty()) {
|
||||
int[] fileIds = myChangeInfos.keys(); // snapshot of the keys
|
||||
@@ -148,5 +140,4 @@ public class VfsEventsMerger {
|
||||
return fileId;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-3
@@ -86,6 +86,7 @@ class ReadMostlyRWLock {
|
||||
boolean isReadLockedByThisThread() {
|
||||
checkReadThreadAccess();
|
||||
Reader status = R.get();
|
||||
throwIfImpatient(status);
|
||||
return status.readRequested;
|
||||
}
|
||||
|
||||
@@ -107,9 +108,7 @@ class ReadMostlyRWLock {
|
||||
if (iteration > SPIN_TO_WAIT_FOR_LOCK) {
|
||||
status.blocked = true;
|
||||
try {
|
||||
if (status.impatientReads) {
|
||||
throw new ApplicationUtil.CannotRunReadActionException();
|
||||
}
|
||||
throwIfImpatient(status);
|
||||
LockSupport.parkNanos(this, 1000000); // unparked by writeUnlock
|
||||
}
|
||||
finally {
|
||||
@@ -121,6 +120,13 @@ class ReadMostlyRWLock {
|
||||
}
|
||||
}
|
||||
|
||||
private void throwIfImpatient(Reader status) {
|
||||
// when client explicitly runs in non-cancelable block do not throw from within nested read actions
|
||||
if (status.impatientReads && writeRequested && !ProgressManager.getInstance().isInNonCancelableSection()) {
|
||||
throw new ApplicationUtil.CannotRunReadActionException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a {@code runnable} in an "impatient" mode.
|
||||
* In this mode any attempt to grab read lock
|
||||
|
||||
@@ -163,7 +163,7 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap
|
||||
runStartupActivity();
|
||||
}
|
||||
else {
|
||||
myStartupManager.registerStartupActivity(() -> runStartupActivity());
|
||||
myStartupManager.registerStartupActivity(this::runStartupActivity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,7 +591,7 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap
|
||||
if (refs.size() <= FREE_QUEUES_LIMIT) return;
|
||||
|
||||
DocumentReference[] backSorted = refs.toArray(new DocumentReference[refs.size()]);
|
||||
Arrays.sort(backSorted, (a, b) -> getLastCommandTimestamp(a) - getLastCommandTimestamp(b));
|
||||
Arrays.sort(backSorted, Comparator.comparingInt(this::getLastCommandTimestamp));
|
||||
|
||||
for (int i = 0; i < backSorted.length - FREE_QUEUES_LIMIT; i++) {
|
||||
DocumentReference each = backSorted[i];
|
||||
@@ -634,7 +634,7 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap
|
||||
@TestOnly
|
||||
public void dropHistoryInTests() {
|
||||
flushMergers();
|
||||
LOG.assertTrue(myCommandLevel == 0);
|
||||
LOG.assertTrue(myCommandLevel == 0, myCommandLevel);
|
||||
|
||||
myUndoStacksHolder.clearAllStacksInTests();
|
||||
myRedoStacksHolder.clearAllStacksInTests();
|
||||
@@ -643,8 +643,7 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap
|
||||
@TestOnly
|
||||
private void flushMergers() {
|
||||
// Run dummy command in order to flush all mergers...
|
||||
CommandProcessor.getInstance()
|
||||
.executeCommand(myProject, EmptyRunnable.getInstance(), CommonBundle.message("drop.undo.history.command.name"), null);
|
||||
CommandProcessor.getInstance().executeCommand(myProject, EmptyRunnable.getInstance(), CommonBundle.message("drop.undo.history.command.name"), null);
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
|
||||
+1
-2
@@ -2,7 +2,7 @@
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.openapi.updateSettings.impl.PluginUpdateInfoDialog.PluginUpdateInfoPanel">
|
||||
<grid id="18751" binding="myPanel" layout-manager="GridBagLayout">
|
||||
<constraints>
|
||||
<xy x="63" y="44" width="604" height="510"/>
|
||||
<xy x="63" y="44" width="604" height="522"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
@@ -13,7 +13,6 @@
|
||||
<gridbag weightx="1.0" weighty="0.0"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<preferredSize width="268" height="30"/>
|
||||
<text resource-bundle="messages/IdeBundle" key="updates.plugins.ready.header"/>
|
||||
</properties>
|
||||
</component>
|
||||
|
||||
@@ -21,4 +21,5 @@ public class SSHUtil {
|
||||
public static final Pattern PASSPHRASE_PROMPT = Pattern.compile("Enter passphrase for key \\'(.*)\\':\\s?");
|
||||
public static final Pattern PASSWORD_PROMPT = Pattern.compile("(.*)\\'s password:\\s?");
|
||||
public static final String PASSWORD_PROMPT_SUFFIX = "password:";
|
||||
public static final String CONFIRM_CONNECTION_PROMPT = "Are you sure you want to continue connecting";
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
|
||||
// unless stated otherwise, the behavior described in cases is true for 162+
|
||||
class UpdateStrategyTest {
|
||||
@Test fun `channel contains no builds`() {
|
||||
val result = check("IU-145.258", ChannelStatus.RELEASE, """<channel id="IDEA_Release" status="release" licensing="release"/>""")
|
||||
@@ -150,6 +151,7 @@ class UpdateStrategyTest {
|
||||
assertBuild("143.2332", result.newBuild)
|
||||
}
|
||||
|
||||
// since 163
|
||||
@Test fun `updates from the same baseline are preferred (per-release channels)`() {
|
||||
val result = check("IU-143.2287", ChannelStatus.EAP, """
|
||||
<channel id="IDEA_143_EAP" status="eap" licensing="eap">
|
||||
|
||||
+43
@@ -714,4 +714,47 @@ public class ApplicationImplTest extends LightPlatformTestCase {
|
||||
readAction2.get();
|
||||
readAction1.get();
|
||||
}
|
||||
|
||||
public void testReadActionInImpatientModeMustNotThrowWhenThereIsAPendingWriteAndWeAreUnderNonCancelableSection() throws Exception {
|
||||
AtomicBoolean stopRead = new AtomicBoolean();
|
||||
AtomicBoolean readAcquired = new AtomicBoolean();
|
||||
ApplicationImpl app = (ApplicationImpl)ApplicationManager.getApplication();
|
||||
Future<?> readAction1 = app.executeOnPooledThread(() ->
|
||||
app.runReadAction(() -> {
|
||||
readAcquired.set(true);
|
||||
try {
|
||||
while (!stopRead.get()) ;
|
||||
}
|
||||
finally {
|
||||
readAcquired.set(false);
|
||||
}
|
||||
})
|
||||
);
|
||||
while (!readAcquired.get());
|
||||
|
||||
AtomicBoolean executingImpatientReader = new AtomicBoolean();
|
||||
|
||||
Future<?> readAction2 = app.executeOnPooledThread(() -> {
|
||||
// wait for write action attempt to start
|
||||
while (!app.isWriteActionPending());
|
||||
ProgressManager.getInstance().executeNonCancelableSection(()->{
|
||||
app.executeByImpatientReader(() -> {
|
||||
executingImpatientReader.set(true);
|
||||
app.runReadAction(EmptyRunnable.getInstance());
|
||||
// must not throw
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Future<?> readAction1Canceler = app.executeOnPooledThread(() -> {
|
||||
while (!executingImpatientReader.get());
|
||||
TimeoutUtil.sleep(300); // make sure readAction2 does call runReadAction()
|
||||
stopRead.set(true);
|
||||
});
|
||||
app.runWriteAction(EmptyRunnable.getInstance());
|
||||
|
||||
readAction1Canceler.get();
|
||||
readAction2.get();
|
||||
readAction1.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,6 +373,14 @@ public class PsiTestUtil {
|
||||
public static Sdk addJdkAnnotations(@NotNull Sdk sdk) {
|
||||
String path = FileUtil.toSystemIndependentName(PlatformTestUtil.getCommunityPath()) + "/java/jdkAnnotations";
|
||||
VirtualFile root = LocalFileSystem.getInstance().findFileByPath(path);
|
||||
return addRootsToJdk(sdk, AnnotationOrderRootType.getInstance(), root);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Contract(pure=true)
|
||||
public static Sdk addRootsToJdk(@NotNull Sdk sdk,
|
||||
@NotNull OrderRootType rootType,
|
||||
@NotNull VirtualFile... roots) {
|
||||
Sdk clone;
|
||||
try {
|
||||
clone = (Sdk)sdk.clone();
|
||||
@@ -381,7 +389,9 @@ public class PsiTestUtil {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
SdkModificator sdkModificator = clone.getSdkModificator();
|
||||
sdkModificator.addRoot(root, AnnotationOrderRootType.getInstance());
|
||||
for (VirtualFile root : roots) {
|
||||
sdkModificator.addRoot(root, rootType);
|
||||
}
|
||||
sdkModificator.commitChanges();
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ debugger.renderers.file.description=Enable file object renderer
|
||||
debugger.single.smart.step.force=true
|
||||
debugger.single.smart.step.force.description=Do force step into on single variant smart step into
|
||||
debugger.emulate.method.breakpoints=false
|
||||
debugger.emulate.method.breakpoints.description=Emulate method breakpoints with line breakpoints
|
||||
debugger.emulate.method.breakpoints.description=Emulate method breakpoints with line breakpoints by default
|
||||
debugger.intern.string.literals=false
|
||||
debugger.intern.string.literals.description=Make string literal refer to the same instance of class String
|
||||
|
||||
@@ -913,5 +913,3 @@ build.manager.async.fs.events.description=Experimental: TranslatingCompilerFiles
|
||||
|
||||
batch.inspections.use.psi.as.ref.table.key=false
|
||||
batch.inspections.use.psi.as.ref.table.key.description=Use PsiElement as key for RefManager's table
|
||||
json.schema.fast.annotation.update=false
|
||||
json.schema.fast.annotation.update.description=Restart highlighting for all json files matching json schema on json schema fiel change
|
||||
@@ -22,6 +22,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* @author Konstantin Kolosovsky.
|
||||
@@ -212,4 +214,13 @@ public abstract class BaseDataReader {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void waitFor(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
|
||||
try {
|
||||
myFinishedFuture.get(timeout, unit);
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -90,6 +90,12 @@ public class ChangeDiffRequestProducer implements DiffRequestProducer {
|
||||
}
|
||||
|
||||
public static boolean isEquals(@NotNull Change change1, @NotNull Change change2) {
|
||||
if (!Comparing.equal(ChangesUtil.getBeforePath(change1), ChangesUtil.getBeforePath(change2)) ||
|
||||
!Comparing.equal(ChangesUtil.getAfterPath(change1), ChangesUtil.getAfterPath(change2))) {
|
||||
// we use Change.hashCode(), so removing this check might violate comparison contract
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ChangeDiffViewerWrapperProvider provider : ChangeDiffViewerWrapperProvider.EP_NAME.getExtensions()) {
|
||||
ThreeState equals = provider.isEquals(change1, change2);
|
||||
if (equals == ThreeState.NO) return false;
|
||||
|
||||
+10
-9
@@ -24,7 +24,7 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import java.io.File
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.*
|
||||
|
||||
/**
|
||||
* @author traff
|
||||
@@ -39,18 +39,19 @@ class TerminalProjectOptionsProvider(private val myProject: Project) : Persisten
|
||||
}
|
||||
|
||||
override fun loadState(state: State) {
|
||||
shellPath = state.myShellPath
|
||||
myState.myShellPath = state.myShellPath
|
||||
myState.myStartingDirectory = state.myStartingDirectory
|
||||
}
|
||||
|
||||
class State {
|
||||
var myShellPath: String? = null
|
||||
|
||||
var myStartingDirectory: String? = null
|
||||
}
|
||||
|
||||
var shellPath: String? by ValueWithDefault { defaultShellPath }
|
||||
var shellPath: String? by ValueWithDefault(State::myShellPath, myState) { defaultShellPath }
|
||||
|
||||
var startingDirectory: String? by ValueWithDefault { defaultStartingDirectory }
|
||||
var startingDirectory: String? by ValueWithDefault(State::myStartingDirectory, myState) { defaultStartingDirectory }
|
||||
|
||||
val defaultStartingDirectory: String?
|
||||
get() {
|
||||
@@ -114,15 +115,15 @@ class TerminalProjectOptionsProvider(private val myProject: Project) : Persisten
|
||||
|
||||
}
|
||||
|
||||
class ValueWithDefault(val default: () -> String?) {
|
||||
private var _value: String? = null
|
||||
|
||||
// TODO: In Kotlin 1.1 it will be possible to pass references to instance properties. Until then we need 'state' argument as a reciever for
|
||||
// to property to apply
|
||||
class ValueWithDefault(val prop: KMutableProperty1<TerminalProjectOptionsProvider.State, String?>, val state: TerminalProjectOptionsProvider.State, val default: () -> String?) {
|
||||
operator fun getValue(thisRef: Any?, property: KProperty<*>): String? {
|
||||
return if (_value !== null) _value else default()
|
||||
return if (prop.get(state) !== null) prop.get(state) else default()
|
||||
}
|
||||
|
||||
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String?) {
|
||||
_value = if (value == default() || value.isNullOrEmpty()) null else value
|
||||
prop.set(state, if (value == default() || value.isNullOrEmpty()) null else value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.PlatformUtils;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -51,6 +52,7 @@ public class IpnbFilePanel extends JPanel implements Scrollable, DataProvider, D
|
||||
private static final Logger LOG = Logger.getInstance(IpnbFilePanel.class);
|
||||
private final DocumentAdapter myDocumentListener;
|
||||
private final Document myDocument;
|
||||
private final MessageBusConnection myBusConnection;
|
||||
private IpnbFile myIpnbFile;
|
||||
private final Project myProject;
|
||||
@NotNull private final IpnbFileEditor myParent;
|
||||
@@ -98,19 +100,22 @@ public class IpnbFilePanel extends JPanel implements Scrollable, DataProvider, D
|
||||
}, 10, ModalityState.stateForComponent(this));
|
||||
|
||||
UIUtil.requestFocus(this);
|
||||
ApplicationManager.getApplication().getMessageBus().connect().subscribe(ProjectEx.ProjectSaved.TOPIC,
|
||||
new ProjectEx.ProjectSaved() {
|
||||
@Override
|
||||
public void saved(@NotNull Project project) {
|
||||
CommandProcessor.getInstance().runUndoTransparentAction(
|
||||
() -> ApplicationManager.getApplication()
|
||||
.runWriteAction(() -> saveToFile(false)));
|
||||
}
|
||||
});
|
||||
myBusConnection = ApplicationManager.getApplication().getMessageBus().connect();
|
||||
myBusConnection.subscribe(ProjectEx.ProjectSaved.TOPIC,
|
||||
new ProjectEx.ProjectSaved() {
|
||||
@Override
|
||||
public void saved(@NotNull Project project) {
|
||||
CommandProcessor.getInstance().runUndoTransparentAction(
|
||||
() -> ApplicationManager.getApplication()
|
||||
.runWriteAction(() -> saveToFile(false)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
myDocument.removeDocumentListener(myDocumentListener);
|
||||
Disposer.dispose(myBusConnection);
|
||||
}
|
||||
|
||||
private void readFromFile(boolean showError) {
|
||||
@@ -391,9 +396,11 @@ public class IpnbFilePanel extends JPanel implements Scrollable, DataProvider, D
|
||||
myIpnbFile.removeCell(index);
|
||||
remove(index);
|
||||
|
||||
int indexToSelect = index < myIpnbPanels.size() ? index : index-1;
|
||||
final IpnbEditablePanel panel = myIpnbPanels.get(indexToSelect);
|
||||
setSelectedCell(panel, false);
|
||||
if (!myIpnbPanels.isEmpty()) {
|
||||
int indexToSelect = index < myIpnbPanels.size() ? index : index - 1;
|
||||
final IpnbEditablePanel panel = myIpnbPanels.get(indexToSelect);
|
||||
setSelectedCell(panel, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveToFile(boolean synchronize) {
|
||||
@@ -620,7 +627,7 @@ public class IpnbFilePanel extends JPanel implements Scrollable, DataProvider, D
|
||||
createAndAddCell(true, IpnbCodeCell.createEmptyCodeCell());
|
||||
CommandProcessor.getInstance().executeCommand(getProject(),
|
||||
() -> ApplicationManager.getApplication().runWriteAction(
|
||||
() -> saveToFile(false)), "Ipnb.runCell", new Object());
|
||||
() -> saveToFile(false)), "Ipnb.runCell", new Object());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -308,7 +308,10 @@ public class IpnbCodePanel extends IpnbEditablePanel<JComponent, IpnbCodeCell> {
|
||||
}
|
||||
if (outputContent != null) {
|
||||
myCell.addCellOutput(outputContent);
|
||||
addOutputPanel(myViewPanel, outputContent, outputContent instanceof IpnbOutOutputCell);
|
||||
final JComponent component = myHideableOutputPanel.getSecondComponent();
|
||||
if (component != null) {
|
||||
addOutputPanel(component, outputContent, outputContent instanceof IpnbOutOutputCell);
|
||||
}
|
||||
}
|
||||
final IpnbFilePanel filePanel = myParent.getIpnbFilePanel();
|
||||
filePanel.revalidateAndRepaint();
|
||||
|
||||
@@ -28,7 +28,10 @@ import org.jetbrains.plugins.ipnb.format.cells.output.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class IpnbParser {
|
||||
private static final Logger LOG = Logger.getInstance(IpnbParser.class);
|
||||
@@ -57,7 +60,7 @@ public class IpnbParser {
|
||||
IpnbFileRaw rawFile = gson.fromJson(fileText.toString(), IpnbFileRaw.class);
|
||||
if (rawFile == null) {
|
||||
int nbformat = isIpythonNewFormat(virtualFile) ? 4 : 3;
|
||||
return new IpnbFile(Collections.emptyMap(), nbformat, Lists.newArrayList(), path);
|
||||
return new IpnbFile(new HashMap<>(), nbformat, Lists.newArrayList(), path);
|
||||
}
|
||||
List<IpnbCell> cells = new ArrayList<>();
|
||||
final IpnbWorksheet[] worksheets = rawFile.worksheets;
|
||||
@@ -256,7 +259,7 @@ public class IpnbParser {
|
||||
public IpnbCell createCell(boolean isValidSource) {
|
||||
final IpnbCell cell;
|
||||
if (cell_type.equals("markdown")) {
|
||||
cell = new IpnbMarkdownCell(isValidSource ? source : Collections.emptyList(), metadata);
|
||||
cell = new IpnbMarkdownCell(isValidSource ? source : new ArrayList<>(), metadata);
|
||||
}
|
||||
else if (cell_type.equals("code")) {
|
||||
final List<IpnbOutputCell> outputCells = new ArrayList<>();
|
||||
@@ -265,14 +268,14 @@ public class IpnbParser {
|
||||
}
|
||||
final Integer prompt = prompt_number != null ? prompt_number : execution_count;
|
||||
cell = new IpnbCodeCell(language == null ? "python" : language,
|
||||
input == null ? (isValidSource ? source : Collections.emptyList()) : input,
|
||||
input == null ? (isValidSource ? source : new ArrayList<>()) : input,
|
||||
prompt, outputCells, metadata);
|
||||
}
|
||||
else if (cell_type.equals("raw")) {
|
||||
cell = new IpnbRawCell(isValidSource ? source : Collections.emptyList());
|
||||
cell = new IpnbRawCell(isValidSource ? source : new ArrayList<>());
|
||||
}
|
||||
else if (cell_type.equals("heading")) {
|
||||
cell = new IpnbHeadingCell(isValidSource ? source : Collections.emptyList(), level, metadata);
|
||||
cell = new IpnbHeadingCell(isValidSource ? source : new ArrayList<>(), level, metadata);
|
||||
}
|
||||
else {
|
||||
cell = null;
|
||||
@@ -303,7 +306,7 @@ public class IpnbParser {
|
||||
final CellOutputRaw raw = new CellOutputRaw();
|
||||
raw.metadata = outputCell.getMetadata();
|
||||
if (raw.metadata == null && !(outputCell instanceof IpnbStreamOutputCell) && !(outputCell instanceof IpnbErrorOutputCell)) {
|
||||
raw.metadata = Collections.emptyMap();
|
||||
raw.metadata = new HashMap<>();
|
||||
}
|
||||
|
||||
if (outputCell instanceof IpnbPngOutputCell) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.ipnb.format.cells.output.IpnbOutputCell;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -61,7 +61,7 @@ public class IpnbCodeCell extends IpnbEditableCell {
|
||||
|
||||
@NotNull
|
||||
public static IpnbCodeCell createEmptyCodeCell() {
|
||||
return new IpnbCodeCell("python", Collections.emptyList(), null, new ArrayList<>(),
|
||||
Collections.emptyMap());
|
||||
return new IpnbCodeCell("python", new ArrayList<>(), null, new ArrayList<>(),
|
||||
new HashMap<>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ envs {
|
||||
conda "django18", "2.7", ["django==1.6"], false
|
||||
textfile "django18/tags.txt", "django"
|
||||
|
||||
// conda "django17", "2.7", ["django==1.7"], false
|
||||
// textfile "django17/tags.txt", "django\nskeletons"
|
||||
conda "django17", "2.7", ["django==1.7"], false
|
||||
textfile "django17/tags.txt", "django\nskeletons"
|
||||
|
||||
conda "python34", "3.4", ["ipython==2.1", "django==1.6", "behave", "jinja2", "tox>=2.0", "pandas"], true
|
||||
textfile "python34/tags.txt", "python3\nipython\nipython200\nskeletons\ndjango\nbehave\ntox\njinja2\npython34\npackaging\npandas"
|
||||
@@ -43,8 +43,12 @@ if (new File(envs.envsDirectory, "django_latest").exists() &&
|
||||
delete new File(envs.envsDirectory, "django_latest")
|
||||
}
|
||||
|
||||
if (System.getenv("NO_CLEAN") == null && envs.envsDirectory.exists() &&
|
||||
envs.envsDirectory.lastModified()<project.buildscript.sourceFile.lastModified()) {
|
||||
def bootstrapDirNotEmpty = envs.bootstrapDirectory.exists() &&
|
||||
(new File(envs.bootstrapDirectory, "latest_64/bin/conda").exists() ||
|
||||
new File(envs.bootstrapDirectory, "latest_64/Scripts/conda.exe").exists())
|
||||
|
||||
if (!bootstrapDirNotEmpty || (System.getenv("NO_CLEAN") == null && envs.envsDirectory.exists() &&
|
||||
envs.envsDirectory.lastModified() < project.buildscript.sourceFile.lastModified())) {
|
||||
// clean the cache if the build script if modified later
|
||||
println "Cleaning cached environments at " + envs.envsDirectory
|
||||
delete envs.envsDirectory
|
||||
|
||||
@@ -151,7 +151,7 @@ public interface PydevConsoleRunner {
|
||||
}
|
||||
}));
|
||||
|
||||
return command.replace(PydevConsoleRunnerImpl.WORKING_DIR_AND_PY_PATHS_ENV, path);
|
||||
return command.replace(PydevConsoleRunnerImpl.WORKING_DIR_AND_PYTHON_PATHS, path);
|
||||
}
|
||||
|
||||
static Map<String, String> addDefaultEnvironments(Sdk sdk, Map<String, String> envs, @NotNull Project project) {
|
||||
|
||||
@@ -127,9 +127,9 @@ import static com.intellij.execution.runners.AbstractConsoleRunnerWithHistory.re
|
||||
* @author traff, oleg
|
||||
*/
|
||||
public class PydevConsoleRunnerImpl implements PydevConsoleRunner {
|
||||
public static final String WORKING_DIR_AND_PY_PATHS_ENV = "WORKING_DIR_AND_PYTHON_PATHS";
|
||||
public static final String WORKING_DIR_AND_PYTHON_PATHS = "WORKING_DIR_AND_PYTHON_PATHS";
|
||||
public static final String CONSOLE_START_COMMAND = "import sys; print('Python %s on %s' % (sys.version, sys.platform))\n" +
|
||||
"sys.path.extend([" + WORKING_DIR_AND_PY_PATHS_ENV + "])\n";
|
||||
"sys.path.extend([" + WORKING_DIR_AND_PYTHON_PATHS + "])\n";
|
||||
private static final Logger LOG = Logger.getInstance(PydevConsoleRunnerImpl.class.getName());
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
public static final String PYDEV_PYDEVCONSOLE_PY = "pydev/pydevconsole.py";
|
||||
|
||||
Reference in New Issue
Block a user