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:
@@ -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
|
||||
|
||||
+56
-29
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+17
-46
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -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));
|
||||
}
|
||||
|
||||
+5
-48
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+14
-35
@@ -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,
|
||||
|
||||
+10
-1
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -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
|
||||
*/
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
+4
-1
@@ -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() {
|
||||
|
||||
+8
-4
@@ -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
-9
@@ -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
|
||||
|
||||
+54
-44
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-7
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user