annotation support for debugger renderers - IDEA-144797

This commit is contained in:
Egor Ushakov
2019-01-21 15:54:30 +03:00
parent b07780bc51
commit eea7326ed9
4 changed files with 69 additions and 23 deletions
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2017 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.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.debugger.actions;
import com.intellij.debugger.engine.DebugProcessImpl;
@@ -26,6 +12,7 @@ import com.intellij.debugger.ui.tree.render.NodeRenderer;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.xdebugger.frame.XValue;
import com.intellij.xdebugger.impl.ui.tree.actions.XDebuggerTreeActionBase;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
@@ -102,10 +89,10 @@ public class ViewAsGroup extends ActionGroup implements DumbAware {
return myChildren;
}
private static AnAction [] calcChildren(List<JavaValue> values) {
private static AnAction [] calcChildren(List<JavaValue> values, Project project) {
List<AnAction> renderers = new ArrayList<>();
List<NodeRenderer> allRenderers = NodeRendererSettings.getInstance().getAllRenderers();
List<NodeRenderer> allRenderers = NodeRendererSettings.getInstance().getAllRenderers(project);
boolean anyValueDescriptor = false;
@@ -178,7 +165,7 @@ public class ViewAsGroup extends ActionGroup implements DumbAware {
process.getManagerThread().schedule(new DebuggerContextCommandImpl(debuggerContext) {
@Override
public void threadAction(@NotNull SuspendContextImpl suspendContext) {
myChildren = calcChildren(values);
myChildren = calcChildren(values, process.getProject());
DebuggerAction.enableAction(event, myChildren.length > 0);
}
});
@@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.debugger.engine;
import com.intellij.Patches;
@@ -161,7 +161,9 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
myNodeRenderersMap.clear();
myRenderers.clear();
try {
NodeRendererSettings.getInstance().getAllRenderers().stream().filter(NodeRenderer::isEnabled).forEachOrdered(myRenderers::add);
NodeRendererSettings.getInstance().getAllRenderers(myProject).stream()
.filter(NodeRenderer::isEnabled)
.forEachOrdered(myRenderers::add);
}
finally {
DebuggerInvocationUtil.swingInvokeLater(myProject, () -> {
@@ -14,20 +14,27 @@ import com.intellij.debugger.ui.tree.DebuggerTreeNode;
import com.intellij.debugger.ui.tree.ValueDescriptor;
import com.intellij.debugger.ui.tree.render.*;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.PsiElement;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.AnnotatedElementsSearch;
import com.intellij.util.EventDispatcher;
import com.intellij.util.IncorrectOperationException;
import com.sun.jdi.Value;
import org.jdom.Element;
import org.jetbrains.annotations.Debugger;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -41,6 +48,8 @@ import java.util.List;
@Storage(value = "debugger.renderers.xml", deprecated = true),
})
public class NodeRendererSettings implements PersistentStateComponent<Element> {
private static final Logger LOG = Logger.getInstance(NodeRendererSettings.class);
@NonNls private static final String REFERENCE_RENDERER = "Reference renderer";
@NonNls public static final String RENDERER_TAG = "Renderer";
@NonNls private static final String RENDERER_ID = "ID";
@@ -218,7 +227,7 @@ public class NodeRendererSettings implements PersistentStateComponent<Element> {
myDispatcher.getMulticaster().renderersChanged();
}
public List<NodeRenderer> getAllRenderers() {
public List<NodeRenderer> getAllRenderers(Project project) {
// the order is important as the renderers are applied according to it
final List<NodeRenderer> allRenderers = new ArrayList<>();
@@ -228,6 +237,10 @@ public class NodeRendererSettings implements PersistentStateComponent<Element> {
return true;
});
if (Registry.is("debugger.renderers.annotations")) {
ReadAction.run(() -> addAnnotationRenderers(allRenderers, project));
}
// plugins registered renderers come after that
allRenderers.addAll(NodeRenderer.EP_NAME.getExtensionList());
@@ -241,6 +254,49 @@ public class NodeRendererSettings implements PersistentStateComponent<Element> {
return allRenderers;
}
private void addAnnotationRenderers(List<NodeRenderer> renderers, Project project) {
try {
GlobalSearchScope allScope = GlobalSearchScope.allScope(project);
String annotationFqn = Debugger.Renderer.class.getName().replace("$", ".");
PsiClass annotationClass =
JavaPsiFacade.getInstance(project).findClass(annotationFqn, allScope);
if (annotationClass != null) {
AnnotatedElementsSearch.searchPsiClasses(annotationClass, allScope)
.forEach(e -> {
PsiAnnotation annotation = e.getAnnotation(annotationFqn);
if (annotation != null) {
String text = getAttributeValue(annotation, "text");
LabelRenderer labelRenderer = StringUtil.isEmpty(text) ? null : createLabelRenderer(null, text, null);
String childrenArray = getAttributeValue(annotation, "childrenArray");
String isLeaf = getAttributeValue(annotation, "hasChildren");
ExpressionChildrenRenderer childrenRenderer =
StringUtil.isEmpty(childrenArray) ? null : createExpressionArrayChildrenRenderer(childrenArray, isLeaf, myArrayRenderer);
CompoundReferenceRenderer renderer = createCompoundReferenceRenderer(
e.getQualifiedName(), e.getQualifiedName(), labelRenderer, childrenRenderer);
renderer.setEnabled(true);
renderers.add(renderer);
}
});
}
}
catch (IndexNotReadyException | ProcessCanceledException ignore) {
}
catch (Exception e) {
LOG.error(e);
}
}
private static String getAttributeValue(PsiAnnotation annotation, String attribute) {
PsiAnnotationMemberValue value = annotation.findAttributeValue(attribute);
if (value == null) {
return null;
}
if (value instanceof PsiLiteralValue) {
return String.valueOf(((PsiLiteralValue)value).getValue());
}
throw new IllegalStateException("String literal expected, but was " + value);
}
public Renderer readRenderer(Element root) throws InvalidDataException {
if (root == null) {
return null;
@@ -367,6 +367,7 @@ debugger.evaluate.single.threaded.timeout=1000
debugger.evaluate.single.threaded.timeout.description=Number of milliseconds to evaluate resuming only the current thread, then resume all threads
debugger.call.tracing=false
debugger.call.tracing.arguments=true
debugger.renderers.annotations=false
execution.java.always.debug=false
execution.java.always.debug.description=Always run java processes with the debug agent