Merge remote-tracking branch 'origin/master'

This commit is contained in:
Valentin Fondaratov
2016-10-25 14:06:35 +03:00
36 changed files with 562 additions and 538 deletions
@@ -32,7 +32,7 @@ import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
import com.intellij.debugger.requests.ClassPrepareRequestor;
import com.intellij.debugger.settings.DebuggerSettings;
import com.intellij.debugger.ui.impl.watch.EvaluationDescriptor;
import com.intellij.debugger.ui.impl.watch.CompilingEvaluatorImpl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
@@ -245,7 +245,7 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
}
throw new EventProcessingException(title[0], ex.getMessage(), ex);
}
}
return true;
}
@@ -269,7 +269,7 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
SourcePosition position = ContextUtil.getSourcePosition(context);
PsiElement element = ContextUtil.getContextElement(context, position);
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, () ->
createExpressionEvaluator(myProject, context, element, position, expressionToEvaluate, this::createLogMessageCodeFragment));
createExpressionEvaluator(myProject, element, position, expressionToEvaluate, this::createLogMessageCodeFragment));
Value eval = evaluator.evaluate(context);
buf.append(eval instanceof VoidValue ? "void" : DebuggerUtils.getValueAsString(context, eval));
}
@@ -342,9 +342,8 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
}
try {
Project project = context.getProject();
SourcePosition contextSourcePosition = ContextUtil.getSourcePosition(context);
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(project, () -> {
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, () -> {
// IMPORTANT: calculate context psi element basing on the location where the exception
// has been hit, not on the location where it was set. (For line breakpoints these locations are the same, however,
// for method, exception and field breakpoints these locations differ)
@@ -352,7 +351,7 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
if (contextPsiElement == null) {
contextPsiElement = getEvaluationElement(); // as a last resort
}
return createExpressionEvaluator(project, context, contextPsiElement, contextSourcePosition, getCondition(),
return createExpressionEvaluator(myProject, contextPsiElement, contextSourcePosition, getCondition(),
this::createConditionCodeFragment);
});
return DebuggerUtilsEx.evaluateBoolean(evaluator, context);
@@ -368,7 +367,6 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
}
private static ExpressionEvaluator createExpressionEvaluator(Project project,
EvaluationContextImpl context,
PsiElement contextPsiElement,
SourcePosition contextSourcePosition,
TextWithImports text,
@@ -378,7 +376,7 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
return EvaluatorBuilderImpl.build(text, contextPsiElement, contextSourcePosition, project);
}
catch (UnsupportedExpressionException ex) {
ExpressionEvaluator eval = EvaluationDescriptor.createCompilingEvaluator(context, contextPsiElement, fragmentFactory);
ExpressionEvaluator eval = CompilingEvaluatorImpl.create(project, contextPsiElement, fragmentFactory);
if (eval != null) {
return eval;
}
@@ -387,11 +385,11 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
}
private PsiCodeFragment createConditionCodeFragment(PsiElement context) {
return createCodeFragment(getProject(), getCondition(), context);
return createCodeFragment(myProject, getCondition(), context);
}
private PsiCodeFragment createLogMessageCodeFragment(PsiElement context) {
return createCodeFragment(getProject(), getLogMessage(), context);
return createCodeFragment(myProject, getLogMessage(), context);
}
private static PsiCodeFragment createCodeFragment(Project project, TextWithImports text, PsiElement context) {
@@ -51,10 +51,12 @@ import java.util.Collection;
* @author egor
*/
public abstract class CompilingEvaluator implements ExpressionEvaluator {
@NotNull protected final Project myProject;
@NotNull protected final PsiElement myPsiContext;
@NotNull protected final ExtractLightMethodObjectHandler.ExtractedData myData;
public CompilingEvaluator(@NotNull PsiElement context, @NotNull ExtractLightMethodObjectHandler.ExtractedData data) {
public CompilingEvaluator(@NotNull Project project, @NotNull PsiElement context, @NotNull ExtractLightMethodObjectHandler.ExtractedData data) {
myProject = project;
myPsiContext = context;
myData = data;
}
@@ -86,16 +88,15 @@ public abstract class CompilingEvaluator implements ExpressionEvaluator {
try {
// invoke base evaluator on call code
Project project = ApplicationManager.getApplication().runReadAction((Computable<Project>)myPsiContext::getProject);
SourcePosition position = ContextUtil.getSourcePosition(evaluationContext);
ExpressionEvaluator evaluator =
DebuggerInvocationUtil.commitAndRunReadAction(project, new EvaluatingComputable<ExpressionEvaluator>() {
DebuggerInvocationUtil.commitAndRunReadAction(myProject, new EvaluatingComputable<ExpressionEvaluator>() {
@Override
public ExpressionEvaluator compute() throws EvaluateException {
TextWithImports callCode = getCallCode();
PsiElement copyContext = myData.getAnchor();
CodeFragmentFactory factory = DebuggerUtilsEx.findAppropriateCodeFragmentFactory(callCode, copyContext);
return factory.getEvaluatorBuilder().build(factory.createCodeFragment(callCode, copyContext, project), position);
return factory.getEvaluatorBuilder().build(factory.createCodeFragment(callCode, copyContext, myProject), position);
}
});
((EvaluationContextImpl)evaluationContext).setClassLoader(classLoader);
@@ -148,12 +149,8 @@ public abstract class CompilingEvaluator implements ExpressionEvaluator {
protected String getGenClassQName() {
return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
@Override
public String compute() {
return JVMNameUtil.getNonAnonymousClassName(myData.getGeneratedInnerClass());
}
});
return ApplicationManager.getApplication().runReadAction(
(Computable<String>)() -> JVMNameUtil.getNonAnonymousClassName(myData.getGeneratedInnerClass()));
}
///////////////// Compiler stuff
@@ -18,7 +18,7 @@ package com.intellij.debugger.ui.impl.watch;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.server.BuildManager;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.ClassObject;
import com.intellij.openapi.compiler.CompilationException;
@@ -26,15 +26,20 @@ import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.compiler.CompilerMessageCategory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiCodeFragment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.refactoring.extractMethod.PrepareFailedException;
import com.intellij.refactoring.extractMethodObject.ExtractLightMethodObjectHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -44,35 +49,31 @@ import org.jetbrains.jps.model.java.compiler.AnnotationProcessingConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.function.Function;
// todo: consider batching compilations in order not to start a separate process for every class that needs to be compiled
public class CompilingEvaluatorImpl extends CompilingEvaluator {
private final EvaluationContextImpl myEvaluationContext;
public CompilingEvaluatorImpl(EvaluationContextImpl evaluationContext, @NotNull PsiElement context, @NotNull ExtractLightMethodObjectHandler.ExtractedData data) {
super(context, data);
myEvaluationContext = evaluationContext;
public CompilingEvaluatorImpl(@NotNull Project project,
@NotNull PsiElement context,
@NotNull ExtractLightMethodObjectHandler.ExtractedData data) {
super(project, context, data);
}
@Override
@NotNull
protected Collection<ClassObject> compile(@Nullable JavaSdkVersion debuggeeVersion) throws EvaluateException {
final Module module = ApplicationManager.getApplication().runReadAction(new Computable<Module>() {
@Override
public Module compute() {
return ModuleUtilCore.findModuleForPsiElement(myPsiContext);
}
});
final List<String> options = new ArrayList<>();
Module module = ApplicationManager.getApplication().runReadAction(
(Computable<Module>)() -> ModuleUtilCore.findModuleForPsiElement(myPsiContext));
List<String> options = new ArrayList<>();
options.add("-encoding");
options.add("UTF-8");
final List<File> platformClasspath = new ArrayList<>();
final List<File> classpath = new ArrayList<>();
List<File> platformClasspath = new ArrayList<>();
List<File> classpath = new ArrayList<>();
AnnotationProcessingConfiguration profile = null;
if (module != null) {
profile = CompilerConfiguration.getInstance(module.getProject()).getAnnotationProcessingConfiguration(module);
final ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
assert myProject.equals(module.getProject()) : module + " is from another project";
profile = CompilerConfiguration.getInstance(myProject).getAnnotationProcessingConfiguration(module);
ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
for (String s : rootManager.orderEntries().compileOnly().recursively().exportedOnly().withoutSdk().getPathsList().getPathList()) {
classpath.add(new File(s));
}
@@ -82,31 +83,31 @@ public class CompilingEvaluatorImpl extends CompilingEvaluator {
}
JavaBuilder.addAnnotationProcessingOptions(options, profile);
final Pair<Sdk, JavaSdkVersion> runtime = BuildManager.getJavacRuntimeSdk(myEvaluationContext.getProject());
final JavaSdkVersion buildRuntimeVersion = runtime.getSecond();
Pair<Sdk, JavaSdkVersion> runtime = BuildManager.getJavacRuntimeSdk(myProject);
JavaSdkVersion buildRuntimeVersion = runtime.getSecond();
// if compiler or debuggee version or both are unknown, let source and target be the compiler's defaults
if (buildRuntimeVersion != null && debuggeeVersion != null) {
final JavaSdkVersion minVersion = buildRuntimeVersion.ordinal() > debuggeeVersion.ordinal() ? debuggeeVersion : buildRuntimeVersion;
final String sourceOption = getSourceOption(minVersion.getMaxLanguageLevel());
JavaSdkVersion minVersion = buildRuntimeVersion.ordinal() > debuggeeVersion.ordinal() ? debuggeeVersion : buildRuntimeVersion;
String sourceOption = getSourceOption(minVersion.getMaxLanguageLevel());
options.add("-source");
options.add(sourceOption);
options.add("-target");
options.add(sourceOption);
}
final CompilerManager compilerManager = CompilerManager.getInstance(myEvaluationContext.getProject());
CompilerManager compilerManager = CompilerManager.getInstance(myProject);
File sourceFile = null;
try {
sourceFile = generateTempSourceFile(compilerManager.getJavacCompilerWorkingDir());
final File srcDir = sourceFile.getParentFile();
final List<File> sourcePath = Collections.emptyList();
final Set<File> sources = Collections.singleton(sourceFile);
File srcDir = sourceFile.getParentFile();
List<File> sourcePath = Collections.emptyList();
Set<File> sources = Collections.singleton(sourceFile);
return compilerManager.compileJavaCode(options, platformClasspath, classpath, Collections.emptyList(), sourcePath, sources, srcDir);
}
catch (CompilationException e) {
final StringBuilder res = new StringBuilder("Compilation failed:\n");
StringBuilder res = new StringBuilder("Compilation failed:\n");
for (CompilationException.Message m : e.getMessages()) {
if (m.getCategory() == CompilerMessageCategory.ERROR) {
res.append(m.getText()).append("\n");
@@ -130,7 +131,7 @@ public class CompilingEvaluatorImpl extends CompilingEvaluator {
}
private File generateTempSourceFile(File workingDir) throws IOException {
final Pair<String, String> fileData = ApplicationManager.getApplication().runReadAction((Computable<Pair<String, String>>)() -> {
Pair<String, String> fileData = ApplicationManager.getApplication().runReadAction((Computable<Pair<String, String>>)() -> {
PsiFile file = myData.getGeneratedInnerClass().getContainingFile();
return Pair.create(file.getName(), file.getText());
});
@@ -140,8 +141,34 @@ public class CompilingEvaluatorImpl extends CompilingEvaluator {
if (fileData.second == null) {
throw new IOException("Class source code not specified");
}
final File file = new File(workingDir, "debugger/src/"+fileData.first);
File file = new File(workingDir, "debugger/src/" + fileData.first);
FileUtil.writeToFile(file, fileData.second);
return file;
}
@Nullable
public static ExpressionEvaluator create(@NotNull Project project,
@Nullable PsiElement psiContext,
@NotNull Function<PsiElement, PsiCodeFragment> fragmentFactory)
throws EvaluateException {
if (Registry.is("debugger.compiling.evaluator") && psiContext != null) {
return ApplicationManager.getApplication().runReadAction((ThrowableComputable<ExpressionEvaluator, EvaluateException>)() -> {
try {
ExtractLightMethodObjectHandler.ExtractedData data = ExtractLightMethodObjectHandler.extractLightMethodObject(
project,
psiContext.getContainingFile(),
fragmentFactory.apply(psiContext),
getGeneratedClassName());
if (data != null) {
return new CompilingEvaluatorImpl(project, psiContext, data);
}
}
catch (PrepareFailedException e) {
NodeDescriptorImpl.LOG.info(e);
}
return null;
});
}
return null;
}
}
@@ -30,20 +30,16 @@ import com.intellij.debugger.engine.evaluation.expression.UnsupportedExpressionE
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.psi.*;
import com.intellij.refactoring.extractMethod.PrepareFailedException;
import com.intellij.refactoring.extractMethodObject.ExtractLightMethodObjectHandler;
import com.intellij.psi.PsiCodeFragment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiExpressionCodeFragment;
import com.intellij.xdebugger.frame.XValueModifier;
import com.sun.jdi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
/**
* @author lex
*/
@@ -71,25 +67,26 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl {
return DebuggerUtilsEx.findAppropriateCodeFragmentFactory(text, context).createCodeFragment(text, context, myProject);
}
public final Value calcValue(final EvaluationContextImpl evaluationContext) throws EvaluateException {
public final Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException {
try {
final EvaluationContextImpl thisEvaluationContext = getEvaluationContext(evaluationContext);
EvaluationContextImpl thisEvaluationContext = getEvaluationContext(evaluationContext);
SourcePosition position = ContextUtil.getSourcePosition(evaluationContext);
PsiElement psiContext = ContextUtil.getContextElement(evaluationContext, position);
ExpressionEvaluator evaluator;
try {
evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, () ->
DebuggerUtilsEx.findAppropriateCodeFragmentFactory(getEvaluationText(), psiContext)
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, () -> {
try {
return DebuggerUtilsEx.findAppropriateCodeFragmentFactory(getEvaluationText(), psiContext)
.getEvaluatorBuilder()
.build(getEvaluationCode(thisEvaluationContext), position));
}
catch (UnsupportedExpressionException ex) {
evaluator = createCompilingEvaluator(evaluationContext, psiContext, this::createCodeFragment);
if (evaluator == null) {
.build(getEvaluationCode(thisEvaluationContext), position);
}
catch (UnsupportedExpressionException ex) {
ExpressionEvaluator eval = CompilingEvaluatorImpl.create(myProject, psiContext, this::createCodeFragment);
if (eval != null) {
return eval;
}
throw ex;
}
}
});
if (!thisEvaluationContext.getDebugProcess().isAttached()) {
throw EvaluateExceptionUtil.PROCESS_EXITED;
@@ -115,32 +112,6 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl {
}
}
@Nullable
public static ExpressionEvaluator createCompilingEvaluator(EvaluationContextImpl evaluationContext,
@Nullable PsiElement psiContext,
Function<PsiElement, PsiCodeFragment> fragmentFactory)
throws EvaluateException {
if (Registry.is("debugger.compiling.evaluator") && psiContext != null) {
return ApplicationManager.getApplication().runReadAction((ThrowableComputable<ExpressionEvaluator, EvaluateException>)() -> {
try {
ExtractLightMethodObjectHandler.ExtractedData data = ExtractLightMethodObjectHandler.extractLightMethodObject(
evaluationContext.getProject(),
psiContext.getContainingFile(),
fragmentFactory.apply(psiContext),
CompilingEvaluator.getGeneratedClassName());
if (data != null) {
return new CompilingEvaluatorImpl(evaluationContext, psiContext, data);
}
}
catch (PrepareFailedException e) {
LOG.info(e);
}
return null;
});
}
return null;
}
public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException {
PsiElement evaluationCode = getEvaluationCode(context);
if (evaluationCode instanceof PsiExpressionCodeFragment) {
@@ -16,7 +16,6 @@
package com.intellij.execution.junit;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.MetaAnnotationUtil;
import com.intellij.codeInsight.TestFrameworks;
import com.intellij.execution.*;
import com.intellij.execution.junit2.info.MethodLocation;
@@ -26,19 +25,22 @@ import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.util.*;
import com.intellij.testIntegration.JavaTestFramework;
import com.intellij.testIntegration.TestFramework;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.concurrent.ConcurrentMap;
@SuppressWarnings({"UtilityClassWithoutPrivateConstructor"})
public class JUnitUtil {
@@ -223,11 +225,11 @@ public class JUnitUtil {
if (module != null) {
for (final PsiMethod method : psiClass.getAllMethods()) {
ProgressManager.checkCanceled();
if (isMetaAnnotated(method, TEST5_ANNOTATIONS, module)) return true;
if (isMetaAnnotated(method, TEST5_ANNOTATIONS)) return true;
}
for (PsiClass aClass : psiClass.getInnerClasses()) {
if (isMetaAnnotated(aClass, JUNIT5_NESTED, module)) return true;
if (isMetaAnnotated(aClass, Collections.singleton(JUNIT5_NESTED))) return true;
}
}
@@ -260,23 +262,62 @@ public class JUnitUtil {
return true;
}
Module module = ModuleUtilCore.findModuleForPsiElement(method);
return module != null && isMetaAnnotated(method, TEST5_ANNOTATIONS, module);
return isMetaAnnotated(method, TEST5_ANNOTATIONS);
}
private static boolean isMetaAnnotated(PsiModifierListOwner owner, final Collection<String> metaAnnotations, final Module module) {
for (String annotation : metaAnnotations) {
if (isMetaAnnotated(owner, annotation, module)) return true;
private static final ConcurrentMap<String, Key<CachedValue>> annotationsKeyForProvider = ContainerUtil.newConcurrentMap();
@NotNull
private static Key<CachedValue<Boolean>> getKeyForAnnotations(Collection<String> annotations) {
String name = StringUtil.join(annotations, ", ");
Key<CachedValue> key = annotationsKeyForProvider.get(name);
if (key == null) {
key = ConcurrencyUtil.cacheOrGet(annotationsKeyForProvider, name, Key.<CachedValue>create(name));
}
//noinspection unchecked
return (Key)key;
}
private static boolean isMetaAnnotated(PsiModifierListOwner listOwner, final Collection<String> annotations) {
if (AnnotationUtil.isAnnotated(listOwner, annotations, false)) {
return true;
}
PsiModifierList modifierList = listOwner.getModifierList();
if (modifierList != null) {
for (PsiAnnotation annotation : modifierList.getApplicableAnnotations()) {
PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement();
if (nameReferenceElement != null) {
PsiElement resolve = nameReferenceElement.resolve();
if (resolve instanceof PsiClass) {
Boolean annotated = CachedValuesManager.getManager(listOwner.getProject()).getCachedValue(resolve, getKeyForAnnotations(annotations), () -> new CachedValueProvider.Result<>(
isTestAnnotatedAnnotation((PsiClass)resolve, new HashSet<>(), annotations), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT), false);
if (annotated != null && annotated) return true;
}
}
}
}
return false;
}
private static boolean isMetaAnnotated(PsiModifierListOwner owner, String annotation, Module module) {
Collection<PsiClass> annotations = MetaAnnotationUtil.getAnnotationTypesWithChildren(module, annotation, true);
Stream<String> qualifiedNames = annotations.stream().map(psiClass -> psiClass.getQualifiedName());
if (AnnotationUtil.isAnnotated(owner, qualifiedNames.collect(Collectors.toSet()), false)) {
private static boolean isTestAnnotatedAnnotation(PsiClass aClass, final Set<PsiClass> visited, final Collection<String> annotations) {
if (AnnotationUtil.isAnnotated(aClass, annotations, false)) {
return true;
}
PsiModifierList modifierList = aClass.getModifierList();
if (modifierList != null) {
for (PsiAnnotation psiAnnotation : modifierList.getApplicableAnnotations()) {
PsiJavaCodeReferenceElement nameReferenceElement = psiAnnotation.getNameReferenceElement();
if (nameReferenceElement != null) {
PsiElement resolve = nameReferenceElement.resolve();
if (resolve instanceof PsiClass && visited.add((PsiClass)resolve) &&
((PsiClass)resolve).isAnnotationType() &&
isTestAnnotatedAnnotation((PsiClass)resolve, visited, annotations)) {
return true;
}
}
}
}
return false;
}
@@ -51,13 +51,13 @@ public class JavaModuleGraphUtil {
public static Collection<PsiJavaModule> findCycle(@NotNull PsiJavaModule module) {
Project project = module.getProject();
List<Set<PsiJavaModule>> cycles = CachedValuesManager.getManager(project).getCachedValue(project, () ->
Result.create(findCycles(project), JavaModuleFileChangeTracker.getInstance(project)));
Result.create(findCycles(project), JavaModuleFileChangeTracker.getDependencies(project)));
return ContainerUtil.find(cycles, set -> set.contains(module));
}
public static boolean exports(@NotNull PsiJavaModule source, @NotNull String packageName, @NotNull PsiJavaModule target) {
Map<String, Set<String>> exports = CachedValuesManager.getCachedValue(source, () ->
Result.create(exportsMap(source), JavaModuleFileChangeTracker.getInstance(source.getProject())));
Result.create(exportsMap(source), JavaModuleFileChangeTracker.getDependencies(source.getProject())));
Set<String> targets = exports.get(packageName);
return targets != null && (targets.isEmpty() || targets.contains(target.getModuleName()));
}
@@ -65,7 +65,7 @@ public class JavaModuleGraphUtil {
public static boolean reads(@NotNull PsiJavaModule source, @NotNull PsiJavaModule destination) {
Project project = source.getProject();
RequiresGraph graph = CachedValuesManager.getManager(project).getCachedValue(project, () ->
Result.create(buildRequiresGraph(project), JavaModuleFileChangeTracker.getInstance(project)));
Result.create(buildRequiresGraph(project), JavaModuleFileChangeTracker.getDependencies(project)));
return graph.reads(source, destination);
}
@@ -15,8 +15,6 @@
*/
package com.intellij.codeInsight.hints
import com.intellij.lang.Language
import com.intellij.lang.java.JavaLanguage
import com.intellij.psi.PsiCallExpression
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
@@ -48,8 +46,6 @@ class JavaInlayParameterHintsProvider : InlayParameterHintsProvider {
return MethodInfo(fullMethodName, paramNames)
}
override val language: Language = JavaLanguage.INSTANCE
override val defaultBlackList = setOf(
"(begin*, end*)",
"(start*, end*)",
@@ -150,7 +150,7 @@ public class LightJavaModule extends LightElement implements PsiJavaModule {
@Override
public Result<LightJavaModule> compute(Pair<PsiManager, VirtualFile> p) {
LightJavaModule module = new LightJavaModule(p.first, p.second);
return Result.create(module, JavaModuleFileChangeTracker.getInstance(p.first.getProject()));
return Result.create(module, JavaModuleFileChangeTracker.getDependencies(p.first.getProject()));
}
}, false, pair(manager, jarRoot));
}
@@ -16,57 +16,14 @@
package com.intellij.psi.impl.source;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ModificationTracker;
import com.intellij.openapi.util.NotNullLazyKey;
import com.intellij.psi.*;
import com.intellij.psi.PsiTreeChangeEvent;
import com.intellij.util.NotNullFunction;
import com.intellij.openapi.roots.ProjectRootModificationTracker;
import org.jetbrains.annotations.NotNull;
import static com.intellij.psi.PsiTreeChangeEvent.*;
public class JavaModuleFileChangeTracker implements ModificationTracker {
private static final NotNullLazyKey<ModificationTracker, Project> KEY = NotNullLazyKey.create("", new NotNullFunction<Project, ModificationTracker>() {
@NotNull
@Override
public ModificationTracker fun(Project project) {
return new JavaModuleFileChangeTracker(project);
}
});
import static com.intellij.psi.util.PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT;
public class JavaModuleFileChangeTracker {
@NotNull
public static ModificationTracker getInstance(@NotNull Project p) {
return KEY.getValue(p);
}
private volatile long myCount = 0;
private JavaModuleFileChangeTracker(Project project) {
PsiManager.getInstance(project).addPsiTreeChangeListener(new PsiTreeChangeAdapter() {
@Override public void childAdded(@NotNull PsiTreeChangeEvent event) { process(event.getFile()); }
@Override public void childRemoved(@NotNull PsiTreeChangeEvent event) { process(event.getFile()); }
@Override public void childReplaced(@NotNull PsiTreeChangeEvent event) { process(event.getFile()); }
@Override public void childMoved(@NotNull PsiTreeChangeEvent event) { process(event.getFile()); }
@Override public void childrenChanged(@NotNull PsiTreeChangeEvent event) { process(event.getFile()); }
private void process(PsiFile file) {
if (file != null && PsiJavaModule.MODULE_INFO_FILE.equals(file.getName())) {
myCount++;
}
}
@Override
public void propertyChanged(@NotNull PsiTreeChangeEvent event) {
String name = event.getPropertyName();
if (name == PROP_FILE_NAME || name == PROP_DIRECTORY_NAME || name == PROP_ROOTS) {
myCount++;
}
}
}, project);
}
@Override
public long getModificationCount() {
return myCount;
public static Object[] getDependencies(@NotNull Project project) {
return new Object[]{OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, ProjectRootModificationTracker.getInstance(project)};
}
}
@@ -137,7 +137,7 @@ public class PsiJavaModuleReference extends PsiReferenceBase.Poly<PsiJavaModuleR
public Result<PsiJavaModule> compute(Pair<String, Boolean> p) {
Collection<PsiJavaModule> modules = Resolver.findModules(refOwner.getContainingFile(), p.first, p.second);
PsiJavaModule module = modules.size() == 1 ? modules.iterator().next() : null;
return Result.create(module, JavaModuleFileChangeTracker.getInstance(refOwner.getProject()));
return Result.create(module, JavaModuleFileChangeTracker.getDependencies(refOwner.getProject()));
}
}, false, pair(refText, incompleteCode));
}
+1
View File
@@ -3,6 +3,7 @@ automaton.jar
cglib-nodep-3.2.4.jar
cli-parser-1.1.jar
commons-codec-1.9.jar
commons-compress-1.10.jar
commons-httpclient-3.1-patched.jar
commons-logging-1.2.jar
commons-net-3.3.jar
@@ -23,13 +23,11 @@ import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.ex.RangeHighlighterEx;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.TransferToEDTQueue;
import gnu.trove.THashMap;
@@ -47,6 +45,8 @@ public class HighlightingSessionImpl implements HighlightingSession {
@NotNull private final Project myProject;
private final Document myDocument;
private final Map<TextRange,RangeMarker> myRanges2markersCache = new THashMap<>();
private final TransferToEDTQueue<Info> myAddHighlighterInEDTQueue;
private final TransferToEDTQueue<RangeHighlighterEx> myDisposeHighlighterInEDTQueue;
private HighlightingSessionImpl(@NotNull PsiFile psiFile,
@Nullable Editor editor,
@@ -58,6 +58,18 @@ public class HighlightingSessionImpl implements HighlightingSession {
myEditorColorsScheme = editorColorsScheme;
myProject = psiFile.getProject();
myDocument = PsiDocumentManager.getInstance(myProject).getDocument(psiFile);
myDisposeHighlighterInEDTQueue = new TransferToEDTQueue<>("Dispose abandoned highlighter", highlighter -> {
highlighter.dispose();
return true;
}, o -> myProject.isDisposed() || getProgressIndicator().isCanceled(), 200);
myAddHighlighterInEDTQueue = new TransferToEDTQueue<>("Apply highlighting results", info -> {
final EditorColorsScheme colorsScheme = getColorsScheme();
UpdateHighlightersUtil.addHighlighterToEditorIncrementally(myProject, getDocument(), getPsiFile(), info.myRestrictRange.getStartOffset(),
info.myRestrictRange.getEndOffset(),
info.myInfo, colorsScheme, info.myGroupId, myRanges2markersCache);
return true;
}, o -> myProject.isDisposed() || getProgressIndicator().isCanceled(), 200);
}
private static final Key<ConcurrentMap<PsiFile, HighlightingSession>> HIGHLIGHTING_SESSION = Key.create("HIGHLIGHTING_SESSION");
@@ -119,39 +131,6 @@ public class HighlightingSessionImpl implements HighlightingSession {
return myEditorColorsScheme;
}
private final TransferToEDTQueue<Info> myAddHighlighterInEDTQueue =
new TransferToEDTQueue<>("Apply highlighting results", new Processor<Info>() {
@Override
public boolean process(Info info) {
final EditorColorsScheme colorsScheme = getColorsScheme();
UpdateHighlightersUtil
.addHighlighterToEditorIncrementally(myProject, getDocument(), getPsiFile(), info.myRestrictRange.getStartOffset(),
info.myRestrictRange.getEndOffset(),
info.myInfo, colorsScheme, info.myGroupId, myRanges2markersCache);
return true;
}
}, new Condition<Object>() {
@Override
public boolean value(Object o) {
return myProject.isDisposed() || getProgressIndicator().isCanceled();
}
}, 200);
private final TransferToEDTQueue<RangeHighlighterEx> myDisposeHighlighterInEDTQueue =
new TransferToEDTQueue<>("Dispose abandoned highlighter", new Processor<RangeHighlighterEx>() {
@Override
public boolean process(@NotNull RangeHighlighterEx highlighter) {
highlighter.dispose();
return true;
}
}, new Condition<Object>() {
@Override
public boolean value(Object o) {
return myProject.isDisposed() || getProgressIndicator().isCanceled();
}
}, 200);
void queueHighlightInfo(@NotNull HighlightInfo info,
@NotNull TextRange priorityRange,
@NotNull TextRange restrictedRange,
@@ -17,6 +17,7 @@
package com.intellij.codeInsight.daemon.impl;
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.progress.ProgressIndicator;
@@ -151,8 +152,16 @@ public abstract class ProgressableTextEditorHighlightingPass extends TextEditorH
}
}
void waitForHighlightInfosApplied() {
ApplicationManager.getApplication().assertIsDispatchThread();
HighlightingSessionImpl session = (HighlightingSessionImpl)myHighlightingSession;
if (session != null) {
session.waitForHighlightInfosApplied();
}
}
static class EmptyPass extends TextEditorHighlightingPass {
public EmptyPass(final Project project, @Nullable final Document document) {
EmptyPass(final Project project, @Nullable final Document document) {
super(project, document, false);
}
@@ -64,6 +64,8 @@ class CommunityLibraryLicenses {
license: "Apache 2.0", url: "http://hc.apache.org/httpclient-3.x"),
new LibraryLicense(name: "Apache Commons IO", libraryName: "commons-io-1.4.jar", version: "1.4", license: "Apache 2.0",
url: "http://commons.apache.org/io/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt"),
new LibraryLicense(name: "Apache Commons Lang", libraryName: "commons-lang", version: "2.6", license: "Apache 2.0",
licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "http://commons.apache.org/proper/commons-lang/"),
new LibraryLicense(name: "Apache Commons Lang 3", libraryName: "commons-lang3-3.2.1.jar", version: "3.2.1", license: "Apache 2.0",
licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.txt", url: "http://commons.apache.org/proper/commons-lang/"),
new LibraryLicense(name: "Apache Commons Logging", libraryName: "commons-logging", version: "1.1.1", license: "Apache 2.0",
@@ -15,7 +15,6 @@
*/
package com.intellij.codeInsight.hints
import com.intellij.lang.Language
import com.intellij.lang.LanguageExtension
import com.intellij.psi.PsiElement
import org.jetbrains.annotations.ApiStatus
@@ -36,13 +35,7 @@ interface InlayParameterHintsProvider {
* and selects "Do not show for this method".
*/
fun getMethodInfo(element: PsiElement): MethodInfo? = null
/**
* Language used when saving blacklist methods
* Maybe will be moved to MethodInfo
*/
val language: Language
/**
* Default list of methods for which hints should not be shown
*/
@@ -33,7 +33,6 @@ import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.util.Alarm;
import com.intellij.util.Processor;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -517,6 +517,9 @@ class PassExecutorService implements Disposable {
throw new RuntimeException(message, e);
}
if (threadsToStartCountdown.decrementAndGet() == 0) {
if (pass instanceof ProgressableTextEditorHighlightingPass) {
((ProgressableTextEditorHighlightingPass)pass).waitForHighlightInfosApplied();
}
log(updateProgress, pass, "Stopping ");
updateProgress.stopIfRunning();
}
@@ -543,7 +546,7 @@ class PassExecutorService implements Disposable {
}
private static void sortById(@NotNull List<TextEditorHighlightingPass> result) {
ContainerUtil.quickSort(result, (o1, o2) -> o1.getId() - o2.getId());
ContainerUtil.quickSort(result, Comparator.comparingInt(TextEditorHighlightingPass::getId));
}
private static int getThreadNum() {
@@ -22,7 +22,9 @@ import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar;
import com.intellij.codeInsight.daemon.impl.ParameterHintsPresentationManager;
import com.intellij.codeInsight.hints.filtering.Matcher;
import com.intellij.codeInsight.hints.filtering.MatcherConstructor;
import com.intellij.codeInsight.hints.settings.Diff;
import com.intellij.codeInsight.hints.settings.ParameterNameHintsSettings;
import com.intellij.lang.Language;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
@@ -71,12 +73,14 @@ public class ParameterHintsPassFactory extends AbstractProjectComponent implemen
myAnnotations.clear();
if (!isEnabled()) return;
InlayParameterHintsProvider provider = InlayParameterHintsExtension.INSTANCE.forLanguage(myFile.getLanguage());
Language language = myFile.getLanguage();
InlayParameterHintsProvider provider = InlayParameterHintsExtension.INSTANCE.forLanguage(language);
if (provider == null) return;
List<Matcher> matchers = ParameterNameHintsSettings
.getInstance()
.getIgnorePatternSet(provider)
Diff diff = ParameterNameHintsSettings.getInstance().getBlackListDiff(language);
Set<String> blackList = diff.applyOn(provider.getDefaultBlackList());
List<Matcher> matchers = blackList
.stream()
.map((item) -> MatcherConstructor.INSTANCE.createMatcher(item))
.collect(Collectors.toList());
@@ -50,7 +50,7 @@ class ShowParameterHintsSettings : AnAction() {
val project = CommonDataKeys.PROJECT.getData(e.dataContext) ?: return
val file = CommonDataKeys.PSI_FILE.getData(e.dataContext) ?: return
val hintExtension = InlayParameterHintsExtension.forLanguage(file.language) ?: return
val dialog = ParameterNameHintsConfigurable(project, hintExtension)
val dialog = ParameterNameHintsConfigurable(project, hintExtension.defaultBlackList, file.language)
dialog.show()
}
}
@@ -15,8 +15,8 @@
*/
package com.intellij.codeInsight.hints.settings;
import com.intellij.codeInsight.hints.InlayParameterHintsProvider;
import com.intellij.codeInsight.hints.filtering.MatcherConstructor;
import com.intellij.lang.Language;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
@@ -38,12 +38,16 @@ import java.util.stream.Collectors;
public class ParameterNameHintsConfigurable extends DialogWrapper {
private final Project myProject;
private final InlayParameterHintsProvider myHintsProvider;
public ParameterNameHintsConfigurable(@NotNull Project project, @NotNull InlayParameterHintsProvider provider) {
private final Set<String> myDefaultBlackList;
private final Language myLanguage;
public ParameterNameHintsConfigurable(@NotNull Project project,
@NotNull Set<String> defaultBlackList,
@NotNull Language language) {
super(project);
myProject = project;
myHintsProvider = provider;
myDefaultBlackList = defaultBlackList;
myLanguage = language;
setTitle("Configure Parameter Name Hints Blacklist");
init();
}
@@ -70,7 +74,8 @@ public class ParameterNameHintsConfigurable extends DialogWrapper {
.filter((e) -> !e.trim().isEmpty())
.collect(Collectors.toSet());
ParameterNameHintsSettings.getInstance().setIgnorePatternSet(myHintsProvider, updatedBlackList);
Diff diff = Diff.Builder.build(myDefaultBlackList, updatedBlackList);
ParameterNameHintsSettings.getInstance().setBlackListDiff(myLanguage, diff);
}
@Nullable
@@ -85,10 +90,11 @@ public class ParameterNameHintsConfigurable extends DialogWrapper {
private void createUIComponents() {
EditorTextFieldProvider service = ServiceManager.getService(myProject, EditorTextFieldProvider.class);
myEditorTextField = service.getEditorField(PlainTextLanguage.INSTANCE, myProject, ContainerUtil.emptyIterable());
Set<String> blacklist = ParameterNameHintsSettings.getInstance().getIgnorePatternSet(myHintsProvider);
Diff diff = ParameterNameHintsSettings.getInstance().getBlackListDiff(myLanguage);
Set<String> blacklist = diff.applyOn(myDefaultBlackList);
String text = StringUtil.join(blacklist, "\n");
myEditorTextField.setText(text);
myEditorTextField.addDocumentListener(new DocumentAdapter() {
@Override
@@ -1,6 +1,5 @@
package com.intellij.codeInsight.hints.settings
import com.intellij.codeInsight.hints.InlayParameterHintsProvider
import com.intellij.lang.Language
import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.State
@@ -19,11 +18,52 @@ private object XmlTagHelper {
}
class Diff(val added: Set<String>, val removed: Set<String>) {
fun applyOn(base: Set<String>): Set<String> {
val baseSet = base.toMutableSet()
added.forEach { baseSet.add(it) }
removed.forEach { baseSet.remove(it) }
return baseSet
}
companion object Builder {
fun build(base: Set<String>, updated: Set<String>): Diff {
val removed = base.toMutableSet()
removed.removeAll(updated)
val added = updated.toMutableSet()
added.removeAll(base)
return Diff(added, removed)
}
}
}
@State(name = "ParameterNameHintsSettings", storages = arrayOf(Storage("parameter.hints.xml")))
class ParameterNameHintsSettings : PersistentStateComponent<Element> {
private val myRemovedPatterns = hashMapOf<String, List<String>>()
private val myAddedPatterns = hashMapOf<String, List<String>>()
private val myRemovedPatterns = hashMapOf<String, Set<String>>()
private val myAddedPatterns = hashMapOf<String, Set<String>>()
fun addIgnorePattern(language: Language, pattern: String) {
val patternsBefore = getAddedPatterns(language)
setAddedPatterns(language, patternsBefore + pattern)
}
fun getBlackListDiff(language: Language): Diff {
val added = getAddedPatterns(language)
val removed = getRemovedPatterns(language)
return Diff(added, removed)
}
fun setBlackListDiff(language: Language, diff: Diff) {
setAddedPatterns(language, diff.added)
setRemovedPatterns(language, diff.removed)
}
override fun getState(): Element {
val root = Element("settings")
val blacklists = root.getOrCreateChild(XmlTagHelper.BLACKLISTS)
@@ -47,73 +87,43 @@ class ParameterNameHintsSettings : PersistentStateComponent<Element> {
myRemovedPatterns[language] = it.extractPatterns(XmlTagHelper.REMOVED)
}
}
fun addIgnorePattern(language: Language, pattern: String) {
val patternsBefore = getAddedPatterns(language)
setAddedPatterns(language, patternsBefore + pattern)
}
fun getIgnorePatternSet(hintsProvider: InlayParameterHintsProvider): Set<String> {
val added = getAddedPatterns(hintsProvider.language)
val removed = getRemovedPatterns(hintsProvider.language)
val updated = hintsProvider.defaultBlackList.toMutableSet()
updated.removeAll(removed)
updated.addAll(added)
return updated
}
fun setIgnorePatternSet(provider: InlayParameterHintsProvider, updatedBlackList: Set<String>) {
val defaultBlackList = provider.defaultBlackList
val removed = defaultBlackList.toMutableSet()
removed.removeAll(updatedBlackList)
val added = updatedBlackList.toMutableSet()
added.removeAll(defaultBlackList)
val language = provider.language
setRemovedPatterns(language, removed)
setAddedPatterns(language, added)
}
companion object {
@JvmStatic
fun getInstance() = service<ParameterNameHintsSettings>()
}
private fun getAddedPatterns(language: Language): List<String> {
private fun getAddedPatterns(language: Language): Set<String> {
val key = language.displayName
return myAddedPatterns[key] ?: emptyList()
return myAddedPatterns[key] ?: emptySet()
}
private fun getRemovedPatterns(language: Language): List<String> {
private fun getRemovedPatterns(language: Language): Set<String> {
val key = language.displayName
return myRemovedPatterns[key] ?: emptyList()
return myRemovedPatterns[key] ?: emptySet()
}
private fun setRemovedPatterns(language: Language, removed: Collection<String>) {
private fun setRemovedPatterns(language: Language, removed: Set<String>) {
val key = language.displayName
myRemovedPatterns[key] = removed.toList()
myRemovedPatterns[key] = removed
}
private fun setAddedPatterns(language: Language, added: Collection<String>) {
private fun setAddedPatterns(language: Language, added: Set<String>) {
val key = language.displayName
myAddedPatterns[key] = added.toList()
myAddedPatterns[key] = added
}
}
private fun Element.addLanguagePatternElements(language: String, patterns: List<String>, tag: String) {
private fun Element.addLanguagePatternElements(language: String, patterns: Set<String>, tag: String) {
val list = getOrCreateChild(XmlTagHelper.LANGUAGE_LIST)
list.setAttribute(XmlTagHelper.LANGUAGE, language)
val elements = patterns.map { it.toPatternElement(tag) }
list.addContent(elements)
}
private fun Element.extractPatterns(tag: String): List<String> {
return getChildren(tag).mapNotNull { it.attributeValue(XmlTagHelper.PATTERN) }
private fun Element.extractPatterns(tag: String): Set<String> {
return getChildren(tag).mapNotNull { it.attributeValue(XmlTagHelper.PATTERN) }.toSet()
}
private fun Element.attributeValue(attr: String): String? = this.getAttribute(attr)?.value
@@ -24,6 +24,7 @@ import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.refactoring.rename.inplace.InplaceRefactoring;
import com.intellij.ui.JBColor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FList;
@@ -52,11 +53,14 @@ class LookupPreview {
myInlays.clear();
String suffix = getSuffixText(item);
if (!suffix.isEmpty() && myLookup.getTopLevelEditor() instanceof EditorImpl) {
myLookup.getTopLevelEditor().getCaretModel().runForEachCaret(caret -> {
Editor editor = myLookup.getTopLevelEditor();
if (!suffix.isEmpty() && editor instanceof EditorImpl &&
!editor.getSelectionModel().hasSelection() &&
InplaceRefactoring.getActiveInplaceRenamer(editor) == null) {
for (Caret caret : editor.getCaretModel().getAllCarets()) {
ensureCaretBeforeInlays(caret);
addInlay(suffix, caret.getOffset());
});
}
}
}
@@ -47,7 +47,7 @@ public class CommonFindUsagesDialog extends AbstractFindUsagesDialog {
boolean isSingleFile,
@NotNull FindUsagesHandler handler) {
super(project, findUsagesOptions, toShowInNewTab, mustOpenInNewTab, isSingleFile, isTextSearch(element, isSingleFile, handler),
!isSingleFile && !element.getManager().isInProject(element));
true);
myPsiElement = element;
myHelpId = ObjectUtils.chooseNotNull(handler.getHelpId(), HelpID.FIND_OTHER_USAGES);
init();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 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.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide.ui.search;
import com.intellij.application.options.OptionsContainingConfigurable;
@@ -34,31 +33,30 @@ import com.intellij.openapi.options.UnnamedConfigurable;
import com.intellij.openapi.options.ex.ConfigurableWrapper;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.io.FileUtil;
import org.jdom.Document;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import java.util.*;
/**
* Used by Installer's build buildSearchableOptions step. In order to run locally use TraverseUi configuration.
* Pass corresponding -Didea.platform.prefix=YOUR_IDE_PREFIX to vm options and choose main_YOUR_IDE module
* Used in installer's "build searchable options" step.
*
* In order to run locally, use "TraverseUi" run configuration (pass corresponding "idea.platform.prefix" property via VM options,
* and choose correct main module).
*/
@SuppressWarnings({"CallToPrintStackTrace", "SynchronizeOnThis"})
@SuppressWarnings({"CallToPrintStackTrace", "SynchronizeOnThis", "UseOfSystemOutOrSystemErr"})
public class TraverseUIStarter extends ApplicationStarterEx {
@NonNls private static final String OPTIONS = "options";
@NonNls private static final String CONFIGURABLE = "configurable";
@NonNls private static final String ID = "id";
@NonNls private static final String CONFIGURABLE_NAME = "configurable_name";
@NonNls private static final String OPTION = "option";
@NonNls private static final String NAME = "name";
@NonNls private static final String PATH = "path";
@NonNls private static final String HIT = "hit";
private static final String OPTIONS = "options";
private static final String CONFIGURABLE = "configurable";
private static final String ID = "id";
private static final String CONFIGURABLE_NAME = "configurable_name";
private static final String OPTION = "option";
private static final String NAME = "name";
private static final String PATH = "path";
private static final String HIT = "hit";
private String OUTPUT_PATH;
@@ -68,7 +66,6 @@ public class TraverseUIStarter extends ApplicationStarterEx {
}
@Override
@NonNls
public String getCommandName() {
return "traverseUI";
}
@@ -79,7 +76,7 @@ public class TraverseUIStarter extends ApplicationStarterEx {
}
@Override
public void main(String[] args){
public void main(String[] args) {
System.out.println("Starting searchable options index builder");
try {
startup(OUTPUT_PATH);
@@ -93,52 +90,54 @@ public class TraverseUIStarter extends ApplicationStarterEx {
}
public static void startup(String outputPath) throws IOException {
final HashMap<SearchableConfigurable, TreeSet<OptionDescription>> options =
new HashMap<>();
Map<SearchableConfigurable, Set<OptionDescription>> options = new HashMap<>();
SearchUtil.processProjectConfigurables(ProjectManager.getInstance().getDefaultProject(), options);
Element root = new Element(OPTIONS);
for (SearchableConfigurable configurable : options.keySet()) {
for (SearchableConfigurable option : options.keySet()) {
SearchableConfigurable configurable = option;
Element configurableElement = new Element(CONFIGURABLE);
final String id = configurable.getId();
if (id == null) continue;
String id = configurable.getId();
configurableElement.setAttribute(ID, id);
configurableElement.setAttribute(CONFIGURABLE_NAME, configurable.getDisplayName());
final TreeSet<OptionDescription> sortedOptions = options.get(configurable);
Set<OptionDescription> sortedOptions = options.get(configurable);
writeOptions(configurableElement, sortedOptions);
if (configurable instanceof ConfigurableWrapper) {
final UnnamedConfigurable wrapped = ((ConfigurableWrapper)configurable).getConfigurable();
UnnamedConfigurable wrapped = ((ConfigurableWrapper)configurable).getConfigurable();
if (wrapped instanceof SearchableConfigurable) {
configurable = (SearchableConfigurable)wrapped;
}
}
if (configurable instanceof KeymapPanel){
if (configurable instanceof KeymapPanel) {
processKeymap(configurableElement);
} else if (configurable instanceof OptionsContainingConfigurable){
}
else if (configurable instanceof OptionsContainingConfigurable) {
processOptionsContainingConfigurable((OptionsContainingConfigurable)configurable, configurableElement);
} else if (configurable instanceof PluginManagerConfigurable) {
final TreeSet<OptionDescription> descriptions = wordsToOptionDescriptors(Collections.singleton(AvailablePluginsManagerMain.MANAGE_REPOSITORIES));
for (OptionDescription description : descriptions) {
}
else if (configurable instanceof PluginManagerConfigurable) {
for (OptionDescription description : wordsToOptionDescriptors(Collections.singleton(AvailablePluginsManagerMain.MANAGE_REPOSITORIES))) {
append(null, AvailablePluginsManagerMain.MANAGE_REPOSITORIES, description.getOption(), configurableElement);
}
} else if (configurable instanceof AllFileTemplatesConfigurable) {
}
else if (configurable instanceof AllFileTemplatesConfigurable) {
processFileTemplates(configurableElement);
}
root.addContent(configurableElement);
configurable.disposeUIResources();
}
final File file = new File(outputPath);
if (!file.isFile()) {
file.getParentFile().mkdirs();
file.createNewFile();
}
FileUtil.ensureCanCreateFile(new File(outputPath));
JDOMUtil.writeDocument(new Document(root), outputPath, "\n");
System.out.println("Searchable options index builder completed");
}
private static void processFileTemplates(Element configurableElement) {
final SearchableOptionsRegistrar optionsRegistrar = SearchableOptionsRegistrar.getInstance();
TreeSet<OptionDescription> options = new TreeSet<>();
SearchableOptionsRegistrar optionsRegistrar = SearchableOptionsRegistrar.getInstance();
Set<OptionDescription> options = new TreeSet<>();
FileTemplateManager fileTemplateManager = FileTemplateManager.getDefaultInstance();
processTemplates(optionsRegistrar, options, fileTemplateManager.getAllTemplates());
@@ -149,45 +148,30 @@ public class TraverseUIStarter extends ApplicationStarterEx {
writeOptions(configurableElement, options);
}
private static void processTemplates(SearchableOptionsRegistrar optionsRegistrar,
TreeSet<OptionDescription> options,
FileTemplate[] templates) {
private static void processTemplates(SearchableOptionsRegistrar registrar, Set<OptionDescription> options, FileTemplate[] templates) {
for (FileTemplate template : templates) {
collectOptions(optionsRegistrar, options, template.getName());
//collectOptions(optionsRegistrar, options, template.getDescription());
collectOptions(registrar, options, template.getName(), null);
}
}
private static void collectOptions(SearchableOptionsRegistrar optionsRegistrar,
TreeSet<OptionDescription> options,
String text) {
collectOptions(optionsRegistrar, options, text, null);
}
private static void collectOptions(SearchableOptionsRegistrar optionsRegistrar,
TreeSet<OptionDescription> options,
String text,
String path) {
final Set<String> strings = optionsRegistrar.getProcessedWordsWithoutStemming(text);
for (String word : strings) {
private static void collectOptions(SearchableOptionsRegistrar registrar, Set<OptionDescription> options, String text, String path) {
for (String word : registrar.getProcessedWordsWithoutStemming(text)) {
options.add(new OptionDescription(word, text, path));
}
}
private static void processOptionsContainingConfigurable(final OptionsContainingConfigurable configurable,
final Element configurableElement) {
final Set<String> optionsPath = configurable.processListOptions();
final TreeSet<OptionDescription> result = wordsToOptionDescriptors(optionsPath);
private static void processOptionsContainingConfigurable(OptionsContainingConfigurable configurable, Element configurableElement) {
Set<String> optionsPath = configurable.processListOptions();
Set<OptionDescription> result = wordsToOptionDescriptors(optionsPath);
writeOptions(configurableElement, result);
}
private static TreeSet<OptionDescription> wordsToOptionDescriptors(Set<String> optionsPath) {
SearchableOptionsRegistrar searchableOptionsRegistrar = SearchableOptionsRegistrar.getInstance();
final TreeSet<OptionDescription> result = new TreeSet<>();
private static Set<OptionDescription> wordsToOptionDescriptors(Set<String> optionsPath) {
SearchableOptionsRegistrar registrar = SearchableOptionsRegistrar.getInstance();
Set<OptionDescription> result = new TreeSet<>();
for (String opt : optionsPath) {
final Set<String> words = searchableOptionsRegistrar.getProcessedWordsWithoutStemming(opt);
for (String word : words) {
if (word != null){
for (String word : registrar.getProcessedWordsWithoutStemming(opt)) {
if (word != null) {
result.add(new OptionDescription(word, opt, null));
}
}
@@ -195,7 +179,7 @@ public class TraverseUIStarter extends ApplicationStarterEx {
return result;
}
private static void processKeymap(final Element configurableElement){
private static void processKeymap(Element configurableElement) {
final ActionManager actionManager = ActionManager.getInstance();
final String componentName = actionManager.getComponentName();
final SearchableOptionsRegistrar searchableOptionsRegistrar = SearchableOptionsRegistrar.getInstance();
@@ -215,7 +199,7 @@ public class TraverseUIStarter extends ApplicationStarterEx {
writeOptions(configurableElement, options);
}
private static void writeOptions(Element configurableElement, TreeSet<OptionDescription> options) {
private static void writeOptions(Element configurableElement, Set<OptionDescription> options) {
for (OptionDescription opt : options) {
append(opt.getPath(), opt.getHit(), opt.getOption(), configurableElement);
}
@@ -230,4 +214,4 @@ public class TraverseUIStarter extends ApplicationStarterEx {
optionElement.setAttribute(HIT, hit);
configurableElement.addContent(optionElement);
}
}
}
@@ -16,14 +16,12 @@
package com.intellij.codeInsight.hints.settings
import com.intellij.codeInsight.hints.InlayParameterHintsProvider
import com.intellij.lang.Language
import com.intellij.openapi.fileTypes.PlainTextLanguage
import junit.framework.TestCase
class MockInlayProvider(override val defaultBlackList: Set<String>): InlayParameterHintsProvider {
override val language: Language = PlainTextLanguage.INSTANCE
}
class MockInlayProvider(override val defaultBlackList: Set<String>): InlayParameterHintsProvider
class ParameterNameSettingsTest : TestCase() {
@@ -40,14 +38,20 @@ class ParameterNameSettingsTest : TestCase() {
}
fun addIgnorePattern(newPattern: String) {
settings.addIgnorePattern(inlayProvider.language, newPattern)
settings.addIgnorePattern(PlainTextLanguage.INSTANCE, newPattern)
}
fun setIgnorePattern(vararg newPatternSet: String) {
settings.setIgnorePatternSet(inlayProvider, setOf(*newPatternSet))
val base = inlayProvider.defaultBlackList
val diff = Diff.build(base, setOf(*newPatternSet))
settings.setBlackListDiff(PlainTextLanguage.INSTANCE, diff)
}
fun getIgnoreSet(): Set<String> = settings.getIgnorePatternSet(inlayProvider)
fun getIgnoreSet(): Set<String> {
val diff = settings.getBlackListDiff(PlainTextLanguage.INSTANCE)
return diff.applyOn(inlayProvider.defaultBlackList)
}
fun `test ignore pattern is added`() {
defaultSettingsUpdated("xxx")
@@ -165,12 +165,26 @@ public class JBViewport extends JViewport implements ZoomableViewport {
@Override
public void scrollRectToVisible(Rectangle bounds) {
Component view = getView();
if (view instanceof JComponent) {
if (view instanceof JComponent && !isAutoscroll(bounds)) {
JBInsets.addTo(bounds, getViewInsets((JComponent)view));
}
super.scrollRectToVisible(bounds);
}
private boolean isAutoscroll(Rectangle bounds) {
if (bounds.x == -bounds.width || bounds.x == getWidth()) {
if (bounds.y + bounds.height + bounds.y == getHeight()) {
return true;
}
}
if (bounds.y == -bounds.height || bounds.y == getHeight()) {
if (bounds.x + bounds.width + bounds.x == getWidth()) {
return true;
}
}
return false;
}
/**
* Returns the alignment of the specified scroll bar
* if and only if the specified scroll bar
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 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.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide.ui.search;
import com.intellij.application.options.SkipSelfSearchComponent;
@@ -24,15 +23,12 @@ import com.intellij.openapi.options.MasterDetails;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.options.ex.GlassPanel;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.*;
import com.intellij.ui.components.JBList;
import com.intellij.util.Alarm;
import com.intellij.util.Consumer;
import com.intellij.ui.JBColor;
import com.intellij.ui.SimpleColoredComponent;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.TabbedPaneWrapper;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,36 +36,32 @@ import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* User: anna
* Date: 07-Feb-2006
* @author anna
* @since 07.02.2006
*/
public class SearchUtil {
private static final Pattern HTML_PATTERN = Pattern.compile("<[^<>]*>");
private static final Pattern QUOTED = Pattern.compile("\\\"([^\\\"]+)\\\"");
private static final Pattern QUOTED = Pattern.compile("\"([^\"]+)\"");
public static final String HIGHLIGHT_WITH_BORDER = "searchUtil.highlightWithBorder";
public static final String STYLE_END = "</style>";
private SearchUtil() {
}
private SearchUtil() { }
public static void processProjectConfigurables(Project project, HashMap<SearchableConfigurable, TreeSet<OptionDescription>> options) {
public static void processProjectConfigurables(Project project, Map<SearchableConfigurable, Set<OptionDescription>> options) {
processConfigurables(ShowSettingsUtilImpl.getConfigurables(project, false), options);
}
private static void processConfigurables(final Configurable[] configurables,
final HashMap<SearchableConfigurable, TreeSet<OptionDescription>> options) {
private static void processConfigurables(Configurable[] configurables, Map<SearchableConfigurable, Set<OptionDescription>> options) {
for (Configurable configurable : configurables) {
if (configurable instanceof SearchableConfigurable) {
TreeSet<OptionDescription> configurableOptions = new TreeSet<>();
Set<OptionDescription> configurableOptions = new TreeSet<>();
if (configurable instanceof Configurable.Composite) {
final Configurable[] children = ((Configurable.Composite)configurable).getConfigurables();
@@ -86,26 +78,24 @@ public class SearchUtil {
if (configurable instanceof MasterDetails) {
final MasterDetails md = (MasterDetails)configurable;
md.initUi();
_processComponent(configurable, configurableOptions, md.getMaster());
_processComponent(configurable, configurableOptions, md.getDetails().getComponent());
processComponent(configurable, configurableOptions, md.getMaster());
processComponent(configurable, configurableOptions, md.getDetails().getComponent());
}
else {
_processComponent(configurable, configurableOptions, configurable.createComponent());
processComponent(configurable, configurableOptions, configurable.createComponent());
}
}
}
}
private static void _processComponent(final Configurable configurable, final TreeSet<OptionDescription> configurableOptions,
final JComponent component) {
if (component == null) return;
processUILabel(configurable.getDisplayName(), configurableOptions, null);
processComponent(component, configurableOptions, null);
private static void processComponent(Configurable configurable, Set<OptionDescription> configurableOptions, JComponent component) {
if (component != null) {
processUILabel(configurable.getDisplayName(), configurableOptions, null);
processComponent(component, configurableOptions, null);
}
}
public static void processComponent(final JComponent component, final Set<OptionDescription> configurableOptions, @NonNls String path) {
private static void processComponent(JComponent component, Set<OptionDescription> configurableOptions, String path) {
if (component instanceof SkipSelfSearchComponent) return;
final Border border = component.getBorder();
if (border instanceof TitledBorder) {
@@ -122,19 +112,19 @@ public class SearchUtil {
}
}
else if (component instanceof JCheckBox) {
@NonNls final String checkBoxTitle = ((JCheckBox)component).getText();
final String checkBoxTitle = ((JCheckBox)component).getText();
if (checkBoxTitle != null) {
processUILabel(checkBoxTitle, configurableOptions, path);
}
}
else if (component instanceof JRadioButton) {
@NonNls final String radioButtonTitle = ((JRadioButton)component).getText();
final String radioButtonTitle = ((JRadioButton)component).getText();
if (radioButtonTitle != null) {
processUILabel(radioButtonTitle, configurableOptions, path);
}
}
else if (component instanceof JButton) {
@NonNls final String buttonTitle = ((JButton)component).getText();
final String buttonTitle = ((JButton)component).getText();
if (buttonTitle != null) {
processUILabel(buttonTitle, configurableOptions, path);
}
@@ -163,18 +153,15 @@ public class SearchUtil {
}
}
private static void processUILabel(@NonNls final String title, final Set<OptionDescription> configurableOptions, String path) {
private static void processUILabel(String title, Set<OptionDescription> configurableOptions, String path) {
final Set<String> words = SearchableOptionsRegistrar.getInstance().getProcessedWordsWithoutStemming(title);
@NonNls final String regex = "[\\W&&[^\\p{Punct}\\p{Blank}]]";
final String regex = "[\\W&&[^\\p{Punct}\\p{Blank}]]";
for (String option : words) {
configurableOptions.add(new OptionDescription(option, HTML_PATTERN.matcher(title).replaceAll(" ").replaceAll(regex, " "), path));
}
}
public static Runnable lightOptions(final SearchableConfigurable configurable,
final JComponent component,
final String option,
final GlassPanel glassPanel) {
public static Runnable lightOptions(SearchableConfigurable configurable, JComponent component, String option, GlassPanel glassPanel) {
return () -> {
if (!traverseComponentsTree(configurable, glassPanel, component, option, true)) {
traverseComponentsTree(configurable, glassPanel, component, option, false);
@@ -191,7 +178,8 @@ public class SearchUtil {
final Set<String> titleWords = searchableOptionsRegistrar.getProcessedWords(title);
pathWords.removeAll(titleWords);
if (pathWords.isEmpty()) return i;
} else if (tabIdx.equalsIgnoreCase(title)) { //e.g. only stop words
}
else if (tabIdx.equalsIgnoreCase(title)) { //e.g. only stop words
return i;
}
}
@@ -210,12 +198,11 @@ public class SearchUtil {
return -1;
}
private static boolean traverseComponentsTree(final SearchableConfigurable configurable,
private static boolean traverseComponentsTree(SearchableConfigurable configurable,
GlassPanel glassPanel,
JComponent rootComponent,
String option,
boolean force) {
rootComponent.putClientProperty(HIGHLIGHT_WITH_BORDER, null);
if (option == null || option.trim().length() == 0) return false;
@@ -271,7 +258,6 @@ public class SearchUtil {
}
}
final Component[] components = rootComponent.getComponents();
for (Component component : components) {
if (component instanceof JComponent) {
@@ -298,20 +284,19 @@ public class SearchUtil {
return highlight;
}
public static boolean isComponentHighlighted(String text, String option, final boolean force, final SearchableConfigurable configurable) {
public static boolean isComponentHighlighted(String text, String option, boolean force, final SearchableConfigurable configurable) {
if (text == null || option == null || option.length() == 0) return false;
final SearchableOptionsRegistrar searchableOptionsRegistrar = SearchableOptionsRegistrar.getInstance();
final Set<String> words = searchableOptionsRegistrar.getProcessedWords(option);
final Set<String> options =
configurable != null ? searchableOptionsRegistrar.replaceSynonyms(words, configurable) : words;
final Set<String> options = configurable != null ? searchableOptionsRegistrar.replaceSynonyms(words, configurable) : words;
if (options == null || options.isEmpty()) {
return text.toLowerCase().indexOf(option.toLowerCase()) != -1;
return text.toLowerCase(Locale.US).contains(option.toLowerCase(Locale.US));
}
final Set<String> tokens = searchableOptionsRegistrar.getProcessedWords(text);
if (!force) {
options.retainAll(tokens);
final boolean highlight = !options.isEmpty();
return highlight || text.toLowerCase().indexOf(option.toLowerCase()) != -1;
return highlight || text.toLowerCase(Locale.US).contains(option.toLowerCase(Locale.US));
}
else {
options.removeAll(tokens);
@@ -319,7 +304,7 @@ public class SearchUtil {
}
}
public static String markup(@NonNls @NotNull String textToMarkup, @Nullable String filter) {
public static String markup(@NotNull String textToMarkup, @Nullable String filter) {
if (filter == null || filter.length() == 0) {
return textToMarkup;
}
@@ -332,11 +317,13 @@ public class SearchUtil {
head = textToMarkup.substring(0, bodyStart);
if (bodyEnd >= 0) {
foot = textToMarkup.substring(bodyEnd);
} else {
}
else {
foot = "";
}
textToMarkup = textToMarkup.substring(bodyStart, bodyEnd);
} else {
}
else {
foot = "";
head = "";
}
@@ -360,7 +347,7 @@ public class SearchUtil {
private static String quoteStrictOccurrences(final String textToMarkup, final String filter) {
String cur = "";
final String s = textToMarkup.toLowerCase();
final String s = textToMarkup.toLowerCase(Locale.US);
for (String part : filter.split(" ")) {
if (s.contains(part)) {
cur += "\"" + part + "\" ";
@@ -372,13 +359,14 @@ public class SearchUtil {
return cur;
}
private static String markup(@NonNls String textToMarkup, final Pattern insideHtmlTagPattern, final String option) {
private static String markup(String textToMarkup, final Pattern insideHtmlTagPattern, final String option) {
final int styleIdx = textToMarkup.indexOf("<style");
final int styleEndIdx = textToMarkup.indexOf("</style>");
if (styleIdx < 0 || styleEndIdx < 0) {
return markupInText(textToMarkup, insideHtmlTagPattern, option);
}
return markup(textToMarkup.substring(0, styleIdx), insideHtmlTagPattern, option) + markup(textToMarkup.substring(styleEndIdx + STYLE_END.length()), insideHtmlTagPattern, option);
return markup(textToMarkup.substring(0, styleIdx), insideHtmlTagPattern, option) +
markup(textToMarkup.substring(styleEndIdx + STYLE_END.length()), insideHtmlTagPattern, option);
}
private static String markupInText(String textToMarkup, Pattern insideHtmlTagPattern, String option) {
@@ -403,7 +391,7 @@ public class SearchUtil {
}
public static void appendFragments(String filter,
@NonNls String text,
String text,
@SimpleTextAttributes.StyleAttributeConstant int style,
final Color foreground,
final Color background,
@@ -432,9 +420,10 @@ public class SearchUtil {
final int start = index.intValue();
if (pos > start) {
final String highlighted = selectedWords.get(selectedWords.size() - 1);
if (highlighted.length() < stripped.length()){
if (highlighted.length() < stripped.length()) {
selectedWords.remove(highlighted);
} else {
}
else {
continue;
}
}
@@ -469,111 +458,15 @@ public class SearchUtil {
final Set<String> filters = SearchableOptionsRegistrar.getInstance().getProcessedWords(filter);
final String[] words = text.substring(pos, end).split("[\\W&&[^-]]+");
for (String word : words) {
if (filters.contains(PorterStemmerUtil.stem(word.toLowerCase()))) {
if (filters.contains(PorterStemmerUtil.stem(word.toLowerCase(Locale.US)))) {
selectedWords.add(word);
}
}
}
}
@Nullable
private static JBPopup createPopup(final ConfigurableSearchTextField searchField,
final JBPopup[] activePopup,
final Alarm showHintAlarm,
final Consumer<String> selectConfigurable,
final Project project,
final int down) {
final String filter = searchField.getText();
if (filter == null || filter.length() == 0) return null;
final Map<String, Set<String>> hints = SearchableOptionsRegistrar.getInstance().findPossibleExtension(filter, project);
final DefaultListModel model = new DefaultListModel();
final JList list = new JBList(model);
for (String groupName : hints.keySet()) {
model.addElement(groupName);
final Set<String> descriptions = hints.get(groupName);
if (descriptions != null) {
for (String hit : descriptions) {
if (hit == null) continue;
model.addElement(new OptionDescription(null, groupName, hit, null));
}
}
}
list.setCellRenderer(new DefaultListCellRenderer() {
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
final Component rendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof String) {
setText("------ " + value + " ------");
}
else if (value instanceof OptionDescription) {
setText(((OptionDescription)value).getHit());
}
return rendererComponent;
}
});
if (model.size() > 0) {
final Runnable onChosen = () -> {
final Object selectedValue = list.getSelectedValue();
if (selectedValue instanceof OptionDescription) {
final OptionDescription description = ((OptionDescription)selectedValue);
searchField.setText(description.getHit());
searchField.addCurrentTextToHistory();
SwingUtilities.invokeLater(() -> { //do not show look up again
showHintAlarm.cancelAllRequests();
selectConfigurable.consume(description.getConfigurableId());
});
}
};
final JBPopup popup = JBPopupFactory.getInstance()
.createListPopupBuilder(list)
.setItemChoosenCallback(onChosen)
.setRequestFocus(down != 0)
.createPopup();
list.addKeyListener(new KeyAdapter() {
public void keyPressed(final KeyEvent e) {
if (e.getKeyCode() != KeyEvent.VK_ENTER && e.getKeyCode() != KeyEvent.VK_UP && e.getKeyCode() != KeyEvent.VK_DOWN &&
e.getKeyCode() != KeyEvent.VK_PAGE_UP && e.getKeyCode() != KeyEvent.VK_PAGE_DOWN) {
searchField.requestFocusInWindow();
if (cancelPopups(activePopup) && e.getKeyCode() == KeyEvent.VK_ESCAPE) {
return;
}
if (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
searchField.process(
new KeyEvent(searchField, KeyEvent.KEY_TYPED, e.getWhen(), e.getModifiers(), KeyEvent.VK_UNDEFINED, e.getKeyChar()));
}
}
}
});
if (down > 0) {
if (list.getSelectedIndex() < list.getModel().getSize() - 1) {
list.setSelectedIndex(list.getSelectedIndex() + 1);
}
}
else if (down < 0) {
if (list.getSelectedIndex() > 0) {
list.setSelectedIndex(list.getSelectedIndex() - 1);
}
}
return popup;
}
return null;
}
private static boolean cancelPopups(final JBPopup[] activePopup) {
for (JBPopup popup : activePopup) {
if (popup != null && popup.isVisible()) {
popup.cancel();
return true;
}
}
return false;
}
public static List<Set<String>> findKeys(String filter, Set<String> quoted) {
filter = processFilter(filter.toLowerCase(), quoted);
filter = processFilter(filter.toLowerCase(Locale.US), quoted);
final List<Set<String>> keySetList = new ArrayList<>();
final SearchableOptionsRegistrar optionsRegistrar = SearchableOptionsRegistrar.getInstance();
final Set<String> words = optionsRegistrar.getProcessedWords(filter);
@@ -609,17 +502,6 @@ public class SearchUtil {
return withoutQuoted + " " + filter.substring(beg);
}
//to process event
public static class ConfigurableSearchTextField extends SearchTextFieldWithStoredHistory {
public ConfigurableSearchTextField() {
super("ALL_CONFIGURABLES_PANEL_SEARCH_HISTORY");
}
public void process(final KeyEvent e) {
((TextFieldWithProcessing)getTextEditor()).processKeyEvent(e);
}
}
public static List<Configurable> expand(ConfigurableGroup[] groups) {
final ArrayList<Configurable> result = new ArrayList<>();
for (ConfigurableGroup eachGroup : groups) {
@@ -635,10 +517,9 @@ public class SearchUtil {
for (Configurable each : configurables) {
addChildren(each, result);
}
result = ContainerUtil.filter(result, configurable -> !(configurable instanceof SearchableConfigurable.Parent) || ((SearchableConfigurable.Parent)configurable).isVisible());
return result;
return ContainerUtil.filter(result, configurable -> !(configurable instanceof SearchableConfigurable.Parent) ||
((SearchableConfigurable.Parent)configurable).isVisible());
}
private static void addChildren(Configurable configurable, List<Configurable> list) {
@@ -650,5 +531,4 @@ public class SearchUtil {
}
}
}
}
}
@@ -455,8 +455,7 @@ public class SoftWrapModelImpl extends InlayModel.SimpleAdapter
* @return <code>true</code> if soft wraps-aware processing should be used; <code>false</code> otherwise
*/
public boolean prepareToMapping() {
if (myUpdateInProgress || myBulkUpdateInProgress ||
myActive > 0 || !isSoftWrappingEnabled() || myEditor.getDocument().getTextLength() <= 0) {
if (myUpdateInProgress || myBulkUpdateInProgress || myActive > 0 || !isSoftWrappingEnabled()) {
return false;
}
@@ -417,4 +417,20 @@ public class EditorImplTest extends AbstractEditorTest {
type('b');
assertEquals(heightInPixels - myEditor.getLineHeight(), myEditor.getScrollingModel().getVerticalScrollOffset());
}
public void testEditorWithSoftWrapsBecomesVisibleAfterDocumentTextRemoval() throws Exception {
initText("abc def ghi");
configureSoftWraps(3);
JViewport viewport = ((EditorEx)myEditor).getScrollPane().getViewport();
viewport.setExtentSize(new Dimension()); // emulate editor becoming invisible
new WriteCommandAction.Simple(getProject()) {
@Override
protected void run() throws Throwable {
Document document = myEditor.getDocument();
document.deleteString(0, document.getTextLength());
}
}.execute();
viewport.setExtentSize(new Dimension(1000, 1000)); // editor becomes visible
verifySoftWrapPositions();
}
}
@@ -171,13 +171,14 @@ public class TestLoggerFactory implements Logger.Factory {
if (!success && BUFFER.length() != 0) {
if (UsefulTestCase.IS_UNDER_TEAMCITY) {
// print in several small statements to avoid service messages tearing causing this fold to expand
System.err.flush();
System.err.println("##teamcity[blockOpened name='DEBUG log']\n");
System.err.flush();
System.err.println(BUFFER);
System.err.flush();
System.err.println("\n##teamcity[blockClosed name='DEBUG log']\n");
System.err.flush();
// using .out instead of .err by the advice from Nikita Skvortsov
System.out.flush();
System.out.println("##teamcity[blockOpened name='DEBUG log']\n");
System.out.flush();
System.out.println(BUFFER);
System.out.flush();
System.out.println("\n##teamcity[blockClosed name='DEBUG log']\n");
System.out.flush();
}
else {
// mark each line in IDEA console with this hidden mark to be able to fold it automatically
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 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.
@@ -377,7 +377,6 @@ public class SrcFileAnnotator implements Disposable {
// use id mapping
lineNumberInCurrent = line;
}
LOG.assertTrue(lineNumberInCurrent < document.getLineCount());
executableLines.put(line, (LineData)lineData);
classLines.put(line, postProcessedLines);
@@ -27,7 +27,6 @@ class JUnit5GenerationTest extends JUnit5CodeInsightTest {
" @Test\n" +
" void name() {\n" +
" \n" +
"\n" +
" }\n" +
"\n" +
" @Test void m2(){}}");
@@ -0,0 +1,105 @@
/*
* 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.jetbrains.python.console;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.FoldRegion;
import com.intellij.openapi.editor.FoldingModel;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.ex.FoldingListener;
import com.intellij.util.DocumentUtil;
import com.jetbrains.python.console.pydev.ConsoleCommunicationListener;
import org.jetbrains.annotations.NotNull;
public class PyConsoleStartFolding extends DocumentAdapter implements ConsoleCommunicationListener, FoldingListener {
private PythonConsoleView myConsoleView;
private boolean isFirstCommandWasExecuted = false;
private boolean doNotAddFoldingAgain = false;
private FoldRegion myStartFoldRegion;
private static final String DEFAULT_FOLDING_MESSAGE = "Python Console";
private int startLineOffset = 0;
public PyConsoleStartFolding(PythonConsoleView consoleView) {
super();
myConsoleView = consoleView;
}
public void setStartLineOffset(int startLineOffset) {
this.startLineOffset = startLineOffset;
}
@Override
public void documentChanged(DocumentEvent event) {
addFolding();
}
private void addFolding() {
Document document = myConsoleView.getEditor().getDocument();
if (doNotAddFoldingAgain || document.getTextLength() == 0) {
return;
}
FoldingModel foldingModel = myConsoleView.getEditor().getFoldingModel();
foldingModel.runBatchFoldingOperation(() -> {
int start = startLineOffset;
String placeholderText = DEFAULT_FOLDING_MESSAGE;
int firstLine = document.getLineNumber(startLineOffset);
for (int line = firstLine; line < document.getLineCount(); line++) {
String lineText = document.getText(DocumentUtil.getLineTextRange(document, line));
if (lineText.startsWith("Python")) {
placeholderText = lineText;
start = document.getLineStartOffset(line);
break;
}
}
if (myStartFoldRegion != null) {
foldingModel.removeFoldRegion(myStartFoldRegion);
}
FoldRegion foldRegion = foldingModel.addFoldRegion(start, document.getTextLength() - 1, placeholderText);
if (foldRegion != null) {
foldRegion.setExpanded(false);
myStartFoldRegion = foldRegion;
}
});
if (isFirstCommandWasExecuted) {
document.removeDocumentListener(this);
}
}
@Override
public void commandExecuted(boolean more) {
isFirstCommandWasExecuted = true;
}
@Override
public void inputRequested() {
}
@Override
public void onFoldRegionStateChange(@NotNull FoldRegion region) {
if (region.equals(myStartFoldRegion) && region.isExpanded()) {
myConsoleView.getEditor().getComponent().updateUI();
doNotAddFoldingAgain = true;
}
}
@Override
public void onFoldProcessingEnd() {
}
}
@@ -588,7 +588,6 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner {
myConsoleView.attachToProcess(myProcessHandler);
createContentDescriptorAndActions();
// Run
myProcessHandler.startNotify();
});
@@ -635,6 +634,7 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner {
final List<AnAction> actions = fillToolBarActions(toolbarActions, contentDescriptor);
registerActionShortcuts(actions, myConsoleView.getConsoleEditor().getComponent());
registerActionShortcuts(actions, panel);
getConsoleView().addConsoleFolding(false);
showContentDescriptor(contentDescriptor);
}
@@ -33,6 +33,7 @@ import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.FoldingModelEx;
import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.openapi.editor.markup.HighlighterTargetArea;
@@ -114,6 +115,30 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable
getFile().putCopyableUserData(PydevConsoleRunner.CONSOLE_KEY, communication);
}
private PyConsoleStartFolding createConsoleFolding() {
PyConsoleStartFolding startFolding = new PyConsoleStartFolding(this);
myExecuteActionHandler.getConsoleCommunication().addCommunicationListener(startFolding);
getEditor().getDocument().addDocumentListener(startFolding);
((FoldingModelEx)getEditor().getFoldingModel()).addListener(startFolding, this);
return startFolding;
}
public void addConsoleFolding(boolean isDebugConsole) {
try {
if (isDebugConsole && myExecuteActionHandler != null) {
PyConsoleStartFolding folding = createConsoleFolding();
// in debug console we should add folding from the place where the folding was turned on
folding.setStartLineOffset(getEditor().getDocument().getTextLength());
}
else {
myInitialized.doWhenDone(this::createConsoleFolding);
}
}
catch (Exception e) {
LOG.error(e.getMessage());
}
}
public void setExecutionHandler(@NotNull PydevConsoleExecuteActionHandler consoleExecuteActionHandler) {
myExecuteActionHandler = consoleExecuteActionHandler;
}
@@ -73,6 +73,7 @@ public class PythonDebugLanguageConsoleView extends DuplexConsoleView<ConsoleVie
if (!primary && !isPrimaryConsoleEnabled()) {
PythonConsoleView console = getPydevConsoleView();
console.addConsoleFolding(true);
console.showStartMessageForFirstExecution(DEBUG_CONSOLE_START_COMMAND);
IdeFocusManager.findInstance().requestFocus(console.getConsoleEditor().getContentComponent(), true);