mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
[debugger] fix stack frames folding, IDEA-340584
There were some problems with folding/hiding, please see test changes. ^IDEA-344033 fixed GitOrigin-RevId: cc004b02094381a5ce85155c699c2f31b63a82d6
This commit is contained in:
committed by
intellij-monorepo-bot
parent
dff6b3aaff
commit
40f60bd16e
@@ -265,17 +265,39 @@ public class JavaExecutionStack extends XExecutionStack {
|
||||
return myAdded <= StackFrameProxyImpl.FRAMES_BATCH_MAX ? Priority.NORMAL : Priority.LOW;
|
||||
}
|
||||
|
||||
private void flushHiddenFrames() {
|
||||
if (!XFramesView.shouldFoldHiddenFrames()) return;
|
||||
|
||||
if (myHiddenCount > 0) {
|
||||
assert myFirstHiddenFrame != null;
|
||||
var placeholder = new XFramesView.HiddenStackFramesItem(myHiddenCount, myFirstHiddenFrame);
|
||||
myContainer.addStackFrames(Collections.singletonList(placeholder), false);
|
||||
myHiddenCount = 0;
|
||||
myFirstHiddenFrame = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void rememberHiddenFrame(XStackFrame frame) {
|
||||
if (!XFramesView.shouldFoldHiddenFrames()) return;
|
||||
|
||||
if (myHiddenCount == 0) {
|
||||
myFirstHiddenFrame = frame;
|
||||
}
|
||||
myHiddenCount++;
|
||||
}
|
||||
|
||||
private void addStackFrames(List<XStackFrame> frames, boolean last) {
|
||||
flushHiddenFrames();
|
||||
myContainer.addStackFrames(frames, last);
|
||||
}
|
||||
|
||||
private boolean addFrameIfNeeded(XStackFrame frame, boolean last) {
|
||||
if (++myAdded > mySkip) {
|
||||
if (myHiddenCount > 0) {
|
||||
assert myFirstHiddenFrame != null;
|
||||
myContainer.addStackFrames(XFramesView.createHiddenFramePlaceholder(myHiddenCount, myFirstHiddenFrame), false);
|
||||
}
|
||||
myContainer.addStackFrames(Collections.singletonList(frame), last);
|
||||
addStackFrames(Collections.singletonList(frame), last);
|
||||
return true;
|
||||
}
|
||||
if (last) {
|
||||
myContainer.addStackFrames(Collections.emptyList(), true);
|
||||
addStackFrames(Collections.emptyList(), true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -307,18 +329,13 @@ public class JavaExecutionStack extends XExecutionStack {
|
||||
if (frame instanceof JavaStackFrame) {
|
||||
((JavaStackFrame)frame).getDescriptor().updateRepresentationNoNotify(null, () -> {
|
||||
// repaint on icon change
|
||||
myContainer.addStackFrames(Collections.emptyList(), !myStackFramesIterator.hasNext());
|
||||
addStackFrames(Collections.emptyList(), !myStackFramesIterator.hasNext());
|
||||
});
|
||||
}
|
||||
addFrameIfNeeded(frame, false);
|
||||
myHiddenCount = 0;
|
||||
myFirstHiddenFrame = null;
|
||||
}
|
||||
else {
|
||||
if (myHiddenCount == 0) {
|
||||
myFirstHiddenFrame = frame;
|
||||
}
|
||||
myHiddenCount++;
|
||||
rememberHiddenFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,7 +367,7 @@ public class JavaExecutionStack extends XExecutionStack {
|
||||
appendRelatedStack(suspendContext, myAsyncStack.subList(myAddedAsync, myAsyncStack.size()));
|
||||
}
|
||||
else {
|
||||
myContainer.addStackFrames(Collections.emptyList(), true);
|
||||
addStackFrames(Collections.emptyList(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,18 +400,29 @@ public class JavaExecutionStack extends XExecutionStack {
|
||||
XStackFrame newFrame = stackFrame.createFrame(myDebugProcess);
|
||||
if (newFrame != null) {
|
||||
if (showFrame(newFrame)) {
|
||||
StackFrameItem.setWithSeparator(newFrame, mySeparator);
|
||||
if (mySeparator) {
|
||||
flushHiddenFrames();
|
||||
StackFrameItem.setWithSeparator(newFrame);
|
||||
}
|
||||
if (addFrameIfNeeded(newFrame, false)) {
|
||||
// No need to propagate the separator further, because it was added.
|
||||
mySeparator = false;
|
||||
}
|
||||
myHiddenCount = 0;
|
||||
myFirstHiddenFrame = null;
|
||||
}
|
||||
else if (XFramesView.shouldFoldHiddenFrames()) {
|
||||
if (mySeparator) {
|
||||
flushHiddenFrames();
|
||||
// The separator for this hidden frame will be used as the placeholder separator.
|
||||
StackFrameItem.setWithSeparator(newFrame);
|
||||
mySeparator = false;
|
||||
}
|
||||
rememberHiddenFrame(newFrame);
|
||||
}
|
||||
else {
|
||||
if (myHiddenCount == 0) {
|
||||
myFirstHiddenFrame = newFrame;
|
||||
if (!mySeparator && StackFrameItem.hasSeparatorAbove(newFrame)) {
|
||||
// Frame has a separator, but it wasn't added; we need to propagate the separator further.
|
||||
mySeparator = true;
|
||||
}
|
||||
myHiddenCount++;
|
||||
}
|
||||
}
|
||||
schedule(suspendContext, null, myAsyncStack, mySeparator);
|
||||
|
||||
@@ -57,7 +57,9 @@ class StackFrameList extends XDebuggerFramesList {
|
||||
}
|
||||
else {
|
||||
XStackFrame frame = frameInfo.createFrame(myDebugProcess);
|
||||
StackFrameItem.setWithSeparator(frame, separator);
|
||||
if (separator) {
|
||||
StackFrameItem.setWithSeparator(frame);
|
||||
}
|
||||
DebuggerUIUtil.invokeLater(() -> getModel().add(frame));
|
||||
separator = false;
|
||||
}
|
||||
|
||||
@@ -228,9 +228,14 @@ public class StackFrameItem {
|
||||
return new CapturedStackFrame(debugProcess, this);
|
||||
}
|
||||
|
||||
public static void setWithSeparator(XStackFrame frame, boolean withSeparator) {
|
||||
if (frame instanceof CapturedStackFrame) {
|
||||
((CapturedStackFrame)frame).setWithSeparator(withSeparator);
|
||||
public static boolean hasSeparatorAbove(XStackFrame frame) {
|
||||
return frame instanceof XDebuggerFramesList.ItemWithSeparatorAbove frameWithSeparator &&
|
||||
frameWithSeparator.hasSeparatorAbove();
|
||||
}
|
||||
|
||||
public static void setWithSeparator(XStackFrame frame) {
|
||||
if (frame instanceof XDebuggerFramesList.ItemWithSeparatorAbove frameWithSeparator) {
|
||||
frameWithSeparator.setWithSeparator(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,6 +333,7 @@ public class StackFrameItem {
|
||||
return myWithSeparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWithSeparator(boolean withSeparator) {
|
||||
myWithSeparator = withSeparator;
|
||||
}
|
||||
|
||||
@@ -230,8 +230,9 @@ memory.instances.close.text=Close
|
||||
threads.list.threads.not.available=Threads are not available
|
||||
data.views.configurable.panel.title=Editor
|
||||
hide.library.frames.tooltip=Hide Frames from Libraries
|
||||
fold.library.frames.tooltip=Fold Frames from Libraries
|
||||
show.all.frames.tooltip=Show All Frames
|
||||
label.hidden.frames={0,number} hidden {0,choice, 1#frame|2#frames}
|
||||
label.folded.frames={0,number} hidden {0,choice, 1#frame|2#frames}
|
||||
options.kotlin.attribute.descriptor.inline.stack.frames=Inline stack frames
|
||||
options.java.attribute.descriptor.breakpoint.line=Breakpoint line
|
||||
options.java.attribute.descriptor.execution.point=Execution point
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.XDebuggerBundle;
|
||||
import com.intellij.xdebugger.impl.XDebuggerUtilImpl;
|
||||
import com.intellij.xdebugger.impl.frame.XFramesView;
|
||||
import com.intellij.xdebugger.impl.settings.XDebuggerSettingManagerImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -43,7 +44,11 @@ final class ShowLibraryFramesAction extends ToggleAction {
|
||||
if (Boolean.TRUE.equals(isSupported)) {
|
||||
presentation.setVisible(true);
|
||||
final boolean shouldShow = !Toggleable.isSelected(presentation);
|
||||
presentation.setText(XDebuggerBundle.message(shouldShow ? "hide.library.frames.tooltip" : "show.all.frames.tooltip"));
|
||||
presentation.setText(XDebuggerBundle.message(shouldShow
|
||||
? (XFramesView.shouldFoldHiddenFrames()
|
||||
? "fold.library.frames.tooltip"
|
||||
: "hide.library.frames.tooltip")
|
||||
: "show.all.frames.tooltip"));
|
||||
}
|
||||
else {
|
||||
presentation.setVisible(false);
|
||||
|
||||
@@ -426,6 +426,9 @@ public class XDebuggerFramesList extends DebuggerFramesList implements DataProvi
|
||||
public interface ItemWithSeparatorAbove {
|
||||
boolean hasSeparatorAbove();
|
||||
@NlsContexts.Separator String getCaptionAboveOf();
|
||||
|
||||
default void setWithSeparator(boolean withSeparator) {
|
||||
}
|
||||
}
|
||||
|
||||
public interface ItemWithCustomBackgroundColor {
|
||||
|
||||
@@ -725,20 +725,25 @@ public final class XFramesView extends XDebugView {
|
||||
}
|
||||
}
|
||||
|
||||
private static class HiddenStackFramesItem extends XStackFrame implements XDebuggerFramesList.ItemWithCustomBackgroundColor,
|
||||
XDebuggerFramesList.ItemWithSeparatorAbove {
|
||||
/**
|
||||
* Synthetic frame which encapsulates hidden library frames as a single fold.
|
||||
*
|
||||
* @see #shouldFoldHiddenFrames()
|
||||
*/
|
||||
public static class HiddenStackFramesItem extends XStackFrame implements XDebuggerFramesList.ItemWithCustomBackgroundColor,
|
||||
XDebuggerFramesList.ItemWithSeparatorAbove {
|
||||
|
||||
private final int hiddenFrameCount;
|
||||
private final @NotNull XStackFrame firstHiddenFrame;
|
||||
|
||||
private HiddenStackFramesItem(int hiddenFrameCount, @NotNull XStackFrame firstHiddenFrame) {
|
||||
public HiddenStackFramesItem(int hiddenFrameCount, @NotNull XStackFrame firstHiddenFrame) {
|
||||
this.hiddenFrameCount = hiddenFrameCount;
|
||||
this.firstHiddenFrame = firstHiddenFrame;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizePresentation(@NotNull ColoredTextContainer component) {
|
||||
component.append(XDebuggerBundle.message("label.hidden.frames", hiddenFrameCount), SimpleTextAttributes.GRAYED_ATTRIBUTES);
|
||||
component.append(XDebuggerBundle.message("label.folded.frames", hiddenFrameCount), SimpleTextAttributes.GRAYED_ATTRIBUTES);
|
||||
component.setIcon(EmptyIcon.ICON_16);
|
||||
}
|
||||
|
||||
@@ -764,10 +769,12 @@ public final class XFramesView extends XDebugView {
|
||||
}
|
||||
}
|
||||
|
||||
public static List<XStackFrame> createHiddenFramePlaceholder(int hiddenFrameCount, @NotNull XStackFrame firstHiddenFrame) {
|
||||
return Registry.is("debugger.library.frames.fold.instead.of.hide")
|
||||
? Collections.singletonList(new HiddenStackFramesItem(hiddenFrameCount, firstHiddenFrame))
|
||||
: Collections.emptyList();
|
||||
/**
|
||||
* Whether hidden frames are folded into a single-item placeholder.
|
||||
* Otherwise, they completely disappear.
|
||||
*/
|
||||
public static boolean shouldFoldHiddenFrames() {
|
||||
return Registry.is("debugger.library.frames.fold.instead.of.hide");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class CreationCoroutineStackFrameItem(
|
||||
return debugProcess.invokeInManagerThread {
|
||||
val frame = debugProcess.findFirstFrame() ?: return@invokeInManagerThread null
|
||||
val position = location.findPosition(debugProcess)
|
||||
CreationCoroutineStackFrame(frame, position, first, location)
|
||||
CreationCoroutineStackFrame(frame, position, withSepartor = first, location)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class CoroutinePreflightFrame(
|
||||
class CreationCoroutineStackFrame(
|
||||
frame: StackFrameProxyImpl,
|
||||
sourcePosition: XSourcePosition?,
|
||||
val first: Boolean,
|
||||
private var withSepartor: Boolean,
|
||||
location: Location? = frame.safeLocation()
|
||||
) : CoroutineStackFrame(frame, sourcePosition, emptyList(), false, location), XDebuggerFramesList.ItemWithSeparatorAbove {
|
||||
|
||||
@@ -52,7 +52,11 @@ class CreationCoroutineStackFrame(
|
||||
KotlinDebuggerCoroutinesBundle.message("coroutine.dump.creation.trace")
|
||||
|
||||
override fun hasSeparatorAbove() =
|
||||
first
|
||||
withSepartor
|
||||
|
||||
override fun setWithSeparator(withSeparator: Boolean) {
|
||||
this.withSepartor = withSeparator
|
||||
}
|
||||
}
|
||||
|
||||
open class CoroutineStackFrame(
|
||||
|
||||
@@ -8,6 +8,7 @@ Thread stack trace:
|
||||
CoroutineInfo: 1 coroutine RUNNING
|
||||
CoroutineStackFrame main:!LINE_NUMBER!, SuspendFunStackTraceHiddenKt (continuation)
|
||||
()
|
||||
Coroutine Creation Stack Trace
|
||||
CreationCoroutineStackFrame main:!LINE_NUMBER!, SuspendFunStackTraceHiddenKt (continuation)
|
||||
($result, this)
|
||||
CreationCoroutineStackFrame FRAME:main:-1, SuspendFunStackTraceHiddenKt (continuation)
|
||||
|
||||
Reference in New Issue
Block a user