mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Add an ability to load values in Debugger/Console on demand (PY-29468)
This commit is contained in:
@@ -104,11 +104,21 @@ USE_LIB_COPY = SUPPORT_GEVENT and \
|
||||
(IS_PY3K and sys.version_info[1] >= 3))
|
||||
|
||||
|
||||
class ValuesPolicy:
|
||||
SYNC = 0
|
||||
ASYNC = 1
|
||||
ON_DEMAND = 2
|
||||
|
||||
|
||||
LOAD_VALUES_POLICY = ValuesPolicy.SYNC
|
||||
if os.getenv('PYDEVD_LOAD_VALUES_ASYNC', 'False') == 'True':
|
||||
LOAD_VALUES_POLICY = ValuesPolicy.ASYNC
|
||||
if os.getenv('PYDEVD_LOAD_VALUES_ON_DEMAND', 'False') == 'True':
|
||||
LOAD_VALUES_POLICY = ValuesPolicy.ON_DEMAND
|
||||
DEFAULT_VALUES_DICT = {ValuesPolicy.ASYNC: "__pydevd_value_async", ValuesPolicy.ON_DEMAND: "__pydevd_value_on_demand"}
|
||||
|
||||
INTERACTIVE_MODE_AVAILABLE = sys.platform in ('darwin', 'win32') or os.getenv('DISPLAY') is not None
|
||||
IS_PYCHARM = True
|
||||
|
||||
LOAD_VALUES_ASYNC = os.getenv('PYDEVD_LOAD_VALUES_ASYNC', 'False') == 'True'
|
||||
DEFAULT_VALUE = "__pydevd_value_async"
|
||||
ASYNC_EVAL_TIMEOUT_SEC = 60
|
||||
NEXT_VALUE_SEPARATOR = "__pydev_val__"
|
||||
BUILTINS_MODULE_NAME = '__builtin__' if IS_PY2 else 'builtins'
|
||||
|
||||
@@ -4,9 +4,7 @@ from _pydevd_bundle import pydevd_extension_utils
|
||||
from _pydevd_bundle import pydevd_resolver
|
||||
import sys
|
||||
from _pydevd_bundle.pydevd_constants import dict_iter_items, dict_keys, IS_PY3K, \
|
||||
BUILTINS_MODULE_NAME, MAXIMUM_VARIABLE_REPRESENTATION_SIZE, RETURN_VALUES_DICT, LOAD_VALUES_ASYNC, \
|
||||
DEFAULT_VALUE
|
||||
|
||||
BUILTINS_MODULE_NAME, MAXIMUM_VARIABLE_REPRESENTATION_SIZE, RETURN_VALUES_DICT, LOAD_VALUES_POLICY, ValuesPolicy, DEFAULT_VALUES_DICT
|
||||
from _pydev_bundle.pydev_imports import quote
|
||||
from _pydevd_bundle.pydevd_extension_api import TypeResolveProvider, StrPresentationProvider
|
||||
|
||||
@@ -232,7 +230,7 @@ def is_builtin(x):
|
||||
|
||||
|
||||
def should_evaluate_full_value(val):
|
||||
return not LOAD_VALUES_ASYNC or (is_builtin(type(val)) and not isinstance(val, (list, tuple, dict)))
|
||||
return LOAD_VALUES_POLICY == ValuesPolicy.SYNC or (is_builtin(type(val)) and not isinstance(val, (list, tuple, dict)))
|
||||
|
||||
|
||||
def frame_vars_to_xml(frame_f_locals, hidden_ns=None):
|
||||
@@ -289,7 +287,7 @@ def var_to_xml(val, name, doTrim=True, additional_in_xml='', evaluate_full_value
|
||||
_type, typeName, resolver = get_type(v)
|
||||
type_qualifier = getattr(_type, "__module__", "")
|
||||
if not evaluate_full_value:
|
||||
value = DEFAULT_VALUE
|
||||
value = DEFAULT_VALUES_DICT[LOAD_VALUES_POLICY]
|
||||
else:
|
||||
try:
|
||||
str_from_provider = _str_from_providers(v, _type, typeName)
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.xdebugger.frame.*;
|
||||
import com.intellij.xdebugger.frame.presentation.XRegularValuePresentation;
|
||||
import com.jetbrains.python.debugger.pydev.PyDebugCallback;
|
||||
import com.jetbrains.python.debugger.pydev.PyVariableLocator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -29,7 +30,6 @@ public class PyDebugValue extends XNamedValue {
|
||||
public static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
public static final String RETURN_VALUES_PREFIX = "__pydevd_ret_val_dict";
|
||||
public static final String DEFAULT_VALUE_ASYNC = "__pydevd_value_async";
|
||||
|
||||
private @Nullable String myTempName = null;
|
||||
private final @Nullable String myType;
|
||||
@@ -40,12 +40,23 @@ public class PyDebugValue extends XNamedValue {
|
||||
private final boolean myIsIPythonHidden;
|
||||
private @Nullable PyDebugValue myParent;
|
||||
private @Nullable String myId = null;
|
||||
private boolean myLoadValueAsync;
|
||||
private ValuesPolicy myLoadValuePolicy;
|
||||
private @NotNull PyFrameAccessor myFrameAccessor;
|
||||
private @Nullable PyVariableLocator myVariableLocator;
|
||||
private volatile @Nullable XValueNode myLastNode = null;
|
||||
private final boolean myErrorOnEval;
|
||||
|
||||
public enum ValuesPolicy {
|
||||
SYNC, ASYNC, ON_DEMAND
|
||||
}
|
||||
|
||||
private static final Map<String, ValuesPolicy> POLICY_DEFAULT_VALUES = ImmutableMap.of("__pydevd_value_async", ValuesPolicy.ASYNC,
|
||||
"__pydevd_value_on_demand",
|
||||
ValuesPolicy.ON_DEMAND);
|
||||
|
||||
public static final Map<ValuesPolicy, String> POLICY_ENV_VARS = ImmutableMap.of(ValuesPolicy.ASYNC, "PYDEVD_LOAD_VALUES_ASYNC",
|
||||
ValuesPolicy.ON_DEMAND, "PYDEVD_LOAD_VALUES_ON_DEMAND");
|
||||
|
||||
public PyDebugValue(@NotNull final String name,
|
||||
@Nullable final String type,
|
||||
@Nullable String typeQualifier,
|
||||
@@ -78,9 +89,9 @@ public class PyDebugValue extends XNamedValue {
|
||||
myErrorOnEval = errorOnEval;
|
||||
myParent = parent;
|
||||
myFrameAccessor = frameAccessor;
|
||||
myLoadValueAsync = false;
|
||||
if (DEFAULT_VALUE_ASYNC.equals(myValue)) {
|
||||
myLoadValueAsync = true;
|
||||
myLoadValuePolicy = ValuesPolicy.SYNC;
|
||||
if (POLICY_DEFAULT_VALUES.keySet().contains(myValue)) {
|
||||
myLoadValuePolicy = POLICY_DEFAULT_VALUES.get(myValue);
|
||||
setValue(" ");
|
||||
}
|
||||
}
|
||||
@@ -88,7 +99,7 @@ public class PyDebugValue extends XNamedValue {
|
||||
public PyDebugValue(@NotNull PyDebugValue value, @NotNull String newName) {
|
||||
this(newName, value.getType(), value.getTypeQualifier(), value.getValue(), value.isContainer(), value.isReturnedVal(),
|
||||
value.isIPythonHidden(), value.isErrorOnEval(), value.getParent(), value.getFrameAccessor());
|
||||
setLoadValueAsync(value.isLoadValueAsync());
|
||||
setLoadValuePolicy(value.getLoadValuePolicy());
|
||||
setTempName(value.getTempName());
|
||||
}
|
||||
|
||||
@@ -149,12 +160,12 @@ public class PyDebugValue extends XNamedValue {
|
||||
return myParent == null ? this : myParent.getTopParent();
|
||||
}
|
||||
|
||||
public boolean isLoadValueAsync() {
|
||||
return myLoadValueAsync;
|
||||
public ValuesPolicy getLoadValuePolicy() {
|
||||
return myLoadValuePolicy;
|
||||
}
|
||||
|
||||
public void setLoadValueAsync(boolean loadValueAsync) {
|
||||
myLoadValueAsync = loadValueAsync;
|
||||
public void setLoadValuePolicy(ValuesPolicy loadValueAsync) {
|
||||
myLoadValuePolicy = loadValueAsync;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -243,8 +254,22 @@ public class PyDebugValue extends XNamedValue {
|
||||
node.setPresentation(getValueIcon(), myType, value, myContainer);
|
||||
}
|
||||
|
||||
public void updateNodeValueAfterLoading(@NotNull XValueNode node, @NotNull String value, @NotNull String linkText) {
|
||||
node.setPresentation(getValueIcon(), myType, value, myContainer);
|
||||
public void updateNodeValueAfterLoading(@NotNull XValueNode node,
|
||||
@NotNull String value,
|
||||
@NotNull String linkText,
|
||||
@Nullable String errorMessage) {
|
||||
if (errorMessage != null) {
|
||||
node.setPresentation(getValueIcon(), new XRegularValuePresentation(value, myType) {
|
||||
@Override
|
||||
public void renderValue(@NotNull XValueTextRenderer renderer) {
|
||||
renderer.renderError(errorMessage);
|
||||
}
|
||||
}, myContainer);
|
||||
}
|
||||
else {
|
||||
node.setPresentation(getValueIcon(), myType, value, myContainer);
|
||||
}
|
||||
|
||||
if (isNumericContainer()) return; // do not update FullValueEvaluator not to break Array Viewer
|
||||
if (value.length() >= MAX_VALUE) {
|
||||
node.setFullValueEvaluator(new PyFullValueEvaluator(myFrameAccessor, getEvaluationExpression()));
|
||||
@@ -274,11 +299,11 @@ public class PyDebugValue extends XNamedValue {
|
||||
return new PyDebugCallback<String>() {
|
||||
@Override
|
||||
public void ok(String value) {
|
||||
myLoadValueAsync = false;
|
||||
myLoadValuePolicy = ValuesPolicy.SYNC;
|
||||
myValue = value;
|
||||
XValueNode node = myLastNode;
|
||||
if (node != null && !node.isObsolete()) {
|
||||
updateNodeValueAfterLoading(node, value, "");
|
||||
updateNodeValueAfterLoading(node, value, "", null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +325,7 @@ public class PyDebugValue extends XNamedValue {
|
||||
XValue value = childrenList.getValue(i);
|
||||
if (value instanceof PyDebugValue) {
|
||||
PyDebugValue debugValue = (PyDebugValue)value;
|
||||
if (debugValue.isLoadValueAsync()) {
|
||||
if (debugValue.getLoadValuePolicy() == ValuesPolicy.ASYNC || debugValue.isNumericContainer()) {
|
||||
variables.add(new PyFrameAccessor.PyAsyncValue<>(debugValue, debugValue.createDebugValueCallback()));
|
||||
}
|
||||
}
|
||||
@@ -328,9 +353,12 @@ public class PyDebugValue extends XNamedValue {
|
||||
if (value.length() >= MAX_VALUE) {
|
||||
node.setFullValueEvaluator(new PyFullValueEvaluator(myFrameAccessor, treeName));
|
||||
}
|
||||
if (myLoadValueAsync) {
|
||||
if (myLoadValuePolicy == ValuesPolicy.ASYNC) {
|
||||
node.setFullValueEvaluator(new PyLoadingValueEvaluator("... Loading Value", myFrameAccessor, treeName));
|
||||
}
|
||||
else if (myLoadValuePolicy == ValuesPolicy.ON_DEMAND) {
|
||||
node.setFullValueEvaluator(new PyOnDemandValueEvaluator("Show Value", myFrameAccessor, this, node));
|
||||
}
|
||||
return;
|
||||
}
|
||||
String linkText = "...View as " + postfix;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.jetbrains.python.debugger;
|
||||
|
||||
import com.intellij.xdebugger.XSourcePosition;
|
||||
import com.intellij.xdebugger.frame.XCompositeNode;
|
||||
import com.intellij.xdebugger.frame.XValueChildrenList;
|
||||
import com.jetbrains.python.debugger.pydev.PyDebugCallback;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -44,6 +45,13 @@ public interface PyFrameAccessor {
|
||||
return false;
|
||||
}
|
||||
|
||||
default void setCurrentRootNode(@NotNull XCompositeNode node) {}
|
||||
|
||||
@Nullable
|
||||
default XCompositeNode getCurrentRootNode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
class PyAsyncValue<T> {
|
||||
private final @NotNull PyDebugValue myDebugValue;
|
||||
private final @NotNull PyDebugCallback<T> myCallback;
|
||||
|
||||
@@ -8,22 +8,22 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @author traff
|
||||
*/
|
||||
public class PyFullValueEvaluator extends XFullValueEvaluator {
|
||||
private final PyFrameAccessor myDebugProcess;
|
||||
private final String myExpression;
|
||||
@NotNull protected final PyFrameAccessor myDebugProcess;
|
||||
@NotNull protected final String myExpression;
|
||||
|
||||
/**
|
||||
* @param linkText text of the link what will be appended to a variables tree node text
|
||||
* @param debugProcess
|
||||
* @param expression
|
||||
*/
|
||||
protected PyFullValueEvaluator(String linkText, PyFrameAccessor debugProcess, String expression) {
|
||||
protected PyFullValueEvaluator(String linkText, @NotNull PyFrameAccessor debugProcess, @NotNull String expression) {
|
||||
super(linkText);
|
||||
myDebugProcess = debugProcess;
|
||||
myExpression = expression;
|
||||
}
|
||||
|
||||
|
||||
protected PyFullValueEvaluator(PyFrameAccessor debugProcess, String expression) {
|
||||
protected PyFullValueEvaluator(@NotNull PyFrameAccessor debugProcess, @NotNull String expression) {
|
||||
myDebugProcess = debugProcess;
|
||||
myExpression = expression;
|
||||
}
|
||||
@@ -32,7 +32,7 @@ public class PyFullValueEvaluator extends XFullValueEvaluator {
|
||||
@Override
|
||||
public void startEvaluation(@NotNull XFullValueEvaluationCallback callback) {
|
||||
String expression = myExpression.trim();
|
||||
if ("".equals(expression)) {
|
||||
if (expression.isEmpty()) {
|
||||
callback.evaluated("");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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.
|
||||
package com.jetbrains.python.debugger
|
||||
|
||||
import com.intellij.xdebugger.frame.XValueNode
|
||||
|
||||
class PyOnDemandValueEvaluator(linkText: String,
|
||||
debugProcess: PyFrameAccessor,
|
||||
var debugValue: PyDebugValue,
|
||||
var node: XValueNode) : PyFullValueEvaluator(linkText, debugProcess, debugValue.evaluationExpression) {
|
||||
|
||||
override fun startEvaluation(callback: XFullValueEvaluationCallback) {
|
||||
node.setFullValueEvaluator(PyLoadingValueEvaluator("... Loading Value", myDebugProcess, myExpression))
|
||||
callback.evaluated("... Loading Value")
|
||||
val pyAsyncValue = PyFrameAccessor.PyAsyncValue<String>(debugValue, debugValue.createDebugValueCallback())
|
||||
myDebugProcess.loadAsyncVariablesValues(listOf(pyAsyncValue))
|
||||
}
|
||||
|
||||
override fun isShowValuePopup(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.xdebugger.XSourcePosition;
|
||||
import com.intellij.xdebugger.frame.XCompositeNode;
|
||||
import com.intellij.xdebugger.frame.XValueChildrenList;
|
||||
import com.intellij.xdebugger.frame.XValueNode;
|
||||
import com.jetbrains.python.console.parsing.PythonConsoleData;
|
||||
@@ -112,9 +113,11 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl
|
||||
private int myFullValueSeq = 0;
|
||||
private final Map<Integer, List<PyFrameAccessor.PyAsyncValue<String>>> myCallbackHashMap = new ConcurrentHashMap<>();
|
||||
|
||||
private @Nullable PythonConsoleView myConsoleView;
|
||||
@Nullable private PythonConsoleView myConsoleView;
|
||||
private final List<PyFrameListener> myFrameListeners = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
|
||||
@Nullable private XCompositeNode myCurrentRootNode;
|
||||
|
||||
/**
|
||||
* Initializes the xml-rpc communication.
|
||||
*
|
||||
@@ -629,7 +632,7 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl
|
||||
XValueNode node = value.getLastNode();
|
||||
if (node != null && !node.isObsolete()) {
|
||||
if (e.getMessage().startsWith("Timeout") || e.getMessage().startsWith("Console already exited")) {
|
||||
value.updateNodeValueAfterLoading(node, " ", "Timeout Exceeded");
|
||||
value.updateNodeValueAfterLoading(node, " ", "", PyVariableViewSettings.LOADING_TIMED_OUT);
|
||||
}
|
||||
else {
|
||||
LOG.error(e);
|
||||
@@ -677,6 +680,17 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl
|
||||
return new XValueChildrenList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentRootNode(@NotNull XCompositeNode node) {
|
||||
myCurrentRootNode = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public XCompositeNode getCurrentRootNode() {
|
||||
return myCurrentRootNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeVariable(PyDebugValue variable, String value) throws PyDebuggerException {
|
||||
if (myClient != null) {
|
||||
|
||||
@@ -77,6 +77,7 @@ import com.jetbrains.python.PythonHelper;
|
||||
import com.jetbrains.python.console.actions.ShowVarsAction;
|
||||
import com.jetbrains.python.console.pydev.ConsoleCommunicationListener;
|
||||
import com.jetbrains.python.debugger.PyDebugRunner;
|
||||
import com.jetbrains.python.debugger.PyDebugValue;
|
||||
import com.jetbrains.python.debugger.PyVariableViewSettings;
|
||||
import com.jetbrains.python.debugger.settings.PyDebuggerSettings;
|
||||
import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase;
|
||||
@@ -207,7 +208,7 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner {
|
||||
DefaultActionGroup settings = new DefaultActionGroup("Settings", true);
|
||||
settings.getTemplatePresentation().setIcon(AllIcons.General.GearPlain);
|
||||
settings.add(new PyVariableViewSettings.SimplifiedView(null));
|
||||
settings.add(new PyVariableViewSettings.AsyncView());
|
||||
settings.add(new PyVariableViewSettings.VariablesPolicyGroup());
|
||||
|
||||
toolbarActions.add(settings);
|
||||
|
||||
@@ -1018,8 +1019,8 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner {
|
||||
myEnvironmentVariables = envs;
|
||||
myEnvironmentVariables.putAll(consoleSettings.getEnvs());
|
||||
PyDebuggerSettings debuggerSettings = PyDebuggerSettings.getInstance();
|
||||
if (debuggerSettings.isLoadValuesAsync()) {
|
||||
myEnvironmentVariables.put(PyVariableViewSettings.PYDEVD_LOAD_VALUES_ASYNC, "True");
|
||||
if (debuggerSettings.getValuesPolicy() != PyDebugValue.ValuesPolicy.SYNC) {
|
||||
myEnvironmentVariables.put(PyDebugValue.POLICY_ENV_VARS.get(debuggerSettings.getValuesPolicy()), "True");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +101,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
|
||||
private PyReferrersLoader myReferrersProvider;
|
||||
private final List<PyFrameListener> myFrameListeners = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
private boolean isCythonWarningShown = false;
|
||||
@Nullable private XCompositeNode myCurrentRootNode;
|
||||
|
||||
public PyDebugProcess(@NotNull XDebugSession session,
|
||||
@NotNull ServerSocket serverSocket,
|
||||
@@ -451,7 +452,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
|
||||
super.registerAdditionalActions(leftToolbar, topToolbar, settings);
|
||||
settings.add(new WatchReturnValuesAction(this));
|
||||
settings.add(new PyVariableViewSettings.SimplifiedView(this));
|
||||
settings.add(new PyVariableViewSettings.AsyncView());
|
||||
settings.add(new PyVariableViewSettings.VariablesPolicyGroup());
|
||||
}
|
||||
|
||||
private static class WatchReturnValuesAction extends ToggleAction {
|
||||
@@ -747,7 +748,8 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
|
||||
XValueNode node = value.getLastNode();
|
||||
if (node != null && !node.isObsolete()) {
|
||||
if (e.getMessage().startsWith("Timeout")) {
|
||||
value.updateNodeValueAfterLoading(node, " ", "Timeout Exceeded");
|
||||
value.updateNodeValueAfterLoading(node, " ", "", PyVariableViewSettings.LOADING_TIMED_OUT);
|
||||
PyVariableViewSettings.showWarningMessage(getCurrentRootNode());
|
||||
}
|
||||
else {
|
||||
LOG.error(e);
|
||||
@@ -830,6 +832,17 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
|
||||
return PyDebugSupportUtils.canSaveToTemp(project, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentRootNode(@Nullable XCompositeNode currentRootNode) {
|
||||
myCurrentRootNode = currentRootNode;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public XCompositeNode getCurrentRootNode() {
|
||||
return myCurrentRootNode;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PyStackFrame currentFrame() throws PyDebuggerException {
|
||||
if (!isConnected()) {
|
||||
|
||||
@@ -333,8 +333,8 @@ public class PyDebugRunner extends GenericProgramRunner {
|
||||
if (debuggerSettings.isLibrariesFilterEnabled()) {
|
||||
environment.put(PYDEVD_FILTER_LIBRARIES, "True");
|
||||
}
|
||||
if (debuggerSettings.isLoadValuesAsync()) {
|
||||
environment.put(PyVariableViewSettings.PYDEVD_LOAD_VALUES_ASYNC, "True");
|
||||
if (debuggerSettings.getValuesPolicy() != PyDebugValue.ValuesPolicy.SYNC) {
|
||||
environment.put(PyDebugValue.POLICY_ENV_VARS.get(debuggerSettings.getValuesPolicy()), "True");
|
||||
}
|
||||
|
||||
PydevConsoleRunnerFactory.putIPythonEnvFlag(project, environment);
|
||||
|
||||
@@ -129,6 +129,7 @@ public class PyStackFrame extends XStackFrame {
|
||||
@Override
|
||||
public void computeChildren(@NotNull final XCompositeNode node) {
|
||||
if (node.isObsolete()) return;
|
||||
myDebugProcess.setCurrentRootNode(node);
|
||||
ApplicationManager.getApplication().executeOnPooledThread(() -> {
|
||||
try {
|
||||
boolean cached = myDebugProcess.isCurrentFrameCached();
|
||||
@@ -214,7 +215,7 @@ public class PyStackFrame extends XStackFrame {
|
||||
node.addChildren(list, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return AllIcons.Debugger.WatchLastReturnValue;
|
||||
@@ -237,7 +238,7 @@ public class PyStackFrame extends XStackFrame {
|
||||
node.addChildren(list, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return PythonIcons.Python.Debug.SpecialVar;
|
||||
@@ -258,10 +259,6 @@ public class PyStackFrame extends XStackFrame {
|
||||
return myFrameInfo.getThreadId() + ":" + myFrameInfo.getId();
|
||||
}
|
||||
|
||||
public String getFrameName() {
|
||||
return myFrameInfo.getName();
|
||||
}
|
||||
|
||||
protected XSourcePosition getPosition() {
|
||||
return myPosition;
|
||||
}
|
||||
|
||||
@@ -15,15 +15,23 @@
|
||||
*/
|
||||
package com.jetbrains.python.debugger;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.openapi.actionSystem.ToggleAction;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.xdebugger.frame.XCompositeNode;
|
||||
import com.intellij.xdebugger.frame.XDebuggerTreeNodeHyperlink;
|
||||
import com.jetbrains.python.debugger.settings.PyDebuggerSettings;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PyVariableViewSettings {
|
||||
public static final String PYDEVD_LOAD_VALUES_ASYNC = "PYDEVD_LOAD_VALUES_ASYNC";
|
||||
public static final String LOADING_TIMED_OUT = "Loading timed out";
|
||||
public static final String ON_DEMAND_LINK_TEXT = "Switch to loading on demand";
|
||||
public static final String WARNING_MESSAGE = "The values of several variables couldn't be loaded ";
|
||||
|
||||
public static class SimplifiedView extends ToggleAction {
|
||||
private final PyDebugProcess myProcess;
|
||||
@@ -60,33 +68,107 @@ public class PyVariableViewSettings {
|
||||
}
|
||||
}
|
||||
|
||||
public static class AsyncView extends ToggleAction {
|
||||
private final String myText;
|
||||
private volatile boolean myLazyVariablesEvaluation;
|
||||
public static void showWarningMessage(@Nullable final XCompositeNode node) {
|
||||
if (node == null) return;
|
||||
final PyDebuggerSettings debuggerSettings = PyDebuggerSettings.getInstance();
|
||||
if (debuggerSettings.getValuesPolicy() == PyDebugValue.ValuesPolicy.ON_DEMAND) return;
|
||||
|
||||
public AsyncView() {
|
||||
super("", "Load variable values asynchronously", null);
|
||||
myLazyVariablesEvaluation = PyDebuggerSettings.getInstance().isLoadValuesAsync();
|
||||
myText = "Load Values Asynchronously";
|
||||
node.setMessage(
|
||||
WARNING_MESSAGE, AllIcons.General.BalloonWarning, SimpleTextAttributes.REGULAR_ATTRIBUTES,
|
||||
new XDebuggerTreeNodeHyperlink(ON_DEMAND_LINK_TEXT) {
|
||||
private boolean linkClicked = false;
|
||||
|
||||
@Override
|
||||
public void onClick(MouseEvent event) {
|
||||
debuggerSettings.setValuesPolicy(PyDebugValue.ValuesPolicy.ON_DEMAND);
|
||||
linkClicked = true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getLinkText() {
|
||||
if (linkClicked) {
|
||||
return "";
|
||||
}
|
||||
else {
|
||||
return ON_DEMAND_LINK_TEXT;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static class VariablesPolicyGroup extends DefaultActionGroup {
|
||||
@NotNull private final List<PolicyAction> myValuesPolicyActions = new ArrayList<>();
|
||||
|
||||
public VariablesPolicyGroup() {
|
||||
super("Variables Loading Policy", true);
|
||||
myValuesPolicyActions
|
||||
.add(new PolicyAction("Synchronously", "Load variable values synchronously", PyDebugValue.ValuesPolicy.SYNC, this));
|
||||
myValuesPolicyActions
|
||||
.add(new PolicyAction("Asynchronously", "Load variable values asynchronously", PyDebugValue.ValuesPolicy.ASYNC, this));
|
||||
myValuesPolicyActions
|
||||
.add(new PolicyAction("On demand", "Load variable values on demand", PyDebugValue.ValuesPolicy.ON_DEMAND, this));
|
||||
|
||||
for (AnAction action : myValuesPolicyActions) {
|
||||
add(action);
|
||||
}
|
||||
}
|
||||
|
||||
public void updatePolicyActions() {
|
||||
final PyDebugValue.ValuesPolicy currentValuesPolicy = PyDebuggerSettings.getInstance().getValuesPolicy();
|
||||
for (PolicyAction action : myValuesPolicyActions) {
|
||||
action.setEnabled(currentValuesPolicy == action.getPolicy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class PolicyAction extends ToggleAction {
|
||||
@NotNull private final String myText;
|
||||
@NotNull private final PyDebugValue.ValuesPolicy myPolicy;
|
||||
@NotNull private final VariablesPolicyGroup myActionGroup;
|
||||
private volatile boolean isEnabled;
|
||||
|
||||
public PolicyAction(@NotNull String text,
|
||||
@NotNull String description,
|
||||
@NotNull PyDebugValue.ValuesPolicy policy,
|
||||
@NotNull VariablesPolicyGroup actionGroup) {
|
||||
super("", description, null);
|
||||
myText = text;
|
||||
myPolicy = policy;
|
||||
myActionGroup = actionGroup;
|
||||
isEnabled = PyDebuggerSettings.getInstance().getValuesPolicy() == policy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull final AnActionEvent e) {
|
||||
super.update(e);
|
||||
myActionGroup.updatePolicyActions();
|
||||
final Presentation presentation = e.getPresentation();
|
||||
presentation.setEnabled(true);
|
||||
presentation.setText(myText);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PyDebugValue.ValuesPolicy getPolicy() {
|
||||
return myPolicy;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
isEnabled = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelected(AnActionEvent e) {
|
||||
return myLazyVariablesEvaluation;
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(AnActionEvent e, boolean hide) {
|
||||
myLazyVariablesEvaluation = hide;
|
||||
PyDebuggerSettings.getInstance().setLoadValuesAsync(hide);
|
||||
isEnabled = hide;
|
||||
if (hide) {
|
||||
PyDebuggerSettings.getInstance().setValuesPolicy(myPolicy);
|
||||
}
|
||||
myActionGroup.updatePolicyActions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.intellij.util.SmartList;
|
||||
import com.intellij.util.xmlb.XmlSerializerUtil;
|
||||
import com.intellij.xdebugger.settings.DebuggerSettingsCategory;
|
||||
import com.intellij.xdebugger.settings.XDebuggerSettings;
|
||||
import com.jetbrains.python.debugger.PyDebugValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -26,7 +27,7 @@ public class PyDebuggerSettings extends XDebuggerSettings<PyDebuggerSettings> im
|
||||
public static final String FILTERS_DIVIDER = ";";
|
||||
private boolean myWatchReturnValues = false;
|
||||
private boolean mySimplifiedView = true;
|
||||
private boolean myLoadValuesAsync = true;
|
||||
private volatile PyDebugValue.ValuesPolicy myValuesPolicy = PyDebugValue.ValuesPolicy.ASYNC;
|
||||
|
||||
public PyDebuggerSettings() {
|
||||
super("python");
|
||||
@@ -49,12 +50,12 @@ public class PyDebuggerSettings extends XDebuggerSettings<PyDebuggerSettings> im
|
||||
mySimplifiedView = simplifiedView;
|
||||
}
|
||||
|
||||
public boolean isLoadValuesAsync() {
|
||||
return myLoadValuesAsync;
|
||||
public PyDebugValue.ValuesPolicy getValuesPolicy() {
|
||||
return myValuesPolicy;
|
||||
}
|
||||
|
||||
public void setLoadValuesAsync(boolean loadValuesAsync) {
|
||||
myLoadValuesAsync = loadValuesAsync;
|
||||
public void setValuesPolicy(PyDebugValue.ValuesPolicy valuesPolicy) {
|
||||
myValuesPolicy = valuesPolicy;
|
||||
}
|
||||
|
||||
public static PyDebuggerSettings getInstance() {
|
||||
|
||||
Reference in New Issue
Block a user