mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 06:50:54 +07:00
Inline button for view as image
[pycharm] PY-79803 Debugger: add button Merge-request: IJ-MR-160372 Merged-by: Ekaterina Itsenko <ekaterina.itsenko@jetbrains.com> (cherry picked from commit e2900c27343967e61033554e12cca97a0cc78e61) GitOrigin-RevId: 454f42494582b5e3b4cf3342145f2316d65e8dd0
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d889654caf
commit
3de80b5d6e
@@ -20,5 +20,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.util.io" />
|
||||
<orderEntry type="module" module-name="intellij.platform.debugger.impl" />
|
||||
<orderEntry type="module" module-name="intellij.python.syntax.core" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.core.impl" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,5 +1,6 @@
|
||||
pydev.loading.value=... Loading Value
|
||||
pydev.show.value=Show Value
|
||||
pydev.view.as=...View as {0}
|
||||
pydev.view.as.image=...View as Image
|
||||
pydev.value.protected.attributes.group.name=Protected Attributes
|
||||
pydev.error.message.failed.to.find.free.socket.port=Failed to find a free socket port
|
||||
@@ -5,6 +5,12 @@ import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -20,9 +26,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -353,7 +360,7 @@ public class PyDebugValue extends XNamedValue {
|
||||
public void computePresentation(@NotNull XValueNode node, @NotNull XValuePlace place) {
|
||||
String value = PyTypeHandler.format(this);
|
||||
setFullValueEvaluator(node, value);
|
||||
setConfigureTypeRenderersLink(node);
|
||||
setAdditionalLinks(node);
|
||||
if (value.length() >= MAX_VALUE) {
|
||||
value = value.substring(0, MAX_VALUE);
|
||||
}
|
||||
@@ -361,6 +368,25 @@ public class PyDebugValue extends XNamedValue {
|
||||
setElementPresentation(node, value);
|
||||
}
|
||||
|
||||
private void setAdditionalLinks(@NotNull XValueNode node) {
|
||||
if (node instanceof XValueNodeImpl valueNode) {
|
||||
if (checkAndEnableViewAsImageVisibility(this)) {
|
||||
addViewAsImageLink(valueNode);
|
||||
}
|
||||
addConfigureTypeRendererLink(valueNode);
|
||||
}
|
||||
}
|
||||
|
||||
private void addConfigureTypeRendererLink(@NotNull XValueNodeImpl valueNode) {
|
||||
String typeRendererId = getTypeRendererId();
|
||||
if (typeRendererId != null) {
|
||||
XDebuggerTreeNodeHyperlink link = myFrameAccessor.getUserTypeRenderersLink(typeRendererId);
|
||||
if (link != null) {
|
||||
valueNode.addAdditionalHyperlink(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateNodeValueAfterLoading(@NotNull XValueNode node,
|
||||
@NotNull String value,
|
||||
@NotNull @Nls String linkText,
|
||||
@@ -463,19 +489,85 @@ public class PyDebugValue extends XNamedValue {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (node instanceof XValueNodeImpl valueNode) {
|
||||
addViewAsImageLink(valueNode);
|
||||
}
|
||||
String linkText = PydevBundle.message("pydev.view.as", postfix);
|
||||
node.setFullValueEvaluator(new PyNumericContainerValueEvaluator(linkText, myFrameAccessor, treeName));
|
||||
}
|
||||
|
||||
private void setConfigureTypeRenderersLink(@NotNull XValueNode node) {
|
||||
String typeRendererId = getTypeRendererId();
|
||||
if (node instanceof XValueNodeImpl valueNode) {
|
||||
valueNode.clearAdditionalHyperlinks();
|
||||
if (typeRendererId != null) {
|
||||
XDebuggerTreeNodeHyperlink link = myFrameAccessor.getUserTypeRenderersLink(typeRendererId);
|
||||
if (link != null) valueNode.addAdditionalHyperlink(link);
|
||||
private static void addViewAsImageLink(XValueNodeImpl valueNode) {
|
||||
if (!checkAndShowViewAsImageOnScreen((PyDebugValue)valueNode.getXValue()))
|
||||
return;
|
||||
String viewAsImageText = PydevBundle.message("pydev.view.as.image");
|
||||
valueNode.addAdditionalHyperlink(new XDebuggerTreeNodeHyperlink(viewAsImageText) {
|
||||
@Override
|
||||
public void onClick(MouseEvent event) {
|
||||
AnAction action = ActionManager.getInstance().getAction("JupyterShowAsImageAction");
|
||||
DataContext dataContext = DataManager.getInstance().getDataContext((Component)event.getSource());
|
||||
AnActionEvent actionEvent = AnActionEvent.createFromAnAction(
|
||||
action,
|
||||
null,
|
||||
"JupyterShowAsImageAction",
|
||||
dataContext
|
||||
);
|
||||
action.actionPerformed(actionEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alwaysOnScreen() {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean checkAndShowViewAsImageOnScreen(PyDebugValue debugValue) {
|
||||
boolean showViewAsImage = Registry.get("actions.show.as.image.visibility").asBoolean();
|
||||
if (!showViewAsImage) {
|
||||
return false;
|
||||
}
|
||||
return checkAndEnableViewAsImageVisibility(debugValue);
|
||||
}
|
||||
|
||||
private static boolean checkAndEnableViewAsImageVisibility(PyDebugValue debugValue) {
|
||||
String nodeType = debugValue.getType();
|
||||
return switch (Objects.requireNonNull(nodeType)) {
|
||||
case NodeTypes.NDARRAY_NODE_TYPE, NodeTypes.EAGER_TENSOR_NODE_TYPE, NodeTypes.RESOURCE_VARIABLE_NODE_TYPE,
|
||||
NodeTypes.SPARSE_TENSOR_NODE_TYPE, NodeTypes.TENSOR_NODE_TYPE -> {
|
||||
int[] shape = extractShape(debugValue);
|
||||
yield isValidArrayShape(shape);
|
||||
}
|
||||
case NodeTypes.IMAGE_NODE_TYPE, NodeTypes.FIGURE_NODE_TYPE -> true;
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
private static int[] extractShape(PyDebugValue debugValue) {
|
||||
String shapeString = debugValue.getShape() == null ? "" : debugValue.getShape();
|
||||
return Arrays.stream(shapeString.replace("(", "").replace(")", "").split(","))
|
||||
.map(String::trim)
|
||||
.mapToInt(s -> {
|
||||
try {
|
||||
return Integer.parseInt(s);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
})
|
||||
.filter(value -> value != Integer.MIN_VALUE)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
private static boolean isValidArrayShape(int[] shape) {
|
||||
if (shape == null || shape.length == 0) {
|
||||
return false;
|
||||
}
|
||||
return switch (shape.length) {
|
||||
case 1, 2 -> true;
|
||||
case 3 -> shape[2] == 3 || shape[2] == 4 || shape[2] == 1;
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user