IDEA-175168 On-demand renderers - force on-demand action

This commit is contained in:
Egor.Ushakov
2017-06-30 17:13:53 +03:00
parent c7c899ff54
commit 7bab95fea2
9 changed files with 192 additions and 146 deletions
@@ -311,20 +311,13 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
String value = truncateToMaxLength(myValue);
Renderer lastRenderer = myValueDescriptor.getLastRenderer();
if (lastRenderer instanceof OnDemandRenderer) {
OnDemandRenderer onDemandRenderer = (OnDemandRenderer)lastRenderer;
if (OnDemandRenderer.isCalculated(myValueDescriptor)) {
lastRenderer = onDemandRenderer.getRenderer();
}
else {
return;
}
}
if (lastRenderer instanceof CompoundTypeRenderer) {
lastRenderer = ((CompoundTypeRenderer)lastRenderer).getLabelRenderer();
}
if (lastRenderer instanceof ToStringRenderer) {
if (!((ToStringRenderer)lastRenderer).isShowValue(myValueDescriptor, myValueDescriptor.getStoredEvaluationContext())) {
return; // to avoid empty line for not calculated toStrings
}
value = StringUtil.wrapWithDoubleQuote(value);
}
renderer.renderValue(value);
@@ -610,4 +610,8 @@ public abstract class ValueDescriptorImpl extends NodeDescriptorImpl implements
}
return "";
}
public EvaluationContextImpl getStoredEvaluationContext() {
return myStoredEvaluationContext;
}
}
@@ -0,0 +1,63 @@
/*
* 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.
*/
package com.intellij.debugger.ui.tree.actions
import com.intellij.debugger.settings.NodeRendererSettings
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.ToggleAction
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.util.Key
import com.intellij.xdebugger.XDebuggerManager
import com.intellij.xdebugger.impl.XDebugSessionImpl
import com.intellij.xdebugger.impl.ui.XDebugSessionData
/**
* @author egor
*/
class ForceOnDemandRenderersAction : ToggleAction(), DumbAware {
override fun isSelected(e: AnActionEvent): Boolean {
return RENDERERS_ONDEMAND_FORCED.get(getSessionData(e), false)
}
override fun setSelected(e: AnActionEvent, state: Boolean) {
RENDERERS_ONDEMAND_FORCED.set(getSessionData(e), state)
NodeRendererSettings.getInstance().fireRenderersChanged()
}
companion object {
private val RENDERERS_ONDEMAND_FORCED = Key.create<Boolean>("RENDERERS_ONDEMAND_FORCED")
private fun getSessionData(e: AnActionEvent): XDebugSessionData? {
var data = e.getData(XDebugSessionData.DATA_KEY)
if (data == null) {
val project = e.project
if (project != null) {
val session = XDebuggerManager.getInstance(project).currentSession
if (session != null) {
data = (session as XDebugSessionImpl).sessionData
}
}
}
return data
}
@JvmStatic
fun isForcedOnDemand(session: XDebugSessionImpl): Boolean {
return RENDERERS_ONDEMAND_FORCED.get(session.sessionData, false)
}
}
}
@@ -18,23 +18,23 @@ package com.intellij.debugger.ui.tree.render;
import com.intellij.debugger.DebuggerBundle;
import com.intellij.debugger.engine.DebugProcess;
import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.debugger.engine.FullValueEvaluatorProvider;
import com.intellij.debugger.engine.evaluation.*;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
import com.intellij.debugger.engine.evaluation.EvaluationContext;
import com.intellij.debugger.engine.evaluation.TextWithImports;
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
import com.intellij.debugger.ui.tree.ValueDescriptor;
import com.intellij.openapi.util.DefaultJDOMExternalizer;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.xdebugger.frame.XFullValueEvaluator;
import com.sun.jdi.Value;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer, FullValueEvaluatorProvider {
public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer, OnDemandRenderer {
public static final @NonNls String UNIQUE_ID = "LabelRenderer";
public boolean myOnDemand;
@@ -62,7 +62,7 @@ public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer, F
public String calcLabel(ValueDescriptor descriptor, EvaluationContext evaluationContext, DescriptorLabelListener labelListener)
throws EvaluateException {
if (myOnDemand && !OnDemandRenderer.isCalculated(descriptor)) {
if (!isShowValue(descriptor, evaluationContext)) {
return "";
}
@@ -92,13 +92,10 @@ public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer, F
return result;
}
@Nullable
@NotNull
@Override
public XFullValueEvaluator getFullValueEvaluator(EvaluationContextImpl evaluationContext, ValueDescriptorImpl valueDescriptor) {
if (myOnDemand && !OnDemandRenderer.isCalculated(valueDescriptor)) {
return OnDemandRenderer.createFullValueEvaluator("… " + getLabelExpression().getText());
}
return null;
public String getLinkText() {
return "… " + getLabelExpression().getText();
}
public void readExternal(Element element) throws InvalidDataException {
@@ -124,6 +121,11 @@ public class LabelRenderer extends TypeRenderer implements ValueLabelRenderer, F
myLabelExpression.setReferenceExpression(expression);
}
@Override
public boolean isOnDemand(EvaluationContext evaluationContext) {
return myOnDemand || OnDemandRenderer.super.isOnDemand(evaluationContext);
}
public boolean isOnDemand() {
return myOnDemand;
}
@@ -0,0 +1,88 @@
/*
* 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.
*/
package com.intellij.debugger.ui.tree.render;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.FullValueEvaluatorProvider;
import com.intellij.debugger.engine.JavaValue;
import com.intellij.debugger.engine.evaluation.EvaluationContext;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
import com.intellij.debugger.ui.tree.ValueDescriptor;
import com.intellij.debugger.ui.tree.actions.ForceOnDemandRenderersAction;
import com.intellij.openapi.util.Key;
import com.intellij.xdebugger.frame.XFullValueEvaluator;
import com.intellij.xdebugger.frame.XValuePlace;
import com.intellij.xdebugger.impl.XDebugSessionImpl;
import com.intellij.xdebugger.impl.ui.tree.nodes.HeadlessValueEvaluationCallback;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author egor
*/
public interface OnDemandRenderer extends FullValueEvaluatorProvider {
@Nullable
@Override
default XFullValueEvaluator getFullValueEvaluator(EvaluationContextImpl evaluationContext,
ValueDescriptorImpl valueDescriptor) {
if (isOnDemand(evaluationContext) && !isCalculated(valueDescriptor)) {
return createFullValueEvaluator(getLinkText());
}
return null;
}
String getLinkText();
default boolean isOnDemand(EvaluationContext evaluationContext) {
return isOnDemandForced(evaluationContext);
}
default boolean isShowValue(ValueDescriptor valueDescriptor, EvaluationContext evaluationContext) {
return !isOnDemand(evaluationContext) || isCalculated(valueDescriptor);
}
static XFullValueEvaluator createFullValueEvaluator(String text) {
return new XFullValueEvaluator(text) {
@Override
public void startEvaluation(@NotNull XFullValueEvaluationCallback callback) {
if (callback instanceof HeadlessValueEvaluationCallback) {
XValueNodeImpl node = ((HeadlessValueEvaluationCallback)callback).getNode();
node.clearFullValueEvaluator();
setCalculated(((JavaValue)node.getValueContainer()).getDescriptor());
node.getValueContainer().computePresentation(node, XValuePlace.TREE);
}
callback.evaluated("");
}
}.setShowValuePopup(false);
}
Key<Boolean> ON_DEMAND_CALCULATED = Key.create("ON_DEMAND_CALCULATED");
static boolean isCalculated(ValueDescriptor descriptor) {
return ON_DEMAND_CALCULATED.get(descriptor, false);
}
static void setCalculated(ValueDescriptor descriptor) {
ON_DEMAND_CALCULATED.set(descriptor, true);
}
static boolean isOnDemandForced(EvaluationContext evaluationContext) {
return ForceOnDemandRenderersAction.isForcedOnDemand(
(XDebugSessionImpl)((DebugProcessImpl)evaluationContext.getDebugProcess()).getXdebugProcess().getSession());
}
}
@@ -1,120 +0,0 @@
/*
* 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.
*/
package com.intellij.debugger.ui.tree.render
import com.intellij.debugger.DebuggerBundle
import com.intellij.debugger.DebuggerContext
import com.intellij.debugger.engine.FullValueEvaluatorProvider
import com.intellij.debugger.engine.JavaValue
import com.intellij.debugger.engine.evaluation.EvaluateException
import com.intellij.debugger.engine.evaluation.EvaluationContext
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl
import com.intellij.debugger.ui.tree.DebuggerTreeNode
import com.intellij.debugger.ui.tree.NodeDescriptor
import com.intellij.debugger.ui.tree.ValueDescriptor
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiElement
import com.intellij.xdebugger.frame.XFullValueEvaluator
import com.intellij.xdebugger.frame.XValuePlace
import com.intellij.xdebugger.impl.ui.tree.nodes.HeadlessValueEvaluationCallback
import com.sun.jdi.Type
import com.sun.jdi.Value
import javax.swing.Icon
/**
* @author egor
*/
class OnDemandRenderer(val renderer: NodeRendererImpl) : NodeRendererImpl(), FullValueEvaluatorProvider {
init {
isEnabled = true
}
@Throws(EvaluateException::class)
override fun calcLabel(descriptor: ValueDescriptor, evaluationContext: EvaluationContext, listener: DescriptorLabelListener): String? {
if (!isCalculated(descriptor)) {
return ""
}
return renderer.calcLabel(descriptor, evaluationContext, listener)
}
override fun getFullValueEvaluator(evaluationContext: EvaluationContextImpl?, valueDescriptor: ValueDescriptorImpl): XFullValueEvaluator? {
if (!isCalculated(valueDescriptor)) {
return createFullValueEvaluator(DebuggerBundle.message("message.node.toString"))
}
return null
}
override fun buildChildren(value: Value?, builder: ChildrenBuilder?, evaluationContext: EvaluationContext?) {
renderer.buildChildren(value, builder, evaluationContext)
}
override fun getChildValueExpression(node: DebuggerTreeNode?, context: DebuggerContext?): PsiElement {
return renderer.getChildValueExpression(node, context)
}
override fun isExpandable(value: Value?, evaluationContext: EvaluationContext?, parentDescriptor: NodeDescriptor?): Boolean {
return renderer.isExpandable(value, evaluationContext, parentDescriptor)
}
override fun calcValueIcon(descriptor: ValueDescriptor?,
evaluationContext: EvaluationContext?,
listener: DescriptorLabelListener?): Icon? {
return renderer.calcValueIcon(descriptor, evaluationContext, listener)
}
override fun isApplicable(type: Type?): Boolean {
return renderer.isApplicable(type)
}
override fun getName(): String {
return "OnDemand" + renderer.getName()
}
override fun getUniqueId(): String {
return "OnDemand" + renderer.getUniqueId()
}
companion object {
@JvmStatic
fun createFullValueEvaluator(text: String): XFullValueEvaluator {
return object : XFullValueEvaluator(text) {
override fun startEvaluation(callback: XFullValueEvaluator.XFullValueEvaluationCallback) {
if (callback is HeadlessValueEvaluationCallback) {
val node = callback.node
node.clearFullValueEvaluator()
setCalculated((node.valueContainer as JavaValue).descriptor)
node.valueContainer.computePresentation(node, XValuePlace.TREE)
}
callback.evaluated("")
}
}.setShowValuePopup(false)
}
@JvmField
val ON_DEMAND_CALCULATED = Key.create<Boolean>("ON_DEMAND_CALCULATED")
@JvmStatic
fun isCalculated(descriptor: ValueDescriptor): Boolean {
return ON_DEMAND_CALCULATED.get(descriptor, false)
}
@JvmStatic
fun setCalculated(descriptor: ValueDescriptor) {
ON_DEMAND_CALCULATED.set(descriptor, true)
}
}
}
@@ -34,10 +34,11 @@ import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants;
import com.sun.jdi.*;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING;
public class ToStringRenderer extends NodeRendererImpl {
public class ToStringRenderer extends NodeRendererImpl implements OnDemandRenderer {
public static final @NonNls String UNIQUE_ID = "ToStringRenderer";
private boolean USE_CLASS_FILTERS = false;
@@ -76,6 +77,11 @@ public class ToStringRenderer extends NodeRendererImpl {
@Override
public String calcLabel(final ValueDescriptor valueDescriptor, EvaluationContext evaluationContext, final DescriptorLabelListener labelListener)
throws EvaluateException {
if (!isShowValue(valueDescriptor, evaluationContext)) {
return "";
}
final Value value = valueDescriptor.getValue();
BatchEvaluator.getBatchEvaluator(evaluationContext.getDebugProcess()).invoke(new ToStringCommand(evaluationContext, value) {
@Override
@@ -96,6 +102,12 @@ public class ToStringRenderer extends NodeRendererImpl {
return XDebuggerUIConstants.COLLECTING_DATA_MESSAGE;
}
@NotNull
@Override
public String getLinkText() {
return DebuggerBundle.message("message.node.toString");
}
public boolean isUseClassFilters() {
return USE_CLASS_FILTERS;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* 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.
@@ -16,13 +16,14 @@
package com.intellij.xdebugger.impl.ui;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.xdebugger.XExpression;
import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
public class XDebugSessionData {
public class XDebugSessionData extends UserDataHolderBase {
public static final DataKey<XDebugSessionData> DATA_KEY = DataKey.create("XDebugSessionData");
@NotNull
+3
View File
@@ -225,6 +225,9 @@
<action id="Debugger.CreateRenderer" class="com.intellij.debugger.actions.CreateRendererAction" text="Create..."/>
<action id="Debugger.AutoRenderer" class="com.intellij.debugger.actions.AutoRendererAction"/>
<action id="Debugger.MuteRenderers" class="com.intellij.debugger.ui.tree.actions.ForceOnDemandRenderersAction" text="Force Renderers On-demand">
<add-to-group group-id="XDebugger.ValueGroup" anchor="last"/>
</action>
</group>
<action class="com.intellij.debugger.memory.action.ShowInstancesByClassAction"